Member area: in-page dialogs replace every browser prompt/confirm

Mobile Safari shows a red 'Suppress dialogs' option on the second native pop-up
in a row and, once tapped, swallows every later prompt on the site until reload
(Hugh, 2026-09-12, campaign top-up). IAP.ask / IAP.confirmBox in common.js render
a modal-card dialog (Enter/Escape, focus, backdrop cancel); all nine call sites in
my.js use them (top-up credits, link insert x2 with selection restore, pay it
forward, adopt note, release, unlink, add position, Trust Wallet check).
Version tags bumped on every page that loads common.js.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-12 09:31:43 -05:00
parent 261f90d843
commit ebac2fcb32
16 changed files with 59 additions and 27 deletions
+1 -1
View File
@@ -329,7 +329,7 @@
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/admin.js?v=20260912a"></script> <script src="/assets/admin.js?v=20260912a"></script>
</body> </body>
</html> </html>
+28 -1
View File
@@ -205,5 +205,32 @@ window.IAP = (function () {
note: 'Joined through you so far: <b>' + refs + '</b>.' } note: 'Joined through you so far: <b>' + refs + '</b>.' }
]; ];
} }
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, reportAd, requestCode, launchChecks, launchToggle, $ }; // In-page dialogs instead of window.prompt / confirm. Mobile Safari shows a red "Suppress dialogs"
// option on the second native pop-up in a row and, once tapped, swallows every later prompt on the
// site until reload. ask() resolves the typed value (null on cancel); confirmBox() resolves true/false.
function dialog(o) {
return new Promise(resolve => {
const esc = t => String(t == null ? '' : t).replace(/[&<>"]/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]));
const back = document.createElement('div'); back.className = 'modal-back'; back.style.zIndex = '200';
const field = o.type === 'none' ? '' : o.type === 'textarea'
? '<textarea id="dlgInput" rows="5" style="width:100%;margin-top:12px">' + esc(o.value) + '</textarea>'
: '<input id="dlgInput" type="' + (o.type === 'number' ? 'number' : 'text') + '" ' + (o.type === 'number' ? 'inputmode="decimal" min="0" step="any" ' : '') + 'value="' + esc(o.value) + '" placeholder="' + esc(o.placeholder) + '" style="width:100%;margin-top:12px" autocomplete="off">';
back.innerHTML = '<div class="modal-card" role="dialog" aria-modal="true">' + (o.title ? '<h3 style="margin:0 0 8px">' + esc(o.title) + '</h3>' : '')
+ (o.text ? '<p class="muted small" style="margin:0;white-space:pre-line">' + esc(o.text) + '</p>' : '') + field
+ '<div style="display:flex;gap:10px;justify-content:flex-end;margin-top:16px;flex-wrap:wrap"><button type="button" class="btn ghost" id="dlgCancel">' + esc(o.cancel || 'Cancel') + '</button><button type="button" class="btn" id="dlgOk">' + esc(o.ok || 'OK') + '</button></div></div>';
document.body.appendChild(back);
const inp = back.querySelector('#dlgInput');
const done = v => { document.removeEventListener('keydown', onKey); back.remove(); resolve(v); };
const okv = () => done(o.type === 'none' ? true : (inp ? inp.value : ''));
const onKey = e => { if (e.key === 'Escape') { e.preventDefault(); done(o.type === 'none' ? false : null); } else if (e.key === 'Enter' && o.type !== 'textarea') { e.preventDefault(); okv(); } };
document.addEventListener('keydown', onKey);
back.querySelector('#dlgOk').addEventListener('click', okv);
back.querySelector('#dlgCancel').addEventListener('click', () => done(o.type === 'none' ? false : null));
back.addEventListener('click', e => { if (e.target === back) done(o.type === 'none' ? false : null); });
setTimeout(() => { if (inp) { inp.focus(); if (inp.select && o.type !== 'textarea') inp.select(); } else back.querySelector('#dlgOk').focus(); }, 30);
});
}
function ask(o) { return dialog(Object.assign({ type: 'text', value: '', placeholder: '' }, o || {})); }
function confirmBox(text, o) { return dialog(Object.assign({ type: 'none', text, ok: 'Yes', cancel: 'No' }, o || {})); }
return { getConfig, fmtPol, fmtUsd, status, renderNav, refreshNavWallet, describeEvent, feedRow, adSlot, reportAd, requestCode, launchChecks, launchToggle, ask, confirmBox, $ };
})(); })();
+16 -11
View File
@@ -651,7 +651,7 @@
catch (e) { IAP.status(e.message, 'bad'); } catch (e) { IAP.status(e.message, 'bad'); }
})); }));
el.querySelectorAll('button[data-topup]').forEach(b => b.addEventListener('click', async () => { el.querySelectorAll('button[data-topup]').forEach(b => b.addEventListener('click', async () => {
const n = prompt('How many credits to add to this campaign? (buys more views)'); const n = await IAP.ask({ title: 'Add credits', text: 'How many credits to add to this campaign? More credits buy more views.', type: 'number', placeholder: 'e.g. 100', ok: 'Add credits' });
if (!n) return; if (!n) return;
try { const r = await api('/api/my/campaigns/' + b.dataset.topup + '/topup', { credits: Number(n) }); try { const r = await api('/api/my/campaigns/' + b.dataset.topup + '/topup', { credits: Number(n) });
IAP.status('Added ' + r.added + ' credits' + (r.reactivated ? ' — campaign is live again.' : '.'), 'ok'); IAP.status('Added ' + r.added + ' credits' + (r.reactivated ? ' — campaign is live again.' : '.'), 'ok');
@@ -676,10 +676,11 @@
btn.addEventListener('click', () => { $('cSoloEd').focus(); document.execCommand(btn.dataset.cmd, false, null); })); btn.addEventListener('click', () => { $('cSoloEd').focus(); document.execCommand(btn.dataset.cmd, false, null); }));
document.querySelectorAll('.ed-bar [data-block]').forEach(btn => document.querySelectorAll('.ed-bar [data-block]').forEach(btn =>
btn.addEventListener('click', () => { $('cSoloEd').focus(); document.execCommand('formatBlock', false, btn.dataset.block); })); btn.addEventListener('click', () => { $('cSoloEd').focus(); document.execCommand('formatBlock', false, btn.dataset.block); }));
$('edLinkBtn').addEventListener('click', () => { $('edLinkBtn').addEventListener('click', async () => {
const url = prompt('Link URL (https://…)'); const sel = window.getSelection(); const range = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null; // the dialog steals the selection
const url = await IAP.ask({ title: 'Insert link', text: 'Link URL (https://…)', placeholder: 'https://', ok: 'Insert' });
if (!url) return; if (!url) return;
$('cSoloEd').focus(); $('cSoloEd').focus(); if (range) { sel.removeAllRanges(); sel.addRange(range); }
document.execCommand('createLink', false, url); document.execCommand('createLink', false, url);
}); });
// inline media: upload, then drop the element at the cursor (BV-style) // inline media: upload, then drop the element at the cursor (BV-style)
@@ -1031,7 +1032,7 @@
async function pif(email, name, address) { async function pif(email, name, address) {
let suggest = 25; let suggest = 25;
try { const { products } = await (await fetch('/api/catalog')).json(); const p20 = (products || []).find(p => p.priceCents === 2000); if (p20 && p20.costWei) suggest = Math.ceil(Number(p20.costWei) / 1e18) + 3; } catch (e) {} try { const { products } = await (await fetch('/api/catalog')).json(); const p20 = (products || []).find(p => p.priceCents === 2000); if (p20 && p20.costWei) suggest = Math.ceil(Number(p20.costWei) / 1e18) + 3; } catch (e) {}
const amt = prompt('Send POL from your wallet to ' + name + ' (' + address.slice(0, 6) + '…' + address.slice(-4) + ') for their first package.\nSuggested: the $20 package plus fees. Amount in POL:', String(suggest)); const amt = await IAP.ask({ title: 'Pay it forward', text: 'Send POL from your wallet to ' + name + ' (' + address.slice(0, 6) + '…' + address.slice(-4) + ') for their first package.\nSuggested: the $20 package plus fees. Amount in POL:', type: 'number', value: String(suggest), ok: 'Send POL' });
if (amt === null) return; if (amt === null) return;
const pol = Number(amt); if (!(pol > 0)) { IAP.status('Enter an amount in POL.', 'bad'); return; } const pol = Number(amt); if (!(pol > 0)) { IAP.status('Enter an amount in POL.', 'bad'); return; }
try { try {
@@ -1066,7 +1067,7 @@
+ '<span class="dt">last sign-in: <b>' + ago(w.lastSeen) + '</b></span>' + '<span class="dt">last sign-in: <b>' + ago(w.lastSeen) + '</b></span>'
+ (r.eligible ? '<button class="btn small" type="button" data-adopt="' + esc(w.username || w.email) + '" data-aname="' + esc(w.name) + '">Adopt</button>' : '') + '</div>').join(''); + (r.eligible ? '<button class="btn small" type="button" data-adopt="' + esc(w.username || w.email) + '" data-aname="' + esc(w.name) + '">Adopt</button>' : '') + '</div>').join('');
el.querySelectorAll('[data-adopt]').forEach(b => b.addEventListener('click', async () => { el.querySelectorAll('[data-adopt]').forEach(b => b.addEventListener('click', async () => {
const note = prompt('Your first message to ' + b.dataset.aname + ' (sent as a chat and an email):', 'Hi, I picked you up from the InstantAdPay holding tank so you have a sponsor who will actually help. Reply here and I will walk you through the first three steps.'); const note = await IAP.ask({ title: 'Adopt ' + b.dataset.aname, text: 'Your first message to ' + b.dataset.aname + ' (sent as a chat and an email):', type: 'textarea', ok: 'Adopt and send', value: 'Hi, I picked you up from the InstantAdPay holding tank so you have a sponsor who will actually help. Reply here and I will walk you through the first three steps.' });
if (note === null) return; if (note === null) return;
try { const rr = await api('/api/my/tank/adopt', { who: b.dataset.adopt, note }); IAP.status('You are now the sponsor for ' + rr.name + '. Chat and email sent.', 'ok'); loadTank(); loadCoach(); } try { const rr = await api('/api/my/tank/adopt', { who: b.dataset.adopt, note }); IAP.status('You are now the sponsor for ' + rr.name + '. Chat and email sent.', 'ok'); loadTank(); loadCoach(); }
catch (e) { IAP.status(e.message, 'bad'); } catch (e) { IAP.status(e.message, 'bad'); }
@@ -1100,7 +1101,7 @@
const inp = $('chatInput'); if (inp) { inp.value = b.dataset.say.replace(/\{\{name\}\}/g, b.dataset.nname.replace(/^@/, '')); inp.focus(); } const inp = $('chatInput'); if (inp) { inp.value = b.dataset.say.replace(/\{\{name\}\}/g, b.dataset.nname.replace(/^@/, '')); inp.focus(); }
})); }));
el.querySelectorAll('[data-release]').forEach(b => b.addEventListener('click', async () => { el.querySelectorAll('[data-release]').forEach(b => b.addEventListener('click', async () => {
if (!confirm('Release ' + b.dataset.rname + ' to the holding tank? You stop being their sponsor and another member can adopt them.')) return; if (!(await IAP.confirmBox('Release ' + b.dataset.rname + ' to the holding tank? You stop being their sponsor and another member can adopt them.', { title: 'Release to the tank', ok: 'Release' }))) return;
try { await api('/api/my/tank/release', { email: b.dataset.release }); IAP.status(b.dataset.rname + ' is in the holding tank.', 'ok'); loadCoach(); } try { await api('/api/my/tank/release', { email: b.dataset.release }); IAP.status(b.dataset.rname + ' is in the holding tank.', 'ok'); loadCoach(); }
catch (e) { IAP.status(e.message, 'bad'); } catch (e) { IAP.status(e.message, 'bad'); }
})); }));
@@ -1247,7 +1248,11 @@
b.addEventListener('click', () => { $('bcEd').focus(); document.execCommand(b.dataset.bc, false, null); })); b.addEventListener('click', () => { $('bcEd').focus(); document.execCommand(b.dataset.bc, false, null); }));
document.querySelectorAll('[data-bcblock]').forEach(b => document.querySelectorAll('[data-bcblock]').forEach(b =>
b.addEventListener('click', () => { $('bcEd').focus(); document.execCommand('formatBlock', false, b.dataset.bcblock); })); b.addEventListener('click', () => { $('bcEd').focus(); document.execCommand('formatBlock', false, b.dataset.bcblock); }));
if ($('bcLinkBtn')) $('bcLinkBtn').addEventListener('click', () => { const u = prompt('Link URL (https://…)'); if (u) { $('bcEd').focus(); document.execCommand('createLink', false, u); } }); if ($('bcLinkBtn')) $('bcLinkBtn').addEventListener('click', async () => {
const sel = window.getSelection(); const range = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
const u = await IAP.ask({ title: 'Insert link', text: 'Link URL (https://…)', placeholder: 'https://', ok: 'Insert' });
if (u) { $('bcEd').focus(); if (range) { sel.removeAllRanges(); sel.addRange(range); } document.execCommand('createLink', false, u); }
});
if ($('bcSendBtn')) $('bcSendBtn').addEventListener('click', busy2($('bcSendBtn'), async () => { if ($('bcSendBtn')) $('bcSendBtn').addEventListener('click', busy2($('bcSendBtn'), async () => {
const r = await api('/api/my/broadcast', { scope: $('bcScope').value, subject: $('bcSubject').value, body: $('bcEd').innerHTML }); const r = await api('/api/my/broadcast', { scope: $('bcScope').value, subject: $('bcSubject').value, body: $('bcEd').innerHTML });
IAP.status('Broadcast sent to ' + r.sent + ' member' + (r.sent === 1 ? '' : 's') + '.', 'ok'); IAP.status('Broadcast sent to ' + r.sent + ' member' + (r.sent === 1 ? '' : 's') + '.', 'ok');
@@ -1537,7 +1542,7 @@
$('buyFromWrap').hidden = !list.length; $('buyFromWrap').hidden = !list.length;
} }
document.querySelectorAll('[data-unlink]').forEach(b => b.addEventListener('click', async () => { document.querySelectorAll('[data-unlink]').forEach(b => b.addEventListener('click', async () => {
if (!confirm('Unlink ' + short(b.dataset.unlink) + ' from your account?')) return; if (!(await IAP.confirmBox('Unlink ' + short(b.dataset.unlink) + ' from your account?', { title: 'Unlink position', ok: 'Unlink' }))) return;
try { await api('/api/my/positions/remove', { address: b.dataset.unlink }); IAP.status('Position unlinked.', 'ok'); loadPositions(); } try { await api('/api/my/positions/remove', { address: b.dataset.unlink }); IAP.status('Position unlinked.', 'ok'); loadPositions(); }
catch (e) { IAP.status(e.message, 'bad'); } catch (e) { IAP.status(e.message, 'bad'); }
})); }));
@@ -1547,7 +1552,7 @@
const me = await (await fetch('/api/me')).json(); const me = await (await fetch('/api/me')).json();
if (!me.address) throw new Error('Link your main wallet first (Wallet tab), then add positions under it.'); if (!me.address) throw new Error('Link your main wallet first (Wallet tab), then add positions under it.');
if (!me.memberId) throw new Error('Switch on payouts for your main wallet first (Wallet tab). Positions register under your member number.'); if (!me.memberId) throw new Error('Switch on payouts for your main wallet first (Wallet tab). Positions register under your member number.');
if (!confirm('Your wallet will ask which account to connect. Tick ONLY the new account (not ' + short(me.address) + '), then sign once.\n\nIf you have not created the extra account yet: MetaMask, account menu, Add account. Trust or SafePal: switch wallet.\n\nReady?')) return; if (!(await IAP.confirmBox('Your wallet will ask which account to connect. Tick ONLY the new account (not ' + short(me.address) + '), then sign once.\n\nIf you have not created the extra account yet: MetaMask, account menu, Add account. Trust or SafePal: switch wallet.\n\nReady?', { title: 'Add a position', ok: 'Ready' }))) return;
IAP.status('Pick the new account in your wallet, then sign once…'); IAP.status('Pick the new account in your wallet, then sign once…');
const r = await IAPWallet.signIn({ asPosition: true, pick: true }); const r = await IAPWallet.signIn({ asPosition: true, pick: true });
$('qsHint').textContent = 'Added ' + short(r.address) + '. Now choose it under "Buy from" and buy a $20 or larger package.'; $('qsHint').textContent = 'Added ' + short(r.address) + '. Now choose it under "Buy from" and buy a $20 or larger package.';
@@ -1617,7 +1622,7 @@
} }
const pct = Number(need * 100n / bal); const pct = Number(need * 100n / bal);
const isTrust = /trust/i.test(IAPWallet.walletName() || ''); const isTrust = /trust/i.test(IAPWallet.walletName() || '');
if (isTrust && pct > 55 && !confirm('Heads up for Trust Wallet users: this purchase uses about ' + pct + '% of the POL in your wallet, and Trust Wallet refuses transactions that spend most of the balance (it shows a "drain your wallet" warning with only Stop and go back).' + '\n\n' + 'Options: pick a smaller package first, add some POL, or connect a different wallet (MetaMask, Phantom, SafePal). Extra POL always stays yours.' + '\n\n' + 'Try it anyway?')) { if (isTrust && pct > 55 && !(await IAP.confirmBox('Heads up for Trust Wallet users: this purchase uses about ' + pct + '% of the POL in your wallet, and Trust Wallet refuses transactions that spend most of the balance (it shows a "drain your wallet" warning with only Stop and go back).' + '\n\n' + 'Options: pick a smaller package first, add some POL, or connect a different wallet (MetaMask, Phantom, SafePal). Extra POL always stays yours.' + '\n\n' + 'Try it anyway?', { title: 'Trust Wallet check', ok: 'Buy anyway', cancel: 'Pause' }))) {
IAP.status('Purchase paused. Pick a smaller package, add POL, or connect another wallet, then try again.', 'ok'); IAP.status('Purchase paused. Pick a smaller package, add POL, or connect another wallet, then try again.', 'ok');
return; return;
} }
+1 -1
View File
@@ -141,7 +141,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/contract.js?v=20260908p"></script> <script src="/assets/contract.js?v=20260908p"></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
</body> </body>
+1 -1
View File
@@ -26,7 +26,7 @@
<p class="muted small">You decide whether, and how much, to spend. Never spend more than you can afford to lose.</p> <p class="muted small">You decide whether, and how much, to spend. Never spend more than you can afford to lose.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -461,7 +461,7 @@
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/wallet.js?v=20260909c"></script> <script src="/assets/wallet.js?v=20260909c"></script>
<script src="/assets/home.js?v=20260906m"></script> <script src="/assets/home.js?v=20260906m"></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
+1 -1
View File
@@ -155,7 +155,7 @@
InstantAdPay · <a href="/contract">Contract</a> · <a href="/terms">Terms</a> · <a href="/privacy">Privacy</a> · <a href="/disclaimer">Disclaimer</a> InstantAdPay · <a href="/contract">Contract</a> · <a href="/terms">Terms</a> · <a href="/privacy">Privacy</a> · <a href="/disclaimer">Disclaimer</a>
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260911c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/join.js?v=20260912a"></script> <script src="/assets/join.js?v=20260912a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -85,7 +85,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260911c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/launch.js?v=20260911b"></script> <script src="/assets/launch.js?v=20260911b"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -37,7 +37,7 @@
<div>InstantAdPay · <a href="/">how it works</a> · <a id="contractLink" href="#" target="_blank" rel="noopener">contract source ↗</a></div> <div>InstantAdPay · <a href="/">how it works</a> · <a id="contractLink" href="#" target="_blank" rel="noopener">contract source ↗</a></div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/ledger.js?v=20260906m"></script> <script src="/assets/ledger.js?v=20260906m"></script>
<script src="/assets/chat.js?v=20260906m"></script> <script src="/assets/chat.js?v=20260906m"></script>
</body> </body>
+2 -2
View File
@@ -908,10 +908,10 @@
</div> </div>
</div> </div>
</div> </div>
<script src="/assets/common.js?v=20260911c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/wallet.js?v=20260911a"></script> <script src="/assets/wallet.js?v=20260911a"></script>
<script src="/assets/promo.js?v=20260911a"></script> <script src="/assets/promo.js?v=20260911a"></script>
<script src="/assets/my.js?v=20260912a"></script> <script src="/assets/my.js?v=20260912b"></script>
<script src="/assets/chat.js?v=20260907l"></script> <script src="/assets/chat.js?v=20260907l"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -192,7 +192,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never spend what you cannot afford.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260911c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/plays.js?v=20260910b"></script> <script src="/assets/plays.js?v=20260910b"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -28,7 +28,7 @@
<p class="muted small">We use reasonable safeguards, but no system is perfectly secure. Protect your email and your wallet.</p> <p class="muted small">We use reasonable safeguards, but no system is perfectly secure. Protect your email and your wallet.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -36,7 +36,7 @@
<p class="muted small" style="margin-top:18px">See also the <a href="/disclaimer">Disclaimer</a> and <a href="/privacy">Privacy Policy</a>.</p> <p class="muted small" style="margin-top:18px">See also the <a href="/disclaimer">Disclaimer</a> and <a href="/privacy">Privacy Policy</a>.</p>
</div> </div>
</div></section> </div></section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/legal.js?v=20260908a"></script> <script src="/assets/legal.js?v=20260908a"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -34,7 +34,7 @@
<p><a href="/ledger">← Back to the live ledger</a> · <a href="/contract">Read the contract review</a></p> <p><a href="/ledger">← Back to the live ledger</a> · <a href="/contract">Read the contract review</a></p>
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/tx.js?v=20260906m"></script> <script src="/assets/tx.js?v=20260906m"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -47,7 +47,7 @@
</div> </div>
</div> </div>
</section> </section>
<script src="/assets/common.js?v=20260910c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/wall.js?v=20260911v"></script> <script src="/assets/wall.js?v=20260911v"></script>
</body> </body>
</html> </html>
+1 -1
View File
@@ -121,7 +121,7 @@
<div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never share your recovery phrase.</div> <div class="small">Advertising services with a performance referral program. Not an investment product; no income guarantees. Crypto transactions are irreversible. Never share your recovery phrase.</div>
</footer> </footer>
</div> </div>
<script src="/assets/common.js?v=20260911c"></script> <script src="/assets/common.js?v=20260912b"></script>
<script src="/assets/wallets.js?v=20260911b"></script> <script src="/assets/wallets.js?v=20260911b"></script>
</body> </body>
</html> </html>