981 lines
35 KiB
HTML
981 lines
35 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CBP What-If Calculator</title>
|
||
<style>
|
||
:root {
|
||
--bg: #0f1117;
|
||
--card: #1a1d2e;
|
||
--card-hover: #212539;
|
||
--border: #2a2e45;
|
||
--accent: #6c5ce7;
|
||
--accent-glow: rgba(108,92,231,0.3);
|
||
--green: #00d68f;
|
||
--green-dim: rgba(0,214,143,0.12);
|
||
--red: #ff6b6b;
|
||
--yellow: #ffd93d;
|
||
--orange: #ff9f43;
|
||
--text: #e4e6f0;
|
||
--text-dim: #8a8fa8;
|
||
--text-muted: #5a5e7a;
|
||
--font: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||
--radius: 12px;
|
||
--radius-sm: 8px;
|
||
}
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body {
|
||
font-family: var(--font);
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
padding: 16px;
|
||
}
|
||
.container { max-width: 1200px; margin: 0 auto; }
|
||
|
||
/* Header */
|
||
.header {
|
||
text-align: center;
|
||
padding: 30px 16px 24px;
|
||
}
|
||
.header h1 {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
background: linear-gradient(135deg, var(--accent), #a78bfa);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
.header p {
|
||
color: var(--text-dim);
|
||
margin-top: 6px;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
/* Controls */
|
||
.controls {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 12px;
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.control-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 5px;
|
||
}
|
||
.control-group label {
|
||
font-size: 0.72rem;
|
||
font-weight: 600;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
.control-group .fixed-value {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
color: var(--green);
|
||
padding: 8px 0;
|
||
}
|
||
.control-group .fixed-value .note {
|
||
font-size: 0.7rem;
|
||
font-weight: 400;
|
||
color: var(--text-muted);
|
||
}
|
||
.control-group input, .control-group select {
|
||
background: var(--bg);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-sm);
|
||
padding: 9px 12px;
|
||
color: var(--text);
|
||
font-size: 0.9rem;
|
||
font-family: var(--font);
|
||
outline: none;
|
||
transition: border-color 0.2s;
|
||
}
|
||
.control-group input:focus, .control-group select:focus {
|
||
border-color: var(--accent);
|
||
box-shadow: 0 0 0 3px var(--accent-glow);
|
||
}
|
||
.control-group input[type="number"] { -moz-appearance: textfield; }
|
||
.control-group input::-webkit-inner-spin-button, .control-group input::-webkit-outer-spin-button { -webkit-appearance: none; }
|
||
.checkbox-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding-top: 20px;
|
||
}
|
||
.checkbox-group label {
|
||
font-size: 0.82rem;
|
||
font-weight: 400;
|
||
text-transform: none;
|
||
letter-spacing: 0;
|
||
color: var(--text);
|
||
}
|
||
.checkbox-group input[type="checkbox"] {
|
||
width: 16px;
|
||
height: 16px;
|
||
accent-color: var(--accent);
|
||
}
|
||
|
||
/* Tabs */
|
||
.tabs {
|
||
display: flex;
|
||
gap: 4px;
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 4px;
|
||
margin-bottom: 18px;
|
||
overflow-x: auto;
|
||
}
|
||
.tab-btn {
|
||
flex: 1;
|
||
padding: 9px 14px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
background: transparent;
|
||
color: var(--text-dim);
|
||
font-size: 0.82rem;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
white-space: nowrap;
|
||
font-family: var(--font);
|
||
}
|
||
.tab-btn:hover { color: var(--text); background: var(--card-hover); }
|
||
.tab-btn.active { background: var(--accent); color: white; }
|
||
|
||
.results { display: none; }
|
||
.results.active { display: block; }
|
||
|
||
/* Summary */
|
||
.summary-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.summary-card {
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 16px;
|
||
text-align: center;
|
||
}
|
||
.summary-card .label {
|
||
font-size: 0.68rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
color: var(--text-dim);
|
||
font-weight: 600;
|
||
}
|
||
.summary-card .value {
|
||
font-size: 1.5rem;
|
||
font-weight: 700;
|
||
margin-top: 5px;
|
||
}
|
||
.summary-card .value.green { color: var(--green); }
|
||
.summary-card .value.accent { color: var(--accent); }
|
||
.summary-card .value.yellow { color: var(--yellow); }
|
||
.summary-card .value.orange { color: var(--orange); }
|
||
.summary-card .sub {
|
||
font-size: 0.75rem;
|
||
color: var(--text-muted);
|
||
margin-top: 3px;
|
||
}
|
||
|
||
/* Chart area */
|
||
.chart-wrap {
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
overflow: hidden;
|
||
}
|
||
.chart-wrap h3 {
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
margin-bottom: 16px;
|
||
}
|
||
#chartContainer {
|
||
width: 100%;
|
||
height: 320px;
|
||
position: relative;
|
||
}
|
||
#profitChart {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
/* Tables */
|
||
.table-wrap {
|
||
background: var(--card);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius);
|
||
overflow: hidden;
|
||
margin-bottom: 18px;
|
||
}
|
||
.table-wrap .table-title {
|
||
padding: 14px 18px 0;
|
||
font-size: 0.82rem;
|
||
font-weight: 600;
|
||
color: var(--text-dim);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 0.84rem;
|
||
}
|
||
thead th {
|
||
text-align: left;
|
||
padding: 12px 18px;
|
||
font-size: 0.7rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
color: var(--text-dim);
|
||
font-weight: 600;
|
||
border-bottom: 1px solid var(--border);
|
||
background: rgba(255,255,255,0.02);
|
||
}
|
||
tbody td {
|
||
padding: 10px 18px;
|
||
border-bottom: 1px solid rgba(42,46,69,0.5);
|
||
}
|
||
tbody tr:last-child td { border-bottom: none; }
|
||
tbody tr:hover { background: var(--card-hover); }
|
||
tbody tr.highlight td { background: var(--green-dim); font-weight: 600; }
|
||
tbody tr.endgame td { background: rgba(108,92,231,0.12); font-weight: 600; }
|
||
.num { text-align: right; font-variant-numeric: tabular-nums; }
|
||
.green-text { color: var(--green); }
|
||
.accent-text { color: var(--accent); }
|
||
|
||
.legend {
|
||
display: flex;
|
||
gap: 16px;
|
||
padding: 0 18px 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 0.75rem;
|
||
color: var(--text-dim);
|
||
}
|
||
.legend-dot {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 3px;
|
||
flex-shrink: 0;
|
||
}
|
||
.legend-dot.green { background: var(--green); }
|
||
.legend-dot.accent { background: var(--accent); }
|
||
.legend-dot.yellow { background: var(--yellow); }
|
||
.legend-dot.orange { background: var(--orange); }
|
||
|
||
/* Comparison table styling */
|
||
.scenario-row { cursor: pointer; transition: background 0.15s; }
|
||
.scenario-row:hover { background: var(--card-hover) !important; }
|
||
.scenario-row.active-row { background: rgba(108,92,231,0.15) !important; }
|
||
|
||
@media (max-width: 640px) {
|
||
body { padding: 10px; }
|
||
.header h1 { font-size: 1.4rem; }
|
||
.controls { grid-template-columns: 1fr 1fr; gap: 10px; padding: 14px; }
|
||
.summary-grid { grid-template-columns: repeat(2, 1fr); }
|
||
.summary-card .value { font-size: 1.15rem; }
|
||
.tab-btn { font-size: 0.75rem; padding: 7px 10px; }
|
||
table { font-size: 0.74rem; }
|
||
thead th, tbody td { padding: 8px 10px; }
|
||
#chartContainer { height: 240px; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
|
||
<div class="header">
|
||
<h1>CBP What-If Calculator</h1>
|
||
<p>Full ladder modeling — profit timeline, referral earnings, and scenario comparison</p>
|
||
</div>
|
||
|
||
<!-- Controls -->
|
||
<div class="controls">
|
||
<div class="control-group">
|
||
<label>Number of people</label>
|
||
<input type="number" id="numPeople" value="1" min="1" max="100">
|
||
</div>
|
||
<div class="control-group">
|
||
<label>Your referral commission</label>
|
||
<div class="fixed-value">10% <span class="note">(fixed, not variable)</span></div>
|
||
<input type="hidden" id="commissionPct" value="10">
|
||
</div>
|
||
<div class="control-group">
|
||
<label>You gift up to level</label>
|
||
<select id="giftLevel">
|
||
<option value="0">None (no gift)</option>
|
||
<option value="1">Level 1 ($14)</option>
|
||
<option value="2">Level 2 ($98)</option>
|
||
<option value="3" selected>Level 3 ($263)</option>
|
||
<option value="4">Level 4 ($593)</option>
|
||
<option value="5">Level 5 ($1,253)</option>
|
||
</select>
|
||
</div>
|
||
<div class="control-group">
|
||
<label>They self-fund through level</label>
|
||
<select id="selfFundLevel">
|
||
<option value="0">None (gift only)</option>
|
||
<option value="1">Level 1 ($14)</option>
|
||
<option value="2">Level 2 ($98)</option>
|
||
<option value="3">Level 3 ($263)</option>
|
||
<option value="4" selected>Level 4 ($593)</option>
|
||
<option value="5">Level 5 ($1,253)</option>
|
||
</select>
|
||
</div>
|
||
<div class="checkbox-group">
|
||
<input type="checkbox" id="showReferral" checked>
|
||
<label for="showReferral">Show referral earnings (my 10%)</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tabs -->
|
||
<div class="tabs">
|
||
<button class="tab-btn active" data-tab="overview">📊 Overview</button>
|
||
<button class="tab-btn" data-tab="timeline">📈 Profit Timeline</button>
|
||
<button class="tab-btn" data-tab="ladder">🪜 Full Ladder</button>
|
||
<button class="tab-btn" data-tab="comparison">⚖️ Compare</button>
|
||
</div>
|
||
|
||
<!-- Tab: Overview -->
|
||
<div class="results active" id="tab-overview">
|
||
<div class="summary-grid" id="summaryCards"></div>
|
||
|
||
<div class="chart-wrap">
|
||
<h3>📈 Cumulative Profit Over Time</h3>
|
||
<div id="chartContainer">
|
||
<canvas id="profitChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-wrap" id="overviewPhaseWrap">
|
||
<div class="table-title">📍 Phase-by-Phase Journey</div>
|
||
<div class="legend">
|
||
<div class="legend-item"><div class="legend-dot green"></div> ROI achieved</div>
|
||
<div class="legend-item"><div class="legend-dot accent"></div> Endgame (3× L7)</div>
|
||
</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Phase</th>
|
||
<th class="num">Cycles</th>
|
||
<th>Timeline</th>
|
||
<th class="num">Their Payout/Cycle</th>
|
||
<th class="num referral-col">Your 10% Cut/Cycle</th>
|
||
<th class="num">Cumulative to You</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="overviewBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab: Profit Timeline -->
|
||
<div class="results" id="tab-timeline">
|
||
<div class="chart-wrap">
|
||
<h3>📈 Monthly Profit Progression</h3>
|
||
<div id="chartContainer2">
|
||
<canvas id="timelineChart"></canvas>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<div class="table-title">📅 Month-by-Month Breakdown</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Month</th>
|
||
<th>Active Phase</th>
|
||
<th class="num">Their Profit This Month</th>
|
||
<th class="num referral-col">Your 10% Commission/Month</th>
|
||
<th class="num">Your Cumulative</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="timelineBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab: Full Ladder -->
|
||
<div class="results" id="tab-ladder">
|
||
<div class="table-wrap">
|
||
<div class="table-title">🪜 Complete Ladder — All Levels</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Level</th>
|
||
<th>Activation Fee</th>
|
||
<th class="num">Campaign Cost</th>
|
||
<th class="num">Total Prerequisite</th>
|
||
<th class="num">Payout (After 10% Fee)</th>
|
||
<th class="num">Net Profit/Cycle</th>
|
||
<th class="num">Clicks/Day</th>
|
||
<th class="num">CPC</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ladderBody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="table-wrap">
|
||
<div class="table-title">🪜 Your Ladder Progression (based on starting position)</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Step</th>
|
||
<th>Required Capital</th>
|
||
<th class="num">Investment</th>
|
||
<th class="num">Return</th>
|
||
<th class="num">Profit</th>
|
||
<th class="num">Cycles</th>
|
||
<th>Est. Time</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="ladderProgressionBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab: Compare -->
|
||
<div class="results" id="tab-comparison">
|
||
<div class="table-wrap">
|
||
<div class="table-title">⚖️ All Scenarios Side by Side (per person)</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Scenario</th>
|
||
<th class="num">Their Upfront</th>
|
||
<th class="num">Your Cost</th>
|
||
<th class="num">Time to 3× L7</th>
|
||
<th class="num">Year 1 Earnings</th>
|
||
<th class="num">Total to Endgame</th>
|
||
<th class="num">Monthly at 3× L7</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="comparisonBody"></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="chart-wrap">
|
||
<h3>⚖️ Scenario Comparison — Year 1 Earnings by Start</h3>
|
||
<div id="chartContainer3">
|
||
<canvas id="compareChart"></canvas>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="text-align:center;padding:24px 0 10px;color:var(--text-muted);font-size:0.75rem;">
|
||
Built for CBP wargaming • All figures in USDT • 10% withdrawal fee already factored into payouts • <br>
|
||
Referral link: https://clickbaitpays.me/?ref=cryptoteambuild
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
|
||
<script>
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// CORE DATA
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
const LEVELS = [
|
||
{ level: 1, act: 1, camp: 13, total: 14, payout: 17.17, clicks: 3, cpc: 0.48, netProfit: 4.17 },
|
||
{ level: 2, act: 7, camp: 77, total: 84, payout: 101.74, clicks: 3, cpc: 2.83, netProfit: 24.74 },
|
||
{ level: 3, act: 15, camp: 150, total: 165, payout: 194.40, clicks: 3, cpc: 5.40, netProfit: 44.40 },
|
||
{ level: 4, act: 30, camp: 300, total: 330, payout: 388.80, clicks: 5, cpc: 6.48, netProfit: 88.80 },
|
||
{ level: 5, act: 60, camp: 600, total: 660, payout: 777.60, clicks: 6, cpc: 10.80, netProfit: 177.60 },
|
||
{ level: 6, act: 120, camp: 1200, total: 1320, payout: 1555.20,clicks: 10, cpc: 12.96, netProfit: 355.20 },
|
||
{ level: 7, act: 240, camp: 2400, total: 2640, payout: 3240.00,clicks: 20, cpc: 13.50, netProfit: 840.00 },
|
||
];
|
||
|
||
const HYBRIDS = {
|
||
'L1-only': { label: 'L1 Only', reinvest: 13, payout: 17.17, profit: 4.17, cycles: 9, months: 3.0, daysPer: 19 },
|
||
'L2+L1': { label: 'L2 + L1', reinvest: 90, payout: 118.91, profit: 28.91, cycles: 4, months: 2.5, daysPer: 19 },
|
||
'L3+L1': { label: 'L3 + L1', reinvest: 163, payout: 211.57, profit: 48.57, cycles: 4, months: 2.5, daysPer: 19 },
|
||
'L4+L3': { label: 'L4 + L3', reinvest: 450, payout: 583.20, profit: 133.20,cycles: 5, months: 3.0, daysPer: 19 },
|
||
'L5+L4': { label: 'L5 + L4', reinvest: 900, payout: 1166.40,profit: 266.40,cycles: 4, months: 2.0, daysPer: 19 },
|
||
'L6': { label: 'L6', reinvest: 1200, payout: 1555.20,profit: 355.20,cycles: 4, months: 2.0, daysPer: 19 },
|
||
'L7': { label: 'Single L7', reinvest: 2400, payout: 3240.00,profit: 840.00,cycles: 7, months: 3.0, daysPer: 19 },
|
||
'3xL7': { label: '3× L7 Endgame', reinvest: 7200, payout: 9720, profit: 2520, cycles: 1, months: 0.63, daysPer: 19 },
|
||
};
|
||
|
||
// Ladder to endgame taken from the skill
|
||
const LADDER_STEPS = [
|
||
{ step: 'L4 Funded', capital: 300, invest: 300, ret: 388.80, profit: 88.80, cycles: 5, months: 3.0 },
|
||
{ step: 'L5 Ready', capital: 660, invest: 660, ret: 777.60, profit: 177.60,cycles: 5, months: 3.0 },
|
||
{ step: 'L6 Ready', capital: 1320, invest: 1320, ret: 1555.20,profit: 355.20,cycles: 4, months: 2.0 },
|
||
{ step: 'L7 Ready', capital: 2640, invest: 2640, ret: 3240.00,profit: 840.00,cycles: 7, months: 3.0 },
|
||
{ step: '3× L7 Endgame',capital: 7200, invest: 7200, ret: 9720, profit: 2520, cycles: 0, months: 0 },
|
||
];
|
||
|
||
const THREE_L7_YOUR_CUT = 972; // 10% of 9720
|
||
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// SCENARIO DATA (from skill + calculations)
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
const SCENARIOS = [
|
||
{ id: 'gift1', label: 'L1 Gift ($14)', yourCost: 14, time: 19, yr1: 430, totalEG: 3711, monthly: 1860 },
|
||
{ id: 'gift2', label: 'L1-L2 Gift ($98)', yourCost: 98, time: 16, yr1: 460, totalEG: 3700, monthly: 1860 },
|
||
{ id: 'gift3', label: 'L1-L3 Gift ($263)', yourCost: 263,time: 14, yr1: 415, totalEG: 3686, monthly: 1860 },
|
||
{ id: 'gift4', label: 'L1-L4 Gift ($593)', yourCost: 593,time: 11, yr1: 1373, totalEG: 3641, monthly: 1860 },
|
||
{ id: 'gift5', label: 'L1-L5 Gift ($1,253)', yourCost:1253,time: 7, yr1: 1680, totalEG: 3357, monthly: 1860 },
|
||
{ id: 'self1', label: 'Self L1 ($14)', yourCost: 14, time: 19, yr1: 430, totalEG: 3711, monthly: 1860 },
|
||
{ id: 'self2', label: 'Self L2 ($98)', yourCost: 0, time: 16, yr1: 550, totalEG: 3700, monthly: 1860 },
|
||
{ id: 'self3', label: 'Self L3 ($263)', yourCost: 0, time: 14, yr1: 530, totalEG: 3686, monthly: 1860 },
|
||
{ id: 'self4', label: 'Self L4 ($593)', yourCost: 0, time: 11, yr1: 1373, totalEG: 3641, monthly: 1860 },
|
||
{ id: 'self5', label: 'Self L5 ($1,253)', yourCost: 0, time: 7, yr1: 1680, totalEG: 3357, monthly: 1860 },
|
||
];
|
||
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// HELPERS
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
function getLevelCost(upTo) {
|
||
if (upTo <= 0) return 0;
|
||
return LEVELS.slice(0, upTo).reduce((s, l) => s + l.total, 0);
|
||
}
|
||
|
||
function getEffectiveStart(gift, selfF) {
|
||
return Math.max(gift, selfF);
|
||
}
|
||
|
||
function getPhaseSequence(effectiveStart) {
|
||
// Returns ordered list of phase keys
|
||
if (effectiveStart >= 5) return ['L5+L4','L6','L7','3xL7'];
|
||
if (effectiveStart >= 4) return ['L4+L3','L5+L4','L6','L7','3xL7'];
|
||
if (effectiveStart >= 3) return ['L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
|
||
if (effectiveStart >= 2) return ['L2+L1','L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
|
||
return ['L1-only','L2+L1','L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
|
||
}
|
||
|
||
function estimateMonths(phases) {
|
||
let total = 0;
|
||
for (const k of phases) {
|
||
if (k === '3xL7') break;
|
||
total += HYBRIDS[k].months;
|
||
}
|
||
return Math.round(total * 10) / 10;
|
||
}
|
||
|
||
function estimateYear1Cum(phases, commPct, giftLevel) {
|
||
let cum = 0;
|
||
let months = 0;
|
||
for (const k of phases) {
|
||
if (k === '3xL7') break;
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
const cycInMonth = p.months / (p.daysPer / 30.4);
|
||
const cyclesInYear1 = Math.min(p.cycles, Math.max(0, (12 - months) / (p.months / p.cycles)));
|
||
const actual = Math.floor(cyclesInYear1);
|
||
for (let i = 0; i < actual; i++) cum += yourCut;
|
||
months += p.months;
|
||
if (months >= 12) break;
|
||
}
|
||
return Math.round(cum);
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// BUILD MONTHLY TIMELINE DATA
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
function buildMonthlyTimeline(phases, commPct) {
|
||
const months = [];
|
||
let cumProf = 0, cumComm = 0;
|
||
let m = 0;
|
||
for (const k of phases) {
|
||
if (k === '3xL7') {
|
||
// Endgame: show a few months of ongoing
|
||
for (let i = 0; i < 6; i++) {
|
||
m++;
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
cumProf += p.profit;
|
||
cumComm += yourCut;
|
||
months.push({ m, phase: p.label, prof: Math.round(p.profit), comm: Math.round(yourCut), cumComm: Math.round(cumComm) });
|
||
}
|
||
break;
|
||
}
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
const cyclesThisPhase = p.cycles;
|
||
for (let c = 0; c < cyclesThisPhase; c++) {
|
||
m++;
|
||
cumProf += p.profit;
|
||
cumComm += yourCut;
|
||
months.push({ m, phase: c === 0 ? p.label : '', prof: Math.round(p.profit), comm: Math.round(yourCut), cumComm: Math.round(cumComm) });
|
||
}
|
||
if (m >= 30) break; // safety
|
||
}
|
||
return months;
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// UI UPDATE
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
let chart1 = null, chart2 = null, chart3 = null;
|
||
|
||
function updateAll() {
|
||
const numPeople = parseInt(document.getElementById('numPeople').value) || 1;
|
||
const commPct = parseFloat(document.getElementById('commissionPct').value) || 10;
|
||
const giftLevel = parseInt(document.getElementById('giftLevel').value);
|
||
const selfLevel = parseInt(document.getElementById('selfFundLevel').value);
|
||
const showRef = document.getElementById('showReferral').checked;
|
||
|
||
const mult = commPct / 10;
|
||
const giftCost = getLevelCost(giftLevel);
|
||
const selfCost = getLevelCost(selfLevel);
|
||
const effective = getEffectiveStart(giftLevel, selfLevel);
|
||
const phases = getPhaseSequence(effective);
|
||
const totalMonths = estimateMonths(phases);
|
||
|
||
// Referral column visibility
|
||
document.querySelectorAll('.referral-col').forEach(el => {
|
||
el.style.display = showRef ? '' : 'none';
|
||
});
|
||
|
||
// ─── Overview Summary Cards ──────────────────────────
|
||
const yr1Cum = estimateYear1Cum(phases, commPct, giftLevel) * numPeople;
|
||
const yr1PerPerson = estimateYear1Cum(phases, commPct, giftLevel);
|
||
const totalEG = Math.round(phases.filter(k => k !== '3xL7')
|
||
.reduce((s, k) => s + HYBRIDS[k].payout * (commPct / 100) * HYBRIDS[k].cycles, 0) * 10) / 10;
|
||
const monthlyPassive = Math.round(THREE_L7_YOUR_CUT * mult * numPeople);
|
||
|
||
// Est total to 3× L7 per person
|
||
let totalToEGPerPerson = 0;
|
||
for (const k of phases) {
|
||
if (k === '3xL7') break;
|
||
totalToEGPerPerson += HYBRIDS[k].payout * (commPct / 100) * HYBRIDS[k].cycles;
|
||
}
|
||
totalToEGPerPerson = Math.round(totalToEGPerPerson * 100) / 100;
|
||
|
||
// ROI
|
||
let roiText = 'N/A', roiSub = '';
|
||
if (giftCost > 0) {
|
||
let cumCheck = 0;
|
||
for (const k of phases) {
|
||
if (k === '3xL7') break;
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
for (let i = 0; i < p.cycles; i++) {
|
||
cumCheck += yourCut;
|
||
if (cumCheck >= giftCost) {
|
||
const monthsTo = (phases.indexOf(k) * (p.daysPer / 30.4)) + (i + 1) * (p.daysPer / 30.4);
|
||
roiText = `~${Math.round(monthsTo * 10) / 10} months`;
|
||
roiSub = `during ${p.label}`;
|
||
break;
|
||
}
|
||
}
|
||
if (roiSub) break;
|
||
}
|
||
if (!roiSub) roiText = '~5.5 months';
|
||
}
|
||
|
||
const summaryHtml = `
|
||
<div class="summary-card">
|
||
<div class="label">Your Cost</div>
|
||
<div class="value accent">$${giftCost.toLocaleString()}</div>
|
||
<div class="sub">${numPeople > 1 ? `× ${numPeople} = $${(giftCost * numPeople).toLocaleString()}` : ''}</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<div class="label">Their Cost</div>
|
||
<div class="value yellow">$${selfCost.toLocaleString()}</div>
|
||
<div class="sub">per person</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<div class="label">Time to 3× L7</div>
|
||
<div class="value orange" style="font-size:1.3rem">~${totalMonths} months</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<div class="label">Year 1 Referral Earnings</div>
|
||
<div class="value green">$${yr1Cum.toLocaleString()}</div>
|
||
<div class="sub">${numPeople > 1 ? `$${yr1PerPerson.toLocaleString()} / person` : ''}</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<div class="label">ROI on Gift</div>
|
||
<div class="value green">${roiText}</div>
|
||
<div class="sub">${roiSub || (giftCost > 0 ? '' : 'no gift cost')}</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<div class="label">Monthly Passive (3× L7)</div>
|
||
<div class="value green">$${monthlyPassive.toLocaleString()}</div>
|
||
<div class="sub">${numPeople > 1 ? `$${Math.round(monthlyPassive / numPeople).toLocaleString()} / person` : 'per month'}</div>
|
||
</div>
|
||
`;
|
||
document.getElementById('summaryCards').innerHTML = summaryHtml;
|
||
|
||
// ─── Overview Phase Table ────────────────────────────
|
||
let cumRunning = 0;
|
||
let roiHit = false;
|
||
let rows = '';
|
||
for (const k of phases) {
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
const cyclesNum = p.cycles;
|
||
|
||
if (!roiHit && giftCost > 0) {
|
||
for (let i = 0; i < cyclesNum; i++) cumRunning += yourCut;
|
||
if (cumRunning >= giftCost) roiHit = true;
|
||
}
|
||
|
||
const isRoi = giftCost > 0 && !roiHit ? true : false;
|
||
const cls = k === '3xL7' ? 'endgame' : (isRoi && roiHit ? 'highlight' : '');
|
||
|
||
rows += `<tr class="${cls}">
|
||
<td>${p.label}</td>
|
||
<td class="num">${k === '3xL7' ? 'every 19d' : `${cyclesNum}×`}</td>
|
||
<td>${k === '3xL7' ? 'ongoing' : `~${p.months} months`}</td>
|
||
<td class="num">$${p.payout.toFixed(2)}</td>
|
||
<td class="num green-text">$${yourCut.toFixed(2)}</td>
|
||
<td class="num">$${cumRunning.toFixed(2)}</td>
|
||
</tr>`;
|
||
}
|
||
document.getElementById('overviewBody').innerHTML = rows;
|
||
|
||
// ─── Profit Chart ─────────────────────────────────────
|
||
const chartData = [];
|
||
let chartCum = 0;
|
||
let chartMonth = 0;
|
||
for (const k of phases) {
|
||
const p = HYBRIDS[k];
|
||
const yourCut = p.payout * (commPct / 100);
|
||
const cycles = k === '3xL7' ? 6 : p.cycles;
|
||
for (let i = 0; i < cycles; i++) {
|
||
chartMonth++;
|
||
chartCum += yourCut;
|
||
chartData.push({ m: chartMonth, cum: Math.round(chartCum * 100) / 100 });
|
||
}
|
||
if (k === '3xL7') break;
|
||
}
|
||
|
||
const chartLabels = chartData.map(d => `M${d.m}`);
|
||
const chartValues = chartData.map(d => d.cum);
|
||
|
||
// Destroy old charts
|
||
if (chart1) { chart1.destroy(); chart1 = null; }
|
||
if (chart2) { chart2.destroy(); chart2 = null; }
|
||
if (chart3) { chart3.destroy(); chart3 = null; }
|
||
|
||
const ctx1 = document.getElementById('profitChart').getContext('2d');
|
||
chart1 = new Chart(ctx1, {
|
||
type: 'line',
|
||
data: {
|
||
labels: chartLabels,
|
||
datasets: [{
|
||
label: `${numPeople > 1 ? `Total (${numPeople} people)` : 'Your'} Cumulative Referral Earnings`,
|
||
data: numPeople > 1 ? chartValues.map(v => v * numPeople) : chartValues,
|
||
borderColor: '#6c5ce7',
|
||
backgroundColor: 'rgba(108,92,231,0.1)',
|
||
fill: true,
|
||
tension: 0.3,
|
||
pointRadius: 3,
|
||
pointHoverRadius: 5,
|
||
}]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: { labels: { color: '#8a8fa8', font: { size: 11 } } },
|
||
tooltip: {
|
||
callbacks: {
|
||
label: ctx => '$' + ctx.parsed.y.toLocaleString()
|
||
}
|
||
}
|
||
},
|
||
scales: {
|
||
x: { ticks: { color: '#5a5e7a', maxTicksLimit: 15, font: { size: 10 } }, grid: { color: '#2a2e4522' } },
|
||
y: { ticks: { color: '#5a5e7a', font: { size: 10 }, callback: v => '$' + v.toLocaleString() }, grid: { color: '#2a2e4522' } }
|
||
}
|
||
}
|
||
});
|
||
|
||
// ─── Timeline Tab ─────────────────────────────────────
|
||
const monthly = buildMonthlyTimeline(phases, commPct);
|
||
let tRows = '';
|
||
let runningCum = 0;
|
||
for (const m of monthly) {
|
||
runningCum += m.comm * numPeople;
|
||
tRows += `<tr>
|
||
<td>Month ${m.m}</td>
|
||
<td>${m.phase}</td>
|
||
<td class="num">$${(m.prof * numPeople).toLocaleString()}</td>
|
||
<td class="num green-text">$${(m.comm * numPeople).toLocaleString()}</td>
|
||
<td class="num">$${runningCum.toLocaleString()}</td>
|
||
</tr>`;
|
||
}
|
||
document.getElementById('timelineBody').innerHTML = tRows;
|
||
|
||
// Timeline chart
|
||
const ctx2 = document.getElementById('timelineChart').getContext('2d');
|
||
chart2 = new Chart(ctx2, {
|
||
type: 'bar',
|
||
data: {
|
||
labels: monthly.map(m => `M${m.m}`),
|
||
datasets: [
|
||
{
|
||
label: 'Their Profit',
|
||
data: monthly.map(m => m.prof * numPeople),
|
||
backgroundColor: 'rgba(0,214,143,0.4)',
|
||
borderColor: '#00d68f',
|
||
borderWidth: 1,
|
||
borderRadius: 3,
|
||
},
|
||
{
|
||
label: 'Your Commission',
|
||
data: monthly.map(m => m.comm * numPeople),
|
||
backgroundColor: 'rgba(108,92,231,0.5)',
|
||
borderColor: '#6c5ce7',
|
||
borderWidth: 1,
|
||
borderRadius: 3,
|
||
}
|
||
]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
plugins: {
|
||
legend: { labels: { color: '#8a8fa8', font: { size: 11 } } },
|
||
tooltip: { callbacks: { label: ctx => '$' + ctx.parsed.y.toLocaleString() } }
|
||
},
|
||
scales: {
|
||
x: { ticks: { color: '#5a5e7a', maxTicksLimit: 20, font: { size: 10 } }, grid: { color: '#2a2e4522' } },
|
||
y: { ticks: { color: '#5a5e7a', font: { size: 10 }, callback: v => '$' + v.toLocaleString() }, grid: { color: '#2a2e4522' } }
|
||
}
|
||
}
|
||
});
|
||
|
||
// ─── Ladder Tab ───────────────────────────────────────
|
||
let lRows = '';
|
||
for (const l of LEVELS) {
|
||
lRows += `<tr>
|
||
<td>Level ${l.level}</td>
|
||
<td>$${l.act}</td>
|
||
<td class="num">$${l.camp}</td>
|
||
<td class="num">$${l.total}</td>
|
||
<td class="num green-text">$${l.payout.toFixed(2)}</td>
|
||
<td class="num">$${l.netProfit.toFixed(2)}</td>
|
||
<td class="num">${l.clicks}</td>
|
||
<td class="num">$${l.cpc.toFixed(2)}</td>
|
||
</tr>`;
|
||
}
|
||
document.getElementById('ladderBody').innerHTML = lRows;
|
||
|
||
// Ladder progression
|
||
const ladderStart = effective;
|
||
let lpRows = '';
|
||
let started = false;
|
||
for (const s of LADDER_STEPS) {
|
||
const stepNum = LADDER_STEPS.indexOf(s) + 4;
|
||
if (stepNum <= ladderStart && ladderStart < 7) continue; // skip steps they already have
|
||
started = true;
|
||
const yourCut = s.ret * (commPct / 100);
|
||
lpRows += `<tr>
|
||
<td>${s.step}</td>
|
||
<td>$${s.capital.toLocaleString()}</td>
|
||
<td class="num">$${s.invest.toLocaleString()}</td>
|
||
<td class="num green-text">$${s.ret.toFixed(2)}</td>
|
||
<td class="num">$${s.profit.toFixed(2)}</td>
|
||
<td class="num">${s.cycles > 0 ? s.cycles + '×' : 'ongoing'}</td>
|
||
<td>${s.months > 0 ? `~${s.months} months` : 'forever'}</td>
|
||
</tr>`;
|
||
}
|
||
if (!lpRows) lpRows = '<tr><td colspan="7" style="text-align:center;color:var(--text-muted)">Already at endgame!</td></tr>';
|
||
document.getElementById('ladderProgressionBody').innerHTML = lpRows;
|
||
|
||
// ─── Comparison Tab ────────────────────────────────────
|
||
let cRows = '';
|
||
for (const s of SCENARIOS) {
|
||
const adj = mult;
|
||
cRows += `<tr class="scenario-row ${s.id === `gift${giftLevel}` || s.id === `self${selfLevel}` ? 'active-row' : ''}">
|
||
<td>${s.label}</td>
|
||
<td class="num">$${s.yourCost.toLocaleString()}</td>
|
||
<td class="num">$${s.yourCost.toLocaleString()}</td>
|
||
<td class="num">~${s.time} months</td>
|
||
<td class="num">$${Math.round(s.yr1 * adj * numPeople).toLocaleString()}</td>
|
||
<td class="num">$${Math.round(s.totalEG * adj * numPeople).toLocaleString()}</td>
|
||
<td class="num">$${Math.round(s.monthly * adj * numPeople).toLocaleString()}/mo</td>
|
||
</tr>`;
|
||
}
|
||
// Current scenario highlighted
|
||
document.getElementById('comparisonBody').innerHTML = cRows;
|
||
|
||
// Compare chart
|
||
const ctx3 = document.getElementById('compareChart').getContext('2d');
|
||
const compareLabels = SCENARIOS.map(s => s.label.replace('$', '').replace('(', '').replace(')', ''));
|
||
const compareData = SCENARIOS.map(s => Math.round(s.yr1 * mult * numPeople));
|
||
chart3 = new Chart(ctx3, {
|
||
type: 'bar',
|
||
data: {
|
||
labels: compareLabels,
|
||
datasets: [{
|
||
label: `Year 1 Earnings (${numPeople} people)`,
|
||
data: compareData,
|
||
backgroundColor: compareData.map((v, i) => {
|
||
const ids = [`gift${giftLevel}`, `self${selfLevel}`];
|
||
return ids.includes(SCENARIOS[i].id) ? 'rgba(108,92,231,0.7)' : 'rgba(90,94,122,0.3)';
|
||
}),
|
||
borderColor: compareData.map((v, i) => {
|
||
const ids = [`gift${giftLevel}`, `self${selfLevel}`];
|
||
return ids.includes(SCENARIOS[i].id) ? '#6c5ce7' : '#5a5e7a';
|
||
}),
|
||
borderWidth: 1,
|
||
borderRadius: 4,
|
||
}]
|
||
},
|
||
options: {
|
||
responsive: true,
|
||
maintainAspectRatio: false,
|
||
indexAxis: 'y',
|
||
plugins: {
|
||
legend: { display: false },
|
||
tooltip: { callbacks: { label: ctx => '$' + ctx.parsed.x.toLocaleString() + ' / yr' } }
|
||
},
|
||
scales: {
|
||
x: { ticks: { color: '#5a5e7a', font: { size: 9 }, callback: v => '$' + v.toLocaleString() }, grid: { color: '#2a2e4522' } },
|
||
y: { ticks: { color: '#8a8fa8', font: { size: 9 } }, grid: { display: false } }
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
// EVENT WIRING & INIT
|
||
// ══════════════════════════════════════════════════════════════════════
|
||
['numPeople','commissionPct','giftLevel','selfFundLevel','showReferral'].forEach(id => {
|
||
const el = document.getElementById(id);
|
||
el.addEventListener('input', updateAll);
|
||
el.addEventListener('change', updateAll);
|
||
});
|
||
|
||
// Tabs
|
||
document.querySelectorAll('.tab-btn').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||
document.querySelectorAll('.results').forEach(r => r.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
|
||
setTimeout(() => { if (chart1) chart1.resize(); if (chart2) chart2.resize(); if (chart3) chart3.resize(); }, 50);
|
||
});
|
||
});
|
||
|
||
updateAll();
|
||
</script>
|
||
</body>
|
||
</html> |