// joaokury.xyz — personal homepage (refined)
const { useState, useEffect, useMemo } = React;

// ── Logo mark ─────────────────────────────────────────
const Mark = ({ size = 18 }) => (
  <svg width={size} height={size} viewBox="0 0 64 64" fill="none">
    <rect x="6"  y="6"  width="24" height="24" fill="currentColor" />
    <rect x="34" y="6"  width="24" height="24" stroke="currentColor" strokeWidth="2.5" />
    <rect x="6"  y="34" width="24" height="24" stroke="currentColor" strokeWidth="2.5" />
    <rect x="34" y="34" width="24" height="24" fill="var(--accent)" />
  </svg>
);

function useFavicon() {
  useEffect(() => {
    const svg = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
      <rect x='6' y='6' width='24' height='24' fill='%231a1814'/>
      <rect x='34' y='6' width='24' height='24' stroke='%231a1814' stroke-width='2.5' fill='none'/>
      <rect x='6' y='34' width='24' height='24' stroke='%231a1814' stroke-width='2.5' fill='none'/>
      <rect x='34' y='34' width='24' height='24' fill='%23c4421f'/>
    </svg>`.replace(/\n/g, '').replace(/\s+/g, ' ');
    let link = document.querySelector("link[rel='icon']");
    if (!link) { link = document.createElement('link'); link.rel = 'icon'; document.head.appendChild(link); }
    link.href = 'data:image/svg+xml;utf8,' + svg;
  }, []);
}

// ── Theme ─────────────────────────────────────────────
function useTheme() {
  const [theme, setTheme] = useState(() => localStorage.getItem('jk-theme') || 'light');
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('jk-theme', theme);
  }, [theme]);
  return [theme, () => setTheme(t => t === 'dark' ? 'light' : 'dark')];
}

// ── Live SP clock ─────────────────────────────────────
function useSPTime() {
  const [time, setTime] = useState('');
  useEffect(() => {
    const tick = () => {
      const now = new Date();
      const t = now.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', timeZone: 'America/Sao_Paulo' });
      setTime(t);
    };
    tick();
    const id = setInterval(tick, 30000);
    return () => clearInterval(id);
  }, []);
  return time;
}

const SunIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
);
const MoonIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
);

// ── Rotating word (hero) ──────────────────────────────
function RotatingWord({ words, interval = 2200 }) {
  const [active, setActive] = React.useState(0);
  const [outgoing, setOutgoing] = React.useState(null);
  const [w, setW] = React.useState(null);
  const activeRef = React.useRef(null);

  React.useEffect(() => {
    const id = setInterval(() => {
      setActive(v => { setOutgoing(v); return (v + 1) % words.length; });
    }, interval);
    return () => clearInterval(id);
  }, [words, interval]);

  React.useEffect(() => {
    if (outgoing === null) return;
    const t = setTimeout(() => setOutgoing(null), 700);
    return () => clearTimeout(t);
  }, [outgoing]);

  React.useLayoutEffect(() => {
    if (activeRef.current) setW(activeRef.current.offsetWidth);
  }, [active]);

  return (
    <span className="rot-wrap" style={w !== null ? { width: w + 'px' } : undefined}>
      <span key={words[active]} ref={activeRef} className="rot-active ser">{words[active]}</span>
      {outgoing !== null && outgoing !== active && (
        <span key={"out-" + words[outgoing]} className="rot-old ser">{words[outgoing]}</span>
      )}
    </span>
  );
}

// ── Nav ───────────────────────────────────────────────
function Nav({ theme, onToggle }) {
  const time = useSPTime();
  return (
    <nav className="nav">
      <div className="wrap nav-inner">
        <a href="#top" className="brand">
          <Mark size={18} />
          <span className="brand-name">João Kury</span>
          <span className="brand-sub">Founder · LATAM</span>
        </a>
        <div className="nav-links">
          <a href="#about">About</a>
          <a href="#experience">Work</a>
          <a href="#writing">Writing</a>
          <a href="#videos">Videos</a>
          <a href="#speaking">Speaking</a>
          <a href="#photos">Photos</a>
        </div>
        <div className="nav-right">
          <span className="clock"><span className="dot-live"/> SP · {time}</span>
          <button className="theme-toggle" onClick={onToggle} title="Toggle theme" aria-label="Toggle theme">
            {theme === 'dark' ? <SunIcon/> : <MoonIcon/>}
          </button>
        </div>
      </div>
    </nav>
  );
}

// ── Hero ──────────────────────────────────────────────
function Hero() {
  const h = SITE.hero;
  return (
    <header id="top" className="hero">
      <div className="wrap">
        <span className="hero-tag"><span className="dot"/> Open to conversations</span>
        <h1>
          João Kury,<br/>
          <RotatingWord words={["founder", "operator", "growth", "writer"]} /> in<br/>
          Latin America.
        </h1>
        <div className="hero-grid">
          <p className="hero-intro">
            {h.line.split('Modular Crypto').map((part, i, arr) =>
              i < arr.length - 1
                ? <React.Fragment key={i}>{part}<a href="#experience">Modular Crypto</a></React.Fragment>
                : <React.Fragment key={i}>{part}</React.Fragment>
            )}
          </p>
          <div className="hero-meta">
            <div className="hero-meta-row"><span className="k">Role</span><span className="v">Co-founder, Modular Crypto</span></div>
            <div className="hero-meta-row"><span className="k">Focus</span><span className="v">Crypto × AI · LATAM growth</span></div>
            <div className="hero-meta-row"><span className="k">Contact</span><span className="v"><a className="link" href="https://t.me/joaokury" target="_blank" rel="noopener">@joaokury</a> · Telegram</span></div>
          </div>
        </div>
      </div>
    </header>
  );
}

// ── About ─────────────────────────────────────────────
function About() {
  const totalTalks = SITE.events.reduce((s, e) => s + e.count, 0);
  return (
    <section id="about" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">01 · About</div>
          <h2 className="section-title">Co-founder of <em>Modular Crypto</em>.</h2>
        </div>
        <div className="about-grid">
          <div></div>
          <div>
            <div className="about-prose">
              {SITE.about.map((p, i) => <p key={i}>{p}</p>)}
            </div>
            <div className="about-stats">
              <div className="stat"><div className="num">{totalTalks}<span className="plus">+</span></div><div className="lbl">Talks since 2022</div></div>
              <div className="stat"><div className="num">4</div><div className="lbl">Countries · LATAM</div></div>
              <div className="stat"><div className="num">20<span className="plus">+</span></div><div className="lbl">Essays published</div></div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// ── Experience ────────────────────────────────────────
function Experience() {
  return (
    <section id="experience" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">02 · Work</div>
          <h2 className="section-title">A brief <em>history</em>.</h2>
        </div>
        <div className="timeline-list">
          {SITE.experience.map((e, i) => {
            const isCurrent = e.period.includes('present') && i === 0;
            return (
              <div key={i} className="exp-row">
                <div className="exp-period">
                  {e.period}
                  {isCurrent && <span className="now-tag">NOW</span>}
                </div>
                <div className="exp-main">
                  <div className="role">{e.role} <span className="at">at </span><span className="company">{e.company}</span></div>
                  <div className="summary">{e.summary}</div>
                </div>
                <div className="exp-loc">{e.location}</div>
              </div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

// ── Writing ───────────────────────────────────────────
function Writing() {
  return (
    <section id="writing" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">03 · Writing</div>
          <h2 className="section-title">Selected <em>articles</em>.</h2>
        </div>
        <div className="articles">
          {SITE.articles.map((a, i) => (
            <a className="art-row" href={a.url} key={i} target="_blank" rel="noopener">
              <div className="art-num">{String(i + 1).padStart(2, '0')}</div>
              <div className="art-title">{a.title}</div>
              <div className="art-venue">{a.venue}</div>
              <div className="art-date">{a.date}</div>
              <span className="arrow">↗</span>
            </a>
          ))}
        </div>
        <div className="art-foot">
          <span>A selection. There are others scattered across venues.</span>
          <a href="https://newsletter.modularcrypto.xyz" target="_blank" rel="noopener">More on Modular Crypto ↗</a>
        </div>
      </div>
    </section>
  );
}

// ── Videos ──────────────────────────────────────────
const PlayIcon = () => (
  <svg viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
);
const YTIcon = () => (
  <svg viewBox="0 0 24 24" fill="currentColor"><path d="M21.6 7.2a2.5 2.5 0 0 0-1.76-1.77C18.25 5 12 5 12 5s-6.25 0-7.84.43A2.5 2.5 0 0 0 2.4 7.2 26.2 26.2 0 0 0 2 12a26.2 26.2 0 0 0 .4 4.8 2.5 2.5 0 0 0 1.76 1.77C5.75 19 12 19 12 19s6.25 0 7.84-.43a2.5 2.5 0 0 0 1.76-1.77A26.2 26.2 0 0 0 22 12a26.2 26.2 0 0 0-.4-4.8zM10 15V9l5.2 3-5.2 3z"/></svg>
);

function VideoThumb({ id, alt }) {
  // Try maxres first (HD uploads), fall back to hqdefault, then to placeholder.
  const [src, setSrc] = useState(`https://i.ytimg.com/vi/${id}/maxresdefault.jpg`);
  const [step, setStep] = useState(0);
  const [failed, setFailed] = useState(false);
  const onError = () => {
    if (step === 0) { setStep(1); setSrc(`https://i.ytimg.com/vi/${id}/hqdefault.jpg`); }
    else { setFailed(true); }
  };
  if (failed || !id) {
    return (
      <div className="vid-thumb-fallback">
        <span>YouTube · {id || 'pending'}</span>
      </div>
    );
  }
  return <img className="vid-thumb" src={src} alt={alt} loading="lazy" onError={onError} />;
}

function Videos() {
  const [activeIdx, setActiveIdx] = useState(0);
  const [playing, setPlaying] = useState(false);
  const [meta, setMeta] = useState({}); // id -> { title, author }

  // Fetch oEmbed titles for any video without a manual title override.
  useEffect(() => {
    const list = (SITE.videos || []).filter(v => v.id && !v.title);
    list.forEach(async (v) => {
      try {
        const r = await fetch(`https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=${v.id}&format=json`);
        if (!r.ok) return;
        const j = await r.json();
        setMeta(m => ({ ...m, [v.id]: { title: j.title, author: j.author_name } }));
      } catch (e) { /* fallback to placeholder */ }
    });
  }, []);

  const videos = SITE.videos || [];
  if (!videos.length) return null;

  const titleFor = (v) => v.title || meta[v.id]?.title || '';
  const authorFor = (v) => v.guest || meta[v.id]?.author || '';

  const select = (idx) => {
    setActiveIdx(idx);
    setPlaying(true);
  };

  const active = videos[activeIdx];
  const others = videos.map((v, i) => ({ v, i })).filter(x => x.i !== activeIdx);

  return (
    <section id="videos" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">04 · Videos</div>
          <h2 className="section-title">Long-form <em>conversations</em>.</h2>
        </div>

        <div className="vid-meta">
          <span>Recent episodes · @CriptoNita</span>
          <a className="vid-chan" href={SITE.videosChannelUrl} target="_blank" rel="noopener">
            <YTIcon/> <span>Watch on YouTube ↗</span>
          </a>
        </div>

        <div className="vid-stage">
          {/* Featured player */}
          <div className="vid-featured">
            <div className="vid-thumb-wrap" onClick={() => setPlaying(true)}>
              {playing ? (
                <iframe
                  className="vid-iframe"
                  key={active.id}
                  src={`https://www.youtube-nocookie.com/embed/${active.id}?autoplay=1&rel=0`}
                  title={titleFor(active)}
                  allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                  allowFullScreen
                />
              ) : (
                <>
                  <span className="vid-ep">NOW PLAYING</span>
                  <VideoThumb id={active.id} alt={titleFor(active) || 'Video thumbnail'}/>
                  <span className="vid-play vid-play-lg"><PlayIcon/></span>
                </>
              )}
            </div>
            <div className="vid-featured-body">
              <div className="vid-eyebrow">{authorFor(active) || '@CriptoNita'} · Episode {videos.length - activeIdx}</div>
              <h3 className="vid-featured-title">{titleFor(active) || <span style={{opacity:0.4}}>Loading…</span>}</h3>
              <a className="vid-featured-link" href={`https://www.youtube.com/watch?v=${active.id}`} target="_blank" rel="noopener">
                Watch on YouTube ↗
              </a>
            </div>
          </div>

          {/* Up-next playlist */}
          <div className="vid-playlist">
            <div className="vid-playlist-label">Up next</div>
            {others.map(({v, i}, k) => (
              <button
                key={v.id}
                className="vid-pl-item"
                onClick={() => select(i)}
                aria-label={`Play ${titleFor(v)}`}
              >
                <div className="vid-pl-thumb">
                  <VideoThumb id={v.id} alt={titleFor(v) || 'Video thumbnail'}/>
                  <span className="vid-pl-play"><PlayIcon/></span>
                </div>
                <div className="vid-pl-body">
                  <div className="vid-pl-num">EP {String(videos.length - i).padStart(2, '0')}</div>
                  <div className="vid-pl-title">{titleFor(v) || <span style={{opacity:0.4}}>Loading…</span>}</div>
                </div>
              </button>
            ))}
          </div>
        </div>

        <div className="vid-foot">
          <span>A handful of recent ones. Full archive on the channel.</span>
          <a href={SITE.videosChannelUrl} target="_blank" rel="noopener">See full archive ↗</a>
        </div>
      </div>
    </section>
  );
}

// ── LATAM map — recognizable silhouettes, equirectangular projection ──
// Coords use lon/lat -> svg via project(). viewBox 0..100 wide, 0..140 tall.
// Lon range: -120 to -30 (90° wide -> 100 svg units)
// Lat range: 35 to -56 (91° tall -> ~101 svg units, padded to 140 viewBox)
function project(lon, lat) {
  const x = ((lon + 120) / 90) * 100;
  const y = ((35 - lat) / 91) * 101 + 8; // 8 unit top padding
  return [x, y];
}

// Country outlines — simplified but recognizable. Each is an array of [lon,lat] points.
const COUNTRIES = {
  MEXICO: [
    [-117,32],[-115,30],[-113,29],[-110,27],[-109,23],[-105,20],[-104,19],
    [-101,17],[-97,16],[-94,16],[-92,15],[-90,16],[-88,18],[-87,20],[-90,21],
    [-91,23],[-94,25],[-97,26],[-99,27],[-101,29],[-103,30],[-105,31],
    [-108,31.5],[-111,31.5],[-114,32],[-117,32]
  ],
  GUATEMALA: [
    [-92,15],[-90,16],[-89,17],[-89,15],[-90,14],[-92,14],[-92,15]
  ],
  HONDURAS: [
    [-89,16],[-87,16],[-85,16],[-83,15],[-83,13],[-86,13],[-88,14],[-89,15],[-89,16]
  ],
  NICARAGUA: [
    [-87,15],[-85,15],[-84,13],[-83,11],[-85,11],[-87,12],[-87,15]
  ],
  COSTA_RICA: [
    [-85,11],[-83,11],[-82,9],[-83,8],[-85,10],[-85,11]
  ],
  PANAMA: [
    [-83,9],[-81,9],[-79,9],[-77,8],[-78,7],[-80,7],[-83,8],[-83,9]
  ],
  COLOMBIA: [
    [-79,11],[-76,11],[-72,11],[-71,12],[-70,9],[-69,6],[-67,6],[-67,1],
    [-69,-1],[-70,-2],[-72,-2],[-74,-1],[-76,0],[-77,1],[-78,3],[-78,5],
    [-79,8],[-79,11]
  ],
  VENEZUELA: [
    [-72,11],[-70,12],[-67,11],[-64,11],[-61,10],[-60,8],[-61,6],[-63,5],
    [-65,4],[-67,2],[-67,6],[-69,6],[-70,9],[-71,12],[-72,11]
  ],
  GUYANA_REGION: [
    [-61,8],[-58,8],[-56,5],[-54,4],[-52,3],[-52,1],[-54,1],[-57,2],[-60,3],[-61,6],[-61,8]
  ],
  ECUADOR: [
    [-81,1],[-79,1],[-76,0],[-77,-1],[-79,-3],[-81,-3],[-81,1]
  ],
  PERU: [
    [-81,-3],[-79,-3],[-77,-2],[-74,-1],[-72,-2],[-70,-4],[-70,-9],[-69,-13],
    [-69,-17],[-71,-18],[-73,-17],[-76,-15],[-79,-8],[-81,-6],[-81,-3]
  ],
  BOLIVIA: [
    [-69,-11],[-66,-10],[-63,-12],[-60,-15],[-58,-17],[-58,-20],[-62,-22],
    [-65,-22],[-68,-22],[-69,-19],[-69,-17],[-69,-13],[-69,-11]
  ],
  BRAZIL: [
    [-72,-2],[-70,-2],[-69,-1],[-67,1],[-67,2],[-65,4],[-63,5],[-61,6],
    [-60,3],[-57,2],[-54,1],[-52,1],[-52,3],[-50,1],[-48,0],[-46,-1],
    [-44,-2],[-41,-3],[-38,-4],[-35,-5],[-35,-8],[-37,-11],[-39,-14],
    [-39,-18],[-41,-22],[-44,-23],[-46,-24],[-48,-26],[-49,-29],[-52,-32],
    [-54,-31],[-56,-30],[-57,-28],[-55,-25],[-55,-22],[-58,-20],[-58,-17],
    [-60,-15],[-63,-12],[-66,-10],[-69,-11],[-70,-9],[-70,-4],[-72,-2]
  ],
  PARAGUAY: [
    [-62,-22],[-58,-20],[-55,-22],[-55,-25],[-57,-27],[-60,-27],[-62,-25],[-62,-22]
  ],
  CHILE: [
    [-71,-18],[-69,-19],[-69,-22],[-69,-25],[-70,-30],[-71,-35],[-72,-40],
    [-73,-44],[-74,-48],[-74,-52],[-72,-54],[-71,-55],[-72,-50],[-73,-46],
    [-72,-42],[-72,-38],[-71,-33],[-71,-28],[-70,-23],[-70,-20],[-71,-18]
  ],
  ARGENTINA: [
    [-69,-22],[-65,-22],[-62,-22],[-60,-27],[-58,-30],[-58,-33],[-57,-35],
    [-58,-38],[-62,-40],[-65,-42],[-67,-46],[-69,-50],[-68,-53],[-66,-54],
    [-68,-52],[-70,-50],[-71,-46],[-72,-42],[-72,-38],[-71,-33],[-71,-28],
    [-70,-23],[-69,-22]
  ],
  URUGUAY: [
    [-58,-30],[-54,-31],[-53,-33],[-55,-34],[-57,-35],[-58,-33],[-58,-30]
  ],
};

const OUTLINE_HIGHLIGHT = ['MEXICO','HONDURAS','BRAZIL','ARGENTINA'];

function pathFromCoords(coords) {
  return coords.map(([lon, lat], i) => {
    const [x, y] = project(lon, lat);
    return (i === 0 ? 'M ' : 'L ') + x.toFixed(2) + ' ' + y.toFixed(2);
  }).join(' ') + ' Z';
}

function LatamMap({ events, hovered, onHover }) {
  return (
    <svg viewBox="0 0 100 140" preserveAspectRatio="xMidYMid meet">
      <defs>
        <pattern id="hatch" patternUnits="userSpaceOnUse" width="2" height="2" patternTransform="rotate(45)">
          <line x1="0" y1="0" x2="0" y2="2" stroke="currentColor" strokeWidth="0.3" opacity="0.22"/>
        </pattern>
      </defs>

      {/* Latitude reference lines */}
      {[
        { lat: 23.5, label: 'TROPIC OF CANCER · 23.5°N' },
        { lat: 0,    label: 'EQUATOR · 0°' },
        { lat: -23.5,label: 'TROPIC OF CAPRICORN · 23.5°S' },
      ].map((g, i) => {
        const [, y] = project(0, g.lat);
        return (
          <g key={i}>
            <line x1="0" y1={y} x2="100" y2={y} stroke="var(--line-3)" strokeWidth="0.15" strokeDasharray="0.6 1.2"/>
            <text x="99" y={y - 0.6} fill="var(--fg-3)" fontSize="1.5" fontFamily="JetBrains Mono" letterSpacing="0.15" textAnchor="end">{g.label}</text>
          </g>
        );
      })}

      {/* Country fills */}
      {Object.entries(COUNTRIES).map(([name, coords]) => {
        const isHi = OUTLINE_HIGHLIGHT.includes(name);
        return (
          <path
            key={name}
            d={pathFromCoords(coords)}
            fill={isHi ? 'var(--bg-3)' : 'var(--bg-2)'}
            stroke="var(--line-3)"
            strokeWidth="0.35"
            strokeLinejoin="round"
          />
        );
      })}

      {/* Hatch overlay only on visited countries */}
      {OUTLINE_HIGHLIGHT.map(name => (
        <path
          key={name + '-h'}
          d={pathFromCoords(COUNTRIES[name])}
          fill="url(#hatch)"
          style={{color:'var(--accent)'}}
          opacity="0.45"
        />
      ))}

      {/* Country labels */}
      {[
        { name: 'MEXICO',    lon: -103, lat: 24, size: 2.4 },
        { name: 'HONDURAS',  lon: -86,  lat: 14.6, size: 1.4 },
        { name: 'COLOMBIA',  lon: -73,  lat: 4,  size: 1.7 },
        { name: 'VENEZUELA', lon: -66,  lat: 7.5,size: 1.5 },
        { name: 'PERU',      lon: -75,  lat: -10,size: 1.7 },
        { name: 'BOLIVIA',   lon: -65,  lat: -17,size: 1.5 },
        { name: 'BRAZIL',    lon: -54,  lat: -11,size: 3.0 },
        { name: 'CHILE',     lon: -71.5, lat: -38, size: 1.5 },
        { name: 'ARGENTINA', lon: -65,  lat: -38,size: 2.0 },
        { name: 'URUGUAY',   lon: -55,  lat: -33,size: 1.2 },
        { name: 'PARAGUAY',  lon: -58,  lat: -23,size: 1.2 },
        { name: 'ECUADOR',   lon: -78.5,lat: -1.5,size: 1.2 },
      ].map((c, i) => {
        const [x, y] = project(c.lon, c.lat);
        const visited = OUTLINE_HIGHLIGHT.includes(c.name);
        return (
          <text
            key={i}
            x={x} y={y}
            fill={visited ? 'var(--fg)' : 'var(--fg-3)'}
            fontSize={c.size}
            fontFamily="JetBrains Mono"
            letterSpacing="0.25"
            textAnchor="middle"
            opacity={visited ? 0.95 : 0.65}
            fontWeight={visited ? 600 : 400}
          >{c.name}</text>
        );
      })}

      {/* Connection lines from SP outward (when nothing hovered) */}
      {hovered === null && events.map((e, i) => {
        if (e.city === 'São Paulo') return null;
        const sp = events.find(x => x.city === 'São Paulo');
        const [sx, sy] = project(sp.lon, sp.lat);
        const [ex, ey] = project(e.lon, e.lat);
        return (
          <line key={`l${i}`} x1={sx} y1={sy} x2={ex} y2={ey}
            stroke="var(--accent)" strokeWidth="0.18" strokeDasharray="0.5 0.8" opacity="0.5" />
        );
      })}

      {/* Markers */}
      {events.map((e, i) => {
        const [x, y] = project(e.lon, e.lat);
        const isHover = hovered === i;
        const r = Math.max(0.9, Math.min(2.4, e.count * 0.28 + 0.7));
        return (
          <g key={i} onMouseEnter={() => onHover(i)} onMouseLeave={() => onHover(null)} style={{cursor:'pointer'}}>
            <circle cx={x} cy={y} r={r + (isHover ? 3 : 2)} fill="var(--accent)" opacity={isHover ? 0.22 : 0.10}/>
            <circle cx={x} cy={y} r={r} fill="var(--accent)" stroke="var(--paper)" strokeWidth="0.3"/>
            {isHover && (
              <g style={{pointerEvents:'none'}}>
                <rect x={x + 2.5} y={y - 6} width={Math.max(18, e.city.length * 1.1 + 4)} height="5.4" fill="var(--fg)" rx="0.3"/>
                <text x={x + 3.5} y={y - 3.6} fill="var(--bg)" fontSize="1.7" fontFamily="JetBrains Mono" letterSpacing="0.12" fontWeight="500">
                  {e.city.toUpperCase()}
                </text>
                <text x={x + 3.5} y={y - 1.6} fill="var(--bg)" fontSize="1.3" fontFamily="JetBrains Mono" opacity="0.75">
                  {e.count} TALK{e.count > 1 ? 'S' : ''}
                </text>
              </g>
            )}
          </g>
        );
      })}
    </svg>
  );
}

function Speaking() {
  const [hovered, setHovered] = useState(null);
  const totalTalks = useMemo(() => SITE.events.reduce((s, e) => s + e.count, 0), []);
  const totalCities = SITE.events.length;

  return (
    <section id="speaking" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">05 · Speaking</div>
          <h2 className="section-title">Talks across <em>LATAM</em>.</h2>
        </div>

        <div className="speak-stats">
          <div className="speak-stat"><div className="n"><em>{totalTalks}</em>+</div><div className="l">Talks given</div></div>
          <div className="speak-stat"><div className="n">{totalCities}</div><div className="l">Cities</div></div>
          <div className="speak-stat"><div className="n">4</div><div className="l">Countries</div></div>
        </div>

        <div className="prod-callout">
          <div className="prod-callout-eyebrow">Beyond the stage</div>
          <div className="prod-callout-row">
            <div className="prod-stat">
              <div className="prod-n">10<em>+</em></div>
              <div className="prod-l">Events produced across Brazil</div>
            </div>
            <div className="prod-stat">
              <div className="prod-n"><em>1,500</em>+</div>
              <div className="prod-l">Attendees at the largest one</div>
            </div>
          </div>
        </div>

        <div className="speaking-grid">
          <div className="map-wrap">
            <LatamMap events={SITE.events} hovered={hovered} onHover={setHovered} />
            <div className="map-corners">
              <div><span>30°N</span><span>SPEAKING · 2022—2026</span></div>
              <div><span>30°S</span><span>{totalTalks} TALKS</span></div>
            </div>
          </div>
          <div className="city-list">
            {SITE.events.map((e, i) => (
              <div
                className={`city-row ${hovered === i ? 'active' : ''}`}
                key={i}
                onMouseEnter={() => setHovered(i)}
                onMouseLeave={() => setHovered(null)}
              >
                <div className="city-code">{e.code}</div>
                <div>
                  <div className="city-name">{e.city}</div>
                  <div className="city-event">{e.event}</div>
                </div>
                <div className="city-count">{e.count}×</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

// ── Photos ────────────────────────────────────────────
function Photos() {
  return (
    <section id="photos" className="block">
      <div className="wrap">
        <div className="section-head">
          <div className="section-tag">06 · Photos</div>
          <h2 className="section-title">On the <em>road</em>.</h2>
        </div>
        <div className="photo-grid">
          {SITE.photos.map((p, i) => (
            <figure className={`photo ${p.span || ''}`} key={i}>
              <span className="frame-num">FRAME {String(i + 1).padStart(2, '0')}</span>
              <img src={p.src} alt={`${p.caption} — ${p.place}`} loading="lazy" />
              <figcaption className="cap">
                <span>{p.caption} · {p.place}</span>
                <span>{p.date}</span>
              </figcaption>
            </figure>
          ))}
        </div>
      </div>
    </section>
  );
}

// ── Newsletter ────────────────────────────────────────
function Newsletter() {
  const [email, setEmail] = useState("");
  const [done, setDone] = useState(false);
  const onSubmit = (e) => { e.preventDefault(); if (email.includes('@')) setDone(true); };
  const n = SITE.newsletter;
  return (
    <section id="newsletter" className="block">
      <div className="wrap">
        <div className="newsletter-wrap">
          <div>
            <div className="nl-tag">→ Newsletter</div>
            <h2 className="nl-title">Occasional <em>notes</em>.</h2>
            <p className="nl-blurb">{n.blurb}</p>
          </div>
          <form className="nl-form" onSubmit={onSubmit}>
            {done ? (
              <div className="mono" style={{padding:'13px 18px', color:'var(--status)', fontSize:13, border:'1px solid var(--status)', textTransform:'uppercase', letterSpacing:'0.06em'}}>
                ✓ Subscribed. Talk soon.
              </div>
            ) : (
              <>
                <input className="nl-input" type="email" placeholder="you@domain.com" value={email} onChange={e => setEmail(e.target.value)} required />
                <button className="nl-btn" type="submit">{n.cta} →</button>
              </>
            )}
          </form>
        </div>
      </div>
    </section>
  );
}

// ── Footer ────────────────────────────────────────────
function Footer() {
  const year = new Date().getFullYear();
  return (
    <footer id="contact">
      <div className="wrap">
        <div className="foot-grid">
          <div className="foot-block">
            <div className="ft-tag">Say hi</div>
            <div className="colophon">
              Best on <a href="https://t.me/joaokury" target="_blank" rel="noopener">Telegram</a> for quick things, <a href="https://x.com/cripto_nita_" target="_blank" rel="noopener">X</a> for public ones. Long-form goes to email.
            </div>
          </div>

          <div className="foot-block">
            <div className="ft-tag">Elsewhere</div>
            <ul>
              {SITE.social.map(s => (
                <li key={s.label}>
                  <a href={s.url} target="_blank" rel="noopener">
                    <span>{s.label}</span><span className="handle">{s.handle}</span>
                  </a>
                </li>
              ))}
            </ul>
          </div>

          <div className="foot-block">
            <div className="ft-tag">On this page</div>
            <ul>
              <li><a href="#about"><span>About</span><span className="handle">01</span></a></li>
              <li><a href="#experience"><span>Work</span><span className="handle">02</span></a></li>
              <li><a href="#writing"><span>Writing</span><span className="handle">03</span></a></li>
              <li><a href="#videos"><span>Videos</span><span className="handle">04</span></a></li>
              <li><a href="#speaking"><span>Speaking</span><span className="handle">05</span></a></li>
              <li><a href="#photos"><span>Photos</span><span className="handle">06</span></a></li>
            </ul>
          </div>
        </div>

        <div className="foot-bottom">
          <span>© {year} João Kury · {SITE.domain}</span>
          <div className="built">
            <span>Made in São Paulo</span>
          </div>
        </div>
      </div>
    </footer>
  );
}

// ── App ───────────────────────────────────────────────
function App() {
  useFavicon();
  const [theme, toggleTheme] = useTheme();

  return (
    <>
      <Nav theme={theme} onToggle={toggleTheme} />
      <Hero />
      <About />
      <Experience />
      <Writing />
      <Videos />
      <Speaking />
      <Photos />
      <Newsletter />
      <Footer />
    </>
  );
}

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