Skip to content

Update print statement from 'Hello' to 'Goodbye' - #35

Merged
Sazwanismail merged 1 commit into
mainfrom
Sazwanismail-patch-20
Sep 23, 2026
Merged

Sazwanismail merged 1 commit into
mainfrom
Sazwanismail-patch-20

Conversation

@Sazwanismail

@Sazwanismail Sazwanismail commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

User description

🚀 SGAE 2.0 MASTER v39 · 8 KOMPONEN ULTIMATE

Berikut adalah fail HTML lengkap yang menggabungkan semua data v37/v38 + 8 komponen baharu dalam satu fail.

Simpan sebagai sgae_master_v39_ultimate.html:

<!DOCTYPE html>
<html lang="ms">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>SGAE 2.0 MASTER v39 · ULTIMATE · Muhamad Sazwan Bin Ismail</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&family=Roboto+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.1/jspdf.plugin.autotable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#0a0f17;--card:#1e293b;--card2:#0f172a;--border:#334155;--text:#e8eaed;--muted:#94a3b8;
--gold:#ffd700;--cyan:#00e5ff;--green:#34a853;--pink:#ec4899;--purple:#a855f7;
--red:#ef4444;--orange:#f7931a;--blue:#4285f4;--yellow:#f7ea48}
html,body{width:100%;min-height:100%;background:var(--bg);color:var(--text);font-family:'Roboto',system-ui,sans-serif;line-height:1.5}
body{padding:16px}
.container{max-width:1600px;margin:0 auto}
header{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:12px;margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--border)}
h1{font-size:26px;background:linear-gradient(135deg,#ffd700,#ec4899,#a855f7,#00e5ff);-webkit-background-clip:text;background-clip:text;color:transparent;font-weight:900}
.sub{font-size:13px;color:var(--muted);margin-top:4px}
.badges{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.badge{padding:4px 12px;border-radius:20px;font-size:11px;font-weight:600;border:1px solid}
.badge.gold{border-color:var(--gold);color:var(--gold)}
.badge.cyan{border-color:var(--cyan);color:var(--cyan)}
.badge.pink{border-color:var(--pink);color:var(--pink)}
.badge.green{border-color:var(--green);color:var(--green)}
.badge.red{border-color:var(--red);color:var(--red)}
.badge.purple{border-color:var(--purple);color:var(--purple)}
.badge.orange{border-color:var(--orange);color:var(--orange)}
.badge.blue{border-color:var(--blue);color:var(--blue)}
.status-box{font-size:12px;color:var(--muted);text-align:right;min-width:220px}
.status-box .ok{color:var(--green);font-weight:600}
.status-box .err{color:var(--red);font-weight:600}
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:14px;position:relative;overflow:hidden}
.kpi::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#ffd700,#ec4899,#a855f7,#00e5ff)}
.kpi .label{font-size:12px;color:var(--muted);margin-bottom:4px}
.kpi .value{font-size:22px;font-weight:700;margin:4px 0}
.kpi .sub{font-size:11px;color:var(--muted)}
.card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:20px;margin-bottom:20px}
.card h2{font-size:18px;margin-bottom:14px;display:flex;align-items:center;gap:8px;font-weight:700}
.card h2 i{color:var(--cyan)}
.card h3{font-size:15px;margin:12px 0 8px;color:var(--cyan);font-weight:600}
.tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:20px;position:sticky;top:0;background:var(--bg);padding:10px 0;z-index:1000;border-bottom:1px solid var(--border)}
.tab{padding:7px 14px;border-radius:20px;background:var(--card2);border:1px solid var(--border);cursor:pointer;font-size:12px;transition:.2s;color:var(--text);font-weight:500}
.tab:hover{background:var(--card);transform:translateY(-1px)}
.tab.active{background:var(--cyan);color:#0a0f17;border-color:var(--cyan);font-weight:700}
.tab.chat{background:linear-gradient(135deg,rgba(168,85,247,.3),rgba(236,72,153,.2));border-color:var(--purple);color:var(--purple);font-weight:700}
.tab.export{background:linear-gradient(135deg,rgba(52,168,83,.3),rgba(0,229,255,.15));border-color:var(--green);color:var(--green);font-weight:700}
.tab.crypto{background:linear-gradient(135deg,rgba(247,147,26,.3),rgba(245,158,11,.15));border-color:var(--orange);color:var(--orange);font-weight:700}
.tab.i18n{background:linear-gradient(135deg,rgba(66,133,244,.3),rgba(0,229,255,.15));border-color:var(--blue);color:var(--blue);font-weight:700}
.section{display:none;animation:fadeIn .3s}
.section.active{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
table{width:100%;border-collapse:collapse;font-size:13px;margin-top:8px}
th,td{padding:8px 10px;text-align:left;border-bottom:1px solid var(--border);vertical-align:top}
th{background:var(--card2);color:var(--muted);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px}
tr:hover{background:rgba(255,255,255,0.03)}
td.mono{font-family:'Roboto Mono',monospace;font-size:12px}
.gold{color:var(--gold)}.cyan{color:var(--cyan)}.green{color:var(--green)}
.pink{color:var(--pink)}.purple{color:var(--purple)}.red{color:var(--red)}
.orange{color:var(--orange)}.blue{color:var(--blue)}.yellow{color:var(--yellow)}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.grid-3{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
@media(max-width:700px){.grid-2,.grid-3{grid-template-columns:1fr}}
.info-box{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;margin:10px 0}
.info-box .label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.info-box .val{font-size:15px;font-weight:600;margin-top:4px}
.hash-box{background:linear-gradient(135deg,#001a1f,#000);border:2px solid var(--cyan);border-radius:14px;padding:16px;margin:12px 0}
.hash-box .label{font-family:'Roboto Mono',monospace;font-size:10px;color:var(--cyan);font-weight:700;letter-spacing:2px;text-transform:uppercase;margin-bottom:8px}
.hash-box .hash{font-family:'Roboto Mono',monospace;font-size:13px;font-weight:700;color:var(--gold);word-break:break-all;line-height:1.6}
.cts-badge{background:linear-gradient(135deg,#2d2400,#1a1500);border:3px solid var(--yellow);border-radius:16px;padding:20px;text-align:center;margin:12px 0;box-shadow:0 0 40px rgba(247,234,72,.4)}
.cts-badge .title{font-size:1.4rem;font-weight:900;color:var(--yellow);letter-spacing:6px;text-transform:uppercase}
.cts-badge .sub{font-family:'Roboto Mono',monospace;font-size:.7rem;color:#2effb0;letter-spacing:3px;margin-top:6px;font-weight:700}
footer{text-align:center;font-size:12px;color:var(--muted);margin-top:30px;padding-top:16px;border-top:1px solid var(--border)}
.spinner{display:inline-block;width:16px;height:16px;border:2px solid var(--border);border-top-color:var(--cyan);border-radius:50%;animation:spin 1s linear infinite;margin-right:8px;vertical-align:middle}
@keyframes spin{to{transform:rotate(360deg)}}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:var(--card2)}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}
.refresh-btn{background:var(--cyan);color:#0a0f17;border:none;padding:6px 14px;border-radius:8px;cursor:pointer;font-weight:600;font-size:12px;margin-top:6px}
.refresh-btn:hover{background:#00b8cc}
.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-weight:600;font-size:12px;transition:.2s}
.btn-primary{background:var(--cyan);color:#0a0f17}
.btn-primary:hover{background:#00b8cc}
.btn-danger{background:var(--red);color:#fff}
.btn-success{background:var(--green);color:#fff}
.btn-warning{background:var(--yellow);color:#0a0f17}
.btn-purple{background:var(--purple);color:#fff}
/* CHAT */
.chat-box{background:var(--card2);border:1px solid var(--border);border-radius:14px;padding:16px;height:500px;display:flex;flex-direction:column}
.chat-messages{flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:10px}
.chat-msg{max-width:80%;padding:10px 14px;border-radius:14px;font-size:13px;line-height:1.5;word-wrap:break-word}
.chat-msg.user{align-self:flex-end;background:linear-gradient(135deg,#00e5ff,#4285f4);color:#0a0f17;font-weight:500}
.chat-msg.bot{align-self:flex-start;background:var(--card);border:1px solid var(--border);color:var(--text)}
.chat-input{display:flex;gap:8px;margin-top:12px}
.chat-input input{flex:1;padding:10px 14px;border-radius:10px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:13px}
.chat-input input:focus{outline:none;border-color:var(--cyan)}
.chat-input button{padding:10px 20px;border-radius:10px;background:var(--cyan);color:#0a0f17;font-weight:700;cursor:pointer;border:none}
/* EXPORT */
.export-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:16px 0}
.export-card{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:20px;text-align:center;cursor:pointer;transition:.2s}
.export-card:hover{transform:translateY(-3px);border-color:var(--cyan)}
.export-card i{font-size:2.5rem;margin-bottom:10px;display:block}
.export-card .label{font-weight:700;font-size:14px;color:#fff}
.export-card .desc{font-size:11px;color:var(--muted);margin-top:4px}
/* CRYPTO */
.crypto-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin:16px 0}
.crypto-card{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:14px;display:flex;justify-content:space-between;align-items:center}
.crypto-card .sym{font-weight:700;color:var(--gold);font-size:15px}
.crypto-card .price{font-family:'Roboto Mono',monospace;font-size:14px;color:#fff}
.crypto-card .change{font-size:12px;font-weight:600}
.crypto-card .change.up{color:var(--green)}
.crypto-card .change.down{color:var(--red)}
/* I18N */
.lang-btn{padding:6px 14px;border-radius:20px;background:var(--card2);border:1px solid var(--border);cursor:pointer;font-size:12px;margin-right:6px;color:var(--text)}
.lang-btn.active{background:var(--blue);border-color:var(--blue);color:#fff;font-weight:700}
/* DOC VAULT */
.vault-item{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;margin:8px 0;display:flex;align-items:center;gap:12px}
.vault-item .icon{width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,#00e5ff,#a855f7);display:flex;align-items:center;justify-content:center;color:#fff;font-size:18px}
.vault-item .info{flex:1}
.vault-item .name{font-weight:700;color:#fff;font-size:13px}
.vault-item .meta{font-size:11px;color:var(--muted);margin-top:2px}
.vault-item .lock{color:var(--green);font-size:12px}
/* NOTIFICATION */
.notif-item{background:var(--card2);border-left:4px solid var(--cyan);border-radius:8px;padding:12px;margin:8px 0;display:flex;gap:12px;align-items:flex-start}
.notif-item.warning{border-left-color:var(--yellow)}
.notif-item.danger{border-left-color:var(--red)}
.notif-item.success{border-left-color:var(--green)}
.notif-item .icon{font-size:20px;flex-shrink:0}
.notif-item .msg{flex:1;font-size:12px;line-height:1.5}
.notif-item .time{font-size:10px;color:var(--muted);margin-top:4px}
/* NETWORK MONITOR */
.monitor-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.monitor-item{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;text-align:center}
.monitor-item .value{font-size:26px;font-weight:900;font-family:'Roboto Mono',monospace;margin:6px 0}
.monitor-item .label{font-size:11px;color:var(--muted);text-transform:uppercase}
.monitor-item .status{font-size:11px;font-weight:700;margin-top:4px}
.monitor-item .status.online{color:var(--green)}
.monitor-item .status.warning{color:var(--yellow)}
.monitor-item .status.offline{color:var(--red)}
/* CHART */
.chart-container{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:16px;height:320px;position:relative}
/* MAP */
.map-container{height:600px;border-radius:12px;overflow:hidden;border:2px solid var(--cyan);margin:12px 0;position:relative}
#earthMap{width:100%;height:100%}
.leaflet-container{background:#0a0f17 !important;font-family:'Roboto',sans-serif !important}
.leaflet-popup-content-wrapper{background:#1e293b !important;color:#e8eaed !important;border:1px solid #00e5ff !important;border-radius:10px !important}
.leaflet-popup-content{margin:12px 14px !important;font-size:12px !important;line-height:1.6 !important;min-width:220px}
.map-legend{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:12px;margin-top:12px;font-size:12px}
.map-legend .item{display:inline-flex;align-items:center;gap:6px;margin:4px 10px 4px 0}
.map-legend .dot{width:12px;height:12px;border-radius:50%;border:2px solid #fff}
.gran-stat{background:linear-gradient(135deg,rgba(52,211,153,.1),rgba(16,185,129,.05));border:1px solid rgba(52,211,153,.4)}
.gran-stat::before{background:linear-gradient(90deg,#34d399,#fbbf24,#ffd700)}
.tag{display:inline-block;background:var(--card2);border:1px solid var(--border);border-radius:20px;padding:4px 12px;margin:3px;font-size:11px}
</style>
</head>
<body>
<div class="container">

<header>
  <div>
    <h1>🌏 SGAE 2.0 MASTER v39 · ULTIMATE EDITION</h1>
    <div class="sub">Pemilik: <strong class="gold">MUHAMAD SAZWAN BIN ISMAIL</strong> · IC: <span class="mono">961022-02-5739</span></div>
    <div class="sub">MSI: <span class="gold mono">MSI-2026-07734</span> · CMC: <span class="gold mono">CMC-REF-2026-MSI-003</span></div>
    <div class="badges">
      <span class="badge gold">👑 Sovereign</span>
      <span class="badge green">🌱 GRAN 24 Lot</span>
      <span class="badge cyan">🗺️ Peta Bumi</span>
      <span class="badge blue">🌊 Gelombang</span>
      <span class="badge purple">🛰️ 6 Satelit</span>
      <span class="badge pink">👨‍👩‍👧‍👦 Family 7</span>
      <span class="badge orange">💎 39 Modul</span>
    </div>
  </div>
  <div class="status-box">
    <div id="lastUpdate">Memuatkan...</div>
    <div id="apiStatus"><span class="spinner"></span> Menyambung ke API...</div>
    <div style="margin-top:6px">
      <button class="refresh-btn" onclick="fetchData(true)"><i class="fas fa-sync"></i> Refresh</button>
    </div>
  </div>
</header>

<div class="kpi-grid" id="kpiGrid"></div>

<div class="tabs">
  <div class="tab active" data-tab="identiti">👤 Identiti</div>
  <div class="tab" data-tab="keluarga">👨‍👩‍👧‍👦 Keluarga</div>
  <div class="tab" data-tab="gran">🌱 GRAN</div>
  <div class="tab" data-tab="peta">🗺️ Peta Bumi</div>
  <div class="tab" data-tab="gelombang">🌊 Gelombang</div>
  <div class="tab" data-tab="gran_chart">📊 Chart</div>
  <div class="tab" data-tab="satellite_orbit">🛰️ Satelit</div>
  <div class="tab" data-tab="weather">🌦️ Cuaca</div>
  <div class="tab" data-tab="gran_docs">📜 Docs</div>
  <div class="tab" data-tab="globe3d">🌐 3D Globe</div>
  <div class="tab chat" data-tab="chat">🤖 AI Chat</div>
  <div class="tab export" data-tab="export">📥 Export</div>
  <div class="tab crypto" data-tab="crypto">₿ Crypto</div>
  <div class="tab i18n" data-tab="i18n">🌐 i18n</div>
  <div class="tab" data-tab="vault">🔐 Vault</div>
  <div class="tab" data-tab="notifications">🔔 Notif</div>
  <div class="tab" data-tab="monitor">📡 Monitor</div>
  <div class="tab" data-tab="api">🔌 API</div>
  <div class="tab" data-tab="google">🔵 Google</div>
  <div class="tab" data-tab="myipo">📜 MyIPO</div>
  <div class="tab" data-tab="sijil">🎖️ Sijil</div>
  <div class="tab" data-tab="negara">🌍 Negara</div>
  <div class="tab" data-tab="raw">📝 Raw</div>
</div>

<!-- SECTIONS -->
<div class="section active" id="identiti"><div class="card"><h2>👤 Identiti Berdaulat</h2><div id="identitiContent"></div></div></div>
<div class="section" id="keluarga"><div class="card"><h2>👨‍👩‍👧‍👦 Salasilah Keluarga</h2><div id="keluargaContent"></div></div></div>
<div class="section" id="gran"><div class="card"><h2>🌱 GRAN Tanah (12 Lot)</h2><div id="granTanahContent"></div></div><div class="card"><h2>🌍 GRAN Global (12 Lot)</h2><div id="granGlobalContent"></div></div><div class="card"><h2>💰 Ringkasan GRAN</h2><div id="granSummaryContent"></div></div></div>
<div class="section" id="peta"><div class="card"><h2>🗺️ Peta Bumi Interaktif</h2><div class="map-container"><div id="earthMap"></div></div><div class="map-legend"><strong>🔵 Legenda:</strong><br><span class="item"><span class="dot" style="background:#34d399"></span> GRAN Tanah</span><span class="item"><span class="dot" style="background:#fbbf24"></span> GRAN Global</span><span class="item"><span class="dot" style="background:#3b82f6"></span> Office</span><span class="item"><span class="dot" style="background:#f59e0b"></span> Data Center</span><span class="item"><span class="dot" style="background:#06b6d4"></span> PoP</span><span class="item"><span class="dot" style="background:#38bdf8"></span> Sat Ground</span><span class="item"><span class="dot" style="background:#ec4899;width:16px;height:16px"></span> Rumah Keluarga</span></div></div></div>
<div class="section" id="gelombang"><div class="card"><h2>🌊 Data Gelombang Laut</h2><div id="gelombangContent"></div></div></div>
<div class="section" id="gran_chart"><div class="card"><h2>📊 GRAN Tanah Chart</h2><div class="chart-container"><canvas id="chartTanah"></canvas></div></div><div class="card"><h2>📊 GRAN Global Chart</h2><div class="chart-container"><canvas id="chartGlobal"></canvas></div></div><div class="card"><h2>📈 Timeline Pertumbuhan</h2><div class="chart-container"><canvas id="chartTimeline"></canvas></div></div></div>
<div class="section" id="satellite_orbit"><div class="card"><h2>🛰️ SGAE-SAT Constellation</h2><div id="satContent"></div></div><div class="card"><h2>📡 Orbit Visualization</h2><div id="orbitViz"></div></div></div>
<div class="section" id="weather"><div class="card"><h2>🌦️ Cuaca Masa Nyata</h2><div id="weatherContent"></div></div></div>
<div class="section" id="gran_docs"><div class="card"><h2>📜 Hak Milik Tanah</h2><div id="granDocsContent"></div></div></div>
<div class="section" id="globe3d"><div class="card"><h2>🌐 3D Earth Globe</h2><div class="map-container" style="height:700px;background:#000"><div id="globeContainer" style="width:100%;height:100%"></div></div></div></div>

<!-- 1. AI CHAT -->
<div class="section" id="chat">
  <div class="card">
    <h2>🤖 SGAE AI Chat Assistant</h2>
    <div class="chat-box">
      <div class="chat-messages" id="chatMessages">
        <div class="chat-msg bot">👋 Selamat datang! Saya AI berdaulat SGAE 2.0. Tanya saya tentang GRAN, keluarga, aset, atau mana-mana data sistem.</div>
      </div>
      <div class="chat-input">
        <input type="text" id="chatInput" placeholder="Taip soalan..." onkeypress="if(event.key==='Enter')sendChat()">
        <button onclick="sendChat()">📤 Hantar</button>
      </div>
      <div style="margin-top:10px;font-size:11px;color:var(--muted)">
        💡 Cuba: <span class="tag" onclick="quickAsk('Berapa nilai GRAN Tanah?')" style="cursor:pointer">Nilai GRAN?</span>
        <span class="tag" onclick="quickAsk('Senaraikan keluarga saya')" style="cursor:pointer">Keluarga?</span>
        <span class="tag" onclick="quickAsk('Apa itu MSI-2026-07734?')" style="cursor:pointer">MSI?</span>
      </div>
    </div>
  </div>
</div>

<!-- 2. EXPORT -->
<div class="section" id="export">
  <div class="card">
    <h2>📥 Export Data · 4 Format</h2>
    <div class="export-grid">
      <div class="export-card" onclick="exportData('pdf')"><i class="fas fa-file-pdf" style="color:#dc2626"></i><div class="label">PDF Report</div><div class="desc">Laporan lengkap</div></div>
      <div class="export-card" onclick="exportData('excel')"><i class="fas fa-file-excel" style="color:#16a34a"></i><div class="label">Excel</div><div class="desc">Spreadsheet .xlsx</div></div>
      <div class="export-card" onclick="exportData('csv')"><i class="fas fa-file-csv" style="color:#0891b2"></i><div class="label">CSV</div><div class="desc">Comma-separated</div></div>
      <div class="export-card" onclick="exportData('json')"><i class="fas fa-file-code" style="color:#fbbf24"></i><div class="label">JSON</div><div class="desc">Struktur penuh</div></div>
    </div>
    <h3>📊 Pilih Kategori Export</h3>
    <div id="exportOptions"></div>
  </div>
</div>

<!-- 3. CRYPTO LIVE -->
<div class="section" id="crypto">
  <div class="card">
    <h2>₿ Crypto Live Dashboard</h2>
    <div class="kpi-grid" id="cryptoKPI"></div>
    <div class="crypto-grid" id="cryptoGrid"></div>
    <h3>📊 24h Chart</h3>
    <div class="chart-container"><canvas id="cryptoChart"></canvas></div>
  </div>
</div>

<!-- 4. I18N -->
<div class="section" id="i18n">
  <div class="card">
    <h2>🌐 Multi-Language · BM / EN / 中文</h2>
    <div style="margin:12px 0">
      <button class="lang-btn active" onclick="changeLang('ms')">🇲🇾 Bahasa Melayu</button>
      <button class="lang-btn" onclick="changeLang('en')">🇬🇧 English</button>
      <button class="lang-btn" onclick="changeLang('zh')">🇨🇳 中文</button>
    </div>
    <div id="i18nContent"></div>
  </div>
</div>

<!-- 5. VAULT -->
<div class="section" id="vault">
  <div class="card">
    <h2>🔐 Document Vault · Encrypted</h2>
    <div class="kpi-grid">
      <div class="kpi"><div class="label">Total Dokumen</div><div class="value cyan">17</div></div>
      <div class="kpi"><div class="label">Encrypted</div><div class="value green">100%</div></div>
      <div class="kpi"><div class="label">AES-256-GCM</div><div class="value gold">Active</div></div>
      <div class="kpi"><div class="label">Last Access</div><div class="value purple" style="font-size:13px">Just now</div></div>
    </div>
    <div id="vaultContent"></div>
  </div>
</div>

<!-- 6. NOTIFICATIONS -->
<div class="section" id="notifications">
  <div class="card">
    <h2>🔔 Notification Center</h2>
    <div class="kpi-grid">
      <div class="kpi"><div class="label">Total</div><div class="value cyan" id="notifCount">0</div></div>
      <div class="kpi"><div class="label">Success</div><div class="value green" id="notifSuccess">0</div></div>
      <div class="kpi"><div class="label">Warning</div><div class="value yellow" id="notifWarn">0</div></div>
      <div class="kpi"><div class="label">Alert</div><div class="value red" id="notifDanger">0</div></div>
    </div>
    <div id="notifContent"></div>
  </div>
</div>

<!-- 7. NETWORK MONITOR -->
<div class="section" id="monitor">
  <div class="card">
    <h2>📡 Network & Server Monitor</h2>
    <div class="monitor-grid" id="monitorGrid"></div>
    <h3>📈 Latency Chart (Live)</h3>
    <div class="chart-container"><canvas id="monitorChart"></canvas></div>
  </div>
</div>

<div class="section" id="api"><div class="card"><h2>🔌 42 API Endpoints</h2><div id="apiContent"></div></div></div>
<div class="section" id="google"><div class="card"><h2>🔵 17 Google Services</h2><div id="googleContent"></div></div></div>
<div class="section" id="myipo"><div class="card"><h2>📜 MyIPO Portfolio</h2><div id="myipoContent"></div></div></div>
<div class="section" id="sijil"><div class="card"><h2>🎖️ Sijil Global</h2><div id="sijilContent"></div></div></div>
<div class="section" id="negara"><div class="card"><h2>🌍 205 Negara</h2><div id="negaraContent"></div></div></div>
<div class="section" id="raw"><div class="card"><h2>📝 Raw Data</h2><pre id="rawContent" style="background:var(--card2);padding:16px;border-radius:10px;overflow:auto;font-size:11px;max-height:600px;font-family:monospace"></pre></div></div>

<footer>
  SGAE 2.0 MASTER v39 ULTIMATE · © 2026 MUHAMAD SAZWAN BIN ISMAIL · IC: 961022-02-5739<br>
  🏠 F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia · MSI-2026-07734 · CMC-REF-2026-MSI-003
</footer>
</div>

<script>
// ================= DATA =================
const API_BASE = 'http://localhost:8000';
const API_ENDPOINT = API_BASE + '/all';

const GRAN_TANAH = [
  {id:'GRAN-MSI-KDH-7734',flag:'🇲🇾',state:'Kedah',name:'Sazwan Digital Valley (HQ)',area:'2.5 Ha',value:'RM 13,100,000',tenure:'Freehold',lat:5.6944,lng:100.4827,type:'Industrial Tech Park',title:'HS(D) 7734/2024'},
  {id:'GRAN-MSI-KDH-7735',flag:'🇲🇾',state:'Kedah',name:'SGAE Data Center',area:'2.0 Ha',value:'RM 4,500,000',tenure:'Freehold',lat:5.6470,lng:100.4874,type:'Data Center',title:'HS(D) 7735/2024'},
  {id:'GRAN-MSI-KDH-7736',flag:'🇲🇾',state:'Kedah',name:'SGAE R&D Center',area:'1.0 Ha',value:'RM 1,000,000',tenure:'Freehold',lat:5.3700,lng:100.5600,type:'R&D',title:'HS(D) 7736/2024'},
  {id:'GRAN-MSI-KUL-7737',flag:'🇲🇾',state:'Kuala Lumpur',name:'KL Office Tower',area:'0.8 Ha',value:'RM 42,000,000',tenure:'Freehold',lat:3.1390,lng:101.6869,type:'Office Tower',title:'HS(D) 7737/2024'},
  {id:'GRAN-MSI-PNG-7738',flag:'🇲🇾',state:'Penang',name:'Penang Tech Hub',area:'1.2 Ha',value:'RM 18,500,000',tenure:'Leasehold',lat:5.4141,lng:100.3288,type:'Tech Hub',title:'HS(D) 7738/2024'},
  {id:'GRAN-MSI-JHR-7739',flag:'🇲🇾',state:'Johor',name:'JB Data Center',area:'3.0 Ha',value:'RM 22,000,000',tenure:'Freehold',lat:1.4927,lng:103.7414,type:'Data Center',title:'HS(D) 7739/2024'},
  {id:'GRAN-MSI-SG-7740',flag:'🇸🇬',state:'Marina Bay',name:'SG Financial Hub',area:'0.5 Ha',value:'RM 85,000,000',tenure:'Leasehold 99y',lat:1.2830,lng:103.8607,type:'Financial Hub',title:'SLA-2024-7740'},
  {id:'GRAN-MSI-US-7741',flag:'🇺🇸',state:'Silicon Valley',name:'SV Innovation Center',area:'1.5 Ha',value:'RM 62,000,000',tenure:'Freehold',lat:37.4419,lng:-122.1430,type:'Innovation',title:'DEED-2024-7741'},
  {id:'GRAN-MSI-AE-7742',flag:'🇦🇪',state:'Dubai',name:'Dubai Blockchain Hub',area:'1.2 Ha',value:'RM 24,000,000',tenure:'Freehold',lat:25.0805,lng:55.1403,type:'Blockchain',title:'DLD-7742'},
  {id:'GRAN-MSI-JP-7743',flag:'🇯🇵',state:'Tokyo',name:'Tokyo Cyber Defense',area:'0.8 Ha',value:'RM 38,000,000',tenure:'Freehold',lat:35.6762,lng:139.6503,type:'Cyber Defense',title:'TR-7743'},
  {id:'GRAN-MSI-UK-7744',flag:'🇬🇧',state:'London',name:'London FinTech Hub',area:'0.6 Ha',value:'RM 42,000,000',tenure:'Leasehold 999y',lat:51.5054,lng:-0.0235,type:'FinTech Hub',title:'HM-LR-7744'},
  {id:'GRAN-MSI-CH-7745',flag:'🇨🇭',state:'Zurich',name:'Zurich Quantum Center',area:'0.7 Ha',value:'RM 32,000,000',tenure:'Freehold',lat:47.3769,lng:8.5417,type:'Quantum Center',title:'CHE-7745'}
];

const GRAN_GLOBAL = [
  {id:'GRAN-GLB-SG-8801',flag:'🇸🇬',country:'Singapore',name:'SGAE APAC Hub',city:'Marina Bay',lat:1.2830,lng:103.8607,area:'0.4 Ha',value:'RM 147,000,000',tenure:'Leasehold 999y'},
  {id:'GRAN-GLB-US-4401',flag:'🇺🇸',country:'USA',name:'SGAE Silicon Valley',city:'Palo Alto',lat:37.4419,lng:-122.1430,area:'0.8 Ha',value:'RM 131,600,000',tenure:'Freehold'},
  {id:'GRAN-GLB-GB-3301',flag:'🇬🇧',country:'UK',name:'SGAE London FinTech',city:'Canary Wharf',lat:51.5054,lng:-0.0235,area:'0.6 Ha',value:'RM 105,000,000',tenure:'Leasehold 999y'},
  {id:'GRAN-GLB-AE-2201',flag:'🇦🇪',country:'UAE',name:'SGAE Middle East Hub',city:'Dubai Marina',lat:25.0805,lng:55.1403,area:'1.2 Ha',value:'RM 102,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-JP-1101',flag:'🇯🇵',country:'Japan',name:'SGAE Tokyo AI Lab',city:'Shibuya',lat:35.6762,lng:139.6503,area:'0.5 Ha',value:'RM 74,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-CH-9901',flag:'🇨🇭',country:'Switzerland',name:'SGAE Crypto Vault',city:'Zug',lat:47.1662,lng:8.5155,area:'0.3 Ha',value:'RM 63,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-AU-6601',flag:'🇦🇺',country:'Australia',name:'SGAE Sydney DC',city:'Sydney',lat:-33.9026,lng:151.1945,area:'1.5 Ha',value:'RM 74,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-EE-5501',flag:'🇪🇪',country:'Estonia',name:'SGAE e-Residency',city:'Tallinn',lat:59.4370,lng:24.7536,area:'0.2 Ha',value:'RM 21,000,000',tenure:'Digital Estate'},
  {id:'GRAN-GLB-SA-7701',flag:'🇸🇦',country:'Saudi',name:'SGAE NEOM Node',city:'NEOM',lat:28.0000,lng:35.0000,area:'38.7 Ha',value:'RM 148,000,000',tenure:'Leasehold 99y'},
  {id:'GRAN-GLB-MY-7734',flag:'🇲🇾',country:'Malaysia',name:'Sazwan Digital Valley',city:'Kedah',lat:5.6944,lng:100.4827,area:'2.5 Ha',value:'RM 13,100,000',tenure:'Freehold'},
  {id:'GRAN-GLB-MY-7735',flag:'🇲🇾',country:'Malaysia',name:'SGAE Data Center',city:'Kedah',lat:5.6470,lng:100.4874,area:'2.0 Ha',value:'RM 4,500,000',tenure:'Freehold'},
  {id:'GRAN-GLB-MY-7736',flag:'🇲🇾',country:'Malaysia',name:'SGAE R&D',city:'Kulim',lat:5.3700,lng:100.5600,area:'1.0 Ha',value:'RM 1,000,000',tenure:'Freehold'}
];

const SATELLITES = [
  {id:'SGAE-SAT-01',orbit:'GEO',alt:'35,786 km',band:'Ka',signal:96,type:'Communications',lat:0,lng:42.1},
  {id:'SGAE-SAT-02',orbit:'LEO',alt:'550 km',band:'X',signal:92,type:'Imaging',lat:5.6,lng:100.5},
  {id:'SGAE-SAT-03',orbit:'MEO',alt:'20,200 km',band:'Ku',signal:88,type:'Navigation',lat:0,lng:0},
  {id:'SGAE-SAT-04',orbit:'GEO',alt:'35,786 km',band:'Ka',signal:94,type:'SIGINT',lat:0,lng:118},
  {id:'SGAE-SAT-05',orbit:'LEO',alt:'480 km',band:'X',signal:90,type:'Imaging',lat:-10,lng:80},
  {id:'SGAE-SAT-06',orbit:'SSO',alt:'700 km',band:'L',signal:97,type:'IoT/M2M',lat:98,lng:0}
];

const WEATHER_DATA = [
  {city:'Sungai Petani, Kedah',flag:'🇲🇾',temp:32,desc:'Cerah Berawan',humid:65,wind:8,rain:5,icon:'fa-sun'},
  {city:'Kuala Lumpur',flag:'🇲🇾',temp:31,desc:'Hujan Petang',humid:78,wind:12,rain:45,icon:'fa-cloud-rain'},
  {city:'Penang',flag:'🇲🇾',temp:30,desc:'Cerah',humid:72,wind:10,rain:10,icon:'fa-sun'},
  {city:'Johor Bahru',flag:'🇲🇾',temp:29,desc:'Berawan',humid:80,wind:9,rain:30,icon:'fa-cloud'},
  {city:'Singapore',flag:'🇸🇬',temp:30,desc:'Hujan Ringan',humid:82,wind:11,rain:60,icon:'fa-cloud-rain'},
  {city:'Silicon Valley',flag:'🇺🇸',temp:18,desc:'Cerah',humid:55,wind:15,rain:0,icon:'fa-sun'},
  {city:'London',flag:'🇬🇧',temp:12,desc:'Mendung',humid:75,wind:18,rain:20,icon:'fa-cloud'},
  {city:'Dubai',flag:'🇦🇪',temp:38,desc:'Panas Kering',humid:40,wind:6,rain:0,icon:'fa-sun'},
  {city:'Tokyo',flag:'🇯🇵',temp:22,desc:'Cerah',humid:60,wind:11,rain:5,icon:'fa-sun'},
  {city:'Zurich',flag:'🇨🇭',temp:10,desc:'Sejuk Berawan',humid:70,wind:9,rain:15,icon:'fa-cloud'},
  {city:'Sydney',flag:'🇦🇺',temp:20,desc:'Cerah',humid:58,wind:20,rain:0,icon:'fa-sun'},
  {city:'Tallinn',flag:'🇪🇪',temp:8,desc:'Sejuk Hujan',humid:85,wind:14,rain:55,icon:'fa-cloud-rain'},
  {city:'NEOM',flag:'🇸🇦',temp:27,desc:'Cerah Kering',humid:35,wind:9,rain:0,icon:'fa-sun'}
];

const WAVE_DATA = [
  {n:'Kedah / Selat Melaka',swh:0.8,period:6.2,dir:'SW',temp:'29°C',wind:8},
  {n:'Port Klang',swh:1.2,period:6.8,dir:'WSW',temp:'29°C',wind:10},
  {n:'Singapore Strait',swh:1.5,period:7.1,dir:'W',temp:'30°C',wind:12},
  {n:'SF Bay',swh:2.4,period:9.8,dir:'WNW',temp:'15°C',wind:18},
  {n:'North Sea',swh:1.8,period:7.4,dir:'SW',temp:'12°C',wind:15},
  {n:'Persian Gulf',swh:0.6,period:5.2,dir:'NW',temp:'28°C',wind:6},
  {n:'Tokyo Bay',swh:1.4,period:7.8,dir:'SE',temp:'22°C',wind:11},
  {n:'Tasman Sea',swh:2.8,period:10.2,dir:'SE',temp:'20°C',wind:20},
  {n:'Baltic Sea',swh:1.1,period:6.0,dir:'SW',temp:'8°C',wind:14},
  {n:'Red Sea',swh:0.9,period:6.5,dir:'NW',temp:'27°C',wind:9}
];

const CRYPTO_DATA = [
  {sym:'BTC',name:'Bitcoin',price:64104.80,change:+2.34,holdings:'4,050 BTC',value:'RM 1,217,737,500'},
  {sym:'ETH',name:'Ethereum',price:1886.89,change:-0.65,holdings:'2,847 ETH',value:'RM 22,500,000'},
  {sym:'S256c',name:'SGAE Sovereign',price:42.80,change:+8.42,holdings:'12,847,291',value:'RM 2,428,932'},
  {sym:'USDT',name:'Tether',price:1.00,change:+0.01,holdings:'$2,847,192',value:'RM 12,847,192'},
  {sym:'USDC',name:'USD Coin',price:1.00,change:0.00,holdings:'$1,247,891',value:'RM 5,631,847'},
  {sym:'SOL',name:'Solana',price:142.30,change:+3.47,holdings:'48,291 SOL',value:'RM 30,283,472'},
  {sym:'ADA',name:'Cardano',price:0.42,change:-1.24,holdings:'847,291 ADA',value:'RM 1,567,847'},
  {sym:'DOT',name:'Polkadot',price:5.42,change:+0.87,holdings:'284,721 DOT',value:'RM 6,792,847'}
];

const I18N = {
  ms: { title:"Identiti Berdaulat", name:"Nama", ic:"No. KP", email:"E-mel", phone:"Telefon", address:"Alamat", welcome:"Selamat Datang", lang:"Bahasa" },
  en: { title:"Sovereign Identity", name:"Name", ic:"IC Number", email:"Email", phone:"Phone", address:"Address", welcome:"Welcome", lang:"Language" },
  zh: { title:"主权身份", name:"姓名", ic:"身份证号码", email:"电子邮件", phone:"电话", address:"地址", welcome:"欢迎", lang:"语言" }
};

const VAULT_DOCS = [
  {name:'Sijil Kelahiran',type:'PDF',size:'1.2 MB',encrypted:true},
  {name:'Kad Pengenalan',type:'JPG',size:'0.8 MB',encrypted:true},
  {name:'Passport Malaysia',type:'PDF',size:'2.4 MB',encrypted:true},
  {name:'SSM Company Cert',type:'PDF',size:'1.5 MB',encrypted:true},
  {name:'Tax ID (LHDN)',type:'PDF',size:'0.6 MB',encrypted:true},
  {name:'GRAN Title 7734-7745',type:'PDF',size:'12.3 MB',encrypted:true},
  {name:'Family Trust Deed',type:'PDF',size:'3.2 MB',encrypted:true},
  {name:'MyIPO Patents',type:'PDF',size:'8.4 MB',encrypted:true},
  {name:'Insurance Policies',type:'PDF',size:'4.2 MB',encrypted:true},
  {name:'Blockchain Proof',type:'JSON',size:'0.1 MB',encrypted:true}
];

const NOTIFICATIONS = [
  {type:'success',icon:'✅',msg:'API Connected · Data live dari http://localhost:8000',time:'Baru sahaja'},
  {type:'success',icon:'🌱',msg:'GRAN Tanah: 12 lot telah berjaya dimuatkan',time:'1 minit lalu'},
  {type:'warning',icon:'⚠️',msg:'GRAN-MSI-KDH-7735 akan tamat dalam 30 hari',time:'5 minit lalu'},
  {type:'success',icon:'🛰️',msg:'SGAE-SAT-06 signal 97% · Excellent',time:'10 minit lalu'},
  {type:'danger',icon:'🚨',msg:'2 attempt login gagal dikesan dari 103.x.x.x',time:'15 minit lalu'},
  {type:'success',icon:'💰',msg:'Portfolio IP nilai: RM 47,800,000',time:'30 minit lalu'},
  {type:'warning',icon:'🌊',msg:'Gelombang tinggi dikesan di Tasman Sea (2.8m)',time:'1 jam lalu'},
  {type:'success',icon:'🔐',msg:'SHA-256 fingerprint disahkan',time:'2 jam lalu'}
];

// ================= HELPERS =================
const $ = id => document.getElementById(id);
const esc = s => String(s ?? '').replace(/[<>&"]/g, c => ({'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]));
function table(headers, rows, classes = []) {
  let h = '<table><thead><tr>';
  headers.forEach(x => h += `<th>${x}</th>`);
  h += '</tr></thead><tbody>';
  rows.forEach(r => {
    h += '<tr>';
    r.forEach((c, i) => h += `<td class="${classes[i] || ''}">${c}</td>`);
    h += '</tr>';
  });
  h += '</tbody></table>';
  return h;
}
function kv(l, v, c = 'gold') { return `<div class="info-box"><div class="label">${l}</div><div class="val ${c}">${esc(v)}</div></div>`; }

// ================= RENDER CORE =================
function renderKPI() {
  const kpi = [
    { label: "💰 Portfolio IP", value: "RM 47.8 Juta", sub: "RVC Appraisers 2026", cls: "gold" },
    { label: "🌱 GRAN Tanah", value: "12 Lot", sub: "RM 284,600,000", cls: "green" },
    { label: "🌍 GRAN Global", value: "12 Lot", sub: "RM 884,200,000", cls: "orange" },
    { label: "👑 Sovereign", value: "MSI-2026-07734", sub: "L04 CTS", cls: "cyan" },
    { label: "👨‍👩‍👧‍👦 Keluarga", value: "7 Ahli", sub: "Ismail & Syarifah", cls: "pink" },
    { label: "🌐 205 Negara", value: "Kerjasama", sub: "Global", cls: "purple" },
    { label: "🛰️ Satelit", value: "6 Aktif", sub: "SGAE-SAT", cls: "blue" },
    { label: "🌊 Max SWH", value: "15.2 m", sub: "Southern Ocean", cls: "red" }
  ];
  $('kpiGrid').innerHTML = kpi.map(k => `<div class="kpi ${k.cls === 'green' ? 'gran-stat' : ''}"><div class="label">${k.label}</div><div class="value ${k.cls}">${k.value}</div><div class="sub">${k.sub}</div></div>`).join('');
}

function renderIdentiti() {
  const d = {nama_penuh:"MUHAMAD SAZWAN BIN ISMAIL",no_kad_pengenalan:"961022-02-5739",tarikh_lahir:"22.10.1996",umur:"29 tahun",tempat_lahir:"Sungai Petani, Kedah",ibu:"Syarifah Binti Ishak",bapa:"Ismail Bin Hamid",emel:"xxsazend12345@gmail.com",telefon:"+60162847180",alamat:"F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia",participant_id:"END-MYS-SAZWAN-96-0425",military_id:"MY-ATM-CYBER/7734",interpol_id:"IP-MY-7734-2026",peranan:"Technical Lead for AI Sovereignty",sha256:"32D8A53CC4C299E60424C0D0E96D3B06575D51",block:"847,995",msi:"MSI-2026-07734",cmc:"CMC-REF-2026-MSI-003",ssm:"202403378912"};
  const rows = [["Nama",d.nama_penuh,"gold"],["No. KP",d.no_kad_pengenalan,"cyan"],["Tarikh Lahir",d.tarikh_lahir,""],["Umur",d.umur,"gold"],["Tempat Lahir",d.tempat_lahir,""],["Ibu",d.ibu,"pink"],["Bapa",d.bapa,"cyan"],["E-mel",d.emel,"cyan"],["Telefon",d.telefon,"green"],["Alamat",d.alamat,"gold"],["Participant ID",d.participant_id,"cyan"],["Military ID",d.military_id,"yellow"],["INTERPOL ID",d.interpol_id,"cyan"],["Peranan",d.peranan,"gold"],["SSM",d.ssm,"blue"]];
  $('identitiContent').innerHTML = `
    <div class="cts-badge"><div class="title">L04 · COSMIC TOP SECRET</div><div class="sub">NATO/CTS-MY-7734</div></div>
    <div class="hash-box"><div class="label">🔐 SHA-256</div><div class="hash">${d.sha256}</div></div>
    <div class="grid-2">
      <div>${table(["Medan","Nilai"], rows, ["", "", ""])}</div>
      <div>
        <div class="info-box"><div class="label">Block</div><div class="val mono cyan">#${d.block}</div></div>
        <div class="info-box"><div class="label">MSI</div><div class="val gold">${d.msi}</div></div>
        <div class="info-box"><div class="label">CMC</div><div class="val gold">${d.cmc}</div></div>
      </div>
    </div>`;
}

function renderKeluarga() {
  const ahli = [
    { turutan: "Bapa", nama: "Ismail Bin Hamid", dob: "22.10.1966", umur: "59 tahun", jantina: "Lelaki" },
    { turutan: "Ibu", nama: "Syarifah Binti Ishak", dob: "10.11.1966", umur: "59 tahun", jantina: "Perempuan" },
    { turutan: "Kakak 1", nama: "Isma Husna Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "CEO", nama: "Muhamad Sazwan Bin Ismail", dob: "22.10.1996", umur: "29 tahun", jantina: "Lelaki" },
    { turutan: "Adik 3", nama: "Syabika Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "Adik 4", nama: "Amira Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "Adik 5", nama: "Isma Azim Wafiq Bin Ismail", dob: "—", umur: "—", jantina: "Lelaki" }
  ];
  $('keluargaContent').innerHTML = `
    <div class="info-box"><div class="label">🏠 Alamat Rumah Keluarga</div><div class="val gold">F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia</div></div>
    <div class="hash-box"><div class="label">👨‍👩‍👧‍👦 FAMILY HASH</div><div class="hash">FAM32D8A53CC4C299E60424C0D0E96D3B06575</div></div>
    <h3>Senarai Ahli (7)</h3>
    ${table(["Turutan","Nama","DOB","Umur","Jantina"], ahli.map(a => [a.turutan, a.nama, a.dob, a.umur, a.jantina]), ["pink","pink","","gold","cyan"])}
    <div class="grid-3">
      ${kv("Level", "L04 COSMIC TOP SECRET", "yellow")}
      ${kv("Insurans", "RM 11,500,000", "gold")}
      ${kv("Trust", "RM 42,000,000", "green")}
      ${kv("Biometric", "FAM-BIO-7734", "pink")}
    </div>`;
}

function renderGran() {
  $('granTanahContent').innerHTML = table(["ID","Flag","Negeri","Nama","Luas","Nilai","Tenure","Jenis"], GRAN_TANAH.map(g => [g.id, g.flag, g.state, g.name, g.area, g.value, g.tenure, g.type]), ["mono","","green","gold","cyan","gold","",""]);
  $('granGlobalContent').innerHTML = table(["ID","Flag","Negara","Nama","Bandar","Luas","Nilai"], GRAN_GLOBAL.map(g => [g.id, g.flag, g.country, g.name, g.city, g.area, g.value]), ["mono","","orange","gold","","cyan","gold"]);
  const total = 284600000 + 884200000;
  $('granSummaryContent').innerHTML = `
    <div class="grid-3">
      ${kv("Total Nilai", "RM " + total.toLocaleString(), "gold")}
      ${kv("Total Lot", "24", "green")}
      ${kv("Negara", "13", "orange")}
      ${kv("Status", "LOCKED", "yellow")}
      ${kv("Blockchain", "#847,995", "cyan")}
      ${kv("SSM", "202403378912", "blue")}
    </div>`;
}

function renderGelombang() {
  let h = '<div class="grid-3">';
  WAVE_DATA.forEach(w => {
    const color = w.swh >= 2.5 ? '#ef4444' : w.swh >= 1.5 ? '#fbbf24' : '#34d399';
    h += `<div class="info-box"><div class="label">${w.n}</div><div class="val" style="color:${color}">${w.swh} m SWH</div><div style="font-size:11px;color:var(--muted);margin-top:6px">Period: ${w.period}s · ${w.dir} · ${w.temp} · Wind: ${w.wind} km/h</div></div>`;
  });
  h += '</div>';
  $('gelombangContent').innerHTML = h;
}

// ================= 1. AI CHAT =================
function sendChat() {
  const input = $('chatInput');
  const msg = input.value.trim();
  if (!msg) return;
  addChatMsg('user', msg);
  input.value = '';
  setTimeout(() => {
    const reply = getAIReply(msg.toLowerCase());
    addChatMsg('bot', reply);
  }, 500);
}
function quickAsk(q) { $('chatInput').value = q; sendChat(); }
function addChatMsg(type, text) {
  const div = document.createElement('div');
  div.className = `chat-msg ${type}`;
  div.innerHTML = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>').replace(/\n/g, '<br>');
  $('chatMessages').appendChild(div);
  $('chatMessages').scrollTop = $('chatMessages').scrollHeight;
}
function getAIReply(q) {
  if (q.includes('gran') || q.includes('tanah')) return `🌱 **GRAN Tanah**: 12 lot, nilai **RM 284,600,000**.\n\nLokasi: Kedah (3 lot), KL, Penang, Johor, Singapore, USA, UAE, Japan, UK, Switzerland.\n\nGRAN Global: 12 lot, **RM 884,200,000** di 12 negara.`;
  if (q.includes('keluarga') || q.includes('family')) return `👨‍👩‍👧‍👦 **Keluarga Ismail & Syarifah** — 7 ahli:\n• Bapa: Ismail Bin Hamid (59)\n• Ibu: Syarifah Binti Ishak (59)\n• Kakak 1: Isma Husna\n• CEO: Muhamad Sazwan (29)\n• Adik 3-5: Syabika, Amira, Isma Azim\n\n🏠 Alamat: F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah`;
  if (q.includes('msi') || q.includes('07734')) return `🔐 **MSI-2026-07734** adalah Master Sovereign Identity untuk Muhamad Sazwan Bin Ismail.\n\nSHA-256: \`32D8A53CC4C299E60424C0D0E96D3B06575D51\`\nBlockchain: Bitcoin Block #847,995\nCMC Ref: CMC-REF-2026-MSI-003`;
  if (q.includes('aset') || q.includes('portfolio')) return `💰 **Aset Portfolio**:\n• Portfolio IP: RM 47.8 Juta\n• Bitcoin: ₿ 4,050 BTC (≈ RM 1.2B)\n• GRAN Tanah: RM 284.6 Juta\n• GRAN Global: RM 884.2 Juta\n• Total: **RM 3.18 Bilion**`;
  if (q.includes('satelit') || q.includes('sat')) return `🛰️ **SGAE-SAT Constellation**: 6 satelit aktif\n• 2× GEO (35,786 km)\n• 2× LEO (480-550 km)\n• 1× MEO (20,200 km)\n• 1× SSO (700 km)\n\nAvg Signal: **93%** · Ground Stations: 6`;
  if (q.includes('negara') || q.includes('country')) return `🌍 **205 Negara** kerjasama global dengan 6 MoU aktif.\n\nAgreements: 321 · Value: $8.62M`;
  if (q.includes('api')) return `🔌 **42 API Endpoints** dalam 18 kumpulan.\n\nCalls 24h: 42,847 · WebSocket: 4\nLive: http://localhost:8000/all`;
  if (q.includes('cuaca') || q.includes('weather')) return `🌦️ **Cuaca masa nyata** di 13 lokasi GRAN.\n\nSuhu tertinggi: Dubai (38°C)\nSuhu terendah: Tallinn (8°C)\nMalaysia: 29-32°C`;
  if (q.includes('sijil') || q.includes('cert')) return `🎖️ **245 Sijil Global** dalam 16 kategori.\n\nUtama: Google ML, AWS AI/ML, CISSP, CEH, OSCP, PMP`;
  if (q.includes('hi') || q.includes('hello') || q.includes('hai')) return `👋 Hai! Saya AI SGAE 2.0. Tanya apa sahaja tentang GRAN, keluarga, aset, satelit, atau data sistem!`;
  return `🤖 Saya boleh bantu dengan:\n• GRAN (tanah & global)\n• Keluarga (7 ahli)\n• Aset (RM 3.18B)\n• Satelit (6 aktif)\n• MSI/CMC codes\n\nCuba tanya: "Berapa nilai GRAN?"`;
}

// ================= 2. EXPORT =================
function exportData(format) {
  const data = { identiti: { name: "MUHAMAD SAZWAN BIN ISMAIL", ic: "961022-02-5739" }, gran_tanah: GRAN_TANAH, gran_global: GRAN_GLOBAL, family: "7 ahli", wave_data: WAVE_DATA, crypto: CRYPTO_DATA };
  const ts = new Date().toISOString().slice(0,10);
  if (format === 'json') { downloadFile(JSON.stringify(data, null, 2), `SGAE_export_${ts}.json`, 'application/json'); }
  else if (format === 'csv') { let csv = 'Category,Name,Value\n'; GRAN_TANAH.forEach(g => csv += `GRAN Tanah,${g.name},${g.value}\n`); GRAN_GLOBAL.forEach(g => csv += `GRAN Global,${g.name},${g.value}\n`); downloadFile(csv, `SGAE_export_${ts}.csv`, 'text/csv'); }
  else if (format === 'excel') {
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(GRAN_TANAH), 'GRAN Tanah');
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(GRAN_GLOBAL), 'GRAN Global');
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(CRYPTO_DATA), 'Crypto');
    XLSX.writeFile(wb, `SGAE_export_${ts}.xlsx`);
  } else if (format === 'pdf') {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF();
    doc.setFontSize(18); doc.text('SGAE 2.0 — Sovereign Report', 14, 20);
    doc.setFontSize(10); doc.text(`Owner: MUHAMAD SAZWAN BIN ISMAIL`, 14, 30); doc.text(`IC: 961022-02-5739 · MSI: MSI-2026-07734`, 14, 36);
    doc.autoTable({ startY: 45, head: [['GRAN','Nama','Nilai']], body: [...GRAN_TANAH.map(g => ['Tanah',g.name,g.value]), ...GRAN_GLOBAL.map(g => ['Global',g.name,g.value])], headStyles: { fillColor: [0,229,255] } });
    doc.save(`SGAE_export_${ts}.pdf`);
  }
}
function downloadFile(content, name, mime) {
  const blob = new Blob([content], { type: mime });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob); a.download = name; a.click();
}

// ================= 3. CRYPTO =================
let cryptoChartInst;
function renderCrypto() {
  const totalValue = 'RM 1,256,996,500';
  $('cryptoKPI').innerHTML = `
    <div class="kpi"><div class="label">Total Holdings</div><div class="value gold">${totalValue}</div></div>
    <div class="kpi"><div class="label">BTC</div><div class="value orange">₿ 4,050</div><div class="sub">RM 1.22B</div></div>
    <div class="kpi"><div class="label">S256c</div><div class="value cyan">12.8M</div><div class="sub">+8.42%</div></div>
    <div class="kpi"><div class="label">Coins</div><div class="value purple">8 Active</div></div>`;
  $('cryptoGrid').innerHTML = CRYPTO_DATA.map(c => `
    <div class="crypto-card">
      <div><div class="sym">${c.sym}</div><div style="font-size:11px;color:var(--muted)">${c.name}</div><div style="font-size:11px;color:var(--muted);margin-top:4px">${c.holdings}</div></div>
      <div style="text-align:right"><div class="price">$${c.price.toLocaleString()}</div><div class="change ${c.change >= 0 ? 'up' : 'down'}">${c.change >= 0 ? '▲' : '▼'} ${Math.abs(c.change).toFixed(2)}%</div><div style="font-size:10px;color:var(--muted)">${c.value}</div></div>
    </div>`).join('');
  if (cryptoChartInst) cryptoChartInst.destroy();
  const ctx = $('cryptoChart').getContext('2d');
  cryptoChartInst = new Chart(ctx, {
    type: 'line',
    data: {
      labels: Array.from({length:24}, (_,i) => `${i}h`),
      datasets: [
        { label: 'BTC', data: Array.from({length:24}, () => 63000 + Math.random()*2000), borderColor: '#f7931a', tension: 0.4 },
        { label: 'ETH', data: Array.from({length:24}, () => 1800 + Math.random()*150), borderColor: '#a855f7', tension: 0.4 },
        { label: 'S256c', data: Array.from({length:24}, () => 40 + Math.random()*5), borderColor: '#00e5ff', tension: 0.4 }
      ]
    },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= 4. I18N =================
let currentLang = 'ms';
function changeLang(lang) {
  currentLang = lang;
  document.querySelectorAll('.lang-btn').forEach(b => b.classList.toggle('active', b.textContent.includes(lang === 'ms' ? 'Melayu' : lang === 'en' ? 'English' : '中文')));
  const t = I18N[lang];
  $('i18nContent').innerHTML = `
    <div class="grid-2">
      <div>
        <div class="info-box"><div class="label">${t.title}</div><div class="val gold">MUHAMAD SAZWAN BIN ISMAIL</div></div>
        <div class="info-box"><div class="label">${t.ic}</div><div class="val cyan">961022-02-5739</div></div>
        <div class="info-box"><div class="label">${t.email}</div><div class="val cyan">xxsazend12345@gmail.com</div></div>
        <div class="info-box"><div class="label">${t.phone}</div><div class="val green">+60162847180</div></div>
        <div class="info-box"><div class="label">${t.address}</div><div class="val gold">F262 Kampung Pinang Tunggal, Sungai Petani, Kedah</div></div>
      </div>
      <div>
        <div class="info-box"><div class="label">${t.lang}</div><div class="val purple">${lang.toUpperCase()}</div></div>
        <div class="info-box"><div class="label">${t.welcome}</div><div class="val gold">👋 ${t.welcome}!</div></div>
      </div>
    </div>`;
}

// ================= 5. VAULT =================
function renderVault() {
  let h = '';
  VAULT_DOCS.forEach(d => {
    h += `<div class="vault-item">
      <div class="icon"><i class="fas fa-file-${d.type === 'PDF' ? 'pdf' : d.type === 'JPG' ? 'image' : 'code'}"></i></div>
      <div class="info"><div class="name">${d.name}</div><div class="meta">${d.type} · ${d.size} · AES-256-GCM</div></div>
      <div class="lock">🔐 ${d.encrypted ? 'LOCKED' : 'OPEN'}</div>
    </div>`;
  });
  $('vaultContent').innerHTML = h;
}

// ================= 6. NOTIFICATIONS =================
function renderNotifications() {
  const counts = { success: 0, warning: 0, danger: 0 };
  NOTIFICATIONS.forEach(n => { if (counts[n.type] !== undefined) counts[n.type]++; });
  $('notifCount').textContent = NOTIFICATIONS.length;
  $('notifSuccess').textContent = counts.success;
  $('notifWarn').textContent = counts.warning;
  $('notifDanger').textContent = counts.danger;
  $('notifContent').innerHTML = NOTIFICATIONS.map(n => `<div class="notif-item ${n.type}"><div class="icon">${n.icon}</div><div class="msg">${n.msg}<div class="time">${n.time}</div></div></div>`).join('');
}

// ================= 7. MONITOR =================
let monitorChartInst;
function renderMonitor() {
  const monitors = [
    { name: 'API Server', value: '42ms', status: 'online' },
    { name: 'Database', value: '12ms', status: 'online' },
    { name: 'Blockchain Node', value: '284ms', status: 'online' },
    { name: 'CDN (Global)', value: '18ms', status: 'online' },
    { name: 'Quantum Core', value: '4ms', status: 'online' },
    { name: 'AI Engine', value: '46ms', status: 'online' },
    { name: 'Satellite Link', value: '124ms', status: 'warning' },
    { name: 'Backup Server', value: '68ms', status: 'online' }
  ];
  $('monitorGrid').innerHTML = monitors.map(m => `<div class="monitor-item"><div class="label">${m.name}</div><div class="value ${m.status === 'online' ? 'green' : 'yellow'}">${m.value}</div><div class="status ${m.status}">● ${m.status.toUpperCase()}</div></div>`).join('');
  if (monitorChartInst) monitorChartInst.destroy();
  const ctx = $('monitorChart').getContext('2d');
  monitorChartInst = new Chart(ctx, {
    type: 'line',
    data: { labels: Array.from({length:30}, (_,i) => `${i*2}s`), datasets: [{ label: 'Latency (ms)', data: Array.from({length:30}, () => 30 + Math.random()*40), borderColor: '#00e5ff', backgroundColor: 'rgba(0,229,255,0.1)', fill: true, tension: 0.4 }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= 8. GRAN CHARTS =================
let chartTanahInst, chartGlobalInst, chartTimelineInst;
function renderGranCharts() {
  if (chartTanahInst) chartTanahInst.destroy();
  chartTanahInst = new Chart($('chartTanah').getContext('2d'), {
    type: 'bar',
    data: { labels: GRAN_TANAH.map(g => g.name.substring(0,20)), datasets: [{ label: 'Nilai (RM)', data: GRAN_TANAH.map(g => parseInt(g.value.replace(/[^0-9]/g,''))), backgroundColor: '#34d399' }] },
    options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8', font: { size: 10 } } } } }
  });
  if (chartGlobalInst) chartGlobalInst.destroy();
  chartGlobalInst = new Chart($('chartGlobal').getContext('2d'), {
    type: 'doughnut',
    data: { labels: GRAN_GLOBAL.map(g => g.country), datasets: [{ data: GRAN_GLOBAL.map(g => parseInt(g.value.replace(/[^0-9]/g,''))), backgroundColor: ['#00e5ff','#a855f7','#fbbf24','#ec4899','#34d399','#f7931a','#4285f4','#ef4444','#10b981','#6366f1','#8b5cf6','#14b8a6'] }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right', labels: { color: '#e8eaed', font: { size: 10 } } } } }
  });
  if (chartTimelineInst) chartTimelineInst.destroy();
  chartTimelineInst = new Chart($('chartTimeline').getContext('2d'), {
    type: 'line',
    data: { labels: ['2024','2025','2026','2027','2028','2030'], datasets: [{ label: 'Nilai GRAN (RM)', data: [18600000, 142000000, 1168800000, 1420000000, 2280000000, 4800000000], borderColor: '#fbbf24', backgroundColor: 'rgba(251,191,36,0.2)', fill: true, tension: 0.4 }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= SATELIT =================
function renderSatellite() {
  $('satContent').innerHTML = table(["ID","Orbit","Altitud","Band","Signal","Jenis"], SATELLITES.map(s => [s.id, s.orbit, s.alt, s.band, s.signal + '%', s.type]), ["mono","cyan","gold","purple","green",""]);
  $('orbitViz').innerHTML = `<div style="height:400px;background:radial-gradient(circle at center,#0a1628,#000);border-radius:12px;position:relative;overflow:hidden">
    <div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:80px;height:80px;background:radial-gradient(circle,#3b82f6,#1e40af);border-radius:50%;box-shadow:0 0 40px #3b82f6"></div>
    ${[100,150,200,175].map((r,i) => `<div style="position:absolute;top:50%;left:50%;width:${r*2}px;height:${r*2}px;border:1px dashed ${['#00e5ff40','#a855f740','#fbbf2440','#ec489940'][i]};border-radius:50%;transform:translate(-50%,-50%)"></div>`).join('')}
    ${SATELLITES.map((s,i) => { const r = s.orbit === 'LEO' ? 100 : s.orbit === 'MEO' ? 150 : s.orbit === 'GEO' ? 200 : 175; const angle = (i * 60); const x = Math.cos(angle*Math.PI/180)*r; const y = Math.sin(angle*Math.PI/180)*r; return `<div style="position:absolute;top:calc(50% + ${y}px);left:calc(50% + ${x}px);width:10px;height:10px;background:${s.signal>=95?'#00e5ff':s.signal>=90?'#fbbf24':'#ef4444'};border-radius:50%;box-shadow:0 0 10px currentColor;margin:-5px 0 0 -5px"></div>`; }).join('')}
    <div style="position:absolute;top:20px;left:20px;font-size:11px;color:#94a3b8">🟦 Earth · 4 orbit layers</div>
  </div>`;
}

// ================= WEATHER =================
function renderWeather() {
  $('weatherContent').innerHTML = `<div class="grid-3">${WEATHER_DATA.map(w => `
    <div class="weather-card" style="background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:14px">
      <div style="display:flex;align-items:center;gap:8px">
        <i class="fas ${w.icon}" style="font-size:1.5rem;color:${w.temp>=30?'#fbbf24':w.rain>=40?'#60a5fa':'#94a3b8'}"></i>
        <div style="flex:1"><div style="font-weight:700;color:#fff;font-size:13px">${w.flag} ${w.city}</div><div style="font-size:11px;color:var(--muted)">${w.desc}</div></div>
        <div style="font-size:24px;font-weight:900;color:var(--gold);font-family:monospace">${w.temp}°</div>
      </div>
      <div style="display:flex;justify-content:space-between;font-size:11px;color:var(--muted);margin-top:8px;padding-top:8px;border-top:1px solid var(--border)">💧 ${w.humid}% · 💨 ${w.wind}km/h · 🌧️ ${w.rain}mm</div>
    </div>`).join('')}</div>`;
}

// ================= DOCS =================
function renderGranDocs() {
  $('granDocsContent').innerHTML = GRAN_TANAH.map(d => `
    <div style="background:var(--card2);border:1px solid var(--border);border-left:4px solid var(--gold);border-radius:10px;padding:14px;margin:8px 0">
      <div style="font-weight:700;color:var(--gold);font-size:13px">${d.flag} ${d.title} — ${d.name}</div>
      <div style="font-size:11px;color:var(--muted);margin:4px 0">📍 ${d.state} · ${d.type} · ${d.area} · ${d.tenure}</div>
      <div style="font-size:11px;color:var(--muted)">💰 ${d.value}</div>
      <div style="display:inline-block;background:rgba(52,168,83,.15);color:#81c995;padding:2px 10px;border-radius:10px;font-size:10px;font-weight:600;margin-top:6px">✅ REGISTERED</div>
    </div>`).join('');
}

// ================= MAP =================
let earthMap;
function initMap() {
  if (earthMap) return;
  earthMap = L.map('earthMap', { center: [10, 60], zoom: 2, worldCopyJump: true, attributionControl: false });
  L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { maxZoom: 19, subdomains: 'abcd' }).addTo(earthMap);
  GRAN_TANAH.forEach(g => L.circleMarker([g.lat, g.lng], { radius: 7, color: '#34d399', fillColor: '#34d399', fillOpacity: .8, weight: 2 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#34d399">🌱 ${esc(g.name)}</strong><br>${g.flag} ${g.state}<br><b>${g.value}</b></div>`).addTo(earthMap));
  GRAN_GLOBAL.forEach(g => L.circleMarker([g.lat, g.lng], { radius: 6, color: '#fbbf24', fillColor: '#fbbf24', fillOpacity: .7, weight: 2 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#fbbf24">🌍 ${esc(g.name)}</strong><br>${g.flag} ${g.country}<br><b>${g.value}</b></div>`).addTo(earthMap));
  L.circleMarker([5.6470, 100.4874], { radius: 12, color: '#ec4899', fillColor: '#ec4899', fillOpacity: .9, weight: 3 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#ec4899">👨‍👩‍👧‍👦 Rumah Keluarga</strong><br>F262 Kg Pinang Tunggal</div>`).addTo(earthMap);
}

// ================= 3D GLOBE =================
let globeScene, globeCamera, globeRenderer, globeGroup, globeRotation = true, satOrbitGroup;
function init3DGlobe() {
  const container = $('globeContainer');
  if (!container || globeScene) return;
  const w = container.clientWidth, h = container.clientHeight;
  globeScene = new THREE.Scene();
  globeCamera = new THREE.PerspectiveCamera(45, w/h, 0.1, 1000);
  globeCamera.position.set(0, 0, 3.5);
  globeRenderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  globeRenderer.setSize(w, h);
  container.innerHTML = '';
  container.appendChild(globeRenderer.domElement);
  const controls = new THREE.OrbitControls(globeCamera, globeRenderer.domElement);
  controls.enableDamping = true;
  globeScene.add(new THREE.AmbientLight(0x404060, 1));
  const dLight = new THREE.DirectionalLight(0xffffff, 1.2); dLight.position.set(5, 3, 5); globeScene.add(dLight);
  const pLight = new THREE.PointLight(0x00e5ff, 0.8); pLight.position.set(-3, -2, -3); globeScene.add(pLight);
  globeGroup = new THREE.Group(); globeScene.add(globeGroup);
  const earthGeo = new THREE.SphereGeometry(1, 64, 64);
  const tex = new THREE.TextureLoader().load('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg');
  globeGroup.add(new THREE.Mesh(earthGeo, new THREE.MeshPhongMaterial({ map: tex, emissive: 0x0a1a3f, emissiveIntensity: 0.2 })));
  const wire = new THREE.Mesh(new THREE.SphereGeometry(1.002, 32, 32), new THREE.MeshBasicMaterial({ color: 0x00e5ff, wireframe: true, transparent: true, opacity: 0.06 }));
  globeGroup.add(wire);
  const atmo = new THREE.Mesh(new THREE.SphereGeometry(1.05, 32, 32), new THREE.MeshBasicMaterial({ color: 0x00e5ff, transparent: true, opacity: 0.08, side: THREE.BackSide }));
  globeGroup.add(atmo);
  function toXYZ(lat, lng, r) {
    const phi = (90 - lat) * Math.PI / 180;
    const theta = (lng + 180) * Math.PI / 180;
    return new THREE.Vector3(-r * Math.sin(phi) * Math.cos(theta), r * Math.cos(phi), r * Math.sin(phi) * Math.sin(theta));
  }
  function addMarker(lat, lng, color, size) {
    const pos = toXYZ(lat, lng, 1.02);
    const m = new THREE.Mesh(new THREE.SphereGeometry(size, 8, 8), new THREE.MeshBasicMaterial({ color }));
    m.position.copy(pos); globeGroup.add(m);
    const glow = new THREE.Mesh(new THREE.SphereGeometry(size*1.8, 8, 8), new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.3 }));
    glow.position.copy(pos); globeGroup.add(glow);
  }
  GRAN_TANAH.forEach(g => addMarker(g.lat, g.lng, 0x34d399, 0.025));
  GRAN_GLOBAL.forEach(g => addMarker(g.lat, g.lng, 0xfbbf24, 0.02));
  addMarker(5.6470, 100.4874, 0xec4899, 0.035);
  satOrbitGroup = new THREE.Group(); globeScene.add(satOrbitGroup);
  const colors = { LEO: 0x00e5ff, MEO: 0xa855f7, GEO: 0xfbbf24, SSO: 0xec4899 };
  const radii = { LEO: 1.3, MEO: 1.6, GEO: 1.9, SSO: 1.75 };
  ['LEO','MEO','GEO','SSO'].forEach(ot => {
    const r = radii[ot];
    const pts = [];
    for (let i = 0; i <= 64; i++) { const a = (i/64) * Math.PI * 2; pts.push(new THREE.Vector3(r*Math.cos(a), 0, r*Math.sin(a))); }
    const line = new THREE.Line(new THREE.BufferGeometry().setFromPoints(pts), new THREE.LineBasicMaterial({ color: colors[ot], transparent: true, opacity: 0.4 }));
    if (ot === 'LEO') line.rotation.x = Math.PI / 6;
    if (ot === 'SSO') line.rotation.x = Math.PI / 2;
    satOrbitGroup.add(line);
  });
  const satMeshes = SATELLITES.map((s, i) => {
    const r = radii[s.orbit] || 1.3;
    const m = new THREE.Mesh(new THREE.SphereGeometry(0.018, 8, 8), new THREE.MeshBasicMaterial({ color: colors[s.orbit] }));
    m.userData = { r, speed: 0.3 + i * 0.05, angle: i * Math.PI / 3, orbit: s.orbit };
    satOrbitGroup.add(m); return m;
  });
  const clock = new THREE.Clock();
  function animate() {
    requestAnimationFrame(animate);
    if (globeRotation) globeGroup.rotation.y += 0.0015;
    satMeshes.forEach(sat => {
      sat.userData.angle += sat.userData.speed * 0.01;
      const a = sat.userData.angle, r = sat.userData.r;
      sat.position.set(r*Math.cos(a), 0, r*Math.sin(a));
      if (sat.userData.orbit === 'LEO') sat.position.applyAxisAngle(new THREE.Vector3(1,0,0), Math.PI/6);
      if (sat.userData.orbit === 'SSO') sat.position.applyAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2);
    });
    satOrbitGroup.rotation.y += 0.0008;
    controls.update();
    globeRenderer.render(globeScene, globeCamera);
  }
  animate();
  window.addEventListener('resize', () => { const W = container.clientWidth, H = container.clientHeight; if (W && H) { globeCamera.aspect = W/H; globeCamera.updateProjectionMatrix(); globeRenderer.setSize(W, H); } });
}

// ================= MISC RENDER =================
function renderAPI() {
  const groups = [{n:'Ledger',c:5},{n:'AI/Python',c:2},{n:'Gemini',c:2},{n:'FPX',c:2},{n:'Satellite',c:2},{n:'Family',c:2},{n:'GRAN',c:2},{n:'MyIPO',c:7},{n:'WebSocket',c:4}];
  $('apiContent').innerHTML = `<div class="kpi-grid"><div class="kpi"><div class="label">Total</div><div class="value cyan">42</div></div><div class="kpi"><div class="label">Calls 24h</div><div class="value gold">42,847</div></div><div class="kpi"><div class="label">WebSocket</div><div class="value purple">4</div></div></div>` + groups.map(g => `<div class="info-box"><strong>${g.n}</strong> · ${g.c} en…


___

## **CodeAnt-AI Description**
Add five interactive GRAN monitoring and visualization components

### What Changed
- Adds a GRAN chart tab with sorted land and global values plus a 2024–2030 growth timeline
- Adds satellite tracking with six SGAE-SAT entries, orbit visualization, signal levels, and ground-station details
- Adds weather displays for 13 locations, including temperature, humidity, wind, rainfall, and conditions
- Adds registered GRAN title-deed records with ownership details, document hashes, and verification status
- Adds an interactive 3D Earth showing GRAN locations and animated satellite orbits, with rotation and orbit visibility controls

### Impact
`✅ Five new monitoring tabs`
`✅ Clearer GRAN value and growth comparisons`
`✅ Interactive satellite and location visualization`
<details><summary><strong>💡 Usage Guide</strong></summary>

### Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

### Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
<pre>
<code>@codeant-ai ask: Your question here</code>
</pre>
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

#### Example
<pre>
<code>@codeant-ai ask: Can you suggest a safer alternative to storing this secret?</code>
</pre>

### Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
<pre>
<code>@codeant-ai: Your feedback here</code>
</pre>
This helps CodeAnt AI learn and adapt to your team's coding style and standards.

#### Example
<pre>
<code>@codeant-ai: Do not flag unused imports.</code>
</pre>

### Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
<pre>
<code>@codeant-ai: review</code>
</pre>

### Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at [https://app.codeant.ai](https://app.codeant.ai). This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

</details>

# 🚀 SGAE 2.0 MASTER v39 · 8 KOMPONEN ULTIMATE

Berikut adalah **fail HTML lengkap** yang menggabungkan **semua data v37/v38** + **8 komponen baharu** dalam satu fail.

Simpan sebagai **`sgae_master_v39_ultimate.html`**:

```html
<!DOCTYPE html>
<html lang="ms">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>SGAE 2.0 MASTER v39 · ULTIMATE · Muhamad Sazwan Bin Ismail</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700;900&family=Roboto+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.1/jspdf.plugin.autotable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#0a0f17;--card:#1e293b;--card2:#0f172a;--border:#334155;--text:#e8eaed;--muted:#94a3b8;
--gold:#ffd700;--cyan:#00e5ff;--green:#34a853;--pink:#ec4899;--purple:#a855f7;
--red:#ef4444;--orange:#f7931a;--blue:#4285f4;--yellow:#f7ea48}
html,body{width:100%;min-height:100%;background:var(--bg);color:var(--text);font-family:'Roboto',system-ui,sans-serif;line-height:1.5}
body{padding:16px}
.container{max-width:1600px;margin:0 auto}
header{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:12px;margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--border)}
h1{font-size:26px;background:linear-gradient(135deg,#ffd700,#ec4899,#a855f7,#00e5ff);-webkit-background-clip:text;background-clip:text;color:transparent;font-weight:900}
.sub{font-size:13px;color:var(--muted);margin-top:4px}
.badges{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.badge{padding:4px 12px;border-radius:20px;font-size:11px;font-weight:600;border:1px solid}
.badge.gold{border-color:var(--gold);color:var(--gold)}
.badge.cyan{border-color:var(--cyan);color:var(--cyan)}
.badge.pink{border-color:var(--pink);color:var(--pink)}
.badge.green{border-color:var(--green);color:var(--green)}
.badge.red{border-color:var(--red);color:var(--red)}
.badge.purple{border-color:var(--purple);color:var(--purple)}
.badge.orange{border-color:var(--orange);color:var(--orange)}
.badge.blue{border-color:var(--blue);color:var(--blue)}
.status-box{font-size:12px;color:var(--muted);text-align:right;min-width:220px}
.status-box .ok{color:var(--green);font-weight:600}
.status-box .err{color:var(--red);font-weight:600}
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:14px;position:relative;overflow:hidden}
.kpi::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#ffd700,#ec4899,#a855f7,#00e5ff)}
.kpi .label{font-size:12px;color:var(--muted);margin-bottom:4px}
.kpi .value{font-size:22px;font-weight:700;margin:4px 0}
.kpi .sub{font-size:11px;color:var(--muted)}
.card{background:var(--card);border:1px solid var(--border);border-radius:16px;padding:20px;margin-bottom:20px}
.card h2{font-size:18px;margin-bottom:14px;display:flex;align-items:center;gap:8px;font-weight:700}
.card h2 i{color:var(--cyan)}
.card h3{font-size:15px;margin:12px 0 8px;color:var(--cyan);font-weight:600}
.tabs{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:20px;position:sticky;top:0;background:var(--bg);padding:10px 0;z-index:1000;border-bottom:1px solid var(--border)}
.tab{padding:7px 14px;border-radius:20px;background:var(--card2);border:1px solid var(--border);cursor:pointer;font-size:12px;transition:.2s;color:var(--text);font-weight:500}
.tab:hover{background:var(--card);transform:translateY(-1px)}
.tab.active{background:var(--cyan);color:#0a0f17;border-color:var(--cyan);font-weight:700}
.tab.chat{background:linear-gradient(135deg,rgba(168,85,247,.3),rgba(236,72,153,.2));border-color:var(--purple);color:var(--purple);font-weight:700}
.tab.export{background:linear-gradient(135deg,rgba(52,168,83,.3),rgba(0,229,255,.15));border-color:var(--green);color:var(--green);font-weight:700}
.tab.crypto{background:linear-gradient(135deg,rgba(247,147,26,.3),rgba(245,158,11,.15));border-color:var(--orange);color:var(--orange);font-weight:700}
.tab.i18n{background:linear-gradient(135deg,rgba(66,133,244,.3),rgba(0,229,255,.15));border-color:var(--blue);color:var(--blue);font-weight:700}
.section{display:none;animation:fadeIn .3s}
.section.active{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}
table{width:100%;border-collapse:collapse;font-size:13px;margin-top:8px}
th,td{padding:8px 10px;text-align:left;border-bottom:1px solid var(--border);vertical-align:top}
th{background:var(--card2);color:var(--muted);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px}
tr:hover{background:rgba(255,255,255,0.03)}
td.mono{font-family:'Roboto Mono',monospace;font-size:12px}
.gold{color:var(--gold)}.cyan{color:var(--cyan)}.green{color:var(--green)}
.pink{color:var(--pink)}.purple{color:var(--purple)}.red{color:var(--red)}
.orange{color:var(--orange)}.blue{color:var(--blue)}.yellow{color:var(--yellow)}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.grid-3{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
@media(max-width:700px){.grid-2,.grid-3{grid-template-columns:1fr}}
.info-box{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;margin:10px 0}
.info-box .label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.info-box .val{font-size:15px;font-weight:600;margin-top:4px}
.hash-box{background:linear-gradient(135deg,#001a1f,#000);border:2px solid var(--cyan);border-radius:14px;padding:16px;margin:12px 0}
.hash-box .label{font-family:'Roboto Mono',monospace;font-size:10px;color:var(--cyan);font-weight:700;letter-spacing:2px;text-transform:uppercase;margin-bottom:8px}
.hash-box .hash{font-family:'Roboto Mono',monospace;font-size:13px;font-weight:700;color:var(--gold);word-break:break-all;line-height:1.6}
.cts-badge{background:linear-gradient(135deg,#2d2400,#1a1500);border:3px solid var(--yellow);border-radius:16px;padding:20px;text-align:center;margin:12px 0;box-shadow:0 0 40px rgba(247,234,72,.4)}
.cts-badge .title{font-size:1.4rem;font-weight:900;color:var(--yellow);letter-spacing:6px;text-transform:uppercase}
.cts-badge .sub{font-family:'Roboto Mono',monospace;font-size:.7rem;color:#2effb0;letter-spacing:3px;margin-top:6px;font-weight:700}
footer{text-align:center;font-size:12px;color:var(--muted);margin-top:30px;padding-top:16px;border-top:1px solid var(--border)}
.spinner{display:inline-block;width:16px;height:16px;border:2px solid var(--border);border-top-color:var(--cyan);border-radius:50%;animation:spin 1s linear infinite;margin-right:8px;vertical-align:middle}
@keyframes spin{to{transform:rotate(360deg)}}
::-webkit-scrollbar{width:8px;height:8px}
::-webkit-scrollbar-track{background:var(--card2)}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:4px}
.refresh-btn{background:var(--cyan);color:#0a0f17;border:none;padding:6px 14px;border-radius:8px;cursor:pointer;font-weight:600;font-size:12px;margin-top:6px}
.refresh-btn:hover{background:#00b8cc}
.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-weight:600;font-size:12px;transition:.2s}
.btn-primary{background:var(--cyan);color:#0a0f17}
.btn-primary:hover{background:#00b8cc}
.btn-danger{background:var(--red);color:#fff}
.btn-success{background:var(--green);color:#fff}
.btn-warning{background:var(--yellow);color:#0a0f17}
.btn-purple{background:var(--purple);color:#fff}
/* CHAT */
.chat-box{background:var(--card2);border:1px solid var(--border);border-radius:14px;padding:16px;height:500px;display:flex;flex-direction:column}
.chat-messages{flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:10px}
.chat-msg{max-width:80%;padding:10px 14px;border-radius:14px;font-size:13px;line-height:1.5;word-wrap:break-word}
.chat-msg.user{align-self:flex-end;background:linear-gradient(135deg,#00e5ff,#4285f4);color:#0a0f17;font-weight:500}
.chat-msg.bot{align-self:flex-start;background:var(--card);border:1px solid var(--border);color:var(--text)}
.chat-input{display:flex;gap:8px;margin-top:12px}
.chat-input input{flex:1;padding:10px 14px;border-radius:10px;border:1px solid var(--border);background:var(--card);color:var(--text);font-size:13px}
.chat-input input:focus{outline:none;border-color:var(--cyan)}
.chat-input button{padding:10px 20px;border-radius:10px;background:var(--cyan);color:#0a0f17;font-weight:700;cursor:pointer;border:none}
/* EXPORT */
.export-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:16px 0}
.export-card{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:20px;text-align:center;cursor:pointer;transition:.2s}
.export-card:hover{transform:translateY(-3px);border-color:var(--cyan)}
.export-card i{font-size:2.5rem;margin-bottom:10px;display:block}
.export-card .label{font-weight:700;font-size:14px;color:#fff}
.export-card .desc{font-size:11px;color:var(--muted);margin-top:4px}
/* CRYPTO */
.crypto-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin:16px 0}
.crypto-card{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:14px;display:flex;justify-content:space-between;align-items:center}
.crypto-card .sym{font-weight:700;color:var(--gold);font-size:15px}
.crypto-card .price{font-family:'Roboto Mono',monospace;font-size:14px;color:#fff}
.crypto-card .change{font-size:12px;font-weight:600}
.crypto-card .change.up{color:var(--green)}
.crypto-card .change.down{color:var(--red)}
/* I18N */
.lang-btn{padding:6px 14px;border-radius:20px;background:var(--card2);border:1px solid var(--border);cursor:pointer;font-size:12px;margin-right:6px;color:var(--text)}
.lang-btn.active{background:var(--blue);border-color:var(--blue);color:#fff;font-weight:700}
/* DOC VAULT */
.vault-item{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;margin:8px 0;display:flex;align-items:center;gap:12px}
.vault-item .icon{width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,#00e5ff,#a855f7);display:flex;align-items:center;justify-content:center;color:#fff;font-size:18px}
.vault-item .info{flex:1}
.vault-item .name{font-weight:700;color:#fff;font-size:13px}
.vault-item .meta{font-size:11px;color:var(--muted);margin-top:2px}
.vault-item .lock{color:var(--green);font-size:12px}
/* NOTIFICATION */
.notif-item{background:var(--card2);border-left:4px solid var(--cyan);border-radius:8px;padding:12px;margin:8px 0;display:flex;gap:12px;align-items:flex-start}
.notif-item.warning{border-left-color:var(--yellow)}
.notif-item.danger{border-left-color:var(--red)}
.notif-item.success{border-left-color:var(--green)}
.notif-item .icon{font-size:20px;flex-shrink:0}
.notif-item .msg{flex:1;font-size:12px;line-height:1.5}
.notif-item .time{font-size:10px;color:var(--muted);margin-top:4px}
/* NETWORK MONITOR */
.monitor-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}
.monitor-item{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:14px;text-align:center}
.monitor-item .value{font-size:26px;font-weight:900;font-family:'Roboto Mono',monospace;margin:6px 0}
.monitor-item .label{font-size:11px;color:var(--muted);text-transform:uppercase}
.monitor-item .status{font-size:11px;font-weight:700;margin-top:4px}
.monitor-item .status.online{color:var(--green)}
.monitor-item .status.warning{color:var(--yellow)}
.monitor-item .status.offline{color:var(--red)}
/* CHART */
.chart-container{background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:16px;height:320px;position:relative}
/* MAP */
.map-container{height:600px;border-radius:12px;overflow:hidden;border:2px solid var(--cyan);margin:12px 0;position:relative}
#earthMap{width:100%;height:100%}
.leaflet-container{background:#0a0f17 !important;font-family:'Roboto',sans-serif !important}
.leaflet-popup-content-wrapper{background:#1e293b !important;color:#e8eaed !important;border:1px solid #00e5ff !important;border-radius:10px !important}
.leaflet-popup-content{margin:12px 14px !important;font-size:12px !important;line-height:1.6 !important;min-width:220px}
.map-legend{background:var(--card2);border:1px solid var(--border);border-radius:10px;padding:12px;margin-top:12px;font-size:12px}
.map-legend .item{display:inline-flex;align-items:center;gap:6px;margin:4px 10px 4px 0}
.map-legend .dot{width:12px;height:12px;border-radius:50%;border:2px solid #fff}
.gran-stat{background:linear-gradient(135deg,rgba(52,211,153,.1),rgba(16,185,129,.05));border:1px solid rgba(52,211,153,.4)}
.gran-stat::before{background:linear-gradient(90deg,#34d399,#fbbf24,#ffd700)}
.tag{display:inline-block;background:var(--card2);border:1px solid var(--border);border-radius:20px;padding:4px 12px;margin:3px;font-size:11px}
</style>
</head>
<body>
<div class="container">

<header>
  <div>
    <h1>🌏 SGAE 2.0 MASTER v39 · ULTIMATE EDITION</h1>
    <div class="sub">Pemilik: <strong class="gold">MUHAMAD SAZWAN BIN ISMAIL</strong> · IC: <span class="mono">961022-02-5739</span></div>
    <div class="sub">MSI: <span class="gold mono">MSI-2026-07734</span> · CMC: <span class="gold mono">CMC-REF-2026-MSI-003</span></div>
    <div class="badges">
      <span class="badge gold">👑 Sovereign</span>
      <span class="badge green">🌱 GRAN 24 Lot</span>
      <span class="badge cyan">🗺️ Peta Bumi</span>
      <span class="badge blue">🌊 Gelombang</span>
      <span class="badge purple">🛰️ 6 Satelit</span>
      <span class="badge pink">👨‍👩‍👧‍👦 Family 7</span>
      <span class="badge orange">💎 39 Modul</span>
    </div>
  </div>
  <div class="status-box">
    <div id="lastUpdate">Memuatkan...</div>
    <div id="apiStatus"><span class="spinner"></span> Menyambung ke API...</div>
    <div style="margin-top:6px">
      <button class="refresh-btn" onclick="fetchData(true)"><i class="fas fa-sync"></i> Refresh</button>
    </div>
  </div>
</header>

<div class="kpi-grid" id="kpiGrid"></div>

<div class="tabs">
  <div class="tab active" data-tab="identiti">👤 Identiti</div>
  <div class="tab" data-tab="keluarga">👨‍👩‍👧‍👦 Keluarga</div>
  <div class="tab" data-tab="gran">🌱 GRAN</div>
  <div class="tab" data-tab="peta">🗺️ Peta Bumi</div>
  <div class="tab" data-tab="gelombang">🌊 Gelombang</div>
  <div class="tab" data-tab="gran_chart">📊 Chart</div>
  <div class="tab" data-tab="satellite_orbit">🛰️ Satelit</div>
  <div class="tab" data-tab="weather">🌦️ Cuaca</div>
  <div class="tab" data-tab="gran_docs">📜 Docs</div>
  <div class="tab" data-tab="globe3d">🌐 3D Globe</div>
  <div class="tab chat" data-tab="chat">🤖 AI Chat</div>
  <div class="tab export" data-tab="export">📥 Export</div>
  <div class="tab crypto" data-tab="crypto">₿ Crypto</div>
  <div class="tab i18n" data-tab="i18n">🌐 i18n</div>
  <div class="tab" data-tab="vault">🔐 Vault</div>
  <div class="tab" data-tab="notifications">🔔 Notif</div>
  <div class="tab" data-tab="monitor">📡 Monitor</div>
  <div class="tab" data-tab="api">🔌 API</div>
  <div class="tab" data-tab="google">🔵 Google</div>
  <div class="tab" data-tab="myipo">📜 MyIPO</div>
  <div class="tab" data-tab="sijil">🎖️ Sijil</div>
  <div class="tab" data-tab="negara">🌍 Negara</div>
  <div class="tab" data-tab="raw">📝 Raw</div>
</div>

<!-- SECTIONS -->
<div class="section active" id="identiti"><div class="card"><h2>👤 Identiti Berdaulat</h2><div id="identitiContent"></div></div></div>
<div class="section" id="keluarga"><div class="card"><h2>👨‍👩‍👧‍👦 Salasilah Keluarga</h2><div id="keluargaContent"></div></div></div>
<div class="section" id="gran"><div class="card"><h2>🌱 GRAN Tanah (12 Lot)</h2><div id="granTanahContent"></div></div><div class="card"><h2>🌍 GRAN Global (12 Lot)</h2><div id="granGlobalContent"></div></div><div class="card"><h2>💰 Ringkasan GRAN</h2><div id="granSummaryContent"></div></div></div>
<div class="section" id="peta"><div class="card"><h2>🗺️ Peta Bumi Interaktif</h2><div class="map-container"><div id="earthMap"></div></div><div class="map-legend"><strong>🔵 Legenda:</strong><br><span class="item"><span class="dot" style="background:#34d399"></span> GRAN Tanah</span><span class="item"><span class="dot" style="background:#fbbf24"></span> GRAN Global</span><span class="item"><span class="dot" style="background:#3b82f6"></span> Office</span><span class="item"><span class="dot" style="background:#f59e0b"></span> Data Center</span><span class="item"><span class="dot" style="background:#06b6d4"></span> PoP</span><span class="item"><span class="dot" style="background:#38bdf8"></span> Sat Ground</span><span class="item"><span class="dot" style="background:#ec4899;width:16px;height:16px"></span> Rumah Keluarga</span></div></div></div>
<div class="section" id="gelombang"><div class="card"><h2>🌊 Data Gelombang Laut</h2><div id="gelombangContent"></div></div></div>
<div class="section" id="gran_chart"><div class="card"><h2>📊 GRAN Tanah Chart</h2><div class="chart-container"><canvas id="chartTanah"></canvas></div></div><div class="card"><h2>📊 GRAN Global Chart</h2><div class="chart-container"><canvas id="chartGlobal"></canvas></div></div><div class="card"><h2>📈 Timeline Pertumbuhan</h2><div class="chart-container"><canvas id="chartTimeline"></canvas></div></div></div>
<div class="section" id="satellite_orbit"><div class="card"><h2>🛰️ SGAE-SAT Constellation</h2><div id="satContent"></div></div><div class="card"><h2>📡 Orbit Visualization</h2><div id="orbitViz"></div></div></div>
<div class="section" id="weather"><div class="card"><h2>🌦️ Cuaca Masa Nyata</h2><div id="weatherContent"></div></div></div>
<div class="section" id="gran_docs"><div class="card"><h2>📜 Hak Milik Tanah</h2><div id="granDocsContent"></div></div></div>
<div class="section" id="globe3d"><div class="card"><h2>🌐 3D Earth Globe</h2><div class="map-container" style="height:700px;background:#000"><div id="globeContainer" style="width:100%;height:100%"></div></div></div></div>

<!-- 1. AI CHAT -->
<div class="section" id="chat">
  <div class="card">
    <h2>🤖 SGAE AI Chat Assistant</h2>
    <div class="chat-box">
      <div class="chat-messages" id="chatMessages">
        <div class="chat-msg bot">👋 Selamat datang! Saya AI berdaulat SGAE 2.0. Tanya saya tentang GRAN, keluarga, aset, atau mana-mana data sistem.</div>
      </div>
      <div class="chat-input">
        <input type="text" id="chatInput" placeholder="Taip soalan..." onkeypress="if(event.key==='Enter')sendChat()">
        <button onclick="sendChat()">📤 Hantar</button>
      </div>
      <div style="margin-top:10px;font-size:11px;color:var(--muted)">
        💡 Cuba: <span class="tag" onclick="quickAsk('Berapa nilai GRAN Tanah?')" style="cursor:pointer">Nilai GRAN?</span>
        <span class="tag" onclick="quickAsk('Senaraikan keluarga saya')" style="cursor:pointer">Keluarga?</span>
        <span class="tag" onclick="quickAsk('Apa itu MSI-2026-07734?')" style="cursor:pointer">MSI?</span>
      </div>
    </div>
  </div>
</div>

<!-- 2. EXPORT -->
<div class="section" id="export">
  <div class="card">
    <h2>📥 Export Data · 4 Format</h2>
    <div class="export-grid">
      <div class="export-card" onclick="exportData('pdf')"><i class="fas fa-file-pdf" style="color:#dc2626"></i><div class="label">PDF Report</div><div class="desc">Laporan lengkap</div></div>
      <div class="export-card" onclick="exportData('excel')"><i class="fas fa-file-excel" style="color:#16a34a"></i><div class="label">Excel</div><div class="desc">Spreadsheet .xlsx</div></div>
      <div class="export-card" onclick="exportData('csv')"><i class="fas fa-file-csv" style="color:#0891b2"></i><div class="label">CSV</div><div class="desc">Comma-separated</div></div>
      <div class="export-card" onclick="exportData('json')"><i class="fas fa-file-code" style="color:#fbbf24"></i><div class="label">JSON</div><div class="desc">Struktur penuh</div></div>
    </div>
    <h3>📊 Pilih Kategori Export</h3>
    <div id="exportOptions"></div>
  </div>
</div>

<!-- 3. CRYPTO LIVE -->
<div class="section" id="crypto">
  <div class="card">
    <h2>₿ Crypto Live Dashboard</h2>
    <div class="kpi-grid" id="cryptoKPI"></div>
    <div class="crypto-grid" id="cryptoGrid"></div>
    <h3>📊 24h Chart</h3>
    <div class="chart-container"><canvas id="cryptoChart"></canvas></div>
  </div>
</div>

<!-- 4. I18N -->
<div class="section" id="i18n">
  <div class="card">
    <h2>🌐 Multi-Language · BM / EN / 中文</h2>
    <div style="margin:12px 0">
      <button class="lang-btn active" onclick="changeLang('ms')">🇲🇾 Bahasa Melayu</button>
      <button class="lang-btn" onclick="changeLang('en')">🇬🇧 English</button>
      <button class="lang-btn" onclick="changeLang('zh')">🇨🇳 中文</button>
    </div>
    <div id="i18nContent"></div>
  </div>
</div>

<!-- 5. VAULT -->
<div class="section" id="vault">
  <div class="card">
    <h2>🔐 Document Vault · Encrypted</h2>
    <div class="kpi-grid">
      <div class="kpi"><div class="label">Total Dokumen</div><div class="value cyan">17</div></div>
      <div class="kpi"><div class="label">Encrypted</div><div class="value green">100%</div></div>
      <div class="kpi"><div class="label">AES-256-GCM</div><div class="value gold">Active</div></div>
      <div class="kpi"><div class="label">Last Access</div><div class="value purple" style="font-size:13px">Just now</div></div>
    </div>
    <div id="vaultContent"></div>
  </div>
</div>

<!-- 6. NOTIFICATIONS -->
<div class="section" id="notifications">
  <div class="card">
    <h2>🔔 Notification Center</h2>
    <div class="kpi-grid">
      <div class="kpi"><div class="label">Total</div><div class="value cyan" id="notifCount">0</div></div>
      <div class="kpi"><div class="label">Success</div><div class="value green" id="notifSuccess">0</div></div>
      <div class="kpi"><div class="label">Warning</div><div class="value yellow" id="notifWarn">0</div></div>
      <div class="kpi"><div class="label">Alert</div><div class="value red" id="notifDanger">0</div></div>
    </div>
    <div id="notifContent"></div>
  </div>
</div>

<!-- 7. NETWORK MONITOR -->
<div class="section" id="monitor">
  <div class="card">
    <h2>📡 Network & Server Monitor</h2>
    <div class="monitor-grid" id="monitorGrid"></div>
    <h3>📈 Latency Chart (Live)</h3>
    <div class="chart-container"><canvas id="monitorChart"></canvas></div>
  </div>
</div>

<div class="section" id="api"><div class="card"><h2>🔌 42 API Endpoints</h2><div id="apiContent"></div></div></div>
<div class="section" id="google"><div class="card"><h2>🔵 17 Google Services</h2><div id="googleContent"></div></div></div>
<div class="section" id="myipo"><div class="card"><h2>📜 MyIPO Portfolio</h2><div id="myipoContent"></div></div></div>
<div class="section" id="sijil"><div class="card"><h2>🎖️ Sijil Global</h2><div id="sijilContent"></div></div></div>
<div class="section" id="negara"><div class="card"><h2>🌍 205 Negara</h2><div id="negaraContent"></div></div></div>
<div class="section" id="raw"><div class="card"><h2>📝 Raw Data</h2><pre id="rawContent" style="background:var(--card2);padding:16px;border-radius:10px;overflow:auto;font-size:11px;max-height:600px;font-family:monospace"></pre></div></div>

<footer>
  SGAE 2.0 MASTER v39 ULTIMATE · © 2026 MUHAMAD SAZWAN BIN ISMAIL · IC: 961022-02-5739<br>
  🏠 F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia · MSI-2026-07734 · CMC-REF-2026-MSI-003
</footer>
</div>

<script>
// ================= DATA =================
const API_BASE = 'http://localhost:8000';
const API_ENDPOINT = API_BASE + '/all';

const GRAN_TANAH = [
  {id:'GRAN-MSI-KDH-7734',flag:'🇲🇾',state:'Kedah',name:'Sazwan Digital Valley (HQ)',area:'2.5 Ha',value:'RM 13,100,000',tenure:'Freehold',lat:5.6944,lng:100.4827,type:'Industrial Tech Park',title:'HS(D) 7734/2024'},
  {id:'GRAN-MSI-KDH-7735',flag:'🇲🇾',state:'Kedah',name:'SGAE Data Center',area:'2.0 Ha',value:'RM 4,500,000',tenure:'Freehold',lat:5.6470,lng:100.4874,type:'Data Center',title:'HS(D) 7735/2024'},
  {id:'GRAN-MSI-KDH-7736',flag:'🇲🇾',state:'Kedah',name:'SGAE R&D Center',area:'1.0 Ha',value:'RM 1,000,000',tenure:'Freehold',lat:5.3700,lng:100.5600,type:'R&D',title:'HS(D) 7736/2024'},
  {id:'GRAN-MSI-KUL-7737',flag:'🇲🇾',state:'Kuala Lumpur',name:'KL Office Tower',area:'0.8 Ha',value:'RM 42,000,000',tenure:'Freehold',lat:3.1390,lng:101.6869,type:'Office Tower',title:'HS(D) 7737/2024'},
  {id:'GRAN-MSI-PNG-7738',flag:'🇲🇾',state:'Penang',name:'Penang Tech Hub',area:'1.2 Ha',value:'RM 18,500,000',tenure:'Leasehold',lat:5.4141,lng:100.3288,type:'Tech Hub',title:'HS(D) 7738/2024'},
  {id:'GRAN-MSI-JHR-7739',flag:'🇲🇾',state:'Johor',name:'JB Data Center',area:'3.0 Ha',value:'RM 22,000,000',tenure:'Freehold',lat:1.4927,lng:103.7414,type:'Data Center',title:'HS(D) 7739/2024'},
  {id:'GRAN-MSI-SG-7740',flag:'🇸🇬',state:'Marina Bay',name:'SG Financial Hub',area:'0.5 Ha',value:'RM 85,000,000',tenure:'Leasehold 99y',lat:1.2830,lng:103.8607,type:'Financial Hub',title:'SLA-2024-7740'},
  {id:'GRAN-MSI-US-7741',flag:'🇺🇸',state:'Silicon Valley',name:'SV Innovation Center',area:'1.5 Ha',value:'RM 62,000,000',tenure:'Freehold',lat:37.4419,lng:-122.1430,type:'Innovation',title:'DEED-2024-7741'},
  {id:'GRAN-MSI-AE-7742',flag:'🇦🇪',state:'Dubai',name:'Dubai Blockchain Hub',area:'1.2 Ha',value:'RM 24,000,000',tenure:'Freehold',lat:25.0805,lng:55.1403,type:'Blockchain',title:'DLD-7742'},
  {id:'GRAN-MSI-JP-7743',flag:'🇯🇵',state:'Tokyo',name:'Tokyo Cyber Defense',area:'0.8 Ha',value:'RM 38,000,000',tenure:'Freehold',lat:35.6762,lng:139.6503,type:'Cyber Defense',title:'TR-7743'},
  {id:'GRAN-MSI-UK-7744',flag:'🇬🇧',state:'London',name:'London FinTech Hub',area:'0.6 Ha',value:'RM 42,000,000',tenure:'Leasehold 999y',lat:51.5054,lng:-0.0235,type:'FinTech Hub',title:'HM-LR-7744'},
  {id:'GRAN-MSI-CH-7745',flag:'🇨🇭',state:'Zurich',name:'Zurich Quantum Center',area:'0.7 Ha',value:'RM 32,000,000',tenure:'Freehold',lat:47.3769,lng:8.5417,type:'Quantum Center',title:'CHE-7745'}
];

const GRAN_GLOBAL = [
  {id:'GRAN-GLB-SG-8801',flag:'🇸🇬',country:'Singapore',name:'SGAE APAC Hub',city:'Marina Bay',lat:1.2830,lng:103.8607,area:'0.4 Ha',value:'RM 147,000,000',tenure:'Leasehold 999y'},
  {id:'GRAN-GLB-US-4401',flag:'🇺🇸',country:'USA',name:'SGAE Silicon Valley',city:'Palo Alto',lat:37.4419,lng:-122.1430,area:'0.8 Ha',value:'RM 131,600,000',tenure:'Freehold'},
  {id:'GRAN-GLB-GB-3301',flag:'🇬🇧',country:'UK',name:'SGAE London FinTech',city:'Canary Wharf',lat:51.5054,lng:-0.0235,area:'0.6 Ha',value:'RM 105,000,000',tenure:'Leasehold 999y'},
  {id:'GRAN-GLB-AE-2201',flag:'🇦🇪',country:'UAE',name:'SGAE Middle East Hub',city:'Dubai Marina',lat:25.0805,lng:55.1403,area:'1.2 Ha',value:'RM 102,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-JP-1101',flag:'🇯🇵',country:'Japan',name:'SGAE Tokyo AI Lab',city:'Shibuya',lat:35.6762,lng:139.6503,area:'0.5 Ha',value:'RM 74,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-CH-9901',flag:'🇨🇭',country:'Switzerland',name:'SGAE Crypto Vault',city:'Zug',lat:47.1662,lng:8.5155,area:'0.3 Ha',value:'RM 63,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-AU-6601',flag:'🇦🇺',country:'Australia',name:'SGAE Sydney DC',city:'Sydney',lat:-33.9026,lng:151.1945,area:'1.5 Ha',value:'RM 74,000,000',tenure:'Freehold'},
  {id:'GRAN-GLB-EE-5501',flag:'🇪🇪',country:'Estonia',name:'SGAE e-Residency',city:'Tallinn',lat:59.4370,lng:24.7536,area:'0.2 Ha',value:'RM 21,000,000',tenure:'Digital Estate'},
  {id:'GRAN-GLB-SA-7701',flag:'🇸🇦',country:'Saudi',name:'SGAE NEOM Node',city:'NEOM',lat:28.0000,lng:35.0000,area:'38.7 Ha',value:'RM 148,000,000',tenure:'Leasehold 99y'},
  {id:'GRAN-GLB-MY-7734',flag:'🇲🇾',country:'Malaysia',name:'Sazwan Digital Valley',city:'Kedah',lat:5.6944,lng:100.4827,area:'2.5 Ha',value:'RM 13,100,000',tenure:'Freehold'},
  {id:'GRAN-GLB-MY-7735',flag:'🇲🇾',country:'Malaysia',name:'SGAE Data Center',city:'Kedah',lat:5.6470,lng:100.4874,area:'2.0 Ha',value:'RM 4,500,000',tenure:'Freehold'},
  {id:'GRAN-GLB-MY-7736',flag:'🇲🇾',country:'Malaysia',name:'SGAE R&D',city:'Kulim',lat:5.3700,lng:100.5600,area:'1.0 Ha',value:'RM 1,000,000',tenure:'Freehold'}
];

const SATELLITES = [
  {id:'SGAE-SAT-01',orbit:'GEO',alt:'35,786 km',band:'Ka',signal:96,type:'Communications',lat:0,lng:42.1},
  {id:'SGAE-SAT-02',orbit:'LEO',alt:'550 km',band:'X',signal:92,type:'Imaging',lat:5.6,lng:100.5},
  {id:'SGAE-SAT-03',orbit:'MEO',alt:'20,200 km',band:'Ku',signal:88,type:'Navigation',lat:0,lng:0},
  {id:'SGAE-SAT-04',orbit:'GEO',alt:'35,786 km',band:'Ka',signal:94,type:'SIGINT',lat:0,lng:118},
  {id:'SGAE-SAT-05',orbit:'LEO',alt:'480 km',band:'X',signal:90,type:'Imaging',lat:-10,lng:80},
  {id:'SGAE-SAT-06',orbit:'SSO',alt:'700 km',band:'L',signal:97,type:'IoT/M2M',lat:98,lng:0}
];

const WEATHER_DATA = [
  {city:'Sungai Petani, Kedah',flag:'🇲🇾',temp:32,desc:'Cerah Berawan',humid:65,wind:8,rain:5,icon:'fa-sun'},
  {city:'Kuala Lumpur',flag:'🇲🇾',temp:31,desc:'Hujan Petang',humid:78,wind:12,rain:45,icon:'fa-cloud-rain'},
  {city:'Penang',flag:'🇲🇾',temp:30,desc:'Cerah',humid:72,wind:10,rain:10,icon:'fa-sun'},
  {city:'Johor Bahru',flag:'🇲🇾',temp:29,desc:'Berawan',humid:80,wind:9,rain:30,icon:'fa-cloud'},
  {city:'Singapore',flag:'🇸🇬',temp:30,desc:'Hujan Ringan',humid:82,wind:11,rain:60,icon:'fa-cloud-rain'},
  {city:'Silicon Valley',flag:'🇺🇸',temp:18,desc:'Cerah',humid:55,wind:15,rain:0,icon:'fa-sun'},
  {city:'London',flag:'🇬🇧',temp:12,desc:'Mendung',humid:75,wind:18,rain:20,icon:'fa-cloud'},
  {city:'Dubai',flag:'🇦🇪',temp:38,desc:'Panas Kering',humid:40,wind:6,rain:0,icon:'fa-sun'},
  {city:'Tokyo',flag:'🇯🇵',temp:22,desc:'Cerah',humid:60,wind:11,rain:5,icon:'fa-sun'},
  {city:'Zurich',flag:'🇨🇭',temp:10,desc:'Sejuk Berawan',humid:70,wind:9,rain:15,icon:'fa-cloud'},
  {city:'Sydney',flag:'🇦🇺',temp:20,desc:'Cerah',humid:58,wind:20,rain:0,icon:'fa-sun'},
  {city:'Tallinn',flag:'🇪🇪',temp:8,desc:'Sejuk Hujan',humid:85,wind:14,rain:55,icon:'fa-cloud-rain'},
  {city:'NEOM',flag:'🇸🇦',temp:27,desc:'Cerah Kering',humid:35,wind:9,rain:0,icon:'fa-sun'}
];

const WAVE_DATA = [
  {n:'Kedah / Selat Melaka',swh:0.8,period:6.2,dir:'SW',temp:'29°C',wind:8},
  {n:'Port Klang',swh:1.2,period:6.8,dir:'WSW',temp:'29°C',wind:10},
  {n:'Singapore Strait',swh:1.5,period:7.1,dir:'W',temp:'30°C',wind:12},
  {n:'SF Bay',swh:2.4,period:9.8,dir:'WNW',temp:'15°C',wind:18},
  {n:'North Sea',swh:1.8,period:7.4,dir:'SW',temp:'12°C',wind:15},
  {n:'Persian Gulf',swh:0.6,period:5.2,dir:'NW',temp:'28°C',wind:6},
  {n:'Tokyo Bay',swh:1.4,period:7.8,dir:'SE',temp:'22°C',wind:11},
  {n:'Tasman Sea',swh:2.8,period:10.2,dir:'SE',temp:'20°C',wind:20},
  {n:'Baltic Sea',swh:1.1,period:6.0,dir:'SW',temp:'8°C',wind:14},
  {n:'Red Sea',swh:0.9,period:6.5,dir:'NW',temp:'27°C',wind:9}
];

const CRYPTO_DATA = [
  {sym:'BTC',name:'Bitcoin',price:64104.80,change:+2.34,holdings:'4,050 BTC',value:'RM 1,217,737,500'},
  {sym:'ETH',name:'Ethereum',price:1886.89,change:-0.65,holdings:'2,847 ETH',value:'RM 22,500,000'},
  {sym:'S256c',name:'SGAE Sovereign',price:42.80,change:+8.42,holdings:'12,847,291',value:'RM 2,428,932'},
  {sym:'USDT',name:'Tether',price:1.00,change:+0.01,holdings:'$2,847,192',value:'RM 12,847,192'},
  {sym:'USDC',name:'USD Coin',price:1.00,change:0.00,holdings:'$1,247,891',value:'RM 5,631,847'},
  {sym:'SOL',name:'Solana',price:142.30,change:+3.47,holdings:'48,291 SOL',value:'RM 30,283,472'},
  {sym:'ADA',name:'Cardano',price:0.42,change:-1.24,holdings:'847,291 ADA',value:'RM 1,567,847'},
  {sym:'DOT',name:'Polkadot',price:5.42,change:+0.87,holdings:'284,721 DOT',value:'RM 6,792,847'}
];

const I18N = {
  ms: { title:"Identiti Berdaulat", name:"Nama", ic:"No. KP", email:"E-mel", phone:"Telefon", address:"Alamat", welcome:"Selamat Datang", lang:"Bahasa" },
  en: { title:"Sovereign Identity", name:"Name", ic:"IC Number", email:"Email", phone:"Phone", address:"Address", welcome:"Welcome", lang:"Language" },
  zh: { title:"主权身份", name:"姓名", ic:"身份证号码", email:"电子邮件", phone:"电话", address:"地址", welcome:"欢迎", lang:"语言" }
};

const VAULT_DOCS = [
  {name:'Sijil Kelahiran',type:'PDF',size:'1.2 MB',encrypted:true},
  {name:'Kad Pengenalan',type:'JPG',size:'0.8 MB',encrypted:true},
  {name:'Passport Malaysia',type:'PDF',size:'2.4 MB',encrypted:true},
  {name:'SSM Company Cert',type:'PDF',size:'1.5 MB',encrypted:true},
  {name:'Tax ID (LHDN)',type:'PDF',size:'0.6 MB',encrypted:true},
  {name:'GRAN Title 7734-7745',type:'PDF',size:'12.3 MB',encrypted:true},
  {name:'Family Trust Deed',type:'PDF',size:'3.2 MB',encrypted:true},
  {name:'MyIPO Patents',type:'PDF',size:'8.4 MB',encrypted:true},
  {name:'Insurance Policies',type:'PDF',size:'4.2 MB',encrypted:true},
  {name:'Blockchain Proof',type:'JSON',size:'0.1 MB',encrypted:true}
];

const NOTIFICATIONS = [
  {type:'success',icon:'✅',msg:'API Connected · Data live dari http://localhost:8000',time:'Baru sahaja'},
  {type:'success',icon:'🌱',msg:'GRAN Tanah: 12 lot telah berjaya dimuatkan',time:'1 minit lalu'},
  {type:'warning',icon:'⚠️',msg:'GRAN-MSI-KDH-7735 akan tamat dalam 30 hari',time:'5 minit lalu'},
  {type:'success',icon:'🛰️',msg:'SGAE-SAT-06 signal 97% · Excellent',time:'10 minit lalu'},
  {type:'danger',icon:'🚨',msg:'2 attempt login gagal dikesan dari 103.x.x.x',time:'15 minit lalu'},
  {type:'success',icon:'💰',msg:'Portfolio IP nilai: RM 47,800,000',time:'30 minit lalu'},
  {type:'warning',icon:'🌊',msg:'Gelombang tinggi dikesan di Tasman Sea (2.8m)',time:'1 jam lalu'},
  {type:'success',icon:'🔐',msg:'SHA-256 fingerprint disahkan',time:'2 jam lalu'}
];

// ================= HELPERS =================
const $ = id => document.getElementById(id);
const esc = s => String(s ?? '').replace(/[<>&"]/g, c => ({'<':'&lt;','>':'&gt;','&':'&amp;','"':'&quot;'}[c]));
function table(headers, rows, classes = []) {
  let h = '<table><thead><tr>';
  headers.forEach(x => h += `<th>${x}</th>`);
  h += '</tr></thead><tbody>';
  rows.forEach(r => {
    h += '<tr>';
    r.forEach((c, i) => h += `<td class="${classes[i] || ''}">${c}</td>`);
    h += '</tr>';
  });
  h += '</tbody></table>';
  return h;
}
function kv(l, v, c = 'gold') { return `<div class="info-box"><div class="label">${l}</div><div class="val ${c}">${esc(v)}</div></div>`; }

// ================= RENDER CORE =================
function renderKPI() {
  const kpi = [
    { label: "💰 Portfolio IP", value: "RM 47.8 Juta", sub: "RVC Appraisers 2026", cls: "gold" },
    { label: "🌱 GRAN Tanah", value: "12 Lot", sub: "RM 284,600,000", cls: "green" },
    { label: "🌍 GRAN Global", value: "12 Lot", sub: "RM 884,200,000", cls: "orange" },
    { label: "👑 Sovereign", value: "MSI-2026-07734", sub: "L04 CTS", cls: "cyan" },
    { label: "👨‍👩‍👧‍👦 Keluarga", value: "7 Ahli", sub: "Ismail & Syarifah", cls: "pink" },
    { label: "🌐 205 Negara", value: "Kerjasama", sub: "Global", cls: "purple" },
    { label: "🛰️ Satelit", value: "6 Aktif", sub: "SGAE-SAT", cls: "blue" },
    { label: "🌊 Max SWH", value: "15.2 m", sub: "Southern Ocean", cls: "red" }
  ];
  $('kpiGrid').innerHTML = kpi.map(k => `<div class="kpi ${k.cls === 'green' ? 'gran-stat' : ''}"><div class="label">${k.label}</div><div class="value ${k.cls}">${k.value}</div><div class="sub">${k.sub}</div></div>`).join('');
}

function renderIdentiti() {
  const d = {nama_penuh:"MUHAMAD SAZWAN BIN ISMAIL",no_kad_pengenalan:"961022-02-5739",tarikh_lahir:"22.10.1996",umur:"29 tahun",tempat_lahir:"Sungai Petani, Kedah",ibu:"Syarifah Binti Ishak",bapa:"Ismail Bin Hamid",emel:"xxsazend12345@gmail.com",telefon:"+60162847180",alamat:"F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia",participant_id:"END-MYS-SAZWAN-96-0425",military_id:"MY-ATM-CYBER/7734",interpol_id:"IP-MY-7734-2026",peranan:"Technical Lead for AI Sovereignty",sha256:"32D8A53CC4C299E60424C0D0E96D3B06575D51",block:"847,995",msi:"MSI-2026-07734",cmc:"CMC-REF-2026-MSI-003",ssm:"202403378912"};
  const rows = [["Nama",d.nama_penuh,"gold"],["No. KP",d.no_kad_pengenalan,"cyan"],["Tarikh Lahir",d.tarikh_lahir,""],["Umur",d.umur,"gold"],["Tempat Lahir",d.tempat_lahir,""],["Ibu",d.ibu,"pink"],["Bapa",d.bapa,"cyan"],["E-mel",d.emel,"cyan"],["Telefon",d.telefon,"green"],["Alamat",d.alamat,"gold"],["Participant ID",d.participant_id,"cyan"],["Military ID",d.military_id,"yellow"],["INTERPOL ID",d.interpol_id,"cyan"],["Peranan",d.peranan,"gold"],["SSM",d.ssm,"blue"]];
  $('identitiContent').innerHTML = `
    <div class="cts-badge"><div class="title">L04 · COSMIC TOP SECRET</div><div class="sub">NATO/CTS-MY-7734</div></div>
    <div class="hash-box"><div class="label">🔐 SHA-256</div><div class="hash">${d.sha256}</div></div>
    <div class="grid-2">
      <div>${table(["Medan","Nilai"], rows, ["", "", ""])}</div>
      <div>
        <div class="info-box"><div class="label">Block</div><div class="val mono cyan">#${d.block}</div></div>
        <div class="info-box"><div class="label">MSI</div><div class="val gold">${d.msi}</div></div>
        <div class="info-box"><div class="label">CMC</div><div class="val gold">${d.cmc}</div></div>
      </div>
    </div>`;
}

function renderKeluarga() {
  const ahli = [
    { turutan: "Bapa", nama: "Ismail Bin Hamid", dob: "22.10.1966", umur: "59 tahun", jantina: "Lelaki" },
    { turutan: "Ibu", nama: "Syarifah Binti Ishak", dob: "10.11.1966", umur: "59 tahun", jantina: "Perempuan" },
    { turutan: "Kakak 1", nama: "Isma Husna Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "CEO", nama: "Muhamad Sazwan Bin Ismail", dob: "22.10.1996", umur: "29 tahun", jantina: "Lelaki" },
    { turutan: "Adik 3", nama: "Syabika Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "Adik 4", nama: "Amira Binti Ismail", dob: "—", umur: "—", jantina: "Perempuan" },
    { turutan: "Adik 5", nama: "Isma Azim Wafiq Bin Ismail", dob: "—", umur: "—", jantina: "Lelaki" }
  ];
  $('keluargaContent').innerHTML = `
    <div class="info-box"><div class="label">🏠 Alamat Rumah Keluarga</div><div class="val gold">F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah, Malaysia</div></div>
    <div class="hash-box"><div class="label">👨‍👩‍👧‍👦 FAMILY HASH</div><div class="hash">FAM32D8A53CC4C299E60424C0D0E96D3B06575</div></div>
    <h3>Senarai Ahli (7)</h3>
    ${table(["Turutan","Nama","DOB","Umur","Jantina"], ahli.map(a => [a.turutan, a.nama, a.dob, a.umur, a.jantina]), ["pink","pink","","gold","cyan"])}
    <div class="grid-3">
      ${kv("Level", "L04 COSMIC TOP SECRET", "yellow")}
      ${kv("Insurans", "RM 11,500,000", "gold")}
      ${kv("Trust", "RM 42,000,000", "green")}
      ${kv("Biometric", "FAM-BIO-7734", "pink")}
    </div>`;
}

function renderGran() {
  $('granTanahContent').innerHTML = table(["ID","Flag","Negeri","Nama","Luas","Nilai","Tenure","Jenis"], GRAN_TANAH.map(g => [g.id, g.flag, g.state, g.name, g.area, g.value, g.tenure, g.type]), ["mono","","green","gold","cyan","gold","",""]);
  $('granGlobalContent').innerHTML = table(["ID","Flag","Negara","Nama","Bandar","Luas","Nilai"], GRAN_GLOBAL.map(g => [g.id, g.flag, g.country, g.name, g.city, g.area, g.value]), ["mono","","orange","gold","","cyan","gold"]);
  const total = 284600000 + 884200000;
  $('granSummaryContent').innerHTML = `
    <div class="grid-3">
      ${kv("Total Nilai", "RM " + total.toLocaleString(), "gold")}
      ${kv("Total Lot", "24", "green")}
      ${kv("Negara", "13", "orange")}
      ${kv("Status", "LOCKED", "yellow")}
      ${kv("Blockchain", "#847,995", "cyan")}
      ${kv("SSM", "202403378912", "blue")}
    </div>`;
}

function renderGelombang() {
  let h = '<div class="grid-3">';
  WAVE_DATA.forEach(w => {
    const color = w.swh >= 2.5 ? '#ef4444' : w.swh >= 1.5 ? '#fbbf24' : '#34d399';
    h += `<div class="info-box"><div class="label">${w.n}</div><div class="val" style="color:${color}">${w.swh} m SWH</div><div style="font-size:11px;color:var(--muted);margin-top:6px">Period: ${w.period}s · ${w.dir} · ${w.temp} · Wind: ${w.wind} km/h</div></div>`;
  });
  h += '</div>';
  $('gelombangContent').innerHTML = h;
}

// ================= 1. AI CHAT =================
function sendChat() {
  const input = $('chatInput');
  const msg = input.value.trim();
  if (!msg) return;
  addChatMsg('user', msg);
  input.value = '';
  setTimeout(() => {
    const reply = getAIReply(msg.toLowerCase());
    addChatMsg('bot', reply);
  }, 500);
}
function quickAsk(q) { $('chatInput').value = q; sendChat(); }
function addChatMsg(type, text) {
  const div = document.createElement('div');
  div.className = `chat-msg ${type}`;
  div.innerHTML = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>').replace(/\n/g, '<br>');
  $('chatMessages').appendChild(div);
  $('chatMessages').scrollTop = $('chatMessages').scrollHeight;
}
function getAIReply(q) {
  if (q.includes('gran') || q.includes('tanah')) return `🌱 **GRAN Tanah**: 12 lot, nilai **RM 284,600,000**.\n\nLokasi: Kedah (3 lot), KL, Penang, Johor, Singapore, USA, UAE, Japan, UK, Switzerland.\n\nGRAN Global: 12 lot, **RM 884,200,000** di 12 negara.`;
  if (q.includes('keluarga') || q.includes('family')) return `👨‍👩‍👧‍👦 **Keluarga Ismail & Syarifah** — 7 ahli:\n• Bapa: Ismail Bin Hamid (59)\n• Ibu: Syarifah Binti Ishak (59)\n• Kakak 1: Isma Husna\n• CEO: Muhamad Sazwan (29)\n• Adik 3-5: Syabika, Amira, Isma Azim\n\n🏠 Alamat: F262 Kampung Pinang Tunggal, 08000 Sungai Petani, Kedah`;
  if (q.includes('msi') || q.includes('07734')) return `🔐 **MSI-2026-07734** adalah Master Sovereign Identity untuk Muhamad Sazwan Bin Ismail.\n\nSHA-256: \`32D8A53CC4C299E60424C0D0E96D3B06575D51\`\nBlockchain: Bitcoin Block #847,995\nCMC Ref: CMC-REF-2026-MSI-003`;
  if (q.includes('aset') || q.includes('portfolio')) return `💰 **Aset Portfolio**:\n• Portfolio IP: RM 47.8 Juta\n• Bitcoin: ₿ 4,050 BTC (≈ RM 1.2B)\n• GRAN Tanah: RM 284.6 Juta\n• GRAN Global: RM 884.2 Juta\n• Total: **RM 3.18 Bilion**`;
  if (q.includes('satelit') || q.includes('sat')) return `🛰️ **SGAE-SAT Constellation**: 6 satelit aktif\n• 2× GEO (35,786 km)\n• 2× LEO (480-550 km)\n• 1× MEO (20,200 km)\n• 1× SSO (700 km)\n\nAvg Signal: **93%** · Ground Stations: 6`;
  if (q.includes('negara') || q.includes('country')) return `🌍 **205 Negara** kerjasama global dengan 6 MoU aktif.\n\nAgreements: 321 · Value: $8.62M`;
  if (q.includes('api')) return `🔌 **42 API Endpoints** dalam 18 kumpulan.\n\nCalls 24h: 42,847 · WebSocket: 4\nLive: http://localhost:8000/all`;
  if (q.includes('cuaca') || q.includes('weather')) return `🌦️ **Cuaca masa nyata** di 13 lokasi GRAN.\n\nSuhu tertinggi: Dubai (38°C)\nSuhu terendah: Tallinn (8°C)\nMalaysia: 29-32°C`;
  if (q.includes('sijil') || q.includes('cert')) return `🎖️ **245 Sijil Global** dalam 16 kategori.\n\nUtama: Google ML, AWS AI/ML, CISSP, CEH, OSCP, PMP`;
  if (q.includes('hi') || q.includes('hello') || q.includes('hai')) return `👋 Hai! Saya AI SGAE 2.0. Tanya apa sahaja tentang GRAN, keluarga, aset, satelit, atau data sistem!`;
  return `🤖 Saya boleh bantu dengan:\n• GRAN (tanah & global)\n• Keluarga (7 ahli)\n• Aset (RM 3.18B)\n• Satelit (6 aktif)\n• MSI/CMC codes\n\nCuba tanya: "Berapa nilai GRAN?"`;
}

// ================= 2. EXPORT =================
function exportData(format) {
  const data = { identiti: { name: "MUHAMAD SAZWAN BIN ISMAIL", ic: "961022-02-5739" }, gran_tanah: GRAN_TANAH, gran_global: GRAN_GLOBAL, family: "7 ahli", wave_data: WAVE_DATA, crypto: CRYPTO_DATA };
  const ts = new Date().toISOString().slice(0,10);
  if (format === 'json') { downloadFile(JSON.stringify(data, null, 2), `SGAE_export_${ts}.json`, 'application/json'); }
  else if (format === 'csv') { let csv = 'Category,Name,Value\n'; GRAN_TANAH.forEach(g => csv += `GRAN Tanah,${g.name},${g.value}\n`); GRAN_GLOBAL.forEach(g => csv += `GRAN Global,${g.name},${g.value}\n`); downloadFile(csv, `SGAE_export_${ts}.csv`, 'text/csv'); }
  else if (format === 'excel') {
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(GRAN_TANAH), 'GRAN Tanah');
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(GRAN_GLOBAL), 'GRAN Global');
    XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet(CRYPTO_DATA), 'Crypto');
    XLSX.writeFile(wb, `SGAE_export_${ts}.xlsx`);
  } else if (format === 'pdf') {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF();
    doc.setFontSize(18); doc.text('SGAE 2.0 — Sovereign Report', 14, 20);
    doc.setFontSize(10); doc.text(`Owner: MUHAMAD SAZWAN BIN ISMAIL`, 14, 30); doc.text(`IC: 961022-02-5739 · MSI: MSI-2026-07734`, 14, 36);
    doc.autoTable({ startY: 45, head: [['GRAN','Nama','Nilai']], body: [...GRAN_TANAH.map(g => ['Tanah',g.name,g.value]), ...GRAN_GLOBAL.map(g => ['Global',g.name,g.value])], headStyles: { fillColor: [0,229,255] } });
    doc.save(`SGAE_export_${ts}.pdf`);
  }
}
function downloadFile(content, name, mime) {
  const blob = new Blob([content], { type: mime });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob); a.download = name; a.click();
}

// ================= 3. CRYPTO =================
let cryptoChartInst;
function renderCrypto() {
  const totalValue = 'RM 1,256,996,500';
  $('cryptoKPI').innerHTML = `
    <div class="kpi"><div class="label">Total Holdings</div><div class="value gold">${totalValue}</div></div>
    <div class="kpi"><div class="label">BTC</div><div class="value orange">₿ 4,050</div><div class="sub">RM 1.22B</div></div>
    <div class="kpi"><div class="label">S256c</div><div class="value cyan">12.8M</div><div class="sub">+8.42%</div></div>
    <div class="kpi"><div class="label">Coins</div><div class="value purple">8 Active</div></div>`;
  $('cryptoGrid').innerHTML = CRYPTO_DATA.map(c => `
    <div class="crypto-card">
      <div><div class="sym">${c.sym}</div><div style="font-size:11px;color:var(--muted)">${c.name}</div><div style="font-size:11px;color:var(--muted);margin-top:4px">${c.holdings}</div></div>
      <div style="text-align:right"><div class="price">$${c.price.toLocaleString()}</div><div class="change ${c.change >= 0 ? 'up' : 'down'}">${c.change >= 0 ? '▲' : '▼'} ${Math.abs(c.change).toFixed(2)}%</div><div style="font-size:10px;color:var(--muted)">${c.value}</div></div>
    </div>`).join('');
  if (cryptoChartInst) cryptoChartInst.destroy();
  const ctx = $('cryptoChart').getContext('2d');
  cryptoChartInst = new Chart(ctx, {
    type: 'line',
    data: {
      labels: Array.from({length:24}, (_,i) => `${i}h`),
      datasets: [
        { label: 'BTC', data: Array.from({length:24}, () => 63000 + Math.random()*2000), borderColor: '#f7931a', tension: 0.4 },
        { label: 'ETH', data: Array.from({length:24}, () => 1800 + Math.random()*150), borderColor: '#a855f7', tension: 0.4 },
        { label: 'S256c', data: Array.from({length:24}, () => 40 + Math.random()*5), borderColor: '#00e5ff', tension: 0.4 }
      ]
    },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= 4. I18N =================
let currentLang = 'ms';
function changeLang(lang) {
  currentLang = lang;
  document.querySelectorAll('.lang-btn').forEach(b => b.classList.toggle('active', b.textContent.includes(lang === 'ms' ? 'Melayu' : lang === 'en' ? 'English' : '中文')));
  const t = I18N[lang];
  $('i18nContent').innerHTML = `
    <div class="grid-2">
      <div>
        <div class="info-box"><div class="label">${t.title}</div><div class="val gold">MUHAMAD SAZWAN BIN ISMAIL</div></div>
        <div class="info-box"><div class="label">${t.ic}</div><div class="val cyan">961022-02-5739</div></div>
        <div class="info-box"><div class="label">${t.email}</div><div class="val cyan">xxsazend12345@gmail.com</div></div>
        <div class="info-box"><div class="label">${t.phone}</div><div class="val green">+60162847180</div></div>
        <div class="info-box"><div class="label">${t.address}</div><div class="val gold">F262 Kampung Pinang Tunggal, Sungai Petani, Kedah</div></div>
      </div>
      <div>
        <div class="info-box"><div class="label">${t.lang}</div><div class="val purple">${lang.toUpperCase()}</div></div>
        <div class="info-box"><div class="label">${t.welcome}</div><div class="val gold">👋 ${t.welcome}!</div></div>
      </div>
    </div>`;
}

// ================= 5. VAULT =================
function renderVault() {
  let h = '';
  VAULT_DOCS.forEach(d => {
    h += `<div class="vault-item">
      <div class="icon"><i class="fas fa-file-${d.type === 'PDF' ? 'pdf' : d.type === 'JPG' ? 'image' : 'code'}"></i></div>
      <div class="info"><div class="name">${d.name}</div><div class="meta">${d.type} · ${d.size} · AES-256-GCM</div></div>
      <div class="lock">🔐 ${d.encrypted ? 'LOCKED' : 'OPEN'}</div>
    </div>`;
  });
  $('vaultContent').innerHTML = h;
}

// ================= 6. NOTIFICATIONS =================
function renderNotifications() {
  const counts = { success: 0, warning: 0, danger: 0 };
  NOTIFICATIONS.forEach(n => { if (counts[n.type] !== undefined) counts[n.type]++; });
  $('notifCount').textContent = NOTIFICATIONS.length;
  $('notifSuccess').textContent = counts.success;
  $('notifWarn').textContent = counts.warning;
  $('notifDanger').textContent = counts.danger;
  $('notifContent').innerHTML = NOTIFICATIONS.map(n => `<div class="notif-item ${n.type}"><div class="icon">${n.icon}</div><div class="msg">${n.msg}<div class="time">${n.time}</div></div></div>`).join('');
}

// ================= 7. MONITOR =================
let monitorChartInst;
function renderMonitor() {
  const monitors = [
    { name: 'API Server', value: '42ms', status: 'online' },
    { name: 'Database', value: '12ms', status: 'online' },
    { name: 'Blockchain Node', value: '284ms', status: 'online' },
    { name: 'CDN (Global)', value: '18ms', status: 'online' },
    { name: 'Quantum Core', value: '4ms', status: 'online' },
    { name: 'AI Engine', value: '46ms', status: 'online' },
    { name: 'Satellite Link', value: '124ms', status: 'warning' },
    { name: 'Backup Server', value: '68ms', status: 'online' }
  ];
  $('monitorGrid').innerHTML = monitors.map(m => `<div class="monitor-item"><div class="label">${m.name}</div><div class="value ${m.status === 'online' ? 'green' : 'yellow'}">${m.value}</div><div class="status ${m.status}">● ${m.status.toUpperCase()}</div></div>`).join('');
  if (monitorChartInst) monitorChartInst.destroy();
  const ctx = $('monitorChart').getContext('2d');
  monitorChartInst = new Chart(ctx, {
    type: 'line',
    data: { labels: Array.from({length:30}, (_,i) => `${i*2}s`), datasets: [{ label: 'Latency (ms)', data: Array.from({length:30}, () => 30 + Math.random()*40), borderColor: '#00e5ff', backgroundColor: 'rgba(0,229,255,0.1)', fill: true, tension: 0.4 }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= 8. GRAN CHARTS =================
let chartTanahInst, chartGlobalInst, chartTimelineInst;
function renderGranCharts() {
  if (chartTanahInst) chartTanahInst.destroy();
  chartTanahInst = new Chart($('chartTanah').getContext('2d'), {
    type: 'bar',
    data: { labels: GRAN_TANAH.map(g => g.name.substring(0,20)), datasets: [{ label: 'Nilai (RM)', data: GRAN_TANAH.map(g => parseInt(g.value.replace(/[^0-9]/g,''))), backgroundColor: '#34d399' }] },
    options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8', font: { size: 10 } } } } }
  });
  if (chartGlobalInst) chartGlobalInst.destroy();
  chartGlobalInst = new Chart($('chartGlobal').getContext('2d'), {
    type: 'doughnut',
    data: { labels: GRAN_GLOBAL.map(g => g.country), datasets: [{ data: GRAN_GLOBAL.map(g => parseInt(g.value.replace(/[^0-9]/g,''))), backgroundColor: ['#00e5ff','#a855f7','#fbbf24','#ec4899','#34d399','#f7931a','#4285f4','#ef4444','#10b981','#6366f1','#8b5cf6','#14b8a6'] }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'right', labels: { color: '#e8eaed', font: { size: 10 } } } } }
  });
  if (chartTimelineInst) chartTimelineInst.destroy();
  chartTimelineInst = new Chart($('chartTimeline').getContext('2d'), {
    type: 'line',
    data: { labels: ['2024','2025','2026','2027','2028','2030'], datasets: [{ label: 'Nilai GRAN (RM)', data: [18600000, 142000000, 1168800000, 1420000000, 2280000000, 4800000000], borderColor: '#fbbf24', backgroundColor: 'rgba(251,191,36,0.2)', fill: true, tension: 0.4 }] },
    options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { labels: { color: '#e8eaed' } } }, scales: { x: { ticks: { color: '#94a3b8' } }, y: { ticks: { color: '#94a3b8' } } } }
  });
}

// ================= SATELIT =================
function renderSatellite() {
  $('satContent').innerHTML = table(["ID","Orbit","Altitud","Band","Signal","Jenis"], SATELLITES.map(s => [s.id, s.orbit, s.alt, s.band, s.signal + '%', s.type]), ["mono","cyan","gold","purple","green",""]);
  $('orbitViz').innerHTML = `<div style="height:400px;background:radial-gradient(circle at center,#0a1628,#000);border-radius:12px;position:relative;overflow:hidden">
    <div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:80px;height:80px;background:radial-gradient(circle,#3b82f6,#1e40af);border-radius:50%;box-shadow:0 0 40px #3b82f6"></div>
    ${[100,150,200,175].map((r,i) => `<div style="position:absolute;top:50%;left:50%;width:${r*2}px;height:${r*2}px;border:1px dashed ${['#00e5ff40','#a855f740','#fbbf2440','#ec489940'][i]};border-radius:50%;transform:translate(-50%,-50%)"></div>`).join('')}
    ${SATELLITES.map((s,i) => { const r = s.orbit === 'LEO' ? 100 : s.orbit === 'MEO' ? 150 : s.orbit === 'GEO' ? 200 : 175; const angle = (i * 60); const x = Math.cos(angle*Math.PI/180)*r; const y = Math.sin(angle*Math.PI/180)*r; return `<div style="position:absolute;top:calc(50% + ${y}px);left:calc(50% + ${x}px);width:10px;height:10px;background:${s.signal>=95?'#00e5ff':s.signal>=90?'#fbbf24':'#ef4444'};border-radius:50%;box-shadow:0 0 10px currentColor;margin:-5px 0 0 -5px"></div>`; }).join('')}
    <div style="position:absolute;top:20px;left:20px;font-size:11px;color:#94a3b8">🟦 Earth · 4 orbit layers</div>
  </div>`;
}

// ================= WEATHER =================
function renderWeather() {
  $('weatherContent').innerHTML = `<div class="grid-3">${WEATHER_DATA.map(w => `
    <div class="weather-card" style="background:var(--card2);border:1px solid var(--border);border-radius:12px;padding:14px">
      <div style="display:flex;align-items:center;gap:8px">
        <i class="fas ${w.icon}" style="font-size:1.5rem;color:${w.temp>=30?'#fbbf24':w.rain>=40?'#60a5fa':'#94a3b8'}"></i>
        <div style="flex:1"><div style="font-weight:700;color:#fff;font-size:13px">${w.flag} ${w.city}</div><div style="font-size:11px;color:var(--muted)">${w.desc}</div></div>
        <div style="font-size:24px;font-weight:900;color:var(--gold);font-family:monospace">${w.temp}°</div>
      </div>
      <div style="display:flex;justify-content:space-between;font-size:11px;color:var(--muted);margin-top:8px;padding-top:8px;border-top:1px solid var(--border)">💧 ${w.humid}% · 💨 ${w.wind}km/h · 🌧️ ${w.rain}mm</div>
    </div>`).join('')}</div>`;
}

// ================= DOCS =================
function renderGranDocs() {
  $('granDocsContent').innerHTML = GRAN_TANAH.map(d => `
    <div style="background:var(--card2);border:1px solid var(--border);border-left:4px solid var(--gold);border-radius:10px;padding:14px;margin:8px 0">
      <div style="font-weight:700;color:var(--gold);font-size:13px">${d.flag} ${d.title} — ${d.name}</div>
      <div style="font-size:11px;color:var(--muted);margin:4px 0">📍 ${d.state} · ${d.type} · ${d.area} · ${d.tenure}</div>
      <div style="font-size:11px;color:var(--muted)">💰 ${d.value}</div>
      <div style="display:inline-block;background:rgba(52,168,83,.15);color:#81c995;padding:2px 10px;border-radius:10px;font-size:10px;font-weight:600;margin-top:6px">✅ REGISTERED</div>
    </div>`).join('');
}

// ================= MAP =================
let earthMap;
function initMap() {
  if (earthMap) return;
  earthMap = L.map('earthMap', { center: [10, 60], zoom: 2, worldCopyJump: true, attributionControl: false });
  L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { maxZoom: 19, subdomains: 'abcd' }).addTo(earthMap);
  GRAN_TANAH.forEach(g => L.circleMarker([g.lat, g.lng], { radius: 7, color: '#34d399', fillColor: '#34d399', fillOpacity: .8, weight: 2 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#34d399">🌱 ${esc(g.name)}</strong><br>${g.flag} ${g.state}<br><b>${g.value}</b></div>`).addTo(earthMap));
  GRAN_GLOBAL.forEach(g => L.circleMarker([g.lat, g.lng], { radius: 6, color: '#fbbf24', fillColor: '#fbbf24', fillOpacity: .7, weight: 2 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#fbbf24">🌍 ${esc(g.name)}</strong><br>${g.flag} ${g.country}<br><b>${g.value}</b></div>`).addTo(earthMap));
  L.circleMarker([5.6470, 100.4874], { radius: 12, color: '#ec4899', fillColor: '#ec4899', fillOpacity: .9, weight: 3 }).bindPopup(`<div style="color:#e8eaed"><strong style="color:#ec4899">👨‍👩‍👧‍👦 Rumah Keluarga</strong><br>F262 Kg Pinang Tunggal</div>`).addTo(earthMap);
}

// ================= 3D GLOBE =================
let globeScene, globeCamera, globeRenderer, globeGroup, globeRotation = true, satOrbitGroup;
function init3DGlobe() {
  const container = $('globeContainer');
  if (!container || globeScene) return;
  const w = container.clientWidth, h = container.clientHeight;
  globeScene = new THREE.Scene();
  globeCamera = new THREE.PerspectiveCamera(45, w/h, 0.1, 1000);
  globeCamera.position.set(0, 0, 3.5);
  globeRenderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
  globeRenderer.setSize(w, h);
  container.innerHTML = '';
  container.appendChild(globeRenderer.domElement);
  const controls = new THREE.OrbitControls(globeCamera, globeRenderer.domElement);
  controls.enableDamping = true;
  globeScene.add(new THREE.AmbientLight(0x404060, 1));
  const dLight = new THREE.DirectionalLight(0xffffff, 1.2); dLight.position.set(5, 3, 5); globeScene.add(dLight);
  const pLight = new THREE.PointLight(0x00e5ff, 0.8); pLight.position.set(-3, -2, -3); globeScene.add(pLight);
  globeGroup = new THREE.Group(); globeScene.add(globeGroup);
  const earthGeo = new THREE.SphereGeometry(1, 64, 64);
  const tex = new THREE.TextureLoader().load('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg');
  globeGroup.add(new THREE.Mesh(earthGeo, new THREE.MeshPhongMaterial({ map: tex, emissive: 0x0a1a3f, emissiveIntensity: 0.2 })));
  const wire = new THREE.Mesh(new THREE.SphereGeometry(1.002, 32, 32), new THREE.MeshBasicMaterial({ color: 0x00e5ff, wireframe: true, transparent: true, opacity: 0.06 }));
  globeGroup.add(wire);
  const atmo = new THREE.Mesh(new THREE.SphereGeometry(1.05, 32, 32), new THREE.MeshBasicMaterial({ color: 0x00e5ff, transparent: true, opacity: 0.08, side: THREE.BackSide }));
  globeGroup.add(atmo);
  function toXYZ(lat, lng, r) {
    const phi = (90 - lat) * Math.PI / 180;
    const theta = (lng + 180) * Math.PI / 180;
    return new THREE.Vector3(-r * Math.sin(phi) * Math.cos(theta), r * Math.cos(phi), r * Math.sin(phi) * Math.sin(theta));
  }
  function addMarker(lat, lng, color, size) {
    const pos = toXYZ(lat, lng, 1.02);
    const m = new THREE.Mesh(new THREE.SphereGeometry(size, 8, 8), new THREE.MeshBasicMaterial({ color }));
    m.position.copy(pos); globeGroup.add(m);
    const glow = new THREE.Mesh(new THREE.SphereGeometry(size*1.8, 8, 8), new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.3 }));
    glow.position.copy(pos); globeGroup.add(glow);
  }
  GRAN_TANAH.forEach(g => addMarker(g.lat, g.lng, 0x34d399, 0.025));
  GRAN_GLOBAL.forEach(g => addMarker(g.lat, g.lng, 0xfbbf24, 0.02));
  addMarker(5.6470, 100.4874, 0xec4899, 0.035);
  satOrbitGroup = new THREE.Group(); globeScene.add(satOrbitGroup);
  const colors = { LEO: 0x00e5ff, MEO: 0xa855f7, GEO: 0xfbbf24, SSO: 0xec4899 };
  const radii = { LEO: 1.3, MEO: 1.6, GEO: 1.9, SSO: 1.75 };
  ['LEO','MEO','GEO','SSO'].forEach(ot => {
    const r = radii[ot];
    const pts = [];
    for (let i = 0; i <= 64; i++) { const a = (i/64) * Math.PI * 2; pts.push(new THREE.Vector3(r*Math.cos(a), 0, r*Math.sin(a))); }
    const line = new THREE.Line(new THREE.BufferGeometry().setFromPoints(pts), new THREE.LineBasicMaterial({ color: colors[ot], transparent: true, opacity: 0.4 }));
    if (ot === 'LEO') line.rotation.x = Math.PI / 6;
    if (ot === 'SSO') line.rotation.x = Math.PI / 2;
    satOrbitGroup.add(line);
  });
  const satMeshes = SATELLITES.map((s, i) => {
    const r = radii[s.orbit] || 1.3;
    const m = new THREE.Mesh(new THREE.SphereGeometry(0.018, 8, 8), new THREE.MeshBasicMaterial({ color: colors[s.orbit] }));
    m.userData = { r, speed: 0.3 + i * 0.05, angle: i * Math.PI / 3, orbit: s.orbit };
    satOrbitGroup.add(m); return m;
  });
  const clock = new THREE.Clock();
  function animate() {
    requestAnimationFrame(animate);
    if (globeRotation) globeGroup.rotation.y += 0.0015;
    satMeshes.forEach(sat => {
      sat.userData.angle += sat.userData.speed * 0.01;
      const a = sat.userData.angle, r = sat.userData.r;
      sat.position.set(r*Math.cos(a), 0, r*Math.sin(a));
      if (sat.userData.orbit === 'LEO') sat.position.applyAxisAngle(new THREE.Vector3(1,0,0), Math.PI/6);
      if (sat.userData.orbit === 'SSO') sat.position.applyAxisAngle(new THREE.Vector3(1,0,0), Math.PI/2);
    });
    satOrbitGroup.rotation.y += 0.0008;
    controls.update();
    globeRenderer.render(globeScene, globeCamera);
  }
  animate();
  window.addEventListener('resize', () => { const W = container.clientWidth, H = container.clientHeight; if (W && H) { globeCamera.aspect = W/H; globeCamera.updateProjectionMatrix(); globeRenderer.setSize(W, H); } });
}

// ================= MISC RENDER =================
function renderAPI() {
  const groups = [{n:'Ledger',c:5},{n:'AI/Python',c:2},{n:'Gemini',c:2},{n:'FPX',c:2},{n:'Satellite',c:2},{n:'Family',c:2},{n:'GRAN',c:2},{n:'MyIPO',c:7},{n:'WebSocket',c:4}];
  $('apiContent').innerHTML = `<div class="kpi-grid"><div class="kpi"><div class="label">Total</div><div class="value cyan">42</div></div><div class="kpi"><div class="label">Calls 24h</div><div class="value gold">42,847</div></div><div class="kpi"><div class="label">WebSocket</div><div class="value purple">4</div></div></div>` + groups.map(g => `<div class="info-box"><strong>${g.n}</strong> · ${g.c} en…
@Sazwanismail Sazwanismail self-assigned this Sep 23, 2026
@Sazwanismail Sazwanismail added documentation Improvements or additions to documentation Media Sosial media Windows hunter Projects personal Win Kemenangan labels Sep 23, 2026
@Sazwanismail Sazwanismail added Strategic Kecekapan semulajadi size:XXL This PR changes 1000+ lines, ignoring generated files size:L This PR changes 100-499 lines, ignoring generated files size:XL This PR changes 500-999 lines, ignoring generated files size:XS This PR changes 0-9 lines, ignoring generated files labels Sep 23, 2026
@codeant-ai

codeant-ai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR e772890 Sep 23, 2026 · 15:33 15:34

@codeant-ai

codeant-ai Bot commented Sep 23, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@changeset-bot

changeset-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e772890

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

This was linked to issues Sep 23, 2026
@Sazwanismail
Sazwanismail merged commit ce67639 into main Sep 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation Media Sosial media size:L This PR changes 100-499 lines, ignoring generated files size:XL This PR changes 500-999 lines, ignoring generated files size:XS This PR changes 0-9 lines, ignoring generated files size:XXL This PR changes 1000+ lines, ignoring generated files Strategic Kecekapan semulajadi Win Kemenangan Windows hunter Projects personal

Projects

Development

Successfully merging this pull request may close these issues.

docs.github.com/codespaces Comments language Profile Beta

1 participant