/* Direction B — wide photographic bands: photography-forward, one glance per project */
const { useEffect: useProjFx, useState: useProjState } = React;
const P = { ink: "#282828", soft: "#544e45", faint: "#6b6456", paper: "#eceae5", paper2: "#e3e0d9", line: "rgba(40,40,40,0.20)", clay: "#5f594f" };
const Pvars = { "--ink": P.ink, color: P.ink, background: P.paper };
const PAD = "clamp(28px,6vw,96px)";
const PROJECTS = [
  { id: "pr-res11", name: "Residence / 11", cat: "Residential", loc: "Dubai", year: "2026", src: "res11-bedroom-day.png", tone: "#c9bda7", href: "project.html?p=residence-11", blurb: "A residence planned around a courtyard, for filtered light." },
  { id: "pr-s14", name: "Personal Sanctuary", cat: "Residential", loc: "Milano", year: "2025", src: "sanctuary14-hero.jpg", tone: "#a99b86", href: "project.html?p=sanctuary-14", blurb: "A private home, reflects the lifestyle and a beauty of rest." },
  { id: "pr-destino", name: "Hotel Destino", cat: "Hospitality", loc: "Ibiza", year: "2025", src: "destino-akari-lobby.png", tone: "#c9b79a", href: "project.html?p=hotel-destino", blurb: "A terrace, lounge and spa in Ibiza." },
  { id: "pr-s09", name: "Residence / 09", cat: "Residential", loc: "Milano", year: "2023", src: "sanctuary09-5.jpg", tone: "#9c9484", href: "project.html?p=sanctuary-09", blurb: "Ninth floor on Piazza Alvar Aalto." },
  { id: "pr-s44", name: "Residence / 44", cat: "Residential", loc: "Milano", year: "2024", src: "sanctuary44-6.jpg", tone: "#b1a89a", href: "project.html?p=sanctuary-44", blurb: "A family residence on Via Agnelo, with a terrace." },
  { id: "pr-folks", name: "Folks Bakery", cat: "Hospitality", loc: "Ukraine", year: "2026", src: "folks-counter.png", tone: "#c3b39e", href: "project.html?p=folks-bakery", blurb: "The original brick and plaster were kept and repaired." },
  { id: "pr-hotel", name: "The Farm", cat: "Hospitality", loc: "Concept", year: "2026", src: "locked/hotel-suite.jpg", tone: "#8a8072", href: "project.html?p=hotel", blurb: "A hotel concept built from the land it stands on." },
];

/* one lead image, then a steady two-column rhythm */
function bandLayout(i) {
  return i === 0 ? { span: 12, ratio: "16 / 7", big: true } : { span: 6, ratio: "4 / 3" };
}

function Band({ p, i }) {
  const L = bandLayout(i);
  const [hov, setHov] = useProjState(false);
  const navTimer = React.useRef(null);
  // A click on the photo navigates, but a double-click must reach the slot's
  // own reframe handler instead, so navigation waits long enough to tell them apart.
  const isPlainClick = (e) => !(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) && e.button === 0;
  const onClick = (e) => {
    if (!isPlainClick(e) || !e.target.closest("image-slot")) return;
    e.preventDefault();
    clearTimeout(navTimer.current);
    navTimer.current = setTimeout(() => { window.location.href = p.href; }, 280);
  };
  const onDoubleClick = (e) => {
    if (!isPlainClick(e) || !e.target.closest("image-slot")) return;
    e.preventDefault();
    clearTimeout(navTimer.current);
  };
  return (
    <a href={p.href} className="reveal" draggable="false" onClick={onClick} onDoubleClick={onDoubleClick}
      onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}
      style={{ display: "block", textDecoration: "none", color: P.ink, gridColumn: `span ${L.span}` }}>
      <div style={{ position: "relative", overflow: "hidden", aspectRatio: L.ratio, background: P.paper2 }}>
        <Plate slot={p.id} src={p.src} tone={p.tone} placeholder=" " style={{ position: "absolute", inset: 0, transform: hov ? "scale(1.03)" : "scale(1)", transition: "transform 1.2s cubic-bezier(.2,.7,.15,1)" }} />
      </div>
      <h2 className="serif" style={{ fontSize: L.big ? "clamp(26px,3vw,44px)" : "clamp(21px,2.1vw,30px)", fontWeight: 300, margin: "clamp(16px,1.8vw,22px) 0 0", letterSpacing: "-0.018em", lineHeight: 1.1 }}>{p.name}</h2>
      <p className="journal" style={{ fontSize: L.big ? "clamp(16px,1.7vw,20px)" : "clamp(15px,1.5vw,17px)", fontWeight: 200, margin: "8px 0 0", color: P.soft, lineHeight: 1.55, maxWidth: "46ch", minHeight: L.big ? 0 : "calc(2 * 1.55em)" }}>{p.blurb}</p>
      <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 16, marginTop: "clamp(16px,1.8vw,22px)", paddingTop: 12, borderTop: `1px solid ${hov ? P.ink : P.line}`, transition: "border-color .35s ease" }}>
        <span className="label" style={{ fontSize: 12, letterSpacing: "0.2em", color: P.soft }}>{p.cat} &nbsp;|&nbsp; {p.loc}</span>
        <span className="label" style={{ fontSize: 12, letterSpacing: "0.2em", color: P.faint }}>{p.year}</span>
      </div>
    </a>
  );
}

/* the four movements of the Method, pinned: one fills the screen at a time as you scroll */
const MOVES = [
  { t: "Sense", domain: "The Body", line: "Interiors act on the body through the senses: light, sound, touch, temperature and proportion." },
  { t: "Shape", domain: "The Space", line: "Quiet the room, and the mind settles with it." },
  { t: "Regulate", domain: "The Nervous System", line: "Every culture has known how a room should feel." },
  { t: "Restore", domain: "Your Energy", line: "A home should give your energy back." },
];
function MoveMotif({ i, c, size = 84 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 72 72" fill="none" stroke={c} strokeWidth={size < 48 ? 1.4 : 0.75} strokeLinecap="round" aria-hidden="true" style={{ display: "block", flex: "none" }}>
      {i === 0 && <g><circle cx="36" cy="36" r="3" fill={c} stroke="none" /><circle cx="36" cy="36" r="11" strokeDasharray="1 3.5" /><circle cx="36" cy="36" r="19" strokeDasharray="1 3.5" /><circle cx="36" cy="36" r="27" strokeDasharray="1 3.5" opacity="0.55" /></g>}
      {i === 1 && <g><circle cx="36" cy="36" r="24" /><ellipse cx="36" cy="36" rx="24" ry="8.5" transform="rotate(-28 36 36)" /><ellipse cx="36" cy="36" rx="24" ry="8.5" transform="rotate(28 36 36)" /><circle cx="36" cy="36" r="2.2" fill={c} stroke="none" /></g>}
      {i === 2 && <g><circle cx="14" cy="36" r="7.5" strokeDasharray="1 3" /><path d="M36 28.5a7.5 7.5 0 0 0 0 15" fill={c} stroke="none" /><circle cx="36" cy="36" r="7.5" /><circle cx="58" cy="36" r="7.5" fill={c} stroke="none" /></g>}
      {i === 3 && <g><circle cx="36" cy="36" r="8" fill={c} stroke="none" /><circle cx="36" cy="36" r="13" /><path d="M36 10v5M36 62v-5M10 36h5M62 36h-5M17.6 17.6l3.5 3.5M54.4 54.4l-3.5-3.5M54.4 17.6l-3.5 3.5M17.6 54.4l3.5-3.5" /><circle cx="36" cy="36" r="27" strokeDasharray="1 3.5" opacity="0.55" /></g>}
    </svg>
  );
}
function MethodMoves() {
  const V = window.MV_VARIANT || "word";
  if (V === "dial") return <MoveDial />;
  if (V === "word" || V === "inline") return null;
  // four quiet columns, read at a glance; hovering one brings it forward
  const [hi, setHi] = useProjState(-1);
  return (
    <section className="pj-moves reveal" style={{ padding: `clamp(10px,1.4vw,18px) ${PAD} clamp(8px,1vw,14px)` }}>
      <div className="pj-mv-grid" onMouseLeave={() => setHi(-1)}
        style={{ display: "grid", gridTemplateColumns: "repeat(4, minmax(0,1fr))", maxWidth: 1320, margin: "0 auto", borderTop: `1px solid ${P.line}`, borderBottom: `1px solid ${P.line}` }}>
        {MOVES.map((m, i) => (
          <a key={m.t} href="method.html" onMouseEnter={() => setHi(i)} onFocus={() => setHi(i)}
            style={{ display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", gap: 12, textDecoration: "none", color: P.ink,
              padding: "clamp(22px,2.6vw,34px) clamp(12px,1.6vw,24px)", borderLeft: i ? `1px solid ${P.line}` : "none",
              opacity: hi === -1 || hi === i ? 1 : 0.4, transition: "opacity .45s ease" }}>
            <span className="pj-mv-icon" style={{ display: "block", transform: hi === i ? "rotate(30deg) scale(1.08)" : "none", transition: "transform 1.1s cubic-bezier(.2,.7,.15,1)" }}>
              <MoveMotif i={i} c={P.soft} size={40} />
            </span>
            <span className="label" style={{ fontSize: 12, letterSpacing: "0.2em", color: P.ink }}>{m.t}</span>
            <span className="serif" style={{ fontSize: "clamp(16px,1.35vw,19px)", fontWeight: 300, lineHeight: 1.35, color: P.soft, maxWidth: "22ch", textWrap: "balance" }}>{m.line}</span>
          </a>
        ))}
      </div>
    </section>
  );
}
/* B: one movement at a time, turning on its own like a slow dial */
function MoveDial() {
  const [a, setA] = useProjState(0);
  useProjFx(() => { const t = setInterval(() => setA(x => (x + 1) % MOVES.length), 3600); return () => clearInterval(t); }, []);
  return (
    <a href="method.html" className="reveal" style={{ display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", textDecoration: "none", color: P.ink, padding: `clamp(6px,1vw,12px) ${PAD} clamp(14px,2vw,26px)` }}>
      <div style={{ position: "relative", width: 56, height: 56 }}>
        {MOVES.map((m, i) => (
          <span key={m.t} style={{ position: "absolute", inset: 0, opacity: a === i ? 1 : 0, transform: a === i ? "rotate(0)" : "rotate(-40deg) scale(.85)", transition: "opacity .9s ease, transform 1.2s cubic-bezier(.2,.7,.15,1)" }}>
            <MoveMotif i={i} c={P.soft} size={56} />
          </span>
        ))}
      </div>
      <div style={{ position: "relative", height: "clamp(62px,6vw,74px)", width: "100%", maxWidth: 560, marginTop: 14 }}>
        {MOVES.map((m, i) => (
          <div key={m.t} style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: a === i ? 1 : 0, transform: a === i ? "none" : "translateY(8px)", transition: "opacity .8s ease, transform .9s ease" }}>
            <span className="label" style={{ fontSize: 12, letterSpacing: "0.2em" }}>{m.t} &middot; {m.domain}</span>
            <span className="serif" style={{ fontSize: "clamp(17px,1.6vw,21px)", fontWeight: 300, color: P.soft }}>{m.line}</span>
          </div>
        ))}
      </div>
      <div style={{ display: "flex", gap: 8, marginTop: 6 }}>
        {MOVES.map((m, i) => <span key={m.t} style={{ width: 18, height: 1, background: a === i ? P.ink : P.line, transition: "background .5s ease" }} />)}
      </div>
    </a>
  );
}

/* A: editorial dek, Architectural Digest manner: hairline, italic serif line, small-caps index */
function MoveWord() {
  return (
    <span style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "clamp(12px,1.4vw,16px)" }}>
      <span aria-hidden="true" style={{ width: 36, height: 1, background: P.ink, opacity: 0.5, marginTop: "clamp(12px,1.4vw,18px)" }} />
      <span className="serif ital" style={{ fontSize: "clamp(18px,1.7vw,23px)", fontWeight: 300, color: P.soft, letterSpacing: "0.005em", lineHeight: 1.35 }}>Activate your senses through design.</span>
      <a href="method.html" className="label" style={{ fontSize: 11, letterSpacing: "0.28em", textIndent: "0.14em", color: P.ink, textDecoration: "none", display: "flex", gap: "0.9em", flexWrap: "wrap", justifyContent: "center" }}>
        {MOVES.map((m, i) => <React.Fragment key={m.t}>{i > 0 && <span aria-hidden="true" style={{ color: P.faint }}>&middot;</span>}<span>{m.t}</span></React.Fragment>)}
      </a>
    </span>
  );
}

/* C: one movement set between rows of the work, as a quiet caption */
function MoveCaption({ i }) {
  const m = MOVES[i];
  return (
    <a href="method.html" className="reveal" style={{ gridColumn: "span 12", display: "flex", alignItems: "center", justifyContent: "center", gap: "clamp(12px,1.6vw,20px)", textDecoration: "none", color: P.ink, padding: "clamp(4px,1vw,12px) 0", flexWrap: "wrap", textAlign: "center" }}>
      <MoveMotif i={i} c={P.soft} size={34} />
      <span className="label" style={{ fontSize: 12, letterSpacing: "0.2em" }}>{m.t}</span>
      <span className="serif" style={{ fontSize: "clamp(17px,1.6vw,21px)", fontWeight: 300, color: P.soft }}>{m.line}</span>
    </a>
  );
}

function ProjectsPage() {
  const cat = (new URLSearchParams(location.search).get("cat") || "").toLowerCase();
  const shown = cat ? PROJECTS.filter(p => p.cat.toLowerCase() === cat) : PROJECTS;
  useProjFx(() => {
    const io = new IntersectionObserver((es) => { es.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }); }, { threshold: 0.12 });
    document.querySelectorAll(".reveal").forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);
  return (
    <div className="mk" style={{ ...Pvars, width: "100%", overflowX: "clip" }}>
      <div className="pj-header" style={{ position: "relative", zIndex: 10, padding: `40px ${PAD} 0`, display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
        <HoverMenuLeft color={P.ink} logoSize={30} items={["Interiors", "Services", "About"]} />
        <HoverMenu color={P.ink} items={["Method", "Schedule a call"]} />
      </div>
      <section id="works" className="snap" style={{ position: "relative", minHeight: "auto", display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", textAlign: "center", padding: `clamp(40px,5vw,72px) ${PAD} clamp(28px,3.4vw,44px)`, maxWidth: 1500, margin: "0 auto" }}>
        <div className="reveal" style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
          <div className="label" style={{ fontSize: 12, color: P.soft, letterSpacing: "0.3em", textIndent: "0.15em", marginBottom: "clamp(20px,2.4vw,30px)" }}>Selected Works</div>
          <h1 className="serif" style={{ fontSize: "clamp(24px,2.7vw,38px)", fontWeight: 300, lineHeight: 1.0, margin: 0, letterSpacing: "0.12em", textIndent: "0.06em", maxWidth: "16ch" }}>
            {cat ? cat.charAt(0).toUpperCase() + cat.slice(1) : "Interiors"}
          </h1>
          <div className="journal" style={{ fontSize: "clamp(16px,1.5vw,20px)", color: P.soft, margin: "2px 0 0", maxWidth: 600, lineHeight: 1.5 }}>
            {(window.MV_VARIANT || "word") === "word" ? <MoveWord /> : "Activate your senses through design."}
          </div>
        </div>
      </section>
      <MethodMoves />
      <section style={{ padding: `clamp(20px,2.5vw,36px) ${PAD} clamp(70px,8vw,110px)` }}>
        <div className="pj-grid" style={{ display: "grid", gridTemplateColumns: "repeat(12, minmax(0, 1fr))", gap: "clamp(44px,5.5vw,88px) clamp(28px,3vw,48px)", maxWidth: 1320, margin: "0 auto", alignItems: "start" }}>
          {shown.map((p, i) => {
            const card = <Band key={p.id} p={p} i={i} />;
            // inline variant: a movement after the lead image and after every second row
            const slot = window.MV_VARIANT === "inline" ? (i === 0 ? 0 : (i % 4 === 0 ? i / 4 : -1)) : -1;
            return slot >= 0 && slot < MOVES.length ? [card, <MoveCaption key={"mv" + slot} i={slot} />] : card;
          })}
        </div>
      </section>
      <SiteFooter palette={P} />
    </div>
  );
}
ReactDOM.createRoot(document.getElementById("root")).render(<ProjectsPage />);
