function ProjectModal({ project, onClose }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!project) return;
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    if (ref.current) ref.current.focus();
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
  }, [project, onClose]);
  if (!project) return null;
  return ReactDOM.createPortal(
    <div role="dialog" aria-modal="true" aria-label={project.title} onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 60, background: 'rgba(15,15,15,.44)', display: 'grid',
      placeItems: 'center', padding: 'var(--space-lg)', animation: reduced() ? 'none' : 'pfPage .25s ease both'
    }}>
      <div onClick={e => e.stopPropagation()} ref={ref} tabIndex={-1} style={{
        background: 'var(--canvas)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-4)',
        maxWidth: 640, width: '100%', maxHeight: '86vh', overflowY: 'auto'
      }}>
        <div style={{ height: 8, background: 'var(--gradient-sunset-stripe)', borderRadius: 'var(--radius-lg) var(--radius-lg) 0 0' }} />
        <div style={{ padding: 'var(--space-xxl)', display: 'grid', gap: 'var(--space-md)' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 'var(--space-md)' }}>
            <div style={{ display: 'grid', gap: 'var(--space-xs)' }}>
              <Eyebrow>{project.category} · {project.year}</Eyebrow>
              <h2 style={{ font: 'var(--type-heading-3)', color: 'var(--ink)', margin: 0 }}>{project.title}</h2>
            </div>
            <button onClick={onClose} aria-label="Close" style={{ background: 'none', border: '1px solid var(--hairline)', borderRadius: 'var(--radius-md)', width: 36, height: 36, display: 'grid', placeItems: 'center', cursor: 'pointer', color: 'var(--ink)' }}><Icon name="X" size={16} /></button>
          </div>
          <p style={{ font: 'var(--type-body-md)', color: 'var(--charcoal)', margin: 0 }}>{project.detail}</p>
          <div style={{ display: 'flex', gap: 'var(--space-xxl)', flexWrap: 'wrap', padding: 'var(--space-md) 0', borderTop: '1px solid var(--hairline-soft)', borderBottom: '1px solid var(--hairline-soft)' }}>
            {project.metrics.map(([k, v]) => (
              <div key={k} className="pf-nowrap"><div style={{ font: 'var(--type-heading-4)', color: 'var(--ink)' }}>{v}</div><div style={{ font: 'var(--type-caption)', color: 'var(--steel)' }}>{k}</div></div>
            ))}
          </div>
          <div style={{ display: 'flex', gap: 'var(--space-xs)', flexWrap: 'wrap' }}>{project.tech.map(t => <Badge key={t} tone="cream">{t}</Badge>)}</div>
          <div style={{ display: 'flex', gap: 'var(--space-md)', marginTop: 'var(--space-xs)' }}>
            <Button variant="primary" as="a" href={project.demo} target="_blank" rel="noopener noreferrer">Live demo<Icon name="ExternalLink" size={15} /></Button>
            <Button variant="secondary" as="a" href={project.github} target="_blank" rel="noopener noreferrer">Source<Icon name="Github" size={15} /></Button>
          </div>
        </div>
      </div>
    </div>,
    document.body
  );
}

function ProjectsPage() {
  const cats = ['All', ...Array.from(new Set(PROJECTS.map(p => p.category)))];
  const [cat, setCat] = React.useState('All');
  const [open, setOpen] = React.useState(null);
  const list = cat === 'All' ? PROJECTS : PROJECTS.filter(p => p.category === cat);
  React.useEffect(() => {
    const on = e => { const p = PROJECTS.find(x => x.title === e.detail); if (p) { setCat('All'); setOpen(p); } };
    window.addEventListener('pf:open-project', on);
    return () => window.removeEventListener('pf:open-project', on);
  }, []);
  return (
    <div className="pf-page">
      <Section>
        <PageHead eyebrow="Projects" title="Things I built, and what they taught me." lede="Three shipped projects, all AI-adjacent. Click any card for the write-up." />
        <Reveal style={{ marginBottom: 'var(--space-xxl)' }}>
          <Tabs kind="pill" items={cats} value={cat} onChange={setCat} />
        </Reveal>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(300px,1fr))', gap: 'var(--space-lg)' }}>
          {list.map((p, i) => (
            <Reveal key={p.title} delay={i * 80}>
              <article className="pf-lift" style={{ background: 'var(--canvas)', border: '1px solid var(--hairline-soft)', borderRadius: 'var(--radius-lg)', overflow: 'hidden', display: 'grid', gridTemplateRows: 'auto 1fr auto', height: '100%' }}>
                <div style={{ height: 148, background: 'var(--gradient-sunset-soft)', display: 'grid', placeItems: 'center', position: 'relative' }} role="img" aria-label={'Thumbnail for ' + p.title}>
                  <span style={{ color: 'var(--primary-deep)' }}><Icon name="Code2" size={28} /></span>
                  {p.featured && <span style={{ position: 'absolute', top: 12, left: 12 }}><Badge tone="orange">Featured</Badge></span>}
                </div>
                <div style={{ padding: 'var(--space-xl)', display: 'grid', gap: 'var(--space-xs)', alignContent: 'start' }}>
                  <Eyebrow>{p.category} · {p.year}</Eyebrow>
                  <h2 style={{ font: 'var(--type-heading-5)', color: 'var(--ink)', margin: 0 }}>
                    <button onClick={() => setOpen(p)} className="pf-sweep" style={{ background: 'none', border: 0, padding: 0, font: 'inherit', color: 'inherit', cursor: 'pointer' }}>{p.title}</button>
                  </h2>
                  <p style={{ font: 'var(--type-body-sm)', color: 'var(--slate)', margin: 0 }}>{p.blurb}</p>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 'var(--space-xs)' }}>{p.tech.map(t => <Badge key={t} tone="cream">{t}</Badge>)}</div>
                </div>
                <div style={{ display: 'flex', gap: 'var(--space-md)', alignItems: 'center', padding: 'var(--space-md) var(--space-xl)', borderTop: '1px solid var(--hairline-soft)' }}>
                  <Button variant="link" onClick={() => setOpen(p)}>Details</Button>
                  <a href={p.demo} target="_blank" rel="noopener noreferrer" aria-label={p.title + ' live demo'} style={{ color: 'var(--steel)', display: 'inline-flex' }}><Icon name="ExternalLink" size={16} /></a>
                  <a href={p.github} target="_blank" rel="noopener noreferrer" aria-label={p.title + ' source on GitHub'} style={{ color: 'var(--steel)', display: 'inline-flex' }}><Icon name="Github" size={16} /></a>
                </div>
              </article>
            </Reveal>
          ))}
        </div>
      </Section>
      <ProjectModal project={open} onClose={() => setOpen(null)} />
    </div>
  );
}
Object.assign(window, { ProjectsPage, ProjectModal });
