diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html
index 83bd378..4da0f36 100644
--- a/web/zebra-spaces.html
+++ b/web/zebra-spaces.html
@@ -3191,6 +3191,21 @@ async function handleSignal(raw){
if (canSpeak(myRole) && canSpeak(m.role) && !peers.has(m.uuid)){
connectToPeer(m.uuid, myUUID < m.uuid);
}
+ /* If the role transition stripped them of the ability to
+ * publish (anything -> listener), their camera/screen/game
+ * tiles can't get fresh RTP anymore. The demoted page calls
+ * sfuUnpublish* on its own side which should propagate via
+ * SFU 'ended', but that path is unreliable (Pion may not
+ * fire OnConnectionStateChange immediately and SSE renego
+ * can race). Authoritative removal: drop tiles by pubkey
+ * here, the moment the role change broadcast lands. */
+ if (canSpeak(prev) && !canSpeak(m.role) && subjPub){
+ try {
+ removeScreenTile(subjPub);
+ removeCameraTile(subjPub);
+ removeVideoTile('gameshare', subjPub);
+ } catch(_){}
+ }
}
renderRoom();
reorderTiles();
@@ -3974,8 +3989,8 @@ logLine('', 'ready โ pick a handle, type a rendezvous code, enter the space');