Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision 2f50c533f5a3f95640b17e833ac1bb7bc0207ac1)
+++ src/routes/posts.js	(revision 6053c6cd26763e88d5f2f920fb1270ca5bea6b78)
@@ -713,5 +713,7 @@
     // top-level "open the player" link that works even when a browser shield/CSP blocks
     // the cross-site iframe (a full-page navigation is not a cross-site frame).
-    return { ...p, content, embedHtml, embedUrl };
+    let poll = null;
+    if (p.poll_json) { try { poll = JSON.parse(p.poll_json); } catch { /* ignore */ } }
+    return { ...p, content, embedHtml, embedUrl, poll };
   });
   // Option A: allow the followed Klonkt sites' player iframes (you follow them) by
@@ -799,4 +801,15 @@
   }
   if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
+  res.redirect('/news');
+});
+
+// Vote on a fediverse poll (a Question in the feed). Owner-only, like the other interactions.
+router.post('/news/vote', requireSiteManager, async (req, res) => {
+  const site = res.locals.site;
+  const note = (req.body.note || '').toString();
+  let choice = req.body.choice;
+  if (choice == null) choice = [];
+  if (!Array.isArray(choice)) choice = [choice];
+  if (site && note && choice.length) { try { await ActivityPubService.voteOnPoll(site, note, choice.map(String)); } catch (e) { /* ignore */ } }
   res.redirect('/news');
 });
