git / moonbite-network / templates/moon.html · raw

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"><meta name="theme-color" content="#0B0D12"><title>MoonBite — The Last Unowned Thing</title><meta name="description" content="{{ consensus.initial_subsidy_coins }} MBITE born every {{ consensus.block_time_min }} minutes. No premine, no presale, nobody to buy it from. You mine it, or it isn't yours."><link rel="icon" type="image/svg+xml" href="/static/moonbite-logo.svg"><link rel="stylesheet" href="/static/fonts/moonbite-fonts.css"><style>/* Doc 04: three roles. A heavy grotesque for display, a quiet sans for   reading, a monospace for anything that is a number.   Archivo Black and Inter are self-hosted from /static/fonts (latin subset,   OFL-licensed). They are deliberately not loaded from Google Fonts: /privacy   states the site loads nothing that phones home, and a webfont CDN sends   every visitor's IP to Google on every page load. Every figure that is   money, a hash, an address or a block height is monospace with tabular   figures — amounts that shift width as they update look untrustworthy. */:root{  --font-display:'Archivo Black','Helvetica Neue','Arial Black',sans-serif;  --font-body:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;  --font-data:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;}h1,h2,.big,.reveal .big,.balance-amount,.elapsed,.mort-big{  font-family:var(--font-display); font-weight:400; letter-spacing:-.02em;}.num,.mono,.addr,.cert .amt,.cl .v,.tot .v,.mcell .v,.odds .v,.loss .v,.count .v,.zero-band .v,.total .v,.vault-v,td.n,th.n{  font-family:var(--font-data); font-variant-numeric:tabular-nums;}* { margin:0; padding:0; box-sizing:border-box; }html { scroll-behavior:smooth; }body { background:#0B0D12; color:#F5F2EA;  font-family:var(--font-body);  overflow-x:hidden; -webkit-font-smoothing:antialiased; }::selection { background:#D9A441; color:#0B0D12; }a { -webkit-tap-highlight-color:transparent; }button { -webkit-tap-highlight-color:transparent; font-family:inherit; }#sky { position:fixed; inset:0; z-index:0; }.wrap { position:relative; z-index:1; max-width:520px; margin:0 auto; padding:0 18px; }@media (min-width:900px){ .wrap { max-width:980px; } }.kicker { letter-spacing:.3em; font-size:.64rem; color:#D9A441; text-transform:uppercase;  font-weight:800; }.num { font-variant-numeric:tabular-nums; }/* ------------------------------------------------------------------ HERO */.hero { min-height:100svh; display:flex; flex-direction:column; justify-content:center;  padding:2vh 0 3vh; text-align:center; position:relative; }.orb-wrap { position:relative; width:min(50vw,240px); aspect-ratio:1; margin:0 auto; }#orb { width:100%; height:100%; display:block; }.hero h1 { font-size:clamp(2.5rem,10vw,4.6rem); font-weight:800; line-height:1.02;  letter-spacing:-.02em; margin-top:1vh; }.hero h1 .g { color:#D9A441; }.hero .sub { color:#8A8580; font-size:clamp(.98rem,3.6vw,1.15rem); line-height:1.6;  margin:14px auto 0; max-width:420px; }.hero .sub b { color:#F5F2EA; font-weight:700; }/* live terminal card */.term { margin:18px auto 0; width:100%; max-width:440px; background:rgba(22,26,34,.82);  border:1px solid rgba(217,164,65,.22); border-radius:20px; padding:18px 18px 16px;  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);  box-shadow:0 20px 60px rgba(0,0,0,.5), inset 0 1px 0 rgba(245,242,234,.06);  text-align:left; }.term-top { display:flex; justify-content:space-between; align-items:center; }.live { display:flex; align-items:center; gap:7px; font-size:.66rem; font-weight:800;  letter-spacing:.22em; color:#2E9E6B; }.live i { width:7px; height:7px; border-radius:50%; background:#2E9E6B; display:inline-block;  animation:blip 1.8s infinite; }@keyframes blip { 0%,100%{opacity:1} 50%{opacity:.25} }.term-net { font-size:.66rem; letter-spacing:.18em; color:#8A8580; font-weight:700; }.term-grid { display:grid; grid-template-columns:1fr 1fr; gap:0 14px; margin-top:14px; }.tcell { padding:10px 0 8px; border-top:1px solid rgba(245,242,234,.07); }.tcell .v { font-size:clamp(1.25rem,5.4vw,1.6rem); font-weight:800; color:#F5F2EA; line-height:1.1; }.tcell .v .u { font-size:.62em; color:#D9A441; font-weight:800; }.tcell .k { font-size:.58rem; letter-spacing:.2em; color:#8A8580; text-transform:uppercase;  margin-top:4px; font-weight:700; }.supply { grid-column:1/-1; padding-top:12px; border-top:1px solid rgba(245,242,234,.07); }.supply-bar { height:7px; border-radius:4px; background:rgba(245,242,234,.08); overflow:hidden;  margin-top:8px; }.supply-fill { height:100%; width:0%; min-width:2px; border-radius:4px;  background:linear-gradient(90deg,#D9A441,#B8863B); transition:width 1s ease; }.supply-row { display:flex; justify-content:space-between; font-size:.62rem; color:#8A8580;  margin-top:6px; letter-spacing:.08em; }.supply-row b { color:#D9A441; }.hero-cta { margin:16px auto 0; display:flex; gap:12px; justify-content:center; }.btn { display:inline-flex; align-items:center; justify-content:center; gap:9px;  border:none; border-radius:10px; padding:16px 28px; font-weight:800; font-size:1rem;  cursor:pointer; text-decoration:none; transition:transform .15s ease; }.btn:active { transform:scale(.97); }.btn-gold { background:#D9A441; color:#0B0D12; box-shadow:0 10px 34px rgba(217,164,65,.28); }.btn-ghost { background:transparent; color:#F5F2EA; border:1px solid rgba(245,242,234,.22); }.hero-proof { margin:12px 0 0; font-size:.7rem; color:#8A8580; letter-spacing:.06em; }.scroll-cue { margin-top:26px; font-size:.6rem; letter-spacing:.28em;  color:#8A8580; display:flex; flex-direction:column; align-items:center; gap:7px; }.scroll-cue i { display:block; width:1px; height:26px;  background:linear-gradient(180deg, rgba(217,164,65,.7), rgba(217,164,65,0));  animation:cueDrop 2.1s ease-in-out infinite; }@keyframes cueDrop { 0%,100%{opacity:.35; transform:scaleY(.7)} 50%{opacity:1; transform:scaleY(1)} }@media (prefers-reduced-motion: reduce){ .scroll-cue i { animation:none; } }/* ------------------------------------------------------------- HALVING */.sec { padding:9vh 0 6vh; text-align:center; }.sec h2 { font-size:clamp(1.7rem,7vw,3rem); font-weight:800; line-height:1.1;  letter-spacing:-.01em; margin-top:12px; }.sec .dim { color:#8A8580; font-size:.95rem; line-height:1.65; max-width:430px;  margin:12px auto 0; }.clock { display:flex; gap:10px; justify-content:center; margin-top:26px; }.cl { background:#161A22; border:1px solid rgba(217,164,65,.2); border-radius:10px;  min-width:72px; padding:14px 8px 11px; }.cl .v { font-size:clamp(1.6rem,7.5vw,2.4rem); font-weight:800; color:#D9A441; line-height:1; }.cl .k { font-size:.56rem; letter-spacing:.2em; color:#8A8580; text-transform:uppercase;  margin-top:6px; font-weight:700; }.halv-line { margin-top:20px; font-size:.95rem; color:#F5F2EA; }.halv-line b { color:#C8402F; }.tickerband { margin-top:30px; border-top:1px solid rgba(217,164,65,.14);  border-bottom:1px solid rgba(217,164,65,.14); padding:10px 0; overflow:hidden;  white-space:nowrap; font-size:.7rem; letter-spacing:.14em; color:#8A8580; }.tickerband span { display:inline-block; padding-left:100%;  animation:tick 28s linear infinite; }@keyframes tick { to { transform:translateX(-100%); } }.tickerband b { color:#D9A441; font-weight:800; }/* --------------------------------------------------------- CARD MAKER */.maker { background:#161A22; border:1px solid rgba(217,164,65,.2); border-radius:20px;  padding:22px 18px; margin-top:24px; text-align:center;  box-shadow:0 24px 70px rgba(0,0,0,.45); }.maker-preview { width:100%; max-width:340px; margin:0 auto; border-radius:10px;  overflow:hidden; border:1px solid rgba(217,164,65,.28); display:none;  box-shadow:0 14px 44px rgba(0,0,0,.5); }.maker-preview.show { display:block; animation:pop .5s cubic-bezier(.2,1.5,.4,1); }@keyframes pop { from{transform:scale(.9);opacity:0} to{transform:scale(1);opacity:1} }.maker-preview canvas { width:100%; display:block; }.year-row { display:flex; gap:10px; justify-content:center; align-items:center;  margin:16px 0 6px; }.year-in { background:#0B0D12; border:1px solid rgba(217,164,65,.35); color:#F5F2EA;  font-size:1.35rem; font-weight:800; text-align:center; width:130px; padding:13px 10px;  border-radius:10px; outline:none; letter-spacing:.06em; }.year-in:focus { border-color:#D9A441; box-shadow:0 0 30px rgba(217,164,65,.16); }.year-go { background:#D9A441; color:#0B0D12; border:none; border-radius:10px;  padding:13px 20px; font-weight:800; font-size:.95rem; cursor:pointer; }.maker-actions { display:none; gap:10px; justify-content:center; margin-top:14px; flex-wrap:wrap; }.maker-actions.show { display:flex; }.mk-btn { background:transparent; border:1px solid rgba(217,164,65,.4); color:#D9A441;  border-radius:10px; padding:13px 18px; min-height:44px; font-weight:800; font-size:.82rem;  cursor:pointer; }.mk-btn.solid { background:#D9A441; color:#0B0D12; border-color:#D9A441; }/* ------------------------------------------------------------ MANIFESTO */.rail { display:flex; gap:12px; overflow-x:auto; scroll-snap-type:x mandatory;  padding:22px 18px 8px; margin:0 -18px; -webkit-overflow-scrolling:touch;  scrollbar-width:none; }.rail::-webkit-scrollbar { display:none; }.rc { scroll-snap-align:center; flex:0 0 78%; max-width:330px; background:#161A22;  border:1px solid rgba(245,242,234,.1); border-radius:20px; padding:26px 22px;  text-align:left; min-height:170px; display:flex; flex-direction:column;  justify-content:space-between; }.rc .big { font-size:clamp(1.5rem,6vw,2rem); font-weight:800; line-height:1.15; }.rc .big s { color:rgba(245,242,234,.38); text-decoration-color:rgba(200,64,47,.85);  text-decoration-thickness:3px; }.rc .tag { font-size:.62rem; letter-spacing:.24em; color:#8A8580; text-transform:uppercase;  font-weight:800; margin-bottom:14px; }.rc.gold { background:linear-gradient(160deg,#D9A441,#B8863B); border:none; }.rc.gold .big { color:#0B0D12; }.rc.gold .tag { color:rgba(11,13,18,.6); }.rail-hint { font-size:.66rem; color:#8A8580; letter-spacing:.2em; margin-top:2px; }@media (min-width:900px){ .rail-hint { display:none; } .rc { flex:0 0 31%; } }/* -------------------------------------------------------------- WORLD */.world-card { background:#161A22; border:1px solid rgba(217,164,65,.2); border-radius:20px;  padding:22px 20px; margin-top:22px; display:flex; align-items:center; gap:16px;  text-align:left; text-decoration:none; }.world-card .fl { font-size:2rem; line-height:1; }.world-card .t { flex:1; }.world-card .t b { color:#F5F2EA; font-size:1.02rem; display:block; }.world-card .t span { color:#8A8580; font-size:.82rem; }.world-card .arr { color:#D9A441; font-weight:800; font-size:1.2rem; }/* --------------------------------------------------------- STICKY CTA */.dock { position:fixed; left:0; right:0; bottom:0; z-index:40; padding:10px 14px  calc(10px + env(safe-area-inset-bottom)); display:flex; gap:10px;  background:linear-gradient(180deg, rgba(11,13,18,0), rgba(11,13,18,.92) 40%);  pointer-events:none; opacity:0; transform:translateY(12px); transition:all .35s ease; }.dock.on { opacity:1; transform:none; pointer-events:auto; }.dock .btn { flex:1; padding:16px 10px; font-size:.95rem; border-radius:10px; }@media (min-width:900px){ .dock { display:none; } }.pad-dock { height:86px; }@media (min-width:900px){ .pad-dock { height:0; } }@media (prefers-reduced-motion: reduce) {  .live i, .tickerband span { animation:none; }  .maker-preview.show { animation:none; }}#mortCanvas { background:#0B0D12; }/* Doc 17: visible keyboard focus on every interactive element. */a:focus-visible, button:focus-visible, input:focus-visible,select:focus-visible, [tabindex]:focus-visible {  outline:2px solid #D9A441; outline-offset:3px; border-radius:6px;}</style></head><body><canvas id="sky"></canvas>{% include 'partials/nav.html' %}<div class="wrap">  <!-- ============================================================ HERO -->  <section class="hero">    <div class="orb-wrap"><canvas id="orb"></canvas></div>    <h1>The last<br><span class="g">unowned</span> thing.</h1>    <p class="sub"><b>{{ consensus.initial_subsidy_coins }} MBITE</b> are born every      <b>{{ consensus.block_time_min }} minutes</b>. There is no company, no presale,      and nobody to buy it from. You mine it, or it isn't yours.</p>    <div class="term">      <div class="term-top">        <div class="live"><i></i>LIVE CHAIN</div>        <div class="term-net">MOONBITE · POW</div>      </div>      <div class="term-grid">        <div class="tcell">          <div class="v num" id="tHeight">0</div>          <div class="k">Block height</div>        </div>        <div class="tcell">          <div class="v num">{{ consensus.current_reward_coins|int }}<span class="u"> MBITE</span></div>          <div class="k">Reward per block</div>        </div>        <div class="supply">          <div class="supply-row"><span>SUPPLY MINED</span><b class="num" id="tMined">0</b></div>          <div class="supply-bar"><div class="supply-fill" id="tFill"></div></div>          <div class="supply-row"><span class="num" id="tPct">0.000%</span><span>of {{ consensus.max_supply_label }}</span></div>        </div>      </div>    </div>    <div class="hero-cta">      <a class="btn btn-gold" href="/start" id="heroMine">Mine your first block</a>    </div>    <div class="hero-proof">No signup · no purchase · your CPU is the hardware</div>    <div class="scroll-cue">THE REWARD IS FALLING<i></i></div>  </section>  <!-- ================================================= NEW HERE (plain English) -->  <style>    .newhere{ max-width:520px; margin:0 auto; padding:6vh 0 2vh; }    @media (min-width:900px){ .newhere{ max-width:820px; } }    .nh-tag{ letter-spacing:.28em; font-size:.6rem; color:#D9A441; text-transform:uppercase;      font-weight:800; text-align:center; }    .nh-h{ font-family:var(--font-display); font-weight:400; letter-spacing:-.02em;      font-size:clamp(1.5rem,5.5vw,2.1rem); text-align:center; margin:10px 0 4px; line-height:1.1; }    .nh-lead{ color:#8A8580; text-align:center; font-size:clamp(.95rem,3.4vw,1.05rem);      line-height:1.6; max-width:440px; margin:0 auto 30px; }    .nh-grid{ display:grid; gap:14px; }    @media (min-width:760px){ .nh-grid{ grid-template-columns:repeat(3,1fr); gap:16px; } }    .nh-card{ border:1px solid rgba(245,242,234,.11); border-radius:12px; padding:22px 20px;      background:rgba(245,242,234,.02); }    .nh-n{ font-family:var(--font-data); font-size:.7rem; letter-spacing:.18em; color:#D9A441;      font-weight:700; }    .nh-q{ font-family:var(--font-display); font-weight:400; font-size:1.05rem; margin:8px 0 8px;      color:#F5F2EA; }    .nh-a{ color:#C9C4BA; font-size:.95rem; line-height:1.62; }    .nh-a b{ color:#F5F2EA; font-weight:600; }    .nh-honest{ margin-top:22px; border-left:2px solid #D9A441; padding:12px 0 12px 16px;      color:#8A8580; font-size:.88rem; line-height:1.6; max-width:600px; margin-left:auto; margin-right:auto; }    .nh-honest b{ color:#D9A441; font-weight:700; }    /* jargon tooltip */    .jt{ border-bottom:1px dotted rgba(217,164,65,.7); cursor:help; color:inherit; position:relative;      outline:none; }    .jt:focus-visible{ border-radius:2px; box-shadow:0 0 0 2px rgba(217,164,65,.5); }    .jt .jt-def{ position:absolute; left:50%; bottom:calc(100% + 8px); transform:translateX(-50%);      width:min(240px,72vw); background:#14161d; color:#C9C4BA; border:1px solid rgba(217,164,65,.35);      border-radius:8px; padding:10px 12px; font-size:.8rem; line-height:1.5; font-weight:400;      letter-spacing:normal; text-align:left; z-index:30; box-shadow:0 12px 30px rgba(0,0,0,.5);      opacity:0; visibility:hidden; transition:opacity .15s ease, transform .15s ease; pointer-events:none; }    .jt .jt-def::after{ content:''; position:absolute; top:100%; left:50%; transform:translateX(-50%);      border:6px solid transparent; border-top-color:#14161d; }    .jt:hover .jt-def, .jt:focus .jt-def, .jt.open .jt-def{ opacity:1; visibility:visible; }  </style>  <section class="newhere" id="newhere">    <div class="nh-tag">New here? · 60 seconds, plain English</div>    <h2 class="nh-h">What is this, in normal words</h2>    <p class="nh-lead">No crypto knowledge needed. Three questions, answered straight.</p>    <div class="nh-grid">      <div class="nh-card">        <div class="nh-n">01 — WHAT IT IS</div>        <div class="nh-q">Money you make with your own computer.</div>        <div class="nh-a">MoonBite is <b>digital cash</b> that isn't run by any bank or company.          New coins are created by ordinary computers doing math — a process called          <span class="jt" tabindex="0">mining<span class="jt-def">Your computer solves puzzles to help run the network. When it wins, it earns brand-new coins. No special hardware — a normal PC works.</span></span>.          Nobody printed them, nobody is selling them to you.</div>      </div>      <div class="nh-card">        <div class="nh-n">02 — WHAT YOU GET</div>        <div class="nh-q">Coins that land in your wallet.</div>        <div class="nh-a">When your computer helps run the network, <b>MBITE</b> coins appear in your          <span class="jt" tabindex="0">wallet<span class="jt-def">A free app that holds your coins and your secret recovery phrase. You own it — no account, no company can freeze it.</span></span>.          Early on there are more coins per win; over time that          <span class="jt" tabindex="0">amount is cut in half<span class="jt-def">A “halving.” The reward for mining drops by 50% at set intervals, so coins get scarcer over time — the same rule Bitcoin uses.</span></span>,          so getting in early means more.</div>      </div>      <div class="nh-card">        <div class="nh-n">03 — WHAT TO DO</div>        <div class="nh-q">Download one app. That's it.</div>        <div class="nh-a">Get the wallet, click <b>start mining</b>, and leave it running. Your computer's          spare power does the work and coins accumulate on their own. No sign-up,          no payment, no card. <a href="/start" style="color:#D9A441;">Start here →</a></div>      </div>    </div>    <p class="nh-honest"><b>Being honest:</b> MoonBite is brand new. It has <b>no cash price yet</b> and      no promise it ever will — you're here at the very beginning, which is the whole point and also      the risk. Never spend money you can't afford to lose, and never trust anyone who "sells" you MBITE.      You mine it, or it isn't yours.</p>  </section>  <!-- ========================================================= HALVING -->  <section class="sec">    <div class="kicker">THE REWARD ONLY GOES DOWN</div>    <h2>{{ consensus.initial_subsidy_coins }} becomes {{ consensus.initial_subsidy_coins // 2 }}.<br>It never comes back.</h2>    <div class="clock">      <div class="cl"><div class="v num" id="cD">—</div><div class="k">Days</div></div>      <div class="cl"><div class="v num" id="cH">—</div><div class="k">Hours</div></div>      <div class="cl"><div class="v num" id="cM">—</div><div class="k">Min</div></div>      <div class="cl"><div class="v num" id="cS">—</div><div class="k">Sec</div></div>    </div>    <div class="halv-line">Until block <b class="num">{{ '{:,}'.format(consensus.next_halving_height) }}</b>, when the reward is cut in half — forever.</div>    <p class="dim">Half of every MBITE that will ever exist is mined in this first era.      The people in it can never be joined, only remembered.</p>  </section>  <div class="tickerband"><span id="tickerText">    <b>{{ consensus.initial_subsidy_coins }} MBITE</b> per block &nbsp;·&nbsp; halving every    <b>{{ '{:,}'.format(consensus.halving_interval) }}</b> blocks &nbsp;·&nbsp; cap    <b>{{ consensus.max_supply_label }}</b> &nbsp;·&nbsp; final block ≈    <b>{{ consensus.final_block_year }}</b> &nbsp;·&nbsp; no premine &nbsp;·&nbsp; no presale    &nbsp;·&nbsp; CPU-mined RandomX &nbsp;·&nbsp;  </span></div>  <!-- ====================================================== CARD MAKER -->  <section class="sec">    <div class="kicker">THE CLOCK YOU'RE ACTUALLY ON</div>    <h2>How many halvings<br>will you live to see?</h2>    <p class="dim">The final MBITE block lands around <b style="color:#D9A441;">{{ consensus.final_block_year }}</b>.      Enter your birth year — get your card.</p>    <div class="maker">      <div class="maker-preview" id="mkPrev"><canvas id="mortCanvas" width="1080" height="1080"></canvas></div>      <div class="year-row">        <input class="year-in num" id="birthYear" type="number" inputmode="numeric"               min="1920" max="2026" placeholder="1998" aria-label="Birth year">        <button class="year-go" id="yearGo">→</button>      </div>      <div class="maker-actions" id="mkActions">        <button class="mk-btn solid" id="btnSave">Save card</button>        <button class="mk-btn" id="btnCopyMort">Copy text</button>        <button class="mk-btn" id="btnNative">Share</button>      </div>    </div>  </section>  <!-- ======================================================= MANIFESTO -->  <section class="sec" style="padding-bottom:2vh;">    <div class="kicker">WHY THIS EXISTS</div>    <h2>Everything else<br>got claimed.</h2>  </section>  <div class="rail" id="rail">    <div class="rc"><div class="tag">01</div><div class="big"><s>Land</s> — owned.</div></div>    <div class="rc"><div class="tag">02</div><div class="big"><s>Music</s> — licensed.</div></div>    <div class="rc"><div class="tag">03</div><div class="big"><s>Your face</s> — scraped.</div></div>    <div class="rc"><div class="tag">04</div><div class="big"><s>Your data</s> — sold.</div></div>    <div class="rc gold"><div class="tag">05 · ONE THING LEFT</div>      <div class="big">You mine it,<br>or it isn't yours.</div></div>  </div>  <div class="rail-hint" style="text-align:center;">SWIPE →</div>  <!-- =========================================================== WORLD -->  <section class="sec" style="padding-top:6vh;">    <a class="world-card" href="/world-cup">      <div class="fl"></div>      <div class="t">        <b id="wcLine">The Mining World Cup</b>        <span id="wcSub">Every block has a country. Claim your nation's number.</span>      </div>      <div class="arr">→</div>    </a>    <div class="hero-cta" style="margin-top:26px;">      <a class="btn btn-gold" href="/start">Start mining</a>      <a class="btn btn-ghost" href="/calculator">Run your numbers</a>    </div>  </section>  <div class="pad-dock"></div></div>{% include 'partials/footer.html' %}<!-- mobile thumb dock --><div class="dock" id="dock">  <a class="btn btn-gold" href="/start">Mine your first block</a></div><script nonce="{{ csp_nonce }}">(function () {  'use strict';  var CONS = {    reward: {{ consensus.initial_subsidy_coins }},    blockSec: {{ consensus.block_time_sec }},    halving: {{ consensus.halving_interval }},    cap: {{ consensus.max_supply_coins }},    nextHalving: {{ consensus.next_halving_height }},    launch: {{ consensus.launch_year }},    lastYear: {{ consensus.final_block_year }},    halvingYears: {{ consensus.halving_years }}  };  function $(id){ return document.getElementById(id); }  function fmt(n){ return Math.round(n).toLocaleString('en-US'); }  /* Doc 11: block heights are never thousands-separated — only amounts are. */  function ht(n){ return String(Math.round(n||0)); }  /* clipboard.writeText rejects on insecure contexts, denied permission and     some browsers; an uncaught rejection surfaces as a console error. */  function copyText(s){    try {      if (navigator.clipboard && navigator.clipboard.writeText)        return navigator.clipboard.writeText(s).catch(function(){});    } catch(e){}    return null;  }  if (!CanvasRenderingContext2D.prototype.roundRect) {    CanvasRenderingContext2D.prototype.roundRect = function (x,y,w,h,r) {      r = Math.min(r, w/2, h/2);      this.moveTo(x+r,y); this.arcTo(x+w,y,x+w,y+h,r); this.arcTo(x+w,y+h,x,y+h,r);      this.arcTo(x,y+h,x,y,r); this.arcTo(x,y,x+w,y,r); this.closePath(); return this;    };  }  /* ------------------------------------------------------------- sky */  var sky = $('sky'), sg = sky.getContext('2d'), W, H, stars = [];  var DPR = Math.min(window.devicePixelRatio || 1, 2);  var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;  function resize(){    W = innerWidth; H = innerHeight;    sky.width = W*DPR; sky.height = H*DPR;    sky.style.width = W+'px'; sky.style.height = H+'px';    sg.setTransform(DPR,0,0,DPR,0,0);    stars = [];    for (var i=0,n=Math.min(160,(W*H/9000)|0); i<n; i++)      stars.push({x:Math.random()*W, y:Math.random()*H, r:Math.random()*1.1+.25,                  tw:Math.random()*6.28});  }  addEventListener('resize', resize); resize();  var st = 0;  (function skyLoop(){    st += reduced ? 0 : .008;    sg.fillStyle = '#0B0D12'; sg.fillRect(0,0,W,H);    for (var i=0;i<stars.length;i++){      var s = stars[i];      sg.globalAlpha = .18 + .32*Math.abs(Math.sin(st+s.tw));      sg.fillStyle = '#F5F2EA';      sg.beginPath(); sg.arc(s.x,s.y,s.r,0,6.2832); sg.fill();    }    sg.globalAlpha = 1;    requestAnimationFrame(skyLoop);  })();  /* ------------------------------------------------- orb: the living mark */  var orb = $('orb'), og = orb.getContext('2d');  var minedFrac = 0, orbT = 0;  /* Doc 01: the mark is a single closed path, never assembled from two     overlapping circles, and never carries a stroke, gradient or shadow.     This is the canonical path from the standard, drawn verbatim via Path2D     so the geometry cannot drift from spec.     Doc 06: the bite deepens by one increment as blocks are found, so mined     supply scales the cut rather than any decorative ring. */  var MARK = new Path2D('M 13.99 -99.02 A 100 100 0 1 0 99.02 -13.99 ' +                        'A 62.00 62.00 0 0 1 13.99 -99.02 Z');  function drawOrb(){    var S = orb.clientWidth;    if (S > 0 && orb.width !== S*DPR){ orb.width = S*DPR; orb.height = S*DPR; }    og.setTransform(DPR,0,0,DPR,0,0);    og.clearRect(0,0,S,S);    var k = (S*0.78)/280;                 /* viewBox -140..140 */    og.save();    og.translate(S/2, S/2 + S*0.012);    og.scale(k, k);    og.fillStyle = '#F5F2EA';    og.fill(MARK);    /* struck bars: 2.55R wide, 0.13R thick, at -0.34R and +0.18R */    og.fillStyle = '#D9A441';    og.beginPath(); og.roundRect(-127.5, -34, 255, 13, 6.5); og.fill();    og.beginPath(); og.roundRect(-127.5,  18, 255, 13, 6.5); og.fill();    og.restore();    requestAnimationFrame(drawOrb);  }  requestAnimationFrame(drawOrb);  /* --------------------------------------------------------- live chain */  var chainH = 0;  function paintChain(){    $('tHeight').textContent = ht(chainH);    var mined = Math.min(chainH, CONS.halving) * CONS.reward;    $('tMined').textContent = fmt(mined) + ' MBITE';    var pct = 100 * mined / CONS.cap;    $('tPct').textContent = pct.toFixed(3) + '%';    $('tFill').style.width = Math.max(.4, pct) + '%';    minedFrac = mined / CONS.cap;  }  paintChain();  function pollChain(){    fetch('/api/blockchain/info').then(function(r){return r.json();}).then(function(j){      var h = j.height || j.blocks || 0;      if (h >= 0){ chainH = h; paintChain(); }    }).catch(function(){});  }  pollChain(); setInterval(pollChain, 15000);  /* ------------------------------------------------------ halving clock */  var t0 = Date.now();  function clock(){    var blocksLeft = Math.max(0, CONS.nextHalving - chainH);    var secs = blocksLeft*CONS.blockSec - (Date.now()-t0)/1000;    if (secs < 0) secs = 0;    var d = Math.floor(secs/86400), h = Math.floor(secs%86400/3600),        m = Math.floor(secs%3600/60), s = Math.floor(secs%60);    $('cD').textContent = fmt(d);    $('cH').textContent = (h<10?'0':'')+h;    $('cM').textContent = (m<10?'0':'')+m;    $('cS').textContent = (s<10?'0':'')+s;  }  clock(); setInterval(clock, 1000);  /* ------------------------------------------------- world cup teaser */  fetch('/api/worldcup').then(function(r){return r.json();}).then(function(j){    if (j.total_miners > 0){      $('wcLine').textContent = j.total_countries + ' countries · ' +        j.total_miners + ' miners enlisted';      $('wcSub').textContent = 'The Mining World Cup — claim your nation’s next number.';    }  }).catch(function(){});  /* --------------------------------------------------- mortality maker */  var mort = null;  function computeMort(y){    var death = y + 80;    var halvings = Math.max(0, Math.floor((death - CONS.launch)/CONS.halvingYears));    var seesLast = death >= CONS.lastYear;    var gens = Math.max(1, Math.ceil((CONS.lastYear - death)/28));    return { year:y, halvings:halvings, seesLast:seesLast, gens:gens };  }  function drawCard(m){    var cv = $('mortCanvas'), x = cv.getContext('2d');    var bg = x.createLinearGradient(0,0,0,1080);    bg.addColorStop(0,'#0B0D12'); bg.addColorStop(1,'#161A22');    x.fillStyle = bg; x.fillRect(0,0,1080,1080);    for (var i=0;i<80;i++){      x.globalAlpha = .12+Math.random()*.45; x.fillStyle = '#F5F2EA';      x.beginPath(); x.arc(Math.random()*1080,Math.random()*1080,Math.random()*1.8+.4,0,6.2832); x.fill();    }    x.globalAlpha = 1; x.textAlign = 'center';    x.strokeStyle = 'rgba(217,164,65,.4)'; x.lineWidth = 4;    x.strokeRect(36,36,1008,1008);    /* the mark */    x.beginPath(); x.arc(540,225,105,0,6.2832); x.fillStyle = '#F5F2EA'; x.fill();    x.beginPath(); x.arc(598,146,82,0,6.2832); x.fillStyle = '#0B0D12'; x.fill();    x.fillStyle = '#D9A441';    x.beginPath(); x.roundRect(388,183,304,13,6.5); x.fill();    x.beginPath(); x.roundRect(400,240,280,13,6.5); x.fill();    x.fillStyle = '#8A8580'; x.font = '700 32px Arial';    x.fillText('MY MOONBITE MORTALITY CLOCK', 540, 420);    x.fillStyle = '#D9A441'; x.font = '800 122px Arial';    x.fillText(m.halvings + ' HALVING' + (m.halvings===1?'':'S'), 540, 565);    x.fillStyle = '#F5F2EA'; x.font = '400 40px Arial';    x.fillText('is all I get to see.', 540, 630);    x.font = '700 42px Arial'; x.fillStyle = '#C8402F';    if (m.seesLast) {      x.fillText('I might witness the final block.', 540, 745);    } else {      x.fillText('The final block lands ≈ ' + CONS.lastYear + '.', 540, 725);      x.fillStyle = '#F5F2EA'; x.font = '400 36px Arial';      x.fillText(m.gens + ' generation' + (m.gens>1?'s':'') + ' after me.', 540, 785);    }    x.fillStyle = '#F5F2EA'; x.font = 'italic 38px Arial';    x.fillText('What you mine now outlives you.', 540, 880);    x.fillStyle = '#D9A441'; x.font = '700 32px Arial';    x.fillText('moonbite.org', 540, 955);    x.fillStyle = 'rgba(245,242,234,.32)'; x.font = '400 20px Arial';    x.fillText('MBITE has no market value and is not an investment.', 540, 1005);  }  function makeCard(){    var y = parseInt($('birthYear').value, 10);    if (!(y>=1920 && y<=2026)) return;    mort = computeMort(y);    drawCard(mort);    $('mkPrev').classList.add('show');    $('mkActions').classList.add('show');    $('mkPrev').scrollIntoView({behavior:'smooth', block:'center'});  }  $('yearGo').addEventListener('click', makeCard);  $('birthYear').addEventListener('keydown', function(e){ if(e.key==='Enter') makeCard(); });  $('birthYear').addEventListener('input', function(){    if (this.value.length === 4) makeCard();  });  function shareText(){    if (!mort) return '';    return 'I will live to see ' + mort.halvings + ' MoonBite halvings. The final block lands ~' +      CONS.lastYear + ' — after me. What you mine now outlives you. moonbite.org';  }  $('btnSave').addEventListener('click', function(){    var a = document.createElement('a');    a.download = 'moonbite-mortality.png';    a.href = $('mortCanvas').toDataURL('image/png'); a.click();  });  $('btnCopyMort').addEventListener('click', function(){    copyText(shareText());    this.textContent = ' Copied'; var b = this;    setTimeout(function(){ b.textContent = 'Copy text'; }, 1800);  });  $('btnNative').addEventListener('click', function(){    if (navigator.share) navigator.share({ text: shareText() }).catch(function(){});    else { copyText(shareText()); }  });  /* ------------------------------------------------------ thumb dock */  var hero = document.querySelector('.hero');  var io = new IntersectionObserver(function(es){    $('dock').classList.toggle('on', !es[0].isIntersecting);  }, { threshold: .12 });  io.observe(hero);})();</script><script nonce="{{ csp_nonce }}">(function(){  document.querySelectorAll('.newhere .jt').forEach(function(el){    el.addEventListener('click', function(e){      e.stopPropagation();      var was = el.classList.contains('open');      document.querySelectorAll('.newhere .jt.open').forEach(function(o){o.classList.remove('open');});      if(!was) el.classList.add('open');    });  });  document.addEventListener('click', function(){    document.querySelectorAll('.newhere .jt.open').forEach(function(o){o.classList.remove('open');});  });})();</script></body></html>