SHEET_ID = "1eM7x2Si2bbUUBFjo9sR4XskrV41XsYpwmn4cWsLPj3I"
SHEET_GID = "1335221155"
PRESENT_LABEL = "Present"
// ── Fetch & parse ────────────────────────────────────────
sheetData = {
try {
const url = `https://docs.google.com/spreadsheets/d/${SHEET_ID}/export?format=csv&gid=${SHEET_GID}`
const res = await fetch(url)
if (!res.ok) return []
const text = await res.text()
return d3.csvParse(text).filter(d => d.in_resume === "TRUE")
} catch(e) {
return []
}
}
// ── Helpers ──────────────────────────────────────────────
function parseLink(str) {
if (!str) return { text: "", url: null }
const m = str.match(/^\[([^\]]+)\]\(([^)]+)\)/)
return m ? { text: m[1], url: m[2] } : { text: str, url: null }
}
function fmtRange(start, end) {
const e = (end || "").trim()
return e ? `${start} — ${end}` : `${start} — ${PRESENT_LABEL}`
}
function bullets(row) {
return [row.description_1, row.description_2, row.description_3]
.filter(d => d && d.trim())
.map(d => d.replace(/^[•\-]\s*/, "").trim())
}
// ── Filtered subsets ─────────────────────────────────────
workExp = sheetData.filter(d => d.section === "working_experience")
.sort((a,b) => Number(b.start) - Number(a.start))
education = sheetData.filter(d => d.section === "education")
.sort((a,b) => Number(b.start) - Number(a.start))
projects = sheetData.filter(d => d.section === "research_projects")
.sort((a,b) => Number(b.start) - Number(a.start))
certs = sheetData.filter(d => d.section === "short_courses")
.sort((a,b) => Number(b.start) - Number(a.start))
// ── Arrow icon ───────────────────────────────────────────
arrowSvg = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>`