diff --git a/server/public/home.html b/server/public/home.html
index d69fe93..ec176ff 100644
--- a/server/public/home.html
+++ b/server/public/home.html
@@ -2654,7 +2654,7 @@ function meetParticipantsList(){ const a=[{id:'__local', name:((ME&&ME.name)||(M
let meetChatLog=[], meetChatUnread=0, meetChatTo='';
function resetMeetChat(){ meetChatLog=[]; meetChatUnread=0; meetChatTo=''; const c=document.getElementById('meetChat'); if(c) c.remove(); updateMeetChatBadge(); }
function meetChatRecipients(){ const a=[]; meetPeers.forEach((pp,pid)=>a.push({id:pid, name:meetNames.get(pid)||pp.name||'Guest'})); return a; }
-function toggleMeetChat(){ const ex=document.getElementById('meetChat'); if(ex){ ex.remove(); return; } const meet=document.querySelector('.meet'); if(!meet) return; const p=document.createElement('div'); p.id='meetChat'; p.className='meet-panel meet-chat'; meet.appendChild(p); meetChatUnread=0; updateMeetChatBadge(); renderMeetChat(); }
+function toggleMeetChat(){ const ex=document.getElementById('meetChat'); if(ex){ ex.remove(); try{ bzNativeSyncTiles(); }catch(_){} return; } const meet=document.querySelector('.meet'); if(!meet) return; const p=document.createElement('div'); p.id='meetChat'; p.className='meet-panel meet-chat'; meet.appendChild(p); meetChatUnread=0; updateMeetChatBadge(); renderMeetChat(); try{ bzNativeSyncTiles(); }catch(_){} }
function updateMeetChatBadge(){ const b=document.getElementById('meetChatBadge'); if(!b) return; if(meetChatUnread>0){ b.textContent=meetChatUnread>9?'9+':meetChatUnread; b.style.display='grid'; } else b.style.display='none'; }
function renderMeetChat(){
const p=document.getElementById('meetChat'); if(!p) return;
@@ -2719,7 +2719,7 @@ function copyMeetingLink(){
function fallbackCopy(text,cb){ try{ const ta=document.createElement('textarea'); ta.value=text; ta.style.position='fixed'; ta.style.opacity='0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); cb&&cb(); }catch(_){ prompt('Copy this link:', text); } }
let meetPanelTab='people'; // 'people' | 'add'
let _addPool=null; // cached candidates for "Add people" (group members for a group call)
-function toggleMeetPanel(){ const ex=document.getElementById('meetPanel'); if(ex){ ex.remove(); return; } const meet=document.querySelector('.meet'); if(!meet) return; meetPanelTab='people'; const p=document.createElement('div'); p.id='meetPanel'; p.className='meet-panel'; meet.appendChild(p); renderMeetPanel(); }
+function toggleMeetPanel(){ const ex=document.getElementById('meetPanel'); if(ex){ ex.remove(); try{ bzNativeSyncTiles(); }catch(_){} return; } const meet=document.querySelector('.meet'); if(!meet) return; meetPanelTab='people'; const p=document.createElement('div'); p.id='meetPanel'; p.className='meet-panel'; meet.appendChild(p); renderMeetPanel(); try{ bzNativeSyncTiles(); }catch(_){} }
function renderMeetPanel(){
const p=document.getElementById('meetPanel'); if(!p) return;
const list=meetParticipantsList();
@@ -5060,9 +5060,10 @@ function openMeetMore(anchor){
const r=anchor.getBoundingClientRect();
menu.style.left=Math.max(8,Math.min(r.left-100, window.innerWidth-menu.offsetWidth-8))+'px';
menu.style.top=Math.max(8,(r.top-menu.offsetHeight-10))+'px';
- menu.querySelectorAll('.mm-opt').forEach(b=>b.onclick=()=>{ const it=items[+b.dataset.i]; menu.remove(); try{ it.fn(); }catch(_){} });
- const close=(e)=>{ if(!menu.contains(e.target) && !anchor.contains(e.target)){ menu.remove(); document.removeEventListener('mousedown',close); document.removeEventListener('touchstart',close); } };
+ menu.querySelectorAll('.mm-opt').forEach(b=>b.onclick=()=>{ const it=items[+b.dataset.i]; menu.remove(); try{ it.fn(); }catch(_){} try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} });
+ const close=(e)=>{ if(!menu.contains(e.target) && !anchor.contains(e.target)){ menu.remove(); document.removeEventListener('mousedown',close); document.removeEventListener('touchstart',close); try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} } };
setTimeout(()=>{ document.addEventListener('mousedown',close); document.addEventListener('touchstart',close); },0);
+ try{ if(meetNative) bzNativeSyncTiles(); }catch(_){} // clear the native video NOW so the menu isn't hidden behind it
}
async function setSpeakerDevice(id){
meetSinkId=id||''; try{ localStorage.setItem('bzc_sink', meetSinkId); }catch(_){}
@@ -5390,9 +5391,14 @@ let meetNative=false, meetNativeUuid=null, _ncEnding=false; // native call: WebV
// join-leave / camera-toggle changes; a no-op on web calls. getBoundingClientRect coords are CSS px, which
// equal points in the WKWebView, so the plugin can use them directly.
let _ncTileTimer=null;
+// Any web menu/panel/modal that opens over the meeting would be hidden BEHIND the native video (which draws
+// on top of the WebView). While one is open, clear the native video so the web UI is usable; the poll restores
+// it when they close. (Covers the More/audio menus, participant panel, meeting chat, modals, image lightbox.)
+function bzMeetOverlayOpen(){ return !!document.querySelector('.meet-panel, .spk-menu, .modal-ov, .lightbox'); }
function bzNativeSyncTiles(){
if(!meetNative) return;
const NC=nativeCallPlugin(); if(!NC||!NC.syncVideoTiles) return;
+ if(bzMeetOverlayOpen()){ try{ NC.syncVideoTiles({ tiles:[] }); }catch(_){} return; } // a menu/panel is open → don't cover it
const tiles=[];
// Native views draw ON TOP of the WebView, so a full-height tile would cover the control bar. Never let a
// tile's native video extend past the top of the meeting controls (or, in normal grid mode, below the grid).