const { useState, useEffect, useRef, useCallback } = React;

const REDUCED = window.matchMedia("(prefers-reduced-motion: reduce)").matches;


/* ------------------------------------------------------------------ */
/*  PROJECT DATA                                                       */
/* ------------------------------------------------------------------ */
const PROJECTS = [
  {
    id: "aarja", name: "AARJA", dot: "#febc2e", img: "assets/folders/aarja.png",
    meta: "Creative Direction · Branding · Social",
    tags: ["Brand Identity", "Packaging", "Meta Ads", "Social Media", "SEO"],
    about: "Aarja is a Hong Kong fine jewelry brand with a hidden layer — each piece doubles as an aromatherapy diffuser, infused with essential oils. Positioned at the intersection of high-design jewelry and mindful living, the brand targets design-conscious urban women who want beautiful things that also do something.",
    problem: "Aarja came to us as a blank canvas. The founders had a product concept but no brand — no name direction, no visual identity, no story, no launch assets.",
    approach: "Blue Dragon served as the full creative agency for the launch: developed the brand concept and positioning, designed the logo and complete visual identity system, defined the color palette, typography, and mood, directed the packaging design, built a 6-week Instagram content calendar, produced editorial product photography, and created all Meta ad creatives — images and video.",
    result: "A complete brand launched in Hong Kong — cohesive identity across packaging, Instagram, and paid social. A content system the brand now runs independently, and a visual language that has held up across every channel since launch.",
    pdfSlides: Array.from({length:19},(_,i)=>`assets/aarja-pdf/page-${i+1}.png`),
    pdfLabel: "Brand Identity",
    metaAds: {
      images: ["assets/aarja-gallery/Ad-Creative-1.png","assets/aarja-gallery/Ad-Creative-3.png","assets/aarja-gallery/Ad-Creative-5.png","assets/aarja-gallery/Ad-Creative-6.png"],
      videos: ["assets/aarja-videos/meta-v1.mov","assets/aarja-videos/meta-v2.mov"],
    },
    videoList: [
      { src: "assets/aarja-videos/reel-1.mp4",  title: "UGC-style review" },
      { src: "assets/aarja-videos/reel-2.mp4",  title: "Aesthetic video" },
      { src: "assets/aarja-videos/reel-3.mov",  title: "Mother's day campaign", fit: "contain" },
      { src: "assets/aarja-videos/reel-4.mov",  title: "Lifestyle short video" },
      { src: "assets/aarja-videos/reel-5.mov",  title: "Sales-y video for mother's day campaign" },
      { src: "assets/aarja-videos/reel-6.mp4",  title: "Lifestyle fashion video" },
    ],
  },
  {
    id: "kodifly", name: "Kodifly", dot: "#0A0F2C", img: "assets/folders/kodifly.png",
    meta: "Deep Tech · LiDAR AI · B2B",
    tags: ["SEO/GEO", "LinkedIn", "Email", "Product Launch", "Content"],
    about: "Kodifly is a Hong Kong deep tech startup building AI + LiDAR tools for construction and infrastructure — SpatialSense (point cloud inspection platform), Sifu (AI WhatsApp-native construction site management), and Trace (field documentation tool for site records and compliance).",
    problem: "Kodifly had three strong AI products but no marketing infrastructure — no SEO presence, no content engine, no outbound sequences, and no launch assets for any of the three products.",
    approach: "Built a full Marketing OS from the ground up: SEO and GEO audits for two products, a 500-idea LinkedIn content engine, weekly editorial calendar, multi-region email sequences in four languages (UAE English, SG/MY English, Hong Kong Traditional Chinese, KSA Arabic), product launch assets for Sifu and Trace including landing page copy rewrites, and a Reddit organic seeding playbook.",
    result: "61 qualified leads generated, 214 KOLs mapped, active LinkedIn pipeline across founders and company page, and launch-ready assets across all three products.",
    metaAds: {
      images: ["assets/kodifly/6.png","assets/kodifly/canto-stresslevel.png","assets/kodifly/complexity-arabic.png","assets/kodifly/reportdone-arabic.png"],
    },
    videoList: [
      { src: "assets/kodifly-videos/trace-launch.mp4", title: "SpatialSense Trace — Product Launch", desc: "Launch video for Trace, Kodifly's field documentation tool that turns site photos, voice notes, and drawings into structured compliance records." },
      { src: "assets/kodifly-videos/sifu-anime.mov",   title: "Sifu — Anime Launch Film",          desc: "Anime-style launch film for Sifu, produced in a Ghost in the Shell / Seinen aesthetic to announce the product to a tech-forward audience." },
      { src: "assets/kodifly-videos/sifu-corporate.mp4",title: "Sifu — Corporate Launch Film",     desc: "Corporate launch video for Sifu, the AI-powered WhatsApp-native construction management platform built for MENA and East Asia." },
    ],
  },
  {
    id: "pipeline", name: "Pipeline Zero", dot: "#28c840", img: "assets/folders/pipeline.png",
    meta: "Fictional Brand · Gen-AI · B2B SaaS",
    tags: ["Brand Creation", "Positioning", "Website", "GTM"],
    about: "Pipeline Zero is a fictional brand created by Blue Dragon — an AI-powered sales operations platform built as a full brand and GTM case study.",
    problem: "The brief: design a credible, technical B2B SaaS brand that could stand alongside real players in the AI sales-ops market — without a single real customer yet.",
    approach: "Built the brand from scratch: name, positioning, visual identity, website copy, and launch visuals.",
    result: "A portfolio-ready brand with a complete GTM narrative — positioning, site, and messaging that hold up against real competitors in the space.",
    pdfSlides: Array.from({length:9},(_,i)=>`assets/pipeline-pdf/page-${i+1}.png`),
    pdfLabel: "Case Study",
  },
  {
    id: "siplog", name: "SIPLOG", dot: "#0047CC", img: "assets/folders/siplog.png",
    meta: "Fictional Brand · Gen-AI · B2C Product",
    tags: ["Brand Creation", "App Launch", "Video", "Paid Social"],
    about: "SIPLOG is a fictional brand created by Blue Dragon — a consumer hydration-tracking product built as a full brand and product launch case study.",
    problem: "The brief: launch a consumer wellness product that feels premium and specific, not another generic health tracker.",
    approach: "End-to-end launch: brand voice, visual identity, and launch visuals.",
    result: "A complete launch playbook — brand, creative, and channel strategy — built as a proof of concept for Blue Dragon's consumer product capabilities.",
    pdfSlides: Array.from({length:11},(_,i)=>`assets/siplog-pdf/page-${i+1}.png`),
    pdfLabel: "Case Study",
  },
  {
    id: "calmform", name: "Calmform", dot: "#ff5f57", img: "assets/folders/calmform.png",
    meta: "Fictional Brand · Gen-AI · Skincare",
    tags: ["Brand Creation", "Visual Identity", "Social Media", "AI Content"],
    about: "Calmform is a fictional brand created by Blue Dragon — a clinical skincare brand built as a full identity and social media case study.",
    problem: "The brief: build a skincare brand that reads clinical and calm without feeling pharmaceutical — designed for a daily social media cadence without a big team behind it.",
    approach: "Built a serene visual system and an AI-assisted content pipeline: brand identity, tone of voice, and a repeatable production process for daily output.",
    result: "A fully operational content engine — consistent daily output, 40% lift in saved posts, and a visual identity that scales across formats.",
    pdfSlides: Array.from({length:9},(_,i)=>`assets/calmform-pdf/page-${i+1}.png`),
    pdfLabel: "Case Study",
  },
];

/* positions of folders scattered across the hills (% of work section) */
const FOLDER_POS = [
  { left: "14%", top: "12%" },
  { left: "55%", top: "6%" },
  { left: "78%", top: "28%" },
  { left: "28%", top: "46%" },
  { left: "66%", top: "52%" },
];

/* ------------------------------------------------------------------ */
/*  WORLD — continuous sky→hills parallax wallpaper                    */
/* ------------------------------------------------------------------ */
function Cloud({ style }) {
  return <div className="cloud" style={style} />;
}

function World() {
  const sceneRef = useRef(null);   // the wallpaper image (panned on scroll = descent)

  useEffect(() => {
    if (REDUCED) return;
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const max = Math.max(1, document.body.scrollHeight - window.innerHeight);
        const p = Math.min(1, Math.max(0, window.scrollY / max)); // 0..1 descent
        const vh = window.innerHeight;
        // image is 150vh tall; pan from top (sky) down to bottom (grass)
        if (sceneRef.current) sceneRef.current.style.transform = `translateY(${-p * vh * 0.5}px)`;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  if (REDUCED) {
    return (
      <div style={{ position: "sticky", top: 0, height: "100vh", overflow: "hidden", zIndex: 0,
        backgroundImage: "url(assets/wallpaper.jpg)", backgroundSize: "cover", backgroundPosition: "center 35%" }} aria-hidden="true" />
    );
  }

  return (
    <div style={{ position: "sticky", top: 0, height: "100vh", overflow: "hidden", zIndex: 0, background: "#4f8fd1" }} aria-hidden="true">
      <div ref={sceneRef} style={{
        position: "absolute", left: "-3%", top: 0, width: "106%", height: "150vh",
        backgroundImage: "url(assets/wallpaper.jpg)", backgroundSize: "cover", backgroundPosition: "center top",
        willChange: "transform",
      }} />
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  FOLDER ICON (bright macOS blue)                                    */
/* ------------------------------------------------------------------ */
function FolderIcon() {
  return (
    <svg className="folder-icon" viewBox="0 0 120 96" fill="none">
      <defs>
        <linearGradient id="ftab" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="var(--folder-tab)" /><stop offset="1" stopColor="var(--folder-top)" />
        </linearGradient>
        <linearGradient id="fbody" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor="var(--folder-top)" /><stop offset="1" stopColor="var(--folder-bot)" />
        </linearGradient>
      </defs>
      <path d="M8 20 q0-8 8-8 h26 q5 0 8 5 l4 7 h-46 Z" fill="url(#ftab)" />
      <rect x="6" y="22" width="108" height="66" rx="11" fill="url(#fbody)" />
      <rect x="6" y="22" width="108" height="24" rx="11" fill="#ffffff" opacity="0.14" />
    </svg>
  );
}

/* ------------------------------------------------------------------ */
/*  META ADS CAROUSEL (plain, fitted to frame)                        */
/* ------------------------------------------------------------------ */
function useSwipe(onPrev, onNext) {
  const t = useRef(null);
  return {
    onTouchStart: (e) => { t.current = e.touches[0].clientX; },
    onTouchEnd:   (e) => {
      if (t.current === null) return;
      const dx = e.changedTouches[0].clientX - t.current;
      if (dx > 50) onPrev();
      else if (dx < -50) onNext();
      t.current = null;
    },
  };
}

function MetaAdsCarousel({ metaAds }) {
  const items = [
    ...(metaAds.images||[]).map(src=>({ type:"image", src })),
    ...(metaAds.videos||[]).map(src=>({ type:"video", src })),
  ];
  const [idx, setIdx] = useState(0);
  const cur = items[idx];
  const prev = () => setIdx(i => Math.max(0, i-1));
  const next = () => setIdx(i => Math.min(items.length-1, i+1));
  const swipe = useSwipe(prev, next);
  return (
    <div style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:12, padding:"8px 0 4px" }}>
      <div style={{ width:"100%", position:"relative" }} {...swipe}>
        {cur.type === "image"
          ? <img src={cur.src} alt="" style={{ width:"100%", maxHeight:"44vh", objectFit:"contain", display:"block", borderRadius:10 }} />
          : <video src={cur.src} controls muted playsInline
              style={{ width:"100%", maxHeight:"44vh", display:"block", borderRadius:10, background:"#000" }} />
        }
      </div>
      <div style={{ display:"flex", alignItems:"center", gap:10 }}>
        <button className="carousel-nav" onClick={prev} style={{ opacity:idx===0?0.3:1 }}>←</button>
        <div style={{ display:"flex", gap:6 }}>
          {items.map((_,i)=>(
            <div key={i} onClick={()=>setIdx(i)} style={{ width:7, height:7, borderRadius:"50%", cursor:"pointer",
              background:i===idx?"var(--cobalt)":"rgba(10,23,40,.2)", transition:"background .15s" }} />
          ))}
        </div>
        <button className="carousel-nav" onClick={next} style={{ opacity:idx===items.length-1?0.3:1 }}>→</button>
      </div>
      <span style={{ fontFamily:"var(--ui)", fontSize:11, color:"rgba(10,23,40,.4)" }}>{idx+1} of {items.length}</span>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  VIDEO CAROUSEL (plain, no phone mockup)                            */
/* ------------------------------------------------------------------ */
function VideoCarousel({ videos }) {
  const [idx, setIdx] = useState(0);
  const v = videos[idx];
  const prev = () => setIdx(i => Math.max(0, i-1));
  const next = () => setIdx(i => Math.min(videos.length-1, i+1));
  const swipe = useSwipe(prev, next);
  return (
    <div style={{ display:"flex", flexDirection:"column", alignItems:"center", gap:10, padding:"8px 0 4px" }}>
      <div style={{ width:"100%", position:"relative" }} {...swipe}>
        <video key={v.src} src={v.src} controls muted playsInline
          style={{ width:"100%", maxHeight:"44vh", display:"block", borderRadius:10, background:"#000" }} />
      </div>
      {v.title && <p style={{ fontFamily:"var(--ui)", fontSize:13, fontWeight:600, color:"var(--navy)", margin:0, textAlign:"center" }}>{v.title}</p>}
      {v.desc  && <p style={{ fontFamily:"var(--ui)", fontSize:12, color:"rgba(10,23,40,.55)", margin:"2px 0 0", textAlign:"center", lineHeight:1.45, padding:"0 8px" }}>{v.desc}</p>}
      <div style={{ display:"flex", alignItems:"center", gap:10 }}>
        <button className="carousel-nav" onClick={prev} style={{ opacity:idx===0?0.3:1 }}>←</button>
        <div style={{ display:"flex", gap:6 }}>
          {videos.map((_,i)=>(
            <div key={i} onClick={()=>setIdx(i)} style={{ width:7, height:7, borderRadius:"50%", cursor:"pointer",
              background:i===idx?"var(--cobalt)":"rgba(10,23,40,.2)", transition:"background .15s" }} />
          ))}
        </div>
        <button className="carousel-nav" onClick={next} style={{ opacity:idx===videos.length-1?0.3:1 }}>→</button>
      </div>
      <span style={{ fontFamily:"var(--ui)", fontSize:11, color:"rgba(10,23,40,.4)" }}>{idx+1} of {videos.length}</span>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  PROJECT WINDOW (draggable, data-driven tabs, esc-dismiss)          */
/* ------------------------------------------------------------------ */
function ProjectWindow({ project, onClose }) {
  const tabs = [{ id: "case-study", label: "About" }];
  if (project.pdfSlides?.length)   tabs.push({ id: "pdf",       label: project.pdfLabel || "PDF" });
  if (project.metaAds)             tabs.push({ id: "meta-ads",  label: "Meta Ads" });
  if (project.videoList?.length)   tabs.push({ id: "videos",    label: "Videos" });

  const [tab, setTab] = useState("case-study");
  const [pdfPage, setPdfPage] = useState(0);
  const winRef = useRef(null);
  const drag = useRef(null);
  const isMobile = window.matchMedia("(max-width: 720px)").matches;

  useEffect(() => {
    if (isMobile || !winRef.current) return;
    const el = winRef.current;
    const r = el.getBoundingClientRect();
    el.style.left = Math.max(16, (window.innerWidth - r.width) / 2) + "px";
    el.style.top = Math.max(40, (window.innerHeight - r.height) / 2 - 20) + "px";
  }, []);

  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  const onTitleDown = (e) => {
    if (isMobile) return;
    const el = winRef.current;
    const r = el.getBoundingClientRect();
    drag.current = { dx: e.clientX - r.left, dy: e.clientY - r.top };
    const move = (ev) => {
      if (!drag.current) return;
      el.style.left = (ev.clientX - drag.current.dx) + "px";
      el.style.top = Math.max(8, ev.clientY - drag.current.dy) + "px";
    };
    const up = () => { drag.current = null; window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
  };

  const renderContent = () => {
    if (tab === "case-study") return (
      <div className="case">
        {project.about && <><h4>About</h4><p>{project.about}</p></>}
        <h4>Brief</h4><p>{project.problem}</p>
        <h4>What We Built</h4><p>{project.approach}</p>
        <h4>Outcome</h4><p>{project.result}</p>
        <div className="tagrow">{project.tags.map(t => <span className="tag" key={t}>{t}</span>)}</div>
      </div>
    );

    if (tab === "pdf") {
      const slides = project.pdfSlides;
      return (
        <div>
          <img src={slides[pdfPage]} alt={`Slide ${pdfPage+1}`}
            style={{ maxHeight:"calc(60vh - 90px)", width:"auto", maxWidth:"100%", display:"block", margin:"0 auto" }} />
          <div style={{ display:"flex", alignItems:"center", justifyContent:"center", gap:14, padding:"12px 0 6px", borderTop:"1px solid rgba(10,23,40,.08)" }}>
            <button className="carousel-nav" onClick={() => setPdfPage(p => Math.max(0,p-1))} style={{ opacity: pdfPage===0 ? 0.3 : 1 }}>← Prev</button>
            <span style={{ fontFamily:"var(--ui)", fontSize:13, color:"rgba(10,23,40,.55)", minWidth:52, textAlign:"center" }}>{pdfPage+1} / {slides.length}</span>
            <button className="carousel-nav" onClick={() => setPdfPage(p => Math.min(slides.length-1,p+1))} style={{ opacity: pdfPage===slides.length-1 ? 0.3 : 1 }}>Next →</button>
          </div>
        </div>
      );
    }

    if (tab === "meta-ads") return <MetaAdsCarousel metaAds={project.metaAds} />;

    if (tab === "videos") {
      const vids = project.videoList;
      return <VideoCarousel videos={vids} />;
    }
  };

  return (
    <React.Fragment>
      <div className="scrim" onClick={onClose} />
      <div className="win" ref={winRef} role="dialog" aria-modal="true" aria-label={project.name + " case study"}>
        <div className="titlebar" onMouseDown={onTitleDown}>
          <div className="lights">
            <button className="light red" aria-label="Close window" onClick={onClose} />
            <button className="light yellow" aria-label="Minimize" tabIndex={-1} />
            <button className="light green" aria-label="Zoom" tabIndex={-1} />
          </div>
          <span className="win-title">{project.name} — {project.meta}</span>
        </div>
        <div className="seg" role="tablist">
          {tabs.map(t => (
            <button key={t.id} role="tab" aria-selected={tab===t.id} className={tab===t.id?"on":""} onClick={() => { setTab(t.id); setPdfPage(0); }}>{t.label}</button>
          ))}
        </div>
        <div className="win-body">
          <div className="tabwrap">{renderContent()}</div>
        </div>
      </div>
    </React.Fragment>
  );
}

/* ------------------------------------------------------------------ */
/*  README WINDOW — green light expands to reveal more                 */
/* ------------------------------------------------------------------ */
function ReadmeWindow() {
  const [expanded, setExpanded] = useState(false);
  return (
    <div className="win readme-win" style={{ position: "relative", width: expanded ? "min(420px, 100%)" : "min(320px, 100%)", animation: "none", left: "auto", top: "auto", transition: "width .34s cubic-bezier(.2,.9,.25,1.1)" }}>
      <div className="titlebar" style={{ cursor: "default" }}>
        <div className="lights">
          <span className="light red" />
          <span className="light yellow" />
          <button
            className="light green"
            aria-label={expanded ? "Collapse readme" : "Expand readme"}
            aria-expanded={expanded}
            onClick={() => setExpanded((v) => !v)}
            title="Zoom"
          />
        </div>
        <span className="win-title">readme.txt</span>
      </div>
      <div style={{ padding: "16px 18px", fontFamily: "var(--ui)", fontSize: 14, lineHeight: 1.55, color: "rgba(10,23,40,.8)" }}>
        Hi — I'm <b>Madina</b>. I help B2B tech founders launch, position and grow. Open a folder below to see the work.
        <div style={{ display: "grid", gridTemplateRows: expanded ? "1fr" : "0fr", transition: "grid-template-rows .34s cubic-bezier(.2,.9,.25,1.1)" }}>
          <div style={{ overflow: "hidden" }}>
            <div style={{ paddingTop: 12, marginTop: 12, borderTop: "1px solid rgba(10,23,40,.1)" }}>
              I run <b>Blue Dragon</b> — an AI-powered B2B marketing studio based in Hong Kong. Strategy plus AI-assisted execution, so the work starts compounding in days, not months.
              <br /><br />
              From brand to launch to growth, it's end-to-end and hands-on. <span style={{ color: "var(--cobalt)", fontWeight: 550 }}>Tap a folder, or AirDrop me your idea below. ↓</span>
            </div>
          </div>
        </div>
      </div>
      <div style={{ padding: "0 18px 14px", fontFamily: "ui-monospace, 'SF Mono', Menlo, monospace", fontSize: 11, color: "rgba(10,23,40,.4)" }}>
        {expanded ? "▼ click green again to collapse" : "● click the green dot to read more"}
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/*  HERO                                                               */
/* ------------------------------------------------------------------ */
function Hero({ showHint }) {
  return (
    <section style={{ minHeight: "100vh", padding: "clamp(60px,10vh,150px) clamp(20px,7vw,80px) 0", position: "relative" }}>
      <div style={{ maxWidth: 1100, margin: "0 auto" }}>
        <div style={{ marginBottom: 28 }}>
          <span style={{ fontWeight: 650, fontSize: 15, letterSpacing:"-.01em" }}>Blue Dragon Marketing</span>
        </div>

        <h1 className="display" style={{ fontSize: "clamp(44px, 8.4vw, 116px)", margin: "0 0 26px", maxWidth: "16ch" }}>
          Marketing with <span className="ios-select"><span style={{ fontFamily: '"Instrument Serif", serif', fontStyle: "italic", fontWeight: 400 }}>taste.</span><span className="sel-handle start"></span><span className="sel-handle end"></span></span><br />Powered by AI.
        </h1>

        <p style={{ fontSize: "clamp(17px,2.1vw,23px)", lineHeight: 1.5, maxWidth: "34ch", color:"rgba(10,23,40,.86)", fontWeight: 450, margin: 0 }}>
          End-to-end marketing for B2B tech startups. Built on AI. Delivered fast.
        </p>

        <div style={{ marginTop: 54 }}>
          <ReadmeWindow />
        </div>
      </div>

      {showHint && (
        <div className="scroll-hint">
          <span>Scroll to descend</span>
          <svg width="20" height="20" viewBox="0 0 20 20"><path d="M4 7 L10 13 L16 7" stroke="rgba(10,23,40,.6)" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
      )}
    </section>
  );
}

/* ------------------------------------------------------------------ */
/*  WORK                                                               */
/* ------------------------------------------------------------------ */
const EDGE_THRESHOLD = 80;

function Work({ onOpen }) {
  const [offsets, setOffsets] = useState(PROJECTS.map(() => ({ dx: 0, dy: 0 })));
  const [edgeGlow, setEdgeGlow] = useState({ top: 0, right: 0, bottom: 0, left: 0 });
  const drag = useRef(null);
  const lastMoved = useRef(false);
  const containerRef = useRef(null);

  useEffect(() => {
    const onMove = (e) => {
      if (!drag.current) return;
      const rawDx = e.clientX - drag.current.startX + drag.current.initDx;
      const rawDy = e.clientY - drag.current.startY + drag.current.initDy;
      const dx = Math.min(drag.current.maxDx, Math.max(drag.current.minDx, rawDx));
      const dy = Math.min(drag.current.maxDy, Math.max(drag.current.minDy, rawDy));
      drag.current.moved = Math.abs(e.clientX - drag.current.startX) > 4 || Math.abs(e.clientY - drag.current.startY) > 4;
      const idx = drag.current.idx;
      setOffsets(prev => prev.map((o, i) => i === idx ? { dx, dy } : o));
      setEdgeGlow({
        left:   isFinite(drag.current.minDx) ? Math.max(0, 1 - (dx - drag.current.minDx) / EDGE_THRESHOLD) : 0,
        right:  isFinite(drag.current.maxDx) ? Math.max(0, 1 - (drag.current.maxDx - dx) / EDGE_THRESHOLD) : 0,
        top:    isFinite(drag.current.minDy) ? Math.max(0, 1 - (dy - drag.current.minDy) / EDGE_THRESHOLD) : 0,
        bottom: isFinite(drag.current.maxDy) ? Math.max(0, 1 - (drag.current.maxDy - dy) / EDGE_THRESHOLD) : 0,
      });
    };
    const onUp = () => {
      if (drag.current) lastMoved.current = drag.current.moved;
      drag.current = null;
      setEdgeGlow({ top: 0, right: 0, bottom: 0, left: 0 });
    };
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
    return () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
    };
  }, []);

  const isMobile = window.innerWidth <= 720;

  if (isMobile) {
    return (
      <section id="work" style={{ padding: "56px 20px", position: "relative" }}>
        <div style={{ maxWidth: 1100, margin: "0 auto" }}>
          <span style={{ fontFamily:"var(--ui)", fontSize:13, fontWeight:600, letterSpacing:".09em", textTransform:"uppercase", color:"var(--cobalt)" }}>/ Work</span>
          <h2 className="display" style={{ fontSize:"clamp(28px,7vw,44px)", margin:"8px 0 6px" }}>Selected projects</h2>
          <p style={{ fontFamily:"var(--ui)", fontSize:15, color:"rgba(10,23,40,.7)", margin:"0 0 28px" }}>
            Tap a folder to open.
          </p>
          <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:28 }}>
            {PROJECTS.map(p => (
              <button key={p.id} className="folder-btn" onClick={() => onOpen(p)} aria-label={"Open " + p.name}>
                <img className="folder-icon" src={p.img} alt="" draggable={false} />
                <span className="folder-label"><span className="status-dot" style={{ background:p.dot }} />{p.name}</span>
                <span className="folder-meta">{p.meta}</span>
              </button>
            ))}
          </div>
        </div>
      </section>
    );
  }

  return (
    <section id="work" style={{ minHeight: "118vh", padding: "10vh 7vw 18vh", position: "relative" }}>
      <div style={{ maxWidth: 1100, margin: "0 auto", position:"relative" }}>
        <div style={{ display:"flex", alignItems:"baseline", gap:14, marginBottom: 8 }}>
          <span style={{ fontFamily:"var(--ui)", fontSize:13, fontWeight:600, letterSpacing:".09em", textTransform:"uppercase", color:"var(--cobalt)" }}>/ Work</span>
        </div>
        <h2 className="display" style={{ fontSize:"clamp(34px,5.2vw,68px)", margin:"0 0 6px" }}>Selected projects</h2>
        <p style={{ fontFamily:"var(--ui)", fontSize:16, color:"rgba(10,23,40,.7)", maxWidth:"40ch", margin:0 }}>
          Scattered across the hills. Drag to rearrange — double-click to open.
        </p>

        <div ref={containerRef} style={{ position:"relative", height: "min(620px, 78vh)", marginTop: 40, overflow: "hidden" }}>
          {[
            { side: "top",    style: { top:0, left:0, right:0, height:90, background:"linear-gradient(to bottom, rgba(220,50,50,0.45), transparent)" } },
            { side: "bottom", style: { bottom:0, left:0, right:0, height:90, background:"linear-gradient(to top, rgba(220,50,50,0.45), transparent)" } },
            { side: "left",   style: { left:0, top:0, bottom:0, width:90, background:"linear-gradient(to right, rgba(220,50,50,0.45), transparent)" } },
            { side: "right",  style: { right:0, top:0, bottom:0, width:90, background:"linear-gradient(to left, rgba(220,50,50,0.45), transparent)" } },
          ].map(({ side, style }) => (
            <div key={side} style={{ position:"absolute", pointerEvents:"none", zIndex:20, opacity: edgeGlow[side], transition:"opacity 0.08s", ...style }} />
          ))}
          {PROJECTS.map((p, i) => (
            <div key={p.id} style={{
              position: "absolute",
              ...FOLDER_POS[i],
              transform: `translate(${offsets[i].dx}px, ${offsets[i].dy}px)`,
              userSelect: "none",
            }}>
              <button
                className="folder-btn"
                onMouseDown={(e) => {
                  e.preventDefault();
                  const container = containerRef.current?.getBoundingClientRect();
                  const folder = e.currentTarget.parentElement?.getBoundingClientRect();
                  let minDx = -Infinity, maxDx = Infinity, minDy = -Infinity, maxDy = Infinity;
                  if (container && folder) {
                    minDx = offsets[i].dx + (container.left - folder.left);
                    maxDx = offsets[i].dx + (container.right - folder.right);
                    minDy = offsets[i].dy + (container.top - folder.top);
                    maxDy = offsets[i].dy + (container.bottom - folder.bottom);
                  }
                  drag.current = {
                    idx: i,
                    startX: e.clientX,
                    startY: e.clientY,
                    initDx: offsets[i].dx,
                    initDy: offsets[i].dy,
                    moved: false,
                    minDx, maxDx, minDy, maxDy,
                  };
                }}
                onDoubleClick={() => { if (!lastMoved.current) onOpen(p); }}
                aria-label={"Open " + p.name}
              >
                <img className="folder-icon" src={p.img} alt="" draggable={false} />
                <span className="folder-label"><span className="status-dot" style={{ background:p.dot }} />{p.name}</span>
                <span className="folder-meta">{p.meta}</span>
              </button>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ------------------------------------------------------------------ */
/*  DOCK                                                               */
/* ------------------------------------------------------------------ */
function Dock() {
  const items = [["Work","work"],["Services","services"],["About","about"],["Tools","tools"],["Contact","contact"]];
  const go = (id) => {
    const el = document.getElementById(id);
    if (el) window.scrollTo({ top: el.offsetTop - 30, behavior: REDUCED ? "auto" : "smooth" });
  };
  return (
    <nav className="dock" aria-label="Primary">
      {items.map(([label, id]) => <button key={id} className="dock-item" onClick={() => go(id)}>{label}</button>)}
    </nav>
  );
}

/* ------------------------------------------------------------------ */
/*  APP                                                                */
/* ------------------------------------------------------------------ */
function App() {
  const [open, setOpen] = useState(null);
  const [showHint, setShowHint] = useState(true);
  useEffect(() => {
    const onScroll = () => {
      const remaining = document.body.scrollHeight - window.scrollY - window.innerHeight;
      setShowHint(remaining > 200);
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return (
    <React.Fragment>
      <World />
      <div style={{ position: "relative", zIndex: 1, marginTop: "-100vh" }}>
        <Hero showHint={showHint} />
        <Work onOpen={setOpen} />
        <Services />
        <About />
        <Tools />
        <Contact />
        <Footer />
      </div>
      <Dock />
      {open && <ProjectWindow project={open} onClose={() => setOpen(null)} />}
    </React.Fragment>
  );
}

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