/* global React */
const { useState, useEffect, useRef, useMemo } = React;

// ============ TWEAK DEFAULTS ============
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "paper",
  "accent": "#2b4efd",
  "typeFamily": "editorial",
  "heroLayout": "split",
  "gridLayout": "asymmetric",
  "density": "comfortable",
  "tone": "confident",
  "darkMode": false
}/*EDITMODE-END*/;

// ============ THEMES ============
const THEMES = {
  ivory:    { bg: "#F5F1EA", fg: "#1A1A1A", muted: "#8A8478", line: "#1A1A1A", card: "#EFEAE0" },
  paper:    { bg: "#FFFFFF", fg: "#0A0A0A", muted: "#777", line: "#0A0A0A", card: "#F5F5F5" },
  ink:      { bg: "#0E0E0E", fg: "#F5F1EA", muted: "#8A8478", line: "#F5F1EA", card: "#1A1A1A" },
  graphite: { bg: "#1C1C1E", fg: "#E8E6E1", muted: "#8E8E93", line: "#E8E6E1", card: "#2A2A2C" },
  bone:     { bg: "#E8E2D5", fg: "#2A2520", muted: "#8C8478", line: "#2A2520", card: "#DED7C7" },
};

const TYPE_FAMILIES = {
  editorial: { display: '"Fraunces", "Playfair Display", Georgia, serif', body: '"Inter", -apple-system, sans-serif', mono: '"JetBrains Mono", monospace', displayWeight: 400, displayTracking: "-0.03em" },
  swiss:     { display: '"Inter Tight", "Helvetica Neue", sans-serif', body: '"Inter", -apple-system, sans-serif', mono: '"JetBrains Mono", monospace', displayWeight: 500, displayTracking: "-0.04em" },
  mono:      { display: '"JetBrains Mono", "IBM Plex Mono", monospace', body: '"JetBrains Mono", monospace', mono: '"JetBrains Mono", monospace', displayWeight: 500, displayTracking: "-0.02em" },
  warm:      { display: '"Instrument Serif", "Cormorant Garamond", serif', body: '"Inter", sans-serif', mono: '"JetBrains Mono", monospace', displayWeight: 400, displayTracking: "-0.02em" },
};

// ============ CONTENT ============
const PROJECTS = [
  {
    id: 1,
    num: "01",
    title: "Lumen Health",
    client: "Lumen Inc.",
    year: "2025",
    role: "Lead Product Designer",
    tags: ["Product", "Health", "Mobile"],
    desc: "Reimagined the patient onboarding flow for a telehealth platform serving 2M+ users — reducing time-to-first-appointment by 64%.",
    color: "#E8DCC4",
    accent: "#3D5A47",
  },
  {
    id: 2,
    num: "02",
    title: "Kindred Bank",
    client: "Kindred Financial",
    year: "2024",
    role: "Senior UX Designer",
    tags: ["Fintech", "Web", "Design System"],
    desc: "Built the design system and core dashboard for a community-first banking platform. From component library to investor demo.",
    color: "#1A2332",
    accent: "#D4A574",
  },
  {
    id: 3,
    num: "03",
    title: "Field Notes Co.",
    client: "Field Notes",
    year: "2024",
    role: "Brand & Digital",
    tags: ["E-commerce", "Brand", "Web"],
    desc: "Editorial-driven storefront for an artisan stationery brand. Doubled conversion through narrative product pages and curated collections.",
    color: "#C8AB7F",
    accent: "#2A1F18",
  },
];

const SERVICES = [
  { num: "01", name: "Product Design", desc: "End-to-end product strategy, user research, and interaction design for digital platforms." },
  { num: "02", name: "Design Systems", desc: "Scalable component libraries and design tokens that bridge design and engineering teams." },
  { num: "03", name: "Brand & Identity", desc: "Visual identity systems for digital-first brands — from wordmarks to motion." },
  { num: "04", name: "Design Leadership", desc: "Fractional design direction, team coaching, and process design for Series A–C startups." },
];

const EXPERIENCE = [
  { years: "2023 — Now", role: "Principal Designer", company: "Independent Practice" },
  { years: "2020 — 2023", role: "Senior Product Designer", company: "Stripe" },
  { years: "2018 — 2020", role: "Product Designer", company: "Figma" },
  { years: "2016 — 2018", role: "Designer", company: "IDEO" },
];

const TESTIMONIALS = [
  { quote: "Alex translates ambiguity into design with a rigor that's rare. Our team's velocity tripled within a quarter of working together.", author: "Maya Chen", role: "VP Product, Lumen" },
  { quote: "One of the sharpest design minds I've collaborated with. Strategic, hands-on, and deeply considered.", author: "Daniel Park", role: "CEO, Kindred Bank" },
];

const WRITING = [
  { date: "Mar 2026", title: "Designing for trust in financial products", read: "8 min" },
  { date: "Jan 2026", title: "The case for slower onboarding", read: "5 min" },
  { date: "Nov 2025", title: "What I learned building 4 design systems", read: "12 min" },
];

const TONE_VARIATIONS = {
  confident: {
    eyebrow: "Independent Designer · Available Q3 2026",
    headline: ["Designing", "considered", "Designing", "ambitious teams."],
    sub: "I'm a product designer with a decade of practice — partnering with founders and product leaders to ship interfaces that earn trust and clarity.",
    nowText: "Building a design system for a Series B fintech, writing a long essay on calm interfaces, and learning ceramics on weekends.",
  },
  warm: {
    eyebrow: "Hello — Designer based in Brooklyn",
    headline: ["Crafting", "thoughtful", "digital things", "with care."],
    sub: "I design products for people. After ten years inside teams at Stripe, Figma, and IDEO, I now work independently with founders I admire.",
    nowText: "Currently helping a small fintech think through their first design system — and slowly making my way through a stack of design books.",
  },
  direct: {
    eyebrow: "Designer · NYC · Open for projects",
    headline: ["Product", "design.", "Made", "deliberately."],
    sub: "Ten years of product design. Four years inside Stripe and Figma. Now independent. I work with three clients at a time, deeply.",
    nowText: "Design system for a fintech. Essay in progress. Open to one more project starting July.",
  },
};

// ============ COMPONENTS ============

function CursorFollower({ theme }) {
  const ref = useRef(null);
  const [hovering, setHovering] = useState(false);
  useEffect(() => {
    const move = (e) => {
      if (ref.current) {
        ref.current.style.transform = `translate(${e.clientX}px, ${e.clientY}px) translate(-50%, -50%) scale(${hovering ? 2.5 : 1})`;
      }
    };
    const over = (e) => {
      const t = e.target;
      if (t.closest && t.closest("[data-cursor='view']")) setHovering(true);
      else setHovering(false);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseover", over);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseover", over);
    };
  }, [hovering]);
  return (
    <div
      ref={ref}
      style={{
        position: "fixed",
        top: 0,
        left: 0,
        width: 14,
        height: 14,
        borderRadius: "50%",
        background: theme.fg,
        mixBlendMode: "difference",
        pointerEvents: "none",
        zIndex: 9999,
        transition: "transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1)",
        willChange: "transform",
      }}
    />
  );
}

function Reveal({ children, delay = 0, as: Tag = "div", style = {}, ...rest }) {
  const ref = useRef(null);
  const [shown, setShown] = useState(false);
  useEffect(() => {
    const obs = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => { if (e.isIntersecting) { setShown(true); obs.disconnect(); } });
      },
      { threshold: 0.12 }
    );
    if (ref.current) obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  return (
    <Tag
      ref={ref}
      style={{
        opacity: shown ? 1 : 0,
        transform: shown ? "translateY(0)" : "translateY(24px)",
        transition: `opacity 0.9s cubic-bezier(0.2, 0.9, 0.3, 1) ${delay}s, transform 0.9s cubic-bezier(0.2, 0.9, 0.3, 1) ${delay}s`,
        ...style,
      }}
      {...rest}
    >
      {children}
    </Tag>
  );
}

function Marquee({ items, theme, type }) {
  const content = items.join(" — ");
  return (
    <div style={{
      borderTop: `1px solid ${theme.line}`,
      borderBottom: `1px solid ${theme.line}`,
      overflow: "hidden",
      whiteSpace: "nowrap",
      padding: "20px 0",
      fontFamily: type.display,
      fontWeight: type.displayWeight,
      letterSpacing: type.displayTracking,
      fontSize: "clamp(20px, 2.6vw, 38px)",
      lineHeight: 1,
    }}>
      <div style={{
        display: "inline-block",
        animation: "marquee 32s linear infinite",
        paddingRight: 40,
      }}>
        {[0, 1, 2].map((i) => <span key={i} style={{ paddingRight: 40 }}>{content} — </span>)}
      </div>
    </div>
  );
}

function ProfilePicture({ theme, accent, size = 180 }) {
  return (
    <div style={{
      width: size,
      height: size,
      borderRadius: "50%",
      overflow: "hidden",
      position: "relative",
      flexShrink: 0,
      background: `linear-gradient(135deg, ${accent}25 0%, ${theme.card} 60%)`,
      border: `1px solid ${theme.line}30`,
      boxShadow: `0 12px 40px ${theme.fg}15`,
    }}>
      <svg viewBox="0 0 200 200" style={{ width: "100%", height: "100%", display: "block" }}>
        <defs>
          <radialGradient id="pp-bg" cx="50%" cy="35%" r="70%">
            <stop offset="0%" stopColor={accent} stopOpacity="0.18" />
            <stop offset="100%" stopColor={accent} stopOpacity="0" />
          </radialGradient>
          <linearGradient id="pp-skin" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stopColor={theme.fg} stopOpacity="0.12" />
            <stop offset="100%" stopColor={theme.fg} stopOpacity="0.22" />
          </linearGradient>
        </defs>
        <rect width="200" height="200" fill="url(#pp-bg)" />
        {/* Shoulders */}
        <path d="M 25 200 Q 25 145 60 130 L 140 130 Q 175 145 175 200 Z" fill={accent} opacity="0.35" />
        {/* Neck */}
        <rect x="86" y="115" width="28" height="25" fill="url(#pp-skin)" />
        {/* Head */}
        <ellipse cx="100" cy="85" rx="38" ry="44" fill="url(#pp-skin)" />
        {/* Hair */}
        <path d="M 62 78 Q 62 45 100 42 Q 138 45 138 78 Q 138 60 120 55 Q 105 62 88 58 Q 70 62 62 78 Z" fill={theme.fg} opacity="0.55" />
        {/* Subtle facial features */}
        <circle cx="88" cy="88" r="1.6" fill={theme.fg} opacity="0.55" />
        <circle cx="112" cy="88" r="1.6" fill={theme.fg} opacity="0.55" />
        <path d="M 92 102 Q 100 106 108 102" stroke={theme.fg} strokeWidth="1.2" fill="none" opacity="0.4" strokeLinecap="round" />
      </svg>
    </div>
  );
}

function Hero({ theme, type, accent, layout, tone }) {
  const t = TONE_VARIATIONS[tone] || TONE_VARIATIONS.confident;

  if (layout === "centered") {
    return (
      <section style={{ padding: "140px 6vw 100px", textAlign: "center" }}>
        <Reveal style={{ display: "flex", justifyContent: "center", marginBottom: 40 }}>
          <ProfilePicture theme={theme} accent={accent} size={140} />
        </Reveal>
        <Reveal delay={0.05} style={{ fontSize: 13, fontFamily: type.mono, letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 60, color: theme.muted }}>
          {t.eyebrow}
        </Reveal>
        <Reveal delay={0.1} as="h1" style={{
          fontFamily: type.display,
          fontWeight: type.displayWeight,
          letterSpacing: type.displayTracking,
          fontSize: "clamp(56px, 10vw, 180px)",
          lineHeight: 0.95,
          margin: 0,
          color: theme.fg,
        }}>
          {t.headline.map((w, i) => (
            <span key={i} style={{ display: "block" }}>
              {i === 1 ? <em style={{ fontStyle: "italic", color: accent }}>{w}</em> : w}
            </span>
          ))}
        </Reveal>
        <Reveal delay={0.2} style={{
          fontFamily: type.body,
          fontSize: 19,
          lineHeight: 1.55,
          maxWidth: 560,
          margin: "60px auto 0",
          color: theme.muted,
        }}>
          {t.sub}
        </Reveal>
      </section>
    );
  }

  if (layout === "stacked") {
    return (
      <section style={{ padding: "100px 6vw 80px" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 60, fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, gap: 24 }}>
          <Reveal style={{ display: "flex", alignItems: "center", gap: 20 }}>
            <ProfilePicture theme={theme} accent={accent} size={72} />
            <span>{t.eyebrow}</span>
          </Reveal>
          <Reveal delay={0.1}>↳ Scroll for selected work</Reveal>
        </div>
        <Reveal as="h1" style={{
          fontFamily: type.display,
          fontWeight: type.displayWeight,
          letterSpacing: type.displayTracking,
          fontSize: "clamp(64px, 13vw, 220px)",
          lineHeight: 0.92,
          margin: 0,
          color: theme.fg,
        }}>
          {t.headline.map((w, i) => (
            <span key={i} style={{ display: "block" }}>
              {i === 1 ? <em style={{ fontStyle: "italic", color: accent, fontWeight: type.displayWeight }}>{w}</em> : w}
            </span>
          ))}
        </Reveal>
        <Reveal delay={0.3} style={{
          fontFamily: type.body,
          fontSize: 19,
          lineHeight: 1.55,
          maxWidth: 520,
          marginTop: 60,
          marginLeft: "auto",
          color: theme.muted,
        }}>
          {t.sub}
        </Reveal>
      </section>
    );
  }

  // split (default)
  return (
    <section style={{ padding: "100px 6vw 80px" }}>
      <Reveal style={{ display: "flex", alignItems: "center", gap: 24, fontSize: 12, fontFamily: type.mono, letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 60, color: theme.muted }}>
        <ProfilePicture theme={theme} accent={accent} size={88} />
        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
          <span style={{ color: theme.fg, fontFamily: type.display, fontSize: 18, letterSpacing: "-0.01em", textTransform: "none" }}>Alex Mercer</span>
          <span>{t.eyebrow}</span>
        </div>
      </Reveal>
      <div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 60 }}>
        <Reveal as="h1" style={{
          fontFamily: type.display,
          fontWeight: type.displayWeight,
          letterSpacing: type.displayTracking,
          fontSize: "clamp(56px, 11vw, 180px)",
          lineHeight: 0.95,
          margin: 0,
          color: theme.fg,
        }}>
          {t.headline.map((w, i) => (
            <span key={i} style={{ display: "block" }}>
              {i === 1 ? <em style={{ fontStyle: "italic", color: accent, fontWeight: type.displayWeight }}>{w}</em> : w}
            </span>
          ))}
        </Reveal>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 40, alignItems: "end" }}>
          <Reveal delay={0.2} style={{
            fontFamily: type.body,
            fontSize: 18,
            lineHeight: 1.55,
            color: theme.muted,
            maxWidth: 460,
          }}>
            {t.sub}
          </Reveal>
          <Reveal delay={0.3} style={{
            fontFamily: type.mono,
            fontSize: 12,
            letterSpacing: "0.08em",
            textTransform: "uppercase",
            color: theme.muted,
            textAlign: "right",
          }}>
            <div>Brooklyn, NY</div>
            <div>10 years practice</div>
            <div style={{ marginTop: 12, display: "flex", justifyContent: "flex-end", alignItems: "center", gap: 8 }}>
              <span style={{ width: 8, height: 8, borderRadius: "50%", background: "#3D9970", display: "inline-block" }} />
              Available · Q3 2026
            </div>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

function ProjectCard({ p, theme, type, accent, layout, idx }) {
  const [hover, setHover] = useState(false);

  if (layout === "list") {
    return (
      <Reveal delay={idx * 0.05}>
        <a
          href="#"
          data-cursor="view"
          onMouseEnter={() => setHover(true)}
          onMouseLeave={() => setHover(false)}
          style={{
            display: "grid",
            gridTemplateColumns: "60px 1fr 200px 100px",
            gap: 40,
            alignItems: "center",
            padding: "40px 0",
            borderTop: `1px solid ${theme.line}`,
            textDecoration: "none",
            color: theme.fg,
            position: "relative",
            transition: "padding 0.5s",
            paddingLeft: hover ? 24 : 0,
          }}
        >
          <span style={{ fontFamily: type.mono, fontSize: 13, color: theme.muted }}>{p.num}</span>
          <span style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(32px, 5vw, 64px)",
            lineHeight: 1,
            color: hover ? accent : theme.fg,
            transition: "color 0.3s",
          }}>{p.title}</span>
          <span style={{ fontFamily: type.body, fontSize: 14, color: theme.muted }}>{p.tags.join(" · ")}</span>
          <span style={{ fontFamily: type.mono, fontSize: 13, color: theme.muted, textAlign: "right" }}>{p.year} ↗</span>
          {hover && (
            <div style={{
              position: "absolute",
              right: 120,
              top: "50%",
              transform: "translateY(-50%)",
              width: 280,
              height: 180,
              background: p.color,
              pointerEvents: "none",
              boxShadow: "0 24px 60px rgba(0,0,0,0.18)",
              animation: "fadeIn 0.3s",
            }}>
              <div style={{
                width: "100%",
                height: "100%",
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                color: p.accent,
                fontFamily: type.display,
                fontSize: 48,
                fontWeight: type.displayWeight,
                letterSpacing: type.displayTracking,
              }}>{p.title.charAt(0)}</div>
            </div>
          )}
        </a>
      </Reveal>
    );
  }

  // asymmetric / grid card
  const isLeft = idx % 2 === 0;
  return (
    <Reveal delay={idx * 0.08} style={{
      gridColumn: layout === "asymmetric" ? (isLeft ? "1 / 8" : "6 / 13") : "auto",
      marginTop: layout === "asymmetric" ? (idx === 0 ? 0 : isLeft ? 0 : 80) : 0,
    }}>
      <a
        href="#"
        data-cursor="view"
        onMouseEnter={() => setHover(true)}
        onMouseLeave={() => setHover(false)}
        style={{
          display: "block",
          textDecoration: "none",
          color: theme.fg,
        }}
      >
        <div style={{
          aspectRatio: layout === "asymmetric" ? (isLeft ? "4/3" : "3/4") : "4/3",
          background: p.color,
          marginBottom: 24,
          overflow: "hidden",
          position: "relative",
        }}>
          <div style={{
            width: "100%",
            height: "100%",
            background: p.color,
            transform: hover ? "scale(1.04)" : "scale(1)",
            transition: "transform 1.2s cubic-bezier(0.2, 0.9, 0.3, 1)",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}>
            <ProjectMockup project={p} type={type} />
          </div>
          <div style={{
            position: "absolute",
            top: 20,
            left: 20,
            fontFamily: type.mono,
            fontSize: 11,
            letterSpacing: "0.1em",
            textTransform: "uppercase",
            color: p.accent,
            opacity: 0.8,
          }}>{p.num} / Case Study</div>
        </div>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", gap: 24 }}>
          <h3 style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(28px, 3vw, 40px)",
            lineHeight: 1.05,
            margin: 0,
            color: hover ? accent : theme.fg,
            transition: "color 0.3s",
          }}>{p.title}</h3>
          <span style={{ fontFamily: type.mono, fontSize: 12, color: theme.muted, whiteSpace: "nowrap" }}>{p.year}</span>
        </div>
        <p style={{
          fontFamily: type.body,
          fontSize: 15,
          lineHeight: 1.55,
          color: theme.muted,
          marginTop: 12,
          maxWidth: 480,
        }}>{p.desc}</p>
        <div style={{ marginTop: 16, display: "flex", gap: 8, flexWrap: "wrap" }}>
          {p.tags.map((t) => (
            <span key={t} style={{
              fontFamily: type.mono,
              fontSize: 11,
              letterSpacing: "0.06em",
              textTransform: "uppercase",
              color: theme.muted,
              border: `1px solid ${theme.line}`,
              padding: "4px 10px",
              borderRadius: 999,
              opacity: 0.6,
            }}>{t}</span>
          ))}
        </div>
      </a>
    </Reveal>
  );
}

function ProjectMockup({ project, type }) {
  // Simple, abstract mockup - a placeholder design composed of shapes
  return (
    <svg viewBox="0 0 400 300" style={{ width: "70%", height: "70%" }}>
      <rect x="40" y="40" width="320" height="220" fill={project.accent} opacity="0.08" />
      <rect x="60" y="60" width="120" height="14" fill={project.accent} opacity="0.5" />
      <rect x="60" y="84" width="80" height="8" fill={project.accent} opacity="0.3" />
      <rect x="60" y="120" width="280" height="80" fill={project.accent} opacity="0.15" />
      <circle cx="100" cy="160" r="20" fill={project.accent} opacity="0.4" />
      <rect x="140" y="150" width="180" height="6" fill={project.accent} opacity="0.4" />
      <rect x="140" y="166" width="120" height="6" fill={project.accent} opacity="0.25" />
      <rect x="60" y="220" width="60" height="20" fill={project.accent} opacity="0.6" />
      <rect x="130" y="220" width="60" height="20" fill={project.accent} opacity="0.2" />
    </svg>
  );
}

function Work({ theme, type, accent, layout }) {
  return (
    <section id="work" style={{ padding: "140px 6vw 100px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: layout === "list" ? 60 : 100, flexWrap: "wrap", gap: 24 }}>
        <Reveal>
          <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 16 }}>§ 01 / Selected Work</div>
          <h2 style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(40px, 6vw, 88px)",
            lineHeight: 1,
            margin: 0,
            color: theme.fg,
          }}>Recent <em style={{ color: accent, fontStyle: "italic" }}>case studies</em>.</h2>
        </Reveal>
        <Reveal delay={0.1} style={{ fontFamily: type.body, fontSize: 15, color: theme.muted, maxWidth: 320, lineHeight: 1.55 }}>
          A small selection from the past 18 months. Each represents a deep partnership — strategy, design, and shipping.
        </Reveal>
      </div>
      <div style={
        layout === "list"
          ? {}
          : layout === "asymmetric"
          ? { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap: 40, rowGap: 100 }
          : { display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 60, rowGap: 100 }
      }>
        {PROJECTS.map((p, i) => <ProjectCard key={p.id} p={p} theme={theme} type={type} accent={accent} layout={layout} idx={i} />)}
      </div>
    </section>
  );
}

function About({ theme, type, accent }) {
  return (
    <section id="about" style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 80, alignItems: "start" }}>
        <Reveal>
          <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted }}>§ 02 / About</div>
        </Reveal>
        <div>
          <Reveal as="h2" style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(32px, 4.2vw, 64px)",
            lineHeight: 1.1,
            margin: 0,
            color: theme.fg,
          }}>
            I work with founders and product leaders to design <em style={{ color: accent, fontStyle: "italic" }}>considered</em>, <em style={{ color: accent, fontStyle: "italic" }}>useful</em> products — from zero-to-one to mature platforms.
          </Reveal>
          <Reveal delay={0.15} style={{ marginTop: 60, display: "grid", gridTemplateColumns: "1fr 1fr", gap: 60 }}>
            <p style={{ fontFamily: type.body, fontSize: 16, lineHeight: 1.65, color: theme.muted, margin: 0 }}>
              For ten years I've practiced inside teams at IDEO, Figma, and Stripe — shipping products used by millions and shaping design culture in fast-moving organizations.
            </p>
            <p style={{ fontFamily: type.body, fontSize: 16, lineHeight: 1.65, color: theme.muted, margin: 0 }}>
              Now I work independently, with three clients at a time. I'm drawn to honest products, calm interfaces, and teams who care about craft as much as outcomes.
            </p>
          </Reveal>
        </div>
      </div>
    </section>
  );
}

function Services({ theme, type, accent }) {
  return (
    <section id="services" style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <Reveal style={{ marginBottom: 80 }}>
        <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 16 }}>§ 03 / Services</div>
        <h2 style={{
          fontFamily: type.display,
          fontWeight: type.displayWeight,
          letterSpacing: type.displayTracking,
          fontSize: "clamp(40px, 6vw, 88px)",
          lineHeight: 1,
          margin: 0,
          color: theme.fg,
        }}>How I can <em style={{ color: accent, fontStyle: "italic" }}>help</em>.</h2>
      </Reveal>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 0 }}>
        {SERVICES.map((s, i) => (
          <Reveal key={s.num} delay={i * 0.06} style={{
            padding: "48px 40px 48px 0",
            borderTop: `1px solid ${theme.line}`,
            borderRight: i % 2 === 0 ? `1px solid ${theme.line}` : "none",
            paddingLeft: i % 2 === 0 ? 0 : 40,
          }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 16 }}>
              <h3 style={{
                fontFamily: type.display,
                fontWeight: type.displayWeight,
                letterSpacing: type.displayTracking,
                fontSize: "clamp(24px, 2.6vw, 36px)",
                margin: 0,
                color: theme.fg,
              }}>{s.name}</h3>
              <span style={{ fontFamily: type.mono, fontSize: 12, color: theme.muted }}>{s.num}</span>
            </div>
            <p style={{ fontFamily: type.body, fontSize: 15, lineHeight: 1.6, color: theme.muted, margin: 0, maxWidth: 380 }}>{s.desc}</p>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

function Experience({ theme, type, accent }) {
  return (
    <section id="cv" style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 80 }}>
        <Reveal>
          <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 16 }}>§ 04 / Experience</div>
          <h2 style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(32px, 4vw, 56px)",
            lineHeight: 1,
            margin: 0,
            color: theme.fg,
          }}>A decade of <em style={{ color: accent, fontStyle: "italic" }}>practice</em>.</h2>
        </Reveal>
        <div>
          {EXPERIENCE.map((e, i) => (
            <Reveal key={e.role} delay={i * 0.06} style={{
              display: "grid",
              gridTemplateColumns: "180px 1fr 1fr",
              gap: 24,
              padding: "32px 0",
              borderTop: `1px solid ${theme.line}`,
              alignItems: "baseline",
            }}>
              <span style={{ fontFamily: type.mono, fontSize: 13, color: theme.muted }}>{e.years}</span>
              <span style={{
                fontFamily: type.display,
                fontWeight: type.displayWeight,
                letterSpacing: type.displayTracking,
                fontSize: "clamp(20px, 2vw, 28px)",
                color: theme.fg,
              }}>{e.role}</span>
              <span style={{ fontFamily: type.body, fontSize: 15, color: theme.muted, textAlign: "right" }}>{e.company}</span>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
}

function Testimonials({ theme, type, accent }) {
  return (
    <section style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <Reveal style={{ marginBottom: 80 }}>
        <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted }}>§ 05 / Words from Collaborators</div>
      </Reveal>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 80 }}>
        {TESTIMONIALS.map((t, i) => (
          <Reveal key={i} delay={i * 0.1}>
            <div style={{
              fontFamily: type.display,
              fontWeight: type.displayWeight,
              letterSpacing: type.displayTracking,
              fontSize: "clamp(22px, 2.2vw, 32px)",
              lineHeight: 1.3,
              color: theme.fg,
              marginBottom: 32,
            }}>
              <span style={{ color: accent }}>"</span>{t.quote}<span style={{ color: accent }}>"</span>
            </div>
            <div style={{ fontFamily: type.body, fontSize: 14, color: theme.muted }}>
              <div style={{ color: theme.fg, fontWeight: 500 }}>{t.author}</div>
              <div>{t.role}</div>
            </div>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

function Writing({ theme, type, accent }) {
  return (
    <section style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <Reveal style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 60, flexWrap: "wrap", gap: 24 }}>
        <div>
          <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 16 }}>§ 06 / Writing</div>
          <h2 style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(36px, 5vw, 64px)",
            lineHeight: 1,
            margin: 0,
            color: theme.fg,
          }}>Recent <em style={{ color: accent, fontStyle: "italic" }}>essays</em>.</h2>
        </div>
        <a href="#" data-cursor="view" style={{ fontFamily: type.mono, fontSize: 13, color: theme.fg, textDecoration: "none", borderBottom: `1px solid ${theme.line}`, paddingBottom: 4 }}>All writing ↗</a>
      </Reveal>
      <div>
        {WRITING.map((w, i) => (
          <Reveal key={i} delay={i * 0.05}>
            <a href="#" data-cursor="view" style={{
              display: "grid",
              gridTemplateColumns: "120px 1fr 80px",
              gap: 40,
              padding: "32px 0",
              borderTop: `1px solid ${theme.line}`,
              textDecoration: "none",
              color: theme.fg,
              alignItems: "baseline",
            }}>
              <span style={{ fontFamily: type.mono, fontSize: 13, color: theme.muted }}>{w.date}</span>
              <span style={{
                fontFamily: type.display,
                fontWeight: type.displayWeight,
                letterSpacing: type.displayTracking,
                fontSize: "clamp(22px, 2.4vw, 32px)",
                lineHeight: 1.2,
              }}>{w.title}</span>
              <span style={{ fontFamily: type.mono, fontSize: 12, color: theme.muted, textAlign: "right" }}>{w.read}</span>
            </a>
          </Reveal>
        ))}
      </div>
    </section>
  );
}

function Now({ theme, type, accent, tone }) {
  const t = TONE_VARIATIONS[tone] || TONE_VARIATIONS.confident;
  return (
    <section style={{ padding: "140px 6vw 100px", borderTop: `1px solid ${theme.line}` }}>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 2fr", gap: 80, alignItems: "start" }}>
        <Reveal>
          <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 16 }}>§ 07 / Now</div>
          <div style={{ display: "flex", alignItems: "center", gap: 10, fontFamily: type.mono, fontSize: 12, color: theme.muted }}>
            <span style={{ width: 8, height: 8, borderRadius: "50%", background: accent, display: "inline-block", animation: "pulse 2s ease-in-out infinite" }} />
            Updated April 2026
          </div>
        </Reveal>
        <Reveal delay={0.1} style={{
          fontFamily: type.display,
          fontWeight: type.displayWeight,
          letterSpacing: type.displayTracking,
          fontSize: "clamp(28px, 3.6vw, 52px)",
          lineHeight: 1.2,
          color: theme.fg,
        }}>
          INDEPENDENT DESIGNER · AVAILABLE Q3 2026
        </Reveal>
      </div>
    </section>
  );
}

function Contact({ theme, type, accent }) {
  return (
    <section id="contact" style={{ padding: "160px 6vw 80px", borderTop: `1px solid ${theme.line}` }}>
      <Reveal>
        <div style={{ fontFamily: type.mono, fontSize: 12, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 40 }}>§ 08 / Let's Work Together</div>
      </Reveal>
      <Reveal delay={0.1} as="h2" style={{
        fontFamily: type.display,
        fontWeight: type.displayWeight,
        letterSpacing: type.displayTracking,
        fontSize: "90px",
        lineHeight: 1.05,
        margin: 0,
        color: theme.fg,
        whiteSpace: "pre-line",
      }}>
        {"Alex Mercer\nINDEPENDENT DESIGNER · AVAILABLE Q3 2026"}
      </Reveal>
      <Reveal delay={0.2} style={{ marginTop: 80, display: "grid", gridTemplateColumns: "1fr 1fr", gap: 40 }}>
        <div>
          <div style={{ fontFamily: type.mono, fontSize: 11, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 12 }}>Email</div>
          <a href="mailto:hello@alexmercer.studio" data-cursor="view" style={{
            fontFamily: type.display,
            fontWeight: type.displayWeight,
            letterSpacing: type.displayTracking,
            fontSize: "clamp(24px, 3vw, 44px)",
            color: theme.fg,
            textDecoration: "none",
            borderBottom: `1px solid ${theme.line}`,
            paddingBottom: 6,
          }}>hello@alexmercer.studio</a>
        </div>
        <div>
          <div style={{ fontFamily: type.mono, fontSize: 11, letterSpacing: "0.08em", textTransform: "uppercase", color: theme.muted, marginBottom: 12 }}>Elsewhere</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {["Read.cv ↗", "Are.na ↗", "LinkedIn ↗", "Twitter ↗"].map((l) => (
              <a key={l} href="#" data-cursor="view" style={{
                fontFamily: type.body,
                fontSize: 18,
                color: theme.fg,
                textDecoration: "none",
                width: "fit-content",
              }}>{l}</a>
            ))}
          </div>
        </div>
      </Reveal>
    </section>
  );
}

function Footer({ theme, type }) {
  return (
    <footer style={{
      padding: "40px 6vw",
      borderTop: `1px solid ${theme.line}`,
      display: "flex",
      justifyContent: "space-between",
      alignItems: "center",
      flexWrap: "wrap",
      gap: 16,
      fontFamily: type.mono,
      fontSize: 12,
      letterSpacing: "0.06em",
      textTransform: "uppercase",
      color: theme.muted,
    }}>
      <div>© 2026 Alex Mercer · Brooklyn, NY</div>
      <div>Designed & built — every pixel deliberate</div>
      <div>v.04 · 2026</div>
    </footer>
  );
}

function Nav({ theme, type, accent, name }) {
  const [scrolled, setScrolled] = useState(false);
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 80);
    window.addEventListener("scroll", onScroll);
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  return (
    <nav style={{
      position: "fixed",
      top: 0,
      left: 0,
      right: 0,
      padding: scrolled ? "16px 6vw" : "24px 6vw",
      background: scrolled ? `${theme.bg}E0` : "transparent",
      backdropFilter: scrolled ? "blur(12px)" : "none",
      WebkitBackdropFilter: scrolled ? "blur(12px)" : "none",
      display: "flex",
      justifyContent: "space-between",
      alignItems: "center",
      zIndex: 100,
      transition: "padding 0.3s, background 0.3s",
      borderBottom: scrolled ? `1px solid ${theme.line}40` : "1px solid transparent",
    }}>
      <a href="#top" data-cursor="view" style={{
        fontFamily: type.display,
        fontWeight: type.displayWeight,
        letterSpacing: type.displayTracking,
        fontSize: 22,
        color: theme.fg,
        textDecoration: "none",
        display: "flex",
        alignItems: "center",
        gap: 8,
      }}>
        <span style={{
          width: 10, height: 10, borderRadius: "50%", background: accent, display: "inline-block",
        }} />
        {name}
      </a>
      <div style={{ display: "flex", gap: 32, fontFamily: type.mono, fontSize: 12, letterSpacing: "0.06em", textTransform: "uppercase" }}>
        {["Work", "About", "Services", "CV", "Contact"].map((l) => (
          <a key={l} href={`#${l.toLowerCase()}`} data-cursor="view" style={{ color: theme.fg, textDecoration: "none" }}>{l}</a>
        ))}
      </div>
    </nav>
  );
}

// ============ PORTFOLIO TWEAKS PANEL ============
function PortfolioTweaks({ tweaks, setTweak }) {
  const { TweaksPanel, TweakSection, TweakRadio, TweakSelect, TweakColor, TweakToggle } = window;

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Theme">
        <TweakSelect
          label="Color theme"
          value={tweaks.theme}
          options={[
            { value: "ivory", label: "Ivory (warm cream)" },
            { value: "paper", label: "Paper (clean white)" },
            { value: "ink", label: "Ink (dark warm)" },
            { value: "graphite", label: "Graphite (dark cool)" },
            { value: "bone", label: "Bone (muted earth)" },
          ]}
          onChange={(v) => setTweak("theme", v)}
        />
        <TweakColor label="Accent color" value={tweaks.accent} onChange={(v) => setTweak("accent", v)} />
      </TweakSection>

      <TweakSection title="Typography">
        <TweakRadio
          label="Type family"
          value={tweaks.typeFamily}
          options={[
            { value: "editorial", label: "Editorial" },
            { value: "swiss", label: "Swiss" },
            { value: "warm", label: "Warm" },
            { value: "mono", label: "Mono" },
          ]}
          onChange={(v) => setTweak("typeFamily", v)}
        />
      </TweakSection>

      <TweakSection title="Layout">
        <TweakRadio
          label="Hero layout"
          value={tweaks.heroLayout}
          options={[
            { value: "split", label: "Split" },
            { value: "stacked", label: "Stacked" },
            { value: "centered", label: "Centered" },
          ]}
          onChange={(v) => setTweak("heroLayout", v)}
        />
        <TweakRadio
          label="Project grid"
          value={tweaks.gridLayout}
          options={[
            { value: "asymmetric", label: "Asymmetric" },
            { value: "grid", label: "Grid 2-up" },
            { value: "list", label: "List" },
          ]}
          onChange={(v) => setTweak("gridLayout", v)}
        />
        <TweakRadio
          label="Density"
          value={tweaks.density}
          options={[
            { value: "compact", label: "Compact" },
            { value: "comfortable", label: "Comfortable" },
            { value: "spacious", label: "Spacious" },
          ]}
          onChange={(v) => setTweak("density", v)}
        />
      </TweakSection>

      <TweakSection title="Voice">
        <TweakRadio
          label="Copy tone"
          value={tweaks.tone}
          options={[
            { value: "confident", label: "Confident" },
            { value: "warm", label: "Warm" },
            { value: "direct", label: "Direct" },
          ]}
          onChange={(v) => setTweak("tone", v)}
        />
      </TweakSection>
    </TweaksPanel>
  );
}

// ============ APP ============
function App() {
  const { useTweaks } = window;
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [dark, setDark] = useState(false);

  // Resolve theme — if user toggles dark mode override, switch to dark variant
  const baseTheme = THEMES[tweaks.theme] || THEMES.ivory;
  const isDark = baseTheme.bg.startsWith("#0") || baseTheme.bg.startsWith("#1");
  const theme = useMemo(() => {
    if (dark && !isDark) return THEMES.ink;
    if (!dark && isDark) return baseTheme; // keep dark theme if explicitly chosen
    return baseTheme;
  }, [dark, baseTheme, isDark]);

  const type = TYPE_FAMILIES[tweaks.typeFamily] || TYPE_FAMILIES.editorial;
  const accent = tweaks.accent;
  const density = tweaks.density;

  // density scaling
  const densityScale = density === "compact" ? 0.85 : density === "spacious" ? 1.15 : 1;

  useEffect(() => {
    document.body.style.background = theme.bg;
    document.body.style.color = theme.fg;
  }, [theme]);

  return (
    <div style={{
      background: theme.bg,
      color: theme.fg,
      fontFamily: type.body,
      minHeight: "100vh",
      transition: "background 0.4s, color 0.4s",
    }} data-screen-label="Portfolio Landing">
      <CursorFollower theme={theme} />

      <style>{`
        @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,300;0,400;0,500;0,600;1,400;1,500&family=Inter:wght@300;400;500;600&family=Inter+Tight:wght@300;400;500;600;700&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap');

        * { box-sizing: border-box; }
        html, body { margin: 0; padding: 0; }
        body { cursor: none; }
        a { cursor: none; }
        ::selection { background: ${accent}; color: ${theme.bg}; }

        @keyframes marquee {
          0% { transform: translateX(0); }
          100% { transform: translateX(-33.333%); }
        }
        @keyframes pulse {
          0%, 100% { opacity: 1; transform: scale(1); }
          50% { opacity: 0.5; transform: scale(1.3); }
        }
        @keyframes fadeIn {
          from { opacity: 0; transform: translateY(-50%) scale(0.96); }
          to { opacity: 1; transform: translateY(-50%) scale(1); }
        }

        @media (max-width: 800px) {
          body { cursor: auto; }
          a { cursor: pointer; }
        }
      `}</style>

      <Nav theme={theme} type={type} accent={accent} name="Alex Mercer" />

      <div id="top" />

      <div style={{ paddingTop: 80 }}>
        <Hero theme={theme} type={type} accent={accent} layout={tweaks.heroLayout} tone={tweaks.tone} />
        <Marquee items={["Selected work", "2026", "Brooklyn × Worldwide", "Available Q3"]} theme={theme} type={type} />
        <Work theme={theme} type={type} accent={accent} layout={tweaks.gridLayout} />
        <About theme={theme} type={type} accent={accent} />
        <Services theme={theme} type={type} accent={accent} />
        <Experience theme={theme} type={type} accent={accent} />
        <Testimonials theme={theme} type={type} accent={accent} />
        <Writing theme={theme} type={type} accent={accent} />
        <Now theme={theme} type={type} accent={accent} tone={tweaks.tone} />
        <Contact theme={theme} type={type} accent={accent} />
        <Footer theme={theme} type={type} />
      </div>

      <PortfolioTweaks tweaks={tweaks} setTweak={setTweak} />
    </div>
  );
}

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

