From 086e64b3f69662e76329da2f97e2e974db509810 Mon Sep 17 00:00:00 2001 From: martbost Date: Sat, 15 Aug 2026 10:52:43 -0500 Subject: [PATCH] Add home-page "Still have doubts?" trust band + fix CSP blocking inline styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Home page: new reassurance band between the live payment feed and the final CTA — surfaces the three doubts (rules can't change, money never sits in the contract, keeps running if creators vanish) and routes skeptics to /contract. CSP fix (the real find): style-src was 'self' with no 'unsafe-inline', so the browser was silently dropping EVERY inline style="" attribute site-wide — the attribute stayed in the DOM but never applied. This is why the earlier margin fix only worked once moved to a class, and why the new card rendered left-aligned with a teal eyebrow. Added 'unsafe-inline' to style-src only (script-src stays locked to 'self'). Verified via computed styles + full-page screenshots: home, /contract, /how-pay-works now render as authored. Co-Authored-By: Claude Fable 5 --- _diag3.mjs | 15 +++++++++++++++ public/index.html | 2 ++ server.js | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 _diag3.mjs diff --git a/_diag3.mjs b/_diag3.mjs new file mode 100644 index 0000000..7a96e7b --- /dev/null +++ b/_diag3.mjs @@ -0,0 +1,15 @@ +import { chromium } from 'playwright'; +const b = await chromium.launch(); +const p = await b.newPage({ viewport: { width: 1200, height: 900 } }); +await p.goto('http://localhost:3107/?t=' + Math.floor(Math.random()*1e9), { waitUntil: 'networkidle' }); +const mine = p.locator('.card', { hasText: 'you should ask hard questions' }).first(); +const r = await mine.evaluate(el => ({ + inlineTextAlign: el.style.textAlign, + inlinePadding: el.style.padding, + inlineBorderColor: el.style.borderColor, + cssTextLen: el.style.cssText.length, + cssText: el.style.cssText, + computed: getComputedStyle(el).textAlign, +})); +console.log(JSON.stringify(r, null, 2)); +await b.close(); diff --git a/public/index.html b/public/index.html index 4e9fe1f..8591a64 100644 --- a/public/index.html +++ b/public/index.html @@ -17,6 +17,8 @@
Moving-link workflow

Qualify. Then the effort moves down.

Step 1Use link

Share the current position's referral link.

Step 2Get 2

Place exactly two direct positions.

Step 3Retire link

Late signups still spill down — bonus depth, not a problem.

Step 4Help your 2

Shift the team effort to their links.

Step 5Repeat

Keep the qualification wave moving down.

Depth over width

2 → 4 → 8 → 16 → 32 → 64 → 128 → 256

Each generation doubles. A full eight-generation team is 510 positions (2+4+8+16+32+64+128+256) — but the first milestone that matters is the 30 positions in your first four generations: 2 + 4 + 8 + 16.

2
4
8
16
32
64
128
256
Team principle: once your two are in place, retire your link and shift to helping them get their two — their own directs are the only thing that qualifies their positions to catch payments. And if an extra signup comes through your link anyway, it's a bonus, not a problem: it still pays your position the entry reward and spills downward to fill an open slot in your leg. Spillover never qualifies the people below, though — so the team effort always moves down.
Live payment proof

Real payouts, straight from the blockchain.

Every payment in this program happens on a public smart contract on Polygon — nobody can fake, hide, or edit it. Below are the latest member payouts, read live from the contract. Tap any row to verify the transaction yourself on Polygonscan.

Reading the blockchain…
Data is read directly from the RM Circle smart contract (0x33Bd…2DAF) on Polygon Mainnet. Member numbers are on-chain IDs, not names. Past payouts are not a promise of future results. How the contract works — and why the rules can't change →
+
Still have doubts?

Good — you should ask hard questions.

Before you risk anything, it's smart to ask: Can the rules change after I join? Can anyone take my money? What happens if the people who built this walk away? We read the complete, verified smart-contract code and answered every one of those — in plain language, with links so you can check each claim on the blockchain yourself.

The short version: the code can't be changed, member money never sits in the contract, and the whole thing keeps running on its own — even if its creators disappear.

See How the Contract Works →
+
Ready to start?

See the current team placement.

The onboarding page automatically shows the sponsor position the team is currently helping. Always use the sponsor shown there instead of an old screenshot or saved link.

Open Getting Started Instructions →
diff --git a/server.js b/server.js index 80dc7de..b1e7996 100644 --- a/server.js +++ b/server.js @@ -293,7 +293,7 @@ function publicSponsorPayload(sponsor, config) { if(!sponsor)return null; return {id:sponsor.id,name:config.showSponsorName?sponsor.name:null,directs:sponsor.directs,goal:2,level:sponsor.level,referralUrl:`${config.dappReferralBaseUrl}${encodeURIComponent(sponsor.id)}`}; } -const CSP_BASE="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; form-action 'self'; frame-src https://www.youtube-nocookie.com"; +const CSP_BASE="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; form-action 'self'; frame-src https://www.youtube-nocookie.com"; function securityHeaders(extra={}) { // Public pages must render inside safelist / traffic-exchange iframes, so framing stays open here; admin.html re-locks it via ADMIN_FRAME_HEADERS. return {