/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakColor */
const { useState, useEffect, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#e85a2c",
  "density": "comfortable",
  "mode": "light",
  "displayFont": "Inter"
} /*EDITMODE-END*/;

// --- DATA ---------------------------------------------------------------

const PROJECTS = [
{
  id: "bricked",
  num: "01",
  title: "bRICKed",
  subtitle: "Rick Owens × LEGO — a hypothetical brand crossover",
  tags: ["Web", "Brand", "Group"],
  status: "SHIPPED",
  year: "2025",
  role: "Concept, design, build (group project)",
  course: "AI 101",
  cover: { src: "assets/bricked/00-hero.png", label: "bRICKed — hero" },
  summary:
  "A hypothetical brand crossover where Rick Owens' avant-garde fashion world collides with the plastic geometry of LEGO. The site behaves like a real storefront: product gallery, 3D model viewer, minifigure lookbook, full campaign reel, and a dark/light mode toggle that re-themes the entire identity.",
  problem:
  "Brand crossovers usually live as flat lookbooks or PDFs. We wanted to test whether a hypothetical collab could feel like a real, shippable retail product — with a working storefront, a 3D viewer, and a coherent identity that holds up in two opposing modes.",
  approach: [
  "Build a working storefront — product gallery + minifigure lookbook",
  "3D model viewer for hero pieces",
  "Full campaign reel as on-brand editorial",
  "Dark/light toggle that re-themes the entire identity, not just colors"],
  status_note: null,
  link: { href: "https://collab-group.pages.dev", label: "collab-group.pages.dev →" },
  tech: ["Claude Code", "Midjourney", "Gemini", "Google Antigravity"],
  team: {
    context: "Applied AI · Group project",
    members: ["Evan Madrid", "Connor Wold", "Jacob Leddy", "London Glass", "Zachary Rozo"]
  },
  artifacts: [
  { label: "Gallery — looks 01–04", w: 12, h: 720, src: "assets/bricked/gallery.png", fit: "contain" },
  { label: "Minifigures — MF-01 to MF-06", w: 12, h: 560, src: "assets/bricked/minifigures.png", fit: "contain" },
  { label: "Campaign — film", w: 12, h: 720, src: "assets/bricked/campaign-page.png", fit: "contain" },
  { label: "Campaign — motion", w: 12, h: 600, src: "assets/bricked/campaign.gif", fit: "contain", bg: "#000" }]
},
{
  id: "music-vis",
  num: "02",
  title: "AI Music Visualizer",
  subtitle: "Audio-reactive 3D wireframe geometry, rendered in Python",
  tags: ["Python", "Generative", "Audio"],
  status: "SHIPPED",
  year: "2025",
  role: "Concept, design, code",
  course: "AI 101",
  cover: { src: "assets/visualizer/cover-music-vision.gif", label: "AI Music Visualizer — hero", bg: "#000" },
  summary:
  "A Python-rendered visualizer that translates audio into reactive 3D wireframe geometry. Each track has its own custom palette and behavior — from the warm amber and sapphire of Tennessee Whiskey to the violet-and-crimson grid of Prophecy. Three rendering modes including a tiles mode where wireframe panels tumble through space in time with the music.",
  problem:
  "Most music visualizers are one-size-fits-all — the same blob reacting to whatever is playing. Songs have their own visual identity. The system should listen to a track and dress accordingly.",
  approach: [
  "Per-track palette + behavior config — every song is its own scene",
  "Three rendering modes; tiles mode for tumbling wireframe panels",
  "Audio analysis drives geometry deformation in real time",
  "Rendered out in Python for full control over each frame"],
  status_note: null,
  link: { href: "https://music-vision.pages.dev", label: "music-vision.pages.dev →" },
  tech: ["Python", "Claude Code"],
  artifacts: [
  { label: "Site — light mode", w: 8, start: 3, h: 360, src: "assets/visualizer/site-light.png", fit: "contain" },
  { label: "Color mode — visualization", w: 8, start: 3, h: 320, src: "assets/visualizer/color.gif", fit: "contain" },
  { label: "Site — dark mode", w: 8, start: 3, h: 360, src: "assets/visualizer/site-dark.png", bg: "#000", fit: "contain" },
  { label: "Green render — motion", w: 8, start: 3, h: 360, src: "assets/visualizer/green.gif", bg: "#000", fit: "contain" },
  { label: "Hero render — cubic geometry", w: 8, start: 3, h: 320, src: "assets/visualizer/cubic-hero.gif", bg: "#000", fit: "contain" },
  { label: "Tiles mode — split", w: 8, start: 3, h: 320, src: "assets/visualizer/tiles.gif", bg: "#000", fit: "contain" }]
},
{
  id: "tim-brown",
  num: "03",
  title: "Research on a Creative Leader",
  subtitle: "A space-themed long-read on Tim Brown",
  tags: ["Web", "Long-read", "Canvas"],
  status: "SHIPPED",
  year: "2025",
  role: "Research, design, build",
  course: "BUSI 101",
  cover: { src: "assets/leader/hero.gif", label: "Tim Brown — hero animation", bg: "#000" },
  summary:
  "A space-themed long-read on IDEO co-founder and design thinking pioneer Tim Brown. The hero scene is a navigable solar system; each planet opens a deep-dive section on his background, leadership style, signature work, and impact. Built on a hand-rolled canvas starfield with embedded video commentary throughout.",
  problem:
  "A standard research paper buries the subject. For a creative leader whose whole practice is making ideas tangible, the format itself should do some of the talking.",
  approach: [
  "Hero scene: navigable solar system — each planet = a section",
  "Hand-rolled canvas starfield as the running backdrop",
  "Embedded video commentary woven into the reading flow",
  "Sections: background, leadership style, signature work, impact"],
  status_note: null,
  link: { href: "https://leader-research.pages.dev", label: "leader-research.pages.dev →" },
  tech: ["Claude Code", "Midjourney", "Canvas API"],
  artifacts: [
  { label: "Hero — solar system navigation", w: 12, h: 520, src: "assets/leader/01-hero.jpg", bg: "#000", fit: "contain" },
  { label: "Section — innovation & impact", w: 6, h: 280, src: "assets/leader/02-planet-detail.jpg", bg: "#000", fit: "contain" },
  { label: "Section — background", w: 6, h: 280, src: "assets/leader/03-planet-sun.jpg", bg: "#000", fit: "contain" },
  { label: "Hero animation", w: 12, h: 280, src: "assets/leader/hero.gif", bg: "#000", fit: "contain" }]
},
{
  id: "color-lab",
  num: "04",
  title: "Color Lab",
  subtitle: "Browser-based interactive color studio",
  tags: ["WebGL", "Tool", "Interactive"],
  status: "SHIPPED",
  year: "2025",
  role: "Concept, design, build",
  course: "FOUN 112",
  cover: { src: "assets/colorlab/splash.gif", label: "Color Lab — splash animation" },
  summary:
  "An interactive color studio for mixing swatches and painting on a whiteboard you can use to storyboard, ideate, and sketch out concepts. Bring in your own 3D models and color them with the swatches you've made, then open an item overview to sum up production cost based on material, color, and size.",
  problem:
  "Color tools are either too clinical (sliders + hex codes) or too locked-in (paid native apps). I wanted something tactile and playful that anyone can open in a tab and start mixing.",
  approach: [
  "Physics-driven paint tubes — mix, pour, recombine",
  "Real-time painting on 3D models with brush + material settings",
  "Design board for chromatic relationship studies",
  "Pure WebGL — no install, no account"],
  status_note: null,
  link: { href: "https://color-final.pages.dev", label: "color-final.pages.dev →" },
  tech: ["Claude Code", "WebGL", "Three.js"],
  artifacts: [
  { label: "Mixer — paint palette + swatch recipes", w: 12, h: 540, src: "assets/colorlab/mixer.png", fit: "contain" },
  { label: "Design board — sketch + saved palette", w: 6, h: 320, src: "assets/colorlab/design-board.png", fit: "contain" },
  { label: "3D model viewer — paint on a model", w: 6, h: 320, src: "assets/colorlab/3d-viewer.png", fit: "contain" },
  { label: "Spec sheet — bill of materials + capture", w: 12, h: 480, src: "assets/colorlab/spec-sheet.png", fit: "contain" }]
},
{
  id: "porcupine",
  num: "05",
  title: "Porcupine Radio Project",
  subtitle: "CB-style AI companion for the car",
  tags: ["Hardware", "Voice AI", "Personal"],
  status: "WIP",
  year: "2026",
  role: "Concept, hardware, AI integration",
  cover: { src: "assets/porcupine/cover.png", label: "Porcupine Radio — logo", bg: "#fff", fit: "contain" },
  summary:
  "A CB-style AI companion for the car. Tune to a specific channel, say the activation word, and you're talking to an assistant wired into your music library: queue songs hands-free, ask trivia questions, or just have a conversation. The CB form factor is the point — the interaction feels like calling a friend on the dial, not opening another app.",
  problem:
  "Voice assistants in cars feel like phones glued to the dashboard. The CB radio — physical dial, channel tuning, push-to-talk — is one of the best hands-free interfaces ever made, and it's been sitting unused.",
  approach: [
  "Reuse a real CB head unit as the physical interface",
  "Map a channel to an AI persona always-on in that band",
  "Activation word triggers full conversational mode",
  "Wired into the music library + tool calls for trivia and chat"],
  status_note:
  "Work in progress, waiting on hardware and software pieces before the next build phase.",
  artifacts: [
  { label: "Dashboard install — photo", w: 8, h: 320 },
  { label: "Signal flow diagram", w: 4, h: 320 },
  { label: "Channel-tuning UX notes", w: 6, h: 220 },
  { label: "AI persona / system prompt sketch", w: 6, h: 220 }]
},
{
  id: "hexbot",
  num: "06",
  title: "HEX BOT — Henry Protocol",
  subtitle: "Multi-agent control hub for a class Mac Mini",
  tags: ["Interface", "Multi-agent AI", "Academic"],
  status: "SHELVED",
  year: "2025",
  role: "Concept, interface design",
  cover: { label: "Cover — island agent hub mock" },
  summary:
  "A class-commissioned UI hub for our professor's Mac Mini, built to bring all of his AI agents into one place under unified control. The interface is a game-inspired island where each agent lives as a worker character that animates between buildings, and running tasks surface as labeled loading bars with live comment threads.",
  problem:
  "Running many agents in parallel today means juggling terminals and tool windows. There's no single surface to dispatch tasks, see who is working on what, and intervene when something stalls.",
  approach: [
  "Island layout — each agent is a worker animating between buildings",
  "Tasks surface as labeled loading bars with live comment threads",
  "One command bar dispatches across selected agents",
  "Game-inspired affordances make multi-agent state legible at a glance"],
  status_note:
  "Shelved when the compute budget couldn't keep up with the ambition. The interface direction still holds up — revisiting later.",
  artifacts: [
  { label: "Island hub — overview", w: 8, h: 360 },
  { label: "Worker character states", w: 4, h: 360 },
  { label: "Task bars + comment threads", w: 12, h: 240 },
  { label: "Command bar exploration", w: 12, h: 200 }]
}];


// --- HASH ROUTING -------------------------------------------------------

function useHashRoute() {
  const [hash, setHash] = useState(() => window.location.hash.slice(1) || "");
  useEffect(() => {
    const onChange = () => setHash(window.location.hash.slice(1) || "");
    window.addEventListener("hashchange", onChange);
    return () => window.removeEventListener("hashchange", onChange);
  }, []);
  return [hash, (h) => {window.location.hash = h;}];
}

// --- PRIMITIVES ---------------------------------------------------------

function Field({ label, children, span = 3 }) {
  return (
    <div style={{ gridColumn: `span ${span}` }}>
      <div className="uc muted" style={{ fontSize: 10, marginBottom: 6 }}>
        {label}
      </div>
      <div>{children}</div>
    </div>);

}

function Placeholder({ label, h = 320, ratio }) {
  const style = ratio ?
  { aspectRatio: ratio, width: "100%" } :
  { height: h, width: "100%" };
  return (
    <div className="placeholder" style={style}>
      <div>
        <div style={{ marginBottom: 6 }}>[ placeholder ]</div>
        <div style={{ color: "var(--ink-2)" }}>{label}</div>
      </div>
    </div>);

}

function Image({ src, label, h = 320, ratio, fit = "cover", bg }) {
  const style = ratio ?
  { aspectRatio: ratio, width: "100%" } :
  { height: h, width: "100%" };
  return (
    <div
      className="img-frame"
      style={{ ...style, background: bg || "var(--placeholder-a, oklch(94% 0.005 90))" }}>
      <img src={src} alt={label} style={{ width: "100%", height: "100%", objectFit: fit, display: "block" }} />
    </div>);
}

function Media({ artifact }) {
  if (artifact.src) {
    return <Image src={artifact.src} label={artifact.label} h={artifact.h} ratio={artifact.ratio} fit={artifact.fit || "cover"} bg={artifact.bg} />;
  }
  return <Placeholder label={artifact.label} h={artifact.h} ratio={artifact.ratio} />;
}

// --- HEADER -------------------------------------------------------------

function Header({ route, onHome }) {
  const onIndex = !route;
  return (
    <header
      style={{
        position: "sticky",
        top: 0,
        background: "var(--paper)",
        borderBottom: "1px solid var(--rule)",
        zIndex: 10
      }}>
      
      <div
        className="grid"
        style={{ paddingTop: 14, paddingBottom: 14, alignItems: "center" }}>
        
        <a
          href="#"
          onClick={(e) => {e.preventDefault();onHome();}}
          style={{ gridColumn: "span 4" }}
          className="uc">
          
          <strong>Evan Madrid</strong>
          <span className="muted" style={{ marginLeft: 10 }}>
            ／ Portfolio
          </span>
        </a>
        <nav
          style={{
            gridColumn: "span 8",
            display: "flex",
            gap: 24,
            justifyContent: "flex-end",
            fontSize: 12
          }}
          className="uc">
          
          <a
            href="#"
            onClick={(e) => {e.preventDefault();onHome();}}
            style={{ borderBottom: onIndex ? "1px solid var(--ink)" : "none" }}>
            
            Work
          </a>
          <a href="#about">About</a>
          <a href="#contact">Contact</a>
        </nav>
      </div>
    </header>);

}

// --- INDEX (CARD GRID) --------------------------------------------------

function ProjectCard({ project, onOpen }) {
  return (
    <a
      href={`#${project.id}`}
      onClick={(e) => {e.preventDefault();onOpen(project.id);}}
      className="card">
      
      <div className="card-cover">
        {project.cover.src ?
        <Image src={project.cover.src} label={project.cover.label} ratio="4 / 3" fit={project.cover.fit || "cover"} bg={project.cover.bg} /> :

        <Placeholder label={project.cover.label} ratio="4 / 3" />
        }
        <span className={`badge ${project.status.toLowerCase()} card-badge`}>
          {project.status}
        </span>
        <span className="card-num">{project.num}</span>
      </div>
      <div className="card-meta">
        <div className="card-title">
          <h3 className="display" style={{ fontSize: 22, fontWeight: 600, letterSpacing: "-0.01em" }}>
            {project.title}
          </h3>
          <span className="card-arrow" aria-hidden>↗</span>
        </div>
        <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>
          {project.subtitle}
        </div>
        <div className="uc muted" style={{ fontSize: 10, marginTop: 12, letterSpacing: "0.08em" }}>
          {project.tags.join(" · ")} <span style={{ margin: "0 6px" }}>/</span> {project.year}
        </div>
      </div>
    </a>);

}

function IndexView({ accent, onOpen }) {
  const date = useMemo(() => new Date(2026, 4, 1).toISOString().slice(0, 10), []);
  return (
    <>
      <section style={{ padding: "72px 0 48px", borderBottom: "1px solid var(--rule)" }}>
        <div className="grid">
          <div style={{ gridColumn: "span 12", marginBottom: 40 }} className="uc muted">
            <span>Portfolio · v1.0</span>
            <span style={{ margin: "0 16px" }}>·</span>
            <span>SCAD · Applied AI + Service Design</span>
          </div>
          <h1
            className="display"
            style={{
              gridColumn: "span 12",
              fontWeight: 800,
              fontSize: "clamp(44px, 7vw, 96px)",
              lineHeight: 0.95,
              letterSpacing: "-0.03em",
              textWrap: "balance",
              whiteSpace: "pre-line"
            }}>
            Evan Madrid
            <br />
            <span style={{ color: "rgb(144, 142, 138)" }}>
              Designing where{"\n"}AI meets{" "}
              <em style={{ fontStyle: "italic", color: accent }}>service.</em>
            </span>
          </h1>
          <p
            style={{
              gridColumn: "5 / span 7",
              fontSize: 14,
              lineHeight: 1.6,
              marginTop: 40,
              color: "var(--ink-2)",
              textWrap: "pretty"
            }}>
            
            Applied AI major, Service Design minor at SCAD. Interested in
            using AI as a material for service systems that are easier to live
            inside. Seven projects below — in motion, in progress, and shelved.
            Click any card to open the case study.
          </p>
        </div>
      </section>

      <section style={{ padding: "56px 0 96px" }}>
        <div className="grid">
          <div
            style={{
              gridColumn: "span 12",
              marginBottom: 24,
              display: "flex",
              justifyContent: "space-between",
              alignItems: "baseline"
            }}
            className="uc muted">
            
            <span>§ Selected work · 06</span>
            <span>Click a card to open →</span>
          </div>
          <div className="card-grid" style={{ gridColumn: "1 / -1" }}>
            {PROJECTS.map((p) =>
            <ProjectCard key={p.id} project={p} onOpen={onOpen} />
            )}
          </div>
        </div>
      </section>

      <About />
      <Contact accent={accent} />
    </>);

}

// --- DETAIL VIEW --------------------------------------------------------

function DetailView({ project, accent, onBack, onNext, onPrev }) {
  const p = project;
  useEffect(() => {
    window.scrollTo(0, 0);
  }, [p.id]);

  return (
    <article style={{ paddingBottom: 80 }}>
      {/* Breadcrumb */}
      <div className="grid" style={{ padding: "32px 0 24px" }}>
        <div style={{ gridColumn: "span 12", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <a
            href="#"
            onClick={(e) => {e.preventDefault();onBack();}}
            className="uc muted"
            style={{ fontSize: 11 }}>
            
            ← All work
          </a>
          <div className="uc muted" style={{ fontSize: 11 }}>
            Case study · {p.num} / 06
          </div>
        </div>
      </div>

      {/* Cover */}
      <div className="grid" style={{ marginBottom: 48 }}>
        <div style={{ gridColumn: "1 / -1" }}>
          {p.cover.src ?
          <Image src={p.cover.src} label={p.cover.label} ratio="16 / 7" fit={p.cover.fit || "cover"} bg={p.cover.bg} /> :

          <Placeholder label={p.cover.label} ratio="16 / 7" />
          }
        </div>
      </div>

      {/* Title block */}
      <div className="grid" style={{ marginBottom: 48 }}>
        <div style={{ gridColumn: "span 12", display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 24 }} className="uc muted">
          <span>§{p.num} — {p.title}</span>
          <span><span className={`badge ${p.status.toLowerCase()}`}>{p.status}</span></span>
        </div>
        <h2
          className="display"
          style={{
            gridColumn: "span 12",
            fontSize: "clamp(44px, 6.5vw, 88px)",
            fontWeight: 700,
            letterSpacing: "-0.03em",
            lineHeight: 0.98,
            textWrap: "balance"
          }}>
          
          {p.title}
        </h2>
        <div className="muted" style={{ gridColumn: "span 12", marginTop: 16, fontSize: 18 }}>
          {p.subtitle}
        </div>
      </div>

      {/* Meta */}
      <div className="grid" style={{ marginBottom: 24 }}>
        <Field label="Year" span={2}>{p.year}</Field>
        <Field label="Role" span={3}>{p.role}</Field>
        <Field label="Course" span={3}>{p.course || "—"}</Field>
        <Field label="Tags" span={2}>{p.tags.join(" · ")}</Field>
        <Field label="Status" span={2}>
          <span className={`badge ${p.status.toLowerCase()}`}>{p.status}</span>
        </Field>
        <div style={{ gridColumn: "span 12", marginTop: 24 }}><hr /></div>
      </div>

      {/* Overview */}
      <div className="grid" style={{ marginTop: 32 }}>
        <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Overview</div>
        <p style={{ gridColumn: "4 / span 8", fontSize: 17, lineHeight: 1.55, textWrap: "pretty", margin: 0 }}>
          {p.summary}
        </p>
      </div>

      {/* Artifacts */}
      <div className="grid" style={{ marginTop: 56 }}>
        <div style={{ gridColumn: "1 / -1", display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap: 16 }}>
          {p.artifacts.map((a, i) =>
          <div key={i} style={{ gridColumn: a.start ? `${a.start} / span ${a.w}` : `span ${a.w}` }}>
              <Media artifact={a} />
              <div className="uc muted" style={{ fontSize: 10, marginTop: 6 }}>
                Fig. {p.num}.{String(i + 1).padStart(2, "0")} — {a.label}
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Problem */}
      <div className="grid" style={{ marginTop: 64 }}>
        <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Problem</div>
        <p style={{ gridColumn: "4 / span 8", fontSize: 14, lineHeight: 1.65, textWrap: "pretty", margin: 0 }}>
          {p.problem}
        </p>
      </div>

      {/* Approach */}
      <div className="grid" style={{ marginTop: 32 }}>
        <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Approach</div>
        <ol style={{ gridColumn: "4 / span 8", paddingLeft: 0, listStyle: "none", fontSize: 14, lineHeight: 1.7, margin: 0 }}>
          {p.approach.map((step, i) =>
          <li key={i} style={{ display: "flex", gap: 16, paddingBottom: 8 }}>
              <span className="muted" style={{ minWidth: 32 }}>
                {String(i + 1).padStart(2, "0")}
              </span>
              <span>{step}</span>
            </li>
          )}
        </ol>
      </div>

      {p.status_note &&
      <div className="grid" style={{ marginTop: 32 }}>
          <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Status note</div>
          <p
          style={{
            gridColumn: "4 / span 8",
            fontSize: 14,
            lineHeight: 1.6,
            borderLeft: `2px solid ${accent}`,
            paddingLeft: 16,
            color: "var(--ink-2)",
            margin: 0
          }}>
          
            {p.status_note}
          </p>
        </div>
      }

      {p.link &&
      <div className="grid" style={{ marginTop: 32 }}>
          <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Live</div>
          <div style={{ gridColumn: "4 / span 8" }}>
            <a
            href={p.link.href}
            target={p.link.href.startsWith("http") ? "_blank" : undefined}
            rel={p.link.href.startsWith("http") ? "noopener noreferrer" : undefined}
            style={{ fontSize: 18, borderBottom: "1px solid var(--ink)" }}>
              {p.link.label}
            </a>
          </div>
        </div>
      }

      {p.tech && p.tech.length > 0 &&
      <div className="grid" style={{ marginTop: 32 }}>
          <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Tech</div>
          <ul style={{ gridColumn: "4 / span 8", padding: 0, margin: 0, listStyle: "none", display: "flex", flexWrap: "wrap", gap: 8 }}>
            {p.tech.map((t, i) =>
          <li key={i}>
                <span className="badge" style={{ fontSize: 11, padding: "5px 10px" }}>{t}</span>
              </li>
          )}
          </ul>
        </div>
      }

      {p.team && p.team.members && p.team.members.length > 0 &&
      <div className="grid" style={{ marginTop: 32 }}>
          <div style={{ gridColumn: "1 / span 3" }} className="uc muted">Team</div>
          <div style={{ gridColumn: "4 / span 8" }}>
            {p.team.context &&
              <div className="uc muted" style={{ fontSize: 10, marginBottom: 10, letterSpacing: "0.08em" }}>{p.team.context}</div>
            }
            <ul style={{ padding: 0, margin: 0, listStyle: "none", display: "flex", flexWrap: "wrap", columnGap: 24, rowGap: 6 }}>
              {p.team.members.map((m, i) =>
              <li key={i} style={{ fontSize: 16 }}>{m}</li>
              )}
            </ul>
          </div>
        </div>
      }

      {/* Pager */}
      <div className="grid" style={{ marginTop: 96, paddingTop: 24, borderTop: "1px solid var(--rule)" }}>
        <a
          href="#"
          onClick={(e) => {e.preventDefault();onPrev();}}
          style={{ gridColumn: "span 6" }}
          className="uc muted">
          
          ← Previous
        </a>
        <a
          href="#"
          onClick={(e) => {e.preventDefault();onNext();}}
          style={{ gridColumn: "span 6", textAlign: "right" }}
          className="uc muted">
          
          Next →
        </a>
      </div>
    </article>);

}

// --- ABOUT / CONTACT ----------------------------------------------------

function About() {
  return (
    <section id="about" style={{ padding: "80px 0", borderTop: "1px solid var(--rule)", borderBottom: "1px solid var(--rule)" }}>
      <div className="grid">
        <div style={{ gridColumn: "span 12", marginBottom: 32 }} className="uc muted">
          § About
        </div>
        <h2
          className="display"
          style={{
            gridColumn: "1 / span 9",
            fontSize: "clamp(28px, 3.5vw, 48px)",
            fontWeight: 500,
            letterSpacing: "-0.02em",
            lineHeight: 1.15,
            textWrap: "balance",
            margin: 0
          }}>
          
          About Me.
        </h2>

        <div style={{ gridColumn: "1 / -1", display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap: 24, marginTop: 40 }}>
          <Field label="Studying" span={4}>
            SCAD — Applied AI (major), Service Design (minor)
          </Field>
          <Field label="Based" span={4}>Savannah, GA</Field>
          <Field label="Open to" span={4}>SCAD SERVE · SCAD Pro · collaborations</Field>
        </div>

        <p
          style={{
            gridColumn: "1 / span 8",
            marginTop: 32,
            fontSize: 14,
            lineHeight: 1.7,
            color: "var(--ink-2)",
            textWrap: "pretty"
          }}>
          
          I'm Evan Madrid, a first-year student at SCAD. I grew up in Fort
          Worth, Texas, moved to Savannah in high school, and graduated from
          Herschel V. Jenkins High before starting at SCAD — where I'm
          majoring in Applied AI with a minor in Service Design.{" "}
          <br /><br />
          That mix is the work. I design and build at the seam between people
          and AI — interfaces, assistants, and small systems that disappear
          into the work instead of demanding attention. The goal is software
          that feels like a service: present when needed, quiet when not,
          opinionated about what to do next. Some projects ship, some get
          shelved with a good idea inside. Both are documented here, because
          what I learned either way is the point.{" "}
          <br /><br />
          I chose this path because I think AI is a skill everyone will end up
          needing, and service design is the lens that makes it useful instead
          of impressive. After undergrad I'm hoping to come back to SCAD for a
          master's and finish out service design — the half of the equation I
          want to go deeper on.
        </p>

        {/* RESUME LINK */}
        <div style={{ gridColumn: "1 / -1", marginTop: 48, paddingTop: 24, borderTop: "1px solid var(--rule)", display: "flex", justifyContent: "flex-start", alignItems: "center", flexWrap: "wrap", gap: 16 }}>
          <a href="uploads/evan_resume.html" target="_blank" rel="noopener noreferrer" className="uc" style={{ fontSize: 11, padding: "10px 18px", border: "1px solid var(--ink)", borderRadius: 999 }}>
            Open printable resume ↗
          </a>
        </div>
      </div>
    </section>);

}

function Contact({ accent }) {
  return (
    <section id="contact" style={{ padding: "80px 0 120px" }}>
      <div className="grid">
        <div style={{ gridColumn: "span 12", marginBottom: 32 }} className="uc muted">
          § Contact
        </div>
        <h2
          className="display"
          style={{
            gridColumn: "span 12",
            fontSize: "clamp(32px, 4.5vw, 56px)",
            fontWeight: 500,
            letterSpacing: "-0.025em",
            lineHeight: 1.05,
            margin: 0
          }}>
          
          Get in touch <span style={{ color: accent }}>↘</span>
        </h2>

        <div style={{ gridColumn: "1 / -1", display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap: 24, marginTop: 32 }}>
          <Field label="Email" span={6}>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <div>
                <a href="mailto:evanmadrid31@gmail.com" style={{ fontSize: 18, borderBottom: "1px solid var(--ink)" }}>evanmadrid31@gmail.com</a>
                <div className="muted uc" style={{ fontSize: 10, marginTop: 4, letterSpacing: "0.08em" }}>Personal</div>
              </div>
              <div>
                <a href="mailto:emadri20@student.scad.edu" style={{ fontSize: 18, borderBottom: "1px solid var(--ink)" }}>emadri20@student.scad.edu</a>
                <div className="muted uc" style={{ fontSize: 10, marginTop: 4, letterSpacing: "0.08em" }}>School · SCAD</div>
              </div>
            </div>
          </Field>
          <Field label="Phone" span={6}>
            <a href="tel:+10000000000" style={{ fontSize: 18, borderBottom: "1px solid var(--ink)" }}>(817) 366-9722

            </a>
            <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>

            </div>
          </Field>
        </div>

        <div style={{ gridColumn: "span 12", marginTop: 64, paddingTop: 24, borderTop: "1px solid var(--rule)" }}>
          <div className="uc muted" style={{ fontSize: 10, display: "flex", justifyContent: "space-between" }}>
            <span>© Evan Madrid · 2026</span>
            <span></span>
          </div>
        </div>
      </div>
    </section>);

}

// --- TWEAKS -------------------------------------------------------------

function Tweaks({ tweaks, setTweak }) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Accent">
        <TweakColor label="Signal color" value={tweaks.accent} onChange={(v) => setTweak("accent", v)} />
      </TweakSection>
      <TweakSection label="Type">
        <TweakRadio
          label="Display font"
          value={tweaks.displayFont}
          onChange={(v) => setTweak("displayFont", v)}
          options={[
          { label: "Inter", value: "Inter" },
          { label: "Mono", value: "JetBrains Mono" },
          { label: "Serif", value: "Fraunces" }]
          } />
        
      </TweakSection>
      <TweakSection label="Density">
        <TweakRadio
          label="Spacing"
          value={tweaks.density}
          onChange={(v) => setTweak("density", v)}
          options={[
          { label: "Tight", value: "tight" },
          { label: "Comfortable", value: "comfortable" },
          { label: "Roomy", value: "roomy" }]
          } />
        
      </TweakSection>
      <TweakSection label="Mode">
        <TweakRadio
          label="Theme"
          value={tweaks.mode}
          onChange={(v) => setTweak("mode", v)}
          options={[
          { label: "Light", value: "light" },
          { label: "Dark", value: "dark" }]
          } />
        
      </TweakSection>
    </TweaksPanel>);

}

// --- APP ----------------------------------------------------------------

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [hash, setHash] = useHashRoute();

  const projectIds = PROJECTS.map((p) => p.id);
  const project = PROJECTS.find((p) => p.id === hash);
  const isAnchor = hash === "about" || hash === "contact";

  useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty("--accent", tweaks.accent);
    root.style.setProperty(
      "--display",
      `"${tweaks.displayFont}", -apple-system, system-ui, sans-serif`
    );
    if (tweaks.mode === "dark") {
      root.style.setProperty("--paper", "oklch(15% 0.005 90)");
      root.style.setProperty("--ink", "oklch(96% 0.005 90)");
      root.style.setProperty("--ink-2", "oklch(75% 0.005 90)");
      root.style.setProperty("--ink-3", "oklch(55% 0.005 90)");
      root.style.setProperty("--rule", "oklch(28% 0.005 90)");
      root.style.setProperty("--placeholder-a", "oklch(22% 0.005 90)");
      root.style.setProperty("--placeholder-b", "oklch(20% 0.005 90)");
    } else {
      root.style.setProperty("--paper", "oklch(98% 0.005 90)");
      root.style.setProperty("--ink", "oklch(18% 0.01 90)");
      root.style.setProperty("--ink-2", "oklch(40% 0.01 90)");
      root.style.setProperty("--ink-3", "oklch(60% 0.01 90)");
      root.style.setProperty("--rule", "oklch(85% 0.005 90)");
      root.style.setProperty("--placeholder-a", "oklch(94% 0.005 90)");
      root.style.setProperty("--placeholder-b", "oklch(96% 0.005 90)");
    }
    const dens = { tight: 0.75, comfortable: 1, roomy: 1.3 }[tweaks.density] || 1;
    root.style.setProperty("--density", dens);
  }, [tweaks]);

  // Scroll to anchor sections when hash matches
  useEffect(() => {
    if (isAnchor) {
      const el = document.getElementById(hash);
      if (el) el.scrollIntoView({ behavior: "auto" });
    }
  }, [hash, isAnchor]);

  const goHome = () => setHash("");
  const goNext = () => {
    const i = projectIds.indexOf(project.id);
    setHash(projectIds[(i + 1) % projectIds.length]);
  };
  const goPrev = () => {
    const i = projectIds.indexOf(project.id);
    setHash(projectIds[(i - 1 + projectIds.length) % projectIds.length]);
  };

  return (
    <div style={{ minHeight: "100vh" }}>
      <Header route={hash} onHome={goHome} />
      {project ?
      <DetailView
        project={project}
        accent={tweaks.accent}
        onBack={goHome}
        onNext={goNext}
        onPrev={goPrev} /> :


      <IndexView accent={tweaks.accent} onOpen={(id) => setHash(id)} />
      }
      <Tweaks tweaks={tweaks} setTweak={setTweak} />
    </div>);

}

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