diff --git a/server/public/home.html b/server/public/home.html
index 5a96348..56380cd 100644
--- a/server/public/home.html
+++ b/server/public/home.html
@@ -2197,7 +2197,11 @@ function convoShellHTML(it){
+ '';
}
// Small round avatar (photo if the member has one, else colored initials) for a group message sender.
-function senderAvatar(id, name){ const mem=convoMembers.find(x=>x.id===id); const av=mem&&mem.avatar; return ''+(av?'':'')+pEsc(initials(name||'?'))+''; }
+function senderAvatar(id, name){ const mem=convoMembers.find(x=>x.id===id); let av=mem&&mem.avatar; if(!av){ try{ const c=(typeof CONTACTS!=='undefined'?CONTACTS:[]).find(x=>x&&x.id===id); av=c&&c.avatar; }catch(_){} } return ''+(av?'
':'')+pEsc(initials(name||'?'))+''; } // #DP: fall back to the global CONTACTS avatar so a cached-open paint (before convoMembers loads) still shows photos, not just initials
+// Repaint group message sender avatars once convoMembers is loaded — the instant cache-paint renders before the
+// member list arrives, and the network render diffs/skips unchanged messages, so without this the photos would
+// stay as initials on a re-opened group until a full reload.
+function refreshSenderAvatars(){ try{ document.querySelectorAll('#msgs .sender[data-uid]').forEach(sd=>{ const uid=sd.getAttribute('data-uid'); const old=sd.querySelector('.snd-av'); if(!uid||!old) return; const mem=convoMembers.find(x=>x.id===uid); const spans=sd.querySelectorAll('span'); const nm=(mem&&mem.name)||(spans.length?spans[spans.length-1].textContent:'')||''; old.outerHTML=senderAvatar(uid, nm); }); }catch(_){} }
function bubbleHTML(m){
if(m.evt==='call-start') return '