Bucharest Photofest 2026 · Festival Map
BPFmap
Roadmap & Audit
Version V344 → V412 (current) Updated 9 May 2026 Status Active development — 68 V-blocks appended Festival 9–18 October 2026 · 153 days away
68 V-Blocks shipped
18 Features completed
4 Open bugs
12 Roadmap items left
01
V-Block History — What Was Shipped
Chronological log of all appended blocks V344 → V412
V344–V368
Foundation — venue sheet, hero image, popups, welcome V1
Venue sheet visual polish (X circle, number font, separator lines). Hero image via Airtable Google Drive URL. Popup follows pin on drag. Events count in minimised hero. Welcome screen V1: time-based greeting, 2×2 intent grid. Critical fixes (chip wrapping, camera offset, geolocation toast).
V369
Filter strip system + Welcome overlay
.empty-hero rebuilt as flex column. #bpfFltTitle + #bpfFltCtas injected (2×2 grid: Open Now / Nearby / Festival Info / Full Programme). Full-screen #bpfWelcomeOverlay with .bpf-wo-* class tree, photo background, "Witness" title, countdown, chips.
V370
Corrections — Programme exposed, copy text, address in popup
window.openProgramme exposed via #emptyResetBtn proxy. Filter strip: contextual copy line + taller strip (170px). Address hidden from venue hero → popup only. Filter reset re-shows welcome overlay.
V373
Welcome hierarchy fix + filter title nesting
#bpfFltCopy moved inside #bpfFltTitle (grandchild of .empty-hero → immune to V369's direct-child hide rule). #bpfFltTitleTxt span created. Edition chip repositioned above title.
V374
Filter strip horizontal layout + kicker + richer copy
#bpfFltCtas { flex-direction: row } + .bpf-flt-row { display: contents } → all 4 buttons in one row. Kicker "WITNESS — THE 11TH EDITION" added. Per-filter copy texts. Active filter button shows "↩ Home". (Layout later corrected by V412.)
V375
Directions sheet redesign + filter sheet compact
Directions ETA pill: fill-bar width encodes walking time (green <15 min → dark red >50 min). Filter sheet height reduced to 210px. Directions "From your location" header darkened.
V376–V380
Venue chips, topbar, sheet precision passes
Multiple refinement passes: venue type chips (font size, border), topbar gap corrections, sheet-scroll height guards, address display cleanup, venue hero padding tuning.
V381
Welcome overlay editorial rebuild V2
3-line editorial layout with kicker + WITNESS + tagline. Body rebuilt via JS with new DOM structure. Chips reorganised: primary "Explore" + secondary row "Festival Info" / "Programme".
V382
Welcome overlay — comprehensive WOW pass Major
.bpf-v382-* class system. WITNESS at 72px, font-weight: 900, gradient text (white→amber→orange). Stats tiles: 15 Venues / 40+ Events / 10 Days. Primary CTA: radial-gradient coral button. Glass secondary buttons. Countdown "Opens in X days" in lead line.
V383
Welcome photo overlay + topbar gap fix
bpf2023-poster.jpg photo background introduced in #bpfWelcomeOverlay. Topbar gap corrected (searchbar/controls stay at 72px).
V384
Directions + filter precision pass
Directions header copy tightened. Filter sheet padding adjustments.
V385
WOW welcome: photo bleed + WITNESS 86px + "Welcome" CTA
Welcome overlay: photo with stronger radial red glow at top-right. WITNESS scaled to 86px with photo-bleed filter. Body pushed to bottom (justify-content: flex-end). Filter strip: "Full Programme" CTA renamed to "Welcome" (opens overlay).
V386
Precision pass — directions, filter, topbar
Directions refinements. Filter sheet dead-zone eliminated. Topbar gap guarded.
V387
Auto-height filter sheet + welcome content guard
Sheet height: auto eliminates 69px dead zone below CTAs. Welcome overlay JS guard: if V382 WOW content is stripped by base app, rebuilds it from buildV387WelcomeHTML().
V388
Filter spacing + venue chips + searchbar
Filter sheet: +4px top padding, +12px title→copy gap. Venue .sh-chip: 10.5px, visible border. Searchbar: darker icon + edge. Search results: top: 113px (right below searchbar bottom).
V389–V398
Venue hero, saved panel foundations, misc refinements
Venue type classification. Saved venues panel infrastructure (localStorage bookmarks, #savedBtn wired). Venue sort order numbers (01, 02…). Multiple micro-refinements: spacing, colours, chip geometry.
V399
Programme sheet — complete DOM redesign Major
Original .prog-item grid replaced with new structure: .prog-item-row1 (title + time flex), .prog-item-author-r, .prog-item-row3 (chips), .prog-item-detail-r (expandable detail). .pi-chip colour-coded type chips. Expand/collapse via click on row.
V400–V407
Venue type fix, ghost element cleanup, misc
Venue type field mapping corrected. .fi-get-involved ghost element removed (V406) with guard to prevent V400's 800ms re-injection timer (V407). Multiple layout tweaks.
V408
Sheet heights below searchbar + nav backdrop
Festival Info sheet: inset: 130px 22px 0 22px. Programme sheet: max-height: calc(100% − 130px). Navigation modal backdrop: backdrop-filter: none (removed blur, kept solid overlay).
V409
Programme redesign attempt (partial — targeted wrong classes)
CSS targeted .prog-item-time etc. (original classes no longer in DOM after V399). JS MutationObserver also targeted old class names. Broke X close button position. Corrected by V410.
V410
Comprehensive fix + saved panel upgrade + partners V1 Major
Fixed close button position (position: absolute, specificity 0,2,0). Corrected V399 class names throughout CSS. Saved panel: large thin number from v.sortOrder, no "No." prefix. Inline venue navigation bypassing broken bpfGoToVenue chain. AT/WITH detail lines in programme. Partners text chips injected in Festival Info (later upgraded by V411).
V411
Partners — branded logo boxes
Replaces V410's text chips with brand-coloured wordmark boxes: eMAG, Kaufland, Flanco, Decathlon, Auchan, Rompetrol, Dedeman, Sephora, Vodafone. 3-col grid, gloss overlay, "și multe altele!" full-width footer row.
V412
Comprehensive WOW pass — filter / welcome / programme This session
Filter strip: restored 2×2 grid (fixed V374's flex-direction: row regression). Editorial title upgrade (kicker 7px / title 24px 800). Buttons: 12px radius, correct tier styling.
Welcome overlay: full-bleed (inset:0, overrides V370 inset). WITNESS at 100px. Photo background + dramatic red radial. Stats: floating glass cards. Primary CTA: italic gradient coral. Close button: 34px circle.
Programme: hero navy gradient + red corner glow. Left accent bar per item (3px, red when open). Stronger title 13.5px 800. Better chip geometry. Smooth chevron rotation.
Misc: neutralised V410's broken .empty-hero > * { position: relative }.
02
Open Bugs
Known issues — severity & fix path
#IssueSeverityFix path
B1 Grabber visible but non-functional. Visible affordance in all states, does nothing when dragged. Creates false expectation of drag-to-dismiss or expand. UX Hide in mode-empty; or wire touch events → sheet expand/collapse toggle
B2 Popup stays visible when sheet is expanded. Both overlay the same area, visual noise when user drags sheet up. Visual .app.sheet-expanded #popup { display: none } — 1 CSS rule
B3 CSS specificity debt. V344→V412 = 68 V-blocks, each using !important escalation. Rules contradict each other (V374 then V412 on filter layout, V409 then V410 on programme, etc.). File is fragile and hard to reason about. Technical Consolidation pass into a single clean stylesheet — before next edition, not urgent for October
B4 Programme "View on Map" buttonbpfGoToVenue chain unreliable. V410 JS added inline navigation bypass via direct markerMap access; needs user testing to confirm it works across all venue ID types (string vs. number from Airtable). Functional Test in browser; if still broken, add explicit String(id) + Number(id) key lookup with MO fallback
B5 Welcome overlay "Welcome" button in filter strip — V385 renamed "Full Programme" → "Welcome"; V387 re-wires the click handler. Depends on overlay DOM being present. Could fail on first load if overlay hasn't been built yet. Functional Guard: if #bpfWelcomeOverlay not in DOM, call window._bpfReShowWelcome()
B6 Partners section — placeholder brands (eMAG, Kaufland, etc.) are fictitious. Need real confirmed partners and brand colours from BPF team before October. Content Update V411 JS BRANDS array with real confirmed partners
03
Features Completed
From old roadmap (P5–P26) — closed since V368
Closed from original roadmap
P6 ✓
Walking time estimate (Directions)Done · V375
Implemented as a full Directions sheet with ETA pill. Fill bar colour encodes walking time (<15 min green → >50 min dark red). More comprehensive than the original spec.
P7 ✓
Add to Calendar per eventDone · V399+
.prog-cal-btn rendered in each expanded programme item. V410 styles it as a dark filled button (#0b1221).
P8 ✓
Countdown in welcomeDone · V382/V387
"Opens in X days" computed live from Oct 9 2026 in .bpf-v382-lead. Switches copy post-festival.
P9 ✓
Welcome hero editorial background imageDone · V383
bpf2023-poster.jpg full-bleed photo with dark gradient overlay. Red radial glow at top-right corner. V412 upgraded to full-bleed inset:0.
P17 ✓
Personal shortlist (saved venues)Done · V389+
Bookmark icon per venue. Saves to localStorage. Saved panel accessible via #savedBtn. Shows venue number (large thin, from sortOrder), name, type, and "View ↗" navigation button.
New — not in original roadmap
NEW ✓
Full Programme sheet — complete redesignDone · V399
New DOM structure with .prog-item-row1/row3, -r class variants, expandable detail panel, colour-coded type chips. Left accent bar (red when open) added in V412.
NEW ✓
Partners section in Festival InfoDone · V411
3-col grid of branded wordmark boxes injected before .festival-info-footer. Each box has brand background colour + white logo text + gloss overlay.
NEW ✓
Venue sort-order numbers (01, 02…)Done · V369+
Popup, venue hero, and saved panel all use v.sortOrder.padStart(2,'0') instead of raw DB IDs. Large thin number (40px, weight 200) in saved panel.
NEW ✓
Sheet heights below searchbar (130px offset)Done · V408
Festival Info and Programme sheets start at 130px from top — below the searchbar. Prevents any overlap with topbar controls.
NEW ✓
Navigation modal backdrop (no blur)Done · V408
backdrop-filter: none replaced with solid rgba(8,12,28,0.50). Cleaner, faster rendering on mobile.
04
Roadmap — Remaining Items
Not yet implemented — ordered by value tier
★★ High value — implement next
P5
Open until / Opens at — exact hours in venue heroHigh
Replace bare open/closed dot with contextual text: "Open until 21:00" or "Opens Friday 10:00". Airtable already has schedule data. Makes the status dot genuinely actionable.
Airtable hours field + time comparison logic in renderSheet wrapper
P11
Share venue (Web Share API)High
One-tap share: navigator.share() → venue name + address + URL. Opens native iOS/Android share sheet. Drives organic distribution during the festival. Needs P20 (deep links) first.
Web Share API + URL params for deep link (depends on P20)
P13
Grabber — functional or hiddenHigh · B1
Currently a false affordance. Either wire it to expand/collapse the sheet (touch listeners), or hide it in states where drag has no effect. Removes user confusion immediately.
Touch event listeners on grabber → sheet class toggle; or display: none in mode-empty
P20
Deep link URL params + In-Light integrationHigh
?venue=12 pre-selects a venue on load. ?event=45 opens programme to that event. Enables shareable links + bi-directional navigation with In-Light.
URLSearchParams on DOMContentLoaded + matching state.selectedVenueId before first renderAll
P19
Search extended — events, artists, curatorsHigh
Current search matches only venue names. "Laia Abril" should surface her venues. Airtable events already have author/artist fields.
Extend search scoring to ev.title, ev.author across all venues' events arrays
★ Editorial & differentiators
P10
"Next event" prominent in minimised venue sheetMedium
Popup shows "Next Event" already. Minimised sheet shows only a raw count. Surface the next event (title + time-until) directly in the hero strip.
Extract soonest upcoming event from events array, inject into .sh-hero-btm
P12
Dark map tile layer after 20:00Medium
Switch Carto Voyager → Carto Dark Matter after 20:00. Matches the cinematic dark theme of venue sheet. No API key needed.
Time check on load + L.tileLayer swap on the map instance
P14
Featured venue / event in welcome — daily rotationEditorial
Card below CTAs highlighting today's most important event or editor-selected venue. Updated via Airtable. Gives users a reason to re-open each day.
APP_SETTINGS "featured_venue_id" field + card injected in welcome wrapper
P15
"What's on today" summary in welcomeEditorial
One line: "Today: 4 events open now across 3 venues." Computed live. Immediate context, zero taps.
Count open venues + today's events at render time, inject as .bpf-today-line
P16
"Editor's Pick" tag on curated venuesEditorial
Small amber/gold pill on curated venues in popup and venue hero. Set via Airtable boolean field. Pure editorial curation, minimal code effort.
Airtable boolean "featured" + pill in showPopup + renderSheet
P18
"Plan my day" — multi-venue routeDifferentiator
Select 2–4 venues, generate an optimised walking route. Most differentiated feature vs. Google Maps. Start simple: pick from list, route drawn on map with time estimates between stops.
Multi-point state array + polyline chain + walking time between stops
◎ Optional / advanced
P21
Service Worker — offline modeAdvanced
Cache map tiles + Airtable data for offline use. Critical for festival visitors in buildings with poor signal.
P25
CSS consolidation — single clean stylesheetTechnical
68 V-blocks with cascading !important. Before the next edition (2027), a single rewrite would eliminate all specificity debt. Not urgent for October 2026.
P26
font-display: swap for Inter (Google Fonts)Performance
Add &display=swap to the Google Fonts URL. 2-second fix, prevents font-block on slow connections.
05
Next Sessions — Recommended Agenda
Specific, actionable. Each card = one focused session.
Session A · Priority 1 Testing & Bug Validation
Validate V408–V412 in browser before adding new features. Confirm what's actually working vs. what only looks fixed in code.
Filter strip: confirm 2×2 grid restored (V412 fix for V374 regression)
Saved panel "View ↗": confirm venue navigation works (V410 inline bypass)
Programme "View on Map": confirm markerMap key lookup covers string + number IDs
Welcome overlay: confirm full-bleed photo + 100px WITNESS renders
Partners section: confirm injection into Festival Info body
B2 quick fix: add .app.sheet-expanded #popup { display: none }
Estimated: 1 session. CSS-only fixes for confirmed issues.
Session B · Priority 1 Open Until / Opens At — venue status
The single most impactful functional upgrade. The open/closed dot is currently binary and static. Replacing it with exact contextual time makes it genuinely useful for a visitor deciding where to go right now.
Read v.openHours from Airtable (confirm field name)
Compute "Open until HH:MM" / "Opens today HH:MM" / "Opens [day] HH:MM"
Inject contextual text next to status dot in venue hero
Also update popup status dot text (currently "Open now" / "Closed")
Estimated: 1–2 sessions. Requires confirming Airtable field schema first.
Session C · Priority 2 Grabber fix + Popup-on-expand hide
Two quick UX fixes that remove confusing affordances. Together they make the app feel more intentional and polished.
B1 Grabber: hide in mode-empty (.app.mode-empty .sheet-grabber { display: none }) and optionally in mode-selected minimised. Or wire to expand toggle.
B2 Popup: .app.sheet-expanded #popup { opacity: 0; pointer-events: none; transition: opacity .2s } — single CSS rule.
Estimated: 30 min. Pure CSS.
Session D · Priority 2 Deep Links (URL params) + Share Venue
Unlocks shareability. A visitor can send a link to a specific venue. Needed before the share button makes sense.
On load: read ?venue=ID from URLSearchParams
Set state.selectedVenueId = ID before first renderAll(true)
Update URL (pushState) when user taps a venue marker
Add "Share" button in venue hero → navigator.share({ title, url })
Fallback: copy URL to clipboard + toast notification
Estimated: 1 session. No Airtable changes needed.
Session E · Priority 3 Extended Search — events + artists
Searching "Laia Abril" or "documentary" currently returns nothing. With events data already loaded from Airtable, the only missing step is including event fields in the search index.
Extend venueMatchesSearch() to scan v.events[].title and v.events[].author
Show matched event name(s) as sub-text in search results card
Optionally: add artist/curator as a separate result type (opens programme to that event)
Estimated: 1 session. No Airtable changes needed.
Session F · Priority 3 Editorial cards in Welcome + "What's On Today"
Gives the app a daily editorial pulse. Users return to see what's featured. Entirely Airtable-driven — no code deploy needed once implemented.
P15: inject "Today: X events open across Y venues" line into welcome body (.bpf-v382-body)
P14: APP_SETTINGS "featured_venue_id" Airtable field → card injected below CTA chips
Featured card: venue photo (hero image), name, type, "View on map" → tap to navigate
P16: Airtable boolean "featured" → amber "Editor's Pick" pill in popup + venue hero
Estimated: 1–2 sessions. Requires APP_SETTINGS Airtable table with 1 row.
Session G · Low / Pre-festival Partners content update + Dark tile layer
Two independent low-risk upgrades, ideally close to October when partners are confirmed.
Partners: update V411 JS BRANDS array with real confirmed sponsors + actual brand colours from brand guidelines
Dark tiles: L.tileLayer swap to Carto Dark Matter when new Date().getHours() >= 20
font-display swap: add &display=swap to Google Fonts URL (2 min, P26)
Estimated: 30 min combined. Content-driven, not engineering-heavy.
06
Strategic Phases
Recommended sequencing toward October 9, 2026 — 153 days remaining
Implementation phases · BPFmap 2026
Phase 1 · May 2026
Validate & Stabilise
  • Session A — test V408–V412
  • B1 Grabber fix
  • B2 Popup on expand
  • B4 Programme map nav
  • Session B — Open until
  • Session C — UX fixes
Phase 2 · June–August 2026
Discovery & Share
  • Session D — Deep links + Share
  • Session E — Extended search
  • Session F — Editorial cards
  • P10 Next event in hero
  • P12 Dark tile layer
  • P18 Plan my day (MVP)
Phase 3 · Sept–Oct 2026
Festival Ready
  • Session G — Partners + content
  • In-Light deep link integration
  • Real-content Airtable QA
  • P21 Service Worker (if possible)
  • Final CSS review pass
  • Load test + mobile QA