fix(brand/ux): real Biz Connect logo, branded loading screen, phone login, no blank gap

- Replace the leftover 'Your Virtual CXO' logo.png with the app icon (C mark) in every
  header (home/index/connect/dashboard) + the app icon on share.html; delete logo.png.
- Loading screen now shows the orbit mark + 'Biz Connect' wordmark + 'Loading…' (was bare).
- Keep the branded splash up until the chat list finishes loading — no blank/stuck gap
  after login (previously hidden before loadSidebar()).
- Login accepts email OR phone (field was type=email, which rejected phone numbers and so
  blocked the mobile-login that triggers the account merge). Label → 'Email or phone'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 17:16:08 +05:30
parent d515a562a0
commit 952242f62b
6 changed files with 17 additions and 11 deletions
+1 -1
View File
@@ -76,7 +76,7 @@
<script>if(new URLSearchParams(location.search).get('embed')==='1')document.documentElement.classList.add('embed');</script> <script>if(new URLSearchParams(location.search).get('embed')==='1')document.documentElement.classList.add('embed');</script>
<a href="/home" id="homeLink"><span data-ic="arrowLeft" data-sz="16"></span> Home</a> <a href="/home" id="homeLink"><span data-ic="arrowLeft" data-sz="16"></span> Home</a>
<div class="topbar" id="topbar"> <div class="topbar" id="topbar">
<div class="brandrow"><img src="/logo.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span>Connect</span></div></div> <div class="brandrow"><img src="/icon-192.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span>Connect</span></div></div>
<div class="agentchip" id="agentChip"></div> <div class="agentchip" id="agentChip"></div>
</div> </div>
<div class="topbar2" id="bar"><span id="barStatus"></span><button id="endBtn">End session</button></div> <div class="topbar2" id="bar"><span id="barStatus"></span><button id="endBtn">End session</button></div>
+1 -1
View File
@@ -92,7 +92,7 @@
</head> </head>
<body> <body>
<header> <header>
<div class="brandrow"><img src="/logo.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span class="y">Connect</span> <span class="tag">· Dashboard</span></div></div> <div class="brandrow"><img src="/icon-192.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"><div class="brand">Biz <span class="y">Connect</span> <span class="tag">· Dashboard</span></div></div>
<div class="row" id="hdrRight"></div> <div class="row" id="hdrRight"></div>
</header> </header>
<main id="app"></main> <main id="app"></main>
+13 -7
View File
@@ -682,8 +682,11 @@
/* ---- Loading / toast ---- */ /* ---- Loading / toast ---- */
.loading{position:fixed;inset:0;display:grid;place-items:center;background:#1F3B73;z-index:9000;color:rgba(255,255,255,.82);font-size:.9rem;} .loading{position:fixed;inset:0;display:grid;place-items:center;background:#1F3B73;z-index:9000;color:rgba(255,255,255,.82);font-size:.9rem;}
.loading .ld-inner{display:flex;flex-direction:column;align-items:center;gap:1rem;} .loading .ld-inner{display:flex;flex-direction:column;align-items:center;gap:.85rem;}
.loading .ld-inner img{width:72px;height:72px;} .loading .ld-inner img{width:72px;height:72px;}
.loading .ld-wm{font-size:1.35rem;font-weight:800;color:#fff;letter-spacing:.3px;margin-top:.15rem;}
.loading .ld-wm b{color:var(--brand);font-weight:800;}
.loading .ld-sub{color:rgba(255,255,255,.66);font-size:.82rem;}
/* Chat thread loading (light pane) and call-connecting (dark stage) — branded, centered. */ /* Chat thread loading (light pane) and call-connecting (dark stage) — branded, centered. */
.thread-loading{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.7rem;color:var(--muted);font-size:.86rem;} .thread-loading{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.7rem;color:var(--muted);font-size:.86rem;}
.call-connecting{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;background:#16294F;color:rgba(255,255,255,.82);font-size:.95rem;} .call-connecting{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;background:#16294F;color:rgba(255,255,255,.82);font-size:.95rem;}
@@ -757,16 +760,16 @@
<body> <body>
<script src="/icons.js?v=4"></script> <script src="/icons.js?v=4"></script>
<script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@twemoji/api@15.1.0/dist/twemoji.min.js" crossorigin="anonymous"></script>
<script>window.__BUILD='2026-07-02-batch33';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD); <script>window.__BUILD='2026-07-02-batch34';console.log('%cBiz Connect','color:#1F3B73;font-weight:bold','build '+window.__BUILD);
// Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load // Render modern (Twemoji) emojis in place of the OS's flat ones. No-op if the CDN didn't load
// (emojis stay as plain Unicode). (#5) // (emojis stay as plain Unicode). (#5)
function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script> function twemojify(el){ try{ if(el && window.twemoji) window.twemoji.parse(el, { folder:'svg', ext:'.svg' }); }catch(_){} }</script>
<div class="loading" id="loading"><div class="ld-inner"><img src="/loaders/loader-orbit-dark.svg" alt="" width="72" height="72"><span>Loading…</span></div></div> <div class="loading" id="loading"><div class="ld-inner"><img src="/loaders/loader-orbit-dark.svg" alt="" width="72" height="72"><div class="ld-wm">Biz <b>Connect</b></div><span class="ld-sub">Loading…</span></div></div>
<header> <header>
<div class="brandrow"> <div class="brandrow">
<button class="navtoggle" id="navToggle" title="Toggle menu" aria-label="Toggle menu"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button> <button class="navtoggle" id="navToggle" title="Toggle menu" aria-label="Toggle menu"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button>
<img src="/logo.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))"> <img src="/icon-192.png" alt="" style="height:46px;width:auto;max-width:190px;border-radius:8px;object-fit:contain;background:#fff;padding:5px 12px;image-rendering:-webkit-optimize-contrast" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'logo',textContent:'B'}))">
<div class="brand">Biz <span class="y">Connect</span></div> <div class="brand">Biz <span class="y">Connect</span></div>
</div> </div>
<div id="hdrRight"></div> <div id="hdrRight"></div>
@@ -2850,7 +2853,7 @@ async function renderLogin(){
<button id="tabReg">Register team</button> <button id="tabReg">Register team</button>
</div>`:''} </div>`:''}
<form id="loginForm"> <form id="loginForm">
<span class="lbl">Email</span><input id="li_email" type="email" placeholder="you@bizgaze.com" autocomplete="username"> <span class="lbl">Email or phone</span><input id="li_email" type="text" inputmode="email" placeholder="you@bizgaze.com or mobile number" autocomplete="username">
<span class="lbl">Password</span>${pwField('li_pw','password')} <span class="lbl">Password</span>${pwField('li_pw','password')}
<label style="display:flex;align-items:center;gap:.5rem;margin:.7rem 0;color:var(--ink);font-size:.9rem;cursor:pointer"><input type="checkbox" id="li_remember" style="width:18px;height:18px;accent-color:var(--blue);margin:0"> Remember me on this device</label> <label style="display:flex;align-items:center;gap:.5rem;margin:.7rem 0;color:var(--ink);font-size:.9rem;cursor:pointer"><input type="checkbox" id="li_remember" style="width:18px;height:18px;accent-color:var(--blue);margin:0"> Remember me on this device</label>
<button class="gobtn" id="li_btn" type="submit">Sign in</button> <button class="gobtn" id="li_btn" type="submit">Sign in</button>
@@ -2905,15 +2908,18 @@ async function doRegister(){
setupPush(); // register the notification service worker + subscribe to Web Push (if granted) setupPush(); // register the notification service worker + subscribe to Web Push (if granted)
{ const cl=document.getElementById('chatlist'); if(cl) enablePullRefresh(cl, loadSidebar); } // pull-to-refresh the chat list { const cl=document.getElementById('chatlist'); if(cl) enablePullRefresh(cl, loadSidebar); } // pull-to-refresh the chat list
setTimeout(maybeNotifPrompt, 1500); // gentle "enable notifications" prompt if still undecided (key for iOS PWA) setTimeout(maybeNotifPrompt, 1500); // gentle "enable notifications" prompt if still undecided (key for iOS PWA)
document.getElementById('loading').style.display='none';
// Fast-path: when opened from a notification, show the chat immediately (only needs the // Fast-path: when opened from a notification, show the chat immediately (only needs the
// thread fetch) and load the sidebar in the background — don't make the reload wait on it. // thread fetch) and load the sidebar in the background — don't make the reload wait on it.
let oid=null, okind='dm'; let oid=null, okind='dm';
try{ const q=new URLSearchParams(location.search); oid=q.get('openId'); okind=q.get('openKind')||'dm'; if(oid) history.replaceState(null,'','/home'); }catch(_){} try{ const q=new URLSearchParams(location.search); oid=q.get('openId'); okind=q.get('openKind')||'dm'; if(oid) history.replaceState(null,'','/home'); }catch(_){}
if(oid){ if(oid){
selectChat(okind, oid); // open the chat right away (only waits on the thread fetch) selectChat(okind, oid); // open the chat right away (only waits on the thread fetch)
document.getElementById('loading').style.display='none'; // the chat pane shows its own thread loader
loadSidebar().then(()=>{ try{ const it=rowFor(okind,oid); const nm=document.querySelector('#chatPanel .convo-head .nm'); if(it&&nm) nm.textContent=it.name; }catch(_){} }); loadSidebar().then(()=>{ try{ const it=rowFor(okind,oid); const nm=document.querySelector('#chatPanel .convo-head .nm'); if(it&&nm) nm.textContent=it.name; }catch(_){} });
} else { await loadSidebar(); renderChatPanel(); } } else {
await loadSidebar(); renderChatPanel();
document.getElementById('loading').style.display='none'; // keep the branded splash up until the list is ready (no blank/stuck gap)
}
})(); })();
</script> </script>
</body> </body>
+1 -1
View File
@@ -55,7 +55,7 @@
<body> <body>
<header> <header>
<div class="brandrow"> <div class="brandrow">
<img src="/logo.png" alt="" style="height:40px;width:auto;max-width:170px;border-radius:8px;object-fit:contain;background:#fff;padding:4px 10px" onerror="this.style.display='none'"> <img src="/icon-192.png" alt="" style="height:40px;width:auto;max-width:170px;border-radius:8px;object-fit:contain;background:#fff;padding:4px 10px" onerror="this.style.display='none'">
<div class="brand">Biz <span>Connect</span></div> <div class="brand">Biz <span>Connect</span></div>
</div> </div>
<div class="hdr-right"> <div class="hdr-right">
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

+1 -1
View File
@@ -67,7 +67,7 @@
<a href="/" id="homeLink" style="position:fixed;top:14px;left:16px;z-index:50;display:inline-flex;align-items:center;gap:6px;background:rgba(255,255,255,.92);color:#1F3B73;text-decoration:none;font-weight:600;font-size:.86rem;padding:.45rem .8rem;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.15)"><span data-ic="arrowLeft" data-sz="16"></span> Home</a> <a href="/" id="homeLink" style="position:fixed;top:14px;left:16px;z-index:50;display:inline-flex;align-items:center;gap:6px;background:rgba(255,255,255,.92);color:#1F3B73;text-decoration:none;font-weight:600;font-size:.86rem;padding:.45rem .8rem;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.15)"><span data-ic="arrowLeft" data-sz="16"></span> Home</a>
<div class="stage"> <div class="stage">
<div class="brandpanel"> <div class="brandpanel">
<img src="/logo.png" alt="" style="width:88px;height:88px;border-radius:22px;object-fit:contain;margin-bottom:1.2rem;background:#fff;padding:8px;box-shadow:0 12px 30px rgba(0,0,0,.25)" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'mark',textContent:'B'}))"> <img src="/icon-512.png" alt="" style="width:88px;height:88px;border-radius:22px;object-fit:contain;margin-bottom:1.2rem;background:#fff;padding:8px;box-shadow:0 12px 30px rgba(0,0,0,.25)" onerror="this.replaceWith(Object.assign(document.createElement('div'),{className:'mark',textContent:'B'}))">
<div class="wordmark">Biz <span>Connect</span></div> <div class="wordmark">Biz <span>Connect</span></div>
<div class="tagline">Secure, instant remote support — no downloads, you stay in control.</div> <div class="tagline">Secure, instant remote support — no downloads, you stay in control.</div>
</div> </div>