Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision b7d4458e21f8eef0c969874d5d571662936d8702)
+++ src/routes/posts.js	(revision 5421ce1dc5887f2baa36f74f699a8ce0a0382270)
@@ -627,5 +627,5 @@
   // Drop the now-redundant "🎵 … listen on <site>" line — the embedded player below shows it.
   const content = html.replace(/<p>🎵[\s\S]*?<\/p>\s*/i, '');
-  return { origin: u.origin, content, html: `<iframe class="tl-embed-frame tl-embed-klonkt" src="${src}" title="Audio" loading="lazy" frameborder="0" allow="autoplay; encrypted-media"></iframe>` };
+  return { origin: u.origin, embedUrl: src, content, html: `<iframe class="tl-embed-frame tl-embed-klonkt" src="${src}" title="Audio" loading="lazy" frameborder="0" allow="autoplay; encrypted-media"></iframe>` };
 }
 
@@ -636,9 +636,13 @@
     let embedHtml = timelineEmbedHtml(p.content);
     let content = p.content;
+    let embedUrl = null;
     if (!embedHtml) {
       const k = klonktAudioEmbed(p.content, p.url);
-      if (k) { embedHtml = k.html; content = k.content; cspOrigins.add(k.origin); }
+      if (k) { embedHtml = k.html; content = k.content; embedUrl = k.embedUrl; cspOrigins.add(k.origin); }
     }
-    return { ...p, content, embedHtml };
+    // embedUrl = the player's direct /embed?post=… URL. Surfaced so the view can offer a
+    // 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 };
   });
   // Option A: allow the followed Klonkt sites' player iframes (you follow them) by
