// RM Circle: OPTIONAL member profile (Marty + Manson, 2026-09-17). // // Contact details are never required to hold a position, get paid, read the org, // use the training or the tools. Nothing on chain depends on them. They are asked // for in exactly one place where their absence is the whole problem: a message // cannot be delivered to someone who has given no way to reach them. Everything // else is an invitation the member can decline, and declining costs them nothing. // // Usage: window.RMCProfile.prompt({ reason: 'alerts'|'inbox' }) // dismissable // window.RMCProfile.edit('username'|'email') // change later // window.RMCProfile.status() // read-only (function () { 'use strict'; var back = null, resolveDone = null, state = null, oneShot = false, showSteps = true, reason = 'alerts'; var GOLD = '#d4af37', TEAL = '#4ed6cb'; function el(tag, css, html) { var e = document.createElement(tag); if (css) e.style.cssText = css; if (html != null) e.innerHTML = html; return e; } function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]; }); } async function api(path, body) { var r = await fetch(path, body ? { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) } : {}); var j = null; try { j = await r.json(); } catch (e) { j = {}; } if (!r.ok || j.error) throw new Error(j.error || 'Something went wrong. Try again.'); return j; } function shell() { back = el('div', 'position:fixed;inset:0;z-index:2147483100;display:flex;align-items:center;justify-content:center;' + 'padding:20px;background:rgba(3,7,14,.88);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);overflow:auto;'); back.setAttribute('role', 'dialog'); back.setAttribute('aria-label', 'Member profile — optional'); var card = el('div', 'position:relative;width:100%;max-width:440px;max-height:94vh;overflow:auto;border-radius:20px;' + 'background:#0a1119;border:1px solid rgba(212,175,55,.55);box-shadow:0 24px 70px rgba(0,0,0,.7);' + 'font-family:system-ui,Segoe UI,Arial,sans-serif;color:#e8eef6;padding:22px 22px 20px;'); card.id = 'pgCard'; { // every profile dialog can be closed: nothing here is compulsory var x = el('button', 'position:absolute;top:10px;right:12px;z-index:2;width:34px;height:34px;border-radius:50%;border:none;' + 'cursor:pointer;background:rgba(255,255,255,.08);color:#fff;font-size:20px;line-height:1;font-weight:700;', '×'); x.id = 'pgClose'; x.setAttribute('aria-label', 'Close'); x.addEventListener('click', close); card.appendChild(x); back.addEventListener('click', function (e) { if (e.target === back) close(); }); } back.appendChild(card); document.body.appendChild(back); return card; } function head(card, step) { var keep = card.querySelector('button[aria-label="Close"]'); card.innerHTML = ''; if (keep) card.appendChild(keep); if (!showSteps) return card; card.appendChild(el('div', 'text-align:center;letter-spacing:2px;text-transform:uppercase;font-size:11px;font-weight:700;color:' + GOLD + ';margin-bottom:8px;', 'Position #' + esc(state.id) + ' · step ' + step + ' of 2')); return card; } function note(text, color) { return el('p', 'margin:0 0 14px;font-size:13.5px;line-height:1.6;color:' + (color || '#9fb3c8') + ';', text); } function input(id, placeholder, value, type) { var i = el('input'); i.id = id; i.type = type || 'text'; i.placeholder = placeholder; i.value = value || ''; i.autocomplete = type === 'email' ? 'email' : 'off'; i.style.cssText = 'width:100%;box-sizing:border-box;padding:12px 14px;border-radius:11px;border:1px solid rgba(255,255,255,.16);' + 'background:rgba(255,255,255,.04);color:#fff;font-size:16px;margin-bottom:10px;'; return i; } function button(label, id) { var b = el('button', 'width:100%;padding:13px 16px;border-radius:11px;border:none;cursor:pointer;font-size:15px;font-weight:700;' + 'background:linear-gradient(180deg,' + GOLD + ',#b8932f);color:#1a1205;', label); if (id) b.id = id; return b; } function errLine() { return el('p', 'margin:0 0 10px;font-size:13px;color:#ff8b8b;display:none;'); } // ---- step 1: username ---- function stepUsername() { var card = head(document.getElementById('pgCard'), 1); card.appendChild(el('h2', 'margin:0 0 6px;font-size:21px;line-height:1.25;color:#fff;', 'Pick your username')); card.appendChild(note('How your team sees you instead of a bare member number. Letters, numbers or underscores, 3 to 20 characters. Optional, and changeable any time.')); var err = errLine(); card.appendChild(err); var i = input('pgUser', 'e.g. ' + (state.suggest || 'member' + state.id), (state.profile && state.profile.username) || ''); card.appendChild(i); var b = button('Save and continue', 'pgUserSave'); card.appendChild(b); var go = async function () { err.style.display = 'none'; b.disabled = true; b.textContent = 'Saving…'; try { var r = await api('/api/public/profile/username', { username: i.value }); state.profile = r.profile; if (oneShot) { close(); return; } next(); } catch (e) { err.textContent = e.message; err.style.display = 'block'; b.disabled = false; b.textContent = 'Save and continue'; } }; b.addEventListener('click', go); i.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); go(); } }); setTimeout(function () { i.focus(); }, 60); } // ---- step 2: email + code ---- function stepEmail() { var card = head(document.getElementById('pgCard'), 2); var prefill = (state.profile && state.profile.email) || ''; card.appendChild(el('h2', 'margin:0 0 6px;font-size:21px;line-height:1.25;color:#fff;', 'Confirm your email')); card.appendChild(note((reason === 'inbox' ? 'Your inbox needs somewhere to reach you. Add an email and your leader\'s messages reach you even when you are not on the site. ' : 'Get an email the moment a payout lands in your wallet, and your leader can reach you when it matters. ') + 'Optional, never shown to other members, never sold, and you can remove it any time.' + (prefill ? ' We already have this one on file for your payout alerts, so just confirm it.' : ''))); var err = errLine(); card.appendChild(err); var i = input('pgEmail', 'you@example.com', prefill, 'email'); card.appendChild(i); var b = button(prefill ? 'Send me the code' : 'Send me a code', 'pgMailSend'); card.appendChild(b); var codeWrap = el('div', 'display:none;margin-top:14px;padding-top:14px;border-top:1px solid rgba(255,255,255,.1);'); var sentNote = note('', TEAL); codeWrap.appendChild(sentNote); var ci = input('pgCode', '6-digit code', ''); ci.inputMode = 'numeric'; ci.maxLength = 6; codeWrap.appendChild(ci); var cb = button('Confirm and finish', 'pgCodeConfirm'); codeWrap.appendChild(cb); var again = el('p', 'margin:10px 0 0;font-size:12.5px;color:#7f93a8;text-align:center;cursor:pointer;', 'Wrong address? Change it and send a new code.'); again.addEventListener('click', function () { codeWrap.style.display = 'none'; b.disabled = false; b.textContent = 'Send me a code'; i.focus(); }); codeWrap.appendChild(again); card.appendChild(codeWrap); b.addEventListener('click', async function () { err.style.display = 'none'; b.disabled = true; b.textContent = 'Sending…'; try { var r = await api('/api/public/profile/email-start', { email: i.value }); sentNote.textContent = 'Code sent to ' + (r.to || i.value) + '. It lasts 15 minutes. Check spam the first time.'; codeWrap.style.display = 'block'; b.textContent = 'Code sent'; setTimeout(function () { ci.focus(); }, 60); } catch (e) { err.textContent = e.message; err.style.display = 'block'; b.disabled = false; b.textContent = 'Send me a code'; } }); var confirm = async function () { err.style.display = 'none'; cb.disabled = true; cb.textContent = 'Checking…'; try { var r = await api('/api/public/profile/email-verify', { code: ci.value }); state.profile = r.profile; if (oneShot) { close(); return; } done(); } catch (e) { err.textContent = e.message; err.style.display = 'block'; cb.disabled = false; cb.textContent = 'Confirm and finish'; } }; cb.addEventListener('click', confirm); ci.addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); confirm(); } }); setTimeout(function () { i.focus(); }, 60); } function done() { var card = head(document.getElementById('pgCard'), 2); card.innerHTML = '
Your leader can reach you now, and every payout to your wallet sends you a note.