// Site content: CV data, photo series, essays. Single source of truth.

const SITE = {
  name: 'Vladyslav Ostroukhov',
  nameShort: 'Vlady Ostroukhov',
  initials: 'V.O.',
  tagline: 'Environmental scientist, sometimes a chemist, occasionally writes things down.',
  bio_short: 'Born in Donetsk (2004). Currently in Lund, finishing a Master\'s in sustainability science. Worked in geothermal exploration, then medicinal photochemistry, then sustainability. Co-founded two Ukrainian education NGOs. Reads more than is healthy.',
  location: 'Lund, Sweden',
  email: 'vlady.ost.s@proton.me',
  phone: '+46 733 450 390',
  signal: 'vlady.13',
  linkedin: 'https://www.linkedin.com/in/vlady-ost',
  substack: 'https://substack.com/@vladyost',
  instagram: 'https://www.instagram.com/vlady.ost',
  oldPortfolio: 'https://vladyslav-ostroukhov.my.canva.site/photography',
};

// Essays. Two collections — `mine` (written by me) and `sup` (published under
// my editorship). Each is its own page; `url` is the original on Telegraph.
// `date` is YYYY.MM. Listed oldest→newest here; the UI shows newest first.
// Internal body/images get filled in per id as materials come in (see ESSAY_BODY).
const ESSAYS = [
  // ── My essays ───────────────────────────────────────────────
  { id:'m01', sec:'mine', date:'2023.09', title:"The Problem with Occam's Razor", url:'https://telegra.ph/Problema-britvi-Okkama-09-11' },
  { id:'m02', sec:'mine', date:'2023.09', title:'Who Killed the Dinosaurs', url:'https://telegra.ph/Hto-vbiv-dinozavr%D1%96v-09-09' },
  { id:'m03', sec:'mine', date:'2023.10', title:"What's Wrong with Evolution", url:'https://telegra.ph/SHCHo-ne-tak-z-evolyuc%D1%96yeyu-10-03' },
  { id:'m04', sec:'mine', date:'2023.11', title:"What's Wrong with Evolution: Survey Results", url:'https://telegra.ph/SHCHo-ne-tak-z-evolyuc%D1%96yeyu-Rezultati-opituvannya-11-21' },
  { id:'m05', sec:'mine', date:'2024.03', title:"Where COVID-19 Came From, and Who's Blocking the FBI Investigation", url:'https://telegra.ph/Zv%D1%96dki-vil%D1%96z-COVID-19-%D1%96-hto-pereshkodzhaye-rozsl%D1%96duvannyu-FBR-03-31' },
  { id:'m06', sec:'mine', date:'2024.06', title:'Why The Lord of the Rings Is a Story About Ukraine', url:'https://telegra.ph/CHomu-Volodar-persn%D1%96v-ce-rozpov%D1%96d-pro-Ukrainu-06-18' },
  { id:'m07', sec:'mine', date:'2024.07', title:'What Even Is This Fusion of Yours?', url:'https://telegra.ph/Hto-cej-vash-termoyad-07-11' },
  { id:'m08', sec:'mine', date:'2024.09', title:'Learned Helplessness and Ukrainian Schools', url:'https://telegra.ph/Vivchena-bezporadn%D1%96st-%D1%96-ukrainsk%D1%96-shkoli-09-06' },
  { id:'m09', sec:'mine', date:'2024.10', title:'The World Has Gone Global', url:'https://telegra.ph/Sv%D1%96t-stav-globalnim-10-14' },
  { id:'m10', sec:'mine', date:'2024.11', title:'Poland and Slovakia: The Elections', url:'https://telegra.ph/Polshcha-%D1%96-Slovachchina-Vibori-11-02' },
  { id:'m11', sec:'mine', date:'2024.12', title:"Bias Toward Others' Actions vs. Pride in Their Absence", url:'https://telegra.ph/Uperedzhen%D1%96st-shchodo-d%D1%96j-%D1%96nshih-VS-gord%D1%96st-cherez-ih-v%D1%96dsutn%D1%96st-12-01' },
  { id:'m12', sec:'mine', date:'2025.03', title:"You Won't Have a Pension", url:'https://telegra.ph/U-tebe-ne-bude-pens%D1%96i-03-07' },
  { id:'m13', sec:'mine', date:'2025.06', title:'The Kakhovka Dam, One Year On', url:'https://telegra.ph/Kahovska-GES-1-r%D1%96k-op%D1%96slya-06-06' },
  { id:'m14', sec:'mine', date:'2025.07', title:'Donating Is Cool', url:'https://telegra.ph/Donorstvo-ce-kruto-07-19' },
  { id:'m15', sec:'mine', date:'2025.11', title:'Effective Communication', url:'https://telegra.ph/Efektivna-komun%D1%96kac%D1%96ya-11-17' },
  { id:'m16', sec:'mine', date:'2025.12', title:'The One Who Slays the Dragon', url:'https://telegra.ph/Toj-hto-vbivaye-drakona-12-16' },
  { id:'m17', sec:'mine', date:'2026.03', title:'Ideological Drift', url:'https://telegra.ph/%D0%86deolog%D1%96chnij-drift-03-19' },

  // ── Published under my supervision ──────────────────────────
  { id:'s01', sec:'sup', date:'2022.09', title:'Ukrainian Trade: From the Varangians to the Greeks, and the Gas Pipe', url:'https://telegra.ph/Ukrainska-torg%D1%96vlya-z-varyag-u-greki-ta-gazova-truba-09-06' },
  { id:'s02', sec:'sup', date:'2022.09', title:'Oumuamua', url:'https://telegra.ph/Oumuamua-09-29' },
  { id:'s03', sec:'sup', date:'2022.10', title:'Panslavism', url:'https://telegra.ph/Panslav%D1%96zm-10-07' },
  { id:'s04', sec:'sup', date:'2022.10', title:'Panslavism, Continued', url:'https://telegra.ph/Panslav%D1%96zm-Prodovzhennya-10-09' },
  { id:'s05', sec:'sup', date:'2022.10', title:"What Determines a Child's Sex", url:'https://telegra.ph/V%D1%96d-chogo-zalezhit-stat-ditini-10-13' },
  { id:'s06', sec:'sup', date:'2023.03', title:'The Ukrainian Vertep: How It Emerged and Why the Soviets Banned It', url:'https://telegra.ph/Ukrainskij-vertep-yak-v%D1%96n-z%CA%BCyavivsya-%D1%96-chomu-jogo-zaboronyala-radyanska-vlada-03-09' },
  { id:'s07', sec:'sup', date:'2023.05', title:'What Are These Dates: The Eighth and Ninth of May', url:'https://telegra.ph/SHCHo-ce-za-dati-tak%D1%96--vosme-ta-dev%CA%BCyate-travnya-05-08' },
  { id:'s08', sec:'sup', date:'2023.05', title:'Mykhailo Volobuyev: Author of an Independent Ukrainian Economy', url:'https://telegra.ph/Mihajlo-Volobuyev-Avtor-%D1%96dei-ukrainskoi-nezalezhnoi-ekonom%D1%96ki-05-18' },
  { id:'s09', sec:'sup', date:'2023.06', title:'Dissidents: The Names of Ukrainian Heroes', url:'https://telegra.ph/Disidenti-%D1%96mena-ukrainskih-geroiv-06-10' },
  { id:'s10', sec:'sup', date:'2023.06', title:"The Constitution of All European Constitutions: Pylyp Orlyk's Innovation", url:'https://telegra.ph/Konstituc%D1%96ya-us%D1%96h-yevropejskih-konstituc%D1%96j-novatorstvo-Pilipa-Orlika-06-28' },
  { id:'s11', sec:'sup', date:'2023.07', title:'Down with Sharovarshchyna', url:'https://telegra.ph/SHarovarshchinu---get-07-27-2' },
  { id:'s12', sec:'sup', date:'2023.08', title:'The Belt and Road Initiative', url:'https://telegra.ph/%D0%86n%D1%96c%D1%96ativa-Poyas-%D1%96-shlyah-08-03' },
  { id:'s13', sec:'sup', date:'2023.08', title:'32 Years: Three Lost and Two Reborn Hopes for Ukraine', url:'https://telegra.ph/32-roki-3-vtrachen%D1%96-ta-2-v%D1%96drodzhen%D1%96-nad%D1%96i-Ukraini-08-24-2' },
  { id:'s14', sec:'sup', date:'2023.09', title:'The Nature of Homosexuality', url:'https://telegra.ph/Priroda-gomoseksualnost%D1%96-09-22' },
  { id:'s15', sec:'sup', date:'2023.10', title:'The Genius of Les Kurbas', url:'https://telegra.ph/U-chomu-gen%D1%96j-Lesya-Kurbasa-10-05' },
  { id:'s16', sec:'sup', date:'2023.11', title:"Ukraine's Economy After the Maidan", url:'https://telegra.ph/Ekonom%D1%96ka-Ukraini-p%D1%96slya-Majdanu-11-10' },
  { id:'s17', sec:'sup', date:'2023.11', title:'The Fermi Paradox', url:'https://telegra.ph/Paradoks-Ferm%D1%96-11-17' },
  { id:'s18', sec:'sup', date:'2023.12', title:'Idiots and Democracy, or Why Populism Threatens the State', url:'https://telegra.ph/%D0%86d%D1%96oti-ta-demokrat%D1%96ya-abo-chomu-popul%D1%96zm--ce-zagroza-dlya-derzhavi-12-13' },
  { id:'s19', sec:'sup', date:'2023.12', title:'Reaganomics', url:'https://telegra.ph/Rejganom%D1%96ka-12-22' },
  { id:'s20', sec:'sup', date:'2024.03', title:"How a Scandalous Lady Set Britain's Economy Right", url:'https://telegra.ph/YAk-skandalna-pan%D1%96-navela-lad-v-ekonom%D1%96c%D1%96-Velikobritan%D1%96i-03-01' },
  { id:'s21', sec:'sup', date:'2024.03', title:'The Land Market: Did It Change Anything?', url:'https://telegra.ph/Rinok-zeml%D1%96-chi-prineslo-ce-yak%D1%96s-zm%D1%96n-03-15' },
  { id:'s22', sec:'sup', date:'2024.03', title:'In Moldova: Moldovan or Romanian?', url:'https://telegra.ph/U-Moldov%D1%96---moldovska-chi-rumunska-03-22' },
  { id:'s23', sec:'sup', date:'2024.06', title:'What Is Liberalism', url:'https://telegra.ph/SHCHo-take-l%D1%96beral%D1%96zm-06-13' },
  { id:'s24', sec:'sup', date:'2024.06', title:'Why Private Medicine Beats Public', url:'https://telegra.ph/CHomu-privatna-medicina-krashche-za-derzhavnu-06-20' },
  { id:'s25', sec:'sup', date:'2024.06', title:'How Pride Month Came to Be', url:'https://telegra.ph/YAk-zyavivsya-m%D1%96syac-gordost%D1%96-06-27' },
  { id:'s26', sec:'sup', date:'2024.07', title:'State Policy on Drug Circulation', url:'https://telegra.ph/Derzhavna-pol%D1%96tika-v-sfer%D1%96-oborotu-narkotik%D1%96v-07-04' },
  { id:'s27', sec:'sup', date:'2024.07', title:'The Decline of the Free Market, or Insane Credit Expansion', url:'https://telegra.ph/Zanepad-v%D1%96lnogo-rinku-chi-bozhev%D1%96lna-kreditna-ekspans%D1%96ya-07-27' },
  { id:'s28', sec:'sup', date:'2024.07', title:"Hezbollah: Iran's Terror Machine in the Middle East", url:'https://telegra.ph/Hezbolla-%D0%86ranska-mashina-teroru-na-Blizkomu-Shod%D1%96-07-30' },
  { id:'s29', sec:'sup', date:'2024.08', title:"The USSR's Largest HIV/AIDS Outbreak, and Why the Real Cause Was Hidden", url:'https://telegra.ph/Najb%D1%96lshij-spalah-V%D0%86L-SN%D0%86Du-v-Radyanskomu-soyuz%D1%96-chomu-spravzhnyu-prichinu-prihovuvali-08-09' },
  { id:'s30', sec:'sup', date:'2024.08', title:"Myths About Burns and Heatstroke: A Combat Medic's Advice", url:'https://telegra.ph/M%D1%96fi-pro-op%D1%96ki--teplov%D1%96-udari-poradi-bojovogo-medika-08-16' },
  { id:'s31', sec:'sup', date:'2024.08', title:"Durov's Arrest: A Threat to Free Speech", url:'https://telegra.ph/Aresht-Durova---zagroza-svobod%D1%96-slova-08-27' },
  { id:'s32', sec:'sup', date:'2024.09', title:'Protests in Israel: Why People Demand a Ceasefire', url:'https://telegra.ph/Protesti-v-%D0%86zrail%D1%96-chomu-lyudi-vimagayut-pripinennya-vognyu-09-04' },
  { id:'s33', sec:'sup', date:'2024.09', title:"Your Passport in a Terrorist's Hands: Diia Goes Open Source", url:'https://telegra.ph/Tv%D1%96j-pasport-v-rukah-u-terorista-D%D1%96ya-vihodit-v-open-source-09-07' },
  { id:'s34', sec:'sup', date:'2024.09', title:'I Have Nothing to Hide', url:'https://telegra.ph/Men%D1%96-nema-chogo-hovati-09-12' },
  { id:'s35', sec:'sup', date:'2024.09', title:'State Symbols: Their History and Role Today', url:'https://telegra.ph/Derzhavna-simvol%D1%96ka-ii-%D1%96stor%D1%96ya-%D1%96-rol-v-suchasnost%D1%96-09-20' },
  { id:'s36', sec:'sup', date:'2024.09', title:'The Irish Republican Army, Part I', url:'https://telegra.ph/%D0%86rlandska-respubl%D1%96kanska-arm%D1%96ya-%D0%86-09-23' },
  { id:'s37', sec:'sup', date:'2024.10', title:'The Irish Republican Army, Part II', url:'https://telegra.ph/%D0%86rlandska-respubl%D1%96kanska-arm%D1%96ya-%D0%86%D0%86-10-01' },
  { id:'s38', sec:'sup', date:'2024.10', title:'The Irish Republican Army, Part III', url:'https://telegra.ph/%D0%86rlandska-respubl%D1%96kanska-arm%D1%96ya-%D0%86%D0%86%D0%86-10-07' },
  { id:'s39', sec:'sup', date:'2024.10', title:'The House with Chimaeras', url:'https://telegra.ph/Budinok-z-himerami-10-17-2' },
  { id:'s40', sec:'sup', date:'2024.10', title:'Scandinavia Before the Viking Age', url:'https://telegra.ph/Skandinav%D1%96ya-do-epohi-v%D1%96k%D1%96ng%D1%96v-10-23' },
  { id:'s41', sec:'sup', date:'2024.10', title:'Through the Pages of the Unerased Skrypnykivka: Why We Should Return to Kharkiv Orthography', url:'https://telegra.ph/Stor%D1%96nkami-neznishchenoi-skripnik%D1%96vki-CHomu-potr%D1%96bno-povertatisya-do-norm-hark%D1%96vskogo-pravopisu-10-28' },
  { id:'s42', sec:'sup', date:'2024.10', title:'Schizophrenia', url:'https://telegra.ph/SHizofren%D1%96ya-10-30-2' },
  { id:'s43', sec:'sup', date:'2024.11', title:'Elections Will Change Forever', url:'https://telegra.ph/Vibori-zm%D1%96nyatsya-nazavzhdi-11-04-3' },
  { id:'s44', sec:'sup', date:'2024.11', title:'Aristotle, the Father of Sexism', url:'https://telegra.ph/Ar%D1%96stotel--batko-seksizmu-11-08' },
  { id:'s45', sec:'sup', date:'2024.11', title:'Punitive Psychiatry in the USSR', url:'https://telegra.ph/Karalna-psih%D1%96atrichna-medicina-SRSR-11-10' },
  { id:'s46', sec:'sup', date:'2024.11', title:'Farewell, Democracy: How Germany Turned Nazi', url:'https://telegra.ph/Proshchavaj-demokrat%D1%96ye-yak-N%D1%96mechchina-stala-nacistskoyu-11-20' },
  { id:'s47', sec:'sup', date:'2024.12', title:'STALKER 2 and Soft Power', url:'https://telegra.ph/STALKER-2-%D1%96-myaka-sila-12-02' },
  { id:'s48', sec:'sup', date:'2024.12', title:'Genocide', url:'https://telegra.ph/Genocid-12-05-3' },
  { id:'s49', sec:'sup', date:'2024.12', title:'They Glowed After Work', url:'https://telegra.ph/Voni-sv%D1%96tilisya-p%D1%96slya-roboti-12-09' },
  { id:'s50', sec:'sup', date:'2024.12', title:'What Kind of God Are You', url:'https://telegra.ph/YAkij-zhe-ti-Bozhe-12-20-2' },
  { id:'s51', sec:'sup', date:'2024.12', title:'How Christians Banned Christmas for Themselves', url:'https://telegra.ph/YAk-hristiyani-sob%D1%96-R%D1%96zdvo-zaboronili-12-23' },
  { id:'s52', sec:'sup', date:'2024.12', title:'The Su-57: Stealth or Not?', url:'https://telegra.ph/Su-57-stels-chi-vse-taki-n%D1%96-12-27-4' },
  { id:'s53', sec:'sup', date:'2024.12', title:'Arse, Aristotle, and a Bottle: English Is a Joke', url:'https://telegra.ph/Dupa-Ar%D1%96stotel-ta-plyashka-Angl%D1%96jska--ce-zhart-12-30-2' },
  { id:'s54', sec:'sup', date:'2025.01', title:'Ded Moroz Ran After You and Shed Bitter Tears, or What the USSR Has to Do with It', url:'https://telegra.ph/Za-toboyu-b%D1%96gala-D%D1%96du-Moroz-prolila-nemalo-g%D1%96rkih-sl%D1%96z-abo-do-chogo-tut-SRSR-01-01' },
  { id:'s55', sec:'sup', date:'2025.01', title:'Betraying Family for Communism: Three Stories from Red China', url:'https://telegra.ph/Zraditi-s%D1%96myu-zaradi-komun%D1%96zmu-tri-%D1%96stor%D1%96i-z-chervonogo-Kitayu-01-06' },
  { id:'s56', sec:'sup', date:'2025.01', title:'The War of All Against All, or How Modern Society Came to Be', url:'https://telegra.ph/V%D1%96jna-vs%D1%96h-proti-vs%D1%96h-abo-yak-postalo-suchasne-susp%D1%96lstvo-01-14' },
  { id:'s57', sec:'sup', date:'2025.01', title:'How the Moscow Patriarchate Became an Obelisk of Russian Propaganda', url:'https://telegra.ph/YAk-moskovskij-patr%D1%96arhat-stav-obel%D1%96skom-ros%D1%96jskoi-propagandi-01-28' },
  { id:'s58', sec:'sup', date:'2025.02', title:'Enemies of the People in the USSR', url:'https://telegra.ph/Vorogi-narodu-u-SRSR-02-04' },
  { id:'s59', sec:'sup', date:'2025.02', title:"The Psychology of Food Addiction and the Food Industry's Influence", url:'https://telegra.ph/Psiholog%D1%96ya-harchovoi-zalezhnosti-ta-vpliv-harchovoi-%D1%96ndustr%D1%96i-02-12' },
  { id:'s60', sec:'sup', date:'2025.02', title:'DeepSeek R1: Chinese Breakthrough or Cheap Hype?', url:'https://telegra.ph/Deepseek-R1--kitajskij-fenomen-chi-deshevij-hajp-02-19' },
  { id:'s61', sec:'sup', date:'2025.03', title:'The New Autocracies', url:'https://telegra.ph/Nov%D1%96-avtokrat%D1%96i-03-05-7' },
  { id:'s62', sec:'sup', date:'2025.03', title:"The Baptism of Rus in the Ideology of the 'Russian World'", url:'https://telegra.ph/Hreshchennya-Rus%D1%96-v-%D1%96deolog%D1%96i-ruskogo-m%D1%96ra-03-11-2' },
  { id:'s63', sec:'sup', date:'2025.04', title:'How to Field Awkward Questions with Humour and Dignity: Lessons from Political Leaders', url:'https://telegra.ph/YAk-krasivo-v%D1%96dpov%D1%96dati-na-nezruchn%D1%96-zapitannya-z-gumorom-%D1%96-g%D1%96dn%D1%96styu-uroki-v%D1%96d-pol%D1%96tichnih-l%D1%96der%D1%96v-04-09' },
];

// Per-essay content lives in essays/<id>.jsx — ONE SMALL FILE PER ESSAY.
// To add an essay: copy essays/_TEMPLATE.jsx, fill it in, and add one
// <script> line for it in index.html. See the template for full instructions.
const ESSAY_BODY = {};
function registerEssay(e) {
  const meta = { ...e };
  delete meta.body; delete meta.keywords;
  const i = ESSAYS.findIndex((x) => x.id === e.id);
  if (i >= 0) Object.assign(ESSAYS[i], meta); else ESSAYS.push(meta);
  if (e.body || e.keywords) ESSAY_BODY[e.id] = { body: e.body || '', keywords: e.keywords || [] };
}

const SERIES = [
  { id: 's6', year: 2026, title: 'PBC Summer Camp — day three', sub: 'Departure.', frames: 10, no: '06', cover: 'assets/series/s6/01.jpg' },
  { id: 's7', year: 2026, title: 'PBC Summer Camp — day two', sub: 'The middle day.', frames: 10, no: '07', cover: 'assets/series/s7/01.jpg' },
  { id: 's8', year: 2026, title: 'PBC Summer Camp — day one', sub: 'Arrival.', frames: 10, no: '08', cover: 'assets/series/s8/01.jpg' },
  { id: 's9', year: 2026, title: 'Lunds natur', sub: 'The city\'s green edges.', frames: 10, no: '09', cover: 'assets/series/s9/01.jpg' },
  { id: 's10', year: 2026, title: 'B28 graduation', sub: 'Caps, and the throwing of them.', frames: 10, no: '10', cover: 'assets/series/s10/01.jpg' },
  { id: 's11', year: 2026, title: 'K2A fair', sub: 'A careers fair.', frames: 10, no: '11', cover: 'assets/series/s11/01.jpg' },
  { id: 's12', year: 2026, title: 'LAGK', sub: 'At the range.', frames: 10, no: '12', cover: 'assets/series/s12/01.jpg' },
  { id: 's13', year: 2026, title: 'EAGx Nordics \'26', sub: 'The Nordic conference.', frames: 10, no: '13', cover: 'assets/series/s13/01.jpg' },
  { id: 's14', year: 2026, title: 'Tatry', sub: 'Spring in the High Tatras.', frames: 1, no: '14', cover: 'assets/series/s14/01.jpg' },
  { id: 's15', year: 2026, title: 'EA — existential risk', sub: 'An evening on the long term.', frames: 3, no: '15', cover: 'assets/series/s15/01.jpg' },
  { id: 's16', year: 2026, title: 'Söderåsen', sub: 'The ridge, in early spring.', frames: 10, no: '16', cover: 'assets/series/s16/01.jpg' },
  { id: 's17', year: 2026, title: 'Owls + Lund', sub: 'Birds, and the town.', frames: 10, no: '17', cover: 'assets/series/s17/01.jpg' },
  { id: 's18', year: 2026, title: 'Malmö — Ukraine protest', sub: 'Years on, still standing.', frames: 10, no: '18', cover: 'assets/series/s18/01.jpg' },
  { id: 's19', year: 2026, title: 'EA — Denmark meetup', sub: 'Across the bridge, Copenhagen.', frames: 8, no: '19', cover: 'assets/series/s19/01.jpg' },
  { id: 's20', year: 2026, title: 'EA — pizza', sub: 'A meetup, plainly named.', frames: 10, no: '20', cover: 'assets/series/s20/01.jpg' },
  { id: 's21', year: 2026, title: 'Bartek', sub: 'Portraits of a friend.', frames: 6, no: '21', cover: 'assets/series/s21/01.jpg' },
  { id: 's22', year: 2026, title: 'HU board', sub: 'A board, at work.', frames: 10, no: '22', cover: 'assets/series/s22/01.jpg' },
  { id: 's23', year: 2026, title: 'EA — intro talk', sub: 'The first talk of term.', frames: 6, no: '23', cover: 'assets/series/s23/01.jpg' },
  { id: 's24', year: 2026, title: 'EA — tabling', sub: 'Freshers\' fair; a table and a banner.', frames: 9, no: '24', cover: 'assets/series/s24/01.jpg' },
  { id: 's25', year: 2026, title: 'EA — SAF', sub: 'A working session.', frames: 4, no: '25', cover: 'assets/series/s25/01.jpg' },
  { id: 's26', year: 2026, title: 'Methods', sub: 'Two frames, in transit.', frames: 2, no: '26', cover: 'assets/series/s26/01.jpg' },
  { id: 's27', year: 2025, title: 'Örtofta', sub: 'Winter light near the sugar mill.', frames: 10, no: '27', cover: 'assets/series/s27/01.jpg' },
  { id: 's28', year: 2025, title: 'Christmas postcards', sub: 'A set made to be mailed.', frames: 10, no: '28', cover: 'assets/series/s28/01.jpg' },
  { id: 's29', year: 2025, title: 'Christmas — LUMES & LUCAS', sub: 'End of term, the sustainability crowd.', frames: 10, no: '29', cover: 'assets/series/s29/01.jpg' },
  { id: 's30', year: 2025, title: 'Bonfire', sub: 'Late autumn, out of doors.', frames: 10, no: '30', cover: 'assets/series/s30/01.jpg' },
  { id: 's31', year: 2025, title: 'Alt-protein — EA Lund', sub: 'An evening on alternative proteins.', frames: 2, no: '31', cover: 'assets/series/s31/01.jpg' },
  { id: 's32', year: 2025, title: 'EA — EU biotech', sub: 'A day on European biotech policy.', frames: 10, no: '32', cover: 'assets/series/s32/01.jpg' },
  { id: 's33', year: 2025, title: 'Skåne — witch trip', sub: 'Hallowe\'en, across the county.', frames: 9, no: '33', cover: 'assets/series/s33/01.jpg' },
  { id: 's34', year: 2025, title: 'Breanäs', sub: 'A weekend by the lake.', frames: 10, no: '34', cover: 'assets/series/s34/01.jpg' },
  { id: 's35', year: 2025, title: 'ЛЕП', sub: 'Transmission lines, in summer.', frames: 10, no: '35', cover: 'assets/series/s35/01.jpg' },
];

const SERIES_FRAMES = {
  s1: [
    { no: '01', caption: 'Vienna Basin · drill core, GS-04', meta: '2024-06 · 50mm · Provia 100F', ratio: '3/2', span: 'wide' },
    { no: '02', caption: 'Outcrop, Malé Karpaty', meta: '2024-06 · 35mm', ratio: '4/5' },
    { no: '03', caption: 'Field notebook, page 41', meta: '2024-07 · macro', ratio: '4/5' },
    { no: '04', caption: 'Hand sample, dolomite', meta: '2024-07 · 90mm', ratio: '1/1' },
    { no: '05', caption: 'Wellhead, Hainburg', meta: '2024-08 · 28mm', ratio: '3/2', span: 'wide' },
    { no: '06', caption: 'GIS station, after midnight', meta: '2024-08 · 35mm · push +1', ratio: '4/5' },
    { no: '07', caption: 'Z. and the truck', meta: '2024-08 · 50mm', ratio: '4/5' },
    { no: '08', caption: 'Returning to Ostrava', meta: '2024-09 · 35mm', ratio: '3/2', span: 'wide' },
  ],

  s6: [
    { no: '01', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', span: 'wide', src: 'assets/series/s6/01.jpg' },
    { no: '02', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/02.jpg' },
    { no: '03', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/03.jpg' },
    { no: '04', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/04.jpg' },
    { no: '05', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/05.jpg' },
    { no: '06', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/06.jpg' },
    { no: '07', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/07.jpg' },
    { no: '08', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/08.jpg' },
    { no: '09', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/09.jpg' },
    { no: '10', caption: 'PBC Summer Camp — day three', meta: '2026-07', ratio: '3/2', src: 'assets/series/s6/10.jpg' },
  ],
  s7: [
    { no: '01', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', span: 'wide', src: 'assets/series/s7/01.jpg' },
    { no: '02', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/02.jpg' },
    { no: '03', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/03.jpg' },
    { no: '04', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/04.jpg' },
    { no: '05', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/05.jpg' },
    { no: '06', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/06.jpg' },
    { no: '07', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/07.jpg' },
    { no: '08', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/08.jpg' },
    { no: '09', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '3/2', src: 'assets/series/s7/09.jpg' },
    { no: '10', caption: 'PBC Summer Camp — day two', meta: '2026-07', ratio: '4/5', src: 'assets/series/s7/10.jpg' },
  ],
  s8: [
    { no: '01', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', span: 'wide', src: 'assets/series/s8/01.jpg' },
    { no: '02', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/02.jpg' },
    { no: '03', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/03.jpg' },
    { no: '04', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/04.jpg' },
    { no: '05', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/05.jpg' },
    { no: '06', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/06.jpg' },
    { no: '07', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/07.jpg' },
    { no: '08', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/08.jpg' },
    { no: '09', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '3/2', src: 'assets/series/s8/09.jpg' },
    { no: '10', caption: 'PBC Summer Camp — day one', meta: '2026-07', ratio: '4/5', src: 'assets/series/s8/10.jpg' },
  ],
  s9: [
    { no: '01', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', span: 'wide', src: 'assets/series/s9/01.jpg' },
    { no: '02', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/02.jpg' },
    { no: '03', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/03.jpg' },
    { no: '04', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/04.jpg' },
    { no: '05', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/05.jpg' },
    { no: '06', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/06.jpg' },
    { no: '07', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/07.jpg' },
    { no: '08', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/08.jpg' },
    { no: '09', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/09.jpg' },
    { no: '10', caption: 'Lunds natur', meta: '2026-06', ratio: '3/2', src: 'assets/series/s9/10.jpg' },
  ],
  s10: [
    { no: '01', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', span: 'wide', src: 'assets/series/s10/01.jpg' },
    { no: '02', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/02.jpg' },
    { no: '03', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/03.jpg' },
    { no: '04', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/04.jpg' },
    { no: '05', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/05.jpg' },
    { no: '06', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/06.jpg' },
    { no: '07', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/07.jpg' },
    { no: '08', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/08.jpg' },
    { no: '09', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/09.jpg' },
    { no: '10', caption: 'B28 graduation', meta: '2026-06', ratio: '3/2', src: 'assets/series/s10/10.jpg' },
  ],
  s11: [
    { no: '01', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', span: 'wide', src: 'assets/series/s11/01.jpg' },
    { no: '02', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/02.jpg' },
    { no: '03', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/03.jpg' },
    { no: '04', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/04.jpg' },
    { no: '05', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/05.jpg' },
    { no: '06', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/06.jpg' },
    { no: '07', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/07.jpg' },
    { no: '08', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/08.jpg' },
    { no: '09', caption: 'K2A fair', meta: '2026-06', ratio: '3/2', src: 'assets/series/s11/09.jpg' },
    { no: '10', caption: 'K2A fair', meta: '2026-06', ratio: '4/5', src: 'assets/series/s11/10.jpg' },
  ],
  s12: [
    { no: '01', caption: 'LAGK', meta: '2026-05', ratio: '3/2', span: 'wide', src: 'assets/series/s12/01.jpg' },
    { no: '02', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/02.jpg' },
    { no: '03', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/03.jpg' },
    { no: '04', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/04.jpg' },
    { no: '05', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/05.jpg' },
    { no: '06', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/06.jpg' },
    { no: '07', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/07.jpg' },
    { no: '08', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/08.jpg' },
    { no: '09', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/09.jpg' },
    { no: '10', caption: 'LAGK', meta: '2026-05', ratio: '3/2', src: 'assets/series/s12/10.jpg' },
  ],
  s13: [
    { no: '01', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', span: 'wide', src: 'assets/series/s13/01.jpg' },
    { no: '02', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/02.jpg' },
    { no: '03', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/03.jpg' },
    { no: '04', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/04.jpg' },
    { no: '05', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/05.jpg' },
    { no: '06', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/06.jpg' },
    { no: '07', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/07.jpg' },
    { no: '08', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/08.jpg' },
    { no: '09', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '3/2', src: 'assets/series/s13/09.jpg' },
    { no: '10', caption: 'EAGx Nordics \'26', meta: '2026-04', ratio: '4/5', src: 'assets/series/s13/10.jpg' },
  ],
  s14: [
    { no: '01', caption: 'Tatry', meta: '2026-04', ratio: '4/5', src: 'assets/series/s14/01.jpg' },
  ],
  s15: [
    { no: '01', caption: 'EA — existential risk', meta: '2026-03', ratio: '3/2', span: 'wide', src: 'assets/series/s15/01.jpg' },
    { no: '02', caption: 'EA — existential risk', meta: '2026-03', ratio: '3/2', src: 'assets/series/s15/02.jpg' },
    { no: '03', caption: 'EA — existential risk', meta: '2026-03', ratio: '4/5', src: 'assets/series/s15/03.jpg' },
  ],
  s16: [
    { no: '01', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', span: 'wide', src: 'assets/series/s16/01.jpg' },
    { no: '02', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/02.jpg' },
    { no: '03', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/03.jpg' },
    { no: '04', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/04.jpg' },
    { no: '05', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/05.jpg' },
    { no: '06', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/06.jpg' },
    { no: '07', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/07.jpg' },
    { no: '08', caption: 'Söderåsen', meta: '2026-03', ratio: '3/2', src: 'assets/series/s16/08.jpg' },
    { no: '09', caption: 'Söderåsen', meta: '2026-03', ratio: '4/5', src: 'assets/series/s16/09.jpg' },
    { no: '10', caption: 'Söderåsen', meta: '2026-03', ratio: '4/5', src: 'assets/series/s16/10.jpg' },
  ],
  s17: [
    { no: '01', caption: 'Owls + Lund', meta: '2026-03', ratio: '3/2', span: 'wide', src: 'assets/series/s17/01.jpg' },
    { no: '02', caption: 'Owls + Lund', meta: '2026-03', ratio: '3/2', src: 'assets/series/s17/02.jpg' },
    { no: '03', caption: 'Owls + Lund', meta: '2026-03', ratio: '3/2', src: 'assets/series/s17/03.jpg' },
    { no: '04', caption: 'Owls + Lund', meta: '2026-03', ratio: '3/2', src: 'assets/series/s17/04.jpg' },
    { no: '05', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/05.jpg' },
    { no: '06', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/06.jpg' },
    { no: '07', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/07.jpg' },
    { no: '08', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/08.jpg' },
    { no: '09', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/09.jpg' },
    { no: '10', caption: 'Owls + Lund', meta: '2026-03', ratio: '4/5', src: 'assets/series/s17/10.jpg' },
  ],
  s18: [
    { no: '01', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s18/01.jpg' },
    { no: '02', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '3/2', src: 'assets/series/s18/02.jpg' },
    { no: '03', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '3/2', src: 'assets/series/s18/03.jpg' },
    { no: '04', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '3/2', src: 'assets/series/s18/04.jpg' },
    { no: '05', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/05.jpg' },
    { no: '06', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/06.jpg' },
    { no: '07', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/07.jpg' },
    { no: '08', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/08.jpg' },
    { no: '09', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/09.jpg' },
    { no: '10', caption: 'Malmö — Ukraine protest', meta: '2026-02', ratio: '4/5', src: 'assets/series/s18/10.jpg' },
  ],
  s19: [
    { no: '01', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s19/01.jpg' },
    { no: '02', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '3/2', src: 'assets/series/s19/02.jpg' },
    { no: '03', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '3/2', src: 'assets/series/s19/03.jpg' },
    { no: '04', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '3/2', src: 'assets/series/s19/04.jpg' },
    { no: '05', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '4/5', src: 'assets/series/s19/05.jpg' },
    { no: '06', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '4/5', src: 'assets/series/s19/06.jpg' },
    { no: '07', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '4/5', src: 'assets/series/s19/07.jpg' },
    { no: '08', caption: 'EA — Denmark meetup', meta: '2026-02', ratio: '4/5', src: 'assets/series/s19/08.jpg' },
  ],
  s20: [
    { no: '01', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s20/01.jpg' },
    { no: '02', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/02.jpg' },
    { no: '03', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/03.jpg' },
    { no: '04', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/04.jpg' },
    { no: '05', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/05.jpg' },
    { no: '06', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/06.jpg' },
    { no: '07', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/07.jpg' },
    { no: '08', caption: 'EA — pizza', meta: '2026-02', ratio: '3/2', src: 'assets/series/s20/08.jpg' },
    { no: '09', caption: 'EA — pizza', meta: '2026-02', ratio: '4/5', src: 'assets/series/s20/09.jpg' },
    { no: '10', caption: 'EA — pizza', meta: '2026-02', ratio: '4/5', src: 'assets/series/s20/10.jpg' },
  ],
  s21: [
    { no: '01', caption: 'Bartek', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s21/01.jpg' },
    { no: '02', caption: 'Bartek', meta: '2026-02', ratio: '4/5', src: 'assets/series/s21/02.jpg' },
    { no: '03', caption: 'Bartek', meta: '2026-02', ratio: '4/5', src: 'assets/series/s21/03.jpg' },
    { no: '04', caption: 'Bartek', meta: '2026-02', ratio: '4/5', src: 'assets/series/s21/04.jpg' },
    { no: '05', caption: 'Bartek', meta: '2026-02', ratio: '4/5', src: 'assets/series/s21/05.jpg' },
    { no: '06', caption: 'Bartek', meta: '2026-02', ratio: '4/5', src: 'assets/series/s21/06.jpg' },
  ],
  s22: [
    { no: '01', caption: 'HU board', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s22/01.jpg' },
    { no: '02', caption: 'HU board', meta: '2026-02', ratio: '3/2', src: 'assets/series/s22/02.jpg' },
    { no: '03', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/03.jpg' },
    { no: '04', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/04.jpg' },
    { no: '05', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/05.jpg' },
    { no: '06', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/06.jpg' },
    { no: '07', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/07.jpg' },
    { no: '08', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/08.jpg' },
    { no: '09', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/09.jpg' },
    { no: '10', caption: 'HU board', meta: '2026-02', ratio: '4/5', src: 'assets/series/s22/10.jpg' },
  ],
  s23: [
    { no: '01', caption: 'EA — intro talk', meta: '2026-02', ratio: '3/2', span: 'wide', src: 'assets/series/s23/01.jpg' },
    { no: '02', caption: 'EA — intro talk', meta: '2026-02', ratio: '3/2', src: 'assets/series/s23/02.jpg' },
    { no: '03', caption: 'EA — intro talk', meta: '2026-02', ratio: '3/2', src: 'assets/series/s23/03.jpg' },
    { no: '04', caption: 'EA — intro talk', meta: '2026-02', ratio: '3/2', src: 'assets/series/s23/04.jpg' },
    { no: '05', caption: 'EA — intro talk', meta: '2026-02', ratio: '3/2', src: 'assets/series/s23/05.jpg' },
    { no: '06', caption: 'EA — intro talk', meta: '2026-02', ratio: '4/5', src: 'assets/series/s23/06.jpg' },
  ],
  s24: [
    { no: '01', caption: 'EA — tabling', meta: '2026-01', ratio: '3/2', span: 'wide', src: 'assets/series/s24/01.jpg' },
    { no: '02', caption: 'EA — tabling', meta: '2026-01', ratio: '3/2', src: 'assets/series/s24/02.jpg' },
    { no: '03', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/03.jpg' },
    { no: '04', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/04.jpg' },
    { no: '05', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/05.jpg' },
    { no: '06', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/06.jpg' },
    { no: '07', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/07.jpg' },
    { no: '08', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/08.jpg' },
    { no: '09', caption: 'EA — tabling', meta: '2026-01', ratio: '4/5', src: 'assets/series/s24/09.jpg' },
  ],
  s25: [
    { no: '01', caption: 'EA — SAF', meta: '2026-01', ratio: '3/2', span: 'wide', src: 'assets/series/s25/01.jpg' },
    { no: '02', caption: 'EA — SAF', meta: '2026-01', ratio: '4/5', src: 'assets/series/s25/02.jpg' },
    { no: '03', caption: 'EA — SAF', meta: '2026-01', ratio: '4/5', src: 'assets/series/s25/03.jpg' },
    { no: '04', caption: 'EA — SAF', meta: '2026-01', ratio: '4/5', src: 'assets/series/s25/04.jpg' },
  ],
  s26: [
    { no: '01', caption: 'Methods', meta: '2026', ratio: '4/5', src: 'assets/series/s26/01.jpg' },
    { no: '02', caption: 'Methods', meta: '2026', ratio: '4/5', src: 'assets/series/s26/02.jpg' },
  ],
  s27: [
    { no: '01', caption: 'Örtofta', meta: '2025-12', ratio: '3/2', span: 'wide', src: 'assets/series/s27/01.jpg' },
    { no: '02', caption: 'Örtofta', meta: '2025-12', ratio: '3/2', src: 'assets/series/s27/02.jpg' },
    { no: '03', caption: 'Örtofta', meta: '2025-12', ratio: '3/2', src: 'assets/series/s27/03.jpg' },
    { no: '04', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/04.jpg' },
    { no: '05', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/05.jpg' },
    { no: '06', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/06.jpg' },
    { no: '07', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/07.jpg' },
    { no: '08', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/08.jpg' },
    { no: '09', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/09.jpg' },
    { no: '10', caption: 'Örtofta', meta: '2025-12', ratio: '4/5', src: 'assets/series/s27/10.jpg' },
  ],
  s28: [
    { no: '01', caption: 'Christmas postcards', meta: '2025-12', ratio: '3/2', span: 'wide', src: 'assets/series/s28/01.jpg' },
    { no: '02', caption: 'Christmas postcards', meta: '2025-12', ratio: '3/2', src: 'assets/series/s28/02.jpg' },
    { no: '03', caption: 'Christmas postcards', meta: '2025-12', ratio: '3/2', src: 'assets/series/s28/03.jpg' },
    { no: '04', caption: 'Christmas postcards', meta: '2025-12', ratio: '3/2', src: 'assets/series/s28/04.jpg' },
    { no: '05', caption: 'Christmas postcards', meta: '2025-12', ratio: '3/2', src: 'assets/series/s28/05.jpg' },
    { no: '06', caption: 'Christmas postcards', meta: '2025-12', ratio: '4/5', src: 'assets/series/s28/06.jpg' },
    { no: '07', caption: 'Christmas postcards', meta: '2025-12', ratio: '4/5', src: 'assets/series/s28/07.jpg' },
    { no: '08', caption: 'Christmas postcards', meta: '2025-12', ratio: '4/5', src: 'assets/series/s28/08.jpg' },
    { no: '09', caption: 'Christmas postcards', meta: '2025-12', ratio: '4/5', src: 'assets/series/s28/09.jpg' },
    { no: '10', caption: 'Christmas postcards', meta: '2025-12', ratio: '4/5', src: 'assets/series/s28/10.jpg' },
  ],
  s29: [
    { no: '01', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', span: 'wide', src: 'assets/series/s29/01.jpg' },
    { no: '02', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', src: 'assets/series/s29/02.jpg' },
    { no: '03', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', src: 'assets/series/s29/03.jpg' },
    { no: '04', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', src: 'assets/series/s29/04.jpg' },
    { no: '05', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', src: 'assets/series/s29/05.jpg' },
    { no: '06', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '3/2', src: 'assets/series/s29/06.jpg' },
    { no: '07', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '4/5', src: 'assets/series/s29/07.jpg' },
    { no: '08', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '4/5', src: 'assets/series/s29/08.jpg' },
    { no: '09', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '4/5', src: 'assets/series/s29/09.jpg' },
    { no: '10', caption: 'Christmas — LUMES & LUCAS', meta: '2025-12', ratio: '4/5', src: 'assets/series/s29/10.jpg' },
  ],
  s30: [
    { no: '01', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', span: 'wide', src: 'assets/series/s30/01.jpg' },
    { no: '02', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/02.jpg' },
    { no: '03', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/03.jpg' },
    { no: '04', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/04.jpg' },
    { no: '05', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/05.jpg' },
    { no: '06', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/06.jpg' },
    { no: '07', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/07.jpg' },
    { no: '08', caption: 'Bonfire', meta: '2025-11', ratio: '3/2', src: 'assets/series/s30/08.jpg' },
    { no: '09', caption: 'Bonfire', meta: '2025-11', ratio: '4/5', src: 'assets/series/s30/09.jpg' },
    { no: '10', caption: 'Bonfire', meta: '2025-11', ratio: '4/5', src: 'assets/series/s30/10.jpg' },
  ],
  s31: [
    { no: '01', caption: 'Alt-protein — EA Lund', meta: '2025-11', ratio: '3/2', span: 'wide', src: 'assets/series/s31/01.jpg' },
    { no: '02', caption: 'Alt-protein — EA Lund', meta: '2025-11', ratio: '3/2', src: 'assets/series/s31/02.jpg' },
  ],
  s32: [
    { no: '01', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', span: 'wide', src: 'assets/series/s32/01.jpg' },
    { no: '02', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/02.jpg' },
    { no: '03', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/03.jpg' },
    { no: '04', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/04.jpg' },
    { no: '05', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/05.jpg' },
    { no: '06', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/06.jpg' },
    { no: '07', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/07.jpg' },
    { no: '08', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/08.jpg' },
    { no: '09', caption: 'EA — EU biotech', meta: '2025-11', ratio: '3/2', src: 'assets/series/s32/09.jpg' },
    { no: '10', caption: 'EA — EU biotech', meta: '2025-11', ratio: '4/5', src: 'assets/series/s32/10.jpg' },
  ],
  s33: [
    { no: '01', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', span: 'wide', src: 'assets/series/s33/01.jpg' },
    { no: '02', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/02.jpg' },
    { no: '03', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/03.jpg' },
    { no: '04', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/04.jpg' },
    { no: '05', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/05.jpg' },
    { no: '06', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/06.jpg' },
    { no: '07', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '3/2', src: 'assets/series/s33/07.jpg' },
    { no: '08', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '4/5', src: 'assets/series/s33/08.jpg' },
    { no: '09', caption: 'Skåne — witch trip', meta: '2025-10', ratio: '4/5', src: 'assets/series/s33/09.jpg' },
  ],
  s34: [
    { no: '01', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', span: 'wide', src: 'assets/series/s34/01.jpg' },
    { no: '02', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/02.jpg' },
    { no: '03', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/03.jpg' },
    { no: '04', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/04.jpg' },
    { no: '05', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/05.jpg' },
    { no: '06', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/06.jpg' },
    { no: '07', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/07.jpg' },
    { no: '08', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/08.jpg' },
    { no: '09', caption: 'Breanäs', meta: '2025-09', ratio: '3/2', src: 'assets/series/s34/09.jpg' },
    { no: '10', caption: 'Breanäs', meta: '2025-09', ratio: '4/5', src: 'assets/series/s34/10.jpg' },
  ],
  s35: [
    { no: '01', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', span: 'wide', src: 'assets/series/s35/01.jpg' },
    { no: '02', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/02.jpg' },
    { no: '03', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/03.jpg' },
    { no: '04', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/04.jpg' },
    { no: '05', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/05.jpg' },
    { no: '06', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/06.jpg' },
    { no: '07', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/07.jpg' },
    { no: '08', caption: 'ЛЕП', meta: '2025-07', ratio: '3/2', src: 'assets/series/s35/08.jpg' },
    { no: '09', caption: 'ЛЕП', meta: '2025-07', ratio: '4/5', src: 'assets/series/s35/09.jpg' },
    { no: '10', caption: 'ЛЕП', meta: '2025-07', ratio: '1/1', src: 'assets/series/s35/10.jpg' },
  ],
};

const CV = {
  work: [
    { from: '2026.01', to: 'now', role: 'Project Assistant', org: 'LUCSUS — Lund University', kind: 'Contract',
      bullets: [
        'Built an automated workflow for student recommendation-letter processing; cut admin time ~20%.',
        'General administrative optimisation for a research centre that, frankly, was running on goodwill.',
      ] },
    { from: '2025.01', to: 'now', role: 'Freelance Photographer', org: 'Self-employed', kind: 'Freelance' },
    { from: '2023.06', to: '2025.12', role: 'Research Assistant', org: 'LAGEA — VŠB-TU Ostrava', kind: 'Part-time',
      bullets: [
        'Built a play-fairway pipeline for low-temperature geothermal in the Vienna Basin.',
        'ArcPy automation of repetitive GIS chores. Partly-automated web scraping for inputs.',
        'Databases, analysis in ArcGIS / Excel / Origin. Final figures in CorelDraw + ArcGIS Pro.',
      ] },
    { from: '2023.07', to: '2025.07', role: 'Laboratory Technician', org: 'Comenius University Bratislava', kind: 'Full-time',
      bullets: [
        'Thiazole-orange derivatives for deep-red / NIR photodynamic therapy and bioimaging.',
        'Absorption + emission spectroscopy. Spectra prep for publication.',
        'Wrote spectroscopy SOPs PhD students now use. Did the synthesis I was bad at until I was good at it.',
      ] },
  ],
  edu: [
    { from: '2025', to: '2027', deg: 'MSc, Environmental Studies & Sustainability Science', org: 'Lund University Centre for Sustainability Science (LUCSUS)',
      note: 'Swedish Institute Global Professionals scholar.' },
    { from: '2022', to: '2025', deg: 'BSc, Environmental Studies', org: 'Faculty of Natural Sciences, Comenius University Bratislava',
      note: 'Avg. grade 1.00 · 99th percentile · multi-scholarship holder.' },
  ],
  vol: [
    { from: '2026.06', to: 'now', role: 'Photography · Videography', org: 'Plant Based Campus' },
    { from: '2025.10', to: 'now', role: 'Co-president · Organiser', org: 'Effective Altruism Lund' },
    { from: '2025.10', to: 'now', role: 'Student & Health/Safety Representative', org: 'Lund University, LUCSUS faculty board' },
    { from: '2024.09', to: '2025.12', role: 'Co-founder · Editor-in-Chief', org: 'Media Bober (Ukraine)', note: 'Team of 20+; non-formal education for Ukrainian youth.' },
    { from: '2025.09', to: '2025.11', role: 'Study Mentor', org: 'Teach for Ukraine', note: 'Filling gaps the war made in students\' biology and chemistry.' },
    { from: '2020.07', to: '2024.11', role: 'Co-founder · Editor-in-Chief', org: 'ProSvita (Ukraine)', note: '15-person team. Non-formal education.' },
    { from: '2020.03', to: '2022.02', role: 'Research Intern', org: 'Osokorky Wetland Park, Kyiv', note: 'Field surveys toward a landscape protected area.' },
  ],
  skills: [
    { group: 'Tools', items: ['ArcGIS Pro','ArcPy','Origin','Excel','CorelDraw','Python (basic)','LaTeX'] },
    { group: 'Lab', items: ['UV/Vis','Fluorescence','Organic synthesis','SOP authoring'] },
    { group: 'Soft', items: ['Editing','Public speaking','Team management','Workflow design'] },
    { group: 'Languages', items: ['Ukrainian C2','Russian C2','English C1','Slovak C1','Swedish A2','Spanish A1','German A1'] },
  ],
  awards: [
    { year: 2025, t: 'Swedish Institute Scholarship — Global Professionals' },
    { year: 2025, t: 'BSc finished in top 1%, avg. grade 1.00' },
    { year: 2024, t: 'Youngest hire at the Faculty of Natural Sciences, Comenius University' },
    { year: 2024, t: 'Automated ~15% of routine GIS work at LAGEA' },
    { year: 2022, t: 'Two papers on urban sustainable planning, Minor Academy of Sciences of Ukraine' },
    { year: 2022, t: 'Multiple winner — Ukraine national olympiads, environmental & natural sciences' },
  ],
};

// Combined index, reverse-chronological, for the home feed.
const FEED = [
  { date:'2026.06.20', kind:'essay',  to:'essay',  id:'m18', title:'You might not want to study LUMES in 2027-28', meta:'essay' },
  { date:'2026.04.11', kind:'essay',  to:'essay',  id:'m01', title:"The Problem with Occam's Razor", meta:'essay' },
  { date:'2026.02.03', kind:'essay',  to:'essay',  id:'m02', title:'Who Killed the Dinosaurs',      meta:'essay' },
  { date:'2026.01.06', kind:'note',   to:'cv',     id:'n1', title:'Started at LUCSUS as Project Assistant', meta:'role' },
  { date:'2025.11.18', kind:'essay',  to:'essay',  id:'m03', title:"What's Wrong with Evolution",    meta:'essay' },
  { date:'2025.09.02', kind:'essay',  to:'essay',  id:'m05', title:'Where COVID-19 Came From',       meta:'essay' },
  { date:'2025.06.21', kind:'essay',  to:'essay',  id:'m06', title:'Why LOTR Is About Ukraine',       meta:'essay' },
  { date:'2025.04.15', kind:'note',   to:'about',  id:'n2', title:'Moved to Lund, started MSc',      meta:'note' },
  { date:'2024.12.08', kind:'essay',  to:'essay',  id:'m08', title:'Learned Helplessness & Schools',  meta:'essay' },
  { date:'2024.07.14', kind:'essay',  to:'essay',  id:'m09', title:'The World Has Gone Global',       meta:'essay' },
];

// Dates are stored as 'YYYY.MM' or 'YYYY.MM.DD' (sortable). Display format is
// mm/yyyy or dd/mm/yyyy. 'now' and plain years pass through.
function fmtDate(s) {
  if (!s) return s;
  const m = /^(\d{4})\.(\d{2})(?:\.(\d{2}))?$/.exec(String(s).trim());
  if (!m) return s;
  return m[3] ? m[3] + '/' + m[2] + '/' + m[1] : m[2] + '/' + m[1];
}

// Estimated reading time in minutes. Computed from the on-site body when we have
// it (200 wpm); otherwise a stable estimate (4–9 min) derived from the essay id.
function readMins(e) {
  const b = (typeof ESSAY_BODY !== 'undefined' && ESSAY_BODY[e.id] && ESSAY_BODY[e.id].body) || '';
  if (b) {
    const words = b.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().split(' ').filter(Boolean).length;
    return Math.max(1, Math.round(words / 140)); // dense academic prose ≈ 140 wpm
  }
  let h = 0; const s = (e.id || '') + (e.title || '');
  for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) >>> 0;
  return 4 + (h % 6); // 4–9 min
}

// Build a table of contents from an essay body's <h2> headings, and return the
// body with stable ids injected on those headings so the TOC can jump to them.
function essaySections(html) {
  const sections = [];
  const used = {};
  const slug = (text) => {
    let id = 'sec-' + text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
    if (used[id]) { used[id]++; id += '-' + used[id]; } else { used[id] = 1; }
    return id;
  };
  const body = (html || '').replace(/<(h2|h3)([^>]*)>([\s\S]*?)<\/\1>/g, (m, tag, attrs, inner) => {
    const text = inner.replace(/<[^>]+>/g, '').replace(/&amp;/g, '&').trim();
    const id = slug(text);
    sections.push({ id, text, level: tag === 'h3' ? 3 : 2 });
    return `<${tag}${attrs} id="${id}">${inner}</${tag}>`;
  });
  return { sections, body };
}

Object.assign(window, { SITE, ESSAYS, ESSAY_BODY, registerEssay, SERIES, SERIES_FRAMES, CV, FEED, readMins, essaySections, fmtDate });
