/* global React */
const { useState, useEffect, useRef } = React;

const JOIN_URL = "https://stake.com/?offer=sustain&c=dmjlVbU4";
const KICK_URL = "https://kick.com/sustain";

/* ── icons ── */
const Ico = {
  home:    (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M3 9.5L12 3l9 6.5V20a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9.5z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/><path d="M9 21V12h6v9" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/></svg>),
  rewards: (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><circle cx="12" cy="8" r="4" stroke="currentColor" strokeWidth="1.8"/><path d="M8 8H4l2 8h12l2-8h-4M9 16l1 5M15 16l-1 5" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/></svg>),
  bonuses: (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M20 12v8H4v-8M2 7h20v5H2zM12 22V7M12 7S10 2 7 4s3 3 5 3 5-1 5-3-5 1-5 3z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/></svg>),
  link:    (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/></svg>),
  kick:    ({style, ...rest})=>(<img src="assets/kick-logo.png" alt="Kick" style={{width:20,height:20,objectFit:'contain',...style}} {...rest}/>),
  x:      (p)=>(<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.746l7.73-8.835L2.483 2.25h6.945l4.262 5.635zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>),
  chev:    (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  trophy:  (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M8 21h8M12 17v4M7 4h10v4a5 5 0 0 1-10 0V4z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/><path d="M7 6H4a1 1 0 0 0-1 1c0 2.5 1.5 4 4 4M17 6h3a1 1 0 0 1 1 1c0 2.5-1.5 4-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/></svg>),
  moon:    (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/></svg>),
  store:   (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M4 9h16l-1 11a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1L4 9z" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"/><path d="M9 9V6a3 3 0 0 1 6 0v3" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/></svg>),
  check:   (p)=>(<svg viewBox="0 0 24 24" fill="none" {...p}><path d="M5 13l4 4L19 7" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/></svg>),
  play:    (p)=>(<svg viewBox="0 0 24 24" fill="currentColor" {...p}><path d="M8 5v14l11-7z"/></svg>),
};

/* ── falling emotes ── */
function FallingLogos({ enabled, density }) {
  const ref = useRef(null);
  useEffect(() => {
    const canvas = ref.current; if (!canvas) return;
    const ctx = canvas.getContext("2d");
    let raf, W, H, parts = [], running = true;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    let imgReady = false, imgEl = null;
    function resize(){ W=canvas.width=canvas.offsetWidth*devicePixelRatio; H=canvas.height=canvas.offsetHeight*devicePixelRatio; }
    function make(n){ parts = Array.from({length:n}, ()=>spawn(true)); }
    function spawn(any){
      const s=(30+Math.random()*42)*devicePixelRatio;
      return { x:Math.random()*W, y:any?Math.random()*H:-s, size:s,
        vy:(14+Math.random()*22)*devicePixelRatio/60, rot:(Math.random()-.5)*.5,
        vr:(Math.random()-.5)*.006, op:.12+Math.random()*.28,
        sway:Math.random()*Math.PI*2, swaySp:.004+Math.random()*.01,
        swayAmt:(6+Math.random()*18)*devicePixelRatio };
    }
    function frame(){
      if(!running) return;
      ctx.clearRect(0,0,W,H);
      if(imgReady && imgEl){
        for(const p of parts){
          p.y+=p.vy; p.rot+=p.vr; p.sway+=p.swaySp;
          const x=p.x+Math.sin(p.sway)*p.swayAmt;
          if(p.y-p.size>H) Object.assign(p,spawn(false));
          ctx.save(); ctx.globalAlpha=p.op;
          ctx.translate(x,p.y); ctx.rotate(p.rot);
          ctx.drawImage(imgEl,-p.size/2,-p.size/2,p.size,p.size);
          ctx.restore();
        }
      }
      raf=requestAnimationFrame(frame);
    }
    resize();
    const cnt=reduce?0:Math.round((density||1)*(W/devicePixelRatio>700?22:12));
    if(enabled&&!reduce) make(cnt);
    frame();
    const img=new Image(); img.onload=()=>{imgEl=img;imgReady=true;}; img.src="assets/sustain-emote.png";
    const onR=()=>{resize();make(enabled&&!reduce?Math.round((density||1)*(W/devicePixelRatio>700?22:12)):0);};
    window.addEventListener("resize",onR);
    return ()=>{running=false;cancelAnimationFrame(raf);window.removeEventListener("resize",onR);};
  },[enabled,density]);
  return <canvas id="fall-canvas" ref={ref}></canvas>;
}

/* ── background ── */
function Background({ falling, density }) {
  return (
    <div className="bg-root">
      <div className="bg-aurora"></div>
      <div className="bg-dots"></div>
      <FallingLogos enabled={falling} density={density} />
    </div>
  );
}

/* ── sidebar ── */
const NAV_ITEMS = [
  { id:"home",    label:"Home",    icon:"home",    href:"index.html#home" },
  { id:"rewards", label:"Rewards", icon:"rewards", href:"index.html#rewards" },
  { id:"bonuses", label:"Bonuses", icon:"bonuses", href:"index.html#bonuses" },
  { id:"leaderboard", label:"Leaderboard", icon:"trophy", href:"leaderboard.html", badge:"Live", badgeColor:"live" },
  { id:"moon", label:"MOON", icon:"moon", href:"moon.html", badge:"New", badgeColor:"new" },
  { id:"store", label:"Store", icon:"store", href:"#", badge:"Soon", badgeColor:"soon", disabled:true },
];
const SOCIAL_ITEMS = [
  { id:"kick", label:"Watch Live", icon:"kick", url:KICK_URL },
  { id:"x",    label:"X / Twitter", icon:"x",    url:"https://x.com/SustainOnX" },
  { id:"stake",label:"Join Stake", icon:"link", url:JOIN_URL },
];

function Sidebar({ page = "index" }) {
  const [active, setActive] = useState(page === "leaderboard" ? "leaderboard" : "home");
  // In-page items smooth-scroll; items pointing to another .html navigate normally.
  const handleNav = (e, item) => {
    if (item.disabled) { e.preventDefault(); return; }   // ítems "Soon": no navegan
    const [file, hash] = item.href.split("#");
    const onThisPage =
      (page === "index" && file === "index.html") ||
      (page === "leaderboard" && file === "leaderboard.html");
    if (!onThisPage) return;              // let the link redirect to the other page
    e.preventDefault();
    setActive(item.id);
    const el = hash ? document.getElementById(hash) : null;
    if (el) el.scrollIntoView({ behavior:"smooth", block:"start" });
    else window.scrollTo({ top:0, behavior:"smooth" });
  };
  return (
    <aside className="sidebar">
      <a className="sb-logo" href="index.html">
        <img src="assets/sustain-rounded.png" alt="Sustain" />
        <div className="sb-logo-name">
          <span className="top">SUSTAIN</span>
          <span className="vip">REWARDS</span>
        </div>
      </a>

      <nav className="sb-nav">
        {NAV_ITEMS.map(item => {
          const Icon = Ico[item.icon];
          return (
            <a key={item.id} href={item.href}
              className={"sb-item"+(active===item.id?" active":"")+(item.disabled?" is-soon":"")}
              onClick={(e)=>handleNav(e,item)}>
              <Icon />{item.label}
              {item.badge && <span className={"sb-badge "+(item.badgeColor||"")}>{item.badge}</span>}
            </a>
          );
        })}
      </nav>

      <div className="sb-socials">
        <div className="sb-section-label">Socials <span>·</span></div>
        {SOCIAL_ITEMS.map(item => {
          const Icon = Ico[item.icon];
          return (
            <a key={item.id} className="sb-social" href={item.url} target="_blank" rel="noopener">
              <Icon />{item.label}
            </a>
          );
        })}
      </div>
    </aside>
  );
}

/* ── mountain ── */
function Mountain() {
  return (
    <div className="mountain-wrap">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <defs>
          <linearGradient id="mG" x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor="#030609"/>
            <stop offset="100%" stopColor="#020408"/>
          </linearGradient>
        </defs>
        {/* back mid peaks */}
        <path d="M-10,320 L-10,230 L80,160 L180,215 L300,135 L420,200 L545,110 L660,185 L770,98 L880,175 L990,105 L1100,182 L1220,118 L1340,188 L1450,140 L1450,320 Z"
          fill="#07111e"/>
        {/* main peaks */}
        <path d="M-10,320 L-10,262 L100,196 L210,248 L330,162 L445,222 L560,130 L670,198 L778,115 L888,192 L998,125 L1108,198 L1228,138 L1348,202 L1450,162 L1450,320 Z"
          fill="#040c16"/>
        {/* front dark fill — completely solid to bottom */}
        <path d="M-10,320 L-10,284 L120,256 L250,278 L380,248 L510,272 L640,240 L760,266 L880,236 L1000,262 L1120,238 L1250,264 L1380,244 L1450,256 L1450,320 Z"
          fill="url(#mG)"/>
        {/* extra bottom solid to prevent any gaps */}
        <rect x="-10" y="300" width="1470" height="25" fill="#020408"/>
      </svg>
    </div>
  );
}

/* ── hero ── */
function CodeChip(){
  const [copied,setCopied]=useState(false);
  const copy=()=>{
    navigator.clipboard?.writeText("SUSTAIN").catch(()=>{});
    setCopied(true); setTimeout(()=>setCopied(false),1600);
  };
  return (
    <button className="code-chip" onClick={copy} title="Click to copy">
      <span className="cc-label">Use code</span>
      <span className="cc-code">SUSTAIN</span>
      <span className="cc-copy">{copied?"Copied!":"Copy"}</span>
    </button>
  );
}
function Hero() {
  return (
    <section className="hero" id="home">
      {/* characters */}
      <div className="char char-right">
        <img src="assets/slot-raccoon.gif" alt="Raccoon character"
          style={{filter:'drop-shadow(8px 0 28px rgba(74,158,255,.4))',transform:'scaleX(-1)'}} />
      </div>

      {/* floating slot badges removed per user request */}

      {/* center content */}
      <div className="hero-center">
        <div className="stake-label">Stake</div>
        <h1 className="hero-title">
          <span className="blue">SUSTAIN</span><br/>REWARDS
        </h1>
        <p className="hero-sub-text">
          Every wager on <b>Stake</b> under code <span className="hl">SUSTAIN</span> unlocks
          exclusive rewards, instant rakeback and VIP bonuses.
        </p>
        <CodeChip/>
        <div className="hero-cta">
          <a className="btn btn-lg btn-gold" href={JOIN_URL} target="_blank" rel="noopener">
            <Ico.bonuses style={{width:18,height:18}}/> Claim Bonuses
          </a>
          <a className="btn btn-lg btn-blue" href="#bonuses"
            onClick={e=>{e.preventDefault();document.getElementById('bonuses')?.scrollIntoView({behavior:'smooth'})}}>
            View Rewards
          </a>
        </div>
        <div className="chevrons">
          <Ico.chev/><Ico.chev/><Ico.chev/>
        </div>
      </div>

      <Mountain/>
    </section>
  );
}

/* ── perks strip ── */
const PERKS = [
  { big:"3.5%", small:"Instant Rakeback" },
  { big:"10%",  small:"Weekly Loss Back" },
  { big:"3×",   small:"Triple Weekly Bonus" },
  { big:"VIP",  small:"Rank-Up Rewards" },
];
function PerksStrip() {
  return (
    <section className="section reveal" style={{paddingTop:40,paddingBottom:20}} id="rewards">
      <div className="wrap perks-row">
        {PERKS.map((p,i)=>(
          <div className="perk" key={i}>
            <div className="perk-big">{p.big}</div>
            <div className="perk-small">{p.small}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

/* ── bonus cards ── */
function hi(t,cls="hi-gold"){return <span className={cls}>{t}</span>;}
const CARDS = [
  { key:"reload", iconImg:"assets/icon-scatter.png", feat:false,
    title:"7-Day Reload", sub:"New users only",
    items:[<span>Create a ticket with your {hi("Stake name")}</span>,<span>Deposit {hi("$14 or more")}</span>,<span>Free {hi("RELOAD")} every day for {hi("7 days")}</span>,<span>New accounts {hi("(May 5 2026+)")}</span>]},
  { key:"firstdepo", iconImg:"assets/icon-rainbow.png", feat:true,
    title:"First Deposit", sub:"First-time depositors",
    items:[<span>Deposit {hi("any amount","hi-blue")}</span>,<span>Wager {hi("$2,500","hi-blue")} total</span>,<span>Receive {hi("free $20 tip","hi-blue")}</span>,<span>Create a {hi("ticket","hi-blue")} to claim</span>]},
  { key:"tenpct", iconImg:"assets/badge-vs2.webp", feat:false,
    title:"10% Bonus", sub:"One deposit only",
    items:[<span>Valid for {hi("one deposit")} only</span>,<span>Deposit {hi("any amount")}</span>,<span>Get {hi("10%")} back after wagering {hi("10×")}</span>,<span>Bonus capped at {hi("$50")}</span>]},
];
function BonusCards() {
  return (
    <section className="section reveal" id="bonuses" style={{paddingTop:20}}>
      <div className="wrap">
        <div className="section-head">
          <div className="k">Pick your</div>
          <h2>Free <em>Bonus</em></h2>
        </div>
        <div className="cards">
          {CARDS.map(c=>(
            <div className={"card-v2 "+(c.feat?"feat":"")} key={c.key}>
              <div className="card-float-icon">
                <img src={c.iconImg} alt={c.title} style={{width:'100%',height:'100%',objectFit:'contain',filter:'drop-shadow(0 6px 16px rgba(0,0,0,.7))'}}/>
              </div>
              <div className="card-v2-title">{c.title}</div>
              <div className="card-v2-sub">{c.sub}</div>
              <div className="card-pills">{c.items.map((it,i)=><div className="card-pill" key={i}>{it}</div>)}</div>
              <a className="card-btn" href={JOIN_URL} target="_blank" rel="noopener">CLAIM BONUS</a>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── VIP tier ladder ── */
const TIERS = [
  { name:"Bronze",   req:"$10K wagered",   reward:"Welcome perks",  c:"#cd7f47" },
  { name:"Silver",   req:"$50K wagered",   reward:"5% rakeback",    c:"#c2cdd6" },
  { name:"Gold",     req:"$100K wagered",  reward:"Weekly bonus",   c:"#ffd23f" },
  { name:"Platinum", req:"$250K wagered",  reward:"Personal host",  c:"#2fd9c7" },
  { name:"Diamond",  req:"$25M wagered",   reward:"Custom rewards", c:"#7be8ff" },
];

// Íconos de tier: usa tu imagen assets/tier-<nombre>.png; si no está, cae a un SVG.
const TIER_GRAD = {
  Bronze:   ["#e6a86b", "#a85f2e"],
  Silver:   ["#eef2f6", "#9aa7b5"],
  Gold:     ["#ffe89a", "#e0a815"],
  Platinum: ["#8ff5ea", "#20b5a6"],
  Diamond:  ["#c6f4ff", "#49c4ea"],
};
const STAR_PATH = "M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z";
const GEM_PATH  = "M5 3h14l3 5-10 13L2 8z";
function TierIcon({ name }) {
  const [imgOk, setImgOk] = useState(true);
  if (imgOk) {
    return (
      <img className="tc-star tc-img" src={`assets/tier-${name.toLowerCase()}.png`}
        alt={name} onError={() => setImgOk(false)} />
    );
  }
  const [a, b] = TIER_GRAD[name] || ["#fff", "#888"];
  const id = "tier-grad-" + name;
  return (
    <svg className="tc-star" viewBox="0 0 24 24" aria-hidden="true">
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={a} />
          <stop offset="1" stopColor={b} />
        </linearGradient>
      </defs>
      <path d={name === "Diamond" ? GEM_PATH : STAR_PATH}
        fill={`url(#${id})`} stroke="rgba(255,255,255,.45)" strokeWidth="0.6"
        strokeLinejoin="round" />
    </svg>
  );
}
function VipTiers() {
  return (
    <section className="section reveal">
      <div className="wrap tiers-wrap">
        <div className="section-head">
          <div className="k">Climb the ranks</div>
          <h2>VIP <em>Tiers</em></h2>
        </div>
        <div className="tier-row">
          {TIERS.map((t,i)=>(
            <div className="tier-card" key={i} style={{"--tier-c":t.c}}>
              <div className="tc-icon"><TierIcon name={t.name} /></div>
              <div className="tc-name">{t.name}</div>
              <div className="tc-req">{t.req}</div>
              <div className="tc-reward">{t.reward}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── comparison table ── */
const COMP_ROWS = [
  {label:"Basic VIP Level Rewards",   no:true, yes:true},
  {label:"Weekly / Monthly Rewards",  no:true, yes:true},
  {label:"3.5% Boosted Rakeback",     no:false,yes:true},
  {label:"7-Day Free Reload",         no:false,yes:true},
  {label:"10% Deposit Bonus",         no:false,yes:true},
  {label:"Triple Weekly Bonus",       no:false,yes:true},
  {label:"Exclusive VIP Support",     no:false,yes:true},
];
function CompTable() {
  return (
    <section className="section reveal">
      <div className="wrap comp-wrap">
        <div className="section-head">
          <div className="k">Code benefits</div>
          <h2>With vs Without <em>SUSTAIN</em></h2>
        </div>
        <table className="comp-table">
          <thead>
            <tr>
              <th></th>
              <th className="col-no">Without Code</th>
              <th className="col-yes">Code: SUSTAIN</th>
            </tr>
          </thead>
          <tbody>
            {COMP_ROWS.map((r,i)=>(
              <tr key={i}>
                <td>{r.label}</td>
                <td>{r.no?<span className="ico-yes">✓</span>:<span className="ico-no">✕</span>}</td>
                <td><span className="ico-yes">✓</span></td>
              </tr>
            ))}
          </tbody>
        </table>
        <div className="comp-cta">
          <a className="btn btn-lg btn-blue" href={JOIN_URL} target="_blank" rel="noopener">GET ALL PERKS NOW</a>
        </div>
      </div>
    </section>
  );
}

/* ── leaderboard ──
   Ranked by total wagered under code SUSTAIN. Reads a published Google Sheet
   CSV; falls back to demo data if the sheet can't be reached. */
const LB_SHEET_CSV  = "https://docs.google.com/spreadsheets/d/1JCCzG7BMWe74OOX-HpHqo7pnzNMg-M5VlMgAwvK44LY/export?format=csv&gid=1643372957"; // Sep'26 tab
const LB_REFRESH_MIN = 720;                 // re-fetch every 12h
const LB_ROWS        = 15;                  // rows to display
const LB_PRIZE_POOL  = 2500;                // total monthly prize pool (counts up on load)
const LB_PRIZES      = { 1:1000, 2:500, 3:300, 4:200, 5:150, 6:100, 7:75, 8:65, 9:60, 10:50 };
const LB_MOCK = [
  { name:"RaccoonKing",   wagered:184250 },
  { name:"NightOwlBets",  wagered:162900 },
  { name:"LuckyLuna",     wagered:141300 },
  { name:"VoltDrift",     wagered:98750 },
  { name:"CrimsonAce",    wagered:87600 },
  { name:"PixelWager",    wagered:76200 },
  { name:"MangoSpin",     wagered:69450 },
  { name:"ShadowReel",    wagered:61800 },
  { name:"GoldenTumbler", wagered:54900 },
  { name:"FrostByte",     wagered:48300 },
  { name:"EmberFox",      wagered:41750 },
  { name:"ZenithRoll",    wagered:36600 },
  { name:"IronVault",     wagered:29800 },
  { name:"NovaSpin",      wagered:24150 },
  { name:"RiverTide",     wagered:18400 },
];

const lbFmt    = n => "$" + Math.round(n).toLocaleString("en-US");
// Privacy: show first 3 chars + "***" + last char (e.g. "Gun***1").
const lbMask   = name => { const n = String(name||"").trim(); if(!n) return "—"; return n.length>4 ? (n.slice(0,3)+"***"+n.slice(-1)) : (n.slice(0,3)+"***"); };
const lbAvatar = name => { const n = String(name||"").replace(/\s+/g,""); return (n.slice(0,2) || "--").toUpperCase(); };

function lbSplitLine(line){
  const out=[]; let cur="", inQ=false;
  for(let i=0;i<line.length;i++){
    const c=line[i];
    if(c==='"'){ inQ=!inQ; continue; }
    if(c===","&&!inQ){ out.push(cur); cur=""; continue; }
    cur+=c;
  }
  out.push(cur);
  return out.map(s=>s.trim());
}
function lbParseCSV(text){
  const lines=text.split(/\r?\n/).filter(l=>l.trim().length);
  if(!lines.length) return [];
  const header=lbSplitLine(lines[0]).map(h=>h.toLowerCase());
  const idxName = header.findIndex(h=>/user\s*name|username|usuario/.test(h))>=0
    ? header.findIndex(h=>/user\s*name|username|usuario/.test(h))
    : header.findIndex(h=>/name|afiliado|nombre/.test(h));
  const idxWager = header.findIndex(h=>/wager|apostado|amount|monto/.test(h));
  return lines.slice(1).map(l=>lbSplitLine(l)).map(cols=>({
    name: cols[idxName>=0?idxName:0] || "",
    wagered: parseFloat((cols[idxWager>=0?idxWager:2] || "0").replace(/[^0-9.\-]/g,"")) || 0
  })).filter(r=>r.name);
}

/* Countdown to the 1st of next month at 00:00 UTC — when the monthly race ends. */
function lbRaceEndUTC(now){
  const d = new Date(now);
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth()+1, 1, 0, 0, 0);
}
function LeaderboardCountdown(){
  const [now,setNow] = useState(Date.now());
  useEffect(()=>{ const t=setInterval(()=>setNow(Date.now()),1000); return ()=>clearInterval(t); },[]);
  const target = lbRaceEndUTC(now);
  let diff = Math.max(0, target-now);
  const day = Math.floor(diff/864e5); diff -= day*864e5;
  const hr  = Math.floor(diff/36e5);  diff -= hr*36e5;
  const mn  = Math.floor(diff/6e4);   diff -= mn*6e4;
  const sc  = Math.floor(diff/1e3);
  const pad = n => String(n).padStart(2,"0");
  const endLabel = new Date(target).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"});
  const cells = [[day,"Days"],[pad(hr),"Hrs"],[pad(mn),"Min"],[pad(sc),"Sec"]];
  return (
    <div className="lb-timer">
      <div className="lb-timer-label">Race ends in</div>
      <div className="lb-timer-grid">
        {cells.map(([n,u],i)=>(
          <div className="lb-tb" key={i}>
            <span className="n">{n}</span>
            <span className="u">{u}</span>
          </div>
        ))}
      </div>
      <div className="lb-timer-date">Ends {endLabel} · 00:00 UTC</div>
    </div>
  );
}

/* count 0 → target with ease-out on mount */
function useCountUp(target, duration=1700){
  const [val,setVal] = useState(0);
  useEffect(()=>{
    let raf, start=null;
    const ease = t => 1 - Math.pow(1-t, 3);
    const step = ts => {
      if(start===null) start=ts;
      const p = Math.min(1,(ts-start)/duration);
      setVal(Math.round(ease(p)*target));
      if(p<1) raf=requestAnimationFrame(step);
    };
    raf=requestAnimationFrame(step);
    return ()=>cancelAnimationFrame(raf);
  },[target,duration]);
  return val;
}

/* ── collab lockup (very top of leaderboard page) ── */
function LeaderboardCollab(){
  return (
    <div className="lb-collab">
      <img src="assets/sustain-x-stake.png" alt="Sustain × Stake" className="lb-collab-img"
        onError={(e)=>{ e.currentTarget.style.display="none"; }} />
    </div>
  );
}

/* ── prize-pool hero (top of leaderboard page) ── */
function LeaderboardPrizeHero(){
  const amount = useCountUp(LB_PRIZE_POOL);
  return (
    <section className="lb-pp-sec">
      <div className="wrap lb-prizepool">
        <div className="lb-pp-eyebrow">Monthly Leaderboard</div>
        <div className="lb-pp-sub">Only on Stake</div>
        <div className="lb-pp-amount">${amount.toLocaleString("en-US")}</div>
        <p className="lb-pp-desc">
          Only wagers on Stake's <b>“Only on Stake”</b> slots count toward this leaderboard.
          Play them under code <span className="hl">SUSTAIN</span> and earn 2× VIP rewards.
        </p>
        <div className="lb-pp-cta">
          <a className="btn btn-lg btn-gold" href={JOIN_URL} target="_blank" rel="noopener">
            <svg viewBox="0 0 24 24" fill="none" style={{width:18,height:18}}><circle cx="12" cy="8" r="4" stroke="currentColor" strokeWidth="1.8"/><path d="M4 21c0-4 3.5-6 8-6s8 2 8 6" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"/></svg>
            Sign Up
          </a>
        </div>
        <div className="lb-pp-note">
          <div className="lb-pp-note-ico">
            <svg viewBox="0 0 24 24" fill="none" style={{width:20,height:20}}><path d="M12 3l7 3v5c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>
          </div>
          <div>
            <h4>Only your <em>Stake</em> wager counts</h4>
            <p>Only slots listed under Stake's “Only on Stake” category count as wagered on this leaderboard. You also earn 2× VIP rewards on Stake by playing these slots.</p>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── leaderboard rules (bottom of leaderboard page) ── */
const LB_RULES = [
  { span:2, tone:"gold", title:"Only ‘Only on Stake’ slots count",
    body:"Only slots listed under Stake's “Only on Stake” category count as wagered on this leaderboard. You also earn 2× VIP rewards on Stake by playing these slots.",
    icon:(<svg viewBox="0 0 24 24" fill="none"><rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="8.5" cy="9.5" r="1.4" fill="currentColor"/><path d="M4 17l5-5 4 4 3-3 4 4" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/></svg>) },
  { span:1, tone:"red", title:"No wager abuse",
    body:"Any form of wager manipulation is an immediate disqualification.",
    icon:(<svg viewBox="0 0 24 24" fill="none"><path d="M12 3l9 16H3L12 3z" stroke="currentColor" strokeWidth="1.7" strokeLinejoin="round"/><path d="M12 10v4M12 17h.01" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>) },
  { span:1, tone:"red", title:"Self-exclusion voids payouts",
    body:"Self-excluding from Stake voids any pending leaderboard rewards.",
    icon:(<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.7"/><path d="M6 6l12 12" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>) },
  { span:2, tone:"gold", title:"Payments Finalised on the 5th",
    body:"Stake finalises all leaderboard payments on the 5th of each month — it's a new protocol for all Stake affiliates. Please be patient and make a ticket for 24/7 support.",
    icon:(<svg viewBox="0 0 24 24" fill="none"><rect x="2" y="6" width="20" height="12" rx="2" stroke="currentColor" strokeWidth="1.7"/><circle cx="12" cy="12" r="2.5" stroke="currentColor" strokeWidth="1.7"/></svg>) },
];
const LB_RTP = [
  { rtp:"≤ 98%",  pct:"100%" },
  { rtp:"98–99%", pct:"50%" },
  { rtp:"≥ 99%",  pct:"10%" },
];
function LeaderboardRules(){
  return (
    <section className="lb-rules-sec reveal">
      <div className="wrap">
        <div className="lb-rules-card">
          <div className="lb-rules-head">
            <div className="lb-rules-badge">
              <svg viewBox="0 0 24 24" fill="none" style={{width:18,height:18}}><circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.8"/><path d="M12 8v5M12 16h.01" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round"/></svg>
            </div>
            <div>
              <h3>Leaderboard Rules</h3>
              <div className="k">What counts toward your wager</div>
            </div>
          </div>

          <div className="lb-rules-grid">
            {LB_RULES.map((r,i)=>(
              <div className={"lb-rule "+r.tone} style={{gridColumn:"span "+r.span}} key={i}>
                <div className="lb-rule-ico">{r.icon}</div>
                <div>
                  <h4>{r.title}</h4>
                  <p>{r.body}</p>
                </div>
              </div>
            ))}
          </div>

          <div className="lb-rtp">
            <div className="lb-rtp-head">RTP Wager Weighting</div>
            <p className="lb-rtp-desc">Your wager is weighted by each game's RTP: lower-RTP games count in full, higher-RTP games count less.</p>
            <div className="lb-rtp-grid">
              {LB_RTP.map((r,i)=>(
                <div className="lb-rtp-card" key={i}>
                  <div className="rtp-label">Game RTP</div>
                  <div className="rtp-badge">{r.rtp}</div>
                  <div className="rtp-pct">{r.pct}</div>
                  <div className="rtp-sub">of wager counts</div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function Leaderboard(){
  const [data,setData]       = useState(null);
  const [loading,setLoading] = useState(true);
  const [updated,setUpdated] = useState(Date.now());
  const [, setTick]          = useState(0);

  useEffect(()=>{
    let alive=true;
    const load=async(first)=>{
      if(!LB_SHEET_CSV){ if(first&&alive) setLoading(false); return; }
      try{
        const res=await fetch(LB_SHEET_CSV,{cache:"no-store"});
        const text=await res.text();
        const rows=lbParseCSV(text);
        if(alive&&rows.length){ setData(rows); setUpdated(Date.now()); }
      }catch(e){ /* keep fallback data */ }
      finally{ if(first&&alive) setLoading(false); }
    };
    load(true);
    const iv=setInterval(()=>load(false),Math.max(1,LB_REFRESH_MIN)*60000);
    const tk=setInterval(()=>alive&&setTick(t=>t+1),30000);
    return ()=>{alive=false;clearInterval(iv);clearInterval(tk);};
  },[]);

  const timeAgo=()=>{
    const secs=Math.floor((Date.now()-updated)/1000);
    if(secs<60) return "Updated just now";
    const mins=Math.floor(secs/60);
    return `Updated ${mins} min${mins===1?"":"s"} ago`;
  };

  const raw=data??LB_MOCK;
  const sorted=[...raw].sort((a,b)=>b.wagered-a.wagered).slice(0,LB_ROWS).map((r,i)=>({
    ...r, rank:i+1, wageredFmt:lbFmt(r.wagered),
    prizeFmt: LB_PRIZES[i+1]?lbFmt(LB_PRIZES[i+1]):"—",
    name: lbMask(r.name),
    initials: lbAvatar(r.name)
  }));
  const empty={ name:"—", wageredFmt:"$0", prizeFmt:"—", initials:"–" };
  const gold=sorted[0]||empty, silver=sorted[1]||empty, bronze=sorted[2]||empty;
  const rest=sorted.slice(3);
  const demo=!data;
  const showSkeleton = loading && !data;   // no fake data before real data arrives
  const SkelLine = ({w,h,ml}) => <span className="lb-skel lb-skel-line" style={{width:w,height:h,marginLeft:ml}}></span>;

  const Pod=({tier,rank,person})=>(
    <div className={"lb-pod "+tier}>
      <div className="lb-rank-badge">{rank}</div>
      <div className="lb-av">{person.initials}</div>
      <div className="lb-name">{person.name}</div>
      <div className="lb-amt">{person.wageredFmt}</div>
      <div className="lb-prize">{tier==="gold"?"$1,000 prize":tier==="silver"?"$500 prize":"$300 prize"}</div>
    </div>
  );

  return (
    <section className="section reveal" id="leaderboard">
      <div className="wrap lb-wrap">
        <LeaderboardCountdown />

        {showSkeleton ? (
          <React.Fragment>
            <div className="lb-podium">
              {["silver","gold","bronze"].map(t=>(
                <div className={"lb-pod "+t} key={t}>
                  <div className="lb-rank-badge lb-skel">&nbsp;</div>
                  <div className="lb-av lb-skel"></div>
                  <div className="lb-name"><SkelLine w={78}/></div>
                  <div className="lb-amt"><SkelLine w={90} h={18}/></div>
                  <div className="lb-prize"><SkelLine w={60}/></div>
                </div>
              ))}
            </div>
            <div className="lb-table">
              <div className="lb-thead">
                <div>Rank</div><div>Affiliate</div>
                <div className="r-amt">Wagered</div><div className="r-prize h-prize">Prize</div>
              </div>
              {Array.from({length:8}).map((_,i)=>(
                <div className="lb-tr" key={i}>
                  <div className="r-rank"><SkelLine w={24}/></div>
                  <div className="r-aff">
                    <div className="r-av lb-skel"></div>
                    <span className="r-name"><SkelLine w={130}/></span>
                  </div>
                  <div className="r-amt"><SkelLine w={72} ml="auto"/></div>
                  <div className="r-prize"><SkelLine w={46} ml="auto"/></div>
                </div>
              ))}
            </div>
          </React.Fragment>
        ) : (
          <React.Fragment>
            {demo && (
              <div className="lb-demo">
                Showing demo data — live rankings load from the connected Google Sheet.
              </div>
            )}
            <div className="lb-podium">
              <Pod tier="silver" rank="2" person={silver} />
              <Pod tier="gold"   rank="1" person={gold} />
              <Pod tier="bronze" rank="3" person={bronze} />
            </div>
            <div className="lb-table">
              <div className="lb-thead">
                <div>Rank</div><div>Affiliate</div>
                <div className="r-amt">Wagered</div><div className="r-prize h-prize">Prize</div>
              </div>
              {rest.map(row=>(
                <div className="lb-tr" key={row.rank}>
                  <div className="r-rank">#{row.rank}</div>
                  <div className="r-aff">
                    <div className="r-av">{row.initials}</div>
                    <span className="r-name">{row.name}</span>
                  </div>
                  <div className="r-amt">{row.wageredFmt}</div>
                  <div className="r-prize">{row.prizeFmt}</div>
                </div>
              ))}
            </div>
          </React.Fragment>
        )}

        <p className="lb-note">
          Rankings refresh automatically every 12 hours from the connected sheet. 18+. Gamble responsibly.
        </p>
      </div>
    </section>
  );
}

/* ── kick section ── */
function KickSection() {
  return (
    <section className="section reveal" id="kick">
      <div className="wrap kick-inner">
        <div className="kick-left">
          <div className="kick-logo">
            <div className="k-ico"><img src="assets/kick-logo.png" alt="Kick" style={{width:32,height:32,objectFit:'contain'}}/></div>
            <div style={{fontFamily:"'Sora'",fontWeight:800,fontSize:20}}>KICK.COM</div>
          </div>
          <h2>Watch <em>Sustain</em><br/>Live on Kick</h2>
          <p>Join the stream for live giveaways, bonus hunts and high-stakes action. Drop your Stake username in chat to be eligible for rewards.</p>
          <a className="btn btn-lg btn-kick" href={KICK_URL} target="_blank" rel="noopener" style={{display:'none'}}>
            <Ico.kick style={{width:20,height:20}}/> WATCH LIVE
          </a>
        </div>
        <div className="kick-card">
          <div style={{display:'flex',alignItems:'center',justifyContent:'space-between'}}>
            <div className="live-badge"><span className="live-dot"></span>LIVE</div>
            <span className="kick-url">kick.com/sustain</span>
          </div>
          <a className="kick-preview" href={KICK_URL} target="_blank" rel="noopener" style={{display:'none'}}>
            <div className="kick-play"><Ico.play/></div>
            <span>Watch Sustain Live</span>
          </a>
          <div className="kick-embed">
            <iframe src="https://player.kick.com/sustain?muted=true" title="Sustain live on Kick"
              allowFullScreen frameBorder="0"
              style={{width:'100%',aspectRatio:'16/9',border:'0',borderRadius:'11px',display:'block',background:'#000'}}></iframe>
          </div>
          <a className="btn btn-kick" href={KICK_URL} target="_blank" rel="noopener" style={{justifyContent:'center'}}>
            <Ico.kick style={{width:18,height:18}}/> JOIN STREAM
          </a>
        </div>
      </div>
    </section>
  );
}

/* ── footer ── */
function Footer() {
  return (
    <footer className="foot">
      <div className="wrap foot-grid">
        <div>
          <div className="foot-brand">
            <img src="assets/sustain-rounded.png" alt="Sustain"/>
            <span>SUSTAIN<span className="vip">REWARDS</span></span>
          </div>
          <p>We are not responsible for any losses from gambling on casinos or betting sites linked or promoted on this site. As a player, you are solely responsible for your bets. 18+. Gamble responsibly.</p>
        </div>
        <div>
          <h4>Links</h4>
          <div className="foot-links">
            <a href="#home">Home</a>
            <a href="#bonuses">Bonuses</a>
            <a href="#rewards">Rewards</a>
            <a href={JOIN_URL} target="_blank" rel="noopener">Join Stake</a>
          </div>
        </div>
        <div>
          <h4>Community</h4>
          <div className="foot-links">
            <a href={KICK_URL} target="_blank" rel="noopener">
              <Ico.kick style={{width:16,height:16}}/>kick.com/sustain
            </a>
            <a href="https://x.com/SustainOnX" target="_blank" rel="noopener">
              <Ico.x style={{width:16,height:16}}/>x.com/SustainOnX
            </a>
          </div>
        </div>
      </div>
      <div className="wrap foot-bottom">
        <span>© 2026 SustainRewards — All rights reserved</span>
        <span>18+ · Gamble responsibly</span>
      </div>
    </footer>
  );
}

/* ── scroll reveal ── */
function useReveal() {
  useEffect(()=>{
    const els = document.querySelectorAll(".reveal");
    const io = new IntersectionObserver(es=>es.forEach(e=>{
      if(e.isIntersecting){e.target.classList.add("in");io.unobserve(e.target);}
    }),{threshold:.1});
    els.forEach(el=>io.observe(el));
    return ()=>io.disconnect();
  },[]);
}

Object.assign(window,{Background,Sidebar,Hero,PerksStrip,BonusCards,VipTiers,CompTable,Leaderboard,LeaderboardCollab,LeaderboardPrizeHero,LeaderboardRules,KickSection,Footer,useReveal});
