Lifequest / index.html
Nagaraj81's picture
Rename LifeQuest.html to index.html
00007dd verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"/>
<title>LifeQuest: The Game of Smart Choices</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>
<style>
/* ── DESIGN: Dark OLED arcade with gold accents. Single-scroll per page. ── */
:root{
--bg:#0A0E1A;--card:#111827;--card2:#1a2235;
--primary:#7C3AED;--primary2:#00D97E;--gold:#F59E0B;
--red:#EF4444;--text:#F1F5F9;--sub:#64748B;
--border:rgba(255,255,255,.08);
--grad:linear-gradient(135deg,#7C3AED,#5B21B6);
--grad-gold:linear-gradient(135deg,#F59E0B,#D97706);
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{background:var(--bg);color:var(--text);font-family:'Nunito','Trebuchet MS',system-ui,sans-serif;overflow-x:hidden;}
input,button,select,textarea{font-family:inherit}
a{color:inherit;text-decoration:none}
img{max-width:100%}
/* ── PAGE SYSTEM ─────────────────────────────────────────────── */
.page{display:none;min-height:100vh;animation:fadeUp .3s ease}
.page.active{display:block}
@keyframes fadeUp{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}
/* ── SCROLLABLE SECTIONS ──────────────────────────────────────── */
.scroll-page{padding-bottom:30px}
.section{padding:18px 16px}
.section+.section{padding-top:0}
/* ── CARDS ─────────────────────────────────────────────────────── */
.card{background:var(--card);border-radius:20px;padding:18px;border:1px solid var(--border);margin-bottom:12px}
.card-dark{background:var(--card2);border-radius:20px;padding:16px;border:1px solid var(--border);margin-bottom:12px}
.card-gold{background:linear-gradient(135deg,rgba(245,158,11,.15),rgba(245,158,11,.05));border:1px solid rgba(245,158,11,.25);border-radius:20px;padding:16px;margin-bottom:12px}
.card-purple{background:linear-gradient(135deg,rgba(124,58,237,.15),rgba(91,33,182,.05));border:1px solid rgba(124,58,237,.25);border-radius:20px;padding:16px;margin-bottom:12px}
.card-green{background:linear-gradient(135deg,rgba(0,217,126,.12),rgba(0,217,126,.03));border:1px solid rgba(0,217,126,.2);border-radius:20px;padding:16px;margin-bottom:12px}
/* ── TYPOGRAPHY ─────────────────────────────────────────────────── */
.h1{font-size:26px;font-weight:900;line-height:1.2}
.h2{font-size:20px;font-weight:900}
.h3{font-size:16px;font-weight:800}
.label{font-size:11px;font-weight:800;color:var(--sub);text-transform:uppercase;letter-spacing:.8px}
.body{font-size:14px;line-height:1.7;color:rgba(241,245,249,.75)}
/* ── BUTTONS ────────────────────────────────────────────────────── */
.btn{display:block;width:100%;padding:15px;border:none;border-radius:50px;font-size:15px;font-weight:900;cursor:pointer;letter-spacing:.3px;transition:transform .12s,opacity .12s;text-align:center}
.btn:active{transform:scale(.97);opacity:.88}
.btn-primary{background:var(--grad);color:#fff;box-shadow:0 6px 20px rgba(124,58,237,.35)}
.btn-gold{background:var(--grad-gold);color:#000}
.btn-green{background:linear-gradient(135deg,#00D97E,#00A868);color:#fff}
.btn-ghost{background:rgba(255,255,255,.07);color:var(--text);border:1px solid var(--border)}
.btn-sm{padding:10px 20px;font-size:13px;width:auto;display:inline-block}
.btn-row{display:flex;gap:10px;margin-top:12px}
.btn-row .btn{flex:1}
/* ── INPUTS ────────────────────────────────────────────────────── */
.inp-lbl{font-size:11px;font-weight:800;color:var(--sub);text-transform:uppercase;letter-spacing:.5px;display:block;margin-bottom:6px;margin-top:14px}
.inp{width:100%;padding:14px 16px;background:rgba(255,255,255,.06);border:1.5px solid var(--border);border-radius:14px;font-size:15px;font-weight:600;color:var(--text);transition:border-color .2s}
.inp:focus{outline:none;border-color:var(--primary)}
.inp::placeholder{color:rgba(255,255,255,.18)}
.inp-err{background:rgba(239,68,68,.12);border:1px solid rgba(239,68,68,.3);border-radius:10px;padding:10px 14px;font-size:12px;color:#FCA5A5;margin-top:8px;display:none}
select.inp{cursor:pointer}
/* ── HERO / HEADERS ──────────────────────────────────────────── */
.hero{background:linear-gradient(160deg,#1C0547 0%,#0D1F3C 60%,#0A1628 100%);padding:40px 20px 32px;text-align:center;position:relative;overflow:hidden}
.hero::before{content:'';position:absolute;inset:0;background:radial-gradient(ellipse at 50% 0%,rgba(124,58,237,.3),transparent 70%);pointer-events:none}
.page-hdr{background:var(--card);padding:16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:50}
.page-hdr-back{background:none;border:none;color:var(--primary);font-size:13px;font-weight:800;cursor:pointer;padding:6px 12px;border-radius:50px;background:rgba(124,58,237,.1)}
.page-hdr-title{font-size:17px;font-weight:900;flex:1}
/* ── XP BAR ─────────────────────────────────────────────────── */
.xp-wrap{background:rgba(255,255,255,.07);border-radius:50px;padding:8px 14px;display:flex;align-items:center;gap:10px;font-size:12px;font-weight:800}
.xp-bar{flex:1;height:7px;background:rgba(255,255,255,.15);border-radius:4px;overflow:hidden}
.xp-fill{height:100%;background:var(--grad-gold);border-radius:4px;transition:width .8s}
/* ── STATS GRID ──────────────────────────────────────────────── */
.stats-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.stat-box{background:var(--card2);border:1px solid var(--border);border-radius:16px;padding:14px;text-align:center}
.stat-v{font-size:22px;font-weight:900}
.stat-l{font-size:10px;color:var(--sub);font-weight:700;margin-top:3px;text-transform:uppercase}
.stat-3{grid-template-columns:1fr 1fr 1fr}
/* ── PROGRESS BAR ────────────────────────────────────────────── */
.prog-bar{height:8px;background:rgba(255,255,255,.08);border-radius:4px;overflow:hidden;margin:6px 0}
.prog-fill{height:100%;border-radius:4px;transition:width 1s}
/* ── LIST ROWS ───────────────────────────────────────────────── */
.list-row{display:flex;align-items:center;gap:12px;padding:13px 0;border-bottom:1px solid var(--border)}
.list-row:last-child{border-bottom:none}
.list-ic{font-size:26px;flex-shrink:0;width:42px;height:42px;border-radius:12px;display:flex;align-items:center;justify-content:center}
.list-body{flex:1}
.list-title{font-size:14px;font-weight:800}
.list-sub{font-size:11px;color:var(--sub);margin-top:2px}
.list-right{text-align:right;flex-shrink:0}
/* ── PILLS ───────────────────────────────────────────────────── */
.pill{display:inline-flex;align-items:center;gap:4px;padding:4px 11px;border-radius:50px;font-size:11px;font-weight:800}
.pill-gold{background:rgba(245,158,11,.15);color:#F59E0B;border:1px solid rgba(245,158,11,.25)}
.pill-green{background:rgba(0,217,126,.12);color:#00D97E;border:1px solid rgba(0,217,126,.2)}
.pill-purple{background:rgba(124,58,237,.12);color:#A78BFA;border:1px solid rgba(124,58,237,.2)}
.pill-red{background:rgba(239,68,68,.1);color:#F87171;border:1px solid rgba(239,68,68,.2)}
/* ── CHOICE CHIPS ───────────────────────────────────────────── */
.chip-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:12px 0}
.chip{padding:13px 10px;background:rgba(255,255,255,.05);border:2px solid var(--border);border-radius:14px;text-align:center;cursor:pointer;transition:all .15s;font-size:13px;font-weight:700}
.chip.on{border-color:var(--primary);background:rgba(124,58,237,.12);color:#C4B5FD}
.chip:active{transform:scale(.96)}
.chip-3{grid-template-columns:1fr 1fr 1fr}
/* ── CURRENCY GRID ───────────────────────────────────────────── */
.curr-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:10px 0}
.curr-c{padding:11px 6px;background:rgba(255,255,255,.04);border:2px solid var(--border);border-radius:13px;text-align:center;cursor:pointer;transition:all .15s}
.curr-c.on{border-color:var(--primary);background:rgba(124,58,237,.1)}
.curr-c:active{transform:scale(.95)}
.curr-sym{font-size:20px;font-weight:900;display:block}
.curr-lbl{font-size:9px;font-weight:800;color:var(--sub);margin-top:2px}
/* ── GOAL CARDS ──────────────────────────────────────────────── */
.goal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0}
.goal-c{background:rgba(255,255,255,.04);border:2px solid var(--border);border-radius:14px;padding:12px 8px;text-align:center;cursor:pointer;transition:all .15s}
.goal-c.on{border-color:var(--gold);background:rgba(245,158,11,.1)}
.goal-c:active{transform:scale(.95)}
.goal-c-ic{font-size:26px;display:block;margin-bottom:5px}
.goal-c-nm{font-size:11px;font-weight:800}
/* ── AVATAR GRID ─────────────────────────────────────────────── */
.av-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:12px 0}
.av-c{font-size:32px;text-align:center;padding:12px;background:rgba(255,255,255,.04);border:2px solid var(--border);border-radius:14px;cursor:pointer;transition:all .15s}
.av-c.on{border-color:#00D97E;background:rgba(0,217,126,.1)}
.av-c:active{transform:scale(.95)}
/* ── LESSON ROWS ─────────────────────────────────────────────── */
.les-row{display:flex;align-items:center;gap:13px;padding:14px;background:var(--card);border-radius:16px;margin-bottom:9px;cursor:pointer;border:1.5px solid var(--border);transition:border-color .15s}
.les-row.done{border-color:rgba(0,217,126,.3)}
.les-row.locked{opacity:.4;cursor:default}
.les-row:active:not(.locked){transform:scale(.99)}
.les-ic{font-size:28px;flex-shrink:0}
.les-body{flex:1}
.les-ttl{font-size:14px;font-weight:800}
.les-sub{font-size:11px;color:var(--sub);margin-top:2px}
.les-badge{font-size:10px;font-weight:800;margin-top:4px}
/* ── MARKET CARD ─────────────────────────────────────────────── */
.mkt-card{background:var(--card);border-radius:18px;padding:15px;margin-bottom:10px;border:1.5px solid var(--border)}
.mkt-card.owned{border-color:rgba(0,217,126,.35)}
.mkt-top{display:flex;align-items:flex-start;gap:11px}
.mkt-ic{width:48px;height:48px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:26px;flex-shrink:0}
.mkt-info{flex:1}
.mkt-nm{font-size:15px;font-weight:800}
.mkt-sym{font-size:10px;color:var(--sub);text-transform:uppercase;letter-spacing:.4px;margin-top:2px}
.mkt-desc{font-size:11px;color:var(--sub);margin-top:3px}
.mkt-price{text-align:right}
.mkt-px{font-size:16px;font-weight:900}
.mkt-chg{font-size:11px;font-weight:700;margin-top:3px}
.mkt-tags{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:9px 0}
.mkt-btns{display:flex;gap:8px}
.mkt-btn{flex:1;padding:10px;border-radius:10px;border:none;font-size:12px;font-weight:800;cursor:pointer}
.mkt-btn:active{transform:scale(.96)}
.buy-btn{background:rgba(0,217,126,.12);color:#00D97E;border:1px solid rgba(0,217,126,.2)}
.sell-btn{background:rgba(239,68,68,.08);color:#F87171;border:1px solid rgba(239,68,68,.18)}
/* ── BRAIN CARDS ─────────────────────────────────────────────── */
.brain-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px}
.brain-card{background:var(--card);border-radius:16px;padding:16px;cursor:pointer;border:1.5px solid var(--border);transition:all .15s}
.brain-card.done{border-color:rgba(0,217,126,.35)}
.brain-card:active{transform:scale(.97)}
/* ── WORLD CARDS ─────────────────────────────────────────────── */
.world-wrap{margin-bottom:14px}
.world-hdr{border-radius:16px 16px 0 0;padding:14px 16px;display:flex;align-items:center;gap:12px}
.world-body{background:var(--card);border:1px solid var(--border);border-top:none;border-radius:0 0 16px 16px;padding:12px 14px}
.ms-dot-row{display:flex;gap:8px;margin-top:8px}
.ms-dot{width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:900;border:2px solid rgba(255,255,255,.1);cursor:pointer;color:rgba(255,255,255,.3);transition:all .15s}
.ms-dot.done{background:#00D97E;color:#000;border-color:#00D97E}
.ms-dot.active{background:var(--gold);color:#000;border-color:var(--gold)}
/* ── LB ROWS ─────────────────────────────────────────────────── */
.lb-group{margin-bottom:16px}
.lb-group-hdr{background:var(--grad);padding:12px 16px;border-radius:14px 14px 0 0;display:flex;align-items:center;gap:10px}
.lb-row{display:flex;align-items:center;gap:11px;padding:12px 14px;background:var(--card);border-bottom:1px solid var(--border)}
.lb-row:last-child{border-radius:0 0 14px 14px;border-bottom:none}
.lb-row.me{background:rgba(124,58,237,.08);border-left:3px solid var(--primary)}
.lb-cmp-bar{flex:1;height:8px;background:rgba(255,255,255,.06);border-radius:4px;overflow:hidden;margin:4px 0}
.lb-cmp-fill{height:100%;border-radius:4px;transition:width 1s}
/* ── ACHIEVEMENT CARDS ───────────────────────────────────────── */
.ach-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin-bottom:12px}
.ach-card{background:var(--card);border-radius:14px;padding:13px 8px;text-align:center;border:1.5px solid var(--border)}
.ach-card.unlocked{border-color:rgba(245,158,11,.4);background:rgba(245,158,11,.06)}
.ach-card.locked{opacity:.35}
.ach-ic{font-size:28px;margin-bottom:6px}
.ach-nm{font-size:10px;font-weight:800;line-height:1.3}
.ach-rew{font-size:9px;font-weight:800;color:var(--gold);margin-top:5px}
/* ── CERT CARDS ──────────────────────────────────────────────── */
.cert-card{background:linear-gradient(135deg,#1C0547,#0D1F3C);border:1.5px solid rgba(245,158,11,.25);border-radius:18px;padding:20px;margin-bottom:12px;position:relative;overflow:hidden}
.cert-card.locked{opacity:.3;filter:grayscale(.7)}
.cert-bg-ic{position:absolute;font-size:120px;right:-10px;bottom:-20px;opacity:.06;line-height:1}
/* ── AI CHAT ─────────────────────────────────────────────────── */
.chat-wrap{display:flex;flex-direction:column;min-height:60vh}
.chat-msgs{flex:1;display:flex;flex-direction:column;gap:10px;padding:14px 0;min-height:200px}
.chat-msg{max-width:86%;padding:12px 15px;border-radius:18px;font-size:14px;line-height:1.6}
.chat-msg.ai{background:var(--card2);align-self:flex-start;border-bottom-left-radius:4px}
.chat-msg.user{background:var(--grad);color:#fff;align-self:flex-end;border-bottom-right-radius:4px}
.chat-chips{display:flex;flex-wrap:wrap;gap:7px;padding:6px 0 12px}
.chat-chip{background:rgba(124,58,237,.1);border:1px solid rgba(124,58,237,.25);border-radius:50px;padding:7px 13px;font-size:12px;font-weight:700;color:#C4B5FD;cursor:pointer}
.chat-chip:active{transform:scale(.96)}
.chat-inp-row{display:flex;gap:8px;padding:10px 0 4px;border-top:1px solid var(--border)}
.chat-inp{flex:1;padding:12px 15px;background:rgba(255,255,255,.06);border:1.5px solid var(--border);border-radius:50px;font-size:14px;color:var(--text)}
.chat-inp:focus{outline:none;border-color:var(--primary)}
.chat-send{width:44px;height:44px;border:none;border-radius:50%;background:var(--grad);color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0}
/* ── BEHAVIORAL BARS ─────────────────────────────────────────── */
.beh-row{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.beh-lbl{font-size:12px;font-weight:700;width:88px;flex-shrink:0}
.beh-bar{flex:1;height:8px;background:rgba(255,255,255,.08);border-radius:4px;overflow:hidden}
.beh-fill{height:100%;border-radius:4px;transition:width 1s}
.beh-val{font-size:12px;font-weight:900;width:30px;text-align:right}
/* ── PARENT DASH ─────────────────────────────────────────────── */
.child-tab{padding:8px 16px;border-radius:50px;border:2px solid var(--border);background:rgba(255,255,255,.04);font-size:12px;font-weight:800;color:var(--sub);cursor:pointer;white-space:nowrap;transition:all .15s;flex-shrink:0}
.child-tab.on{border-color:var(--gold);background:rgba(245,158,11,.12);color:var(--gold)}
/* ── SPINNERS / OVERLAYS ─────────────────────────────────────── */
.spin{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--sub);padding:12px 0}
.spinner{width:18px;height:18px;border:2.5px solid var(--border);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite;flex-shrink:0}
@keyframes spin{to{transform:rotate(360deg)}}
.xp-pop{position:fixed;font-weight:900;color:var(--gold);text-shadow:0 0 12px rgba(245,158,11,.7);pointer-events:none;z-index:999;animation:xpFly 1.4s ease forwards;font-size:16px}
@keyframes xpFly{0%{opacity:1;transform:translateY(0)}100%{opacity:0;transform:translateY(-70px)}}
#lvl-overlay{position:fixed;inset:0;background:rgba(0,0,0,.92);z-index:500;display:none;align-items:center;justify-content:center;flex-direction:column;text-align:center;padding:30px}
#lvl-overlay.show{display:flex;animation:fadeUp .3s}
/* ── MODAL BOTTOM SHEET ──────────────────────────────────────── */
.sheet-bg{position:fixed;inset:0;background:rgba(0,0,0,.7);backdrop-filter:blur(6px);z-index:200;display:none;align-items:flex-end;justify-content:center}
.sheet-bg.open{display:flex;animation:sheetIn .25s ease}
@keyframes sheetIn{from{opacity:0}to{opacity:1}}
.sheet{background:#111827;border-radius:24px 24px 0 0;padding:22px 20px max(22px,env(safe-area-inset-bottom));width:100%;max-width:420px;max-height:88vh;overflow-y:auto;animation:slideUp .25s ease}
@keyframes slideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}
.sheet-handle{width:40px;height:4px;background:rgba(255,255,255,.15);border-radius:2px;margin:0 auto 18px}
.sheet-em{font-size:48px;display:block;text-align:center;margin-bottom:10px}
.sheet-title{font-size:20px;font-weight:900;text-align:center;margin-bottom:4px}
.sheet-sub{font-size:13px;color:var(--sub);text-align:center;margin-bottom:16px;line-height:1.5}
/* ── NOTIFICATION TOAST ──────────────────────────────────────── */
#toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);background:#1E293B;border:1px solid var(--border);border-radius:50px;padding:12px 22px;font-size:13px;font-weight:700;color:var(--text);z-index:600;display:none;white-space:nowrap;box-shadow:0 8px 24px rgba(0,0,0,.4)}
#toast.show{display:block;animation:toastIn .25s ease}
@keyframes toastIn{from{opacity:0;transform:translateX(-50%) translateY(10px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
/* ── DEMO OVERLAY ────────────────────────────────────────────── */
#demo-overlay{position:fixed;inset:0;z-index:900;pointer-events:none;display:none}
.demo-cursor{position:fixed;width:28px;height:28px;border-radius:50%;background:rgba(255,215,0,.8);box-shadow:0 0 0 4px rgba(255,215,0,.3);z-index:901;pointer-events:none;transform:translate(-50%,-50%);transition:left .5s ease,top .5s ease;display:none}
.demo-label{position:fixed;background:rgba(0,0,0,.85);color:#FFD700;font-size:13px;font-weight:800;padding:8px 16px;border-radius:50px;border:1px solid rgba(255,215,0,.3);z-index:902;pointer-events:none;display:none;max-width:280px;text-align:center;left:50%;transform:translateX(-50%);bottom:100px}
#rec-badge{position:fixed;top:14px;right:14px;background:#EF4444;color:#fff;font-size:11px;font-weight:900;padding:5px 12px;border-radius:50px;z-index:903;display:none;animation:pulse 1s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
/* ── MISC ─────────────────────────────────────────────────────── */
.divider{height:1px;background:var(--border);margin:6px 0}
.empty{text-align:center;padding:28px 0;color:var(--sub);font-size:13px;line-height:1.8}
.risk-low{background:rgba(0,217,126,.1);color:#00D97E}
.risk-med{background:rgba(245,158,11,.12);color:#F59E0B}
.risk-high{background:rgba(249,115,22,.12);color:#FB923C}
.risk-ext{background:rgba(239,68,68,.1);color:#F87171}
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;800;900&family=Fredoka+One&display=swap');
.page{position:fixed!important;inset:0!important;overflow-y:auto!important;overflow-x:hidden!important;-webkit-overflow-scrolling:touch;background:var(--bg);}
.page.active{display:block!important;}
.has-nav{padding-bottom:92px!important;}
@media(min-width:481px){
body{background:#05080f;}
.page{left:50%!important;transform:translateX(-50%)!important;width:480px!important;right:auto!important;border-left:1px solid rgba(255,255,255,.05);border-right:1px solid rgba(255,255,255,.05);}
#mq-bottom-nav{left:50%!important;transform:translateX(-50%)!important;width:480px!important;right:auto!important;}
}
#app-lock-overlay{display:none;position:fixed;inset:0;z-index:99999;background:rgba(5,8,16,.97);backdrop-filter:blur(24px);flex-direction:column;align-items:center;justify-content:center;padding:32px 24px;box-sizing:border-box;}
#app-lock-overlay.visible{display:flex;}
</style>
</head>
<body>
<style>
/* ═══════════════════ NEW DESIGN ADDITIONS ═══════════════════ */
@keyframes floatLogo{0%,100%{transform:translateY(0);}50%{transform:translateY(-8px);}}
@keyframes gradShift{0%{background-position:0%}100%{background-position:200%}}
.mq-welcome-bg{min-height:100vh;background:linear-gradient(175deg,#060B16 0%,#0D0621 50%,#050A14 100%);display:flex;flex-direction:column;overflow-y:auto;}
/* Bottom nav */
#mq-bottom-nav{
display:none;position:fixed;bottom:0;left:0;right:0;z-index:8900;
height:62px;background:rgba(6,11,22,.97);backdrop-filter:blur(20px);
border-top:1px solid rgba(255,255,255,.07);
padding:0 8px;padding-bottom:env(safe-area-inset-bottom,0);
}
#mq-bottom-nav.show{display:flex;}
.mq-bnav-tab{
flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
gap:3px;border:none;background:none;cursor:pointer;
color:rgba(255,255,255,.25);font-family:inherit;padding:5px 2px;
position:relative;transition:color .2s;
}
.mq-bnav-tab.active{color:#fff;}
.mq-bnav-tab.phase-locked{opacity:.3;cursor:not-allowed;}
.mq-bnav-ic{font-size:20px;line-height:1;transition:transform .18s;}
.mq-bnav-tab.active .mq-bnav-ic{transform:scale(1.08);}
.mq-bnav-lbl{font-size:9px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;}
/* Colored bar per phase */
.mq-bnav-tab::before{content:'';position:absolute;top:0;left:50%;transform:translateX(-50%);height:2px;border-radius:0 0 2px 2px;width:0;transition:width .22s;}
.mq-bnav-tab.active[data-phase="learn"]::before{width:26px;background:#3B82F6;}
.mq-bnav-tab.active[data-phase="earn"]::before{width:26px;background:#F59E0B;}
.mq-bnav-tab.active[data-phase="do"]::before{width:26px;background:#10B981;}
.mq-bnav-tab.active[data-phase="sim"]::before{width:26px;background:#A855F7;}
/* Lock badge */
.mq-bnav-lock{position:absolute;top:4px;right:calc(50% - 16px);font-size:8px;background:rgba(255,255,255,.08);border-radius:50%;width:13px;height:13px;display:flex;align-items:center;justify-content:center;}
/* Earn/Do/Sim page grids */
.phase-card-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px;}
.phase-card{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:14px;padding:14px;cursor:pointer;transition:all .16s;position:relative;overflow:hidden;}
.phase-card:active{transform:scale(.97);}
.phase-card-ic{font-size:26px;margin-bottom:8px;}
.phase-card-title{font-size:12px;font-weight:800;line-height:1.2;}
.phase-card-desc{font-size:10px;color:rgba(255,255,255,.35);margin-top:3px;line-height:1.4;}
.phase-card-reward{display:inline-flex;align-items:center;gap:4px;margin-top:8px;padding:3px 8px;border-radius:50px;font-size:9px;font-weight:800;}
/* Lock overlay on card */
.card-lock-overlay{position:absolute;inset:0;background:rgba(6,11,22,.78);border-radius:14px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;}
.card-lock-ic{font-size:22px;}
.card-lock-msg{font-size:9px;font-weight:700;color:rgba(255,255,255,.35);text-align:center;padding:0 10px;}
/* Unlock progress banner */
.unlock-progress{background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);border-radius:13px;padding:13px 14px;margin-bottom:14px;}
.unlock-bar{height:6px;background:rgba(255,255,255,.06);border-radius:3px;overflow:hidden;margin-top:7px;}
.unlock-bar-fill{height:100%;border-radius:3px;transition:width .5s;}
/* Phase headers for earn/do/sim pages */
.phase-page-hdr{background:linear-gradient(180deg,#0A1020 0%,#060B16 100%);padding:16px;padding-top:calc(16px + env(safe-area-inset-top,0));}
.phase-page-hdr-row{display:flex;align-items:center;gap:10px;margin-bottom:13px;}
.phase-av{font-size:30px;}
.phase-meta{flex:1;}
.phase-meta-sub{font-size:10px;color:rgba(255,255,255,.35);font-weight:700;}
.phase-meta-title{font-size:17px;font-weight:900;}
.phase-coins{display:flex;align-items:center;gap:5px;background:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.18);border-radius:50px;padding:6px 11px;}
.phase-coins span{font-size:12px;font-weight:900;color:var(--gold);}
.phase-xp-row{display:flex;align-items:center;gap:8px;}
.phase-lv-badge{background:linear-gradient(135deg,#5B21B6,#7C3AED);border-radius:8px;padding:4px 10px;font-size:10px;font-weight:900;color:#fff;white-space:nowrap;flex-shrink:0;}
.phase-xp-bar{flex:1;height:5px;background:rgba(255,255,255,.06);border-radius:3px;overflow:hidden;}
.phase-xp-fill{height:100%;background:linear-gradient(90deg,#5B21B6,#A855F7);border-radius:3px;transition:width .5s;}
.phase-xp-lbl{font-size:10px;color:rgba(255,255,255,.35);white-space:nowrap;flex-shrink:0;}
/* Do page nw cards row */
.phase-nw-row{display:flex;gap:7px;margin-top:12px;}
.phase-nw-card{flex:1;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:9px 10px;}
.phase-nw-v{font-size:15px;font-weight:900;}
.phase-nw-l{font-size:9px;color:rgba(255,255,255,.35);font-weight:700;text-transform:uppercase;letter-spacing:.4px;margin-top:1px;}
/* Sim hero card */
.sim-hero{background:linear-gradient(135deg,rgba(168,85,247,.1),rgba(168,85,247,.03));border:1px solid rgba(168,85,247,.18);border-radius:16px;padding:20px;text-align:center;cursor:pointer;transition:all .18s;margin-bottom:12px;}
.sim-hero:active{transform:scale(.98);}
/* Page has bottom nav padding */
.has-nav{padding-bottom:92px!important;}
</style>
<!-- ═══════════ BOTTOM NAV ═══════════ -->
<div id="mq-bottom-nav">
<button class="mq-bnav-tab active" id="bnav-learn" data-phase="learn" onclick="switchPhase('learn')">
<span class="mq-bnav-ic">📚</span>
<span class="mq-bnav-lbl">Learn</span>
</button>
<button class="mq-bnav-tab" id="bnav-earn" data-phase="earn" onclick="switchPhase('earn')">
<span class="mq-bnav-ic">🪙</span>
<span class="mq-bnav-lbl">Earn</span>
</button>
<button class="mq-bnav-tab phase-locked" id="bnav-do" data-phase="do" onclick="tryUnlockedPhase('do')">
<span class="mq-bnav-ic">💰</span>
<span class="mq-bnav-lbl">Do</span>
<span class="mq-bnav-lock" id="bnav-do-lock">🔒</span>
</button>
<button class="mq-bnav-tab phase-locked" id="bnav-sim" data-phase="sim" onclick="tryUnlockedPhase('sim')">
<span class="mq-bnav-ic">🎮</span>
<span class="mq-bnav-lbl">Simulate</span>
<span class="mq-bnav-lock" id="bnav-sim-lock">🔒</span>
</button>
</div>
<!-- ═══════════ EARN PHASE PAGE ═══════════ -->
<div class="page has-nav" id="page-earn">
<div class="phase-page-hdr">
<div class="phase-page-hdr-row">
<div class="phase-av" id="earn-av">🦊</div>
<div class="phase-meta">
<div class="phase-meta-sub">Ways to Earn Coins &amp; XP</div>
<div class="phase-meta-title">Earn 🪙</div>
</div>
<div class="phase-coins"><span>🪙</span><span id="earn-coins-val">0</span></div>
</div>
<div class="phase-xp-row">
<div class="phase-lv-badge" id="earn-lv">Lv 1</div>
<div class="phase-xp-bar"><div class="phase-xp-fill" id="earn-xp-fill" style="width:0%"></div></div>
<div class="phase-xp-lbl" id="earn-xp-lbl">0/100 XP</div>
</div>
</div>
<div id="earn-phase-body" style="padding:16px;"></div>
</div>
<!-- ═══════════ DO PHASE PAGE ═══════════ -->
<div class="page has-nav" id="page-do">
<div class="phase-page-hdr">
<div class="phase-page-hdr-row">
<div class="phase-av" id="do-av">🦊</div>
<div class="phase-meta">
<div class="phase-meta-sub">Put your money to work</div>
<div class="phase-meta-title">Do 💰</div>
</div>
<div class="phase-coins"><span>🪙</span><span id="do-coins-val">0</span></div>
</div>
<div class="phase-nw-row">
<div class="phase-nw-card"><div class="phase-nw-v" id="do-cash" style="color:#10B981;">$500</div><div class="phase-nw-l">Cash</div></div>
<div class="phase-nw-card"><div class="phase-nw-v" id="do-saved" style="color:var(--gold);">$0</div><div class="phase-nw-l">Saved</div></div>
<div class="phase-nw-card"><div class="phase-nw-v" id="do-invested" style="color:#C4B5FD;">$0</div><div class="phase-nw-l">Invested</div></div>
</div>
</div>
<div id="do-phase-body" style="padding:16px;"></div>
</div>
<!-- ═══════════ SIMULATE PHASE PAGE ═══════════ -->
<div class="page has-nav" id="page-sim">
<div class="phase-page-hdr">
<div class="phase-page-hdr-row">
<div style="font-size:30px;">🎮</div>
<div class="phase-meta">
<div class="phase-meta-sub">Money Flight Simulator</div>
<div class="phase-meta-title">Simulate 🎮</div>
</div>
<div class="phase-coins"><span>🪙</span><span id="sim-coins-val">0</span></div>
</div>
</div>
<div id="sim-phase-body" style="padding:16px;"></div>
</div>
<!-- ══ TOAST ══════════════════════════════════════════════════════ -->
<div id="toast"></div>
<!-- ══ LEVEL-UP OVERLAY ═══════════════════════════════════════════ -->
<div id="lvl-overlay">
<div style="font-size:90px;margin-bottom:14px"></div>
<div style="font-size:32px;font-weight:900;color:var(--gold);text-shadow:0 0 30px rgba(245,158,11,.8);letter-spacing:2px;margin-bottom:8px" id="lu-ttl">LEVEL UP!</div>
<div style="font-size:16px;color:#fff;margin-bottom:6px" id="lu-sub">Level 2!</div>
<div style="font-size:14px;color:rgba(255,255,255,.5);margin-bottom:28px;line-height:1.65" id="lu-det">🪙 Bonus coins!</div>
<button class="btn btn-gold" style="max-width:240px" onclick="closeLvlUp()">AWESOME! ▶</button>
</div>
<!-- ══ DEMO ELEMENTS ══════════════════════════════════════════════ -->
<div id="demo-overlay"></div>
<div class="demo-cursor" id="demo-cursor"></div>
<div class="demo-label" id="demo-label"></div>
<div id="rec-badge">⏺ REC</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 1: WELCOME
═══════════════════════════════════════════════════════════════════ -->
<div class="page active" id="page-welcome">
<div class="mq-welcome-bg">
<!-- HERO SECTION -->
<div style="padding:48px 24px 20px;text-align:center;">
<div style="font-size:72px;margin-bottom:10px;display:block;filter:drop-shadow(0 0 40px rgba(245,158,11,.6));animation:floatLogo 3s ease-in-out infinite;">🏆</div>
<div style="font-size:30px;font-weight:900;letter-spacing:-1px;margin-bottom:6px;background:linear-gradient(120deg,#FFD93D,#F97316,#A855F7,#FFD93D);background-size:200%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;animation:gradShift 5s linear infinite;">LifeQuest: The Game of Smart Choices</div>
<div style="font-size:11px;color:rgba(255,255,255,.35);margin-bottom:10px;">Powered by K2 V2 Model · MBZUAI</div>
</div>
<!-- STATS STRIP -->
<div style="display:flex;margin:0 16px 20px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:14px;overflow:hidden;">
<div style="flex:1;padding:12px 8px;text-align:center;border-right:1px solid rgba(255,255,255,.06);">
<div style="font-size:20px;font-weight:900;color:var(--gold);">23</div>
<div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;margin-top:2px;text-transform:uppercase;letter-spacing:.4px;">Lessons</div>
</div>
<div style="flex:1;padding:12px 8px;text-align:center;border-right:1px solid rgba(255,255,255,.06);">
<div style="font-size:20px;font-weight:900;color:#A855F7;">7</div>
<div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;margin-top:2px;text-transform:uppercase;letter-spacing:.4px;">Levels</div>
</div>
<div style="flex:1;padding:12px 8px;text-align:center;border-right:1px solid rgba(255,255,255,.06);">
<div style="font-size:20px;font-weight:900;color:#3B82F6;">10</div>
<div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;margin-top:2px;text-transform:uppercase;letter-spacing:.4px;">Scenarios</div>
</div>
<div style="flex:1;padding:12px 8px;text-align:center;">
<div style="font-size:20px;font-weight:900;color:#10B981;">K2</div>
<div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;margin-top:2px;text-transform:uppercase;letter-spacing:.4px;">AI Coach</div>
</div>
</div>
<!-- 3-TAB AUTH BAR -->
<div style="margin:0 16px;display:flex;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:4px;gap:3px;">
<button id="wt-signup" onclick="wTab(1)" style="flex:1;padding:11px 4px;border:none;border-radius:10px;font-family:inherit;font-size:11px;font-weight:800;cursor:pointer;background:linear-gradient(135deg,#6D28D9,#7C3AED);color:#fff;box-shadow:0 2px 10px rgba(124,58,237,.4);letter-spacing:.1px;">👨‍👩‍👧 Sign Up</button>
<button id="wt-login" onclick="wTab(2)" style="flex:1;padding:11px 4px;border:none;border-radius:10px;font-family:inherit;font-size:11px;font-weight:700;cursor:pointer;background:transparent;color:rgba(255,255,255,.35);">🔑 Parent Login</button>
<button id="wt-child" onclick="wTab(3)" style="flex:1;padding:11px 4px;border:none;border-radius:10px;font-family:inherit;font-size:11px;font-weight:700;cursor:pointer;background:transparent;color:rgba(255,255,255,.35);">🎮 Play Now</button>
</div>
<!-- PANEL A: PARENT SIGN UP -->
<div id="wp-a" style="padding:20px 16px 8px;">
<div class="inp-err" id="wps-err" style="display:none;"></div>
<label class="inp-lbl">Your Full Name</label>
<input class="inp" id="wps-name" placeholder="e.g. Sarah Al-Rashid" type="text" autocomplete="off"/>
<label class="inp-lbl">Email Address</label>
<input class="inp" id="wps-email" placeholder="sarah@example.com" type="email"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="wps-pass" placeholder="Min 6 characters" type="password"/>
<label class="inp-lbl">Country</label>
<select class="inp" id="wps-country">
<option value="UAE">🇦🇪 UAE</option>
<option value="Saudi Arabia">🇸🇦 Saudi Arabia</option>
<option value="Qatar">🇶🇦 Qatar</option>
<option value="Kuwait">🇰🇼 Kuwait</option>
<option value="Bahrain">🇧🇭 Bahrain</option>
<option value="Egypt">🇪🇬 Egypt</option>
<option value="UK">🇬🇧 United Kingdom</option>
<option value="USA">🇺🇸 United States</option>
</select>
<button class="btn btn-gold" style="margin-top:4px;" onclick="doWelcomeSignup()">Create Account & Add Child →</button>
<div style="text-align:center;font-size:10px;color:rgba(255,255,255,.2);margin:12px 0 8px;position:relative;"><span style="background:var(--bg);padding:0 10px;position:relative;z-index:1;">already have an account?</span><div style="position:absolute;top:50%;left:0;right:0;height:1px;background:rgba(255,255,255,.06);"></div></div>
<button onclick="wTab(2)" style="width:100%;padding:10px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);border-radius:11px;font-family:inherit;font-size:12px;font-weight:700;color:rgba(255,255,255,.4);cursor:pointer;">Parent Login</button>
</div>
<!-- PANEL B: PARENT LOGIN -->
<div id="wp-b" style="display:none;padding:20px 16px 8px;">
<div style="text-align:center;margin-bottom:16px;">
<div style="font-size:28px;margin-bottom:6px;">👨‍👩‍👧</div>
<div style="font-size:15px;font-weight:800;margin-bottom:3px;">Welcome Back</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);">View your child's K2 AI progress reports</div>
</div>
<div class="inp-err" id="wpl-err" style="display:none;"></div>
<label class="inp-lbl">Email Address</label>
<input class="inp" id="wpl-email" placeholder="parent@email.com" type="email"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="wpl-pass" placeholder="Your password" type="password"/>
<button class="btn btn-primary" style="margin-top:4px;" onclick="doWelcomeParentLogin()">Log Into Dashboard →</button>
<div style="margin-top:14px;background:rgba(255,255,255,.025);border:1px solid rgba(255,255,255,.06);border-radius:12px;padding:12px 14px;">
<div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1px;margin-bottom:6px;text-transform:uppercase;">Demo Credentials</div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:rgba(255,255,255,.35);margin-bottom:3px;"><span>Email</span><span style="color:rgba(255,255,255,.65);font-weight:700;">demo@lifequest.com</span></div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:rgba(255,255,255,.35);margin-bottom:7px;"><span>Password</span><span style="color:rgba(255,255,255,.65);font-weight:700;">demo123</span></div>
<button onclick="(function(){var em=document.getElementById('wpl-email');var p=document.getElementById('wpl-pass');if(em)em.value='demo@lifequest.com';if(p)p.value='demo123';setTimeout(doWelcomeParentLogin,150)})()" style="width:100%;padding:7px;background:rgba(59,130,246,.08);border:1px solid rgba(59,130,246,.15);border-radius:8px;font-family:inherit;font-size:10px;font-weight:800;color:#93C5FD;cursor:pointer;">⚡ Demo Login — Play Now!</button>
</div>
</div>
<!-- PANEL C: CHILD / PLAYER LOGIN -->
<div id="wp-c" style="display:none;padding:20px 16px 8px;">
<div style="text-align:center;margin-bottom:16px;">
<div style="font-size:36px;margin-bottom:6px;">🎮</div>
<div style="font-size:15px;font-weight:900;margin-bottom:3px;">Ready to Play?</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);">Your parent creates your account first</div>
</div>
<div class="inp-err" id="wcl-err" style="display:none;"></div>
<label class="inp-lbl">Player Username</label>
<input class="inp" id="wcl-user" placeholder="your_username" type="text" autocomplete="username"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="wcl-pass" placeholder="Your password" type="password"/>
<button class="btn btn-primary" style="margin-top:4px;background:linear-gradient(135deg,#047857,#10B981);" onclick="doWelcomeChildLogin()">Start My Journey 🚀</button>
<div style="text-align:center;margin-top:12px;"><button onclick="wTab(2)" style="background:none;border:none;color:rgba(255,255,255,.28);font-size:12px;font-weight:700;cursor:pointer;font-family:inherit;text-decoration:underline;text-underline-offset:3px;">← Back to Parent Login</button></div>
<!-- Journey map preview -->
<div style="margin-top:16px;background:rgba(255,255,255,.025);border:1px solid rgba(255,255,255,.06);border-radius:14px;padding:14px 15px;">
<div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1px;margin-bottom:12px;text-transform:uppercase;">Your Journey</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.04);">
<div style="width:32px;height:32px;border-radius:9px;background:rgba(59,130,246,.12);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">📚</div>
<div><div style="font-size:12px;font-weight:800;color:#93C5FD;">1. LEARN</div><div style="font-size:10px;color:rgba(255,255,255,.3);">Complete lessons, earn XP &amp; coins</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.04);">
<div style="width:32px;height:32px;border-radius:9px;background:rgba(245,158,11,.12);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🪙</div>
<div><div style="font-size:12px;font-weight:800;color:var(--gold);">2. EARN</div><div style="font-size:10px;color:rgba(255,255,255,.3);">Quizzes, brain games, leaderboard</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.04);">
<div style="width:32px;height:32px;border-radius:9px;background:rgba(16,185,129,.12);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">💰</div>
<div><div style="font-size:12px;font-weight:800;color:#6EE7B7;">3. DO</div><div style="font-size:10px;color:rgba(255,255,255,.3);">Save, invest &amp; set goals · unlocks at 3 lessons</div></div>
</div>
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;">
<div style="width:32px;height:32px;border-radius:9px;background:rgba(168,85,247,.12);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🎮</div>
<div><div style="font-size:12px;font-weight:800;color:#C4B5FD;">4. SIMULATE</div><div style="font-size:10px;color:rgba(255,255,255,.3);">Real-life scenarios · unlocks at 5 lessons</div></div>
</div>
</div>
<div style="margin-top:12px;background:rgba(16,185,129,.04);border:1px solid rgba(16,185,129,.12);border-radius:12px;padding:11px 13px;">
<div style="font-size:9px;font-weight:800;color:rgba(16,185,129,.6);letter-spacing:1px;margin-bottom:5px;text-transform:uppercase;">Demo Player</div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:rgba(255,255,255,.35);margin-bottom:3px;"><span>Username</span><span style="color:rgba(255,255,255,.65);font-weight:700;">demo_child</span></div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:rgba(255,255,255,.35);margin-bottom:7px;"><span>Password</span><span style="color:rgba(255,255,255,.65);font-weight:700;">demo123</span></div>
<button onclick="(function(){var u=document.getElementById('wcl-user');var p=document.getElementById('wcl-pass');if(u)u.value='demo_child';if(p)p.value='demo123';setTimeout(doWelcomeChildLogin,150)})()" style="width:100%;padding:7px;background:rgba(16,185,129,.08);border:1px solid rgba(16,185,129,.15);border-radius:8px;font-family:inherit;font-size:10px;font-weight:800;color:#6EE7B7;cursor:pointer;">⚡ Demo Login — Parent View!</button>
</div>
</div>
<!-- Feature pills row -->
<div style="display:flex;gap:7px;overflow-x:auto;scrollbar-width:none;padding:16px 16px 36px;">
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">📊</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">20 Real Assets</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">🧠</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">Behavior AI</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">🏆</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">36 Achievements</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">📜</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">7 Certificates</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">🤖</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">K2 AI Coach</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">💳</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">Credit Score</span></div>
<div style="flex-shrink:0;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:50px;padding:7px 13px;"><span style="font-size:13px;">🌍</span><span style="font-size:10px;font-weight:700;color:rgba(255,255,255,.4);white-space:nowrap;">World Events</span></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 3: PARENT LOGIN
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-pauth">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-welcome')">← Back</button>
<div class="page-hdr-title">Parent Login</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="text-align:center;padding:20px 0 10px">
<div style="font-size:52px;margin-bottom:8px">🔐</div>
<div class="h2">Welcome Back!</div>
<div class="body" style="margin-top:6px">Sign in to view your child's progress</div>
</div>
<label class="inp-lbl">Email</label>
<input class="inp" id="pl-email" type="email" placeholder="parent@email.com"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="pl-pass" type="password" placeholder="Password"/>
<div class="inp-err" id="pl-err"></div>
<button class="btn btn-primary" style="margin-top:20px" id="btn-plogin" onclick="doParentLogin()">Sign In →</button>
<div style="text-align:center;font-size:13px;color:var(--sub);margin-top:14px">No account? <span style="color:var(--primary);font-weight:800;cursor:pointer" onclick="wTab(1)">Sign Up Free</span></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 4: ADD CHILD
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-addchild">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-pdash')">← Back</button>
<div class="page-hdr-title">Add Child</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="text-align:center;padding:16px 0 8px">
<div style="font-size:52px;margin-bottom:8px">👦</div>
<div class="h2">Register Your Child</div>
<div class="body" style="margin-top:6px">They'll use these credentials to log in and play</div>
</div>
<label class="inp-lbl">Child's Name</label>
<input class="inp" id="cc-name" placeholder="e.g. Ahmed" autocomplete="off"/>
<label class="inp-lbl">Username (for login)</label>
<input class="inp" id="cc-user" placeholder="e.g. ahmed_gamer"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="cc-pass" type="password" placeholder="Simple password"/>
<label class="inp-lbl">Age</label>
<input class="inp" id="cc-age" type="number" min="6" max="18" placeholder="e.g. 12"/>
<label class="inp-lbl" style="margin-bottom:8px">Choose Avatar</label>
<div class="av-grid" id="cc-avatars">
<div class="av-c on" data-em="🦊" onclick="selCCav(this)">🦊</div>
<div class="av-c" data-em="🐯" onclick="selCCav(this)">🐯</div>
<div class="av-c" data-em="🦁" onclick="selCCav(this)">🦁</div>
<div class="av-c" data-em="🐉" onclick="selCCav(this)">🐉</div>
<div class="av-c" data-em="🦄" onclick="selCCav(this)">🦄</div>
<div class="av-c" data-em="🐼" onclick="selCCav(this)">🐼</div>
<div class="av-c" data-em="🦅" onclick="selCCav(this)">🦅</div>
<div class="av-c" data-em="🐺" onclick="selCCav(this)">🐺</div>
</div>
<div class="inp-err" id="cc-err"></div>
<button class="btn btn-green" style="margin-top:20px" id="btn-createchild" onclick="doCreateChild()">Create Child Account ✓</button>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 5: CHILD LOGIN
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-childlogin">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-welcome')">← Back</button>
<div class="page-hdr-title">Player Login</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="text-align:center;padding:20px 0 10px">
<div style="font-size:52px;margin-bottom:8px">🎮</div>
<div class="h2">Ready to Play?</div>
<div class="body" style="margin-top:6px">Enter your username and password</div><div style="background:rgba(0,217,126,.08);border:1px solid rgba(0,217,126,.2);border-radius:12px;padding:10px 14px;margin-top:10px;font-size:12px;color:#00D97E;font-weight:700">🎮 Demo: username <strong>demo_child</strong> · password <strong>demo123</strong></div>
</div>
<label class="inp-lbl">Username</label>
<input class="inp" id="cl-user" placeholder="your_username" autocomplete="off"/>
<label class="inp-lbl">Password</label>
<input class="inp" id="cl-pass" type="password" placeholder="Password"/>
<div class="inp-err" id="cl-err"></div>
<button class="btn btn-gold" style="margin-top:20px" id="btn-childlogin" onclick="doChildLogin()">Play Now! 🚀</button>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 6: CHILD HOME (scrolls through all sections)
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-home">
<!-- HEADER — same IDs as before so renderHome() works -->
<div style="background:linear-gradient(180deg,#0A1020 0%,#060B16 100%);padding:20px 16px 15px;padding-top:calc(20px + env(safe-area-inset-top,0));">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:14px;">
<div style="font-size:32px;cursor:pointer;" id="h-av" onclick="goPage('page-personality')">🦊</div>
<div style="flex:1;">
<div style="font-size:10px;color:rgba(255,255,255,.35);font-weight:700;" id="h-greet">Good morning! 🌅</div>
<div style="font-size:17px;font-weight:900;line-height:1.1;" id="h-name">LifeQuest</div>
</div>
<div style="display:flex;align-items:center;gap:5px;cursor:pointer;background:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.18);border-radius:50px;padding:6px 12px;" onclick="goPage('page-achievements')">
<span style="font-size:13px;">🪙</span><span style="font-size:12px;font-weight:900;color:var(--gold);" id="coins-val">0</span>
</div>
<button onclick="doLogout()" style="background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.08);border-radius:50%;width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:14px;cursor:pointer;"></button>
</div>
<!-- XP bar — existing IDs preserved -->
<div style="display:flex;align-items:center;gap:8px;margin-bottom:13px;">
<div style="background:linear-gradient(135deg,#5B21B6,#7C3AED);border-radius:8px;padding:4px 10px;font-size:10px;font-weight:900;color:#fff;white-space:nowrap;flex-shrink:0;" id="lv-badge">Lv 1</div>
<div style="flex:1;height:5px;background:rgba(255,255,255,.06);border-radius:3px;overflow:hidden;"><div style="height:100%;background:linear-gradient(90deg,#5B21B6,#A855F7);border-radius:3px;transition:width .5s;" id="xp-fill"></div></div>
<div style="font-size:10px;color:rgba(255,255,255,.35);white-space:nowrap;flex-shrink:0;" id="xp-lbl">0/100 XP</div>
</div>
<!-- Net worth cards -->
<div style="display:flex;gap:7px;">
<div style="flex:1;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:9px 10px;">
<div style="font-size:15px;font-weight:900;color:#10B981;" id="h-cash">$500</div>
<div style="font-size:9px;color:rgba(255,255,255,.35);font-weight:700;text-transform:uppercase;letter-spacing:.4px;margin-top:1px;">Cash</div>
</div>
<div style="flex:1;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:9px 10px;">
<div style="font-size:15px;font-weight:900;color:var(--gold);" id="h-inv">$0</div>
<div style="font-size:9px;color:rgba(255,255,255,.35);font-weight:700;text-transform:uppercase;letter-spacing:.4px;margin-top:1px;">Invested</div>
</div>
<div style="flex:1;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:9px 10px;">
<div style="font-size:15px;font-weight:900;color:#C4B5FD;" id="h-nw">$500</div>
<div style="font-size:9px;color:rgba(255,255,255,.35);font-weight:700;text-transform:uppercase;letter-spacing:.4px;margin-top:1px;">Net Worth</div>
</div>
</div>
</div>
<!-- LEARN PHASE SECTION -->
<div style="padding:16px 16px 8px;">
<!-- Phase header -->
<div style="display:flex;align-items:center;gap:10px;margin-bottom:14px;">
<div style="width:36px;height:36px;border-radius:11px;background:rgba(59,130,246,.1);display:flex;align-items:center;justify-content:center;font-size:19px;flex-shrink:0;">📚</div>
<div style="flex:1;">
<div style="font-size:14px;font-weight:900;color:#93C5FD;">Learn</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:1px;">Complete lessons to unlock all features</div>
</div>
<div style="background:rgba(59,130,246,.1);border:1px solid rgba(59,130,246,.15);border-radius:50px;padding:4px 10px;font-size:10px;font-weight:800;color:#93C5FD;" id="home-les-badge">0/23</div>
</div>
<!-- Next lesson CTA -->
<div id="next-lesson-cta" onclick="startNextLesson()" style="background:linear-gradient(135deg,rgba(59,130,246,.1),rgba(59,130,246,.04));border:1px solid rgba(59,130,246,.2);border-radius:14px;padding:14px;display:flex;align-items:center;gap:12px;cursor:pointer;margin-bottom:10px;">
<div id="next-les-ic" style="width:44px;height:44px;border-radius:12px;background:rgba(59,130,246,.15);display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">💰</div>
<div style="flex:1;">
<div style="font-size:9px;font-weight:800;color:#93C5FD;letter-spacing:.8px;margin-bottom:2px;">▶ NEXT LESSON</div>
<div style="font-size:14px;font-weight:900;" id="next-les-title">What is Money?</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px;" id="next-les-meta">Level 1 · +20 XP</div>
</div>
<div style="font-size:22px;color:#93C5FD;"></div>
</div>
<!-- Coming-up lessons (3 previews) -->
<div id="home-lessons-preview" style="margin-bottom:8px;"></div>
<button onclick="goPage('page-learn')" style="width:100%;padding:10px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:11px;font-family:inherit;font-size:11px;font-weight:700;color:rgba(255,255,255,.35);cursor:pointer;margin-bottom:4px;">View All 23 Lessons &amp; Level Map →</button>
</div>
<!-- Goal banner (original ID preserved) -->
<div style="padding:0 16px 4px;">
<div id="goal-banner"></div>
<button id="btn-home-goals" onclick="goPage('page-goals')" style="display:none;margin-top:6px;width:100%;padding:8px;background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:10px;font-size:11px;font-weight:700;color:rgba(255,255,255,.3);cursor:pointer;font-family:inherit;">View All Goals →</button>
</div>
<!-- Portfolio (original ID: port-list) -->
<div style="padding:0 16px 6px;">
<div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1.2px;margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;text-transform:uppercase;">
<span>💼 Portfolio</span>
<span onclick="switchPhase('do')" style="color:var(--primary);cursor:pointer;font-size:10px;">Market →</span>
</div>
<div id="port-list"></div>
</div>
<!-- Activity (original ID: activity-list) -->
<div style="padding:0 16px 80px;">
<div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1.2px;margin-bottom:10px;text-transform:uppercase;">📋 Recent Activity</div>
<div id="activity-list"></div>
</div>
</div>
<div class="page" id="page-pdash">
<div style="background:linear-gradient(135deg,#1C0547,#0D1F3C);padding:20px 16px">
<div style="display:flex;align-items:center;gap:11px;margin-bottom:14px">
<div style="font-size:32px">👨‍👩‍👧</div>
<div style="flex:1">
<div style="font-size:12px;color:rgba(255,255,255,.4);font-weight:700">PARENT DASHBOARD</div>
<div style="font-size:18px;font-weight:900" id="pd-name">Welcome!</div>
</div>
<button onclick="doLogout()" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.15);border-radius:50px;color:rgba(255,255,255,.5);font-size:11px;font-weight:700;padding:5px 11px;cursor:pointer;font-family:inherit">Log Out</button>
</div>
<button class="btn btn-gold btn-sm" id="btn-addchild" onclick="goPage('page-addchild')" style="margin-bottom:12px">+ Add Child</button>
<div style="display:flex;gap:8px;overflow-x:auto;scrollbar-width:none" id="child-tabs"></div>
</div>
<div class="scroll-page" id="pd-body">
<div id="pd-no-children" class="section"><div class="empty">No children yet.<br/>Tap <strong>+ Add Child</strong> to get started.</div></div>
</div>
</div>
<!-- ════ NEW PAGE: CREDIT SCORE ════════════════════════════════ -->
<div class="page" id="page-credit">
<div style="background:linear-gradient(135deg,#1C0547,#0D1F3C);padding:20px 16px">
<div style="display:flex;align-items:center;gap:11px;margin-bottom:4px">
<button onclick="goPage('page-home')" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.15);border-radius:50px;color:rgba(255,255,255,.6);font-size:11px;font-weight:700;padding:5px 11px;cursor:pointer;font-family:inherit">← Back</button>
<div style="flex:1;font-size:18px;font-weight:900">Quest Credit Score</div>
</div>
</div>
<div class="scroll-page" id="credit-body">
<div class="section"><div class="empty">Loading...</div></div>
</div>
</div>
<!-- ════ NEW PAGE: INVEST CLUB ══════════════════════════════════ -->
<div class="page" id="page-invest-club">
<div style="background:linear-gradient(135deg,#1C0547,#0D1F3C);padding:20px 16px">
<div style="display:flex;align-items:center;gap:11px;margin-bottom:4px">
<button onclick="goPage('page-home')" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.15);border-radius:50px;color:rgba(255,255,255,.6);font-size:11px;font-weight:700;padding:5px 11px;cursor:pointer;font-family:inherit">← Back</button>
<div style="flex:1;font-size:18px;font-weight:900">Investment Club</div>
</div>
</div>
<div class="scroll-page" id="invest-club-body">
<div class="section"><div class="empty">Loading...</div></div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 8: LEARN (all 13 lessons)
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-learn">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">📚 Learn</div>
</div>
<div style="padding:8px 12px 0;display:flex;gap:6px">
<button onclick="goPage('page-curriculum')" style="flex:1;padding:8px;background:rgba(168,85,247,.1);border:1px solid rgba(168,85,247,.2);border-radius:9px;color:#C4B5FD;font-size:11px;font-weight:800;cursor:pointer;font-family:inherit">🗺️ Level Map</button>
<button onclick="goPage('page-certs')" style="flex:1;padding:8px;background:rgba(255,217,61,.08);border:1px solid rgba(255,217,61,.15);border-radius:9px;color:var(--gold);font-size:11px;font-weight:800;cursor:pointer;font-family:inherit">📜 Certificates</button>
</div>
<div class="scroll-page">
<div class="section">
<div class="body" style="margin-bottom:14px">Complete lessons to earn XP &amp; Gold Coins. Each ends with a quiz!</div>
<div id="les-list"></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 9: MARKET
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-market">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">📊 Markets</div>
<div class="pill pill-green" style="font-size:11px">💵 <span id="mkt-cash">$500</span></div>
<button onclick="triggerWorldEvent()" style="padding:5px 11px;background:rgba(245,158,11,.12);border:1px solid rgba(245,158,11,.25);border-radius:8px;color:#F59E0B;font-size:11px;font-weight:800;cursor:pointer;font-family:inherit">🌍 Event</button>
</div>
<div class="scroll-page">
<div class="section" style="padding-bottom:8px">
<div style="display:flex;gap:7px;overflow-x:auto;scrollbar-width:none" id="mkt-filters"></div>
</div>
<div class="section" style="padding-top:0" id="mkt-list"></div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 10: BRAIN HQ
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-brain">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🧠 Brain HQ</div>
</div>
<div class="scroll-page">
<div class="section">
<div class="body" style="margin-bottom:14px">Beat 6 money biases. The AI tracks what your choices reveal about your psychology!</div>
<div class="brain-grid" id="brain-grid"></div>
<div id="bias-score-bar"></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 11: WORLD MAP
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-world">
<div style="background:linear-gradient(135deg,rgba(245,158,11,.15),rgba(245,158,11,.05));padding:16px;border-bottom:1px solid rgba(245,158,11,.15);position:sticky;top:0;z-index:10">
<button class="page-hdr-back" onclick="goPage('page-home')" style="margin-bottom:10px">← Home</button>
<div class="h2" style="color:var(--gold)">🗺️ World Map</div>
<div class="body">5 worlds · 15 missions · Earn XP to unlock</div>
</div>
<div class="scroll-page">
<div class="section" id="world-list"></div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 12: LEADERBOARD
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-leaderboard">
<div style="background:linear-gradient(135deg,#1C0547,#0D1F3C);padding:16px;border-bottom:1px solid rgba(255,255,255,.07)">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div style="font-size:14px;font-weight:900;color:var(--gold)">🏆 Leaderboard</div>
</div>
<div style="display:flex;gap:5px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px">
<button class="lb-tier-btn" data-tier="city" onclick="switchLbTier('city')" style="flex-shrink:0;padding:6px 12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:rgba(255,255,255,.45);font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;transition:all .2s">🏙️ City</button>
<button class="lb-tier-btn" data-tier="zone" onclick="switchLbTier('zone')" style="flex-shrink:0;padding:6px 12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:rgba(255,255,255,.45);font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;transition:all .2s">📍 Zone</button>
<button class="lb-tier-btn" data-tier="country" onclick="switchLbTier('country')" style="flex-shrink:0;padding:6px 12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:rgba(255,255,255,.45);font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;transition:all .2s">🗺️ Country</button>
<button class="lb-tier-btn" data-tier="world" onclick="switchLbTier('world')" style="flex-shrink:0;padding:6px 12px;background:var(--primary);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:#fff;font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;transition:all .2s">🌍 World</button>
<button class="lb-tier-btn" data-tier="planet" onclick="switchLbTier('planet')" style="flex-shrink:0;padding:6px 12px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:rgba(255,255,255,.45);font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;transition:all .2s">🪐 Planet</button>
</div>
</div>
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🏆 Leaderboard</div>
</div>
<div class="scroll-page">
<div class="section" id="lb-body"></div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 13: ACHIEVEMENTS
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-achievements">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🏅 Achievements</div>
</div>
<div class="scroll-page">
<div class="section">
<div class="label" style="margin-bottom:10px">BADGES</div>
<div class="ach-grid" id="ach-grid"></div>
<div class="label" style="margin-bottom:10px;margin-top:6px">CERTIFICATES</div>
<div id="cert-list"></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 14: GOALS
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-goals">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🎯 Goals</div>
</div>
<div class="scroll-page">
<div class="section">
<div class="card-gold" style="cursor:pointer" id="btn-addgoal" onclick="openSheet('sheet-addgoal')">
<div style="text-align:center;font-size:15px;font-weight:800">+ Add New Goal 🎯</div>
</div>
<div id="goals-list"></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE 15: KAI AI MENTOR
═══════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-kai">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🤖 Ask Kai</div>
<div class="pill pill-gold" style="font-size:11px">20 🪙 / Q</div>
</div>
<div class="scroll-page">
<div class="section">
<div class="chat-wrap">
<div class="chat-msgs" id="kai-msgs"></div>
<div class="chat-chips" id="kai-chips"></div>
<div class="chat-inp-row">
<input class="chat-inp" id="kai-inp" placeholder="Ask Kai anything about money..." onkeydown="if(event.key==='Enter')sendKai()"/>
<button class="chat-send" id="btn-sendkai" onclick="sendKai()"></button>
</div>
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
BOTTOM SHEETS (modals)
═══════════════════════════════════════════════════════════════════ -->
<!-- Save -->
<div class="sheet-bg" id="sheet-save">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em">🏦</span>
<div class="sheet-title">Save Money</div>
<div class="sheet-sub">How much do you want to save?</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px" id="save-amts"></div>
<button class="btn btn-green" onclick="doSave()">Save It! 🏦</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-save')">Cancel</button>
</div>
</div>
<!-- Buy -->
<div class="sheet-bg" id="sheet-buy">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em" id="buy-em">📈</span>
<div class="sheet-title" id="buy-ttl">Buy Asset</div>
<div class="sheet-sub" id="buy-sub">Choose quantity</div>
<div class="chip-grid" id="buy-chips"></div>
<div style="display:flex;align-items:center;justify-content:center;gap:18px;background:rgba(255,255,255,.04);border-radius:14px;padding:16px;margin:12px 0">
<div style="text-align:center"><div id="buy-cost" style="font-size:22px;font-weight:900;color:var(--red)">$0</div><div style="font-size:10px;color:var(--sub);margin-top:3px">COST</div></div>
<div style="font-size:20px;color:var(--sub)"></div>
<div style="text-align:center"><div id="buy-left" style="font-size:22px;font-weight:900;color:var(--primary2)">$500</div><div style="font-size:10px;color:var(--sub);margin-top:3px">CASH LEFT</div></div>
</div>
<button class="btn btn-green" id="buy-ok" onclick="confirmBuy()">BUY 🚀</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-buy')">Cancel</button>
</div>
</div>
<!-- Sell -->
<div class="sheet-bg" id="sheet-sell">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em" id="sell-em">💰</span>
<div class="sheet-title" id="sell-ttl">Sell Asset</div>
<div class="sheet-sub" id="sell-sub">Choose quantity</div>
<div class="chip-grid chip-3" id="sell-chips"></div>
<button class="btn btn-primary" onclick="confirmSell()">SELL 💰</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-sell')">Cancel</button>
</div>
</div>
<!-- Lesson -->
<div class="sheet-bg" id="sheet-lesson">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em" id="les-em">📚</span>
<div class="sheet-title" id="les-ttl">Lesson</div>
<div id="les-body" style="font-size:13px;color:rgba(241,245,249,.7);line-height:1.8;margin-bottom:14px;max-height:35vh;overflow-y:auto"></div>
<div id="les-quiz"></div>
<button class="btn btn-primary" id="les-btn" disabled style="margin-top:10px">Pick an answer!</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-lesson')">Close</button>
</div>
</div>
<!-- Brain game -->
<div class="sheet-bg" id="sheet-bgame">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em" id="bg-em">🧠</span>
<div class="sheet-title" id="bg-ttl">Brain Game</div>
<div class="sheet-sub" id="bg-sub">Test your money psychology</div>
<div id="bg-body"></div>
<button class="btn btn-primary" id="bg-nxt" style="display:none;margin-top:10px" onclick="bgNext()">Next →</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-bgame')">Exit</button>
</div>
</div>
<!-- Mission -->
<div class="sheet-bg" id="sheet-mission">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em" id="ms-em">🗺️</span>
<div class="sheet-title" id="ms-ttl">Mission</div>
<div class="sheet-sub" id="ms-sub"></div>
<div id="ms-body"></div>
<button class="btn btn-gold" id="ms-ok" style="margin-top:10px">START 🚀</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-mission')">Later</button>
</div>
</div>
<!-- Add Goal -->
<div class="sheet-bg" id="sheet-addgoal">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em">🎯</span>
<div class="sheet-title">New Goal</div>
<div class="sheet-sub">Choose what to save for</div>
<div class="goal-grid" id="ng-grid">
<div class="goal-c on" data-g="gaming" onclick="selGoal(this)"><span class="goal-c-ic">🎮</span><div class="goal-c-nm">Gaming</div></div>
<div class="goal-c" data-g="sneakers" onclick="selGoal(this)"><span class="goal-c-ic">👟</span><div class="goal-c-nm">Sneakers</div></div>
<div class="goal-c" data-g="trip" onclick="selGoal(this)"><span class="goal-c-ic">✈️</span><div class="goal-c-nm">Trip</div></div>
<div class="goal-c" data-g="college" onclick="selGoal(this)"><span class="goal-c-ic">🎓</span><div class="goal-c-nm">College</div></div>
<div class="goal-c" data-g="business" onclick="selGoal(this)"><span class="goal-c-ic">💼</span><div class="goal-c-nm">Business</div></div>
<div class="goal-c" data-g="custom" onclick="selGoal(this)"><span class="goal-c-ic"></span><div class="goal-c-nm">My Own</div></div>
</div>
<label class="inp-lbl">Custom Name (optional)</label>
<input class="inp" id="ng-name" placeholder="e.g. New laptop"/>
<label class="inp-lbl">Currency</label>
<div class="curr-grid" id="ng-curr">
<div class="curr-c on" data-code="USD" data-sym="$" onclick="selCurr(this)"><span class="curr-sym">$</span><span class="curr-lbl">USD</span></div>
<div class="curr-c" data-code="AED" data-sym="د.إ" onclick="selCurr(this)"><span class="curr-sym" style="font-size:14px">د.إ</span><span class="curr-lbl">AED</span></div>
<div class="curr-c" data-code="EUR" data-sym="€" onclick="selCurr(this)"><span class="curr-sym"></span><span class="curr-lbl">EUR</span></div>
<div class="curr-c" data-code="GBP" data-sym="£" onclick="selCurr(this)"><span class="curr-sym">£</span><span class="curr-lbl">GBP</span></div>
<div class="curr-c" data-code="SAR" data-sym="﷼" onclick="selCurr(this)"><span class="curr-sym" style="font-size:14px"></span><span class="curr-lbl">SAR</span></div>
<div class="curr-c" data-code="BTC" data-sym="₿" onclick="selCurr(this)"><span class="curr-sym"></span><span class="curr-lbl">BTC</span></div>
</div>
<label class="inp-lbl">Target Amount <span id="ng-sym">$</span></label>
<input class="inp" id="ng-amt" type="number" placeholder="Leave blank for default" style="margin-bottom:14px"/>
<button class="btn btn-gold" id="btn-doaddgoal" onclick="doAddGoal()">Add Goal! 🚀</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-addgoal')">Cancel</button>
</div>
</div>
<!-- Rebalance -->
<div class="sheet-bg" id="sheet-rebalance">
<div class="sheet">
<div class="sheet-handle"></div>
<span class="sheet-em">⚖️</span>
<div class="sheet-title">Portfolio Rebalancer</div>
<div class="sheet-sub">K2 AI analyses your portfolio (costs 50 🪙)</div>
<div id="rb-chart" style="display:flex;align-items:flex-end;gap:8px;height:80px;margin:12px 0;justify-content:center"></div>
<div id="rb-suggest"></div>
<button class="btn btn-primary" id="rb-btn" disabled style="margin-top:10px" onclick="applyRb()">Apply Suggestion ✓</button>
<button class="btn btn-ghost" style="margin-top:8px" onclick="closeSheet('sheet-rebalance')">Close</button>
</div>
</div>
<!-- Ach Unlock -->
<div class="sheet-bg" id="sheet-ach-unlock">
<div class="sheet" style="text-align:center">
<div class="sheet-handle"></div>
<div id="au-ic" style="font-size:72px;margin-bottom:12px"></div>
<div class="sheet-title" id="au-ttl">Achievement Unlocked!</div>
<div class="sheet-sub" id="au-desc"></div>
<div class="card-gold" style="margin:12px 0;text-align:center">
<div id="au-rew" style="font-size:20px;font-weight:900;color:var(--gold)">🪙 +50</div>
<div style="font-size:11px;color:var(--sub);margin-top:3px">Gold Coins Reward</div>
</div>
<button class="btn btn-gold" onclick="closeSheet('sheet-ach-unlock')">Claim! 🎉</button>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE: FINANCIAL DECISION SIMULATOR
════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-simulator">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🎮 Money Simulator</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="text-align:center;padding:14px 0">
<div style="font-size:48px;margin-bottom:8px">🎮</div>
<div class="h2">Financial Decision Simulator</div>
<div class="body" style="margin-top:6px;margin-bottom:16px">Practice real-life money decisions. Every choice has consequences — just like real life.</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:16px">
<div class="stat-box"><div class="stat-v" id="sim-runs-val" style="color:var(--gold)">0</div><div class="stat-l">Scenarios Run</div></div>
<div class="stat-box"><div class="stat-v" id="sim-score-val" style="color:#6EE7B7">0</div><div class="stat-l">Smart Decisions</div></div>
</div>
<button class="btn btn-gold" onclick="openSimulator()">▶ Run a Scenario</button>
<button class="btn btn-ghost" style="margin-top:6px" onclick="openTimeSimulator()">⏳ Time Simulator — Compound Growth</button>
<div style="margin-top:16px">
<div class="label" style="margin-bottom:10px">SCENARIO LIBRARY (${SCENARIOS.length} scenarios)</div>
<div id="sim-scenario-list" style="display:flex;flex-direction:column;gap:7px"></div>
</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE: PERSONALITY PROFILE
════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-personality">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-home')">← Home</button>
<div class="page-hdr-title">🧬 My Money Personality</div>
</div>
<div class="scroll-page">
<div class="section" id="personality-body">
<div class="spin"><div class="spinner"></div>Loading profile...</div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE: CURRICULUM MAP (7 Levels)
════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-curriculum">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-learn')">← Learning</button>
<div class="page-hdr-title">🗺️ Curriculum Map</div>
<div class="pill pill-gold" style="font-size:11px" id="curr-done-badge">0/23</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="background:linear-gradient(135deg,rgba(168,85,247,.1),rgba(0,217,126,.05));border:1px solid rgba(168,85,247,.2);border-radius:12px;padding:12px 14px;margin-bottom:14px">
<div style="font-size:12px;font-weight:800;color:#C4B5FD;margin-bottom:3px">23 Lessons · 7 Levels · Full Financial Literacy</div>
<div style="font-size:11px;color:rgba(255,255,255,.45);line-height:1.6">Complete each level to unlock advanced features. Higher levels = real-world financial superpowers.</div>
</div>
<div id="curriculum-body"></div>
</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
PAGE: CERTIFICATES
════════════════════════════════════════════════════════════════ -->
<div class="page" id="page-certs">
<div class="page-hdr">
<button class="page-hdr-back" onclick="goPage('page-achievements')">← Awards</button>
<div class="page-hdr-title">📜 My Certificates</div>
</div>
<div class="scroll-page">
<div class="section">
<div style="text-align:center;padding:10px 0 14px">
<div style="font-size:40px;margin-bottom:6px">📜</div>
<div class="body" style="color:rgba(255,255,255,.5)">Earn certificates by mastering financial skills. Download and share your achievements.</div>
</div>
<div id="certs-body"></div>
</div>
</div>
</div>
<div id="app-lock-overlay">
<div style="text-align:center;margin-bottom:28px;">
<div style="font-size:56px;margin-bottom:10px;">🔒</div>
<div style="font-size:22px;font-weight:900;color:#fff;font-family:'Fredoka One',cursive;margin-bottom:6px;">Session Locked</div>
<div style="font-size:13px;color:rgba(255,255,255,.4);">15 min idle — enter password to continue</div>
</div>
<div style="width:100%;max-width:300px;">
<input id="lock-pass-input" type="password" placeholder="Your password"
style="width:100%;padding:14px;background:rgba(255,255,255,.07);border:1.5px solid rgba(255,255,255,.15);border-radius:12px;color:#fff;font-size:15px;font-family:inherit;box-sizing:border-box;outline:none;margin-bottom:8px;"
onkeydown="if(event.key==='Enter')unlockApp()"/>
<div id="lock-err" style="color:#EF4444;font-size:12px;font-weight:700;margin-bottom:10px;min-height:18px;text-align:center;"></div>
<button onclick="unlockApp()" style="width:100%;padding:14px;background:linear-gradient(135deg,#7C3AED,#5B21B6);border:none;border-radius:12px;color:#fff;font-size:15px;font-weight:900;cursor:pointer;font-family:inherit;box-shadow:0 4px 20px rgba(124,58,237,.4);margin-bottom:12px;">🔓 Unlock</button>
<div style="text-align:center;"><button onclick="lockAndLogout()" style="background:none;border:none;color:rgba(255,255,255,.28);font-size:12px;font-weight:700;cursor:pointer;font-family:inherit;text-decoration:underline;">Log Out Instead</button></div>
</div>
</div>
<script>
/* ═══════════════════════════════════════════════════════════════
MoneyQuest 2.0 — Complete Engine
K2 API · SaaS Auth · Behavioral Intelligence · All Game Logic
═══════════════════════════════════════════════════════════════ */
/* ── K2 API ─────────────────────────────────────────────── */
const K2_API_KEY = "IFM-hdBwCToeVDhs1kUT";
const K2_API_URL = "https://api.k2think.ai/v1/chat/completions";
const MODEL_NAME = "MBZUAI-IFM/K2-Think-v2";
async function k2(system, user, maxTokens=300){
try {
const r = await fetch(K2_API_URL, {
method:'POST',
headers:{'Content-Type':'application/json','Authorization':'Bearer '+K2_API_KEY},
body:JSON.stringify({model:MODEL_NAME,
messages:[{role:'system',content:system},{role:'user',content:user}],
max_tokens:maxTokens, temperature:0.7})
});
const d = await r.json();
let raw = d.choices?.[0]?.message?.content || 'Could not get a response. Try again!';
raw = stripReasoning(raw);
return raw;
} catch(e) {
return 'Connection issue — check your internet and try again! 🔄';
}
}
function stripReasoning(t){
if(!t) return 'Could not get a response. Try again!';
t=t.replace(/<think>[\s\S]*?<\/think>/gi,'');
t=t.replace(/<thinking>[\s\S]*?<\/thinking>/gi,'');
t=t.replace(/```[\s\S]*?```/g,'');
var bad=['let me','i need to','i will',"i'll","i'm ",'thinking:','reasoning:',
'first,','step ','okay,','alright,','so,','well,','now,','great,','sure,',
'to answer','to help',"let's",'hmm','based on','considering','looking at',
'analyzing','since ','given that','note:','note that','important:','remember:',
'user:','assistant:','question:','context:','system:','you asked','the user',
'in this case','as a ','i should','i can ','this means',"i've",'i have',
'here is',"here's",'the answer','to summarize','in summary',
'final answer:','answer:','response:','recommendation:',
'child profile:','child:','player:','name:','age:','behavioral',
'sentence 1','sentence 2','sentence 3','output only',
'delay=','risk=','discipline=','planning=','consistency='];
var lines=t.split('\n').filter(function(l){
var tr=l.trim().toLowerCase();
if(!tr||tr.length<3)return false;
for(var i=0;i<bad.length;i++){if(tr.startsWith(bad[i]))return false;}
return true;
});
var r=lines.join('\n')
.replace(/^(final answer|answer|response|recommendation):\s*/im,'')
.replace(/^(dear \w+,?\s*)/im,'')
.replace(/\n\s*\n\s*\n/g,'\n\n').trim();
if(r.split('\n').length>8||r.length>700){
var ps=r.split(/\n\n+/).filter(function(p){return p.trim().length>30;});
if(ps.length>1)r=ps[ps.length-1];
}
return r||'Could not get a response. Try again!';
}
/* ── LOCAL DB ───────────────────────────────────────────── */
const DB = {
_h(s){ let h=5381; for(let i=0;i<s.length;i++) h=((h<<5)+h)+s.charCodeAt(i); return (h>>>0).toString(36); },
get parents(){ try{ return JSON.parse(localStorage.getItem('mq_parents')||'{}'); }catch(e){return{};} },
get children(){ try{ return JSON.parse(localStorage.getItem('mq_children')||'{}'); }catch(e){return{};} },
saveParents(d){ localStorage.setItem('mq_parents',JSON.stringify(d)); },
saveChildren(d){ localStorage.setItem('mq_children',JSON.stringify(d)); },
get session(){ try{ return JSON.parse(localStorage.getItem('mq_sess')||'null'); }catch(e){return null;} },
saveSession(d){ localStorage.setItem('mq_sess',JSON.stringify(d)); },
clearSession(){ localStorage.removeItem('mq_sess'); },
createParent({name,email,password,country}){
const p=this.parents;
if(p[email]) return {ok:false,msg:'Email already registered'};
p[email]={id:'p_'+Date.now(),name,email,passHash:this._h(password),country,childIds:[],createdAt:Date.now()};
this.saveParents(p); return {ok:true,data:p[email]};
},
loginParent({email,password}){
const p=this.parents[email];
if(!p) return {ok:false,msg:'No account found with this email'};
if(p.passHash!==this._h(password)) return {ok:false,msg:'Incorrect password'};
this.saveSession({role:'parent',id:email});
return {ok:true,data:p};
},
createChild({parentEmail,username,password,name,avatar,age}){
const ch=this.children;
if(ch[username]) return {ok:false,msg:'Username taken — try another'};
const p=this.parents; const par=p[parentEmail];
if(!par) return {ok:false,msg:'Parent not found'};
const initS={name,avatar,age:+age,cash:500,xp:0,goldCoins:150,
port:{},mktPort:{},goals:[],activity:[],decisions:[],
completedMissions:[],completedGames:[],unlockedAchs:[],streak:1,learningDone:[]};
ch[username]={id:'c_'+Date.now(),username,passHash:this._h(password),name,avatar,age:+age,
parentId:parentEmail,S:initS,
beh:{delay:50,risk:50,discipline:50,planning:50,consistency:50,total:0,events:[]},
createdAt:Date.now()};
par.childIds.push(username);
this.saveChildren(ch); this.saveParents(p);
return {ok:true,data:ch[username]};
},
loginChild({username,password}){
const c=this.children[username];
if(!c) return {ok:false,msg:'Username not found'};
if(c.passHash!==this._h(password)) return {ok:false,msg:'Wrong password'};
this.saveSession({role:'child',id:username});
return {ok:true,data:c};
},
getChild(u){ return this.children[u]||null; },
getParent(e){ return this.parents[e]||null; },
saveChildState(u,S){ const c=this.children; if(c[u]){c[u].S=S; this.saveChildren(c);} },
saveBeh(u,b){ const c=this.children; if(c[u]){c[u].beh=b; this.saveChildren(c);} },
parentChildren(email){
const par=this.getParent(email); if(!par) return [];
const ch=this.children;
return par.childIds.map(id=>ch[id]).filter(Boolean);
},
allChildren(){ return Object.values(this.children); },
};
/* ── SESSION + STATE ────────────────────────────────────── */
let CU = null; // current user {role, data}
let S = {}; // active child game state
function initSession(){
const sess=DB.session; if(!sess) return false;
if(sess.role==='parent'){
const p=DB.getParent(sess.id);
if(p){ CU={role:'parent',data:p}; return 'parent'; }
} else {
const c=DB.getChild(sess.id);
if(c){ CU={role:'child',data:c}; S=c.S; return 'child'; }
}
DB.clearSession(); return false;
}
function persistS(){
if(CU?.role==='child') DB.saveChildState(CU.data.username, S);
}
function doLogout(){
DB.clearSession(); CU=null; S={};
goPage('page-welcome');
}
/* ═══════════════════════════════════════════════════════════
FINANCIAL PERSONALITY PROFILE — 7 Types
═══════════════════════════════════════════════════════════ */
const PERSONALITIES=[
{id:'strategic_saver',nm:'Strategic Saver',ic:'🏦',
col:'#3B82F6',
desc:'You think before you act. Every coin has a plan. Your patience will compound into serious wealth.',
trait:'High discipline + High delay + Low risk'},
{id:'balanced_investor',nm:'Balanced Investor',ic:'⚖️',
col:'#10B981',
desc:'You are the rare blend: smart risk-taking balanced with disciplined saving. This is the profile of most self-made millionaires.',
trait:'High discipline + Medium risk + High planning'},
{id:'bold_entrepreneur',nm:'Bold Entrepreneur',ic:'🚀',
col:'#F97316',
desc:'You see opportunity where others see risk. Your boldness is a superpower — just build the discipline to match it.',
trait:'High risk + High planning + Medium discipline'},
{id:'goal_planner',nm:'Goal Planner',ic:'🎯',
col:'#8B5CF6',
desc:'You are relentlessly goal-oriented. Once you commit, nothing stops you. This focus will define your financial future.',
trait:'High planning + High consistency + High delay'},
{id:'cautious_guardian',nm:'Cautious Guardian',ic:'🛡️',
col:'#6B7280',
desc:'Safety first. You protect what you have. Now learn to grow it — small, calculated risks over time will multiply your wealth.',
trait:'Low risk + High discipline + Low planning'},
{id:'impulsive_explorer',nm:'Impulsive Explorer',ic:'⚡',
col:'#EF4444',
desc:'You live in the moment and experience everything life offers. Channel that energy into a system and you become unstoppable.',
trait:'High risk + Low delay + Low discipline'},
{id:'social_giver',nm:'Social Giver',ic:'💝',
col:'#EC4899',
desc:'You are generous and community-minded. The world needs more givers. Pair generosity with a strong financial base and you can give even more.',
trait:'High consistency + Medium discipline + High charity'},
];
function getPersonality(){
const b=S.behavior||{delay:50,risk:50,discipline:50,planning:50,consistency:50};
const donated=S.totalDonated||0;
if(b.discipline>=65&&b.delay>=65&&b.risk<=40) return PERSONALITIES[0];
if(b.discipline>=60&&b.risk>=45&&b.risk<=65&&b.planning>=60) return PERSONALITIES[1];
if(b.risk>=65&&b.planning>=55) return PERSONALITIES[2];
if(b.planning>=70&&b.consistency>=65) return PERSONALITIES[3];
if(b.risk<=35&&b.discipline>=55) return PERSONALITIES[4];
if(donated>=100) return PERSONALITIES[6];
if(b.risk>=55&&b.delay<=45) return PERSONALITIES[5];
return PERSONALITIES[1]; // default: balanced
}
function renderPersonalityPage(){S.personalityViewed=true;persistS();
const el=document.getElementById('personality-body'); if(!el) return;
const p=getPersonality();
const b=S.behavior||{delay:50,risk:50,discipline:50,planning:50,consistency:50};
el.innerHTML=`
<div style="text-align:center;padding:20px 0 8px">
<div style="font-size:60px;filter:drop-shadow(0 0 20px ${p.col}80)">${p.ic}</div>
<div style="font-size:20px;font-weight:900;color:${p.col};margin:8px 0 4px">${p.nm}</div>
<div style="font-size:11px;color:rgba(255,255,255,.4);margin-bottom:14px">${p.trait}</div>
<div style="background:${p.col}15;border:1px solid ${p.col}30;border-radius:14px;padding:14px 16px;text-align:left;margin-bottom:20px">
<div style="font-size:13px;line-height:1.75;color:rgba(255,255,255,.8)">${p.desc}</div>
</div>
</div>
<div class="label" style="margin-bottom:12px">YOUR FINANCIAL DNA</div>
<div style="display:flex;flex-direction:column;gap:8px">
${[
{nm:'Delay Gratification',v:b.delay,col:'#6EE7B7'},
{nm:'Risk Appetite',v:b.risk,col:'#F59E0B'},
{nm:'Savings Discipline',v:b.discipline,col:'#60A5FA'},
{nm:'Planning Ahead',v:b.planning,col:'#C4B5FD'},
{nm:'Consistency',v:b.consistency,col:'#F9A8D4'},
].map(s=>`<div>
<div style="display:flex;justify-content:space-between;margin-bottom:4px">
<div style="font-size:11px;font-weight:700;color:rgba(255,255,255,.65)">${s.nm}</div>
<div style="font-size:11px;font-weight:800;color:${s.col}">${s.v}/100</div>
</div>
<div style="height:7px;background:rgba(255,255,255,.06);border-radius:4px;overflow:hidden">
<div style="height:100%;width:${s.v}%;background:${s.col};border-radius:4px;transition:width .6s ease"></div>
</div>
</div>`).join('')}
</div>
<div style="margin-top:20px;padding:12px;background:rgba(255,255,255,.04);border-radius:12px;text-align:center">
<div style="font-size:10px;color:rgba(255,255,255,.3);margin-bottom:3px">SIMULATOR RUNS</div>
<div style="font-size:20px;font-weight:900;color:var(--gold)">${S.simulatorRuns||0}</div>
</div>
<button class="btn btn-primary" style="margin-top:14px" onclick="openSimulator()">Run Money Simulator 🎮</button>
`;
}
/* ═══════════════════════════════════════════════════════════
TIME SIMULATION ENGINE
═══════════════════════════════════════════════════════════ */
function openTimeSimulator(){S.timeSimOpened=true;persistS();
const curSave=S.port?.save||0;
const curInv=Object.entries(S.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0);
const total=curSave+curInv;
const modal=document.createElement('div');
modal.id='time-sim-modal';
modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9999;display:flex;align-items:flex-end;justify-content:center;backdrop-filter:blur(8px)';
const rates={savings:0.04,investments:0.08};
function project(principal,rate,years){ return principal*Math.pow(1+rate,years); }
const years=[1,5,10,20,30];
const rows=years.map(y=>{
const sv=project(curSave,rates.savings,y);
const iv=project(curInv,rates.investments,y);
return {y,sv,iv,total:sv+iv};
});
modal.innerHTML=`<div style="width:100%;max-width:480px;background:linear-gradient(175deg,#0D0621,#0A1628);border-radius:24px 24px 0 0;padding:24px;max-height:88vh;overflow-y:auto">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<div style="font-size:14px;font-weight:900;color:var(--gold)">⏳ Time Simulator</div>
<button onclick="document.getElementById('time-sim-modal').remove()" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:50px;color:rgba(255,255,255,.5);font-size:11px;padding:4px 11px;cursor:pointer;font-family:inherit"></button>
</div>
<div style="background:rgba(255,255,255,.04);border-radius:12px;padding:13px;margin-bottom:16px">
<div style="font-size:11px;color:rgba(255,255,255,.4);margin-bottom:4px">CURRENT WEALTH</div>
<div style="font-size:24px;font-weight:900;color:var(--gold)">$${total.toFixed(0)}</div>
<div style="font-size:11px;color:rgba(255,255,255,.35);margin-top:3px">Savings: $${curSave.toFixed(0)} @ 4%/yr &nbsp;·&nbsp; Investments: $${curInv.toFixed(0)} @ 8%/yr</div>
</div>
<div class="label" style="margin-bottom:10px">COMPOUND GROWTH PROJECTION</div>
<div style="display:flex;flex-direction:column;gap:8px">
${rows.map(r=>`<div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);border-radius:11px;padding:12px 14px;display:flex;align-items:center;gap:12px">
<div style="font-size:22px;font-weight:900;color:var(--purple);width:48px;text-align:center">${r.y}y</div>
<div style="flex:1">
<div style="font-size:16px;font-weight:900;color:var(--gold)">$${r.total.toFixed(0)}</div>
<div style="font-size:10px;color:rgba(255,255,255,.35)">Savings: $${r.sv.toFixed(0)} · Investments: $${r.iv.toFixed(0)}</div>
</div>
<div style="font-size:12px;font-weight:800;color:#6EE7B7">+${((r.total/Math.max(1,total)-1)*100).toFixed(0)}%</div>
</div>`).join('')}
</div>
<div style="background:rgba(0,217,126,.06);border:1px solid rgba(0,217,126,.15);border-radius:12px;padding:12px 14px;margin-top:14px">
<div style="font-size:11px;color:#6EE7B7;font-weight:800;margin-bottom:4px">💡 Compound Interest Insight</div>
<div style="font-size:11px;color:rgba(255,255,255,.55);line-height:1.65">Starting with $${total.toFixed(0)} today, in 30 years you could have $${rows[4].total.toFixed(0)} — ${((rows[4].total/Math.max(1,total))).toFixed(1)}× more — without adding a single extra dollar. This is the power of time.</div>
</div>
<button class="btn btn-ghost" style="margin-top:12px" onclick="document.getElementById('time-sim-modal').remove()">Close</button>
</div>`;
document.body.appendChild(modal);
}
/* ═══════════════════════════════════════════════════════════
CURRICULUM LEVEL MAP — 7 Levels
═══════════════════════════════════════════════════════════ */
const CURRICULUM_LEVELS=[
{lv:1,nm:'Understanding Money',ic:'💰',col:'#10B981',xpReq:0,
desc:'Money basics, needs vs wants, earning income',lessons:[0,1,13,14]},
{lv:2,nm:'Saving',ic:'🏦',col:'#3B82F6',xpReq:100,
desc:'Saving habits, budgeting, delayed gratification',lessons:[2,15,16]},
{lv:3,nm:'Financial Goals',ic:'🎯',col:'#8B5CF6',xpReq:250,
desc:'Goal setting, compound interest, diversification',lessons:[3,4,5,17]},
{lv:4,nm:'Investing',ic:'📈',col:'#F59E0B',xpReq:500,
desc:'Stocks, bonds, reading charts, crypto vs stocks',lessons:[6,7,8,9,18,19]},
{lv:5,nm:'Lending & Borrowing',ic:'🤝',col:'#EC4899',xpReq:900,
desc:'Debt, credit scores, lending, bonds',lessons:[10,20,21]},
{lv:6,nm:'Entrepreneurship',ic:'🚀',col:'#F97316',xpReq:1400,
desc:'Business basics, cash flow, real estate',lessons:[11,22]},
{lv:7,nm:'Advanced Money Skills',ic:'🌍',col:'#6EE7B7',xpReq:2000,
desc:'Taxes, global markets, financial independence',lessons:[12]},
];
function renderCurriculumMap(){S.curriculumViewed=true;persistS();
const el=document.getElementById('curriculum-body'); if(!el) return;
const myXP=S.xp||0;
el.innerHTML=`<div style="padding:4px 0">
${CURRICULUM_LEVELS.map((lv,i)=>{
const unlocked=myXP>=lv.xpReq;
const levelLessons=lv.lessons.map(id=>LESSONS.find(l=>l.id===id)).filter(Boolean);
const done=levelLessons.filter(l=>(S.learningDone||[]).includes(l.id)).length;
const pct=levelLessons.length?Math.round(done/levelLessons.length*100):0;
return `<div style="background:rgba(255,255,255,.03);border:1px solid ${unlocked?lv.col+'30':'rgba(255,255,255,.06)'};border-radius:14px;padding:14px;margin-bottom:10px;${unlocked?'':'opacity:.5'}">
<div style="display:flex;align-items:center;gap:11px;margin-bottom:${unlocked&&levelLessons.length?'10':'0'}px">
<div style="width:36px;height:36px;border-radius:50%;background:${lv.col}20;display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0">${unlocked?lv.ic:'🔒'}</div>
<div style="flex:1">
<div style="font-size:12px;font-weight:900;color:${unlocked?lv.col:'rgba(255,255,255,.3)'}">LEVEL ${lv.lv} — ${lv.nm}</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:1px">${lv.desc}</div>
</div>
<div style="text-align:right">
<div style="font-size:12px;font-weight:800;color:${unlocked?'var(--gold)':'rgba(255,255,255,.2)'}">${done}/${levelLessons.length}</div>
<div style="font-size:9px;color:rgba(255,255,255,.25)">${unlocked?'lessons':lv.xpReq+' XP to unlock'}</div>
</div>
</div>
${unlocked&&levelLessons.length?`<div style="height:5px;background:rgba(255,255,255,.06);border-radius:3px;overflow:hidden">
<div style="height:100%;width:${pct}%;background:${lv.col};border-radius:3px;transition:width .5s"></div>
</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-top:10px">
${levelLessons.map(l=>{
const d=(S.learningDone||[]).includes(l.id);
return `<div onclick="openLesson(${l.id})" style="padding:5px 9px;background:${d?lv.col+'18':'rgba(255,255,255,.04)'};border:1px solid ${d?lv.col+'40':'rgba(255,255,255,.08)'};border-radius:7px;cursor:pointer;font-size:10px;font-weight:700;color:${d?lv.col:'rgba(255,255,255,.5)'}">${l.icon} ${l.title}</div>`;
}).join('')}
</div>`:''}
</div>`;
}).join('')}
</div>`;
}
/* ═══════════════════════════════════════════════════════════
CERTIFICATE GENERATOR — Canvas-rendered downloadable PDF
═══════════════════════════════════════════════════════════ */
function downloadCert(certId){
const cert=CERTS.find(c=>c.id===certId);
if(!cert) return;
const allCh=DB.allChildren();
const earned=allCh.filter(c=>(c.S?.certs||[]).includes(certId)).length;
const total=Math.max(earned,1);
const myRank=allCh.filter(c=>{
const cs=c.S||{};
return (cs.xp||0)>(S.xp||0);
}).length+1;
const pct=Math.round((1-(myRank/Math.max(allCh.length,10)))*100);
const canvas=document.createElement('canvas');
canvas.width=900; canvas.height=640;
const ctx=canvas.getContext('2d');
// Background gradient
const bg=ctx.createLinearGradient(0,0,900,640);
bg.addColorStop(0,'#0D0621');
bg.addColorStop(0.5,'#12093A');
bg.addColorStop(1,'#060d1a');
ctx.fillStyle=bg;
ctx.fillRect(0,0,900,640);
// Gold border frame
ctx.strokeStyle='rgba(255,217,61,0.6)';
ctx.lineWidth=3;
ctx.strokeRect(24,24,852,592);
ctx.strokeStyle='rgba(255,217,61,0.25)';
ctx.lineWidth=1;
ctx.strokeRect(32,32,836,576);
// Corner decorations
['TL','TR','BL','BR'].forEach(pos=>{
const x=pos.includes('L')?40:860;
const y=pos.includes('T')?40:600;
ctx.beginPath();
ctx.arc(x,y,16,0,Math.PI*2);
ctx.fillStyle='rgba(255,217,61,0.2)';
ctx.fill();
ctx.fillStyle='rgba(255,217,61,0.8)';
ctx.font='bold 16px serif';
ctx.textAlign='center';
ctx.fillText('✦',x,y+6);
});
// Logo row
ctx.fillStyle='rgba(255,217,61,0.9)';
ctx.font='bold 14px DM Sans, sans-serif';
ctx.textAlign='center';
ctx.fillText('🏆 MONEYQUEST 2.0 · POWERED BY K2 AI · UAE', 450, 80);
// Cert icon
ctx.font='64px serif';
ctx.textAlign='center';
ctx.fillText(cert.ic, 450, 175);
// Certificate title
ctx.fillStyle='rgba(255,255,255,0.95)';
ctx.font='bold 13px DM Sans, sans-serif';
ctx.letterSpacing='3px';
ctx.fillText('CERTIFICATE OF ACHIEVEMENT', 450, 225);
// Cert name
ctx.fillStyle='rgba(255,217,61,0.95)';
ctx.font='bold 34px DM Sans, sans-serif';
ctx.fillText(cert.nm, 450, 275);
// Divider
ctx.strokeStyle='rgba(255,217,61,0.3)';
ctx.lineWidth=1;
ctx.beginPath();
ctx.moveTo(200,298); ctx.lineTo(700,298);
ctx.stroke();
// "Awarded to"
ctx.fillStyle='rgba(255,255,255,0.4)';
ctx.font='12px DM Sans, sans-serif';
ctx.fillText('AWARDED TO', 450, 326);
// Child name
ctx.fillStyle='rgba(255,255,255,0.95)';
ctx.font='bold 28px DM Sans, sans-serif';
ctx.fillText(S.name||'MoneyQuest Player', 450, 368);
// Description
ctx.fillStyle='rgba(255,255,255,0.55)';
ctx.font='13px DM Sans, sans-serif';
ctx.fillText(cert.desc, 450, 405);
// Stats row
const date=new Date().toLocaleDateString('en-GB',{day:'2-digit',month:'long',year:'numeric'});
ctx.fillStyle='rgba(0,217,126,0.8)';
ctx.font='bold 12px DM Sans, sans-serif';
ctx.fillText('Top '+Math.max(1,100-pct)+'% of MoneyQuest players · '+date+' · Level '+(Math.floor((S.xp||0)/100)+1), 450, 455);
// Footer line
ctx.strokeStyle='rgba(255,255,255,0.08)';
ctx.beginPath();
ctx.moveTo(80,490); ctx.lineTo(820,490);
ctx.stroke();
// Footer text
ctx.fillStyle='rgba(255,255,255,0.2)';
ctx.font='11px DM Sans, sans-serif';
ctx.fillText('This certificate is awarded in recognition of demonstrated financial literacy and behavioral excellence.', 450, 520);
ctx.fillText('Verified by MoneyQuest AI Assessment System · moneyquest.app', 450, 545);
// Download
const link=document.createElement('a');
link.download='MoneyQuest-'+cert.id+'.png';
link.href=canvas.toDataURL('image/png');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
toast('Certificate downloaded! 📜');
}
function renderCertsPage(){
const el=document.getElementById('certs-body'); if(!el) return;
const allCh=DB.allChildren();
el.innerHTML=`
<div class="label" style="margin-bottom:12px">MY CERTIFICATES (${(S.certs||[]).length}/${CERTS.length})</div>
<div style="display:flex;flex-direction:column;gap:10px">
${CERTS.map(c=>{
const earned=(S.certs||[]).includes(c.id);
const myRank=allCh.filter(ch=>(ch.S?.xp||0)>(S.xp||0)).length+1;
const pct=Math.round((1-myRank/Math.max(allCh.length,10))*100);
return `<div style="background:${earned?'rgba(0,217,126,.06)':'rgba(255,255,255,.03)'};border:1px solid ${earned?'rgba(0,217,126,.22)':'rgba(255,255,255,.07)'};border-radius:14px;padding:14px 15px">
<div style="display:flex;align-items:center;gap:12px">
<div style="font-size:30px;${earned?'':'filter:grayscale(1);opacity:.35'}">${c.ic}</div>
<div style="flex:1">
<div style="font-size:13px;font-weight:800;color:${earned?'#6EE7B7':'rgba(255,255,255,.4)'}">${c.nm}</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px">${earned?c.desc:c.req}</div>
${earned?`<div style="font-size:10px;color:rgba(0,217,126,.7);margin-top:3px;font-weight:700">Top ${Math.max(1,100-pct)}% · Level ${c.level} cert</div>`:''}
</div>
${earned?`<button onclick="downloadCert('${c.id}')" style="background:linear-gradient(135deg,#059669,#00D97E);border:none;border-radius:9px;color:#000;font-size:10px;font-weight:800;padding:7px 11px;cursor:pointer;font-family:inherit;flex-shrink:0">📥 Download</button>`:
`<div style="font-size:9px;color:rgba(255,255,255,.2);text-align:right;flex-shrink:0">+${c.xp} XP<br>+${c.coins} 🪙</div>`}
</div>
</div>`;
}).join('')}
</div>
`;
}
function renderSimulatorPage(){
const rv=document.getElementById('sim-runs-val');
const sv=document.getElementById('sim-score-val');
if(rv) rv.textContent=S.simulatorRuns||0;
if(sv){
const smart=(S.simulatorHistory||[]).length;
sv.textContent=smart;
}
const list=document.getElementById('sim-scenario-list');
if(list){
list.innerHTML=SCENARIOS.map(s=>{
const done=(S.simulatorHistory||[]).includes(s.id);
return `<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;background:${done?'rgba(0,217,126,.05)':'rgba(255,255,255,.03)'};border:1px solid ${done?'rgba(0,217,126,.15)':'rgba(255,255,255,.07)'};border-radius:10px;cursor:pointer" onclick="openSimulatorById('${s.id}')">
<div style="font-size:22px">${s.em}</div>
<div style="flex:1">
<div style="font-size:12px;font-weight:700;color:${done?'#6EE7B7':'rgba(255,255,255,.75)'}">${s.title}</div>
<div style="font-size:10px;color:rgba(255,255,255,.3)">Level ${s.lv} · ${s.coins} coins at stake</div>
</div>
<div style="font-size:10px;font-weight:700;color:${done?'#6EE7B7':'rgba(255,255,255,.2)'}">${done?'✓ Done':'▶ Play'}</div>
</div>`;
}).join('');
}
}
function openSimulatorById(id){
const sc=SCENARIOS.find(s=>s.id===id);
if(!sc) return;
curScenario=sc;
// reuse openSimulator but with specific scenario
const existing=document.getElementById('sim-modal');
if(existing) existing.remove();
const modal=document.createElement('div');
modal.id='sim-modal';
modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9999;display:flex;align-items:flex-end;justify-content:center;backdrop-filter:blur(8px)';
modal.innerHTML=`<div style="width:100%;max-width:480px;background:linear-gradient(175deg,#0D0621,#0A1628);border-radius:24px 24px 0 0;padding:24px;max-height:85vh;overflow-y:auto">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<div style="font-size:11px;font-weight:800;color:rgba(255,255,255,.35);letter-spacing:1.5px">MONEY SIMULATOR</div>
<button onclick="document.getElementById('sim-modal').remove()" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:50px;color:rgba(255,255,255,.5);font-size:11px;padding:4px 11px;cursor:pointer;font-family:inherit">&#x2715;</button>
</div>
<div style="text-align:center;margin-bottom:20px">
<div style="font-size:52px;margin-bottom:6px">${sc.em}</div>
<div style="font-size:18px;font-weight:900;margin-bottom:8px">${sc.title}</div>
<div style="background:rgba(168,85,247,.1);border:1px solid rgba(168,85,247,.2);border-radius:12px;padding:13px 15px;text-align:left">
<div style="font-size:13px;line-height:1.7;color:rgba(255,255,255,.8)">${sc.situation}</div>
</div>
<div style="margin-top:10px;font-size:12px;font-weight:800;color:var(--gold)">&#x1F4B0; ${sc.coins} coins at stake</div>
</div>
<div style="display:flex;flex-direction:column;gap:9px" id="sim-choices">
${sc.choices.map((c,i)=>`<button onclick="pickSimChoice(${i})" style="padding:13px 15px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:12px;color:#fff;font-size:13px;font-weight:700;text-align:left;cursor:pointer;font-family:inherit;line-height:1.5;transition:all .2s" onmouseover="this.style.background='rgba(168,85,247,.12)'" onmouseout="this.style.background='rgba(255,255,255,.04)'">${c.label}</button>`).join('')}
</div>
</div>`;
document.body.appendChild(modal);
}
/* ═══════════════════════════════════════════════════════════
ENHANCED LEADERBOARD — 5 Tiers
═══════════════════════════════════════════════════════════ */
let lbTier='world'; // city|zone|country|world|planet
function switchLbTier(tier){
lbTier=tier;
document.querySelectorAll('.lb-tier-btn').forEach(b=>{
b.style.background=b.dataset.tier===tier?'var(--primary)':'rgba(255,255,255,.04)';
b.style.color=b.dataset.tier===tier?'#fff':'rgba(255,255,255,.45)';
});
renderLeaderboard();
}
/* ═══════════════════════════════════════════════════════════
ADDITIONAL ACHIEVEMENTS for new features
═══════════════════════════════════════════════════════════ */
const EXTRA_ACHIEVEMENTS=[
{id:'sim_first',ic:'🎮',nm:'Simulator Rookie',desc:'Complete your first money scenario',cond:()=>(S.simulatorRuns||0)>=1,rew:20},
{id:'sim_pro',ic:'🏆',nm:'Simulator Pro',desc:'Complete 8 money scenarios',cond:()=>(S.simulatorRuns||0)>=8,rew:60},
{id:'time_sim',ic:'⏳',nm:'Time Traveler',desc:'Use the Time Simulator',cond:()=>(S.timeSimOpened||false),rew:25},
{id:'all_lessons',ic:'📚',nm:'Full Scholar',desc:'Complete all 23 lessons',cond:()=>(S.learningDone||[]).length>=23,rew:200},
{id:'level_map',ic:'🗺️',nm:'Map Master',desc:'View all 7 curriculum levels',cond:()=>(S.curriculumViewed||false),rew:15},
{id:'cert_earned',ic:'📜',nm:'Certified',desc:'Earn your first certificate',cond:()=>(S.certs||[]).length>=1,rew:50},
{id:'personality_set',ic:'🧬',nm:'Self-Aware',desc:'View your Money Personality Profile',cond:()=>(S.personalityViewed||false),rew:20},
{id:'smart_choice',ic:'🧠',nm:'Smart Chooser',desc:'Make 3 disciplined simulator choices',cond:()=>(S.smartChoices||0)>=3,rew:40},
];
function recordDecision(type, data){
if(!S.decisions) S.decisions=[];
S.decisions.push({type,data,ts:Date.now()});
if(S.decisions.length>100) S.decisions=S.decisions.slice(-100);
// Update consistency score on regular activity
if(['save','invest','lesson','simulator'].includes(type)){
if(!S.behavior) S.behavior={delay:50,risk:50,discipline:50,planning:50,consistency:50};
S.behavior.consistency=Math.min(100,(S.behavior.consistency||50)+1);
}
}
// Virtual Tax alias (required by master build spec)
function applyTax(){ checkAndApplyTax && checkAndApplyTax(); }
/* ═══════════════════════════════════════════════════════════
MINI-GAME ENGINE — One unique game type per lesson concept
═══════════════════════════════════════════════════════════ */
const MINI_GAMES={
trivia:{nm:'💡 Quick-Fire Trivia',play:(l)=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:8px">BONUS TRIVIA</div>${(l.opts||[]).map((o,i)=>`<button onclick="mgPick(this,${i},${l.ans})" style="width:100%;padding:8px 12px;margin-bottom:5px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:8px;color:#fff;font-size:12px;font-weight:700;text-align:left;cursor:pointer;font-family:inherit">${['A','B','C','D'][i]}. ${o}</button>`).join('')}</div>`},
sort:{nm:'🗂 Sort Challenge',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:8px">SORT: Need or Want?</div><div id="sort-items" style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:8px">${[['🏠 Shelter','need'],['🎮 New Game','want'],['🍎 Food','need'],['👟 Designer Shoes','want'],['📚 Textbooks','need'],['🎵 Streaming','want']].map(it=>`<button onclick="mgSort(this,'${it[1]}')" style="padding:6px 10px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:7px;color:#fff;font-size:11px;font-weight:700;cursor:pointer;font-family:inherit">${it[0]}</button>`).join('')}</div><div style="display:flex;gap:6px"><div id="mg-need" style="flex:1;min-height:36px;background:rgba(0,217,126,.07);border:1px dashed rgba(0,217,126,.3);border-radius:8px;padding:6px;font-size:10px;color:#6EE7B7;font-weight:700">✅ NEEDS</div><div id="mg-want" style="flex:1;min-height:36px;background:rgba(239,68,68,.07);border:1px dashed rgba(239,68,68,.3);border-radius:8px;padding:6px;font-size:10px;color:#FCA5A5;font-weight:700">💸 WANTS</div></div><div id="mg-score" style="margin-top:6px;font-size:10px;color:rgba(255,255,255,.35)">Tap each item to sort it!</div></div>`},
calc:{nm:'🧮 Compound Calculator',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:6px">$100 at 10%/yr for 10 years = ?</div><div style="display:flex;gap:5px">${[159,194,259,311].map(v=>`<button onclick="mgCalcPick(this,${v},259)" style="flex:1;padding:8px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:8px;color:#fff;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">$${v}</button>`).join('')}</div><div id="mg-calc-out" style="margin-top:6px;font-size:10px;color:rgba(255,255,255,.3)">Formula: P × (1+r)^n</div></div>`},
rank:{nm:'📊 Risk Ranker',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:8px">RANK: Lowest → Highest risk</div>${[['🏦 Savings Account','low'],['📈 S&P 500 ETF','medium'],['💎 Single Stock','high'],['₿ Bitcoin','extreme']].sort(()=>Math.random()-.5).map(it=>`<button onclick="mgRankPick(this,'${it[1]}')" data-risk="${it[1]}" style="width:100%;padding:8px 12px;margin-bottom:4px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.09);border-radius:8px;color:#fff;font-size:11px;font-weight:700;text-align:left;cursor:pointer;font-family:inherit">${it[0]}</button>`).join('')}<div id="mg-rank-out" style="font-size:10px;color:rgba(255,255,255,.3);margin-top:4px">Select from LOWEST risk first</div></div>`},
basket:{nm:'🧺 Diversify Portfolio',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:6px">Spread 100 coins across 4+ types</div><div style="display:grid;grid-template-columns:1fr 1fr;gap:5px">${[['📈 Stocks','stocks'],['🏛️ Bonds','bonds'],['🏠 Property','realestate'],['💰 Cash','cash'],['🥇 Gold','gold'],['₿ Crypto','crypto']].map(it=>`<div style="background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.07);border-radius:8px;padding:7px"><div style="font-size:10px;font-weight:700;color:rgba(255,255,255,.6);margin-bottom:3px">${it[0]}</div><input type="range" min="0" max="50" value="0" oninput="mgBasket()" data-type="${it[1]}" style="width:100%;accent-color:var(--gold)"><div id="bv-${it[1]}" style="font-size:10px;color:var(--gold);text-align:center">0%</div></div>`).join('')}</div><div id="mg-basket-out" style="margin-top:6px;font-size:10px;color:rgba(255,255,255,.35)">Total: <span id="basket-total">0</span>%</div></div>`},
delay:{nm:'⏳ Patience Test',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:8px">You have 50 coins. Wait or spend?</div>${[[0,'⚡ Spend 50 now','rgba(239,68,68,.1)','rgba(239,68,68,.25)','#FCA5A5'],[1,'⏳ Wait 5s — get 80 coins','rgba(0,217,126,.07)','rgba(0,217,126,.2)','#6EE7B7'],[2,'🚀 Wait 10s — get 150 coins','rgba(168,85,247,.07)','rgba(168,85,247,.2)','#C4B5FD']].map(it=>`<button onclick="mgDelay(${it[0]})" style="width:100%;padding:9px;margin-bottom:5px;background:${it[2]};border:1px solid ${it[3]};border-radius:9px;color:${it[4]};font-size:11px;font-weight:700;cursor:pointer;font-family:inherit;text-align:left">${it[1]}</button>`).join('')}<div id="mg-delay-out" style="font-size:10px;color:rgba(255,255,255,.3)"></div></div>`},
budget:{nm:'📋 Zero-Base Budget',play:()=>`<div id="mg-wrap"><div style="font-size:11px;font-weight:800;color:var(--gold);margin-bottom:8px">ZERO-BASE BUDGET — Income: $1000</div>${[['🏠 Needs','needs',500],['🎮 Wants','wants',300],['💰 Savings','savings',200]].map(it=>`<div style="display:flex;align-items:center;gap:6px;margin-bottom:5px"><div style="font-size:10px;color:rgba(255,255,255,.5);width:80px">${it[0]}</div><input type="range" min="0" max="700" value="${it[2]}" oninput="mgBudget()" data-cat="${it[1]}" style="flex:1;accent-color:var(--gold)"><div id="bcat-${it[1]}" style="font-size:11px;font-weight:800;color:var(--gold);width:38px;text-align:right">$${it[2]}</div></div>`).join('')}<div id="mg-budget-out" style="font-size:10px;color:rgba(255,255,255,.35)">Left: $<span id="budget-left">0</span> — aim for 0!</div></div>`},
};
['match','chat','rate','chart','compare','tax','reit','globe','earn','score','launch','flow','lend','bond','fi'].forEach(t=>{MINI_GAMES[t]=MINI_GAMES.trivia;});
function renderMiniGame(l){
const mg=MINI_GAMES[l.game||'trivia']; if(!mg) return '';
return `<div style="background:rgba(168,85,247,.07);border:1px solid rgba(168,85,247,.16);border-radius:12px;padding:13px 14px;margin-top:12px"><div style="font-size:9px;font-weight:800;color:#C4B5FD;letter-spacing:1.2px;margin-bottom:8px;text-transform:uppercase">🎮 Mini Game — ${mg.nm}</div>${typeof mg.play==='function'?mg.play(l):''}</div>`;
}
function mgPick(btn,i,ans){
const wrap=btn.closest('#mg-wrap');
if(!wrap) return;
wrap.querySelectorAll('button').forEach((b,j)=>{b.disabled=true;if(j===ans)b.style.background='rgba(0,217,126,.2)';});
if(i!==ans){btn.style.background='rgba(239,68,68,.15)';}
if(i===ans){addCoins(15);addXP(10);toast('Mini-game correct! +15 🪙');}
}
function mgSort(btn,cat){
const tgt=document.getElementById('mg-'+cat); if(!tgt) return;
const sp=document.createElement('span');
sp.textContent=btn.textContent+' ';
sp.style.cssText='display:inline-block;background:rgba(255,255,255,.08);border-radius:4px;padding:1px 5px;margin:1px;font-size:10px;font-weight:700;color:#fff';
tgt.appendChild(sp);
btn.style.opacity='.3'; btn.disabled=true;
const left=document.querySelectorAll('#sort-items button:not([disabled])');
if(left.length===0){addCoins(20);addXP(15);const s=document.getElementById('mg-score');if(s){s.textContent='✅ Perfect sort! +20 🪙';s.style.color='#6EE7B7';}}
}
function mgCalcPick(btn,v,ans){
const wrap=btn.closest('#mg-wrap');
if(wrap) wrap.querySelectorAll('button').forEach(b=>b.disabled=true);
const out=document.getElementById('mg-calc-out');
if(v===ans){btn.style.background='rgba(0,217,126,.2)';if(out){out.textContent='🎉 Correct! $100×(1.1)^10=$259';out.style.color='#6EE7B7';}addCoins(20);addXP(15);toast('+20 🪙 compound bonus!');}
else{btn.style.background='rgba(239,68,68,.15)';if(out){out.textContent='Answer: $259 — P×(1+r)^n=100×(1.1)^10';out.style.color='#FCA5A5';}}
}
let rankOrder=[],rankExpected=['low','medium','high','extreme'];
function mgRankPick(btn,risk){
rankOrder.push(risk);btn.style.opacity='.5';btn.disabled=true;
const out=document.getElementById('mg-rank-out');
if(rankOrder.length===4){
const ok=rankOrder.every((r,i)=>r===rankExpected[i]);
if(out){out.textContent=ok?'✅ Correct order! +20 🪙':'❌ Correct: Savings→ETF→Stock→Bitcoin';out.style.color=ok?'#6EE7B7':'#FCA5A5';}
if(ok){addCoins(20);addXP(15);toast('+20 🪙 risk ranking master!');}
rankOrder=[];
} else {if(out)out.textContent='Selected: '+rankOrder.join('→')+' …continue';}
}
function mgBasket(){
const inputs=document.querySelectorAll('[data-type]');
let total=0,filled=0;
inputs.forEach(inp=>{const v=parseInt(inp.value)||0;total+=v;const d=document.getElementById('bv-'+inp.dataset.type);if(d)d.textContent=v+'%';if(v>0)filled++;});
const bt=document.getElementById('basket-total');if(bt)bt.textContent=total;
const out=document.getElementById('mg-basket-out');
if(total===100&&filled>=4&&out){out.innerHTML='🎉 <strong style="color:#6EE7B7">Diversified! +25 🪙</strong>';addCoins(25);addXP(20);toast('+25 🪙 diversification master!');inputs.forEach(i=>i.disabled=true);}
else if(out)out.innerHTML='Total: <span id="basket-total">'+total+'</span>% across '+filled+' types';
}
function mgBudget(){
const inputs=document.querySelectorAll('[data-cat]');
let total=0;
inputs.forEach(inp=>{const v=parseInt(inp.value)||0;total+=v;const d=document.getElementById('bcat-'+inp.dataset.cat);if(d)d.textContent='$'+v;});
const left=1000-total;
const l=document.getElementById('budget-left');if(l)l.textContent=Math.abs(left);
const out=document.getElementById('mg-budget-out');
if(out){if(left===0){out.innerHTML='🎉 <strong style="color:#6EE7B7">Zero-based! +25 🪙</strong>';addCoins(25);addXP(20);}
else out.innerHTML=(left>0?'Left':'Over')+': $'+Math.abs(left)+(left<0?' — reduce!':'');}
}
function mgDelay(choice){
document.querySelectorAll('#mg-wrap button').forEach(b=>b.disabled=true);
const out=document.getElementById('mg-delay-out');
if(choice===0){if(out){out.textContent='Spent immediately. 50 coins — missed bigger rewards.';out.style.color='#FCA5A5';}}
else if(choice===1){if(out){out.textContent='Waiting 5s…';out.style.color='#6EE7B7';}setTimeout(()=>{addCoins(80);addXP(20);toast('+80 🪙 patience reward!');if(out)out.textContent='✅ 80 coins earned — patience pays!';},5000);}
else{if(out){out.textContent='Waiting 10s…';out.style.color='#C4B5FD';}setTimeout(()=>{addCoins(150);addXP(30);toast('+150 🪙 legendary patience!');if(out)out.textContent='🏆 150 coins — wealth mindset!';},10000);}
}
/* ── WELCOME PAGE TABS/* ── WELCOME PAGE TABS ───────────────────────────────────── */
function wTab(n){
['wp-a','wp-b','wp-c'].forEach(function(id,i){
var el=document.getElementById(id);
if(el){el.style.display=(i===n-1)?'block':'none';
if(i===n-1) el.classList.add('show'); else el.classList.remove('show');}
});
var classes=['active-signup','active-plogin','active-play'];
['wt-signup','wt-login','wt-child'].forEach(function(id,i){
var el=document.getElementById(id);
if(!el) return;
el.className='auth-tab-btn';
if(i===n-1) el.classList.add(classes[i]);
});
}
function doWelcomeSignup(){
var name=(document.getElementById('wps-name')||{}).value||'';
var email=(document.getElementById('wps-email')||{}).value||'';
var pass=(document.getElementById('wps-pass')||{}).value||'';
var country=(document.getElementById('wps-country')||{}).value||'UAE';
var err=document.getElementById('wps-err');
name=name.trim(); email=email.trim().toLowerCase();
if(!name||!email||!pass){err.textContent='Please fill in all fields.';err.style.display='block';return;}
if(pass.length<6){err.textContent='Password must be at least 6 characters.';err.style.display='block';return;}
var res=DB.createParent({name:name,email:email,password:pass,country:country});
if(!res.ok){err.textContent=res.msg||'Signup failed.';err.style.display='block';return;}
err.style.display='none';
CU={role:'parent',data:res.data}; DB.saveSession({role:'parent',id:email});
goPage('page-addchild');
}
function doWelcomeParentLogin(){
var email=(document.getElementById('wpl-email')||{}).value||'';
var pass=(document.getElementById('wpl-pass')||{}).value||'';
var err=document.getElementById('wpl-err');
email=email.trim().toLowerCase();
if(!email||!pass){err.textContent='Enter email and password.';err.style.display='block';return;}
var res=DB.loginParent({email:email,password:pass});
if(!res.ok){err.textContent=res.msg||'Login failed.';err.style.display='block';return;}
err.style.display='none';
CU={role:'parent',data:res.data}; DB.saveSession({role:'parent',id:email});
goPage('page-pdash');
}
function doWelcomeChildLogin(){
var username=(document.getElementById('wcl-user')||{}).value||'';
var pass=(document.getElementById('wcl-pass')||{}).value||'';
var err=document.getElementById('wcl-err');
username=username.trim().toLowerCase().replace(/\s+/g,'_');
if(!username||!pass){err.textContent='Enter your username and password.';err.style.display='block';return;}
var res=DB.loginChild({username:username,password:pass});
if(!res.ok){err.textContent=res.msg||'Login failed.';err.style.display='block';return;}
err.style.display='none';
CU={role:'child',data:res.data}; S=res.data.S;
goPage('page-home'); initMarketPrices(); startEventScheduler(); loadLimitOrders();
}
/* ── PAGE + SHEET NAVIGATION ────────────────────────────── */
function goPage(id){
document.querySelectorAll('.page').forEach(p=>p.classList.remove('active'));
const el=document.getElementById(id);
if(el){ el.classList.add('active'); el.scrollTop=0; window.scrollTo(0,0); }
// Auto-load data for the page
if(id==='page-home') renderHome();
if(id==='page-learn') renderLearn();
if(id==='page-market') renderMarket();
if(id==='page-brain') renderBrain();
if(id==='page-world') renderWorld();
if(id==='page-leaderboard') renderLeaderboard();
if(id==='page-achievements') renderAchievements();
if(id==='page-goals') renderGoals();
if(id==='page-kai') loadKai();
if(id==='page-pdash') renderPDash();
if(id==='page-market') renderLimitOrders();
if(id==='page-invest-club') renderInvestClub();
if(id==='page-credit') renderCreditPage();
if(id==='page-simulator') renderSimulatorPage();
if(id==='page-personality') renderPersonalityPage();
if(id==='page-curriculum'){ renderCurriculumMap(); const b=document.getElementById('curr-done-badge'); if(b) b.textContent=(S.learningDone||[]).length+'/23'; }
if(id==='page-certs') renderCertsPage();
}
function openSheet(id){ document.getElementById(id)?.classList.add('open'); }
function closeSheet(id){ document.getElementById(id)?.classList.remove('open'); }
/* ── TOAST ──────────────────────────────────────────────── */
let toastT=null;
function toast(msg,dur=2200){
const t=document.getElementById('toast');
t.textContent=msg; t.classList.add('show');
clearTimeout(toastT);
toastT=setTimeout(()=>t.classList.remove('show'),dur);
}
/* ── XP POP ─────────────────────────────────────────────── */
function xpPop(txt){
const el=document.createElement('div');
el.className='xp-pop'; el.textContent=txt;
el.style.cssText=`left:${15+Math.random()*55}%;top:${25+Math.random()*25}%`;
document.body.appendChild(el);
setTimeout(()=>el.remove(),1500);
}
/* ── CONFETTI ───────────────────────────────────────────── */
function confetti(){
const cols=['#F59E0B','#00D97E','#7C3AED','#EF4444','#3B82F6'];
for(let i=0;i<32;i++){
const el=document.createElement('div');
const c=cols[i%cols.length];
el.style.cssText=`position:fixed;width:${6+Math.random()*8}px;height:${6+Math.random()*8}px;
background:${c};left:${Math.random()*100}%;top:-8px;z-index:9999;
border-radius:${Math.random()>.5?'50%':'2px'};pointer-events:none`;
document.body.appendChild(el);
el.animate([
{transform:`translate(${(Math.random()-.5)*200}px,0) rotate(0deg)`,opacity:1},
{transform:`translate(${(Math.random()-.5)*200}px,${window.innerHeight+20}px) rotate(${720*Math.random()}deg)`,opacity:0}
],{duration:1600+Math.random()*1000}).onfinish=()=>el.remove();
}
}
/* ── LEVEL SYSTEM ───────────────────────────────────────── */
const LEVELS=[
{lv:1,title:'Rookie',icon:'🌱',req:0,coins:0},
{lv:2,title:'Saver',icon:'🌿',req:100,coins:50},
{lv:3,title:'Explorer',icon:'🌳',req:250,coins:80},
{lv:4,title:'Builder',icon:'📊',req:500,coins:120},
{lv:5,title:'Strategist',icon:'⚡',req:900,coins:180},
{lv:6,title:'Architect',icon:'🏗️',req:1400,coins:250},
{lv:7,title:'Wizard',icon:'🧙',req:2000,coins:350},
{lv:8,title:'Master',icon:'🔥',req:2800,coins:500},
{lv:9,title:'Legend',icon:'💫',req:3700,coins:700},
{lv:10,title:'Money God',icon:'👑',req:5000,coins:1000},
];
function getLv(){ for(let i=LEVELS.length-1;i>=0;i--) if((S.xp||0)>=LEVELS[i].req) return LEVELS[i]; return LEVELS[0]; }
function getNextLv(){ const c=getLv(); return LEVELS.find(l=>l.lv===c.lv+1)||c; }
function addXP(n){
const prev=getLv().lv;
S.xp=(S.xp||0)+n;
const next=getLv();
if(next.lv>prev && next.coins>0){
S.goldCoins=(S.goldCoins||0)+next.coins;
showLvlUp(next);
}
xpPop('+'+n+' XP');
persistS();
}
function addCoins(n){
S.goldCoins=(S.goldCoins||0)+n;
xpPop('🪙 +'+n);
document.getElementById('coins-val').textContent=S.goldCoins;
persistS();
}
function showLvlUp(lv){
document.getElementById('lu-ttl').textContent='LEVEL '+lv.lv+'! '+lv.icon;
document.getElementById('lu-sub').textContent='You are now a '+lv.title+'!';
document.getElementById('lu-det').textContent='🪙 +'+lv.coins+' Gold Coins bonus!';
document.getElementById('lvl-overlay').classList.add('show');
confetti();
}
function closeLvlUp(){ document.getElementById('lvl-overlay').classList.remove('show'); checkAchs(); }
/* ── DATA ───────────────────────────────────────────────── */
const GOALS_DB={
gaming:{icon:'🎮',name:'Gaming Setup',targets:{USD:300,AED:1100,EUR:280,GBP:240,SAR:1125,BTC:0.005}},
sneakers:{icon:'👟',name:'Sneakers',targets:{USD:200,AED:735,EUR:185,GBP:160,SAR:750,BTC:0.003}},
trip:{icon:'✈️',name:'Travel Fund',targets:{USD:1000,AED:3675,EUR:930,GBP:800,SAR:3750,BTC:0.016}},
college:{icon:'🎓',name:'College Fund',targets:{USD:5000,AED:18375,EUR:4650,GBP:4000,SAR:18750,BTC:0.08}},
business:{icon:'💼',name:'Mini Business',targets:{USD:500,AED:1840,EUR:465,GBP:400,SAR:1875,BTC:0.008}},
custom:{icon:'⭐',name:'My Goal',targets:{USD:300,AED:1100,EUR:280,GBP:240,SAR:1125,BTC:0.005}},
};
const FA=[
// ── STOCKS ─────────────────────────────────────────────
{id:'aapl',cat:'stocks',ic:'🍎',nm:'Apple',sym:'AAPL',px:185,risk:'low',col:'#6B7280',vol:.08,desc:'iPhone · Mac · Services · Most valuable company'},
{id:'nvda',cat:'stocks',ic:'🖥️',nm:'NVIDIA',sym:'NVDA',px:875,risk:'med',col:'#76B900',vol:.18,desc:'Powers all AI with its GPUs · Data centers'},
{id:'tsla',cat:'stocks',ic:'⚡',nm:'Tesla',sym:'TSLA',px:240,risk:'high',col:'#CC0000',vol:.28,desc:'Electric vehicles · Solar · Robotics · Bold bets'},
{id:'amzn',cat:'stocks',ic:'📦',nm:'Amazon',sym:'AMZN',px:182,risk:'med',col:'#FF9900',vol:.14,desc:'E-commerce + AWS cloud + Alexa · Huge moat'},
{id:'msft',cat:'stocks',ic:'🪟',nm:'Microsoft',sym:'MSFT',px:415,risk:'low',col:'#0078D4',vol:.11,desc:'Office · Azure cloud · OpenAI partner'},
{id:'googl',cat:'stocks',ic:'🔍',nm:'Alphabet',sym:'GOOGL',px:165,risk:'med',col:'#4285F4',vol:.13,desc:'Google Search · YouTube · Cloud · DeepMind'},
// ── ETFs ────────────────────────────────────────────────
{id:'spy',cat:'etf',ic:'🏛️',nm:'S&P 500 ETF',sym:'SPY',px:525,risk:'low',col:'#1E40AF',vol:.06,desc:'Own 500 top US companies · Pays dividends',divYield:.013},
{id:'qqq',cat:'etf',ic:'💡',nm:'NASDAQ 100 ETF',sym:'QQQ',px:448,risk:'low',col:'#7C3AED',vol:.10,desc:'Top 100 tech & growth companies'},
{id:'icln',cat:'etf',ic:'🌱',nm:'Clean Energy ETF',sym:'ICLN',px:17,risk:'med',col:'#059669',vol:.16,desc:'Solar · Wind · Green future investing'},
{id:'vwra',cat:'etf',ic:'🌍',nm:'World ETF',sym:'VWRA',px:115,risk:'low',col:'#0EA5E9',vol:.08,desc:'Own every major market on Earth at once'},
// ── GOLD & COMMODITIES ─────────────────────────────────
{id:'gld',cat:'gold',ic:'🥇',nm:'Gold ETF',sym:'GLD',px:218,risk:'low',col:'#D97706',vol:.05,desc:'Safe-haven store of value · 5,000-year track record'},
{id:'silver',cat:'gold',ic:'🥈',nm:'Silver ETF',sym:'SLV',px:26,risk:'med',col:'#94A3B8',vol:.14,desc:'Industrial metal + store of value · Cheaper than gold'},
{id:'oil',cat:'gold',ic:'🛢️',nm:'Oil ETF',sym:'USO',px:74,risk:'high',col:'#78350F',vol:.22,desc:'Crude oil prices · Affected by global events'},
// ── CRYPTO ─────────────────────────────────────────────
{id:'btc',cat:'crypto',ic:'₿',nm:'Bitcoin',sym:'BTC',px:67000,risk:'extreme',col:'#F59E0B',vol:.38,desc:'Digital gold · Fixed supply 21M · 15-year track record'},
{id:'eth',cat:'crypto',ic:'💎',nm:'Ethereum',sym:'ETH',px:3500,risk:'high',col:'#6366F1',vol:.32,desc:'Smart contracts · DeFi · NFTs · Real utility'},
{id:'sol',cat:'crypto',ic:'☀️',nm:'Solana',sym:'SOL',px:165,risk:'extreme',col:'#8B5CF6',vol:.48,desc:'Fastest blockchain · Low fees · Gaming & NFTs'},
// ── BONDS ───────────────────────────────────────────────
{id:'ustb',cat:'bonds',ic:'🏛️',nm:'US Treasury',sym:'USTB',px:98,risk:'low',col:'#2563EB',vol:.02,desc:'Safest investment · 4.5% annual yield',divYield:.045},
{id:'corp',cat:'bonds',ic:'🏢',nm:'Corp Bonds ETF',sym:'LQD',px:107,risk:'low',col:'#0891B2',vol:.04,desc:'Corporate bonds · 5.2% yield',divYield:.052},
// ── REAL ESTATE ─────────────────────────────────────────
{id:'vnq',cat:'realestate',ic:'🏠',nm:'US REIT Fund',sym:'VNQ',px:85,risk:'low',col:'#DC2626',vol:.07,desc:'Own real estate · 4% dividend yield',divYield:.04},
{id:'emb',cat:'realestate',ic:'🏙️',nm:'Dubai REIT',sym:'EMB',px:52,risk:'med',col:'#B45309',vol:.10,desc:'UAE property market exposure · High rental yields'},
];
const RISK_STYLE={low:'risk-low',med:'risk-med',high:'risk-high',extreme:'risk-ext'};
const CAT_LABELS={all:'All 🌐',stocks:'Stocks 📈',etf:'ETFs 🏛️',gold:'Gold & Commodities 🥇',crypto:'Crypto ₿',bonds:'Bonds 🏢',realestate:'Real Estate 🏠'};
/* ── WORLD EVENTS ENGINE ──────────────────────────────────── */
const WORLD_EVENTS=[
{id:'tech_boom',title:'Tech Breakthrough!',desc:'AI chips surge. Tech stocks +12%',sectors:['aapl','nvda','msft','googl','amzn','qqq'],delta:0.12,type:'positive'},
{id:'crypto_reg',title:'Crypto Regulation News',desc:'Government clampdown fears. Crypto -18%',sectors:['btc','eth','sol'],delta:-0.18,type:'negative'},
{id:'oil_cut',title:'OPEC Supply Cut',desc:'Oil producers reduce output. Energy surges +15%',sectors:['oil'],delta:0.15,type:'positive'},
{id:'recession',title:'Recession Fears',desc:'GDP disappoints. Broad market drops -8%',sectors:['aapl','tsla','amzn','spy'],delta:-0.08,type:'negative'},
{id:'green_deal',title:'Climate Summit Deal',desc:'Global green energy pact. Clean energy +20%',sectors:['icln','gld'],delta:0.20,type:'positive'},
{id:'gold_safe',title:'Global Uncertainty',desc:'Investors flee to safety. Gold surges +10%',sectors:['gld','silver','ustb','corp'],delta:0.10,type:'positive'},
{id:'rate_hike',title:'Interest Rate Hike',desc:'Central bank raises rates. Growth stocks -10%',sectors:['nvda','tsla','eth','sol'],delta:-0.10,type:'negative'},
{id:'re_boom',title:'Real Estate Surge',desc:'Housing demand record high. REITs +14%',sectors:['vnq','emb'],delta:0.14,type:'positive'},
{id:'dividend_day',title:'Dividend Payout Day!',desc:'Holdings pay quarterly dividends',sectors:[],delta:0,type:'dividend'},
{id:'flash_crash',title:'Flash Crash!',desc:'Algorithmic selling triggers broad drop -15%',sectors:['aapl','nvda','msft','spy','qqq'],delta:-0.15,type:'negative'},
];
let activeEvent=null, eventTimer=null, faPrices={};
function initMarketPrices(){
FA.forEach(function(a){ if(!faPrices[a.id]) faPrices[a.id]=a.px; });
}
function triggerWorldEvent(){
const e=WORLD_EVENTS[Math.floor(Math.random()*WORLD_EVENTS.length)];
activeEvent=e;
if(e.type==='dividend'){ processDividends(); return; }
e.sectors.forEach(function(id){
const a=FA.find(function(x){return x.id===id;});
if(a){ if(!faPrices[id]) faPrices[id]=a.px; a.px=+(a.px*(1+e.delta)).toFixed(2); }
});
showEventBanner(e);
checkPanicOrFOMO(e);
clearTimeout(eventTimer);
eventTimer=setTimeout(function(){
e.sectors.forEach(function(id){
const a=FA.find(function(x){return x.id===id;});
if(a&&faPrices[id]) a.px=faPrices[id];
});
activeEvent=null;
const banner=document.getElementById('event-banner');
if(banner) banner.remove();
if(CU&&CU.role==='child') renderMarket();
},90000);
}
function showEventBanner(e){
const old=document.getElementById('event-banner'); if(old) old.remove();
const d=document.createElement('div');
d.id='event-banner';
const bg=e.type==='positive'?'linear-gradient(135deg,#064e3b,#065f46)':e.type==='negative'?'linear-gradient(135deg,#7f1d1d,#991b1b)':'linear-gradient(135deg,#1e1b4b,#312e81)';
d.style.cssText='position:fixed;top:0;left:0;right:0;z-index:999;background:'+bg+';padding:14px 16px;box-shadow:0 4px 20px rgba(0,0,0,.5);cursor:pointer';
d.innerHTML='<div style="font-size:15px;font-weight:900;margin-bottom:2px">'+e.title+'</div><div style="font-size:12px;color:rgba(255,255,255,.7)">'+e.desc+'</div><div style="font-size:10px;color:rgba(255,255,255,.4);margin-top:3px">Tap to dismiss. Lasts 90 seconds.</div>';
d.onclick=function(){ d.remove(); };
document.body.appendChild(d);
if(CU&&CU.role==='child') renderMarket();
toast(e.title,'#F59E0B');
}
function processDividends(){
let total=0;
FA.filter(function(a){return a.divYield;}).forEach(function(a){
const qty=(S.mktPort&&S.mktPort[a.id])||0;
if(qty>0){
const div=+(a.px*a.divYield*qty).toFixed(2);
total+=div; S.cash=(S.cash||0)+div;
addAct(a.ic,a.nm,'Dividend received','+$'+div.toFixed(2),'#00D97E');
}
});
if(total>0){
persistS(); checkAchs();
showEventBanner({title:'Dividend Payout!',desc:'You received $'+total.toFixed(2)+' in dividends.',type:'dividend',sectors:[]});
toast('Dividend $'+total.toFixed(2)+' received!','#00D97E');
if(CU&&CU.role==='child'){renderHome();}
} else {
toast('Dividend day - buy dividend assets to earn!','#00D97E');
}
}
function checkPanicOrFOMO(e){
S._lastEvent={id:e.id,type:e.type,time:Date.now()}; persistS();
}
function startEventScheduler(){
if(window._evtSched) return; window._evtSched=true;
(function schedNext(){
const ms=(3+Math.random()*4)*60*1000;
setTimeout(function(){ if(CU&&CU.role==='child'){ triggerWorldEvent(); } schedNext(); },ms);
})();
}
/* ── LIMIT ORDERS ──────────────────────────────────────────── */
let limitOrders=[];
function loadLimitOrders(){ limitOrders=S.limitOrders||[]; }
function addLimitOrder(assetId,type,qty,targetPx){
loadLimitOrders();
const o={id:'lo_'+Date.now(),assetId:assetId,type:type,qty:+qty,targetPx:+targetPx,createdAt:Date.now()};
limitOrders.push(o); S.limitOrders=limitOrders; persistS();
toast('Limit '+type+' set @ $'+targetPx,'#A855F7');
addXP(2); recordBeh('limit_order',{type:type});
renderLimitOrders();
}
function cancelLimitOrder(id){
loadLimitOrders();
limitOrders=limitOrders.filter(function(o){return o.id!==id;});
S.limitOrders=limitOrders; persistS();
toast('Limit order cancelled','#818CF8'); renderLimitOrders();
}
function checkLimitOrders(){
loadLimitOrders(); if(!limitOrders.length) return;
const filled=[]; let changed=false;
limitOrders=limitOrders.filter(function(o){
const a=FA.find(function(x){return x.id===o.assetId;}); if(!a) return false;
const hit=(o.type==='buy'&&a.px<=o.targetPx)||(o.type==='sell'&&a.px>=o.targetPx);
if(!hit) return true;
if(o.type==='buy'){
const cost=a.px*o.qty;
if((S.cash||0)>=cost){
S.cash-=cost; S.mktPort=S.mktPort||{}; S.mktPort[a.id]=(S.mktPort[a.id]||0)+o.qty;
addAct(a.ic,a.nm,'Limit Buy filled','-$'+cost.toFixed(0),'#818CF8'); filled.push(o); changed=true;
}
} else {
const qty=Math.min(o.qty,(S.mktPort&&S.mktPort[a.id])||0);
if(qty>0){
const proceeds=a.px*qty; S.cash=(S.cash||0)+proceeds;
if(S.mktPort){ S.mktPort[a.id]-=qty; if(!S.mktPort[a.id]) delete S.mktPort[a.id]; }
addAct(a.ic,a.nm,'Limit Sell filled','+$'+proceeds.toFixed(0),'#00D97E'); filled.push(o); changed=true;
}
}
return false;
});
if(changed){ S.limitOrders=limitOrders; persistS(); toast(filled.length+' limit order(s) executed!','#00D97E'); if(CU&&CU.role==='child'){renderMarket();renderHome();} }
}
function renderLimitOrders(){
const el=document.getElementById('limit-orders-list'); if(!el) return;
loadLimitOrders();
if(!limitOrders.length){ el.innerHTML='<div style="color:var(--sub);font-size:12px;padding:8px 0">No active limit orders</div>'; return; }
el.innerHTML=limitOrders.map(function(o){
const a=FA.find(function(x){return x.id===o.assetId;})||{nm:o.assetId,ic:'?'};
const typeCol=o.type==='buy'?'#818CF8':'#00D97E';
return '<div style="display:flex;align-items:center;gap:8px;padding:8px;background:rgba(255,255,255,.04);border-radius:8px;margin-bottom:6px">'
+'<span style="font-size:16px">'+a.ic+'</span>'
+'<div style="flex:1"><div style="font-size:12px;font-weight:700">'+a.nm+' x'+o.qty+'</div>'
+'<div style="font-size:10px;color:'+typeCol+';font-weight:800">'+o.type.toUpperCase()+' @ $'+o.targetPx+'</div></div>'
+'<button data-lo-id="'+o.id+'" class="lo-cancel-btn" style="padding:4px 10px;background:rgba(239,68,68,.15);border:1px solid rgba(239,68,68,.3);border-radius:6px;color:#EF4444;font-size:11px;font-weight:700;cursor:pointer;font-family:inherit">Cancel</button>'
+'</div>';
}).join('');
el.querySelectorAll('.lo-cancel-btn').forEach(function(btn){
btn.onclick=function(){ cancelLimitOrder(btn.dataset.loId); };
});
}
// Event delegation for limit order cancel
document.addEventListener('click',function(e){
const btn=e.target.closest('.lo-cancel-btn');
if(btn){ cancelLimitOrder(btn.dataset.loId); }
});
// Check limit orders every 30s
setInterval(checkLimitOrders,30000);
/* ── RISK PERSONA ENGINE ──────────────────────────────────── */
const RISK_PERSONAS=[
{id:'cautious',min:0,max:30,title:'The Cautious Collector 🛡️',desc:'You prefer safety over big swings. Bonds and blue chips are your comfort zone.',color:'#22D3EE'},
{id:'balanced',min:31,max:55,title:'The Balanced Builder ⚖️',desc:'Smart mix of growth and safety. You understand diversification.',color:'#A855F7'},
{id:'bold',min:56,max:75,title:'The Bold Venturer 🚀',desc:'High-risk, high-reward mindset. Great instincts but watch the volatility!',color:'#F59E0B'},
{id:'daredevil',min:76,max:100,title:'The Market Daredevil 🎰',desc:'All-in on high risk assets. Exciting — but watch your safety net!',color:'#EF4444'},
];
function getRiskPersona(){
const beh=getBeh();
const port=S.mktPort||{};
let riskScore=beh.risk||50;
// Adjust based on actual portfolio composition
const totalVal=Object.entries(port).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0);
if(totalVal>0){
const highRiskVal=Object.entries(port).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id&&(a?.risk==='extreme'||a?.risk==='high'));return t+(a?a.px*q:0);},0);
const cryptoAlloc=Object.entries(port).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id&&x.cat==='crypto');return t+(a?a.px*q:0);},0)/Math.max(1,totalVal);
riskScore=Math.min(100,riskScore+(cryptoAlloc*60));
}
return RISK_PERSONAS.find(p=>riskScore>=p.min&&riskScore<=p.max)||RISK_PERSONAS[1];
}
/* ── SENTIMENT DETECTION ──────────────────────────────────── */
function detectSentiment(action){
const ev=S._lastEvent;
if(!ev||Date.now()-ev.time>120000) return null; // only flag within 2min of event
if(action==='sell'&&ev.type==='negative') return 'panic_sell';
if(action==='buy'&&ev.type==='positive') return 'fomo_buy';
if(action==='buy'&&ev.type==='negative') return 'contrarian_buy'; // good!
if(action==='sell'&&ev.type==='positive') return 'discipline_sell'; // good!
return null;
}
function handleSentiment(sentiment, assetName){
if(!sentiment) return;
const msgs={
panic_sell:{msg:'⚠️ Panic Selling Alert! Selling during a dip often locks in losses. Legendary investors like Warren Buffett say: be greedy when others are fearful.',lesson:'Try the Loss Aversion brain game to understand this bias.',beh:'bad',type:'neg'},
fomo_buy:{msg:'⚠️ FOMO Buy Detected! Buying after a price spike means you might be late to the party. Check if the price is still good value.',lesson:'Play the FOMO Detector game to train this instinct.',beh:'bad',type:'neg'},
contrarian_buy:{msg:'🧠 Contrarian Move! Buying during a dip takes courage and discipline — exactly what the best investors do.',lesson:'+5 bonus XP for smart contrarian thinking!',beh:'good',type:'pos'},
discipline_sell:{msg:'✅ Disciplined Sell! Taking profit at a peak and resisting greed shows excellent emotional control.',lesson:'+5 bonus XP for emotional discipline!',beh:'good',type:'pos'},
};
const m=msgs[sentiment]; if(!m) return;
// Show cooling-off mini lesson
showSentimentAlert(m);
if(m.beh==='bad') recordBeh('emotional_trade',{sentiment});
else { addXP(5); recordBeh('rational_trade',{sentiment}); }
}
function showSentimentAlert(m){
const d=document.createElement('div');
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9990;display:flex;align-items:flex-end;justify-content:center;padding:20px;animation:fadeIn .3s ease';
d.innerHTML='<div style="background:#1e1b2e;border:1px solid rgba(255,255,255,.15);border-radius:20px;padding:22px;max-width:360px;width:100%">'
+'<div style="font-size:16px;font-weight:900;margin-bottom:8px">'+m.msg+'</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.6);margin-bottom:16px;line-height:1.6">'+m.lesson+'</div>'
+'<button onclick="this.parentElement.parentElement.remove()" style="width:100%;padding:11px;background:var(--primary);border:none;border-radius:12px;color:#fff;font-size:14px;font-weight:800;cursor:pointer;font-family:inherit">Got it — keep learning!</button></div>';
document.body.appendChild(d);
}
/* ── LIFE CROSSROADS — AI-GENERATED SCENARIOS ─────────────── */
let crossroadsActive=false;
async function triggerCrossroads(){
if(crossroadsActive) return;
crossroadsActive=true;
const nw=(S.cash||0)+Object.entries(S.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0);
const prompt='You are creating a financial decision challenge for a '+( S.age||12)+'-year-old. '
+'Their portfolio: cash $'+(S.cash||0).toFixed(0)+', net worth $'+nw.toFixed(0)+', goals: '+(S.goals||[]).map(g=>g.name).join(', ')+'.'
+'Generate ONE "Life Crossroads" dilemma in this exact JSON format (no other text): '
+'{"title":"short dramatic title","scenario":"2-sentence setup","choice_a":"option A label","choice_b":"option B label","wise_choice":"a"or"b","lesson":"1 sentence explaining the smart choice"}';
const sys='You are a financial education game AI. Output ONLY valid JSON. No thinking. No markdown.';
try{
const raw=await k2(sys,prompt,200);
const clean=raw.replace(/```json|```/g,'').trim();
const data=JSON.parse(clean);
showCrossroads(data);
}catch(e){
// Fallback crossroads
showCrossroads({
title:'Emergency Fund Test 🚨',
scenario:'Your virtual laptop just broke and costs $200 to fix. But you are 80% toward your savings goal.',
choice_a:'Use savings to fix laptop immediately',
choice_b:'Wait, keep saving — find another solution',
wise_choice:'b',
lesson:'Emergency funds are for real emergencies. Before spending savings, ask: is this truly urgent?'
});
crossroadsActive=false;
}
}
function showCrossroads(data){
const d=document.createElement('div');
d.id='crossroads-modal';
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.9);z-index:9991;display:flex;align-items:center;justify-content:center;padding:20px;animation:fadeIn .3s ease';
const inner=document.createElement('div');
inner.style.cssText='background:linear-gradient(135deg,#1e1b4b,#0f172a);border:1px solid rgba(168,85,247,.3);border-radius:20px;padding:22px;max-width:360px;width:100%';
inner.innerHTML='<div style="font-size:11px;font-weight:800;color:#A855F7;margin-bottom:8px;letter-spacing:1px">LIFE CROSSROADS</div>'
+'<div style="font-size:16px;font-weight:900;margin-bottom:10px" id="cr-title"></div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.7);line-height:1.65;margin-bottom:18px" id="cr-scenario"></div>'
+'<button id="cr-btn-a" style="width:100%;padding:12px;background:rgba(168,85,247,.2);border:1.5px solid rgba(168,85,247,.4);border-radius:12px;color:#fff;font-size:13px;font-weight:700;cursor:pointer;margin-bottom:8px;text-align:left;font-family:inherit"></button>'
+'<button id="cr-btn-b" style="width:100%;padding:12px;background:rgba(168,85,247,.2);border:1.5px solid rgba(168,85,247,.4);border-radius:12px;color:#fff;font-size:13px;font-weight:700;cursor:pointer;text-align:left;font-family:inherit"></button>';
d.appendChild(inner);
document.body.appendChild(d);
document.getElementById('cr-title').textContent=data.title;
document.getElementById('cr-scenario').textContent=data.scenario;
document.getElementById('cr-btn-a').textContent='A: '+(data.choice_a||'Option A');
document.getElementById('cr-btn-b').textContent='B: '+(data.choice_b||'Option B');
document.getElementById('cr-btn-a').onclick=()=>resolveCrossroads('a',data.wise_choice,data.lesson);
document.getElementById('cr-btn-b').onclick=()=>resolveCrossroads('b',data.wise_choice,data.lesson);
crossroadsActive=false;
}
function escStr(s){ return (s||'').replace(/'/g,"\'").replace(/"/g,'&quot;'); }
function resolveCrossroads(chosen,wise,lesson){
const correct=chosen===wise;
document.getElementById('crossroads-modal')?.remove();
const d=document.createElement('div');
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9991;display:flex;align-items:flex-end;padding:20px;animation:fadeIn .3s ease';
const box=document.createElement('div');
box.style.cssText='background:#1e1b2e;border:1px solid rgba(255,255,255,.15);border-radius:20px;padding:22px;width:100%;max-width:360px;margin:0 auto';
box.innerHTML=(correct?'<div style="font-size:20px;margin-bottom:8px">✅ Smart Choice!</div>':'<div style="font-size:20px;margin-bottom:8px">Hmm, not quite…</div>')
+'<div style="font-size:13px;color:rgba(255,255,255,.7);line-height:1.65;margin-bottom:16px" id="cr-lesson"></div>'
+(correct?'<div style="color:#00D97E;font-size:13px;font-weight:800;margin-bottom:12px">+20 XP + 5 Gold Coins!</div>':'')
+'<button style="width:100%;padding:11px;background:var(--primary);border:none;border-radius:12px;color:#fff;font-size:14px;font-weight:800;cursor:pointer;font-family:inherit">Continue</button>';
d.appendChild(box);
document.body.appendChild(d);
document.getElementById('cr-lesson').textContent=lesson||'Keep learning and making smart choices!';
box.querySelector('button').onclick=()=>d.remove();
if(correct){ addXP(20); addCoins(5); recordBeh('crossroads_correct',{}); }
else recordBeh('crossroads_wrong',{});
persistS(); checkAchs();
}
/* ── CREDIT SCORE ─────────────────────────────────────────── */
function getCreditScore(){
const s=S;
let score=600; // base
score+=Math.min(80,(s.learningDone||[]).length*6); // lessons: up to +80
score+=Math.min(60,(s.completedMissions||[]).length*4); // missions: up to +60
score+=Math.min(80,(s.goals||[]).filter(g=>g.saved>=g.target).length*40); // completed goals: +40 each
score+=Math.min(50,Math.floor((s.streak||1)/3)*5); // streak: up to +50
score-=Math.min(80,(s.decisions||[]).filter(d=>d.negative).length*8); // bad decisions: -8 each
const beh=getBeh();
score+=Math.round((beh.discipline-50)*0.5); // discipline
score+=Math.round((beh.planning-50)*0.5);
return Math.min(850,Math.max(300,score));
}
function getCreditGrade(score){
if(score>=800) return {grade:'AAA',label:'Excellent',color:'#00D97E'};
if(score>=740) return {grade:'AA',label:'Very Good',color:'#6EE7B7'};
if(score>=670) return {grade:'A',label:'Good',color:'#A855F7'};
if(score>=580) return {grade:'B',label:'Fair',color:'#F59E0B'};
return {grade:'C',label:'Needs Work',color:'#EF4444'};
}
/* ── CHARITABLE GIVING ────────────────────────────────────── */
const CHARITIES=[
{id:'edu',name:'Education Fund 📚',desc:'Helps kids access quality education worldwide'},
{id:'tree',name:'Plant a Tree 🌳',desc:'Reforestation project — one tree per $5 donated'},
{id:'water',name:'Clean Water 💧',desc:'Provides clean drinking water to rural villages'},
{id:'animal',name:'Animal Shelter 🐾',desc:'Feeds and rehomes abandoned animals'},
{id:'food',name:'Food Bank 🍱',desc:'Feeds hungry families in your community'},
];
let charityId='edu', charityAmt=10;
function openCharity(){
const old=document.getElementById('charity-modal'); if(old) old.remove();
const d=document.createElement('div');
d.id='charity-modal';
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9990;display:flex;align-items:flex-end;padding:20px;animation:fadeIn .3s ease';
const box=document.createElement('div');
box.style.cssText='background:#0f172a;border:1px solid rgba(0,217,126,.2);border-radius:20px 20px 16px 16px;padding:22px;width:100%;max-width:400px;margin:0 auto';
box.innerHTML='<div style="font-size:16px;font-weight:900;margin-bottom:4px">Charitable Giving</div>'
+'<div style="font-size:12px;color:rgba(255,255,255,.5);margin-bottom:14px">Donate to unlock Philanthropist achievements</div>'
+'<div id="charity-list" style="display:flex;flex-direction:column;gap:8px;margin-bottom:14px"></div>'
+'<div style="margin-bottom:14px"><div style="font-size:12px;color:rgba(255,255,255,.5);margin-bottom:6px">Amount:</div>'
+'<div id="charity-amts" style="display:flex;gap:8px"></div></div>'
+'<div style="display:flex;gap:8px">'
+'<button id="ch-cancel" style="flex:1;padding:11px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;color:rgba(255,255,255,.6);font-weight:700;cursor:pointer;font-family:inherit">Cancel</button>'
+'<button id="ch-donate" style="flex:1;padding:11px;background:linear-gradient(135deg,#00D97E,#059669);border:none;border-radius:10px;color:#000;font-weight:900;cursor:pointer;font-family:inherit">Donate</button>'
+'</div>';
d.appendChild(box);
document.body.appendChild(d);
const list=document.getElementById('charity-list');
CHARITIES.forEach(function(c){
const el=document.createElement('div');
el.className='ch-opt';
el.style.cssText='padding:10px 12px;background:rgba(0,217,126,.05);border:1.5px solid rgba(255,255,255,.1);border-radius:10px;cursor:pointer;transition:.2s';
el.innerHTML='<div style="font-size:13px;font-weight:700">'+c.name+'</div><div style="font-size:11px;color:rgba(255,255,255,.45)">'+c.desc+'</div>';
el.onclick=function(){ charityId=c.id; document.querySelectorAll('.ch-opt').forEach(function(x){x.style.borderColor='rgba(255,255,255,.1)';}); el.style.borderColor='#00D97E'; };
list.appendChild(el);
});
const amts=document.getElementById('charity-amts');
[5,10,25,50].forEach(function(a){
const chip=document.createElement('div');
chip.className='chip'+(a===charityAmt?' on':'');
chip.textContent='$'+a;
chip.onclick=function(){ charityAmt=a; document.querySelectorAll('#charity-amts .chip').forEach(function(x){x.classList.remove('on');}); chip.classList.add('on'); };
amts.appendChild(chip);
});
document.getElementById('ch-cancel').onclick=function(){ d.remove(); };
document.getElementById('ch-donate').onclick=function(){ confirmCharity(); };
}
function confirmCharity(){
if((S.cash||0)<charityAmt){ toast('Not enough cash to donate!'); return; }
S.cash-=charityAmt;
S.totalDonated=(S.totalDonated||0)+charityAmt;
const ch=CHARITIES.find(c=>c.id===charityId)||CHARITIES[0];
addAct('💝',ch.name,'Donation made','-$'+charityAmt,'#00D97E');
addXP(15); addCoins(8);
persistS(); checkAchs();
document.getElementById('charity-modal')?.remove();
toast('💝 Donated $'+charityAmt+' to '+ch.name+'! +15 XP +8 coins','#00D97E');
recordBeh('charity',{amount:charityAmt});
}
/* ── VIRTUAL TAX ─────────────────────────────────────────── */
function checkAndApplyTax(){
const nw=(S.cash||0)+Object.entries(S.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0);
if(nw<1000) return; // only applies to high earners
const taxRate=nw>=5000?0.015:nw>=2500?0.010:0.005;
const tax=+(taxRate*S.cash||0).toFixed(2);
if(tax<1) return;
S.cash=Math.max(0,(S.cash||0)-tax);
S.totalTaxPaid=(S.totalTaxPaid||0)+tax;
addAct('🏛️','City Tax','Community fund contribution','-$'+tax.toFixed(2),'#818CF8');
persistS();
// Every $50 in community tax unlocks a group reward
if((S.totalTaxPaid||0)>=(50*Math.floor((S.totalTaxPaid||0)/50+0.01))){
toast('🏛️ Community Milestone! Your taxes funded a new school. +10 XP bonus!','#818CF8');
addXP(10);
}
}
/* ── PARENT BOUNTIES & MATCHING ──────────────────────────── */
function renderParentBounties(childId){
const ch=DB.children[childId]; if(!ch) return '';
const bounties=(ch.bounties||[]);
const matching=ch.matchRate||0;
const bItems=bounties.map(function(b){
const done=b.done;
return '<div style="padding:10px;background:rgba(255,217,61,.06);border:1px solid rgba(255,217,61,.15);border-radius:10px;margin-bottom:8px">'
+'<div style="display:flex;justify-content:space-between;align-items:center">'
+'<div><div style="font-size:13px;font-weight:700">'+b.task+'</div>'
+'<div style="font-size:11px;color:rgba(255,255,255,.45)">Reward: $'+b.reward+' + '+b.coins+' coins</div></div>'
+(done?'<span style="color:#00D97E;font-size:12px;font-weight:800">Done!</span>'
:'<button data-cid="'+childId+'" data-bid="'+b.id+'" class="bounty-verify-btn" style="padding:6px 12px;background:var(--gold);border:none;border-radius:8px;color:#000;font-size:11px;font-weight:800;cursor:pointer;font-family:inherit">Verify</button>')
+'</div></div>';
}).join('');
const matchBtns=[0,2,5,10].map(function(v){
return '<button data-cid="'+childId+'" data-rate="'+v+'" class="match-rate-btn" style="flex:1;padding:8px;background:'+(matching===v?'var(--primary)':'rgba(255,255,255,.06)')+';border:1.5px solid '+(matching===v?'var(--primary)':'var(--border)')+';border-radius:8px;color:#fff;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">$'+v+'</button>';
}).join('');
return '<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:10px">PARENT BOUNTIES</div>'
+(bounties.length?bItems:'<div style="color:var(--sub);font-size:12px">No bounties yet. Add a task!</div>')
+'<button data-cid="'+childId+'" class="add-bounty-btn" style="margin-top:10px;width:100%;padding:10px;background:rgba(255,217,61,.1);border:1.5px dashed rgba(255,217,61,.3);border-radius:10px;color:#FFD93D;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">+ Add Bounty Task</button>'
+'</div>'
+'<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:10px">SAVINGS MATCH (401k)</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.7);margin-bottom:10px">For every $10 saved, you add: <strong style="color:#FFD93D">$'+matching+'</strong></div>'
+'<div style="display:flex;gap:8px">'+matchBtns+'</div></div>';
}
// Event delegation for bounty buttons (called after pdRenderChild injects HTML)
document.addEventListener('click',function(e){
const vb=e.target.closest('.bounty-verify-btn');
if(vb){ verifyBounty(vb.dataset.cid,vb.dataset.bid); return; }
const ab=e.target.closest('.add-bounty-btn');
if(ab){ addBountyForm(ab.dataset.cid); return; }
const mb=e.target.closest('.match-rate-btn');
if(mb){ setMatchRate(mb.dataset.cid,+mb.dataset.rate); return; }
});
function addBountyForm(childId){
const old=document.getElementById('bounty-form-modal'); if(old) old.remove();
const d=document.createElement('div');
d.id='bounty-form-modal';
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9990;display:flex;align-items:flex-end;padding:20px;animation:fadeIn .3s ease';
const box=document.createElement('div');
box.style.cssText='background:#0f172a;border:1px solid rgba(255,217,61,.2);border-radius:20px 20px 16px 16px;padding:22px;width:100%;max-width:400px;margin:0 auto';
box.innerHTML='<div style="font-size:16px;font-weight:900;margin-bottom:14px">Add Bounty Task</div>'
+'<input id="bounty-task" placeholder="e.g. Clean the garage" style="width:100%;padding:11px 14px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;color:#fff;font-size:14px;margin-bottom:10px;font-family:inherit"/>'
+'<div style="display:flex;gap:8px;margin-bottom:14px">'
+'<div style="flex:1"><div style="font-size:11px;color:var(--sub);margin-bottom:4px">Cash $</div><input id="bounty-reward" type="number" value="20" style="width:100%;padding:9px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:8px;color:#fff;font-size:13px;font-family:inherit"/></div>'
+'<div style="flex:1"><div style="font-size:11px;color:var(--sub);margin-bottom:4px">Coins</div><input id="bounty-coins" type="number" value="15" style="width:100%;padding:9px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:8px;color:#fff;font-size:13px;font-family:inherit"/></div>'
+'</div>'
+'<div style="display:flex;gap:8px">'
+'<button id="bounty-cancel-btn" style="flex:1;padding:11px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;color:rgba(255,255,255,.6);font-weight:700;cursor:pointer;font-family:inherit">Cancel</button>'
+'<button id="bounty-save-btn" style="flex:1;padding:11px;background:var(--gold);border:none;border-radius:10px;color:#000;font-weight:900;cursor:pointer;font-family:inherit">Add Task</button>'
+'</div>';
d.appendChild(box);
document.body.appendChild(d);
document.getElementById('bounty-cancel-btn').onclick=function(){ d.remove(); };
document.getElementById('bounty-save-btn').onclick=function(){ saveBounty(childId); };
}
function saveBounty(childId){
const task=document.getElementById('bounty-task')?.value.trim();
const reward=+(document.getElementById('bounty-reward')?.value||20);
const coins=+(document.getElementById('bounty-coins')?.value||15);
if(!task){ toast('Enter a task description'); return; }
const ch=DB.children; const c=ch[childId]; if(!c) return;
c.bounties=c.bounties||[];
c.bounties.push({id:'b_'+Date.now(),task,reward,coins,done:false});
const all=DB.children; all[childId]=c; DB.saveChildren(all);
document.querySelectorAll('[style*="position:fixed"]').forEach(el=>{ if(el.innerHTML.includes('bounty-task')) el.remove(); });
toast('✅ Bounty task added!','#FFD93D');
pdSelectChild(childId);
}
function verifyBounty(childId,bountyId){
const allCh=DB.children; const c=allCh[childId]; if(!c) return;
const b=c.bounties?.find(x=>x.id===bountyId); if(!b||b.done) return;
b.done=true;
allCh[childId]=c; DB.saveChildren(allCh);
// Add reward to child's state
const cs=DB.children[childId].S||{};
cs.cash=(cs.cash||0)+b.reward;
cs.goldCoins=(cs.goldCoins||0)+b.coins;
cs.activity=cs.activity||[];
cs.activity.unshift({icon:'🎯',name:'Bounty Complete',desc:b.task,amount:'+$'+b.reward,color:'#FFD93D',t:Date.now()});
allCh[childId].S=cs; DB.saveChildren(allCh);
toast('🎉 Bounty verified! $'+b.reward+' + 🪙'+b.coins+' sent to '+c.name,'#FFD93D');
pdSelectChild(childId);
}
function setMatchRate(childId,rate){
const all=DB.children; const c=all[childId]; if(!c) return;
c.matchRate=rate; all[childId]=c; DB.saveChildren(all);
toast(rate>0?'💰 Match rate set: $'+rate+' per $10 saved!':'Match contribution disabled','#A855F7');
pdSelectChild(childId);
}
/* ── SAVINGS MATCH — apply when child saves ───────────────── */
function applyParentMatch(amount){
const ch=DB.children; if(!ch[CU?.data?.username||'']) return;
const parentId=CU?.data?.parentId; if(!parentId) return;
const parent=DB.parents[parentId]; if(!parent) return;
// Check if parent set a match rate on this child
const childData=ch[CU.data.username]; if(!childData?.matchRate) return;
const matchPer10=childData.matchRate;
const match=Math.floor(amount/10)*matchPer10;
if(match>0){
S.cash=(S.cash||0)+match;
addAct('💰','Parent Match','Employer match on savings','+$'+match,'#FFD93D');
toast('💰 Parent matched $'+match+'! (401k style)','#FFD93D');
}
}
/* ── PEER MENTORSHIP ─────────────────────────────────────── */
function getMentorStatus(){
const certs=(S.unlockedAchs||[]).filter(id=>['cert_saver','cert_investor','cert_beh','cert_scholar'].includes(id));
const isMentor=certs.length>=2&&(S.xp||0)>=500;
return {isMentor,certs:certs.length,xpNeeded:Math.max(0,500-(S.xp||0))};
}
/* ── CREDIT SCORE PAGE ────────────────────────────────────── */
function renderCreditPage(){
const body=document.getElementById('credit-body'); if(!body) return;
const score=getCreditScore();
const grade=getCreditGrade(score);
const pct=((score-300)/550*100).toFixed(1);
const persona=getRiskPersona();
const mentorStatus=getMentorStatus();
body.innerHTML='<div class="section">'
// Credit Score Gauge
+'<div class="card-dark" style="text-align:center;margin-bottom:12px;padding:22px">'
+'<div style="font-size:11px;font-weight:800;color:rgba(255,255,255,.4);letter-spacing:1px;margin-bottom:8px">QUEST CREDIT SCORE</div>'
+'<div style="font-size:56px;font-weight:900;color:'+grade.color+'">'+score+'</div>'
+'<div style="font-size:14px;font-weight:800;color:'+grade.color+';margin-bottom:6px">'+grade.grade+' — '+grade.label+'</div>'
+'<div class="prog-bar" style="margin:10px 0"><div class="prog-fill" style="width:'+pct+'%;background:'+grade.color+'"></div></div>'
+'<div style="display:flex;justify-content:space-between;font-size:10px;color:rgba(255,255,255,.3)"><span>300</span><span>850</span></div>'
+'</div>'
// Risk Persona
+'<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:10px">RISK PERSONA</div>'
+'<div style="padding:14px;background:rgba(168,85,247,.08);border:1.5px solid rgba(168,85,247,.25);border-radius:12px">'
+'<div style="font-size:16px;font-weight:900;color:'+persona.color+';margin-bottom:6px">'+persona.title+'</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.65);line-height:1.6">'+persona.desc+'</div>'
+'</div></div>'
// How to improve
+'<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:10px">HOW TO IMPROVE YOUR SCORE</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.6);line-height:2">'
+'✅ Complete more lessons (+6 pts each)<br>'
+'✅ Finish world map missions (+4 pts each)<br>'
+'✅ Hit your savings goals (+40 pts each)<br>'
+'✅ Maintain your daily streak (+5 pts per 3 days)<br>'
+'❌ Avoid panic selling (-8 pts per emotional trade)'
+'</div></div>'
// Mentor status
+(mentorStatus.isMentor
?'<div class="card-dark" style="margin-bottom:12px;border-color:rgba(255,217,61,.3)">'
+'<div class="label" style="margin-bottom:8px;color:#FFD93D">PEER MENTOR STATUS</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.7)">You qualify as a Peer Mentor! With '+mentorStatus.certs+' certificates, you can guide newer players and earn Legacy XP.</div>'
+'<div style="font-size:12px;color:#FFD93D;margin-top:8px;font-weight:700">Mentor Badge Unlocked!</div>'
+'</div>'
:'<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:8px">PEER MENTOR PATHWAY</div>'
+'<div style="font-size:13px;color:rgba(255,255,255,.55)">Earn 2+ certificates and 500 XP to unlock Peer Mentor status. Help newer players and earn Legacy XP!</div>'
+'<div style="font-size:12px;color:rgba(255,255,255,.35);margin-top:6px">'+(mentorStatus.xpNeeded>0?'Need '+mentorStatus.xpNeeded+' more XP':'Need '+(2-mentorStatus.certs)+' more certificate(s)')+'</div>'
+'</div>')
// Donate button
+'<button onclick="openCharity()" style="width:100%;padding:13px;background:linear-gradient(135deg,#064e3b,#059669);border:none;border-radius:12px;color:#fff;font-size:14px;font-weight:800;cursor:pointer;margin-bottom:8px;font-family:inherit">Donate to Charity +15 XP</button>'
+'</div>';
}
/* ── INVESTMENT CLUB PAGE ─────────────────────────────────── */
const CLUB_PROPOSALS=[]; // {id,proposer,assetId,reason,votes:{yes:[],no:[]},status,createdAt}
function renderInvestClub(){
const body=document.getElementById('invest-club-body'); if(!body) return;
const poolAmt=S.clubContrib||0;
const clubPort=S.clubPort||{};
const poolTotal=Object.entries(clubPort).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0)+poolAmt;
const proposals=S.clubProposals||[];
body.innerHTML='<div class="section">'
+'<div class="card-dark" style="margin-bottom:12px">'
+'<div class="label" style="margin-bottom:10px">SHARED INVESTMENT POOL</div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px">'
+'<div class="stat-box"><div class="stat-v" style="color:var(--primary2)">$'+poolTotal.toFixed(0)+'</div><div class="stat-l">Pool Value</div></div>'
+'<div class="stat-box"><div class="stat-v" style="color:var(--gold)">$'+poolAmt.toFixed(0)+'</div><div class="stat-l">Your Share</div></div>'
+'</div>'
+'<div style="display:flex;gap:8px;margin-bottom:10px">'
+'<button onclick="contributeToClub(25)" style="flex:1;padding:10px;background:rgba(168,85,247,.15);border:1px solid rgba(168,85,247,.3);border-radius:8px;color:#C084FC;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">+$25</button>'
+'<button onclick="contributeToClub(50)" style="flex:1;padding:10px;background:rgba(168,85,247,.15);border:1px solid rgba(168,85,247,.3);border-radius:8px;color:#C084FC;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">+$50</button>'
+'<button onclick="contributeToClub(100)" style="flex:1;padding:10px;background:rgba(168,85,247,.15);border:1px solid rgba(168,85,247,.3);border-radius:8px;color:#C084FC;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">+$100</button>'
+'</div>'
+'</div>'
// Active proposals
+'<div class="card-dark" style="margin-bottom:12px">'
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">'
+'<div class="label">INVESTMENT PROPOSALS</div>'
+'<button onclick="openProposeModal()" style="padding:6px 12px;background:var(--primary);border:none;border-radius:8px;color:#fff;font-size:11px;font-weight:800;cursor:pointer;font-family:inherit">+ Propose</button>'
+'</div>'
+(proposals.length?proposals.map(function(p){
const a=FA.find(x=>x.id===p.assetId)||{nm:p.assetId,ic:'?'};
const yes=(p.votes&&p.votes.yes||[]).length;
const no=(p.votes&&p.votes.no||[]).length;
const total=yes+no||1;
const voted=(p.votes&&p.votes.yes||[]).includes(S.name)||(p.votes&&p.votes.no||[]).includes(S.name);
return '<div style="padding:12px;background:rgba(255,255,255,.04);border-radius:10px;margin-bottom:8px">'
+'<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">'
+'<span style="font-size:18px">'+a.ic+'</span>'
+'<div><div style="font-size:13px;font-weight:700">Buy '+a.nm+'</div>'
+'<div style="font-size:11px;color:rgba(255,255,255,.45)">By '+p.proposer+'</div></div>'
+'</div>'
+'<div style="font-size:12px;color:rgba(255,255,255,.6);margin-bottom:8px">'+p.reason+'</div>'
+'<div class="prog-bar" style="margin-bottom:8px"><div class="prog-fill" style="width:'+(yes/total*100).toFixed(0)+'%;background:#00D97E"></div></div>'
+'<div style="display:flex;justify-content:space-between;font-size:11px;color:rgba(255,255,255,.4);margin-bottom:8px"><span>Yes: '+yes+'</span><span>No: '+no+'</span></div>'
+(!voted?'<div style="display:flex;gap:8px">'
+'<button data-pid="'+p.id+'" data-v="yes" class="vote-btn" style="flex:1;padding:8px;background:rgba(0,217,126,.15);border:1px solid rgba(0,217,126,.3);border-radius:8px;color:#00D97E;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">Vote Yes</button>'
+'<button data-pid="'+p.id+'" data-v="no" class="vote-btn" style="flex:1;padding:8px;background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.25);border-radius:8px;color:#EF4444;font-size:12px;font-weight:800;cursor:pointer;font-family:inherit">Vote No</button>'
+'</div>'
:'<div style="font-size:11px;color:rgba(255,255,255,.35);text-align:center">You voted</div>')
+'</div>';
}).join('')
:'<div style="color:var(--sub);font-size:13px">No proposals yet. Be the first to propose an investment!</div>')
+'</div>'
+'</div>';
// Vote buttons
body.querySelectorAll('.vote-btn').forEach(function(btn){
btn.onclick=function(){ voteOnProposal(btn.dataset.pid,btn.dataset.v); };
});
}
function contributeToClub(amt){
if((S.cash||0)<amt){ toast('Not enough cash!'); return; }
S.cash-=amt; S.clubContrib=(S.clubContrib||0)+amt;
addAct('🤝','Investment Club','Contributed to shared pool','-$'+amt,'#A855F7');
addXP(5); persistS(); renderInvestClub();
toast('Contributed $'+amt+' to the club pool!','#A855F7');
}
function openProposeModal(){
const d=document.createElement('div');
d.id='propose-modal';
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9990;display:flex;align-items:flex-end;padding:20px;animation:fadeIn .3s ease';
const box=document.createElement('div');
box.style.cssText='background:#0f172a;border:1px solid rgba(168,85,247,.2);border-radius:20px 20px 16px 16px;padding:22px;width:100%;max-width:400px;margin:0 auto';
const assetOpts=FA.slice(0,8).map(function(a){return '<option value="'+a.id+'">'+a.ic+' '+a.nm+'</option>';}).join('');
box.innerHTML='<div style="font-size:16px;font-weight:900;margin-bottom:14px">Propose Investment</div>'
+'<select id="prop-asset" style="width:100%;padding:10px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:8px;color:#fff;font-size:13px;margin-bottom:10px;font-family:inherit">'+assetOpts+'</select>'
+'<textarea id="prop-reason" placeholder="Why should the club invest in this?" rows="3" style="width:100%;padding:10px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:8px;color:#fff;font-size:13px;margin-bottom:12px;font-family:inherit;resize:none"></textarea>'
+'<div style="display:flex;gap:8px">'
+'<button id="prop-cancel" style="flex:1;padding:11px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;color:rgba(255,255,255,.6);font-weight:700;cursor:pointer;font-family:inherit">Cancel</button>'
+'<button id="prop-submit" style="flex:1;padding:11px;background:var(--primary);border:none;border-radius:10px;color:#fff;font-weight:900;cursor:pointer;font-family:inherit">Propose</button>'
+'</div>';
d.appendChild(box);
document.body.appendChild(d);
document.getElementById('prop-cancel').onclick=function(){d.remove();};
document.getElementById('prop-submit').onclick=function(){
const assetId=document.getElementById('prop-asset').value;
const reason=document.getElementById('prop-reason').value.trim();
if(!reason){toast('Add a reason for your proposal');return;}
const props=S.clubProposals||[];
props.push({id:'p_'+Date.now(),proposer:S.name,assetId:assetId,reason:reason,votes:{yes:[],no:[]},status:'open',createdAt:Date.now()});
S.clubProposals=props; persistS();
addXP(5); d.remove(); renderInvestClub();
toast('Proposal submitted! Others can now vote.','#A855F7');
};
}
function voteOnProposal(propId,vote){
const props=S.clubProposals||[];
const p=props.find(function(x){return x.id===propId;}); if(!p) return;
p.votes=p.votes||{yes:[],no:[]};
if(p.votes.yes.includes(S.name)||p.votes.no.includes(S.name)){ toast('Already voted!'); return; }
p.votes[vote].push(S.name);
// Auto-execute if majority yes (3+ votes)
const yes=p.votes.yes.length;
if(yes>=3&&p.status==='open'){
p.status='executed';
const pool=S.clubContrib||0;
const a=FA.find(function(x){return x.id===p.assetId;});
if(a&&pool>=a.px){
const qty=Math.floor(pool*0.5/a.px);
if(qty>0){
S.clubContrib-=a.px*qty; S.clubPort=S.clubPort||{};
S.clubPort[p.assetId]=(S.clubPort[p.assetId]||0)+qty;
toast('Club voted YES! Bought '+qty+'x '+a.nm,'#00D97E');
addXP(10);
}
}
}
S.clubProposals=props; persistS(); renderInvestClub();
toast('Vote recorded!','#A855F7'); recordBeh('club_vote',{vote:vote});
}
/* ── LIMIT ORDER SHEET (shown in market) ──────────────────── */
let loAssetId='', loType='buy', loQty=1, loPrice=0;
function openLimitOrderSheet(assetId){
loAssetId=assetId; loType='buy';
const a=FA.find(function(x){return x.id===assetId;});
loPrice=a?+(a.px*0.95).toFixed(2):0; loQty=1;
const d=document.createElement('div');
d.id='sheet-limit-order';
d.className='sheet';
d.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:900;display:flex;align-items:flex-end';
const box=document.createElement('div');
box.style.cssText='background:var(--card);border-radius:20px 20px 0 0;padding:22px;width:100%;max-width:420px;margin:0 auto;max-height:80vh;overflow-y:auto';
box.innerHTML='<div style="font-size:16px;font-weight:900;margin-bottom:4px">Set Limit Order</div>'
+'<div style="font-size:12px;color:rgba(255,255,255,.5);margin-bottom:16px">'+(a?a.nm+' · Current: $'+a.px:assetId)+'</div>'
// Type tabs
+'<div style="display:flex;gap:8px;margin-bottom:14px">'
+'<button id="lo-buy-tab" onclick="loType=\'buy\';this.style.background=\'rgba(129,140,248,.3)\';document.getElementById(\'lo-sell-tab\').style.background=\'rgba(255,255,255,.06)\'" style="flex:1;padding:10px;background:rgba(129,140,248,.3);border:1.5px solid rgba(129,140,248,.4);border-radius:8px;color:#818CF8;font-size:13px;font-weight:800;cursor:pointer;font-family:inherit">Buy Limit</button>'
+'<button id="lo-sell-tab" onclick="loType=\'sell\';this.style.background=\'rgba(0,217,126,.15)\';document.getElementById(\'lo-buy-tab\').style.background=\'rgba(255,255,255,.06)\'" style="flex:1;padding:10px;background:rgba(255,255,255,.06);border:1.5px solid rgba(255,255,255,.1);border-radius:8px;color:#00D97E;font-size:13px;font-weight:800;cursor:pointer;font-family:inherit">Sell Limit</button>'
+'</div>'
// Target price
+'<div style="margin-bottom:12px"><div style="font-size:12px;color:rgba(255,255,255,.5);margin-bottom:6px">Target Price ($)</div>'
+'<input id="lo-price" type="number" value="'+loPrice+'" oninput="loPrice=+this.value" style="width:100%;padding:11px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:8px;color:#fff;font-size:14px;font-family:inherit"/></div>'
// Quantity
+'<div style="margin-bottom:14px"><div style="font-size:12px;color:rgba(255,255,255,.5);margin-bottom:6px">Quantity</div>'
+'<div style="display:flex;gap:6px">'
+[1,2,5,10].map(function(q){return '<div class="chip'+(q===1?' on':'')+'" onclick="loQty='+q+';document.querySelectorAll(\'#sheet-limit-order .chip\').forEach(function(x){x.classList.remove(\'on\')});this.classList.add(\'on\')">×'+q+'</div>';}).join('')
+'</div></div>'
+'<div style="font-size:11px;color:rgba(255,255,255,.4);margin-bottom:14px">Order executes automatically when target price is hit. Checks every 30 seconds.</div>'
+'<div style="display:flex;gap:8px">'
+'<button id="lo-cancel-main" style="flex:1;padding:11px;background:rgba(255,255,255,.06);border:1px solid var(--border);border-radius:10px;color:rgba(255,255,255,.6);font-weight:700;cursor:pointer;font-family:inherit">Cancel</button>'
+'<button id="lo-confirm-btn" style="flex:2;padding:11px;background:var(--primary);border:none;border-radius:10px;color:#fff;font-size:14px;font-weight:800;cursor:pointer;font-family:inherit">Set Order</button>'
+'</div>'
+'<div style="margin-top:12px"><div class="label" style="margin-bottom:8px;font-size:11px">ACTIVE ORDERS</div><div id="limit-orders-list"></div></div>';
d.appendChild(box);
document.body.appendChild(d);
renderLimitOrders();
document.getElementById('lo-cancel-main').onclick=function(){d.remove();};
document.getElementById('lo-confirm-btn').onclick=function(){
loPrice=+(document.getElementById('lo-price').value);
if(!loPrice||loPrice<=0){toast('Enter a valid target price');return;}
addLimitOrder(loAssetId,loType,loQty,loPrice);
d.remove();
};
}
const LESSONS=[
{id:0,game:"trivia",lv:1,icon:'💰',title:'What is Money?',sub:'History of currency',xp:20,
body:'Money is anything people agree has value! Before money, people bartered — swapping goods directly. This was tricky: what if you had apples but wanted shoes, and the shoemaker didn\'t want apples?\n\nMoney solves this! It\'s a universal medium of exchange, store of value, and unit of account.\n\n💡 Fun fact: seashells were used as money in ancient China, salt in ancient Rome (hence "salary"!), and cigarettes in prisons.',
q:'What core problem did money solve?',opts:['People hated vegetables','Barter was hard when wants didn\'t match','Coins were fun to collect','Kings needed taxes'],ans:1,story:'Omar found a seashell on the beach. His neighbor Fatima really wanted it. She offered three mangoes for it. This was bartering — trading things directly. But what if Omar needed shoes, not mangoes? Money solves this problem.'},
{id:1,game:"sort",lv:1,icon:'🏦',title:'Saving vs Spending',sub:'Why saving builds wealth',xp:25,
body:'The 50/30/20 Rule:\n• 50% Needs — food, transport, school\n• 30% Wants — games, clothes, fun\n• 20% Savings & investments 💰\n\nPeople who save consistently become wealthy. Those who spend everything stay stuck.\n\n⚡ Start with just $1 a day — that\'s $365 a year, automatically.',
q:'In the 50/30/20 rule, what % goes to savings?',opts:['10%','5%','20%','50%'],ans:2,story:'Layla received 200 dirhams on Eid. Her friend said \'spend it all!\' Her grandmother said \'save 100.\' Layla saved 100 and spent 100. One year later, her savings had grown to 104 dirhams from bank interest. Small discipline, compounding result.'},
{id:2,game:"match",lv:2,icon:'📈',title:'How Investing Works',sub:'Making your money grow',xp:30,
body:'Investing = putting money to work so it earns MORE money.\n\n📊 A stock is a tiny piece of ownership in a real company.\n\nIf you owned 1 Apple share 10 years ago at $60, it would be $185+ today — that\'s 3× growth!\n\n🔑 The secret: START EARLY. Time is your superpower. $100 at age 12 can become $10,000+ by age 65.',
q:'What does buying a stock actually mean?',opts:['Lending money','Buying tiny ownership in a company','Getting free products','Paying taxes'],ans:1,story:'Ahmed\'s father bought 10 shares of a small company for 50 dirhams each. Five years later, the company grew and each share was worth 180 dirhams. Ahmed\'s father turned 500 dirhams into 1,800 — without working extra hours.'},
{id:3,game:"rank",lv:2,icon:'⚠️',title:'Risk vs Reward',sub:'The fundamental trade-off',xp:25,
body:'Every investment has risk — the chance of losing money.\n\n📊 Risk Ladder (low → high):\n🏦 Savings: 0–5% return, near-zero risk\n🏛️ Bonds: 3–5%, very low risk\n📈 S&P 500 Index: 7–10% avg, moderate risk\n💎 Individual Stocks: 0–50%+, higher risk\n₿ Crypto: −80% to +1000%, extreme risk',
q:'Which has the LOWEST risk?',opts:['Crypto','Individual stocks','Savings account','A tip from a friend'],ans:2,story:'Sara put all her savings into one cryptocurrency. One morning it dropped 70%. She lost most of her money overnight. Her classmate Khalid spread his money across stocks, bonds, and gold. When crypto fell, only 20% of his money was affected.'},
{id:4,game:"calc",lv:2,icon:'✨',title:'Compound Interest',sub:'The 8th wonder of the world',xp:35,
body:'Compound = earning interest ON your interest.\n\n💰 $1,000 at 10% per year:\nYear 1: $1,100\nYear 2: $1,210 (interest on $1,100!)\nYear 10: $2,594\nYear 30: $17,449\n\n🔑 Every year you delay costs you exponentially more. Start today — even with $10.',
q:'Why is compound interest powerful?',opts:['Bank gives bonuses','You earn interest on your interest','Government adds money','Inflation helps'],ans:1,story:'Hamad saved 1,000 dirhams at age 10. His twin sister spent hers on toys. At age 40, Hamad\'s 1,000 dirhams had grown to 17,449 dirhams — doing absolutely nothing. His sister had nothing saved. Same family. Different habits. Different futures.'},
{id:5,game:"basket",lv:3,icon:'🥧',title:'Diversification',sub:'Don\'t put all eggs in one basket',xp:30,
body:'Diversification = spreading investments to reduce risk.\n\n🥚 One basket (all crypto) — one crash wipes you out.\n🥚🥚🥚 Many baskets (stocks + bonds + gold) — one drop hurts less.\n\nAn index fund like S&P 500 = 500 companies in one trade. Instant diversification!',
q:'What is diversification?',opts:['Owning only one stock','Spreading investments to reduce risk','Only investing in crypto','Keeping all cash'],ans:1,story:'Nour invested all her money in one technology company. When the company had a scandal, her portfolio crashed 80%. Her friend Dina owned 20 different companies across 5 industries. When tech fell, her overall portfolio only dropped 12%.'},
{id:6,game:"chat",lv:3,icon:'🤖',title:'AI & The Future of Money',sub:'How tech is changing finance',xp:30,
body:'Finance is being transformed by technology!\n\n💡 AI detects fraud in milliseconds\n💰 Robo-advisors invest your money automatically\n🌍 Blockchain enables global payments in seconds\n📱 Your phone IS your wallet\n\n⚠️ Warning: AI gives advice, but YOU always make the final decision. Never let any algorithm control your money completely.',
q:'What should you always do with AI financial advice?',opts:['Follow immediately','Ignore it','Evaluate and decide yourself','Share on social media'],ans:2,story:'Reem asked her AI assistant if she should invest in a trending stock. The AI gave her a tip. She invested all her money. The tip was wrong. She lost 40%. Remember: AI gives information, not guarantees. Always decide for yourself.'},
{id:7,game:"rate",lv:4,icon:'🏦',title:'Banking & Interest',sub:'How banks use your money',xp:35,
body:'Banks are two things: safe vaults AND active investors.\n\nWhen you deposit:\n1. Bank holds ~10% as reserve\n2. Lends the rest at higher interest\n3. You earn interest for letting them use your money\n\n💰 $500 at 4% = $520 after Year 1 — doing nothing!\n\n🇦🇪 Islamic banks offer profit-sharing instead of interest.',
q:'Why do banks pay you interest?',opts:['For fun','They use your money to make loans','Government mandates it','Loyalty bonuses'],ans:1,story:'Yusuf deposited 5,000 dirhams in a bank. He forgot about it for 3 years. When he checked, he had 5,612 dirhams. The bank had paid him 4% per year just for letting them use his money. His money worked while he slept.'},
{id:8,game:"chart",lv:4,icon:'📊',title:'Reading Stock Charts',sub:'The language of markets',xp:40,
body:'Charts tell the story of price movement.\n\n📈 Uptrend = higher highs = bullish\n📉 Downtrend = lower lows = bearish\n➡️ Sideways = waiting\n\nKey concepts:\n• Volume = conviction behind a move\n• Resistance = price ceiling (sellers appear)\n• Support = price floor (buyers appear)\n\n⚡ Always zoom out. Daily noise vs monthly trend are completely different.',
q:'What does HIGH trading volume usually indicate?',opts:['System error','Strong move with real conviction','Random noise','Low interest'],ans:1,story:'Mariam looked at a stock chart. It kept making higher highs and higher lows for 6 months — an uptrend. She bought. The trend continued. She sold at a profit. She did not guess. She read the story the chart was telling.'},
{id:9,game:"compare",lv:4,icon:'💹',title:'Crypto vs Stocks',sub:'Two very different animals',xp:40,
body:'Stocks = ownership in real businesses with earnings, assets, dividends, and 200+ year track record.\n\nCrypto = digital assets. Value = what others will pay. Often unregulated. 15-year history. 5–10× more volatile than stocks.\n\n⚠️ Start with diversified index funds. Add crypto ONLY after you understand the risk fully.',
q:'Key difference between stocks and crypto?',opts:['Stocks are newer','Stocks = real business; crypto is speculative','Crypto is always safer','No difference'],ans:1,story:'Adam put 500 dirhams in a top cryptocurrency and 500 in an S&P 500 index fund. After 2 years, the crypto was worth 200 dirhams — a 60% loss. The index fund was worth 620 dirhams. Same money. Totally different outcomes.'},
{id:10,game:"tax",lv:5,icon:'🧮',title:'Taxes & Wealth',sub:'Keep more of what you earn',xp:45,
body:'Capital Gains Tax = paid when you SELL for profit.\n\n🗓️ Short-term (held <1yr): taxed as income (higher!)\n📅 Long-term (held >1yr): lower tax rate\n\nTax-advantaged accounts (401k, ISA) grow tax-free — worth hundreds of thousands extra over 40 years.\n\n🇦🇪 UAE: 0% personal income tax is a massive global advantage!',
q:'What is "capital gains tax"?',opts:['Tax on salary','Tax on profit when you sell investments','Annual fee to trade','Tax on dividends only'],ans:1,story:'Jasmine sold her investments for a 10,000 dirham profit in December. She did not know about capital gains tax. In April, she owed 1,500 dirhams in taxes she had already spent. Always plan for tax before spending profits.'},
{id:11,game:"reit",lv:5,icon:'🏠',title:'Real Estate 101',sub:'Property as an investment',xp:45,
body:'Real estate has created more millionaires than any other asset class.\n\n🏠 Two ways to profit:\n1. Appreciation: value rises ~4–6%/yr\n2. Rental income: tenants pay monthly!\n\nREITs = invest in property like a stock, no mortgage needed.\n\n🏙️ Dubai real estate returned 8–15% annually in recent years.',
q:'What is a REIT?',opts:['Type of mortgage','Invest in real estate like a stock','Property management firm','Government housing'],ans:1,story:'Hassan\'s uncle bought a small apartment in Dubai for 300,000 dirhams in 2015. By 2024, it was worth 520,000 dirhams and had earned 180,000 in rent payments. Total return: 400,000 dirhams on one decision made nine years ago.'},
{id:12,game:"globe",lv:6,icon:'🌍',title:'Global Markets',sub:'The world is your portfolio',xp:40,
body:'The US market is only ~44% of global stock value!\n\n🌏 Emerging markets (India, Brazil, SE Asia) = higher growth potential, higher risk.\n\nTrue diversification spans:\n• Countries (US, Europe, Asia, Emerging)\n• Currencies (USD, EUR, AED)\n• Asset classes (stocks, bonds, gold, real estate)\n\n⚡ Most investors miss 56% of global opportunity by only investing locally.',
q:'What % of global stocks is the US market?',opts:['About 80%','About 44%','About 10%','About 60%'],ans:1,story:'Lina only invested in UAE companies. When the local market fell, her entire portfolio dropped. Her friend Sofia invested across 12 countries. When the UAE fell, Sofia\'s international holdings stayed strong. Global diversification saved her.'},
,
{id:13,game:"sort",lv:1,icon:'🤝',title:'Needs vs Wants',sub:'The foundation of smart spending',xp:20,
body:'Needs are things you must have: food, shelter, clothing, school supplies.\n\nWants are things that make life enjoyable but are not essential: games, designer clothes, the latest phone.\n\n\u{1F4A1} The trap: our brain FEELS wants as needs. That feeling passes in 48-72 hours!\n\n\u26A1 The 48-hour rule: wait 2 days before any non-essential purchase.',
q:'Which is a NEED, not a want?',opts:['Designer sneakers','School textbooks','Gaming console','Cinema tickets'],ans:1,story:'Ali had 100 dirhams. He wanted new trainers and also needed school supplies. The trainers felt urgent. But school supplies were a real need. He bought supplies and put 50 toward his trainer savings goal. Needs first. Wants planned for.'},
{id:14,game:"earn",lv:1,icon:'\u{1F4BC}',title:'Earning Money',sub:'How income is created',xp:25,
body:'Income comes from three sources:\n\n1. Active Income: you trade time for money (salary, freelance)\n2. Passive Income: money works for you (dividends, rent, royalties)\n3. Portfolio Income: selling appreciated assets\n\n\u{1F3AF} Goal: build passive income so your time becomes free.\n\n\u{1F4A1} Even at 12 you can earn: tutoring, digital skills, selling crafts.',
q:'Which is PASSIVE income?',opts:['Working a shift','Dividend from a stock','Doing chores for pay','Cutting grass'],ans:1,story:'Fatima spent 2 hours tutoring her neighbor\'s child in math. She charged 30 dirhams per hour. While she slept, her invested savings earned 2 dirhams. Active income required her time. Passive income did not. Both were valuable.'},
{id:15,game:"budget",lv:2,icon:'\u{1F4CB}',title:'Budgeting Basics',sub:'Your financial GPS',xp:30,
body:'A budget is simply: money IN vs money OUT.\n\n\u{1F4CB} Zero-based budget: every dollar gets a job.\n\nIncome $1000:\n- Needs: $500\n- Savings: $200\n- Investments: $100\n- Wants: $200\n= $0 unassigned\n\n\u26A1 The richest people in the world budget obsessively. It is not about restriction. It is about intention.',
q:'What is the purpose of a budget?',opts:['To restrict fun','To assign every dollar a purpose','Only for poor people','To impress others'],ans:1,story:'Omar had 3,000 dirhams income each month but always ran out by the 25th. He started a zero-based budget — assigning every dirham a job. Needs: 1,500. Wants: 900. Savings: 600. For the first time, he reached month-end with money left.'},
{id:16,game:"delay",lv:2,icon:'\u23F3',title:'Delayed Gratification',sub:'The science of waiting',xp:35,
body:'The Stanford Marshmallow Experiment: children who waited 15 minutes for a second marshmallow earned more, had better health, and scored higher on life outcomes decades later.\n\n\u{1F9E0} Delaying gratification is a SKILL you can practice like a muscle.\n\nEvery time you wait before spending, you rewire your brain for wealth.',
q:'What did the marshmallow experiment predict?',opts:['Candy preference','Long-term life success','Sugar sensitivity','Memory ability'],ans:1,story:'Hessa was offered a chocolate cake now or two cakes tomorrow. She waited. Scientists who ran this test found that children who could wait earned more, were healthier, and built more wealth as adults. Waiting is a skill. Practice it.'},
{id:17,game:"score",lv:3,icon:'\u{1F4B3}',title:'Debt & Credit',sub:'Borrowing with wisdom',xp:35,
body:'Good debt builds wealth: a business loan, mortgage on a growing home, education loan.\n\nBad debt loses value: credit card for a phone, loan for a holiday.\n\n\u{1F4B3} Credit score (300-850): your financial trustworthiness rating. Higher score = lower interest rates = cheaper loans.\n\n\u26A0\uFE0F Never borrow to fund a lifestyle you cannot afford.',
q:'What is BAD debt?',opts:['Mortgage on a growing home','Business startup loan','Credit card for holidays','Student loan for a demanded skill'],ans:2,story:'Khalid bought a phone on credit. The phone cost 2,000 dirhams. He paid minimum payments for 2 years. He ended up paying 3,200 dirhams total — 1,200 extra in interest. The real price of that phone was 60% more than the sticker said.'},
{id:18,game:"launch",lv:4,icon:'\u{1F3EA}',title:'Entrepreneurship',sub:'Creating value for others',xp:40,
body:'An entrepreneur finds a problem and builds a profitable solution.\n\n\u{1F4A1} A business needs: a problem to solve, customers who pay, and Revenue > Costs.\n\nStartup path: Idea → Test → Launch → Scale.\n\n\u{1F31F} Most teens who start small businesses develop skills worth 10x more than their first paycheck: selling, managing, problem-solving.\n\nYou do not need money to start. You need value.',
q:'What does an entrepreneur need FIRST?',opts:['Investors','Office space','A problem to solve','A logo'],ans:2,story:'Amira noticed students in her school always lost their pencils. She started selling pencils from her bag for 1 dirham each. She bought 50 pencils for 20 dirhams and sold all of them. That is 50 dirhams revenue, 20 cost, 30 profit — 150% return.'},
{id:19,game:"flow",lv:4,icon:'\u{1F4B0}',title:'Business Cash Flow',sub:'How businesses survive',xp:40,
body:'Cash Flow = Money In (Revenue) minus Money Out (Expenses).\n\nA PROFITABLE business can still go bankrupt if cash runs out!\n\n\u26A0\uFE0F 82% of small businesses fail due to cash flow problems, not bad products.\n\nTrack every dollar in and every dollar out. Always.\n\n\u{1F4A1} Positive cash flow = your business breathes. Negative cash flow = your business suffocates.',
q:'Why can a profitable business still fail?',opts:['Owners steal money','Poor cash flow management','Bad products','Government rules'],ans:1,story:'Saeed\'s father opened a restaurant. It was always full. Profits looked amazing. But suppliers demanded payment before revenue arrived from customers. The business ran out of cash. Full restaurant. Zero cash. This is a cash flow problem.'},
{id:20,game:"lend",lv:5,icon:'\u{1F30D}',title:'Lending & Borrowing',sub:'How money flows between people',xp:30,
body:'Lending = giving money temporarily in exchange for interest income.\n\nBorrowing = receiving money temporarily, paying it back plus interest.\n\nBanks borrow from depositors at 2%, lend to businesses at 6%, keep the spread.\n\n\u{1F4A1} Before lending to a friend: treat it as a gift. Loans often damage relationships when repayment becomes complicated.',
q:'How do banks make profit from lending?',opts:['Government subsidies','Charging higher interest than they pay depositors','Printing money','Investment fees'],ans:1,story:'Rami lent his friend 200 dirhams for two weeks. Two weeks passed. His friend avoided him. Three months later, still no repayment. The friendship became awkward. Rule: never lend what you cannot afford to give away as a gift.'},
{id:21,game:"bond",lv:5,icon:'\u{1F4CA}',title:'Understanding Bonds',sub:'Fixed income explained',xp:30,
body:'A bond = you LEND money to a company or government, they pay you fixed interest, return principal at maturity.\n\n\u{1F4CA} Bond basics:\n- Face value: $1,000 (returned at maturity)\n- Coupon: 4%/yr = $40 annually\n- Maturity: 5, 10, or 30 years\n\n\u{1F3DB}\uFE0F Government bonds: very safe, lower return.\nCorporate bonds: slightly riskier, higher return.\n\n\u{1F4A1} Bonds go DOWN when interest rates go UP.',
q:'What is a bond coupon?',opts:['A discount voucher','The regular interest payment','The maturity date','Bond price'],ans:1,story:'The UAE government issued a 5-year bond paying 4% per year. Sara invested 10,000 dirhams. Each year she received 400 dirhams interest. After 5 years, she got her 10,000 back. Predictable, stable, and safe — that is a bond.'},
{id:22,game:"fi",lv:6,icon:'\u{1F331}',title:'Financial Independence',sub:'Making work optional',xp:45,
body:'Financial Independence (FI): having assets whose investment income covers all living expenses.\n\nFI Number = Annual expenses x 25 (the 4% Rule).\n\nExample: spend $40,000/yr → need $1 million invested.\n\n\u26A1 FIRE movement (FI, Retire Early): people achieve this by 35-45 through aggressive saving from age 20.\n\n\u{1F3AF} You do not need to retire. FI means you CHOOSE to work, not have to.',
q:'What does financial independence mean?',opts:['Having no job','Investment income covers all expenses','Being extremely rich','Winning the lottery'],ans:1,story:'Ahmed calculated his FI number at age 25. He needed 2 million dirhams to retire on his current lifestyle. He started investing 2,000 dirhams per month at 8% return. His projection: financially independent by age 47. The math was on his side.'},
];
/* ═══════════════════════════════════════════════════════════
FINANCIAL DECISION SIMULATOR — 20 Real-Life Scenarios
Each: situation, amount, 3 choices, outcomes, time effect
═══════════════════════════════════════════════════════════ */
const SCENARIOS=[
{id:'s1',em:'🎂',title:'Birthday Money',lv:1,coins:100,
situation:'It is your birthday! Grandma gives you 100 Gold Coins. What do you do?',
choices:[
{label:'Spend it all today!',action:'spend',
outcome:'You bought games and snacks. They were fun for 3 days. Now you have nothing left.',
timeskip:'3 days later',delta:{xp:5,coins:0},beh:{delay:-10,discipline:-8}},
{label:'Save half, spend half',action:'save',
outcome:'You enjoyed 50 coins now and saved 50. Smart balance! In 1 year those 50 coins grew with interest.',
timeskip:'1 year later',delta:{xp:25,coins:10},beh:{delay:8,discipline:8}},
{label:'Save it all for my goal',action:'goal',
outcome:'Incredible discipline! You are now 100 coins closer to your big goal. Every coin counts.',
timeskip:'6 months later',delta:{xp:40,coins:15},beh:{delay:15,discipline:15,planning:10}},
]},
{id:'s2',em:'🚲',title:'The Bicycle Dilemma',lv:1,coins:200,
situation:'You want a bicycle that costs 200 coins. You have 150 saved. A friend offers you a shortcut: borrow 50 from him at 10% interest. What do you do?',
choices:[
{label:'Borrow 50 coins at 10% interest',action:'borrow',
outcome:'You got the bike! But you owe 55 coins back. Debt feels small until repayment day.',
timeskip:'3 months later',delta:{xp:15,coins:-5},beh:{delay:-5,risk:5,discipline:-5}},
{label:'Wait 2 more months and save',action:'save',
outcome:'You waited patiently. You bought the bike debt-free with coins to spare. No one can take it from you.',
timeskip:'2 months later',delta:{xp:35,coins:10},beh:{delay:12,discipline:12,planning:8}},
{label:'Ask parent for a savings match',action:'goal',
outcome:'Your parent matched 25 coins toward your goal! Teamwork accelerated your savings with zero debt.',
timeskip:'1 month later',delta:{xp:30,coins:5},beh:{delay:8,planning:12}},
]},
{id:'s3',em:'🏪',title:'Lemonade Stand',lv:2,coins:50,
situation:'You have 50 coins. A friend wants you to co-invest in a lemonade stand. They project 30% profit but it might fail. Do you:',
choices:[
{label:'Invest all 50 coins!',action:'invest',
outcome:'The stand earned 40% profit! Your 50 became 70 coins. Risk rewarded the bold.',
timeskip:'2 weeks later',delta:{xp:40,coins:20},beh:{risk:12,discipline:5}},
{label:'Invest 25, keep 25 safe',action:'invest',
outcome:'You invested half. Earned 40% on 25 coins = 10 coin profit. Diversified thinking!',
timeskip:'2 weeks later',delta:{xp:30,coins:10},beh:{risk:5,discipline:8}},
{label:'Too risky — save instead',action:'save',
outcome:'You saved safely. The stand did earn 40%... but you missed it. Safety has a cost too.',
timeskip:'2 weeks later',delta:{xp:20,coins:0},beh:{risk:-5,discipline:8}},
]},
{id:'s4',em:'👔',title:'Friend in Need',lv:2,coins:80,
situation:'Your friend has no lunch money and asks to borrow 20 coins — promising to repay in a week. You have 80 coins. What do you do?',
choices:[
{label:'Lend 20 coins with a repayment date',action:'lend',
outcome:'Friend repaid you on time with a thank-you bonus coin! You helped AND maintained financial discipline.',
timeskip:'1 week later',delta:{xp:30,coins:1},beh:{planning:8,consistency:5}},
{label:'Give 20 coins as a gift — no repayment',action:'charity',
outcome:'You gave freely. You felt great and your friend was grateful. Generosity has its own return.',
timeskip:'Same day',delta:{xp:25,coins:0},beh:{discipline:5,consistency:5}},
{label:'Refuse — I need my money',action:'save',
outcome:'You protected your coins but felt uneasy. Sometimes financial safety must be balanced with human connection.',
timeskip:'Same day',delta:{xp:10,coins:0},beh:{risk:-3,planning:3}},
]},
{id:'s5',em:'📱',title:'The New Phone',lv:2,coins:300,
situation:'Your phone is 2 years old and works fine. The new model launches. It costs 300 coins. You have 300 saved. Your goal needs 500 coins. Do you:',
choices:[
{label:'Buy the new phone NOW',action:'spend',
outcome:'Great phone! But your goal is reset to zero. You will need 8 more months to rebuild your savings.',
timeskip:'8 months later',delta:{xp:5,coins:-300},beh:{delay:-15,discipline:-15,planning:-10}},
{label:'Keep working phone — save the 300',action:'save',
outcome:'Your working phone works fine! In 5 months you hit your 500 coin goal. Your future self thanks you.',
timeskip:'5 months later',delta:{xp:50,coins:30},beh:{delay:15,discipline:15,planning:15}},
{label:'Buy refurbished model for 150 coins',action:'spend',
outcome:'Smart compromise! You got an upgrade for half price and saved 150 coins toward your goal.',
timeskip:'3 months later',delta:{xp:35,coins:10},beh:{delay:8,discipline:8,planning:10}},
]},
{id:'s6',em:'🎮',title:'The Game Temptation',lv:1,coins:60,
situation:'A new game releases today for 60 coins. You have exactly 60 coins. Your savings goal is 200 coins and you have 140 saved. This game might be 40% off next month. Do you:',
choices:[
{label:'Buy it NOW — full price!',action:'spend',
outcome:'You played for 2 weeks, enjoyed it, then got bored. Paid 60 when you could have paid 36.',
timeskip:'2 weeks later',delta:{xp:5,coins:-60},beh:{delay:-12,discipline:-10}},
{label:'Wait for the 40% discount',action:'save',
outcome:'Patience paid off! You bought it for 36 coins next month, saving 24 coins for your goal.',
timeskip:'1 month later',delta:{xp:35,coins:24},beh:{delay:12,discipline:12,planning:8}},
{label:'Skip it — focus on goal',action:'goal',
outcome:'You hit your 200 coin goal in 4 weeks. Then bought the game at 50% off on sale. Double win!',
timeskip:'4 weeks later',delta:{xp:50,coins:30},beh:{delay:18,discipline:18,planning:15}},
]},
{id:'s7',em:'🏠',title:'Virtual Real Estate',lv:3,coins:500,
situation:'You have 500 coins. An investment in a virtual property pays 8% per year guaranteed. A crypto coin promises 80% but might crash 60%. What is your strategy?',
choices:[
{label:'All in crypto for 80% gains!',action:'invest',
outcome:'Crash! Your 500 became 200 coins. High risk lived up to its name. Lesson learned viscerally.',
timeskip:'6 months later',delta:{xp:20,coins:-300},beh:{risk:15,delay:-5,discipline:-5}},
{label:'Split: 300 property, 200 crypto',action:'invest',
outcome:'Property paid 24 coins. Crypto crashed but only lost 80. Net result: you survived and grew slightly.',
timeskip:'6 months later',delta:{xp:40,coins:-56},beh:{risk:8,discipline:8,planning:10}},
{label:'All in stable property at 8%',action:'invest',
outcome:'Steady 8%. Your 500 earned 40 coins — guaranteed. Boring but powerful over time.',
timeskip:'1 year later',delta:{xp:45,coins:40},beh:{risk:-5,discipline:12,planning:12}},
]},
{id:'s8',em:'🎓',title:'The College Fund',lv:3,coins:1000,
situation:'You have 1,000 coins earmarked for college. A friend shows you a stock tip that could triple it in 3 months. What do you do?',
choices:[
{label:'Bet the full college fund!',action:'invest',
outcome:'It was a pump-and-dump. You lost everything. College is delayed. Risk you cannot afford is not investing — it is gambling.',
timeskip:'3 months later',delta:{xp:10,coins:-1000},beh:{risk:20,delay:-15,planning:-20}},
{label:'Invest 100, protect the 900',action:'invest',
outcome:'Smart! You risked only what you could afford to lose. Lost 100 but the core fund is safe and growing.',
timeskip:'3 months later',delta:{xp:45,coins:-100},beh:{risk:8,planning:15,discipline:10}},
{label:'Protect all 1,000 for college',action:'save',
outcome:'You stayed disciplined. The tip was a scam anyway. Your college fund is intact. Future: secured.',
timeskip:'same time',delta:{xp:55,coins:0},beh:{delay:15,discipline:20,planning:20}},
]},
{id:'s9',em:'💼',title:'Junior Business Idea',lv:4,coins:200,
situation:'You have a business idea: sell custom digital art online. Start-up cost: 200 coins. Projected monthly revenue: 150 coins. Projected expenses: 80 coins. Do you:',
choices:[
{label:'Launch immediately!',action:'invest',
outcome:'You launched! Month 1: 120 coins revenue. Month 2: 180. By month 3 you turned your 200 into 520 coins.',
timeskip:'3 months later',delta:{xp:80,coins:320},beh:{risk:10,discipline:10,planning:15}},
{label:'Test with 50 coins first',action:'invest',
outcome:'Pilot test confirmed demand. You then launched fully with confidence. Lower risk, verified results.',
timeskip:'2 months later',delta:{xp:70,coins:200},beh:{risk:5,discipline:12,planning:18}},
{label:'Too risky — keep coins safe',action:'save',
outcome:'You stayed safe. The business idea remained an idea. Sometimes the biggest risk is not taking any.',
timeskip:'same time',delta:{xp:15,coins:0},beh:{risk:-5,discipline:5}},
]},
{id:'s10',em:'🌱',title:'The Compound Proof',lv:3,coins:100,
situation:'You have 100 coins earning 10% per year. After 30 simulated years you will have 1,745 coins. But if you wait just 10 years to start, you only get 672 coins. Every year you delay costs you 1,073 coins. Do you:',
choices:[
{label:'Start investing immediately!',action:'invest',
outcome:'30 years later: 100 coins became 1,745! Einstein called compound interest the 8th wonder. Now you believe it.',
timeskip:'30 sim-years',delta:{xp:60,coins:50},beh:{delay:18,planning:18,discipline:15}},
{label:'Wait until I have more money first',action:'save',
outcome:'10 years later you start. You only reach 672. The 1,073 coin difference is the cost of waiting. Starting small is always better than waiting.',
timeskip:'10 sim-years',delta:{xp:30,coins:10},beh:{delay:-8,planning:-5}},
{label:'Spend now — enjoy life today',action:'spend',
outcome:'You enjoyed 100 coins today. 30 years later your peers who invested have 1,745. This is opportunity cost at its most powerful.',
timeskip:'30 sim-years',delta:{xp:10,coins:-100},beh:{delay:-15,discipline:-12}},
]},
];
/* ═══════════════════════════════════════════════════════════
FINANCIAL DECISION SIMULATOR ENGINE
═══════════════════════════════════════════════════════════ */
let curScenario=null, simHistory=[];
function openSimulator(){
S.simulatorRuns=(S.simulatorRuns||0);
const unused=SCENARIOS.filter(s=>!(S.simulatorHistory||[]).includes(s.id));
const pool=unused.length>0?unused:SCENARIOS;
const sc=pool[Math.floor(Math.random()*pool.length)];
curScenario=sc;
const modal=document.createElement('div');
modal.id='sim-modal';
modal.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.85);z-index:9999;display:flex;align-items:flex-end;justify-content:center;backdrop-filter:blur(8px)';
modal.innerHTML=`<div style="width:100%;max-width:480px;background:linear-gradient(175deg,#0D0621,#0A1628);border-radius:24px 24px 0 0;padding:24px;max-height:85vh;overflow-y:auto">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<div style="font-size:11px;font-weight:800;color:rgba(255,255,255,.35);letter-spacing:1.5px">MONEY SIMULATOR</div>
<button onclick="document.getElementById('sim-modal').remove()" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:50px;color:rgba(255,255,255,.5);font-size:11px;padding:4px 11px;cursor:pointer;font-family:inherit"></button>
</div>
<div style="text-align:center;margin-bottom:20px">
<div style="font-size:52px;margin-bottom:6px">${sc.em}</div>
<div style="font-size:18px;font-weight:900;margin-bottom:8px">${sc.title}</div>
<div style="background:rgba(168,85,247,.1);border:1px solid rgba(168,85,247,.2);border-radius:12px;padding:13px 15px;text-align:left">
<div style="font-size:13px;line-height:1.7;color:rgba(255,255,255,.8)">${sc.situation}</div>
</div>
<div style="margin-top:10px;font-size:12px;font-weight:800;color:var(--gold)">💰 ${sc.coins} coins at stake</div>
</div>
<div style="display:flex;flex-direction:column;gap:9px" id="sim-choices">
${sc.choices.map((c,i)=>`<button onclick="pickSimChoice(${i})" style="padding:13px 15px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.1);border-radius:12px;color:#fff;font-size:13px;font-weight:700;text-align:left;cursor:pointer;font-family:inherit;line-height:1.5;transition:all .2s" onmouseover="this.style.background='rgba(168,85,247,.12)'" onmouseout="this.style.background='rgba(255,255,255,.04)'">${c.label}</button>`).join('')}
</div>
</div>`;
document.body.appendChild(modal);
}
function pickSimChoice(i){
if(!curScenario) return;
const ch=curScenario.choices[i];
const el=document.getElementById('sim-choices');
if(!el) return;
el.innerHTML=`<div style="background:linear-gradient(135deg,rgba(0,217,126,.1),rgba(0,217,126,.04));border:1px solid rgba(0,217,126,.2);border-radius:12px;padding:14px 15px">
<div style="font-size:11px;font-weight:800;color:#6EE7B7;margin-bottom:6px">⏱ ${ch.timeskip}</div>
<div style="font-size:14px;line-height:1.7;color:#fff;margin-bottom:12px">${ch.outcome}</div>
<div style="display:flex;gap:10px;margin-bottom:10px">
${ch.delta.xp>0?`<div style="background:rgba(168,85,247,.15);border-radius:8px;padding:6px 10px;font-size:11px;font-weight:800;color:#C4B5FD">+${ch.delta.xp} XP</div>`:''}
${ch.delta.coins>0?`<div style="background:rgba(255,217,61,.12);border-radius:8px;padding:6px 10px;font-size:11px;font-weight:800;color:var(--gold)">+${ch.delta.coins} 🪙</div>`:''}
${ch.delta.coins<0?`<div style="background:rgba(239,68,68,.12);border-radius:8px;padding:6px 10px;font-size:11px;font-weight:800;color:#FCA5A5">${ch.delta.coins} 🪙</div>`:''}
</div>
<div style="font-size:10px;color:rgba(255,255,255,.35);background:rgba(255,255,255,.04);border-radius:8px;padding:8px 10px;margin-bottom:12px">
<strong style="color:rgba(255,255,255,.5)">Opportunity Cost:</strong> Every financial choice excludes other possibilities. The coins you spent cannot be invested. The coins you saved cannot be enjoyed today. Both have value.
</div>
<button onclick="closeSimulator()" class="btn btn-gold">Got it — Keep Going! 💪</button>
</div>`;
// Apply rewards
if(ch.delta.xp>0) addXP(ch.delta.xp);
if(ch.delta.coins>0) addCoins(ch.delta.coins);
// Apply behavior impacts
const beh=ch.beh||{};
Object.entries(beh).forEach(([k,v])=>{
if(S.behavior&&k in S.behavior) S.behavior[k]=Math.max(0,Math.min(100,(S.behavior[k]||50)+v));
});
S.simulatorRuns=(S.simulatorRuns||0)+1;
if(!S.simulatorHistory) S.simulatorHistory=[];
S.simulatorHistory.push(curScenario.id);
persistS();
checkAchs();
recordDecision('simulator',{scenarioId:curScenario.id,choice:i,action:ch.action});
toast('Simulator complete! +'+ch.delta.xp+' XP');
}
function closeSimulator(){
const m=document.getElementById('sim-modal');
if(m) m.remove();
renderHome();
}
const BGAMES=[
{id:'delay',ic:'⏳',nm:'Marshmallow Test',desc:'Delay gratification',reward:30,
scenes:[
{txt:'You have 100 Gold Coins. Spend them NOW on an AI run, OR wait and get 160 coins next session (+60%). What do you do?',
opts:['Spend all 100 now!','Wait for 160 coins'],better:1,
good:'🧠 Delayed gratification = the #1 predictor of financial success. The Stanford marshmallow study proved this over 40 years.',
bad:'⚠️ Natural impulse! But wealth requires waiting. Every delay multiplies your reward significantly.'},
{txt:'Limited sneakers cost $220. You\'ve saved $220 toward a $300 goal. Friend says "don\'t miss out!" Do you:',
opts:['Buy sneakers — FOMO!','Stay committed to my goal'],better:1,
good:'💪 Goal discipline! This is exactly how wealthy people think. Your goals beat social pressure.',
bad:'💡 Social comparison spending is a trap. Protect your goals from impulse purchases.'},
]},
{id:'fomo',ic:'🚀',nm:'FOMO Detector',desc:'Resist Fear Of Missing Out',reward:25,
scenes:[
{txt:'"MoonCoin" is up 800% this week. Everyone\'s talking about it. Never heard of it. Do you:',
opts:['Buy immediately — don\'t miss out!','Research first, then decide'],better:1,
good:'🧠 Smart! FOMO drove the dot-com crash (2000) and crypto crash (2022). Research beats emotion.',
bad:'⚠️ Classic FOMO! When everyone\'s talking about it, the smart money already cashed out.'},
]},
{id:'loss',ic:'📉',nm:'Loss Aversion Lab',desc:'Losses feel 2× worse than gains feel good',reward:25,
scenes:[
{txt:'Stock bought at $100 is now $60 (−40%). Company fundamentals still strong. Do you:',
opts:['Sell immediately — stop the pain!','Hold — fundamentals unchanged'],better:1,
good:'💎 Rational! We feel losses 2× more than gains. Don\'t let pain override logic.',
bad:'📊 Panic selling locks in your loss permanently. Loss aversion costs investors billions in every crash.'},
]},
{id:'overconf',ic:'🦁',nm:'Overconfidence Check',desc:'Are you calibrated or overconfident?',reward:20,
scenes:[
{txt:'After 2 weeks of research you\'re 95% sure TechCorp will rise. How much portfolio % to put in?',
opts:['75%+ — very confident!','Max 10% — no one predicts reliably'],better:1,
good:'🎯 Calibrated! Top fund managers are right ~55% of the time. Big bets destroy wealth.',
bad:'⚡ Overconfidence bias! Even Buffett made costly concentrated bets early in his career.'},
]},
{id:'anchor',ic:'⚓',nm:'Anchor Escape',desc:'Break free from reference prices',reward:20,
scenes:[
{txt:'Bought stock at $200. Now $120. Analysis says fair value is $115. You keep thinking about $200. You:',
opts:['Hold — waiting to break even at $200!','Evaluate only future prospects'],better:1,
good:'🧠 Rational! Your entry price is irrelevant to future value. Only future cash flows matter.',
bad:'⚓ Anchoring! Your $200 is gone regardless. Holding to "get back" ignores current reality.'},
]},
{id:'herd',ic:'🐑',nm:'Herd Immunity',desc:'Think independently',reward:20,
scenes:[
{txt:'90% of financial Twitter says crash is coming. Your own research shows the economy is strong. Do you:',
opts:['Sell everything — 90% must be right!','Stick with research + small hedge'],better:1,
good:'🦁 Independent thinker! Buffett: "Be fearful when others are greedy, greedy when fearful."',
bad:'🐑 The crowd called crashes in 2010, 2012, 2016, 2019 — markets rose every time.'},
]},
];
const WORLDS=[
{id:'w1',ttl:'MONEY BASICS',ic:'💰',col:'#00D97E',xpReq:0,
ms:[{id:'m1',ttl:'Money Origins',ic:'🏺',xp:50,coins:20,desc:'How bartering evolved into modern money.',obj:'Complete 2+ lessons'},
{id:'m2',ttl:'Cash Flow Hero',ic:'💵',xp:75,coins:30,desc:'Track income and expenses.',obj:'Save $100'},
{id:'m3',ttl:'Budget Battle',ic:'⚔️',xp:100,coins:40,desc:'Defeat overspending with a personal budget.',obj:'Add a savings goal'}]},
{id:'w2',ttl:'SAVING MACHINE',ic:'🏦',col:'#3B82F6',xpReq:100,
ms:[{id:'m4',ttl:'50/30/20 Challenge',ic:'📊',xp:120,coins:50,desc:'Apply the golden rule of personal finance.',obj:'Contribute to a goal 3×'},
{id:'m5',ttl:'Emergency Vault',ic:'🛡️',xp:150,coins:60,desc:'Build your financial safety net.',obj:'Save $200 total'},
{id:'m6',ttl:'Compound Engine',ic:'⚙️',xp:200,coins:80,desc:'Watch savings multiply exponentially.',obj:'Complete compound interest lesson'}]},
{id:'w3',ttl:'INVEST REALM',ic:'📈',col:'#F59E0B',xpReq:300,
ms:[{id:'m7',ttl:'First Investment',ic:'📉',xp:150,coins:60,desc:'Buy your first real asset.',obj:'Buy 3 different assets'},
{id:'m8',ttl:'Diversify or Die',ic:'🥧',xp:200,coins:80,desc:'Spread risk the smart way.',obj:'Own 4+ asset types'},
{id:'m9',ttl:'ETF Explorer',ic:'🗺️',xp:250,coins:100,desc:'Passive investing — Buffett\'s recommendation.',obj:'Buy SPY or QQQ'}]},
{id:'w4',ttl:'WEALTH BUILDER',ic:'🏰',col:'#8B5CF6',xpReq:700,
ms:[{id:'m10',ttl:'Real Estate Run',ic:'🏠',xp:300,coins:120,desc:'Property as an asset class via REITs.',obj:'Buy VNQ REIT'},
{id:'m11',ttl:'Crypto Canals',ic:'₿',xp:350,coins:140,desc:'Navigate digital assets, avoid traps.',obj:'Complete FOMO game + buy crypto'},
{id:'m12',ttl:'The Wealth Formula',ic:'🔢',xp:400,coins:160,desc:'Combine all knowledge into a strategy.',obj:'Complete 5+ brain games'}]},
{id:'w5',ttl:'MARKET MASTER',ic:'👑',col:'#EF4444',xpReq:1500,
ms:[{id:'m13',ttl:'Psychology Wars',ic:'🧠',xp:500,coins:200,desc:'Conquer ALL 6 biases.',obj:'Complete all 6 brain games'},
{id:'m14',ttl:'AI Portfolio God',ic:'🤖',xp:600,coins:250,desc:'Use K2 AI to optimize your portfolio.',obj:'Run rebalancer + reach Level 5'},
{id:'m15',ttl:'WEALTH LEGEND',ic:'🏆',xp:1000,coins:500,desc:'Achieve true mastery.',obj:'Reach Level 7'}]},
];
const ACHIEVEMENTS=[
{id:'first_save',ic:'💰',nm:'First Saver',desc:'Save money for the first time',cond:()=>(S.port?.save||0)>0,rew:25},
{id:'first_invest',ic:'📈',nm:'Baby Investor',desc:'Make your first market investment',cond:()=>Object.keys(S.mktPort||{}).length>0,rew:30},
{id:'first_goal',ic:'🎯',nm:'Goal Setter',desc:'Add your first savings goal',cond:()=>(S.goals||[]).length>0,rew:20},
{id:'first_lesson',ic:'📚',nm:'Eager Learner',desc:'Complete your first lesson',cond:()=>(S.learningDone||[]).length>0,rew:15},
{id:'brain_game',ic:'🧠',nm:'Mind Master',desc:'Complete a brain game',cond:()=>(S.completedGames||[]).length>0,rew:30},
{id:'diversified',ic:'🥧',nm:'Diversifier',desc:'Own 4+ different asset types',cond:()=>Object.keys(S.mktPort||{}).length>=4,rew:60},
{id:'level3',ic:'🌳',nm:'Growing Up',desc:'Reach Level 3',cond:()=>getLv().lv>=3,rew:50},
{id:'level5',ic:'⚡',nm:'Strategist',desc:'Reach Level 5',cond:()=>getLv().lv>=5,rew:100},
{id:'all_lessons',ic:'🏫',nm:'Scholar',desc:'Complete all 13 lessons',cond:()=>(S.learningDone||[]).length>=13,rew:200},
{id:'all_games',ic:'🧬',nm:'Bias Buster',desc:'Complete all 6 brain games',cond:()=>(S.completedGames||[]).length>=6,rew:150},
{id:'millionaire',ic:'💎',nm:'$1K Club',desc:'Reach $1,000 net worth',cond:()=>netWorth()>=1000,rew:100},
{id:'big_saver',ic:'🏦',nm:'Big Saver',desc:'Save $200 total',cond:()=>(S.port?.save||0)>=200,rew:75},
{id:'missions5',ic:'🗺️',nm:'World Traveler',desc:'Complete 5 missions',cond:()=>(S.completedMissions||[]).length>=5,rew:80},
{id:'missions_all',ic:'🏆',nm:'World Master',desc:'Complete all 15 missions',cond:()=>(S.completedMissions||[]).length>=15,rew:300},
{id:'philanthropist',ic:'💝',nm:'Philanthropist',desc:'Make your first charitable donation',cond:()=>(S.totalDonated||0)>0,rew:50},
{id:'big_donor',ic:'❤️',nm:'Heart of Gold',desc:'Donate $50+ to charity',cond:()=>(S.totalDonated||0)>=50,rew:100},
{id:'club_member',ic:'🤝',nm:'Club Member',desc:'Contribute to the Investment Club',cond:()=>(S.clubContrib||0)>0,rew:40},
{id:'limit_trader',ic:'⏳',nm:'Strategic Trader',desc:'Place your first limit order',cond:()=>(S.limitOrders||[]).length>0,rew:30},
{id:'dividend_earner',ic:'💰',nm:'Dividend King',desc:'Earn your first dividend',cond:()=>(S.activity||[]).some(a=>a.desc&&a.desc.includes('Dividend')),rew:50},
{id:'credit_good',ic:'💳',nm:'Credit Builder',desc:'Reach a Quest Credit Score of 700+',cond:()=>getCreditScore()>=700,rew:75},
{id:'credit_excellent',ic:'🌟',nm:'Credit Master',desc:'Reach a Quest Credit Score of 800+',cond:()=>getCreditScore()>=800,rew:150},
];
const CERTS=[
{id:'cert_saver',ic:'🏦',nm:'Certified Saver',
desc:'Proven ability to build savings habits and delay gratification.',
req:'Save $200 + complete Saving Machine world',
cond:()=>(S.port?.save||0)>=200&&(S.completedMissions||[]).some(id=>['m4','m5','m6'].includes(id)),
xp:100,coins:150,level:2},
{id:'cert_investor',ic:'📈',nm:'Certified Investor',
desc:'Demonstrated understanding of asset classes, diversification, and market dynamics.',
req:'Own 4+ asset classes + complete Invest Realm world',
cond:()=>{const cats=new Set(Object.keys(S.mktPort||{}).map(id=>{const a=FA.find(x=>x.id===id);return a?.cat;}));return cats.size>=4&&(S.completedMissions||[]).some(id=>['m7','m8','m9'].includes(id));},
xp:150,coins:200,level:4},
{id:'cert_behavior',ic:'🧠',nm:'Behavioral Finance Expert',
desc:'Mastered emotional intelligence in financial decision-making.',
req:'Complete all 6 Brain HQ games + run Simulator 5+ times',
cond:()=>(S.completedGames||[]).length>=6&&(S.simulatorRuns||0)>=5,
xp:200,coins:250,level:3},
{id:'cert_scholar',ic:'📚',nm:'Financial Scholar',
desc:'Completed the comprehensive financial literacy curriculum.',
req:'Complete 15+ lessons',
cond:()=>(S.learningDone||[]).length>=15,
xp:250,coins:300,level:5},
{id:'cert_entrepreneur',ic:'🚀',nm:'Junior Entrepreneur',
desc:'Applied entrepreneurial and business thinking to financial decisions.',
req:'Complete entrepreneurship lessons + run simulator 8+ times',
cond:()=>(S.learningDone||[]).includes(18)&&(S.learningDone||[]).includes(19)&&(S.simulatorRuns||0)>=8,
xp:200,coins:250,level:6},
{id:'cert_legend',ic:'🏆',nm:'Wealth Legend',
desc:'The ultimate achievement — mastery of all financial pillars.',
req:'Earn 4 other certificates + reach Level 8+',
cond:()=>(S.certs||[]).filter(id=>['cert_saver','cert_investor','cert_behavior','cert_scholar'].includes(id)).length>=4&&(S.xp||0)>=2000,
xp:500,coins:1000,level:7},
{id:'cert_smart_spender',ic:'🧮',nm:'Smart Spender',
desc:'Demonstrated exceptional financial decision-making in the simulator.',
req:'Complete 6+ simulator scenarios with disciplined choices',
cond:()=>(S.simulatorRuns||0)>=6,
xp:100,coins:120,level:2},
];
/* ── NET WORTH ──────────────────────────────────────────── */
function netWorth(){
let t=S.cash||0;
Object.entries(S.port||{}).forEach(([id,q])=>{ const a=FA.find(x=>x.id===id); if(a) t+=q*a.px; });
Object.entries(S.mktPort||{}).forEach(([id,q])=>{ const a=FA.find(x=>x.id===id); if(a) t+=q*a.px; });
if(S.port?.save) t+=(S.port.save||0);
return t;
}
/* ── BEHAVIORAL ENGINE ──────────────────────────────────── */
function getBeh(){
if(!CU?.data?.username) return {delay:50,risk:50,discipline:50,planning:50,consistency:50,total:0,events:[]};
return DB.getChild(CU.data.username)?.beh||{delay:50,risk:50,discipline:50,planning:50,consistency:50,total:0,events:[]};
}
function saveBehData(b){ if(CU?.role==='child') DB.saveBeh(CU.data.username,b); }
function recordBeh(type, data={}){
const b=getBeh();
b.total=(b.total||0)+1;
b.events=b.events||[];
b.events.unshift({type,data,ts:Date.now()});
if(b.events.length>60) b.events.pop();
if(type==='save'){ b.discipline=Math.min(100,b.discipline+3); b.consistency=Math.min(100,b.consistency+2); }
if(type==='impulse_spend'){ b.discipline=Math.max(0,b.discipline-4); }
if(type==='goal_contribute'){ b.planning=Math.min(100,b.planning+5); b.discipline=Math.min(100,b.discipline+2); }
if(type==='lesson'){ b.planning=Math.min(100,b.planning+3); }
if(type==='delay_yes'){ b.delay=Math.min(100,b.delay+6); }
if(type==='delay_no'){ b.delay=Math.max(0,b.delay-4); }
if(type==='buy_risky'){ b.risk=Math.min(100,b.risk+7); b.discipline=Math.max(0,b.discipline-1); }
if(type==='buy_safe'){ b.risk=Math.max(0,b.risk-3); b.discipline=Math.min(100,b.discipline+2); }
if(type==='bgame_rational'){ b.delay=Math.min(100,b.delay+4); b.planning=Math.min(100,b.planning+3); }
if(type==='mission'){ b.consistency=Math.min(100,b.consistency+4); b.planning=Math.min(100,b.planning+3); }
saveBehData(b);
}
function behColor(v){ return v>=75?'#00D97E':v>=50?'#3B82F6':v>=30?'#F59E0B':'#EF4444'; }
function behLabel(v){ return v>=75?'Excellent':v>=50?'Good':v>=30?'Developing':'Needs Work'; }
/* ── HOME PAGE ──────────────────────────────────────────── */
function renderHome(){
if(!S.name) return;
const h=new Date().getHours();
const gr=h<12?'Good morning! 🌅':h<17?'Good afternoon! ☀️':'Good evening! 🌙';
setT('h-greet',gr);
setT('h-name','Hey '+S.name+'! 👋');
setT('h-av',S.avatar||'🦊');
const lv=getLv(), nx=getNextLv();
const xpIn=(S.xp||0)-lv.req, xpNeed=nx.req-lv.req;
const pct=lv.lv===10?100:Math.min(100,Math.round(xpIn/Math.max(1,xpNeed)*100));
setT('lv-badge','Lv '+lv.lv+' · '+lv.title);
setT('xp-lbl',xpIn+'/'+xpNeed+' XP');
document.getElementById('xp-fill').style.width=pct+'%';
setT('coins-val',S.goldCoins||0);
setT('h-cash','$'+(S.cash||0).toFixed(0));
const inv=Object.entries(S.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0);
setT('h-inv','$'+inv.toFixed(0));
setT('h-nw','$'+netWorth().toFixed(0));
renderGoalBanner();
renderPortfolio();
renderActivityList();
}
function setT(id,v){ const e=document.getElementById(id); if(e) e.textContent=v; }
function renderGoalBanner(){
const el=document.getElementById('goal-banner'); if(!el) return;
if(!(S.goals||[]).length){
el.innerHTML='<div class="card" style="cursor:pointer;border-color:rgba(245,158,11,.3)" onclick="openSheet(\'sheet-addgoal\')"><div style="text-align:center;font-size:14px;color:var(--sub)">No goal yet — tap to add one! 🎯</div></div>';
return;
}
const g=S.goals[0], pct=Math.min(100,Math.round((g.saved/g.target)*100));
el.innerHTML=`<div class="card">
<div style="display:flex;align-items:center;gap:12px">
<div style="font-size:28px">${g.icon}</div>
<div style="flex:1">
<div class="h3">${g.name}</div>
<div style="font-size:12px;color:var(--sub);margin-top:2px">${g.sym||'$'}${g.saved.toFixed(0)} of ${g.sym||'$'}${g.target}</div>
<div class="prog-bar"><div class="prog-fill" style="width:${pct}%;background:var(--primary2)"></div></div>
</div>
<div style="font-size:22px;font-weight:900;color:var(--primary2)">${pct}%</div>
</div>
</div>`;
}
function renderPortfolio(){
const el=document.getElementById('port-list'); if(!el) return;
const items=[];
Object.entries(S.mktPort||{}).forEach(([id,q])=>{
const a=FA.find(x=>x.id===id); if(a&&q>0)
items.push({ic:a.ic,nm:a.nm,val:(q*a.px).toFixed(0),q,col:a.col});
});
if(S.port?.save>0) items.push({ic:'🏦',nm:'Savings',val:(S.port.save).toFixed(0),q:1,col:'#3B82F6'});
if(!items.length){ el.innerHTML='<div class="empty">No investments yet.<br/>Buy from Markets to start! 📈</div>'; return; }
el.innerHTML=items.map(it=>`<div class="list-row">
<div class="list-ic" style="background:${it.col}20;font-size:24px">${it.ic}</div>
<div class="list-body"><div class="list-title">${it.nm}</div><div class="list-sub">${it.q} held</div></div>
<div class="list-right"><div style="font-size:15px;font-weight:900;color:var(--primary2)">$${it.val}</div></div>
</div>`).join('');
}
function renderActivityList(){
const el=document.getElementById('activity-list'); if(!el) return;
if(!(S.activity||[]).length){ el.innerHTML='<div class="empty">No activity yet. Start playing!</div>'; return; }
el.innerHTML=(S.activity||[]).slice(0,6).map(a=>`<div class="list-row">
<div style="font-size:22px">${a.icon}</div>
<div class="list-body"><div class="list-title" style="font-size:13px">${a.name}</div><div class="list-sub">${a.desc}</div></div>
<div style="font-size:12px;font-weight:800;color:${a.color}">${a.amount}</div>
</div>`).join('');
}
function addAct(icon,name,desc,amount,color){ (S.activity||(S.activity=[])).unshift({icon,name,desc,amount,color}); if(S.activity.length>20) S.activity.pop(); }
/* ── SAVE SHEET ─────────────────────────────────────────── */
let selSaveAmt=50;
function openSaveSheet(){
selSaveAmt=50;
const el=document.getElementById('save-amts');
el.innerHTML=[10,25,50,100].map((a,i)=>`<div onclick="pickSave(${a},this)" class="chip ${i===1?'on':''}" style="padding:10px 18px;flex:none">${'$'+a}</div>`).join('')
+`<div onclick="pickSave(${(S.cash||0)},this)" class="chip" style="padding:10px 18px;flex:none">All ($${(S.cash||0).toFixed(0)})</div>`;
openSheet('sheet-save');
}
function pickSave(a,el){
selSaveAmt=a;
document.querySelectorAll('#save-amts .chip').forEach(c=>c.classList.remove('on'));
el.classList.add('on');
}
function doSave(){
const amt=Math.min(selSaveAmt,S.cash||0);
if(amt<=0){ toast('Not enough cash!'); return; }
S.port=S.port||{}; S.port.save=(S.port.save||0)+amt; S.cash-=amt;
applyParentMatch(amt);
addAct('🏦','Saved money','Put $'+amt+' in savings','+$'+amt,'var(--primary2)');
addXP(5); addCoins(2); recordBeh('save');
closeSheet('sheet-save'); renderHome(); checkAchs(); toast('💰 Saved $'+amt+'!');
}
/* ── LEARN PAGE ─────────────────────────────────────────── */
function renderLearn(){
const el=document.getElementById('les-list'); if(!el) return;
el.innerHTML=LESSONS.map((l,i)=>{
const done=(S.learningDone||[]).includes(l.id);
const locked=i>0&&!(S.learningDone||[]).includes(LESSONS[i-1].id)&&i>2;
return `<div class="les-row ${done?'done':locked?'locked':''}" onclick="${locked?'':` openLesson(${l.id})`}">
<div class="les-ic">${l.icon}</div>
<div class="les-body">
<div class="les-ttl">${l.title}</div>
<div class="les-sub">${l.sub}</div>
<div class="les-badge" style="color:${done?'var(--primary2)':locked?'var(--sub)':'var(--gold)'}">${done?'✅ Done · +'+l.xp+' XP':locked?'🔒 Locked':'⭐ +'+l.xp+' XP · 🪙 +5'}</div>
</div>
</div>`;
}).join('');
}
let curLesson=null;
function openLesson(id){
const l=LESSONS.find(x=>x.id===id); if(!l) return;
curLesson=l;
setT('les-em',l.icon); setT('les-ttl',l.title);
document.getElementById('les-body').innerHTML=l.body.split('\n').map(p=>p.trim()?`<p style="margin-bottom:8px">${p}</p>`:'').join('')+(renderMiniGame(l)||'');
const qEl=document.getElementById('les-quiz');
qEl.innerHTML=`<div style="font-size:11px;font-weight:800;color:var(--primary);text-transform:uppercase;letter-spacing:.8px;margin-bottom:10px;padding:6px 10px;background:rgba(124,58,237,.08);border-radius:8px;display:inline-block;">✅ Quick Check</div>
<div style="font-size:14px;font-weight:700;margin-bottom:10px;color:var(--text)">${l.q}</div>
${l.opts.map((o,i)=>`<button id="opt-${i}" onclick="selAns(${i})" style="width:100%;padding:12px 14px;background:rgba(255,255,255,.06);border:1.5px solid var(--border);border-radius:12px;font-size:13px;font-weight:700;text-align:left;cursor:pointer;margin-bottom:8px;color:var(--text);font-family:inherit;display:block">${o}</button>`).join('')}`;
const btn=document.getElementById('les-btn');
btn.disabled=true; btn.textContent='Pick an answer!'; btn.onclick=null;
openSheet('sheet-lesson');
}
function selAns(i){
if(!curLesson) return;
document.querySelectorAll('[id^="opt-"]').forEach(b=>b.disabled=true);
const good=i===curLesson.ans;
const picked=document.getElementById('opt-'+i);
const correct=document.getElementById('opt-'+curLesson.ans);
picked.style.borderColor=good?'#00D97E':'#EF4444';
picked.style.background=good?'rgba(0,217,126,.1)':'rgba(239,68,68,.1)';
picked.style.color=good?'#00D97E':'#EF4444';
if(!good){ correct.style.borderColor='#00D97E'; correct.style.background='rgba(0,217,126,.1)'; correct.style.color='#00D97E'; }
const btn=document.getElementById('les-btn'); btn.disabled=false;
if(good){
btn.textContent='Correct! 🎉 +'+curLesson.xp+' XP';
btn.onclick=()=>{
if(!(S.learningDone||[]).includes(curLesson.id)){ (S.learningDone||(S.learningDone=[])).push(curLesson.id); addXP(curLesson.xp); addCoins(5); recordBeh('lesson'); }
closeSheet('sheet-lesson'); renderLearn(); renderHome(); checkAchs();
};
} else {
btn.textContent='Almost — keep going! +'+Math.floor(curLesson.xp*.3)+' XP';
btn.onclick=()=>{ addXP(Math.floor(curLesson.xp*.3)); closeSheet('sheet-lesson'); renderLearn(); };
}
}
// Lesson completion wrapper
function doLessonComplete(lid, passed){
if(!lid && typeof curLesson !== 'undefined' && curLesson) lid = curLesson.id;
const l = LESSONS.find(x=>x.id===lid);
if(passed !== false){
if(l && !(S.learningDone||[]).includes(lid)){
(S.learningDone||(S.learningDone=[])).push(lid);
addXP(l.xp); addCoins(5);
if(typeof recordBeh === 'function') recordBeh('lesson');
}
if(typeof closeSheet === 'function') closeSheet('sheet-lesson');
if(typeof renderLearn === 'function') renderLearn();
if(typeof renderHome === 'function') renderHome();
if(typeof checkAchs === 'function') checkAchs();
} else {
if(typeof closeSheet === 'function') closeSheet('sheet-lesson');
if(typeof renderLearn === 'function') renderLearn();
}
}
/* ── MARKET PAGE ────────────────────────────────────────── */
let mktCat='all', buyId=null, buyQty=1, sellId=null, sellQty=1;
function renderMarket(){
setT('mkt-cash','$'+(S.cash||0).toFixed(2));
const fEl=document.getElementById('mkt-filters');
if(fEl) fEl.innerHTML=Object.keys(CAT_LABELS).map(cat=>`<button onclick="setMktCat('${cat}')" style="padding:7px 14px;border-radius:50px;border:1.5px solid ${cat===mktCat?'var(--primary)':' var(--border)'};background:${cat===mktCat?'rgba(124,58,237,.15)':'rgba(255,255,255,.04)'};font-size:12px;font-weight:800;color:${cat===mktCat?'#C4B5FD':'var(--sub)'};cursor:pointer;white-space:nowrap;font-family:inherit">${CAT_LABELS[cat]}</button>`).join('');
const show=mktCat==='all'?FA:FA.filter(a=>a.cat===mktCat);
const list=document.getElementById('mkt-list'); if(!list) return;
list.innerHTML=show.map(a=>{
const q=S.mktPort?.[a.id]||0;
const chg=((Math.random()-.44)*9).toFixed(2); const up=+chg>=0;
const pxFmt=a.px>=1000?'$'+(a.px/1000).toFixed(1)+'K':'$'+a.px;
return `<div class="mkt-card ${q>0?'owned':''}">
<div class="mkt-top">
<div class="mkt-ic" style="background:${a.col}18">${a.ic}</div>
<div class="mkt-info">
<div class="mkt-nm">${a.nm}</div>
<div class="mkt-sym">${a.cat} · ${a.sym}</div>
<div class="mkt-desc">${a.desc}</div>
</div>
<div class="mkt-price">
<div class="mkt-px" style="color:${up?'var(--primary2)':'var(--red)'}">${pxFmt}</div>
<div class="mkt-chg" style="color:${up?'var(--primary2)':'var(--red)'}">${up?'▲':'▼'}${Math.abs(chg)}%</div>
</div>
</div>
<div class="mkt-tags">
<span class="pill ${RISK_STYLE[a.risk]}" style="font-size:10px">${a.risk.toUpperCase()} RISK</span>
${q>0?`<span class="pill pill-green" style="font-size:10px">✓ ${q} owned · $${(q*a.px).toFixed(0)}</span>`:''}
</div>
<div class="mkt-btns">
<button class="mkt-btn buy-btn" onclick="openBuy('${a.id}')">BUY +</button>
${q>0?`<button class="mkt-btn sell-btn" onclick="openSell('${a.id}')">SELL −</button>`:''}
</div>
</div>`;
}).join('');
}
function setMktCat(c){ mktCat=c; renderMarket(); }
function openBuy(id){
buyId=id; buyQty=1;
const a=FA.find(x=>x.id===id);
setT('buy-em',a.ic); setT('buy-ttl','Buy '+a.nm);
setT('buy-sub',a.desc+' · '+a.risk.toUpperCase()+' RISK');
document.getElementById('buy-chips').innerHTML=[1,2,5,10].map((q,i)=>`<div class="chip ${i===0?'on':''}" onclick="selBuyQty(${q},this)">×${q}</div>`).join('');
updBuyCost(); openSheet('sheet-buy');
}
function selBuyQty(q,el){ buyQty=q; document.querySelectorAll('#buy-chips .chip').forEach(c=>c.classList.remove('on')); el.classList.add('on'); updBuyCost(); }
function updBuyCost(){
const a=FA.find(x=>x.id===buyId); if(!a) return;
const cost=a.px*buyQty, rem=(S.cash||0)-cost;
setT('buy-cost','$'+cost.toFixed(2)); setT('buy-left','$'+Math.max(0,rem).toFixed(2));
document.getElementById('buy-ok').disabled=rem<0;
}
function confirmBuy(){
const a=FA.find(x=>x.id===buyId); const cost=a.px*buyQty;
if((S.cash||0)<cost){ toast('Not enough cash!'); return; }
S.cash-=cost; S.mktPort=S.mktPort||{}; S.mktPort[a.id]=(S.mktPort[a.id]||0)+buyQty;
addAct(a.ic,a.nm,'Bought '+buyQty+' @ $'+a.px,'-$'+cost.toFixed(0),'var(--red)');
addXP(20); addCoins(5);
recordBeh(a.risk==='high'||a.risk==='extreme'?'buy_risky':'buy_safe');
closeSheet('sheet-buy'); renderMarket(); renderHome(); checkAchs();
toast(a.ic+' Bought '+buyQty+'× '+a.nm+'!');
}
function openSell(id){
sellId=id; const a=FA.find(x=>x.id===id); const q=S.mktPort?.[id]||0;
setT('sell-em',a.ic); setT('sell-ttl','Sell '+a.nm);
setT('sell-sub',q+' owned · worth $'+(q*a.px).toFixed(2));
const opts=[...new Set([1,Math.max(1,Math.floor(q/2)),q])].filter(v=>v>0&&v<=q);
sellQty=opts[0]||1;
document.getElementById('sell-chips').innerHTML=opts.map((v,i)=>`<div class="chip ${i===0?'on':''}" onclick="sellQty=${v};document.querySelectorAll('#sell-chips .chip').forEach(c=>c.classList.remove('on'));this.classList.add('on')">×${v}</div>`).join('');
openSheet('sheet-sell');
}
function confirmSell(){
const a=FA.find(x=>x.id===sellId); const proc=a.px*sellQty;
S.cash+=proc; S.mktPort[sellId]-=sellQty;
if(S.mktPort[sellId]<=0) delete S.mktPort[sellId];
addAct(a.ic,a.nm,'Sold '+sellQty+' shares','+$'+proc.toFixed(0),'var(--primary2)');
addXP(10); addCoins(3);
const sent=detectSentiment('sell'); if(sent) handleSentiment(sent,a.nm);
closeSheet('sheet-sell'); renderMarket(); renderHome(); checkAchs();
toast('💰 Sold '+sellQty+'× '+a.nm+' for $'+proc.toFixed(0));
}
/* ── BRAIN HQ PAGE ──────────────────────────────────────── */
function renderBrain(){
const el=document.getElementById('brain-grid'); if(!el) return;
el.innerHTML=BGAMES.map(b=>{
const done=(S.completedGames||[]).includes(b.id);
return `<div class="brain-card ${done?'done':''}" onclick="openBGame('${b.id}')">
<div style="font-size:34px;margin-bottom:8px">${b.ic}</div>
<div class="h3" style="font-size:13px">${b.nm}</div>
<div style="font-size:10px;color:var(--sub);margin-top:4px;line-height:1.5">${b.desc}</div>
<div style="font-size:11px;font-weight:800;color:${done?'var(--primary2)':'var(--gold)'};margin-top:8px">${done?'✅ Done':'🪙 +'+b.reward}</div>
</div>`;
}).join('');
const done=(S.completedGames||[]).length;
const sc=document.getElementById('bias-score-bar'); if(!sc) return;
if(done>0){
const pct=Math.round(done/BGAMES.length*100);
sc.innerHTML=`<div class="card-purple"><div class="label" style="margin-bottom:10px">🧠 BIAS RESISTANCE SCORE</div>
<div style="display:flex;align-items:center;gap:14px">
<div style="font-size:44px;font-weight:900;color:${behColor(pct)}">${pct}</div>
<div><div class="h3">${pct>70?'Highly Rational':pct>40?'Developing':'Emotionally Driven'}</div>
<div style="font-size:12px;color:var(--sub);margin-top:3px">${done}/${BGAMES.length} games done</div></div>
</div></div>`;
} else sc.innerHTML='';
}
let curBG=null, bgScene=0, bgAnswers=[];
function openBGame(id){
curBG=BGAMES.find(x=>x.id===id); if(!curBG) return;
bgScene=0; bgAnswers=[];
setT('bg-em',curBG.ic); setT('bg-ttl',curBG.nm); setT('bg-sub',curBG.desc);
renderBGScene(); openSheet('sheet-bgame');
}
function renderBGScene(){
if(bgScene>=curBG.scenes.length){ finishBGame(); return; }
const sc=curBG.scenes[bgScene];
document.getElementById('bg-nxt').style.display='none';
document.getElementById('bg-body').innerHTML=`
<div style="background:rgba(124,58,237,.08);border:1px solid rgba(124,58,237,.15);border-left:3px solid var(--primary);border-radius:12px;padding:14px;margin-bottom:13px;font-size:14px;line-height:1.7;color:var(--text)">
<strong>Scenario ${bgScene+1}/${curBG.scenes.length}:</strong><br/><br/>${sc.txt}</div>
<div style="display:flex;flex-direction:column;gap:8px">
<button id="bgo0" onclick="bgChoose(0)" style="width:100%;padding:13px;background:rgba(255,255,255,.06);border:1.5px solid var(--border);border-radius:13px;font-size:13px;font-weight:700;text-align:left;cursor:pointer;color:var(--text);font-family:inherit">${sc.opts[0]}</button>
<button id="bgo1" onclick="bgChoose(1)" style="width:100%;padding:13px;background:rgba(255,255,255,.06);border:1.5px solid var(--border);border-radius:13px;font-size:13px;font-weight:700;text-align:left;cursor:pointer;color:var(--text);font-family:inherit">${sc.opts[1]}</button>
</div>
<div id="bg-result" style="display:none;background:rgba(255,255,255,.04);border-radius:12px;padding:13px;margin-top:12px;font-size:13px;line-height:1.65;color:rgba(241,245,249,.7)"></div>`;
}
function bgChoose(choice){
const sc=curBG.scenes[bgScene]; bgAnswers.push(choice);
const good=choice===sc.better;
document.getElementById('bgo'+choice).style.borderColor=good?'#00D97E':'#EF4444';
document.getElementById('bgo'+choice).style.background=good?'rgba(0,217,126,.1)':'rgba(239,68,68,.1)';
document.getElementById('bgo0').disabled=true; document.getElementById('bgo1').disabled=true;
const res=document.getElementById('bg-result');
res.innerHTML=`<div style="font-size:13px;font-weight:800;color:${good?'#00D97E':'#F87171'};margin-bottom:6px">${good?'✅ Rational Choice!':'💡 Learning Moment'}</div>${good?sc.good:sc.bad}`;
res.style.display='block';
recordBeh(good?'bgame_rational':'delay_no');
const nb=document.getElementById('bg-nxt'); nb.style.display='block';
nb.textContent=bgScene<curBG.scenes.length-1?'Next Scenario →':'See Results 🎯';
}
function bgNext(){ bgScene++; renderBGScene(); }
function finishBGame(){
const correct=bgAnswers.filter((c,i)=>c===curBG.scenes[i]?.better).length;
const pct=Math.round(correct/Math.max(1,curBG.scenes.length)*100);
if(!(S.completedGames||[]).includes(curBG.id)){ (S.completedGames||(S.completedGames=[])).push(curBG.id); addCoins(curBG.reward); addXP(30); }
document.getElementById('bg-body').innerHTML=`<div style="text-align:center;padding:18px 0">
<div style="font-size:64px;margin-bottom:10px">${pct>70?'🧠':'🎯'}</div>
<div style="font-size:34px;font-weight:900;color:${pct>70?'var(--primary2)':'var(--gold)'}">${pct}%</div>
<div style="font-size:15px;font-weight:800;margin:8px 0">${pct>70?'Highly Rational!':pct>40?'Good progress!':'Keep practising!'}</div>
<div style="font-size:13px;color:var(--sub);line-height:1.7">${correct}/${curBG.scenes.length} optimal decisions<br/>🪙 +${curBG.reward} Gold Coins!</div></div>`;
document.getElementById('bg-nxt').style.display='none';
closeSheet('sheet-bgame'); confetti(); renderBrain(); checkAchs(); persistS();
toast('🧠 Brain game complete! +'+curBG.reward+' coins');
}
/* ── WORLD MAP PAGE ─────────────────────────────────────── */
function renderWorld(){
const el=document.getElementById('world-list'); if(!el) return;
el.innerHTML=WORLDS.map((w,wi)=>{
const unlocked=(S.xp||0)>=w.xpReq;
const done=w.ms.filter(m=>(S.completedMissions||[]).includes(m.id)).length;
const pct=Math.round(done/w.ms.length*100);
return `<div class="world-wrap">
<div class="world-hdr" style="background:${w.col}22;border:1px solid ${w.col}30;border-bottom:none">
<div style="font-size:28px">${w.ic}</div>
<div style="flex:1">
<div class="label" style="color:${w.col}">WORLD ${wi+1} ${!unlocked?'· 🔒 LOCKED':''}</div>
<div class="h3">${w.ttl}</div>
</div>
<div class="pill" style="background:${w.col}20;color:${w.col};border:1px solid ${w.col}30;font-size:11px">${pct}%</div>
</div>
<div class="world-body" style="opacity:${unlocked?1:.4}">
<div class="ms-dot-row">
${w.ms.map((m,mi)=>{
const isDone=(S.completedMissions||[]).includes(m.id);
const firstLeft=w.ms.findIndex(x=>!(S.completedMissions||[]).includes(x.id));
const isActive=unlocked&&mi===firstLeft&&!isDone;
return `<div class="ms-dot ${isDone?'done':isActive?'active':''}" onclick="${unlocked?`openMission('${m.id}','${w.id}')`:''}" title="${m.ttl}">${mi+1}</div>`;
}).join('')}
</div>
<div class="prog-bar" style="margin-top:10px"><div class="prog-fill" style="width:${pct}%;background:${w.col}"></div></div>
<div style="font-size:11px;color:var(--sub);margin-top:5px">${!unlocked?'Need '+w.xpReq+' XP to unlock':'Tap a mission dot to start'}</div>
</div>
</div>`;
}).join('');
}
function openMission(msId,wId){
const w=WORLDS.find(x=>x.id===wId); const m=w?.ms.find(x=>x.id===msId); if(!m) return;
if((S.completedMissions||[]).includes(m.id)){ toast('✅ Already completed!'); return; }
setT('ms-em',m.ic); setT('ms-ttl',m.ttl); setT('ms-sub',w.ttl);
document.getElementById('ms-body').innerHTML=`
<div class="card-purple" style="margin:12px 0;font-size:13px;line-height:1.7;color:rgba(241,245,249,.75)">${m.desc}</div>
<div class="label" style="margin-bottom:6px">OBJECTIVE</div>
<div style="font-size:14px;font-weight:700;margin-bottom:14px">${m.obj}</div>
<div style="display:flex;gap:10px">
<div class="card-gold" style="flex:1;text-align:center;margin:0"><div style="font-size:18px;font-weight:900;color:var(--gold)">${m.xp} XP</div><div class="label" style="margin-top:2px">Reward</div></div>
<div class="card-green" style="flex:1;text-align:center;margin:0"><div style="font-size:18px;font-weight:900;color:var(--primary2)">🪙 ${m.coins}</div><div class="label" style="margin-top:2px">Coins</div></div>
</div>`;
document.getElementById('ms-ok').onclick=()=>{
(S.completedMissions||(S.completedMissions=[])).push(m.id);
addXP(m.xp); addCoins(m.coins); recordBeh('mission');
closeSheet('sheet-mission'); confetti(); renderWorld(); checkAchs(); persistS();
toast('🗺️ Mission complete! +'+m.xp+' XP');
};
openSheet('sheet-mission');
}
/* ── LEADERBOARD PAGE ───────────────────────────────────── */
const FAKE={
gaming:[{name:'AhmedK',av:'🦁',saved:220,target:300,sym:'$',lv:5},{name:'SaraM',av:'🦄',saved:180,target:300,sym:'$',lv:4},{name:'OmarF',av:'🐉',saved:145,target:300,sym:'$',lv:3}],
sneakers:[{name:'NourH',av:'🐯',saved:160,target:200,sym:'$',lv:4},{name:'KhalidR',av:'🦊',saved:95,target:200,sym:'$',lv:2}],
trip:[{name:'LaylaN',av:'🐼',saved:450,target:1000,sym:'$',lv:6}],
college:[{name:'JihadA',av:'🦅',saved:1200,target:5000,sym:'$',lv:7}],
business:[{name:'WalidF',av:'🐺',saved:300,target:500,sym:'$',lv:5}],
};
function renderLeaderboard(){
const el=document.getElementById('lb-body'); if(!el) return;
const myGoals=S.goals||[];
const allCh=DB.allChildren();
const groups={};
// Add fake
Object.entries(FAKE).forEach(([gId,players])=>{ groups[gId]={gId,icon:GOALS_DB[gId]?.icon||'🎯',name:GOALS_DB[gId]?.name||gId,players:[...players.map(p=>({...p,isMe:false}))]}; });
// Add real children
allCh.forEach(c=>(c.S?.goals||[]).forEach(g=>{
if(!groups[g.id]) groups[g.id]={gId:g.id,icon:g.icon||'🎯',name:g.name||g.id,players:[]};
const isMe=CU?.role==='child'&&c.username===CU.data.username;
if(!groups[g.id].players.find(p=>p.name===c.name))
groups[g.id].players.push({name:c.name,av:c.S.avatar||'🦊',saved:g.saved||0,target:g.target||1,sym:g.sym||'$',lv:getLv().lv,isMe});
}));
const myGoalIds=myGoals.map(g=>g.id);
const sorted=Object.values(groups).sort((a,b)=>myGoalIds.includes(a.gId)?-1:myGoalIds.includes(b.gId)?1:0);
el.innerHTML=sorted.map(group=>{
const pl=[...group.players].sort((a,b)=>(b.saved/b.target)-(a.saved/a.target));
const meIdx=pl.findIndex(p=>p.isMe);
return `<div class="lb-group">
<div class="lb-group-hdr">
<div style="font-size:24px">${group.icon}</div>
<div><div style="font-size:15px;font-weight:900">${group.name}</div>
<div style="font-size:11px;opacity:.7">${pl.length} players${meIdx>=0?' · You rank #'+(meIdx+1)+' (top '+Math.round((1-meIdx/pl.length)*100)+'%)':''}</div></div>
</div>
${pl.slice(0,8).map((p,i)=>{
const pct=Math.min(100,Math.round((p.saved/p.target)*100));
const medal=i===0?'🥇':i===1?'🥈':i===2?'🥉':'#'+(i+1);
return `<div class="lb-row ${p.isMe?'me':''}">
<div style="width:28px;font-size:14px;font-weight:900;color:var(--sub)">${medal}</div>
<div style="font-size:22px">${p.av}</div>
<div style="flex:1">
<div style="font-size:13px;font-weight:800">${p.isMe?'You ('+p.name+')':p.name}</div>
<div class="lb-cmp-bar"><div class="lb-cmp-fill" style="width:${pct}%;background:${p.isMe?'var(--primary)':i<3?'var(--gold)':'var(--sub)'}"></div></div>
<div style="font-size:10px;color:var(--sub)">${p.sym}${p.saved} of ${p.sym}${p.target} · Lv ${p.lv}</div>
</div>
</div>`;
}).join('')}
</div>`;
}).join('') || '<div class="empty">No goals set yet.<br/>Add a goal to appear on the leaderboard! 🏆</div>';
}
/* ── ACHIEVEMENTS PAGE ──────────────────────────────────── */
function checkAchs(){
let newUnlock=null;
[...ACHIEVEMENTS,...CERTS,...(typeof EXTRA_ACHIEVEMENTS!=='undefined'?EXTRA_ACHIEVEMENTS:[])].forEach(a=>{
if(!(S.unlockedAchs||[]).includes(a.id)&&a.cond&&a.cond()){
(S.unlockedAchs||(S.unlockedAchs=[])).push(a.id);
if(a.rew) addCoins(a.rew);
if(a.xp) addXP(a.xp);
if(a.coins) addCoins(a.coins);
newUnlock=a;
}
});
if(newUnlock){
setT('au-ic',newUnlock.ic||'🏅'); setT('au-ttl',newUnlock.nm);
setT('au-desc',newUnlock.desc);
document.getElementById('au-rew').textContent='🪙 +'+(newUnlock.rew||newUnlock.coins||0);
openSheet('sheet-ach-unlock'); confetti();
}
persistS();
}
function renderAchievements(){
const grid=document.getElementById('ach-grid'); if(!grid) return;
grid.innerHTML=[...ACHIEVEMENTS,...(typeof EXTRA_ACHIEVEMENTS!=='undefined'?EXTRA_ACHIEVEMENTS:[])].map(a=>{
const unlocked=(S.unlockedAchs||[]).includes(a.id);
return `<div class="ach-card ${unlocked?'unlocked':'locked'}">
<div class="ach-ic">${a.ic}</div>
<div class="ach-nm">${a.nm}</div>
<div style="font-size:8px;color:var(--sub);margin-top:3px;line-height:1.4">${a.desc}</div>
<div class="ach-rew">${unlocked?'✅ Earned':'🪙 +'+a.rew}</div>
</div>`;
}).join('');
const certEl=document.getElementById('cert-list'); if(!certEl) return;
certEl.innerHTML=CERTS.map(c=>{
const unlocked=(S.unlockedAchs||[]).includes(c.id);
return `<div class="cert-card ${unlocked?'':'locked'}">
<div class="cert-bg-ic">${c.ic}</div>
<div style="font-size:44px;margin-bottom:10px">${c.ic}</div>
<div style="font-size:17px;font-weight:900;color:var(--gold);margin-bottom:4px">${c.nm}</div>
<div style="font-size:12px;color:rgba(255,255,255,.5);line-height:1.6;margin-bottom:10px">${c.desc}</div>
<div style="font-size:11px;font-weight:800;color:rgba(255,255,255,.3);margin-bottom:10px">📋 ${c.req}</div>
<div style="height:5px;background:rgba(255,255,255,.1);border-radius:3px;overflow:hidden;margin-bottom:8px"><div style="width:${unlocked?100:0}%;height:100%;background:var(--grad-gold);border-radius:3px"></div></div>
<div style="font-size:11px;font-weight:800;color:${unlocked?'var(--gold)':'rgba(255,255,255,.3)'}">${unlocked?'✅ EARNED! +'+c.coins+' GCoins':'Not yet earned'}</div>
</div>`;
}).join('');
}
/* ── GOALS PAGE ─────────────────────────────────────────── */
function renderGoals(){
const el=document.getElementById('goals-list'); if(!el) return;
if(!(S.goals||[]).length){ el.innerHTML='<div class="empty">No goals yet.<br/>Tap the gold card above to add one! 🎯</div>'; return; }
el.innerHTML=(S.goals||[]).map(g=>{
const pct=Math.min(100,Math.round((g.saved/g.target)*100));
return `<div class="card" style="${pct>=100?'border-color:rgba(0,217,126,.35)':''}">
<div style="display:flex;align-items:center;gap:11px;margin-bottom:11px">
<div style="font-size:28px">${g.icon}</div>
<div style="flex:1"><div class="h3">${g.name}</div><div style="font-size:11px;color:var(--sub);margin-top:2px">${g.currency||'USD'}</div></div>
${pct>=100?'<span class="pill pill-green">✅ Done!</span>':''}
</div>
<div class="prog-bar"><div class="prog-fill" style="width:${pct}%;background:var(--primary2)"></div></div>
<div style="display:flex;justify-content:space-between;margin-top:6px;font-size:12px;color:var(--sub)">
<span>${g.sym||'$'}${g.saved.toFixed(0)} saved</span>
<span>${g.sym||'$'}${g.target} target</span>
</div>
<div class="btn-row" style="margin-top:11px">
<button class="btn btn-green btn-sm" onclick="quickContribute('${g.id}')">💰 +$50</button>
<button class="btn btn-ghost btn-sm" onclick="getGoalAdvice('${g.id}')">🤖 Advice</button>
</div>
</div>`;
}).join('');
}
function selGoal(el){ document.querySelectorAll('#ng-grid .goal-c').forEach(c=>c.classList.remove('on')); el.classList.add('on'); }
function selCurr(el){
document.querySelectorAll('#ng-curr .curr-c').forEach(c=>c.classList.remove('on')); el.classList.add('on');
setT('ng-sym',el.dataset.sym);
}
function doAddGoal(){
const sel=document.querySelector('#ng-grid .goal-c.on'); if(!sel){ toast('Pick a goal first!'); return; }
const gId=sel.dataset.g; const gd=GOALS_DB[gId];
if((S.goals||[]).find(g=>g.id===gId)){ toast('Already added this goal!'); closeSheet('sheet-addgoal'); return; }
const cname=document.getElementById('ng-name')?.value.trim();
const camt=parseFloat(document.getElementById('ng-amt')?.value||'0');
const cEl=document.querySelector('#ng-curr .curr-c.on')||{dataset:{code:'USD',sym:'$'}};
const code=cEl.dataset.code, sym=cEl.dataset.sym;
const target=camt>0?camt:(gd.targets[code]||gd.targets.USD);
(S.goals||(S.goals=[])).push({id:gId,icon:gd.icon,name:cname||gd.name,target,saved:0,sym,currency:code});
addXP(5); addCoins(5); recordBeh('goal_contribute');
closeSheet('sheet-addgoal'); renderGoals(); renderGoalBanner(); checkAchs(); persistS();
toast('🎯 Goal added: '+(cname||gd.name)+'!');
}
function quickContribute(gId){
const g=(S.goals||[]).find(x=>x.id===gId); if(!g) return;
const amt=Math.min(50,S.cash||0);
if(amt<=0){ toast('Not enough cash!'); return; }
S.cash-=amt; g.saved+=amt; recordBeh('goal_contribute');
addXP(8); addCoins(3); renderGoals(); renderGoalBanner(); renderHome(); checkAchs(); persistS();
toast('🎯 +$'+amt+' toward '+g.name+'!');
}
async function getGoalAdvice(gId){
const g=(S.goals||[]).find(x=>x.id===gId); if(!g) return;
goPage('page-kai');
await askKai(`I'm saving for ${g.name}. I need ${g.sym||'$'}${g.target} and have ${g.sym||'$'}${g.saved.toFixed(0)} so far. I'm ${S.age||12} years old. Give me a simple savings plan in 3 steps.`);
}
/* ── KAI AI MENTOR PAGE ─────────────────────────────────── */
let kaiHistory=[];
const KAI_QUESTIONS=[
'How do I move up the leaderboard? 🏆',
'How can I save faster? 💰',
'What mistakes am I making? 🤔',
'Is my risk level too high? ⚠️',
"What's the best investment for me? 📈",
'How do I reach my goal? 🎯',
];
function loadKai(){
const msgs=document.getElementById('kai-msgs');
const chips=document.getElementById('kai-chips');
if(!msgs) return;
msgs.innerHTML=''; kaiHistory=[];
const lv=getLv();
appendMsg('ai',`Hey ${S.name||'there'}! 👋 I'm Kai, your K2 AI money coach.\n\nI can see you are Level ${lv.lv} (${lv.title}) with ${S.xp||0} XP and ${(S.goals||[]).length} goal${(S.goals||[]).length!==1?'s':''} active.\n\nAsk me anything — I'll give you short, honest advice! 🎯`);
if(chips) chips.innerHTML=KAI_QUESTIONS.map(q=>`<div class="chat-chip" onclick="askKai('${q.replace(/'/g,"\\'")}') ">${q}</div>`).join('');
}
function appendKaiResult(text){
var el=document.getElementById('kai-msgs');if(!el)return;
el.querySelectorAll('.kai-result').forEach(function(n){n.remove();});
var d=document.createElement('div');d.className='kai-result';
d.style.cssText='background:linear-gradient(135deg,rgba(0,217,126,.1),rgba(0,217,126,.04));border:1.5px solid rgba(0,217,126,.2);border-radius:14px;padding:14px 16px;margin:8px 0;font-size:14px;line-height:1.75;color:rgba(241,245,249,.92);font-weight:600;';
d.textContent=text;el.appendChild(d);el.scrollTop=el.scrollHeight;
}
function appendMsg(role,text){
const el=document.getElementById('kai-msgs'); if(!el) return;
const d=document.createElement('div'); d.className='chat-msg '+role; d.textContent=text;
el.appendChild(d); el.scrollTop=el.scrollHeight;
}
function showKaiTyping(){
const el=document.getElementById('kai-msgs'); if(!el) return;
const d=document.createElement('div'); d.className='chat-msg ai'; d.id='kai-typing';
d.innerHTML='<span style="display:flex;align-items:center;gap:8px"><span style="width:16px;height:16px;border:2px solid rgba(255,255,255,.2);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite;flex-shrink:0"></span>Kai is thinking...</span>';
el.appendChild(d); el.scrollTop=el.scrollHeight;
}
function rmKaiTyping(){ document.getElementById('kai-typing')?.remove(); }
async function askKai(q){
if(!q.trim()) return;
kaiHistory.push({role:'user',content:q});
const chips=document.getElementById('kai-chips'); if(chips) chips.innerHTML='';
showKaiTyping();
const beh=getBeh();
const g=S.goals?.[0];
const ctx=`Player: ${S.name||'Player'}, age ${S.age||12}, Level ${getLv().lv}. XP: ${S.xp||0}. Cash: $${(S.cash||0).toFixed(0)}.
Goal: ${g?g.name+' ('+Math.round((g.saved/g.target)*100)+'% saved)':'none'}.
Lessons done: ${(S.learningDone||[]).length}/13. Brain games: ${(S.completedGames||[]).length}/6.
Delay score: ${beh.delay}/100. Risk: ${beh.risk}/100. Discipline: ${beh.discipline}/100.
Question: "${q}"`;
try{
const r=await k2(
`You are Kai, money coach for a ${S.age||12}-year-old. ABSOLUTE RULES: 1) Output ONLY the recommendation — zero thinking, zero reasoning, zero preamble, zero steps. 2) Max 2 sentences. Simple words. 3) Use the player's real numbers. 4) End with one emoji. 5) Never start with I/Let me/So/Well/Great/Based on/Looking at.`,
ctx, 180);
rmKaiTyping(); appendKaiResult(r);
kaiHistory.push({role:'assistant',content:r});
addXP(3); addCoins(1); persistS();
} catch(e){
rmKaiTyping(); appendMsg('ai','Connection issue! Try again in a moment. 🔄');
}
}
function sendKai(){
const inp=document.getElementById('kai-inp'); const q=inp.value.trim(); if(!q) return;
if((S.goldCoins||0)<20){ toast('Need 20 🪙 Gold Coins to ask Kai!'); return; }
S.goldCoins-=20; document.getElementById('coins-val').textContent=S.goldCoins;
inp.value=''; askKai(q);
}
/* ── PARENT AUTH ────────────────────────────────────────── */
function doParentSignup(){
const name=document.getElementById('ps-name').value.trim();
const email=document.getElementById('ps-email').value.trim();
const pass=document.getElementById('ps-pass').value;
const country=document.getElementById('ps-country').value;
const err=document.getElementById('ps-err');
err.style.display='none';
if(!name||!email||!pass){ err.textContent='Please fill in all fields'; err.style.display='block'; return; }
if(pass.length<6){ err.textContent='Password must be at least 6 characters'; err.style.display='block'; return; }
const res=DB.createParent({name,email,password:pass,country});
if(!res.ok){ err.textContent=res.msg; err.style.display='block'; return; }
CU={role:'parent',data:res.data}; DB.saveSession({role:'parent',id:email});
goPage('page-pdash');
}
function doParentLogin(){
const email=document.getElementById('pl-email').value.trim();
const pass=document.getElementById('pl-pass').value;
const err=document.getElementById('pl-err'); err.style.display='none';
const res=DB.loginParent({email,password:pass});
if(!res.ok){ err.textContent=res.msg; err.style.display='block'; return; }
CU={role:'parent',data:res.data}; goPage('page-pdash');
}
/* ── CREATE CHILD ───────────────────────────────────────── */
let ccAv='🦊';
function selCCav(el){ document.querySelectorAll('.av-c').forEach(a=>a.classList.remove('on')); el.classList.add('on'); ccAv=el.dataset.em||'🦊'; }
function doCreateChild(){
const name=document.getElementById('cc-name').value.trim();
const username=document.getElementById('cc-user').value.trim().toLowerCase().replace(/\s+/g,'_');
const pass=document.getElementById('cc-pass').value;
const age=document.getElementById('cc-age').value;
const err=document.getElementById('cc-err'); err.style.display='none';
if(!name||!username||!pass||!age){ err.textContent='Please fill all fields'; err.style.display='block'; return; }
if(!CU||CU.role!=='parent'){ err.textContent='Please log in as parent first'; err.style.display='block'; return; }
const res=DB.createChild({parentEmail:CU.data.email,username,password:pass,name,avatar:ccAv,age});
if(!res.ok){ err.textContent=res.msg; err.style.display='block'; return; }
CU.data=DB.getParent(CU.data.email);
toast('✅ Child account created for '+name+'!'); goPage('page-pdash');
}
/* ── CHILD LOGIN ────────────────────────────────────────── */
function doChildLogin(){
const username=document.getElementById('cl-user').value.trim().toLowerCase().replace(/\s+/g,'_');
const pass=document.getElementById('cl-pass').value;
const err=document.getElementById('cl-err'); err.style.display='none';
const res=DB.loginChild({username,password:pass});
if(!res.ok){ err.textContent=res.msg; err.style.display='block'; return; }
CU={role:'child',data:res.data}; S=res.data.S; goPage('page-home'); initMarketPrices(); startEventScheduler(); loadLimitOrders();
}
/* ── PARENT DASHBOARD ───────────────────────────────────── */
function renderPDash(){
if(!CU||CU.role!=='parent') return;
const p=CU.data; setT('pd-name','Hi, '+p.name+'! 👋');
const children=DB.parentChildren(p.email);
const tabs=document.getElementById('child-tabs');
if(tabs) tabs.innerHTML=children.map((c,i)=>`<div class="child-tab ${i===0?'on':''}" onclick="pdSelectChild(${i},this)">${c.avatar} ${c.name}</div>`).join('')
+`<div class="child-tab" onclick="goPage('page-addchild')">+ Add</div>`;
if(children.length>0) pdRenderChild(children[0]);
else document.getElementById('pd-body').innerHTML='<div class="section"><div class="empty">No children yet.<br/>Tap <strong>+ Add Child</strong> above.</div></div>';
}
function pdSelectChild(i,el){
document.querySelectorAll('.child-tab').forEach((t,j)=>t.classList.toggle('on',j===i));
const children=DB.parentChildren(CU.data.email); if(children[i]) pdRenderChild(children[i]);
}
function pdRenderChild(child){
const s=child.S||{}; const beh=child.beh||{delay:50,risk:50,discipline:50,planning:50,consistency:50};
const lv=LEVELS.find(l=>(s.xp||0)>=l.req)||LEVELS[0];
const nw=(s.cash||0)+Object.entries(s.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0)+(s.port?.save||0);
const body=document.getElementById('pd-body'); if(!body) return;
// Hide the no-children placeholder
const noKids=document.getElementById('pd-no-children');
if(noKids) noKids.style.display='none';
body.innerHTML=`<div class="section">
<!-- REPORT BANNER -->
<div style="background:linear-gradient(135deg,rgba(0,217,126,.12),rgba(0,217,126,.04));border:1px solid rgba(0,217,126,.22);border-radius:14px;padding:14px 15px;margin-bottom:14px;display:flex;align-items:center;gap:12px">
<div style="font-size:30px">&#129302;</div>
<div style="flex:1">
<div style="font-size:13px;font-weight:900;color:#6EE7B7;margin-bottom:3px">K2 AI Child Report — ${child.name}</div>
<div style="font-size:11px;color:rgba(255,255,255,.5)">Full behavioral analysis, credit score &amp; personalised parent advice below</div>
</div>
</div>
<!-- Stats -->
<div class="stats-grid" style="margin-bottom:12px">
<div class="stat-box"><div class="stat-v">${s.avatar||'🦊'}</div><div class="stat-l">Avatar</div></div>
<div class="stat-box"><div class="stat-v" style="color:var(--gold)">Lv ${lv.lv}</div><div class="stat-l">${lv.title}</div></div>
<div class="stat-box"><div class="stat-v" style="color:var(--primary2)">$${nw.toFixed(0)}</div><div class="stat-l">Net Worth</div></div>
<div class="stat-box"><div class="stat-v" style="color:var(--gold)">🪙${s.goldCoins||0}</div><div class="stat-l">Gold Coins</div></div>
</div>
<!-- Goals -->
<div class="card-dark" style="margin-bottom:12px">
<div class="label" style="margin-bottom:10px">🎯 SAVINGS GOALS</div>
${(s.goals||[]).length?
(s.goals||[]).map(g=>{const pct=Math.min(100,Math.round((g.saved/g.target)*100)); return `<div style="margin-bottom:10px"><div style="display:flex;justify-content:space-between;font-size:13px;font-weight:700;margin-bottom:4px"><span>${g.icon} ${g.name}</span><span style="color:var(--primary2)">${pct}%</span></div><div class="prog-bar"><div class="prog-fill" style="width:${pct}%;background:var(--primary2)"></div></div><div style="font-size:11px;color:var(--sub);margin-top:3px">${g.sym||'$'}${g.saved.toFixed(0)} of ${g.sym||'$'}${g.target}</div></div>`;}).join('')
:'<div style="color:var(--sub);font-size:13px">No goals set yet</div>'}
</div>
<!-- Progress -->
<div class="card-dark" style="margin-bottom:12px">
<div class="label" style="margin-bottom:10px">📊 LEARNING PROGRESS</div>
<div class="stats-grid stat-3">
<div class="stat-box"><div class="stat-v" style="color:var(--primary)">${(s.learningDone||[]).length}/13</div><div class="stat-l">Lessons</div></div>
<div class="stat-box"><div class="stat-v" style="color:var(--primary)">${(s.completedGames||[]).length}/6</div><div class="stat-l">Brain Games</div></div>
<div class="stat-box"><div class="stat-v" style="color:var(--primary)">${(s.completedMissions||[]).length}/15</div><div class="stat-l">Missions</div></div>
</div>
</div>
<!-- Behavioral -->
<div class="card-dark" style="margin-bottom:12px">
<div class="label" style="margin-bottom:12px">🧠 BEHAVIORAL ANALYTICS</div>
<div class="beh-row"><div class="beh-lbl">Delay Gratif.</div><div class="beh-bar"><div class="beh-fill" style="width:${beh.delay}%;background:${behColor(beh.delay)}"></div></div><div class="beh-val">${beh.delay}</div></div>
<div class="beh-row"><div class="beh-lbl">Risk Appetite</div><div class="beh-bar"><div class="beh-fill" style="width:${beh.risk}%;background:${behColor(beh.risk)}"></div></div><div class="beh-val">${beh.risk}</div></div>
<div class="beh-row"><div class="beh-lbl">Discipline</div><div class="beh-bar"><div class="beh-fill" style="width:${beh.discipline}%;background:${behColor(beh.discipline)}"></div></div><div class="beh-val">${beh.discipline}</div></div>
<div class="beh-row"><div class="beh-lbl">Planning</div><div class="beh-bar"><div class="beh-fill" style="width:${beh.planning}%;background:${behColor(beh.planning)}"></div></div><div class="beh-val">${beh.planning}</div></div>
<div class="beh-row"><div class="beh-lbl">Consistency</div><div class="beh-bar"><div class="beh-fill" style="width:${beh.consistency}%;background:${behColor(beh.consistency)}"></div></div><div class="beh-val">${beh.consistency}</div></div>
<div id="pd-radar-${child.id}" style="margin-top:14px"><canvas id="radar-canvas-${child.id}" height="200"></canvas></div>
</div>
<!-- AI Insight -->
<div class="card-dark" id="pd-ai-${child.id}">
<div class="label" style="margin-bottom:8px">🤖 K2 AI INSIGHT</div>
<div class="spin"><div class="spinner"></div>Generating insight...</div>
</div>
<!-- Recent Decisions -->
<div class="card-dark">
<div class="label" style="margin-bottom:8px">📋 RECENT DECISIONS (${beh.total||0} total)</div>
${(s.decisions||[]).slice(0,5).map(d=>`<div style="padding:8px 0;border-bottom:1px solid var(--border);font-size:12px;color:rgba(241,245,249,.55);line-height:1.5">${d.text||d}</div>`).join('')||'<div style="color:var(--sub);font-size:12px">No decisions recorded yet</div>'}
</div>
</div>`;
// Append bounties + matching panel
const bountyHtml=renderParentBounties(child.username||child.id);
if(bountyHtml){
const extra=document.createElement('div');
extra.innerHTML=bountyHtml;
document.getElementById('pd-body')?.appendChild(extra);
}
setTimeout(()=>{ drawRadar(child,beh); loadPdAI(child,beh,s); },150);
}
function drawRadar(child,beh){
const canvas=document.getElementById('radar-canvas-'+child.id); if(!canvas||typeof Chart==='undefined') return;
new Chart(canvas,{type:'radar',
data:{labels:['Delay\nGratif','Risk\nTolerance','Discipline','Planning','Consistency'],
datasets:[{label:'Profile',data:[beh.delay,beh.risk,beh.discipline,beh.planning,beh.consistency],
backgroundColor:'rgba(124,58,237,.2)',borderColor:'rgba(124,58,237,.8)',borderWidth:2,
pointBackgroundColor:'#7C3AED',pointRadius:4}]},
options:{scales:{r:{min:0,max:100,ticks:{stepSize:25,font:{size:9},color:'#64748B'},
pointLabels:{font:{size:10,weight:'800'},color:'#94A3B8'}}},
plugins:{legend:{display:false}},animation:{duration:600}}});
}
async function loadPdAI(child,beh,s){
const el=document.getElementById('pd-ai-'+child.id); if(!el) return;
const lv=LEVELS.find(l=>(s.xp||0)>=l.req)||LEVELS[0];
const totalDonated=s.totalDonated||0;
const creditScore=Math.min(850,Math.max(300,600
+Math.min(80,(s.learningDone||[]).length*6)
+Math.min(60,(s.completedMissions||[]).length*4)
+Math.min(80,(s.goals||[]).filter(g=>g.saved>=g.target).length*40)
+Math.min(50,Math.floor((s.streak||1)/3)*5)
-Math.min(80,(s.decisions||[]).filter(d=>d.negative).length*8)));
const nw=(s.cash||0)+Object.entries(s.mktPort||{}).reduce((t,[id,q])=>{const a=FA.find(x=>x.id===id);return t+(a?a.px*q:0);},0)+(s.port?.save||0);
const portAssets=Object.keys(s.mktPort||{}).length;
const prompt='CHILD PROFILE FOR PARENT REPORT:\n'
+'Name: '+child.name+', Age: '+child.age+', Level: '+lv.lv+' ('+lv.title+')\n'
+'Net Worth: $'+nw.toFixed(0)+' | Cash: $'+(s.cash||0).toFixed(0)+' | Assets owned: '+portAssets+'\n'
+'Lessons completed: '+(s.learningDone||[]).length+'/13 | Brain games: '+(s.completedGames||[]).length+'/6 | Missions: '+(s.completedMissions||[]).length+'/15\n'
+'Quest Credit Score: '+creditScore+' | Streak: '+(s.streak||0)+' days | Total decisions: '+(beh.total||0)+'\n'
+'Behavioral scores (0-100): Delay Gratification='+beh.delay+', Risk Appetite='+beh.risk+', Discipline='+beh.discipline+', Planning='+beh.planning+', Consistency='+beh.consistency+'\n'
+'Charitable giving: $'+totalDonated+' donated | Savings goals: '+(s.goals||[]).length+' goals\n\n'
+'Write a warm, specific 3-sentence parent report: (1) key insight about this child financial personality based on their behavioral scores and portfolio, (2) one specific strength to celebrate based on their actual numbers, (3) one concrete actionable thing the parent can do THIS WEEK to reinforce good habits.';
el.innerHTML='<div class="label" style="margin-bottom:8px">&#129302; K2 AI CHILD REPORT</div><div class="spin"><div class="spinner"></div>Generating personalised report...</div>';
loadPdAI._call(child,prompt,lv,nw,creditScore,beh,s,el);
}
loadPdAI._call=async function(child,prompt,lv,nw,creditScore,beh,s,el){
try{
const sys='You are a child financial expert writing a parent report. ABSOLUTE RULE: Output ONLY the 3-sentence report. Zero thinking. Zero reasoning. Zero preamble. Zero meta-commentary. Just 3 sentences, nothing else.';
const r=await k2(sys,prompt,250);
const portBreakdown=Object.entries(s.mktPort||{}).map(([id,q])=>{const a=FA.find(x=>x.id===id);return a?a.nm+' x'+q:'';}).filter(Boolean).join(', ')||'No investments yet';
el.innerHTML='<div class="label" style="margin-bottom:10px">&#129302; K2 AI CHILD REPORT</div>'
+'<div style="background:rgba(0,217,126,.06);border:1px solid rgba(0,217,126,.15);border-radius:10px;padding:13px;margin-bottom:12px">'
+'<div style="font-size:13px;line-height:1.75;color:rgba(241,245,249,.82)">'+r+'</div></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:7px;margin-bottom:10px">'
+'<div class="stat-box"><div class="stat-v" style="color:#6EE7B7;font-size:16px">'+creditScore+'</div><div class="stat-l">Credit Score</div></div>'
+'<div class="stat-box"><div class="stat-v" style="color:var(--gold);font-size:16px">$'+nw.toFixed(0)+'</div><div class="stat-l">Net Worth</div></div>'
+'<div class="stat-box"><div class="stat-v" style="color:#C4B5FD;font-size:16px">'+(s.streak||0)+'d</div><div class="stat-l">Streak</div></div>'
+'</div>'
+'<div style="font-size:11px;color:rgba(255,255,255,.35);background:rgba(255,255,255,.04);border-radius:8px;padding:9px 10px">'
+'<span style="font-weight:700;color:rgba(255,255,255,.5)">Portfolio: </span>'+portBreakdown+'</div>';
}catch(e){
el.innerHTML='<div class="label" style="margin-bottom:8px">&#129302; K2 AI CHILD REPORT</div><div style="font-size:13px;color:var(--sub)">AI unavailable — check connection.</div>';
}
};
async function openRebalance(){
if((S.goldCoins||0)<50){ toast('Need 50 🪙 to run rebalancer!'); return; }
S.goldCoins-=50; persistS();
openSheet('sheet-rebalance');
const bars=FA.map(a=>({nm:a.nm.split(' ')[0],val:(S.mktPort?.[a.id]||0)*a.px,col:a.col})).filter(b=>b.val>0);
const maxV=Math.max(1,...bars.map(b=>b.val));
const ch=document.getElementById('rb-chart');
ch.innerHTML=bars.length?bars.map(b=>`<div style="display:flex;flex-direction:column;align-items:center;gap:4px;flex:1"><div style="width:100%;background:${b.col};border-radius:5px 5px 0 0;height:${(b.val/maxV)*68}px;position:relative"><span style="position:absolute;top:-18px;left:50%;transform:translateX(-50%);font-size:9px;font-weight:800;white-space:nowrap;color:var(--text)">$${b.val.toFixed(0)}</span></div><span style="font-size:9px;font-weight:700;color:var(--sub)">${b.nm}</span></div>`).join('')
:'<div style="color:var(--sub);font-size:13px;text-align:center;width:100%">No investments yet</div>';
const sug=document.getElementById('rb-suggest');
sug.innerHTML='<div class="spin"><div class="spinner"></div>K2 AI analysing your portfolio...</div>';
const desc=FA.map(a=>`${a.nm}: $${((S.mktPort?.[a.id]||0)*a.px).toFixed(0)}`).join(', ');
try{
const r=await k2(`You are Kai, a fun money coach. STRICT RULES: (1) Output ONLY your final advice — zero thinking, zero chain-of-thought, no <think> tags. (2) Exactly 2 short sentences. (3) Simple words a child understands. (4) One specific action to take.`,`My portfolio: ${desc}. My goal: ${S.goals?.[0]?.name||'grow my money'}. Is it balanced? What ONE change should I make?`,200);
sug.innerHTML=`<div class="card-purple" style="margin-top:10px"><div style="font-size:12px;font-weight:800;color:#C4B5FD;margin-bottom:6px">🤖 K2 AI Suggests:</div><div style="font-size:13px;line-height:1.7;color:rgba(241,245,249,.8)">${r}</div></div>`;
document.getElementById('rb-btn').disabled=false;
}catch(e){
sug.innerHTML='<div class="card-dark" style="margin-top:10px;font-size:13px;color:var(--sub)">🤖 Tip: Diversify across 3+ asset types for better balance!</div>';
document.getElementById('rb-btn').disabled=false;
}
}
function applyRb(){
addAct('⚖️','Rebalanced','Applied K2 AI advice','✓','#C4B5FD');
addXP(15); closeSheet('sheet-rebalance'); renderHome(); toast('✅ Portfolio rebalanced!');
}
/* ── INIT ───────────────────────────────────────────────── */
window.addEventListener('DOMContentLoaded',()=>{
// Create demo accounts if not already exist (for testing)
try {
const ch=DB.children;
if(!ch['demo_child']){
// Create demo parent
if(!DB.parents['demo@lifequest.com']){
DB.createParent({name:'Demo Parent',email:'demo@lifequest.com',password:'demo123',country:'UAE'});
}
// Create demo child
DB.createChild({parentEmail:'demo@lifequest.com',username:'demo_child',password:'demo123',
name:'Alex',avatar:'🦊',age:12});
}
} catch(e) {}
const role=initSession();
if(role==='parent') goPage('page-pdash');
else if(role==='child') goPage('page-home');
else goPage('page-welcome');
});
/* ═══════════════════════════════════════════════════════════
LEARN → EARN → DO → SIMULATE FRAMEWORK
═══════════════════════════════════════════════════════════ */
var currentPhase='learn';
function getLessonsDone(){return(S.learningDone||[]).length;}
function isPhaseUnlocked(phase){
var d=getLessonsDone();
if(phase==='learn'||phase==='earn')return true;
if(phase==='do')return d>=3;
if(phase==='sim')return d>=5;
return false;
}
function updatePhaseLocks(){
var d=getLessonsDone();
var doTab=document.getElementById('bnav-do');
var doLock=document.getElementById('bnav-do-lock');
if(doTab){if(d>=3){doTab.classList.remove('phase-locked');if(doLock)doLock.style.display='none';}
else{doTab.classList.add('phase-locked');if(doLock){doLock.style.display='flex';doLock.textContent='🔒';}}}
var simTab=document.getElementById('bnav-sim');
var simLock=document.getElementById('bnav-sim-lock');
if(simTab){if(d>=5){simTab.classList.remove('phase-locked');if(simLock)simLock.style.display='none';}
else{simTab.classList.add('phase-locked');if(simLock){simLock.style.display='flex';simLock.textContent='🔒';}}}
}
function switchPhase(phase){
if(!isPhaseUnlocked(phase)){tryUnlockedPhase(phase);return;}
currentPhase=phase;
document.querySelectorAll('.mq-bnav-tab').forEach(function(t){t.classList.remove('active');});
var tab=document.getElementById('bnav-'+phase);
if(tab)tab.classList.add('active');
if(phase==='learn')goPage('page-home');
else if(phase==='earn'){goPage('page-earn');renderEarnPhase();}
else if(phase==='do'){goPage('page-do');renderDoPhase();}
else if(phase==='sim'){goPage('page-sim');renderSimPhase();}
}
function tryUnlockedPhase(phase){
var needed=(phase==='do')?3:5;
var nm=(phase==='do')?'Do':'Simulate';
toast('Complete '+needed+' lessons to unlock '+nm+' 🔒');
}
function showBottomNav(){
var nav=document.getElementById('mq-bottom-nav');
if(nav)nav.classList.add('show');
['page-home','page-earn','page-do','page-sim','page-learn','page-market',
'page-brain','page-world','page-leaderboard','page-achievements',
'page-goals','page-kai','page-credit','page-invest-club',
'page-simulator','page-personality','page-curriculum','page-certs'].forEach(function(pid){
var el=document.getElementById(pid);if(el)el.classList.add('has-nav');
});
updatePhaseLocks();
}
function hideBottomNav(){
var nav=document.getElementById('mq-bottom-nav');
if(nav)nav.classList.remove('show');
}
function renderHomeLessonPreview(){
var done=S.learningDone||[];
var badge=document.getElementById('home-les-badge');
if(badge)badge.textContent=done.length+'/23';
var next=null;
for(var i=0;i<LESSONS.length;i++){if(!done.includes(LESSONS[i].id)){next=LESSONS[i];break;}}
var cta=document.getElementById('next-lesson-cta');
if(next){
setT('next-les-ic',next.icon);setT('next-les-title',next.title);
setT('next-les-meta','Level '+next.lv+' · +'+next.xp+' XP');
if(cta)cta.style.display='flex';
} else {if(cta)cta.style.display='none';}
var preview=document.getElementById('home-lessons-preview');
if(!preview)return;
var upcoming=LESSONS.filter(function(l){return!done.includes(l.id);}).slice(1,4);
if(!upcoming.length){preview.innerHTML='<div style="text-align:center;padding:12px;font-size:12px;color:rgba(255,255,255,.35);">🎉 All lessons complete!</div>';return;}
preview.innerHTML=upcoming.map(function(l){
return '<div style="display:flex;align-items:center;gap:10px;padding:10px 0;border-top:1px solid rgba(255,255,255,.05);cursor:pointer;" onclick="openLesson('+l.id+')">'
+'<div style="width:34px;height:34px;border-radius:9px;background:rgba(255,255,255,.05);display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0;">'+l.icon+'</div>'
+'<div style="flex:1;"><div style="font-size:12px;font-weight:700;">'+l.title+'</div><div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px;">+'+l.xp+' XP</div></div>'
+'<div style="font-size:9px;font-weight:800;background:rgba(59,130,246,.1);border:1px solid rgba(59,130,246,.15);border-radius:50px;padding:2px 8px;color:#93C5FD;">L'+l.lv+'</div>'
+'</div>';
}).join('');
}
function startNextLesson(){
var done=S.learningDone||[];
for(var i=0;i<LESSONS.length;i++){if(!done.includes(LESSONS[i].id)){openLesson(LESSONS[i].id);return;}}
toast('🎉 All lessons complete!');
}
function renderEarnPhase(){
var done=getLessonsDone();
var av=document.getElementById('earn-av');if(av)av.textContent=S.avatar||'🦊';
var cv=document.getElementById('earn-coins-val');if(cv)cv.textContent=S.goldCoins||0;
var lv=getLv(),nx=getNextLv();
var xpIn=(S.xp||0)-lv.req,xpNeed=nx.req-lv.req;
var pct=lv.lv===10?100:Math.min(100,Math.round(xpIn/Math.max(1,xpNeed)*100));
var lvEl=document.getElementById('earn-lv');if(lvEl)lvEl.textContent='Lv '+lv.lv+' · '+lv.title;
var xf=document.getElementById('earn-xp-fill');if(xf)xf.style.width=pct+'%';
var xl=document.getElementById('earn-xp-lbl');if(xl)xl.textContent=xpIn+'/'+xpNeed+' XP';
var body=document.getElementById('earn-phase-body');if(!body)return;
var cards=[
{ic:'📚',t:'Daily Lessons',d:'Learn &amp; earn XP and coins',r:'+20–40 XP',c:'#3B82F6',a:"switchPhase('learn')",lk:false},
{ic:'🧠',t:'Brain HQ',d:'Beat 6 cognitive bias games',r:'+15 XP each',c:'#A855F7',a:"goPage('page-brain')",lk:done<1},
{ic:'🗺️',t:'World Map',d:'Complete world missions',r:'+25 XP + coins',c:'#F59E0B',a:"goPage('page-world')",lk:done<2},
{ic:'🏆',t:'Leaderboard',d:'Your global ranking',r:'City → Planet',c:'#10B981',a:"goPage('page-leaderboard')",lk:false},
{ic:'🏅',t:'Achievements',d:'Unlock 36 badges',r:'Coin bonuses',c:'#EC4899',a:"goPage('page-achievements')",lk:false},
{ic:'🧬',t:'Personality',d:'Your money personality type',r:'7 profiles',c:'#06B6D4',a:"goPage('page-personality')",lk:done<1},
];
var grid='<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px;">';
grid+=cards.map(function(c){
var lk=c.lk?'<div class="card-lock-overlay"><span style="font-size:20px;">🔒</span><span style="font-size:9px;font-weight:700;color:rgba(255,255,255,.35);text-align:center;padding:0 8px;">Complete a lesson first</span></div>':'';
return '<div class="phase-card" onclick="'+c.a+'"><div class="phase-card-ic">'+c.ic+'</div><div class="phase-card-title">'+c.t+'</div><div class="phase-card-desc">'+c.d+'</div><div class="phase-card-reward" style="background:rgba(255,255,255,.04);color:'+c.c+';">'+c.r+'</div>'+lk+'</div>';
}).join('');
grid+='</div>';
grid+='<div style="background:rgba(124,58,237,.07);border:1px solid rgba(124,58,237,.14);border-radius:14px;padding:14px;cursor:pointer;margin-bottom:8px;" onclick="goPage(\'page-kai\')">'
+'<div style="display:flex;align-items:center;gap:10px;">'
+'<div style="font-size:26px;">🤖</div>'
+'<div style="flex:1;"><div style="font-size:13px;font-weight:800;color:#C4B5FD;">Ask Kai — K2 AI Coach</div><div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px;">Get personalized money advice</div></div>'
+'<div style="font-size:20px;color:#C4B5FD;"></div></div></div>';
if(done>=3){
grid+='<div style="background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.11);border-radius:14px;padding:14px;cursor:pointer;" onclick="goPage(\'page-invest-club\')">'
+'<div style="display:flex;align-items:center;gap:10px;">'
+'<div style="font-size:26px;">🤝</div>'
+'<div style="flex:1;"><div style="font-size:13px;font-weight:800;color:#6EE7B7;">Investment Club</div><div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px;">Vote on group investments</div></div>'
+'<div style="font-size:20px;color:#6EE7B7;"></div></div></div>';
}
body.innerHTML=grid;
}
function renderDoPhase(){
var done=getLessonsDone();
var av=document.getElementById('do-av');if(av)av.textContent=S.avatar||'🦊';
var cv=document.getElementById('do-coins-val');if(cv)cv.textContent=S.goldCoins||0;
var inv=Object.entries(S.mktPort||{}).reduce(function(t,e){var a=FA.find(function(x){return x.id===e[0];});return t+(a?a.px*e[1]:0);},0);
var dc=document.getElementById('do-cash');if(dc)dc.textContent='$'+(S.cash||0).toFixed(0);
var ds=document.getElementById('do-saved');if(ds)ds.textContent='$'+((S.port&&S.port.save)||0).toFixed(0);
var di=document.getElementById('do-invested');if(di)di.textContent='$'+inv.toFixed(0);
var body=document.getElementById('do-phase-body');if(!body)return;
if(!isPhaseUnlocked('do')){
body.innerHTML='<div class="unlock-progress"><div style="font-size:13px;font-weight:800;color:rgba(255,255,255,.5);">🔒 Complete 3 lessons to unlock Do</div><div style="font-size:11px;color:rgba(255,255,255,.3);margin-top:4px;">'+done+' of 3 done</div><div class="unlock-bar"><div class="unlock-bar-fill" style="width:'+Math.round(done/3*100)+'%;background:#10B981;"></div></div></div>'
+'<button onclick="switchPhase(\'learn\')" style="width:100%;padding:13px;background:rgba(59,130,246,.08);border:1px solid rgba(59,130,246,.15);border-radius:12px;font-family:inherit;font-size:13px;font-weight:800;color:#93C5FD;cursor:pointer;">📚 Go to Learn →</button>';
return;
}
var cards=[
{ic:'🏦',t:'Save Money',d:'Move cash to savings wallet',r:'+ interest',c:'#10B981',a:"openSheet('sheet-save')"},
{ic:'📊',t:'Buy Stocks',d:'Invest in 20 real assets',r:'Market returns',c:'#3B82F6',a:"goPage('page-market')"},
{ic:'🎯',t:'Set Goals',d:'Save toward a target',r:'Achievement badge',c:'#F59E0B',a:"goPage('page-goals')"},
{ic:'⚡',t:'Life Crossroads',d:'K2 AI financial dilemmas',r:'AI coaching',c:'#A855F7',a:"triggerCrossroads()"},
{ic:'💝',t:'Give Back',d:'Donate to real causes',r:'Philanthropist',c:'#EC4899',a:"openCharity()"},
{ic:'💳',t:'Credit Score',d:'Build your credit rating',r:'300–850 score',c:'#06B6D4',a:"goPage('page-credit')"},
];
var grid='<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:14px;">';
grid+=cards.map(function(c){return '<div class="phase-card" onclick="'+c.a+'"><div class="phase-card-ic">'+c.ic+'</div><div class="phase-card-title">'+c.t+'</div><div class="phase-card-desc">'+c.d+'</div><div class="phase-card-reward" style="background:rgba(255,255,255,.04);color:'+c.c+';">'+c.r+'</div></div>';}).join('');
grid+='</div><div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1px;text-transform:uppercase;margin-bottom:10px;">💼 Your Portfolio</div><div id="do-port-list"></div>';
body.innerHTML=grid;
var portEl=document.getElementById('do-port-list');
if(portEl){
var held=Object.entries(S.mktPort||{}).filter(function(e){return e[1]>0;});
if(!held.length){portEl.innerHTML='<div style="text-align:center;padding:16px;color:rgba(255,255,255,.3);font-size:12px;">No investments yet — tap Buy Stocks above! 📈</div>';}
else{portEl.innerHTML=held.map(function(e){var a=FA.find(function(x){return x.id===e[0];});if(!a)return'';return'<div style="display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid rgba(255,255,255,.05);cursor:pointer;" onclick="openSell(\''+e[0]+'\')">'+'<div style="font-size:18px;">'+a.icon+'</div><div style="flex:1;"><div style="font-size:12px;font-weight:700;">'+a.nm+'</div><div style="font-size:10px;color:rgba(255,255,255,.35);">'+e[1]+' shares</div></div><div style="font-size:13px;font-weight:800;color:#10B981;">$'+(a.px*e[1]).toFixed(0)+'</div></div>';}).join('');}
}
}
function renderSimPhase(){
var done=getLessonsDone();
var cv=document.getElementById('sim-coins-val');if(cv)cv.textContent=S.goldCoins||0;
var body=document.getElementById('sim-phase-body');if(!body)return;
if(!isPhaseUnlocked('sim')){
body.innerHTML='<div class="unlock-progress"><div style="font-size:13px;font-weight:800;color:rgba(255,255,255,.5);">🔒 Complete 5 lessons to unlock Simulate</div><div style="font-size:11px;color:rgba(255,255,255,.3);margin-top:4px;">'+done+' of 5 done</div><div class="unlock-bar"><div class="unlock-bar-fill" style="width:'+Math.round(done/5*100)+'%;background:#A855F7;"></div></div></div>'
+'<button onclick="switchPhase(\'learn\')" style="width:100%;padding:13px;background:rgba(59,130,246,.08);border:1px solid rgba(59,130,246,.15);border-radius:12px;font-family:inherit;font-size:13px;font-weight:800;color:#93C5FD;cursor:pointer;">📚 Go to Learn →</button>';
return;
}
var html2='<div class="sim-hero" onclick="openSimulator()">'
+'<div style="font-size:48px;margin-bottom:8px;">🎮</div>'
+'<div style="font-size:18px;font-weight:900;color:#C4B5FD;margin-bottom:4px;">Financial Decision Simulator</div>'
+'<div style="font-size:11px;color:rgba(255,255,255,.4);line-height:1.65;">Practice real-life money choices. K2 AI tracks your behavior patterns.</div>'
+'<div style="margin-top:12px;padding:8px 16px;background:rgba(168,85,247,.15);border-radius:50px;display:inline-block;font-size:11px;font-weight:800;color:#C4B5FD;">▶ Run a Scenario</div></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:12px;">'
+'<div style="background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:10px;text-align:center;"><div style="font-size:16px;font-weight:900;color:var(--gold);" id="sim-runs-val">'+(S.simulatorRuns||0)+'</div><div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;text-transform:uppercase;margin-top:2px;">Runs</div></div>'
+'<div style="background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:10px;text-align:center;"><div style="font-size:16px;font-weight:900;color:#10B981;">'+(S.smartChoices||0)+'</div><div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;text-transform:uppercase;margin-top:2px;">Smart</div></div>'
+'<div style="background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.06);border-radius:11px;padding:10px;text-align:center;"><div style="font-size:16px;font-weight:900;color:#A855F7;">10</div><div style="font-size:9px;color:rgba(255,255,255,.3);font-weight:700;text-transform:uppercase;margin-top:2px;">Scenarios</div></div>'
+'</div>'
+'<button onclick="openTimeSimulator()" style="width:100%;padding:11px;background:rgba(168,85,247,.06);border:1px solid rgba(168,85,247,.13);border-radius:11px;font-family:inherit;font-size:12px;font-weight:700;color:#C4B5FD;cursor:pointer;margin-bottom:14px;">⏳ Time Simulator — Compound Growth</button>'
+'<div style="font-size:9px;font-weight:800;color:rgba(255,255,255,.25);letter-spacing:1px;margin-bottom:10px;text-transform:uppercase;">Scenario Library</div>'
+'<div id="sim-scen-list2"></div>';
body.innerHTML=html2;
if(typeof SCENARIOS!=='undefined'){
var listEl=document.getElementById('sim-scen-list2');
if(listEl){listEl.innerHTML=SCENARIOS.map(function(sc){var d2=(S.simulatorHistory||[]).includes(sc.id);return'<div style="display:flex;align-items:center;gap:10px;padding:11px 0;border-bottom:1px solid rgba(255,255,255,.05);cursor:pointer;" onclick="openSimulatorById(\''+sc.id+'\')">'+'<div style="font-size:22px;flex-shrink:0;">'+sc.em+'</div><div style="flex:1;"><div style="font-size:12px;font-weight:700;">'+sc.title+'</div><div style="font-size:10px;color:rgba(255,255,255,.35);margin-top:2px;">Level '+sc.lv+' · '+sc.coins+' coins</div></div><div style="font-size:12px;color:'+(d2?'#10B981':'rgba(255,255,255,.2)')+';font-weight:800;">'+(d2?'✓':'›')+'</div></div>';}).join('');}
}
}
/* Override goPage to sync bottom nav */
var _origGoPage=goPage;
goPage=function(id){
_origGoPage(id);
var pm={'page-home':'learn','page-learn':'learn','page-earn':'earn','page-do':'do','page-market':'do','page-goals':'do','page-credit':'do','page-invest-club':'do','page-brain':'earn','page-world':'earn','page-leaderboard':'earn','page-achievements':'earn','page-kai':'earn','page-sim':'sim','page-simulator':'sim','page-personality':'earn','page-curriculum':'learn','page-certs':'learn'};
var phase=pm[id]||currentPhase;
document.querySelectorAll('.mq-bnav-tab').forEach(function(t){t.classList.remove('active');});
var tab=document.getElementById('bnav-'+phase);if(tab)tab.classList.add('active');
if(id==='page-earn')renderEarnPhase();
if(id==='page-do')renderDoPhase();
if(id==='page-sim')renderSimPhase();
if(id==='page-home'){renderHomeLessonPreview();updatePhaseLocks();}
};
/* Override logout */
var _origLogout=doLogout;
doLogout=function(){hideBottomNav();currentPhase='learn';_origLogout();};
/* Override child login to show nav */
var _origCL=doWelcomeChildLogin;
doWelcomeChildLogin=function(){
_origCL();
setTimeout(function(){
var hp=document.getElementById('page-home');
if(hp&&hp.classList.contains('active')){
showBottomNav();renderHomeLessonPreview();updatePhaseLocks();
document.querySelectorAll('.mq-bnav-tab').forEach(function(t){t.classList.remove('active');});
var t=document.getElementById('bnav-learn');if(t)t.classList.add('active');
}
},120);
};
/* Override renderHome */
var _origRH=renderHome;
renderHome=function(){_origRH();renderHomeLessonPreview();updatePhaseLocks();};
/* ── APP LOCK (15-min inactivity) ── */
var _lockTimer=null;
var LOCK_MS=15*60*1000;
function resetLockTimer(){
if(!CU||CU.role!=='child')return;
clearTimeout(_lockTimer);
_lockTimer=setTimeout(showAppLock,LOCK_MS);
}
function showAppLock(){
var ov=document.getElementById('app-lock-overlay');
if(ov)ov.classList.add('visible');
var inp=document.getElementById('lock-pass-input');
if(inp){inp.value='';inp.focus();}
var err=document.getElementById('lock-err');
if(err)err.textContent='';
}
function unlockApp(){
var pass=(document.getElementById('lock-pass-input')||{}).value||'';
var err=document.getElementById('lock-err');
if(!pass){if(err)err.textContent='Enter your password';return;}
if(!CU||!CU.data)return;
var cd=DB.getChild(CU.data.username||CU.data.id);
if(cd&&cd.passHash===DB._h(pass)){
var ov=document.getElementById('app-lock-overlay');
if(ov)ov.classList.remove('visible');
var inp=document.getElementById('lock-pass-input');
if(inp)inp.value='';
if(err)err.textContent='';
resetLockTimer();
if(typeof toast==='function')toast('Welcome back, '+S.name+'! 👋');
}else{
if(err)err.textContent='Wrong password. Try again.';
}
}
function lockAndLogout(){
var ov=document.getElementById('app-lock-overlay');
if(ov) ov.classList.remove('visible');
doLogout();
}
['click','touchstart','keydown','scroll'].forEach(function(ev){
document.addEventListener(ev,resetLockTimer,{passive:true});
});
</script>
</body>
</html>