a57af32f4a
Once every member from Ascensus up could hold several pages, the Funnel Factory's differentiator became a count — the same quantity-not-kind flaw the upper tiers had. L6 now unlocks identity instead: a member's own name, monogram and accent colour on every page they build. Below Fastigium you have a page on the team site; at Fastigium it becomes yours. Three deliberate limits. NO IMAGE UPLOADS. A logo file uploaded by a member and served from rmcircle.team is an abuse surface — whatever they upload lives on our domain. The mark is a monogram generated from their brand name instead: real identity, nothing to moderate. Same reasoning that keeps Traffic Desk creative team-only. ACCENTS ARE A CURATED SET, not a colour picker. Every option is checked against the dark ground, so nobody can pick something that makes their own page unreadable and then wonder why it converts badly. THE DISCLAIMERS ARE NOT THEIRS TO BRAND. Branding replaces the header identity only; the footer — independent team resource, no income guaranteed, cryptocurrency risk — is rendered by us and cannot be removed or restyled. Co-branding, not white-labelling. Verified in the renderer. Branding is resolved against the LIVE contract level at render time, so a position that drops below Fastigium reverts to team identity on its own rather than keeping something it no longer holds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
3.3 KiB
JavaScript
67 lines
3.3 KiB
JavaScript
// One source of truth for "what does this level unlock in the Circle Suite",
|
|
// shared by the Telegram feeds, the X/Twitter payout posts, and anywhere else
|
|
// that congratulates an upgrade.
|
|
//
|
|
// Two honesty rules baked in:
|
|
// 1. `live:false` tiers are NEVER announced. We do not congratulate someone
|
|
// for unlocking software that does not exist yet.
|
|
// 2. The whole feature is gated on config.suiteToolsInAlerts, so nothing goes
|
|
// public while the Suite is still in team beta. Flip it on at launch.
|
|
'use strict';
|
|
|
|
const LEVEL_TOOLS = {
|
|
1: { name: 'Scintilla', live: true, short: 'the Launch Kit and the Traffic Desk — promo center, printable handouts with your QR, the Circle Method course, your dashboard, the AI coach, and banners or text ads on our own ad network' },
|
|
2: { name: 'Ascensus', live: true, short: 'the Copy Engine and Page Builder — an AI copywriter for your posts and DMs, plus your own hosted invitation page' },
|
|
3: { name: 'Fabrica', live: true, short: 'the Email Engine and Video Maker — full sequences in the team voice, and the promo videos rendered with your own end card' },
|
|
4: { name: 'Culmen', live: true, short: 'your Voice Profile — the Copy Engine and Email Engine start writing the way you actually talk' },
|
|
5: { name: 'Apex', live: true, short: 'the Split Tester, and your ad allowance jumps to 50,000 impressions a month' },
|
|
6: { name: 'Fastigium', live: true, short: 'Co-Branded Pages and the Funnel Factory — your own name, monogram and colour on every page you build' },
|
|
7: { name: 'Vertex', live: true, short: 'Leader Ops and Team Grants — your whole organisation triaged live from the contract, plus the ability to hand Suite capacity down to your own people' },
|
|
8: { name: 'Corona', live: true, short: 'the Founder Desk and Network Intelligence — a whole week of promotion in one pass, API access, and what is actually working across every ad the team runs' }
|
|
};
|
|
|
|
// Very short form for character-limited surfaces (X/Twitter).
|
|
const TERSE = {
|
|
1: 'the Launch Kit + Traffic Desk',
|
|
2: 'the Copy Engine + Page Builder',
|
|
3: 'the Email Engine + Video Maker',
|
|
4: 'your own Voice Profile',
|
|
5: 'the Split Tester + 50k impressions',
|
|
6: 'Co-Branded Pages',
|
|
7: 'Leader Ops + Team Grants',
|
|
8: 'the Founder Desk + Network Intelligence'
|
|
};
|
|
|
|
function levelNumber(level, levelName) {
|
|
const n = Number(level);
|
|
if (n >= 1 && n <= 8) return n;
|
|
if (levelName) {
|
|
for (const k of Object.keys(LEVEL_TOOLS)) {
|
|
if (LEVEL_TOOLS[k].name.toLowerCase() === String(levelName).toLowerCase()) return Number(k);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function enabled(cfg) { return !!(cfg && cfg.suiteToolsInAlerts); }
|
|
|
|
// Full sentence fragment, or '' when we shouldn't say anything.
|
|
function unlockText(level, levelName, cfg) {
|
|
if (!enabled(cfg)) return '';
|
|
const n = levelNumber(level, levelName);
|
|
const t = LEVEL_TOOLS[n];
|
|
if (!t || !t.live) return '';
|
|
return t.short;
|
|
}
|
|
|
|
// Terse form for tweets, or '' when we shouldn't say anything.
|
|
function unlockTerse(level, levelName, cfg) {
|
|
if (!enabled(cfg)) return '';
|
|
const n = levelNumber(level, levelName);
|
|
const t = LEVEL_TOOLS[n];
|
|
if (!t || !t.live) return '';
|
|
return TERSE[n] || '';
|
|
}
|
|
|
|
module.exports = { LEVEL_TOOLS, unlockText, unlockTerse, levelNumber, enabled };
|