/* ---------- Content (edit here) ---------- */ // tags: ex = exhibition, com = commissioned work, scr = screening/talk, //       res = residency, good = good news.  sel: true = shown in "Selected Work" mode. const projects = [  { y: 2026, t: "RUSHED", u: "https://paulagarciasans.com/rushed" },  { y: 2026, t: "Undertale", u: "https://paulagarciasans.com/undertale" },  { y: 2026, t: "Ethereal Estate", u: "https://paulagarciasans.com/ethereal-estate-1" },  { y: 2025, t: "The Hatching", u: "https://paulagarciasans.com/the-hatching" },  { y: 2023, t: "Nacreous Clouds", u: "https://paulagarciasans.com/nacreous-clouds-1" },  { y: 2022, t: "Bodies that don’t age", u: "https://paulagarciasans.com/bodies-that-don't-age-1" },  { y: 2021, t: "Hole to Bliss", u: "https://paulagarciasans.com/hole-to-bliss-1" },  { y: 2020, t: "Hyperindividualized Pleasure", u: "https://paulagarciasans.com/hyperindividualized-pleasure-1" },  { y: "", t: "COMMISSIONS", u: "https://paulagarciasans.com/commissions" } ]; const cv = [  { y: 2026, t: "Oblivion was inevitable, Kunstfort bij Vijfhuizen, NL", u: "https://www.kunstfort.nl/nl/tentoonstellingen/de-vergetelheid-was-onvermijdelijk/", tags: ["ex"], sel: true },  { y: 2026, t: "Friendly Secrecy System, Sickhouse, Enschede, NL", tags: ["ex"], sel: true },  { y: 2025, t: "Sala d’Art Jove 2025, HAUS, Barcelona, SP", u: "https://saladartjove.cat/es/artistas-archive/paula-garcia-sans/", tags: ["ex", "good"], sel: true },  { y: 2025, t: "GLOPS Bienal, Vilafranca del Penedès, SP", u: "https://glops.pinnae.cat/artista/paula-garcia-sans/", tags: ["ex"], sel: true },  { y: 2025, t: "3D modelling for Heleen Mineur’s FOLLY, NL", u: "https://www.centraalmuseum.nl/nl/nu-te-zien/tentoonstellingen/folly-een-speculatieve-hervertelling", tags: ["com"], sel: true },  { y: 2025, t: "GlogauAIR Residency, Berlin, DE", u: "https://glogauair.net/activity/meet-the-artist-paula-garcia-sans/", tags: ["res"], sel: true },  { y: 2025, t: "Machinimas, Dokzaal, Amsterdam, NL", u: "https://plantagedok.nl/event/an-evening-of-screenings-by-paula-garcia-sans-faysal-mroueh-and-morgane-billuart/", tags: ["scr"] },  { y: 2025, t: "Worldbuilding and animations for Lorena Solis Bravo’s Samper Mendoza, Virreina Residency, Bogotá, CO", tags: ["com"] },  { y: 2025, t: "Prospects, Art Rotterdam, NL", tags: ["ex"] },  { y: 2025, t: "Animation for Clara Rojas, SIGN Gallery, Groningen, NL", tags: ["com"] },  { y: 2024, t: "MACA x Museumnight, group show, Amsterdam, NL", tags: ["ex"] },  { y: 2024, t: "Animations for Lorena Solis Bravo’s myth, moth, mother", tags: ["com"] },  { y: 2024, t: "The sun called it a day, group show at Neverneverland, Amsterdam, NL", tags: ["ex"] },  { y: 2024, t: "Everything is one the one, group show at Arti et Amicitiae, Amsterdam, NL", u: "https://www.arti.nl/tentoonstelling/everything-is-on-the-one/", tags: ["ex"] },  { y: 2023, t: "I gazed at your visceral ripples, group show at Gallery Elipsis, Amsterdam, NL", tags: ["ex"] },  { y: 2023, t: "Agora, panel talk organized by MARC, Amsterdam, NL", u: "https://marc.amsterdam/MARC-Agora-1", tags: ["scr"] },  { y: 2023, t: "Boring Festival, commissioned by the Kunstfort bij Vijfhuizen, Haarlem, NL", u: "https://www.kunstfort.nl/en/public-program/kunstfort-bij-vijfhuizen-presents-nacreous-clouds-by-paula-garcia-sans-on-boring-festival/", tags: ["ex", "com"], sel: true },  { y: 2023, t: "VFX for Josefin Arnell’s Beast&Feast", u: "https://www.franshalsmuseum.nl/en/event/fever-dream/", tags: ["com"] },  { y: 2023, t: "Future Deserts, group show at Salbker Wassertum, invited by onEARTH Foundation, Magdeburg, DE", tags: ["ex"] },  { y: 2022, t: "3D design for Mathilde Renault’s The Butterfly Effect, International Documentary Festival of Amsterdam, NL", u: "https://www.idfa.nl/en/film/c0167002-068b-41f4-8376-2b096ec0f847/the-butterfly-effect/", tags: ["com"] },  { y: 2022, t: "Bodies that don’t age, exhibition commissioned by the Douanelab, Amsterdam, NL", tags: ["ex", "com"], sel: true },  { y: 2022, t: "BYOB, group show, Upstream Gallery x Oedipus, Amsterdam, NL", tags: ["ex"] },  { y: 2022, t: "Worlds that world, Kunstfort bij Vijfhuizen, Haarlem, NL", u: "https://www.kunstfort.nl/en/news/presentations-worlds-that-world/", tags: ["ex"] },  { y: 2022, t: "Subbacultcha x Rosedout World, visuals for event at ISO, Amsterdam, NL", tags: ["com"] },  { y: 2022, t: "Stedelijk Museum Night, visuals for The New Originals, Amsterdam, NL", u: "https://www.stedelijk.nl/en/events/museumnacht-2021-2", tags: ["com"] },  { y: 2021, t: "3 campaign images for the Dutch National Opera season of 2021-2022", u: "https://www.operaballet.nl/en/dno-x-young-artists", tags: ["com"] },  { y: 2021, t: "MIRA festival & IDEAL, group show curated by mmmad.art, Barcelona, ES", tags: ["ex"] },  { y: 2021, t: "10s10a, online exhibition, curated by mmmad.art for The Wrong Biennale", u: "https://mmmad.art/10s10a-x-The-Wrong-Biennale", tags: ["ex"] },  { y: 2021, t: "Sensual Havoc II, group show at De School-Subbacultcha space, Amsterdam, NL", u: "https://subbacultcha.nl/event/sensual-havoc-ii/", tags: ["ex"] },  { y: 2021, t: "There’s never been a winter so long that spring didn’t come, Laurel Project Space, Amsterdam, NL", u: "https://www.laurelprojectspace.com/exhibitions/There's-Never-Been-a-Winter-So-Long-the-Spring-Didn't-Come", tags: ["ex"] },  { y: 2021, t: "Oh, the places you’d go, group show at the Willem-Twee Museum, Den Bosch, NL", u: "https://www.youtube.com/watch?v=2RtARaV5Qjw", tags: ["ex"] },  { y: 2021, t: "Animation for Nicolas Arthen’s An intricate well", u: "https://www.pakt.nu/2021/nicola-arthen-am-i-an-object-part-ii/", tags: ["com"] },  { y: 2021, t: "Comfort and Vision, curated by Salim Bayri for the One Minutes Foundation", u: "https://nieuweinstituut.nl/en/events/comfort-and-vision", tags: ["scr"] },  { y: 2020, t: "Call for graduates, NEST Ruimte x Melkweg Expo, Den Haag, NL", u: "https://www.mistermotley.nl/calls-graduates/", tags: ["ex"] },  { y: 2020, t: "Kantarion Sound x Off Center, visuals for Yara Said, The Grey Space in the Middle, Den Haag, NL", tags: ["com"] },  { y: 2019, t: "Eye on Art, film screening, Eye Museum, Amsterdam, NL", tags: ["scr"] },  { y: 2017, t: "VR operator, Carne y Arena, Eye Museum, Amsterdam, NL", u: "https://www.eyefilm.nl/en/whats-on/carne-y-arena-virtually-present-physically-invisible/507887", tags: ["com"] } ]; const grants = [  { y: 2026, t: "Fulbright Scholarship", tags: ["grant", "good"] },  { y: 2025, t: "Amsterdams Fonds voor de Kunst, Development Grant", tags: ["grant"] },  { y: 2025, t: "Prize Sala d’Art Jove Barcelona", tags: ["grant", "good"] },  { y: 2025, t: "Digital Culture Research grant, Stimuleringsfonds", tags: ["grant"] },  { y: 2024, t: "Mondriaan Fonds Voucher Development", tags: ["grant"] },  { y: 2024, t: "AFK Project Grant, in collab with Eefje Stenfert", tags: ["grant"] },  { y: 2024, t: "Prins Bernhard Cultuurfonds, Study Grant", tags: ["grant"] },  { y: 2023, t: "Mondriaan Fonds Artist Start Grant", tags: ["grant"] } ]; const education = [  { y: "now", t: "MS Fiction & Entertainment, Southern California Institute of Architecture", tags: [] },  { y: 2020, t: "BA Moving Image, Gerrit Rietveld Academie", tags: [] } ]; /* ---------- Rendering ---------- */ const TAG_LABELS = { ex: "exhibition", com: "commission", scr: "screening/talk", res: "residency", grant: "grant", good: "good news" }; function row(item, extraClass = "") {  const li = document.createElement("li");  li.dataset.tags = (item.tags || []).join(" ");  if (item.sel) li.dataset.sel = "1";  if (extraClass) li.className = extraClass;  const y = document.createElement("span");  y.className = "year";  y.textContent = item.y === "" ? "" : item.y;  const body = document.createElement("span");  if (item.u) {    const a = document.createElement("a");    a.href = item.u; a.target = "_blank"; a.rel = "noopener";    a.textContent = item.t;    body.append(a);  } else {    body.append(item.t);  }  if ((item.tags || []).includes("good")) {    const g = document.createElement("span");    g.className = "tag tag-good"; g.textContent = "GOOD NEWS";    body.append(g);  }  li.append(y, body);  return li; } function renderList(id, items) {  const ul = document.getElementById(id);  items.forEach(i => ul.append(row(i))); } renderList("cv-list", cv); renderList("grant-list", grants); renderList("edu-list", education); const pl = document.getElementById("project-list"); projects.forEach(p => {  const li = document.createElement("li");  const y = document.createElement("span");  y.className = "year"; y.textContent = p.y;  const a = document.createElement("a");  a.className = "title"; a.href = p.u;  a.textContent = p.t + (p.y ? " - " + p.y : "");  // original site shows "[Title - Year]"; the year column already carries it  a.textContent = p.t;  const wrap = document.createElement("span");  wrap.append(a);  li.append(y, wrap);  pl.append(li); }); /* ---------- Quick facts toggle ---------- */ const toggle = document.getElementById("facts-toggle"); const facts = document.getElementById("facts"); toggle.addEventListener("click", () => {  const open = facts.hasAttribute("hidden");  facts.toggleAttribute("hidden", !open);  toggle.setAttribute("aria-expanded", String(open));  toggle.querySelector(".plus").textContent = open ? "–" : "+"; }); /* ---------- Highlight filters ---------- */ const filterButtons = document.querySelectorAll(".filters button"); let active = ""; function applyFilter() {  document.body.classList.toggle("filtering", !!active);  document.querySelectorAll(".cv li").forEach(li => {    const tags = (li.dataset.tags || "").split(" ");    li.classList.toggle("hl", !!active && tags.includes(active));  });  filterButtons.forEach(b => b.setAttribute("aria-pressed", String(b.dataset.filter === active && !!active))); } filterButtons.forEach(b => {  b.addEventListener("click", () => {    active = (b.dataset.filter === active) ? "" : b.dataset.filter;    applyFilter();  }); }); /* ---------- Selected / all mode ---------- */ const modeBtn = document.getElementById("mode-toggle"); const modeName = document.getElementById("mode-name"); let showAll = false; function applyMode() {  document.querySelectorAll("#cv-list li").forEach(li => {    li.hidden = !showAll && !li.dataset.sel;  });  modeName.textContent = showAll ? "'All Work'" : "'Selected Work'";  modeBtn.textContent = showAll ? "show less" : "show more"; } modeBtn.addEventListener("click", () => { showAll = !showAll; applyMode(); }); applyMode();