diff --git a/app/main.py b/app/main.py
index 14f02a9..c0472e1 100644
--- a/app/main.py
+++ b/app/main.py
@@ -523,15 +523,20 @@ function renderMembers() {
const src = m.manual
? 'manual'
: 'OC';
+ // Effective Matrix handle: dashboard-set external MXID, else the local
+ // @username:inference.coop identity (pending users have no username yet).
+ // Account cell: username on top (prominent); email + Matrix handle beneath
+ // in the muted secondary style. Users who never finished setup have no
+ // username — fall back to the email in the top position.
+ const top = m.username || m.email;
+ const mxid = m.matrix_mxid || (m.username ? '@' + m.username + ':inference.coop' : '');
+ const mxidLine = mxid ? '
' + esc(mxid) + '
' : '';
+ const emailLine = m.username ? '' + esc(m.email) + '
' : '';
const org = m.org
? ' org: ' + esc(m.org) + ''
: '';
- // Effective Matrix handle: dashboard-set external MXID, else the local
- // @username:inference.coop identity (pending users have no username yet).
- const mxid = m.matrix_mxid || (m.username ? '@' + m.username + ':inference.coop' : '');
- const mxidLine = mxid ? '' + esc(mxid) + '
' : '';
return '' +
- '| ' + esc(m.email) + (m.username ? ' ' + esc(m.username) + ' ' : '') + mxidLine +
+ ' | ' + esc(top) + '' + emailLine + mxidLine +
(org ? ' ' + org + ' ' : '') + ' | ' +
'' + pill + ' | ' +
'' + act + ' | ' +
@@ -556,8 +561,9 @@ function renderMembers() {
adminSection.style.display = '';
$('admin-rows').innerHTML = adminsData.map(m => {
const reset = m.reset_at ? m.reset_at.slice(0,10) : '—';
+ const adminTop = m.username || m.email;
return '
' +
- '| ' + esc(m.email) + (m.username ? ' ' + esc(m.username) + ' ' : '') + ' | ' +
+ '' + esc(adminTop) + '' + (m.username ? ' ' + esc(m.email) + ' ' : '') + ' | ' +
'admin | ' +
'' + (m.activated ? 'yes' : 'pending') + ' | ' +
'' + fmt(memberSpend(m)) + ' | ' +