diff --git a/check_loginads.mjs b/check_loginads.mjs
new file mode 100644
index 0000000..7b15d7b
--- /dev/null
+++ b/check_loginads.mjs
@@ -0,0 +1,18 @@
+import pkg from 'file:///D:/Projects/MarketingAgent/qa-tester/node_modules/playwright/index.js';
+const { chromium } = pkg;
+const b = await chromium.connectOverCDP('http://127.0.0.1:9222');
+const page = await b.contexts()[0].newPage();
+await page.setViewportSize({ width: 1500, height: 1000 });
+await page.goto('https://www.adrevsplit.com/aradmin/admin.php?b=4411', { waitUntil:'domcontentloaded', timeout:45000 });
+await page.waitForTimeout(2500);
+const r = await page.evaluate(() => {
+ const rows = [...document.querySelectorAll('table tr')].map(tr =>
+ [...tr.querySelectorAll('td,th')].map(td => td.innerText.replace(/\s+/g,' ').trim()));
+ const links = [...document.querySelectorAll('a[href*="rmcircle"], a[href*="join"]')].map(a=>a.getAttribute('href'));
+ return { rows: rows.filter(r2=>r2.length>3).slice(0,14), links: [...new Set(links)] };
+});
+console.log('=== approved login ads ===');
+r.rows.forEach(x => console.log(' ' + x.join(' | ').slice(0,150)));
+console.log('\n=== destination links found ===');
+r.links.forEach(l => console.log(' ' + l));
+await page.close(); await b.close();
diff --git a/gaps.mjs b/gaps.mjs
new file mode 100644
index 0000000..97bce0a
--- /dev/null
+++ b/gaps.mjs
@@ -0,0 +1,28 @@
+import pkg from 'file:///D:/Projects/MarketingAgent/qa-tester/node_modules/playwright/index.js';
+const { chromium } = pkg;
+const b = await chromium.connectOverCDP('http://127.0.0.1:9222');
+const page = await b.contexts()[0].newPage();
+await page.setViewportSize({ width: 1340, height: 1000 });
+await page.goto('https://adrevsplit.com/login.php', { waitUntil:'domcontentloaded', timeout:45000 });
+await page.waitForTimeout(3000);
+console.log(JSON.stringify(await page.evaluate(() => {
+ const col = document.querySelector('.col-lg-10, .custom-col-10');
+ const out = { colTop: col ? Math.round(col.getBoundingClientRect().top) : null, children: [] };
+ if (col) for (const c of col.children) {
+ if (c.getBoundingClientRect().height === 0) continue;
+ const r = c.getBoundingClientRect(); const cs = getComputedStyle(c);
+ out.children.push({
+ tag: c.tagName, cls: (c.className||'').toString().slice(0,30),
+ top: Math.round(r.top), h: Math.round(r.height),
+ mt: cs.marginTop, mb: cs.marginBottom,
+ text: (c.innerText||'').replace(/\s+/g,' ').trim().slice(0,40)
+ });
+ }
+ const ul = document.querySelector('.flexy-menu');
+ out.menuTop = ul ? Math.round(ul.getBoundingClientRect().top) : null;
+ const sec = document.querySelector('section.container');
+ out.sectionTop = sec ? Math.round(sec.getBoundingClientRect().top) : null;
+ out.sectionPadTop = sec ? getComputedStyle(sec).paddingTop : null;
+ return out;
+}, null), null, 1));
+await b.close();
diff --git a/public/my.js b/public/my.js
index 963fb27..0b2476b 100644
--- a/public/my.js
+++ b/public/my.js
@@ -399,7 +399,18 @@
// One-tap nudges: pre-written message per coach recommendation, sent over
// the wallet-verified Messages rails (and bridged to Telegram if linked).
const nudgeTexts={};
- function nudgeBtn(key){return `
`}
+ // Nudges used to send silently with only a "Delivered" note, so nobody could
+ // see WHAT went out or to whom. A member went hunting in her clipboard, found
+ // the unrelated "copy my summary" text still sitting there, and reasonably
+ // concluded the nudge had sent her own position instead of the recipient's.
+ // Preview before, and the exact sent text after, removes the guesswork.
+ function nudgeBtn(key){return `