/* eslint-disable */
const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "glassBlur": 28,
  "glassTint": 34,
  "saturation": 180,
  "accentTint": "green",
  "showOrbs": true,
  "selectedPack": "starter",
  "qcNeeded": 600,
  "dealBonus": 15
}/*EDITMODE-END*/;

const ACCENT_PRESETS = {
  green:  { deep: "#07391b", mid: "#1aa552", bright: "#5cdf85", pale: "#d6f7d8" },
  teal:   { deep: "#0a2f3a", mid: "#0e9aa7", bright: "#5fd6e2", pale: "#cef3f7" },
  emerald:{ deep: "#053628", mid: "#0d8c64", bright: "#4cd9a8", pale: "#cdf3e4" },
  forest: { deep: "#1a2e0e", mid: "#4a7a1f", bright: "#9bd64b", pale: "#e9f5cf" },
};

const PACKS = [
  { id: "starter",  tag: "STARTER",  baseQc: 599,  bonus: 90,   price: 2.99,  dispPct: null },
  { id: "boost",    tag: "BOOST",    baseQc: 2799, bonus: 420,  price: 12.99, dispPct: 8 },
  { id: "business", tag: "BUSINESS", baseQc: 8499, bonus: 3000, price: 39.99, gold: true, dispPct: 20 },
];

// Deal Machine prize table (probabilities sum to 100)
const PRIZES = [
  { id: "free",  label: "free purchase",  icon: "🎁", pct: 1,  bonusPct: 100, gift: true },
  { id: "x2",    label: "× 2 bonus qc",  icon: "✕",  pct: 4,  bonusPct: 100 },
  { id: "p30",   label: "+30% bonus",     icon: "+",  pct: 10, bonusPct: 30 },
  { id: "p15",   label: "+15% bonus",     icon: "+",  pct: 15, bonusPct: 15 },
  { id: "p7",    label: "+7% bonus",      icon: "+",  pct: 25, bonusPct: 7 },
  { id: "p5",    label: "+5% bonus",      icon: "+",  pct: 25, bonusPct: 5 },
  { id: "p3",    label: "+3% bonus",      icon: "+",  pct: 20, bonusPct: 3 },
];

const ASSIST_TIPS = [
  "Pick a pack and I'll generate a nice receipt",
  "Spin the Deal Machine — catch +30%",
  "Business gives the best value per qc",
  "Use the slider to find the right pack for your needs",
  "Payment goes through qweapp.online — fully secure",
];

const GOLD_TIP = "Business selected. Gold mode activated ✨";

const FAQ = [
  { q: "When do qc get credited?",       a: "Instantly after successful payment. If there's a delay longer than 5 minutes — contact support and we'll compensate with bonus qc." },
  { q: "Can I get a refund?",             a: "Yes, within 14 days provided qc haven't been spent. Refunds arrive at the original payment method within 1–3 business days." },
  { q: "Where does payment happen?",      a: "In the secure qweapp.online account environment via a certified payment processor. Card details are never stored in the store or the app." },
  { q: "Does the Deal Machine bonus apply to all packs?", a: "Yes, the active bonus is automatically applied to all packs and stacks with each pack's base bonus." },
];

/* ──────────────────────────────────────────────────────────────────────────── */
/* Payment helpers                                                              */
/* ──────────────────────────────────────────────────────────────────────────── */
function randToken() {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  let s = '';
  for (let i = 0; i < 10; i++) s += chars[Math.floor(Math.random() * chars.length)];
  return s;
}
function randDigits12() {
  let s = '';
  for (let i = 0; i < 12; i++) s += Math.floor(Math.random() * 10);
  return s;
}
function startPayment(packId) {
  let deal = "";
  try {
    const d = JSON.parse(localStorage.getItem(DEAL_CD_KEY) || "{}");
    if (d.prizeId && d.savedAt && Date.now() - d.savedAt < DEAL_CD_MS) {
      const prize = PRIZES.find(p => p.id === d.prizeId);
      if (prize) deal = prize.gift ? "freebuy" : String(prize.bonusPct);
    }
  } catch {}
  const base   = `https://qweapp.online/store/${randToken()}`;
  const suffix = `/buy/eng_${randDigits12()}`;
  window.location.href = base + packId + suffix + (deal ? `?deal=${deal}` : "");
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* Inline icons                                                                 */
/* ──────────────────────────────────────────────────────────────────────────── */
function ArrowLeft() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>; }
function Lock() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>; }
function Plus() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>; }
function Check() { return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12l5 5L20 7"/></svg>; }

/* ──────────────────────────────────────────────────────────────────────────── */
/* Cashier — objects fall top→bottom, frog shoots tongue, tap object for pts  */
/* ──────────────────────────────────────────────────────────────────────────── */

const FC_DEFS = [
  { type:"coin",    emoji:"🪙", pts:10,  weight:75, isSpike:false },
  { type:"bag",     emoji:"💰", pts:100, weight:50, isSpike:false },
  { type:"diamond", emoji:"💎", pts:250, weight:30, isSpike:false },
  { type:"spike",   emoji:"🔺", pts:0,   weight:50, isSpike:true  },
];
const FC_TOTAL_W = FC_DEFS.reduce((s,d)=>s+d.weight, 0);
function fcRandDef() {
  let r = Math.random() * FC_TOTAL_W;
  for (const d of FC_DEFS) { r -= d.weight; if (r <= 0) return d; }
  return FC_DEFS[0];
}

/* ── Attempt + reward helpers (module-level) ─────────────────────────────── */
const FC_ATT_MAX = 3;
const FC_ATT_CD  = 3600 * 1000; // 1 hour
const FC_ATT_KEY = "store_cashier_att";
const FC_REW_KEY = "store_cashier_reward";

function fcLoadUsed() {
  try { return JSON.parse(localStorage.getItem(FC_ATT_KEY) || "[]"); } catch { return []; }
}
function fcActiveUsed(arr) {
  const now = Date.now();
  return arr.filter(t => now - t < FC_ATT_CD);
}
function fcAvail(arr) { return FC_ATT_MAX - fcActiveUsed(arr).length; }
function fcNextRecharge(arr) {
  const active = [...fcActiveUsed(arr)].sort((a,b)=>a-b);
  if (active.length < FC_ATT_MAX) return 0;
  return active[0] + FC_ATT_CD;
}
function fcCalcReward(score) {
  if (score >= 100000) return Math.floor(score / 10000) * 100;
  if (score >= 25000)  return 500;
  if (score >= 5000)   return 250;
  if (score >= 1500)   return 100;
  return 0;
}
function fcSaveReward(score) {
  const qc = fcCalcReward(score);
  if (!qc) return 0;
  try {
    const ex = JSON.parse(localStorage.getItem(FC_REW_KEY) || "{}");
    localStorage.setItem(FC_REW_KEY, JSON.stringify({
      qc: (ex.qc || 0) + qc, savedAt: Date.now()
    }));
  } catch {}
  return qc;
}
function fcFmtTime(ms) {
  const s = Math.ceil(ms / 1000);
  const m = Math.floor(s / 60);
  const h = Math.floor(m / 60);
  if (h > 0) return `${h}h ${m % 60}m`;
  if (m > 0) return `${m}m ${s % 60}s`;
  return `${s}s`;
}

function Cashier({ pack, totalQc, bonusPct }) {
  const stageRef    = useRef(null);
  const frogRef     = useRef(null);
  const objsRef     = useRef([]);
  const tongueRef   = useRef(null);
  const retractTRef = useRef(null);
  const nextIdRef   = useRef(0);
  const scheduleRef = useRef(null);
  const livesRef    = useRef(3);
  const aliveRef    = useRef(false);
  const scoreRef    = useRef(0);

  const [score,     setScore]     = useState(0);
  const [lives,     setLives]     = useState(3);
  const [objs,      setObjs]      = useState([]);
  const [tongueVis, setTongueVis] = useState(null);
  const [phase,     setPhase]     = useState("idle");
  const [usedAtts,  setUsedAtts]  = useState(() => fcActiveUsed(fcLoadUsed()));
  const [coolSecs,  setCoolSecs]  = useState(0);
  const [earnedQc,  setEarnedQc]  = useState(0);

  const avail = fcAvail(usedAtts);

  /* ── CSS ─────────────────────────────────────────────────────────────── */
  useEffect(() => {
    const id = "fc3-css";
    if (document.getElementById(id)) return;
    const el = document.createElement("style");
    el.id = id;
    el.textContent = `
      @keyframes fcPulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.4)} }
      @keyframes fcTongue { from{clip-path:inset(0 100% 0 0)} to{clip-path:inset(0 0% 0 0)} }
      @keyframes fcPop { 0%{transform:scale(1.8);opacity:0} 100%{transform:scale(1);opacity:1} }
      .fc-obj {
        position:absolute; width:36px; height:36px;
        display:flex; align-items:center; justify-content:center;
        font-size:22px; user-select:none; cursor:default;
        filter:drop-shadow(0 2px 5px rgba(0,0,0,0.22));
      }
      .fc-obj.fc-grab  { cursor:pointer; animation:fcPulse 0.4s ease-in-out infinite; }
      .fc-obj.fc-spike { cursor:pointer; filter:drop-shadow(0 0 8px rgba(255,40,0,0.9)); }
      .fc-lbl {
        position:absolute; top:-20px; left:50%;
        transform:translateX(-50%);
        font-size:10px; font-weight:800; white-space:nowrap; pointer-events:none;
      }
      .fc-tongue-wrap { position:absolute; transform-origin:0 50%; pointer-events:none; }
      .fc-tongue-bar  { height:7px; border-radius:999px; width:100%;
                        animation:fcTongue 180ms ease-out forwards; }
      .fc-lives { display:flex; gap:2px; font-size:14px; line-height:1; }
      .fc-att   { display:flex; gap:3px; font-size:13px; }
      .fc-play-btn {
        padding:7px 22px; border-radius:10px; border:none;
        background:var(--accent-mid,#1aa552); color:#fff;
        cursor:pointer; font-weight:700; font-size:14px;
        animation:fcPop 0.3s ease-out;
      }
      .fc-play-btn:disabled {
        background:rgba(0,0,0,0.12); color:rgba(0,0,0,0.35); cursor:default;
        animation:none;
      }
      .fc-milestones {
        display:flex; gap:6px; flex-wrap:wrap; justify-content:center;
        font-size:9px; opacity:0.55; margin-top:4px;
      }
      .fc-milestone { background:rgba(0,0,0,0.07); border-radius:5px; padding:2px 5px; }
    `;
    document.head.appendChild(el);
  }, []);

  /* ── Cooldown ticker ─────────────────────────────────────────────────── */
  useEffect(() => {
    if (avail > 0 || phase !== "idle") { setCoolSecs(0); return; }
    const nextRech = fcNextRecharge(usedAtts);
    const tick = () => {
      const rem = nextRech - Date.now();
      if (rem <= 0) {
        const fresh = fcActiveUsed(fcLoadUsed());
        setUsedAtts(fresh);
        setCoolSecs(0);
      } else {
        setCoolSecs(Math.ceil(rem / 1000));
      }
    };
    tick();
    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, [avail, usedAtts, phase]);

  /* ── mkObj helper ─────────────────────────────────────────────────────── */
  const mkObj = () => {
    const def = fcRandDef();
    return { id: nextIdRef.current++, ...def,
      x: 0.06 + Math.random() * 0.82,
      y: -0.12,
      vy: 0.10 + Math.random() * 0.07,
      grabbed: false };
  };

  /* ── Fall animation ───────────────────────────────────────────────────── */
  useEffect(() => {
    let raf, last = performance.now();
    const tick = (now) => {
      const dt = (now - last) / 1000; last = now;
      if (aliveRef.current) {
        const next = objsRef.current.map(o => {
          if (o.grabbed) return o;
          const ny = o.y + o.vy * dt;
          if (ny > 1.12) {
            const def = fcRandDef();
            return { id: nextIdRef.current++, ...def,
              x: 0.06+Math.random()*0.82, y:-0.12,
              vy: 0.10+Math.random()*0.07, grabbed:false };
          }
          return { ...o, y: ny };
        });
        objsRef.current = next;
        setObjs([...next]);
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  /* ── Shoot loop ───────────────────────────────────────────────────────── */
  useEffect(() => {
    let shootTimer = null;
    function schedule() {
      shootTimer = setTimeout(doShoot, 1000 + Math.random() * 600);
    }
    function doShoot() {
      if (!aliveRef.current || tongueRef.current || livesRef.current <= 0) {
        schedule(); return;
      }
      const candidates = objsRef.current.filter(o => !o.grabbed && o.y > 0.05 && o.y < 0.88);
      if (!candidates.length) { schedule(); return; }
      const stage = stageRef.current?.getBoundingClientRect();
      const frog  = frogRef.current?.getBoundingClientRect();
      if (!stage || !frog) { schedule(); return; }

      const obj = candidates[Math.floor(Math.random() * candidates.length)];

      /* ── frog MOUTH: center-x, lower ~70% of emoji height ── */
      const fx = frog.left - stage.left + frog.width  * 0.50;
      const fy = frog.top  - stage.top  + frog.height * 0.70;

      /* object center */
      const ox = obj.x * stage.width;
      const oy = obj.y * stage.height;

      const dx = ox - fx, dy = oy - fy;
      const len   = Math.sqrt(dx*dx + dy*dy);
      const angle = Math.atan2(dy, dx) * 180 / Math.PI;

      objsRef.current = objsRef.current.map(o =>
        o.id === obj.id ? {...o, grabbed:true} : o
      );
      setObjs([...objsRef.current]);
      tongueRef.current = {objId: obj.id, isSpike: obj.isSpike};
      setTongueVis({x:fx, y:fy, angle, len, isSpike: obj.isSpike});

      retractTRef.current = setTimeout(() => {
        if (obj.isSpike) {
          /* spike: just release, it keeps falling */
          objsRef.current = objsRef.current.map(o =>
            o.id === obj.id ? {...o, grabbed:false} : o
          );
        } else {
          /* good object: frog eats it — remove & spawn fresh */
          const def = fcRandDef();
          const fresh = { id: nextIdRef.current++, ...def,
            x: 0.06+Math.random()*0.82, y:-0.12,
            vy: 0.10+Math.random()*0.07, grabbed:false };
          objsRef.current = objsRef.current
            .filter(o => o.id !== obj.id)
            .concat(fresh);
        }
        setObjs([...objsRef.current]);
        tongueRef.current = null;
        setTongueVis(null);
        schedule();
      }, 750);
    }
    scheduleRef.current = schedule;
    // don't auto-start — startGame() will call schedule()
    return () => { clearTimeout(shootTimer); clearTimeout(retractTRef.current); };
  }, []);

  /* ── Start game ───────────────────────────────────────────────────────── */
  function startGame() {
    if (fcAvail(usedAtts) <= 0) return;
    const now  = Date.now();
    const next = [...fcActiveUsed(usedAtts), now];
    try { localStorage.setItem(FC_ATT_KEY, JSON.stringify(next)); } catch {}
    setUsedAtts(next);

    clearTimeout(retractTRef.current);
    aliveRef.current  = true;
    livesRef.current  = 3;
    scoreRef.current  = 0;
    tongueRef.current = null;
    setScore(0); setLives(3); setTongueVis(null); setEarnedQc(0);

    /* 7 objects staggered */
    const stagger = Array.from({length:7}, (_, i) => {
      const o = mkObj(); o.y = -0.12 - i * 0.18; return o;
    });
    objsRef.current = stagger;
    setObjs([...stagger]);
    setPhase("playing");
    if (scheduleRef.current) scheduleRef.current();
  }

  /* ── Tap object ───────────────────────────────────────────────────────── */
  function onObjTap(obj, e) {
    e && e.stopPropagation();
    const t = tongueRef.current;
    if (!t || t.objId !== obj.id) return;
    clearTimeout(retractTRef.current);
    tongueRef.current = null;
    setTongueVis(null);

    if (obj.isSpike) {
      const nl = Math.max(0, livesRef.current - 1);
      livesRef.current = nl;
      setLives(nl);
      if (nl <= 0) {
        aliveRef.current = false;
        const earned = fcSaveReward(scoreRef.current);
        setEarnedQc(earned);
        setPhase("dead");
        return;
      }
    } else {
      const ns = scoreRef.current + obj.pts;
      scoreRef.current = ns;
      setScore(ns);
    }
    objsRef.current = objsRef.current
      .filter(o => o.id !== obj.id)
      .concat(mkObj());
    setObjs([...objsRef.current]);
    if (scheduleRef.current) scheduleRef.current();
  }

  /* ── Shared stage with objects ────────────────────────────────────────── */
  function renderStage() {
    return (
      <div className="mascot-stage" ref={stageRef} style={{minHeight:200,overflow:"hidden"}}>
        <div ref={frogRef} className="frog">🐸</div>
        {tongueVis && (
          <div className="fc-tongue-wrap" style={{
            left:  tongueVis.x,
            top:   tongueVis.y - 3,
            width: tongueVis.len,
            transform: `rotate(${tongueVis.angle}deg)`,
          }}>
            <div className="fc-tongue-bar" style={{
              background: tongueVis.isSpike
                ? "linear-gradient(to right,#ff2200,#ff7700)"
                : "linear-gradient(90deg,#ff8fb3,#ff5e9c)",
              boxShadow: tongueVis.isSpike
                ? "0 0 8px rgba(255,50,0,0.6)"
                : "0 4px 10px rgba(255,143,179,0.4)",
            }}/>
          </div>
        )}
        {objs.map(o => (
          <div key={o.id}
            className={"fc-obj"
              + (o.grabbed && !o.isSpike ? " fc-grab"  : "")
              + (o.grabbed &&  o.isSpike ? " fc-spike" : "")}
            style={{ left:`calc(${o.x*100}% - 18px)`, top:`calc(${o.y*100}% - 18px)` }}
            onClick={o.grabbed ? (e)=>onObjTap(o,e) : undefined}
          >
            {o.emoji}
            {o.grabbed && !o.isSpike && <span className="fc-lbl" style={{color:"#ff9800"}}>+{o.pts} tap!</span>}
            {o.grabbed &&  o.isSpike && <span className="fc-lbl" style={{color:"#ff3333"}}>⚠️ don't tap!</span>}
          </div>
        ))}
      </div>
    );
  }

  const receipt = (
    <div className="receipt">
      Receipt: <b>{pack.tag.toLowerCase().replace(/^./,c=>c.toUpperCase())}</b> — <b>{totalQc.toLocaleString("en-US")} qc</b> for <b>${pack.price.toFixed(2)}</b>{bonusPct > 0 ? <>, bonus <b>+{bonusPct}%</b></> : null}
    </div>
  );

  const livesRow    = "❤️".repeat(lives) + "🖤".repeat(3 - lives);
  const attRow      = "🟢".repeat(avail) + "⚫".repeat(FC_ATT_MAX - avail);
  const nextMilestone = [1500,5000,25000,100000].find(m => score < m);

  /* ── Idle ─────────────────────────────────────────────────────────────── */
  if (phase === "idle") return (
    <div className="glass mascot">
      <div className="mascot-head">
        <div className="mascot-title"><span>🐸</span><span>frog cashier</span></div>
        <div className="fc-att" title="attempts">{attRow}</div>
      </div>
      <div className="mascot-stage" style={{minHeight:200,display:"flex",flexDirection:"column",
        alignItems:"center",justifyContent:"center",gap:10}}>
        <div style={{fontSize:38}}>🐸</div>
        {avail > 0 ? (
          <button className="fc-play-btn" onClick={startGame}>Play</button>
        ) : (
          <>
            <div style={{fontSize:12,opacity:0.5}}>next attempt in</div>
            <div style={{fontSize:20,fontWeight:700}}>{fcFmtTime(coolSecs*1000)}</div>
          </>
        )}
        <div style={{fontSize:10,opacity:0.45,marginTop:2}}>
          {avail}/{FC_ATT_MAX} attempts · recharge 1h
        </div>
        <div className="fc-milestones">
          <span className="fc-milestone">1 500 → 100 qc</span>
          <span className="fc-milestone">5 000 → 250 qc</span>
          <span className="fc-milestone">25 000 → 500 qc</span>
          <span className="fc-milestone">100k+ → /10k×100 qc</span>
        </div>
      </div>
      {receipt}
    </div>
  );

  /* ── Dead ─────────────────────────────────────────────────────────────── */
  if (phase === "dead") return (
    <div className="glass mascot">
      <div className="mascot-head">
        <div className="mascot-title"><span>🐸</span><span>frog cashier</span></div>
        <div className="mascot-score">💀</div>
      </div>
      <div className="mascot-stage" style={{minHeight:200,display:"flex",flexDirection:"column",
        alignItems:"center",justifyContent:"center",gap:8}}>
        <div style={{fontSize:12,opacity:0.45}}>game over</div>
        <div style={{fontSize:36,fontWeight:800}}>{score.toLocaleString("en-US")} pts</div>
        {earnedQc > 0 && (
          <div style={{fontSize:14,fontWeight:700,color:"var(--accent-mid,#1aa552)"}}>
            +{earnedQc} qc earned! 🎉
          </div>
        )}
        <div className="fc-att" style={{marginTop:4}} title="attempts left">{attRow}</div>
        {avail > 0 ? (
          <button className="fc-play-btn" onClick={startGame} style={{marginTop:4}}>Play again</button>
        ) : (
          <div style={{fontSize:11,opacity:0.45,marginTop:4}}>
            Next attempt in {fcFmtTime(coolSecs*1000 || (fcNextRecharge(usedAtts)-Date.now()))}
          </div>
        )}
      </div>
      {receipt}
    </div>
  );

  /* ── Playing ──────────────────────────────────────────────────────────── */
  return (
    <div className="glass mascot">
      <div className="mascot-head">
        <div className="mascot-title"><span>🐸</span><span>frog cashier</span></div>
        <div style={{display:"flex",alignItems:"center",gap:7}}>
          <span className="fc-lives">{livesRow}</span>
          <div className="mascot-score">{score.toLocaleString("en-US")}</div>
        </div>
      </div>
      {renderStage()}
      {receipt}
    </div>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* Trend bars                                                                   */
/* ──────────────────────────────────────────────────────────────────────────── */
function Trend({ seed = 1, gold = false, delta = "+0.4%" }) {
  const bars = useMemo(() => {
    let s = seed * 9301 + 49297;
    return Array.from({ length: 11 }, () => {
      s = (s * 9301 + 49297) % 233280;
      return 30 + (s / 233280) * 65;
    });
  }, [seed]);
  return (
    <>
      <div className={"rate-trend" + (gold ? " gold" : "")}>
        {bars.map((h, i) => <span key={i} style={{ height: `${h}%` }}/>)}
      </div>
      <div className="rate-trend-foot">24h trend · <b>{delta}</b></div>
    </>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* Slider                                                                       */
/* ──────────────────────────────────────────────────────────────────────────── */
function Slider({ value, onChange, min = 100, max = 15000 }) {
  const trackRef = useRef(null);
  const draggingRef = useRef(false);
  const pct = ((value - min) / (max - min)) * 100;
  const moveTo = (clientX) => {
    const rect = trackRef.current.getBoundingClientRect();
    const x = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
    onChange(Math.round((min + x * (max - min)) / 10) * 10);
  };
  const onDown = (e) => { draggingRef.current = true; moveTo(e.clientX ?? e.touches?.[0]?.clientX); e.preventDefault(); };
  useEffect(() => {
    const onMove = (e) => { if (!draggingRef.current) return; moveTo(e.clientX ?? e.touches?.[0]?.clientX); };
    const onUp = () => { draggingRef.current = false; };
    window.addEventListener("pointermove", onMove);
    window.addEventListener("pointerup", onUp);
    return () => { window.removeEventListener("pointermove", onMove); window.removeEventListener("pointerup", onUp); };
  });
  return (
    <>
      <div className="slider-track" ref={trackRef} onPointerDown={onDown}>
        <div className="slider-fill" style={{ width: `${pct}%` }}/>
        <div className="slider-thumb" style={{ left: `${pct}%` }}/>
      </div>
      <div className="ticks">
        <span>100 qc</span><span>3,000</span><span>7,500</span><span>11,000</span><span>15,000+</span>
      </div>
    </>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* Deal Machine                                                                 */
/* ──────────────────────────────────────────────────────────────────────────── */
const DEAL_CD_KEY = "store_deal_reward";
const DEAL_CD_MS  = 60 * 60 * 1000;

function getDealCooldownSecs() {
  try {
    const d = JSON.parse(localStorage.getItem(DEAL_CD_KEY) || "{}");
    if (!d.savedAt) return 0;
    const rem = Math.ceil((DEAL_CD_MS - (Date.now() - d.savedAt)) / 1000);
    return rem > 0 ? rem : 0;
  } catch { return 0; }
}
function fmtSecs(s) {
  const m = Math.floor(s / 60), sec = s % 60;
  return m > 0 ? `${m}m ${sec}s` : `${sec}s`;
}

function DealMachine({ current, setCurrent, cooldown, setCooldown }) {
  const [spinning, setSpinning] = useState(false);
  const [highlightId, setHighlightId] = useState(current);
  const [coolSecs, setCoolSecs] = useState(() => getDealCooldownSecs());

  useEffect(() => {
    const t = setInterval(() => {
      const rem = getDealCooldownSecs();
      setCoolSecs(rem);
      if (rem <= 0) setCooldown(false);
    }, 1000);
    return () => clearInterval(t);
  }, []);

  const spin = () => {
    if (spinning || cooldown) return;
    setSpinning(true);
    let ticks = 0;
    const total = 14;
    const iv = setInterval(() => {
      ticks++;
      setHighlightId(PRIZES[ticks % PRIZES.length].id);
      if (ticks >= total) {
        clearInterval(iv);
        const r = Math.random() * 100;
        let acc = 0;
        const winner = PRIZES.find((p) => (acc += p.pct) >= r) || PRIZES[PRIZES.length - 1];
        setHighlightId(winner.id);
        setCurrent(winner.id);
        try { localStorage.setItem(DEAL_CD_KEY, JSON.stringify({ prizeId: winner.id, savedAt: Date.now() })); } catch {}
        setSpinning(false);
        setCooldown(true);
        setCoolSecs(3600);
      }
    }, 90);
  };

  const prize = PRIZES.find((p) => p.id === current) || PRIZES[3];

  return (
    <div className="glass deal">
      <div className="deal-head">
        <div>
          <h3>Deal Machine</h3>
          <p>Spin once per hour — get a random bonus on your purchase.</p>
        </div>
        {prize.bonusPct > 0 && (
          <div style={{fontSize:10,fontWeight:800,color:"var(--bg-bright)",padding:"3px 8px",borderRadius:999,
            background:"rgba(92,223,133,0.12)",border:"0.5px solid rgba(92,223,133,0.3)",whiteSpace:"nowrap"}}>
            +{prize.bonusPct}% active
          </div>
        )}
      </div>
      <div className="deal-inner">
        <div className="prize-list">
          {PRIZES.map((p) => {
            const isCurrent = p.id === highlightId;
            return (
              <React.Fragment key={p.id}>
                <div className={"label" + (isCurrent ? " current" : "") + (p.gift ? " gift" : "")}>
                  <span className="ico">{p.icon}</span>
                  <span>{p.label}</span>
                </div>
                <div className={"pct" + (isCurrent ? " current" : "")}>{p.pct}%</div>
              </React.Fragment>
            );
          })}
        </div>
        <button
          className={"spin-btn" + (spinning ? " spinning" : "")}
          disabled={cooldown}
          onClick={spin}>
          {spinning ? "Spinning…" : cooldown ? `Wait ${fmtSecs(coolSecs)}` : "Spin again"}
        </button>
      </div>
      <div className="deal-result">
        Active bonus: <b>{prize.label}</b>. {cooldown ? `Next spin in ${fmtSecs(coolSecs)}.` : "Spin available!"}
      </div>
    </div>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* MoneyRain (gold-mode mini-game)                                              */
/* ──────────────────────────────────────────────────────────────────────────── */
const MONEY_TYPES = ["💰", "🪙", "💵", "💸", "💴", "💶"];
const MONEY_VALUES = { "💰": 5, "🪙": 1, "💵": 3, "💸": 3, "💴": 2, "💶": 2 };
const FROG_COUNT = 6;
const FROG_Y = 0.93;
const MOUTH_Y = FROG_Y - 0.025;
const EXTEND_MS = 160;
const RETRACT_MS = 220;
const CATCH_COOLDOWN_MS = 280;

function makeItem(id, atTop) {
  return {
    id, x: 0.05 + Math.random() * 0.9,
    y: atTop ? -0.06 - Math.random() * 0.2 : Math.random() * 0.6 - 0.2,
    vy: 0.13 + Math.random() * 0.12, vx: (Math.random() - 0.5) * 0.04,
    rot: (Math.random() - 0.5) * 30, spin: (Math.random() - 0.5) * 60,
    type: MONEY_TYPES[Math.floor(Math.random() * MONEY_TYPES.length)],
    caught: false, lockedBy: null,
  };
}

function MoneyRain() {
  const [, forceTick] = useState(0);
  const [score, setScore] = useState(0);
  const itemsRef = useRef(null);
  const frogsRef = useRef(null);
  const idRef = useRef(0);
  const dimsRef = useRef({ w: window.innerWidth, h: window.innerHeight });
  const lastNowRef = useRef(performance.now());

  if (!itemsRef.current) itemsRef.current = Array.from({ length: 10 }, () => makeItem(idRef.current++, false));
  if (!frogsRef.current) frogsRef.current = Array.from({ length: FROG_COUNT }, (_, i) => ({
    id: i, x: 0.07 + (i / (FROG_COUNT - 1)) * 0.86, tongue: null, cooldownUntil: 0, shootUntil: 0,
  }));

  useEffect(() => {
    const onResize = () => { dimsRef.current = { w: window.innerWidth, h: window.innerHeight }; };
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  useEffect(() => {
    let raf;
    const loop = (now) => {
      const dt = Math.min(0.05, (now - lastNowRef.current) / 1000);
      lastNowRef.current = now;
      const items = itemsRef.current, frogs = frogsRef.current;
      for (let i = 0; i < items.length; i++) {
        const it = items[i];
        if (it.caught || it.lockedBy != null) continue;
        it.x += it.vx * dt; it.y += it.vy * dt; it.rot += it.spin * dt;
        if (it.y > 1.06) items[i] = makeItem(idRef.current++, true);
      }
      for (let i = 0; i < frogs.length; i++) {
        const f = frogs[i];
        if (f.tongue || now < f.cooldownUntil) continue;
        let bestIdx = -1, bestY = -Infinity;
        for (let j = 0; j < items.length; j++) {
          const it = items[j];
          if (it.caught || it.lockedBy != null || it.y < 0.18 || it.y > 0.82) continue;
          if (Math.abs(it.x - f.x) > 0.13) continue;
          if (it.y > bestY) { bestY = it.y; bestIdx = j; }
        }
        if (bestIdx >= 0) {
          items[bestIdx].lockedBy = f.id;
          f.tongue = { targetIdx: bestIdx, targetId: items[bestIdx].id, startT: now,
            phase: "extend", targetX: items[bestIdx].x, targetY: items[bestIdx].y };
          f.shootUntil = now + EXTEND_MS + 80;
        }
      }
      let gained = 0;
      for (let i = 0; i < frogs.length; i++) {
        const f = frogs[i], t = f.tongue; if (!t) continue;
        const elapsed = now - t.startT;
        if (t.phase === "extend") {
          if (elapsed >= EXTEND_MS) { const it = items[t.targetIdx]; if (it && it.id === t.targetId) it.caught = true; f.tongue = { ...t, phase: "retract", startT: now }; }
        } else {
          if (elapsed >= RETRACT_MS) { const it = items[t.targetIdx]; if (it && it.id === t.targetId) { gained += MONEY_VALUES[it.type] || 1; items[t.targetIdx] = makeItem(idRef.current++, true); } f.tongue = null; f.cooldownUntil = now + CATCH_COOLDOWN_MS; }
        }
      }
      if (gained > 0) setScore((s) => s + gained);
      forceTick((n) => (n + 1) % 1000000);
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  const items = itemsRef.current, frogs = frogsRef.current;
  const { w, h } = dimsRef.current;
  const now = performance.now();

  function tipFor(f) {
    const t = f.tongue; if (!t) return null;
    const elapsed = now - t.startT;
    const p = t.phase === "extend" ? Math.min(1, elapsed / EXTEND_MS) : Math.max(0, 1 - elapsed / RETRACT_MS);
    return { fx: f.x, fy: MOUTH_Y, tx: f.x + (t.targetX - f.x) * p, ty: MOUTH_Y + (t.targetY - MOUTH_Y) * p,
      progress: p, retract: t.phase === "retract", targetIdx: t.targetIdx };
  }
  const overrideByIdx = {};
  for (const f of frogs) { const tip = tipFor(f); if (tip?.retract) overrideByIdx[tip.targetIdx] = tip; }

  return (
    <>
      <div className="money-rain">
        {items.map((it, idx) => {
          const ov = overrideByIdx[idx]; if (it.caught && !ov) return null;
          const x = ov ? ov.tx : it.x, y = ov ? ov.ty : it.y, scale = ov ? (0.4 + 0.6 * ov.progress) : 1;
          return <div key={it.id} className="money-item"
            style={{ left: `${x * 100}%`, top: `${y * 100}%`,
              transform: `translate(-50%, -50%) rotate(${it.rot}deg) scale(${scale})`, opacity: ov ? ov.progress : 1 }}>{it.type}</div>;
        })}
        {frogs.map((f) => {
          const tip = tipFor(f);
          let tongueEl = null;
          if (tip) {
            const px = (tip.tx - tip.fx) * w, py = (tip.ty - tip.fy) * h;
            tongueEl = <div className="rain-tongue" style={{ left: `${tip.fx * 100}%`, top: `${tip.fy * 100}%`,
              width: `${Math.sqrt(px*px + py*py)}px`, transform: `rotate(${Math.atan2(py, px) * 180 / Math.PI}deg)` }}/>;
          }
          return <React.Fragment key={f.id}>{tongueEl}
            <div className={"rain-frog" + (now < f.shootUntil ? " shoot" : "")}
              style={{ left: `${f.x * 100}%`, bottom: `${(1 - FROG_Y) * 100}%` }}>🐸</div>
          </React.Fragment>;
        })}
      </div>
      <div className="rain-score"><span>CAUGHT</span><span className="num">{String(score).padStart(3, "0")}</span></div>
    </>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* Qwentin assistant                                                            */
/* ──────────────────────────────────────────────────────────────────────────── */
function Qwentin({ override }) {
  const [tipIdx, setTipIdx] = useState(0);
  const [eyes, setEyes] = useState({ px: 0, py: 0 });
  const charRef = useRef(null);

  useEffect(() => {
    if (override) return;
    const iv = setInterval(() => setTipIdx((i) => (i + 1) % ASSIST_TIPS.length), 5000);
    return () => clearInterval(iv);
  }, [override]);

  useEffect(() => {
    const onMove = (e) => {
      const el = charRef.current; if (!el) return;
      const r = el.getBoundingClientRect();
      const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
      const dx = e.clientX - cx, dy = e.clientY - cy;
      const dist = Math.sqrt(dx*dx + dy*dy), max = 3;
      setEyes({ px: Math.max(-max, Math.min(max, (dx / Math.max(dist, 1)) * max)),
                py: Math.max(-max, Math.min(max, (dy / Math.max(dist, 1)) * max)) });
    };
    window.addEventListener("pointermove", onMove);
    return () => window.removeEventListener("pointermove", onMove);
  }, []);

  const bubble = override || ASSIST_TIPS[tipIdx];
  return (
    <div className="qwentin">
      <div className="qwentin-bubble" key={bubble}>
        {override ? <span dangerouslySetInnerHTML={{__html: override.replace("Business", '<span class="sparkle-text">Business</span>')}}/> : bubble}
      </div>
      <div className="qwentin-char" ref={charRef} onClick={() => setTipIdx((i) => (i + 1) % ASSIST_TIPS.length)}>
        <div className="qwentin-eyes">
          <div className="qwentin-eye" style={{ "--px": `${eyes.px}px`, "--py": `${eyes.py}px` }}/>
          <div className="qwentin-eye" style={{ "--px": `${eyes.px}px`, "--py": `${eyes.py}px` }}/>
        </div>
        <div className="qwentin-mouth"/>
      </div>
    </div>
  );
}

/* ──────────────────────────────────────────────────────────────────────────── */
/* App                                                                          */
/* ──────────────────────────────────────────────────────────────────────────── */
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [selectedId, setSelectedId] = useState(t.selectedPack || "starter");
  const [needed, setNeeded] = useState(t.qcNeeded || 600);
  const [dealPrizeId, setDealPrizeId] = useState(() => {
    try {
      const d = JSON.parse(localStorage.getItem(DEAL_CD_KEY) || "{}");
      if (d.savedAt && Date.now() - d.savedAt < DEAL_CD_MS && d.prizeId) return d.prizeId;
    } catch {}
    return "p15";
  });
  const [dealCooldown, setDealCooldown] = useState(() => getDealCooldownSecs() > 0);
  const [openFaq, setOpenFaq] = useState(0);
  const [goldFlash, setGoldFlash] = useState(0);
  const [goldTip, setGoldTip] = useState(false);
  const prevPackRef = useRef(selectedId);

  const goldMode = selectedId === "business";

  useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty("--glass-blur", `${t.glassBlur}px`);
    root.style.setProperty("--glass-tint", `rgba(255,255,255,${t.glassTint / 100})`);
    root.style.setProperty("--glass-sat", `${t.saturation}%`);
  }, [t.glassBlur, t.glassTint, t.saturation]);

  useEffect(() => {
    const stage = document.querySelector(".stage");
    if (goldMode) {
      document.body.classList.add("gold-mode");
      if (stage) stage.style.background = "radial-gradient(140% 90% at 50% -10%, #fde68a 0%, #f5cf4d 32%, #d4a418 58%, #8c5e0c 82%, #2e1b03 100%)";
    } else {
      document.body.classList.remove("gold-mode");
      const a = ACCENT_PRESETS[t.accentTint] || ACCENT_PRESETS.green;
      document.documentElement.style.setProperty("--bg-deep", a.deep);
      document.documentElement.style.setProperty("--bg-mid", a.mid);
      document.documentElement.style.setProperty("--bg-bright", a.bright);
      document.documentElement.style.setProperty("--bg-pale", a.pale);
      if (stage) stage.style.background = `radial-gradient(140% 90% at 50% -10%, ${a.bright} 0%, ${a.mid} 40%, ${a.deep} 75%, #061a0e 100%)`;
    }
    const orbs = document.querySelector(".orbs");
    if (orbs) orbs.style.display = t.showOrbs ? "" : "none";
  }, [goldMode, t.accentTint, t.showOrbs]);

  useEffect(() => {
    if (prevPackRef.current !== "business" && selectedId === "business") {
      setGoldFlash((n) => n + 1); setGoldTip(true);
      const tm = setTimeout(() => setGoldTip(false), 4000);
      prevPackRef.current = selectedId;
      return () => clearTimeout(tm);
    }
    prevPackRef.current = selectedId;
  }, [selectedId]);

  useEffect(() => {
    for (const p of PACKS) {
      if (p.baseQc + p.bonus >= needed) { setSelectedId(p.id); setTweak("selectedPack", p.id); break; }
    }
  }, [needed]);

  const pack = PACKS.find((p) => p.id === selectedId) || PACKS[0];
  const prize = PRIZES.find((p) => p.id === dealPrizeId) || PRIZES[3];
  const baseBonusPct = pack.dispPct !== null ? pack.dispPct : 0;
  const finalBonusPct = baseBonusPct + (prize.id === "free" ? 0 : prize.bonusPct);
  const totalQc = pack.baseQc + pack.bonus + Math.round(pack.baseQc * prize.bonusPct / 100);

  const recoText = useMemo(() => {
    const p = PACKS.find((p) => p.baseQc + p.bonus >= needed) || PACKS[PACKS.length - 1];
    if (needed < 200) return { name: "Starter", note: "minimum to try without overpaying." };
    if (p.id === "starter") return { name: "Starter", note: "quick start without overpaying." };
    if (p.id === "boost")   return { name: "Boost",   note: "best price per qc for regular buyers." };
    return { name: "Business", note: "maximum discount per qc in the store." };
  }, [needed]);

  return (
    <>
      <div className="wrap">
        <div className="topbar">
          <button className="back glass-soft" aria-label="Back to home"
            onClick={() => { window.location.href = "https://qweapp.org/home/"; }}
            style={{background:"none",border:"none",padding:0,cursor:"pointer"}}>
            <ArrowLeft/>
          </button>
          <div style={{display:"flex", alignItems:"center", gap:12}}>
            <div className="plan-switch glass-soft">
              <a href="/sub/+/">Subscription</a>
              <button className="active">Store</button>
            </div>
          </div>
        </div>

        <div className="hero">
          <div className="glass hero-main">
            <div className="eyebrow">
              <span className="dot"></span>
              <span>frog exchange</span>
            </div>
            <h1 className="title">qwe store</h1>
            <p className="sub">
              Buy qwe currency without extra steps. Choose a pack, check your bonuses, get an instant quote and proceed to the secure payment environment.
            </p>
            <div className="tag-row">
              <span className="tag-chip"><span className="live-dot"></span>live rates</span>
              <span className="tag-chip">🔒 secure payment</span>
              <span className="tag-chip">approved by <code>qwentin</code></span>
            </div>
          </div>
          <Cashier pack={pack} totalQc={totalQc} bonusPct={finalBonusPct}/>
        </div>

        <div className="sect-h">Exchange rates</div>
        <div className="rates">
          <div className="glass rate">
            <div className="rate-label">wbrain</div>
            <div className="rate-value">1 <span style={{color:"var(--ink-2)"}}>=</span> 5 <span className="qc">qc</span></div>
            <div className="rate-sub">basic exchange</div>
            <Trend seed={3} delta="+1.2%"/>
          </div>
          <div className="glass rate">
            <div className="rate-label">esp</div>
            <div className="rate-value">1 <span style={{color:"var(--ink-2)"}}>=</span> 40 <span className="qc">qc</span></div>
            <div className="rate-sub">for high-tier purchases</div>
            <Trend seed={7} gold delta="−0.6%"/>
          </div>
          <div className="glass rate">
            <div className="rate-label">usd</div>
            <div className="rate-value">$1 <span style={{color:"var(--ink-2)"}}>=</span> 2 <span className="qc">qc</span></div>
            <div className="rate-sub">dollar equivalent</div>
            <Trend seed={11} delta="+0.4%"/>
          </div>
        </div>

        <div className="glass smart">
          <div className="smart-head">
            <h3>Smart pack picker</h3>
            <div className="need-pill">Need: <span className="num">{needed.toLocaleString("en-US")}</span><span className="qc">qc</span></div>
          </div>
          <Slider value={needed} min={100} max={15000} onChange={(v) => { setNeeded(v); setTweak("qcNeeded", v); }}/>
          <div className="recco">
            <span className="recco-arrow"><Check/></span>
            <span>We recommend <b>{recoText.name}</b>: {recoText.note}</span>
          </div>
        </div>

        <DealMachine current={dealPrizeId} setCurrent={(id) => { setDealPrizeId(id); setTweak("dealBonus", PRIZES.find(p=>p.id===id)?.bonusPct || 0); }} cooldown={dealCooldown} setCooldown={setDealCooldown}/>

        <div className="sect-h">Packs</div>
        <div className="packs">
          {PACKS.map((p) => {
            const base = p.dispPct !== null ? p.dispPct : null;
            const final = base !== null ? base + (prize.id === "free" ? 0 : prize.bonusPct) : (prize.id === "free" ? 0 : prize.bonusPct);
            const total = p.baseQc + p.bonus + Math.round(p.baseQc * prize.bonusPct / 100);
            const isSel = p.id === selectedId;
            return (
              <div key={p.id}
                className={"glass pack" + (isSel ? " selected" : "") + (p.gold ? " business" : "")}
                onClick={() => { setSelectedId(p.id); setTweak("selectedPack", p.id); }}>
                <div className="pack-tag">{p.tag}</div>
                <div className="pack-amount">{total.toLocaleString("en-US")} <span className="qc">qc</span></div>
                <div className="pack-split">({p.baseQc.toLocaleString("en-US")} + {(p.bonus + Math.round(p.baseQc * prize.bonusPct / 100)).toLocaleString("en-US")} bonus)</div>
                <div className="pack-price">${p.price.toFixed(2)}</div>
                {(base !== null || (prize.id !== "free" && prize.bonusPct > 0)) && (
                  <div className="pack-bonus">
                    {base !== null && <span>Bonus: <span className="pct">+{base}%</span></span>}
                    {prize.id !== "free" && prize.bonusPct > 0 && (
                      <span className="dm-tag"> +{prize.bonusPct}% Deal Machine</span>
                    )}
                  </div>
                )}
              </div>
            );
          })}
        </div>

        <div className="sect-h">FAQ</div>
        <div className="faq">
          {FAQ.map((f, i) => (
            <div key={i} className={"glass faq-item" + (openFaq === i ? " open" : "")}
                 onClick={() => setOpenFaq(openFaq === i ? -1 : i)}>
              <div className="faq-q">
                <span>{f.q}</span>
                <span className="faq-q-icon"><Plus/></span>
              </div>
              <div className="faq-a">{f.a}</div>
            </div>
          ))}
        </div>
      </div>

      {goldMode && <MoneyRain/>}
      {goldFlash > 0 && <div className="gold-flash" key={goldFlash}/>}
      <Qwentin override={goldTip ? GOLD_TIP : null}/>

      <div className="cta-dock">
        <div className="glass cta">
          <div className="cta-info">
            <div className="pack-line">
              Pack: <b>{pack.tag.toLowerCase().replace(/^./, c=>c.toUpperCase())}</b> · <b>{totalQc.toLocaleString("en-US")} qc</b>
              <span className="muted"> ({pack.baseQc.toLocaleString("en-US")} + {(pack.bonus + Math.round(pack.baseQc * prize.bonusPct / 100)).toLocaleString("en-US")} bonus)</span>
            </div>
            <div className="price-line">
              <b>${pack.price.toFixed(2)}</b>
              {pack.dispPct !== null && <span> · Bonus +{baseBonusPct}%</span>}
              {prize.id !== "free" && prize.bonusPct > 0 && <span> · Deal +{prize.bonusPct}%</span>}
            </div>
            {prize.bonusPct > 0 && (
              <div style={{fontSize:10,marginTop:2,display:"flex",alignItems:"center",gap:4,
                color:"var(--bg-bright)",fontWeight:700}}>
                <span>🎰</span><span>Deal Machine bonus saved — applied to purchase</span>
              </div>
            )}
          </div>
          <button className="buy" onClick={() => startPayment(pack.id)}>
            Buy
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
          </button>
        </div>
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection label="Glass" />
        <TweakSlider label="Blur" value={t.glassBlur} min={6} max={60} step={1} unit="px" onChange={(v) => setTweak("glassBlur", v)} />
        <TweakSlider label="Tint" value={t.glassTint} min={0} max={80} step={1} unit="%" onChange={(v) => setTweak("glassTint", v)} />
        <TweakSlider label="Saturation" value={t.saturation} min={100} max={260} step={5} unit="%" onChange={(v) => setTweak("saturation", v)} />
        <TweakSection label="Scene" />
        <TweakRadio label="Accent" value={t.accentTint} options={["green","emerald","teal","forest"]} onChange={(v) => setTweak("accentTint", v)} />
        <TweakToggle label="Animated orbs" value={t.showOrbs} onChange={(v) => setTweak("showOrbs", v)} />
        <TweakSection label="Store" />
        <TweakSlider label="qc needed" value={needed} min={100} max={15000} step={50} unit="qc" onChange={(v) => { setNeeded(v); setTweak("qcNeeded", v); }} />
        <TweakRadio label="Pack" value={selectedId} options={["starter","boost","business"]} onChange={(v) => { setSelectedId(v); setTweak("selectedPack", v); }} />
      </TweaksPanel>
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
