// Temporary, admin-controlled heads-up shown right above any wallet-connect // button while a scanner false-positive is being cleared. Driven by // config.walletNotice (admin PATCH): non-empty string = show it, ""/unset = // nothing renders. One config flip removes it everywhere, no deploy. (function () { 'use strict'; fetch('/api/public/config').then(function (r) { return r.json(); }).then(function (c) { var msg = (c && c.walletNotice || '').trim(); if (!msg) return; var placed = false; function attach() { if (placed) return true; // The training page has a connect/unlock button under EVERY gated video — // show the notice only ONCE (above the first one), never per-video. var btns = [].slice.call(document.querySelectorAll('button, a.btn')); var btn = btns.filter(function (b) { return /connect|unlock/i.test(b.textContent || ''); })[0]; if (!btn) return false; placed = true; var n = document.createElement('div'); n.className = 'callout'; n.style.cssText = 'margin:0 0 12px;font-size:13px;line-height:1.5;border-color:rgba(243,190,67,.5)'; n.innerHTML = 'â„šī¸ ' + msg; // admin-authored, same trust level as other config-injected copy btn.parentNode.insertBefore(n, btn); return true; } if (attach()) return; // Connect/unlock buttons on /my and /training are injected AFTER async data // loads — watch the DOM until the first one appears, then stop. if (window.MutationObserver) { var mo = new MutationObserver(function () { if (attach()) mo.disconnect(); }); mo.observe(document.body, { childList: true, subtree: true }); setTimeout(function () { mo.disconnect(); }, 12000); } else { var t = 0, iv = setInterval(function () { if (attach() || ++t > 12) clearInterval(iv); }, 800); } }).catch(function () {}); })();