// screens-public.jsx — WiserGuy landing page + admin Signup
//
// Clean, pricing-forward design. The buy module is now a full-width
// pricing section below the hero so visitors see prices immediately.

const API_BASE = "";
const USERSCRIPT_URL = "/userscript.user.js";

// ── Brand registry ──────────────────────────────────────────────────
const BRANDS = {
  // Public site — wiserguy.cc. No CCU mentions, full public pricing,
  // each money flow goes through its own dedicated bot.
  public: {
    id: "public",
    siteLabel: "wiserguy.cc",
    eyebrow: "your gambling sidekick",
    heroH1Lead: "Auto Claimer for Stake",
    heroH1Tail: null,
    heroSub: "Auto-claim bonus codes. Auto-vault winnings. Daily $1 and scheduled reloads.",
    heroFootnote: <>Free panel forever. Paid passes start at <strong>$10</strong> for 1 week.</>,
    crossLink: null,
    manifestoEyebrow: "why we built this",
    manifesto: "We were sick of paying premium prices to claim bonuses we'd already wagered for. WiserGuy is the tool we wanted to exist — fast, honest, priced under what the going rate has been. Built by people who play the same drops you do.",
    timepassBotUser: "@claimtopupbot",
    timepassBotUrl: "https://t.me/claimtopupbot",
    apiUsBotUser:   "@APIstakeUSbot",
    apiUsBotUrl:    "https://t.me/APIstakeUSbot",
    apiComBotUser:  "@APIstakebot",
    apiComBotUrl:   "https://t.me/APIstakebot",
    supportBotUrl:  "https://t.me/claimtopupbot",
    userscriptPasses: [
      { name: "1 week",   price: "$10", blurb: "~$1.43/day. Most popular.", featured: true },
      { name: "1 month",  price: "$40", blurb: "~$1.33/day. Best long-term value.", featured: false },
    ],
    apiUsPasses: [
      { name: "1 week",  price: "$20", blurb: "Stake.us, 24/7 server-side claiming, one slot.", featured: false },
      { name: "1 month", price: "$60", blurb: "$2/day. Best value for steady use.", featured: true },
    ],
    apiComPasses: [
      { name: "1 week",  price: "$30", blurb: "Stake.com, 24/7 server-side claiming, one slot.", featured: false },
      { name: "1 month", price: "$90", blurb: "$3/day. Best value for steady use.", featured: true },
    ],
    pricingSubhead: <>Three separate bots, one shared infrastructure. Each is its own crypto-paid flow — no subscriptions, no account.</>,
    discountLine: null,
  },

  // CCU site — ccu.wiserguy.cc. Current member-exclusive view with
  // discounted pricing, single bot (@CCUclaimerbot) managing all flows.
  ccu: {
    id: "ccu",
    siteLabel: "ccu.wiserguy.cc",
    eyebrow: "ccu members · gambling sidekick",
    heroH1Lead: "You know",
    heroH1Tail: <>Now he rides along in your tabs.</>,
    heroSub: "Same bot that keeps CCU running — now in your Stake & Shuffle tabs. Auto-claims, Safe-Gambling tools, and reloads on a member-exclusive priced pass.",
    heroFootnote: <>Free panel forever. Passes start at <strong style={{ color: "var(--ok)" }}>free 24h</strong> for CCU members.</>,
    crossLink: { url: "https://wiserguy.cc", text: <>Not a CCU member? Head over to <strong>wiserguy.cc</strong> for the public version.</> },
    manifestoEyebrow: "why we built this",
    manifesto: "We were sick of watching our own community get rinsed paying premium prices to claim bonuses they wagered for. WiserGuy is the tool we wanted to exist — built by people in the same drops you're in, priced exclusively for our community.",
    timepassBotUser: "@CCUclaimerbot",
    timepassBotUrl: "https://t.me/CCUclaimerbot",
    apiUsBotUser:   "@CCUclaimerbot",
    apiUsBotUrl:    "https://t.me/CCUclaimerbot",
    apiComBotUser:  "@CCUclaimerbot",
    apiComBotUrl:   "https://t.me/CCUclaimerbot",
    supportBotUrl:  "https://t.me/CCUclaimerbot",
    userscriptPasses: [
      { name: "24 hours", price: "Free", blurb: "CCU member benefit — free 24h passes on request.", featured: false },
      { name: "1 week",   price: "$5",   blurb: "~71¢/day. Most popular for active players.", featured: true },
      { name: "1 month",  price: "$20",  blurb: "~67¢/day. 50% off the public rate.", featured: false },
    ],
    apiUsPasses: [
      { name: "1 week",  price: "$10", blurb: "Stake.us, 24/7 server-side claiming, one slot.", featured: false },
      { name: "1 month", price: "$30", blurb: "~$1/day. Best value for steady use.", featured: true },
    ],
    apiComPasses: [
      { name: "1 week",  price: "$15", blurb: "Stake.com, 24/7 server-side claiming, one slot.", featured: false },
      { name: "1 month", price: "$45", blurb: "~$1.50/day. Best value for steady use.", featured: true },
    ],
    pricingSubhead: <>Our public prices are already below the going rate. <strong style={{ color: "var(--text)" }}>The prices below are CCU-member exclusive.</strong> Buy on Telegram via <a href="https://t.me/CCUclaimerbot" target="_blank">@CCUclaimerbot</a> — crypto, no subscriptions.</>,
    discountLine: <><strong style={{ color: "var(--text)" }}>Elite VIP members receive exclusive discounts</strong> on top — get with an admin via <code>/support</code> to discuss.</>,
  },
};

function pickBrand() {
  if (typeof window === "undefined") return BRANDS.public;
  const h = window.location.hostname.toLowerCase();
  return h.startsWith("ccu.") ? BRANDS.ccu : BRANDS.public;
}

// ── MAIN LANDING — "manifest" layout ─────────────────────────────────
//
// Designed as one continuous monospace document, not a stack of cards.
// The page IS the product's interface: a system console with sections
// (LAST 24H / ACCESS / PIPELINE / FAQ) separated by hairline rules.
// No card chrome, no shadows, no rounded containers — type, rules, density.
// The TERMINAL palette (cyan acid on near-black) carries the personality;
// JetBrains Mono carries the structure.
const Landing = ({ goto }) => {
  const brand = React.useMemo(() => pickBrand(), []);

  React.useEffect(() => {
    document.documentElement.classList.add("pattern-loud");
    document.documentElement.classList.add("page-manifest");
    return () => {
      document.documentElement.classList.remove("pattern-loud");
      document.documentElement.classList.remove("page-manifest");
    };
  }, []);

  // Live stats from /api/public/stats. Fall back to placeholders so the
  // page never shows skeletons or zeros — it's better to show "—" than
  // a fake "0 claims fired" reading.
  const [stats, setStats] = React.useState(null);
  React.useEffect(() => {
    fetch(API_BASE + "/api/public/stats")
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d) setStats(d); })
      .catch(() => {});
  }, []);
  const fmt = (n) => (n == null ? "—" : Number(n).toLocaleString());

  // Pricing rows — flattened from the brand block. Each row collapses
  // two durations into one entry to fit the line-item shape.
  const ACCESS = [
    { key: "userscript", label: "userscript",    blurb: "browser, your session",      passes: brand.userscriptPasses, url: brand.timepassBotUrl, target: brand.timepassBotUser },
    { key: "us",         label: "api stake.us",  blurb: "server-side, 1 slot, 24/7",  passes: brand.apiUsPasses,      url: brand.apiUsBotUrl,    target: brand.apiUsBotUser },
    { key: "com",        label: "api stake.com", blurb: "server-side, 1 slot, 24/7",  passes: brand.apiComPasses,     url: brand.apiComBotUrl,   target: brand.apiComBotUser },
  ];

  const PIPELINE = [
    { stage: "spot",  note: "a bonus code drops in a community channel" },
    { stage: "relay", note: "we send it to every active member at the same instant" },
    { stage: "claim", note: "it gets claimed on your stake.com or stake.us account" },
  ];

  const TUTORIAL = [
    {
      key: "script",
      label: "userscript path",
      steps: [
        <>install <a href="https://www.tampermonkey.net/" target="_blank" rel="noopener">Tampermonkey</a> — a free browser extension</>,
        <>click <a href="/userscript.user.js">install the WiserGuy userscript</a> (Tampermonkey will prompt)</>,
        <>open Stake.com, Stake.us, or Shuffle — paste your token in the panel that appears</>,
      ],
      foot: <>done. the widget rides along in your tab — codes get claimed through your own session. <a href="#tutorial" onClick={(e) => { e.preventDefault(); goto && goto("tutorial"); }}>see full instructions →</a></>,
    },
    {
      key: "api",
      label: "api path",
      steps: [
        <>get your Stake API key (in Stake: <strong>Settings → API → Reveal</strong>)</>,
        <>buy a pass on the <strong>access</strong> list above — Telegram opens, DM <code>/topup</code> for payment instructions</>,
        <>paste your API key into the bot via <code>/key &lt;name&gt; api &lt;key&gt;</code> — we claim 24/7, no browser needed</>,
      ],
      foot: <>done. codes get claimed even while you sleep — server-side, on your account, per platform. <a href="#tutorial" onClick={(e) => { e.preventDefault(); goto && goto("tutorial"); }}>see full instructions →</a></>,
    },
  ];

  const faqs = [
    { q: "userscript or api?",            a: <>userscript runs in <strong>your browser</strong> on your session. api runs on <strong>our servers</strong>, 24/7, no browser needed, per platform.</> },
    { q: "what's free?",                  a: <>the panel itself, safe-gambling auto-vault, game tools, time-limit warnings, and stake.us daily $1. a pass unlocks live code-claim, reloads, and missed-codes catch-up.</> },
    { q: "will i get banned?",            a: <>userscript fires claims via your own logged-in session — the same path as clicking redeem. api uses your own stake key with the "claim bonus" scope. we never see your password. each site has its own terms; use at your own risk.</> },
    { q: "do i need my browser open?",    a: <>userscript: yes — pin the tab. api: no — it runs server-side, you don't need to be anywhere.</> },
  ];

  return (
    <main className="manifest fade-in">
      {/* ── HEADER ─────────────────────────────────────────────────── */}
      <header className="manifest-head">
        <span className="manifest-sub">
          {brand.id === "ccu" ? "ccu members · auto-claim infrastructure" : "auto-claim infrastructure"}
        </span>
        <span className="manifest-status">
          <span className="manifest-status-dot" /> online
        </span>
      </header>

      {/* ── WHY WE BUILT THIS ─────────────────────────────────────── */}
      {brand.manifesto && (
        <section className="manifest-section">
          <div className="manifest-rule">{brand.manifestoEyebrow || "why"}</div>
          <p className="manifest-manifesto">{brand.manifesto}</p>
        </section>
      )}

      {/* ── ACCESS ─────────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">access</div>
        <ul className="manifest-access">
          {ACCESS.map(row => (
            <li key={row.key} className="manifest-row">
              <div className="manifest-row-head">
                <span className="manifest-row-label">{row.label}</span>
                <span className="manifest-row-blurb">{row.blurb}</span>
              </div>
              <div className="manifest-row-passes">
                {row.passes.map(p => (
                  <button
                    key={p.name}
                    type="button"
                    className={`manifest-pass ${p.featured ? "is-featured" : ""}`}
                    onClick={() => window.open(row.url, "_blank")}
                    title={p.blurb}
                  >
                    <span className="manifest-pass-dur">{p.name.toLowerCase()}</span>
                    <span className="manifest-pass-price">{p.price}</span>
                  </button>
                ))}
              </div>
            </li>
          ))}
        </ul>
        {brand.discountLine && (
          <p className="manifest-note">{brand.discountLine}</p>
        )}
      </section>

      {/* ── HOW IT WORKS ───────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">how it works</div>
        <ol className="manifest-pipeline">
          {PIPELINE.map((p, i) => (
            <li key={p.stage} className="manifest-pipe-row">
              <span className="manifest-pipe-arrow" aria-hidden="true">▸</span>
              <span className="manifest-pipe-stage">{p.stage}</span>
              <span className="manifest-pipe-note">{p.note}</span>
            </li>
          ))}
        </ol>
      </section>

      {/* ── GET STARTED ────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">get started</div>
        <div className="manifest-tut">
          {TUTORIAL.map(t => (
            <div key={t.key} className="manifest-tut-path">
              <h3 className="manifest-tut-head">
                <span className="manifest-tut-marker" aria-hidden="true">▸</span> {t.label}
              </h3>
              <ol className="manifest-tut-steps">
                {t.steps.map((step, i) => (
                  <li key={i}>{step}</li>
                ))}
              </ol>
              <p className="manifest-tut-foot">{t.foot}</p>
            </div>
          ))}
        </div>
      </section>

      {/* ── FAQ ────────────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">faq</div>
        <dl className="manifest-faq">
          {faqs.map((f, i) => (
            <React.Fragment key={i}>
              <dt className="manifest-faq-q"><span className="manifest-faq-marker">Q.</span> {f.q}</dt>
              <dd className="manifest-faq-a"><span className="manifest-faq-marker">A.</span> {f.a}</dd>
            </React.Fragment>
          ))}
        </dl>
      </section>

      {/* ── FOOTER ─────────────────────────────────────────────────── */}
      <footer className="manifest-foot">
        <span>wiserguy.cc</span>
        <span className="manifest-foot-sep">·</span>
        <a href={brand.supportBotUrl} target="_blank" rel="noopener">support</a>
        <span className="manifest-foot-sep">·</span>
        <span>claim engine: <strong>online</strong></span>
      </footer>
    </main>
  );
};

// ── TUTORIAL — detailed setup walkthroughs ──────────────────────────
const Tutorial = ({ goto }) => {
  const brand = React.useMemo(() => pickBrand(), []);

  React.useEffect(() => {
    document.documentElement.classList.add("pattern-loud");
    document.documentElement.classList.add("page-manifest");
    return () => {
      document.documentElement.classList.remove("pattern-loud");
      document.documentElement.classList.remove("page-manifest");
    };
  }, []);

  return (
    <main className="manifest fade-in">
      <header className="manifest-head">
        <span className="manifest-sub">setup · step-by-step</span>
        <a
          href="#landing"
          onClick={(e) => { e.preventDefault(); goto && goto("landing"); }}
          className="manifest-back"
        >
          ← back
        </a>
      </header>

      {/* ── USERSCRIPT ──────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">userscript path</div>
        <p className="manifest-tut-intro">
          The browser route. Free panel forever; a paid pass unlocks live
          bonus-code auto-claim. Runs in your own logged-in session — same
          path as clicking "Redeem" yourself, just automated.
        </p>

        <ol className="manifest-tut-steps manifest-tut-long">
          <li>
            <strong>Install Tampermonkey</strong> — a free browser extension
            that runs custom scripts on web pages. Pick your browser:
            <ul className="manifest-tut-sub">
              <li><a href="https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo" target="_blank" rel="noopener">Chrome / Edge / Brave</a></li>
              <li><a href="https://addons.mozilla.org/firefox/addon/tampermonkey/" target="_blank" rel="noopener">Firefox</a></li>
              <li><a href="https://apps.apple.com/app/tampermonkey/id1482490089" target="_blank" rel="noopener">Safari (Mac/iOS)</a></li>
            </ul>
          </li>
          <li>
            <strong>Install the WiserGuy userscript.</strong> Click <a href="/userscript.user.js">this link</a> — Tampermonkey will open a preview page. Click <em>Install</em> in the top corner.
          </li>
          <li>
            <strong>Open a target site</strong> — <code>stake.com</code>, <code>stake.us</code>, or <code>shuffle.com</code>. A small WiserGuy panel appears in the corner.
          </li>
          <li>
            <strong>Paste your token.</strong> Get a token from the dashboard (top right when signed in). Click the gear icon ⚙ in the panel and paste it. The dot turns green when claims are armed.
          </li>
        </ol>

        <p className="manifest-tut-note">
          <strong>Troubleshooting:</strong> if the panel doesn't appear, make sure Tampermonkey shows the script as <em>Enabled</em> in the extensions menu, then refresh the tab. If the dot stays yellow ("connecting") for more than 10 seconds, your token may have expired — click ⚙ and paste a fresh one.
        </p>
      </section>

      {/* ── API ─────────────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">api path</div>
        <p className="manifest-tut-intro">
          The server-side route. No browser needed — we claim on your account 24/7 using your own Stake API key. Per platform: separate pass for Stake.com and Stake.us.
        </p>

        <ol className="manifest-tut-steps manifest-tut-long">
          <li>
            <strong>Generate your Stake API key.</strong> Log into Stake. Top right avatar → <em>Settings</em> → <em>API</em> → <em>Reveal</em>. Stake will show a long string. Copy it.
            <p className="manifest-tut-callout">
              Don't see "API" in Settings? It's usually under <em>Account</em> or <em>Security</em>. If your account is brand new, Stake may require a small wager or deposit before exposing the API tab.
            </p>
          </li>
          <li>
            <strong>Pay for a pass.</strong> On the landing page → <em>access</em> section, pick a duration for the API product that matches your platform. Click the button — Telegram opens the bot. DM <code>/topup</code> inside the bot for payment instructions (crypto to admin, manual credit).
          </li>
          <li>
            <strong>Give the bot your API key.</strong> In the bot DM, send <code>/create &lt;name&gt;</code> to create a slot, then <code>/key &lt;name&gt; api &lt;your-api-key&gt;</code> to register your Stake API key.
          </li>
          <li>
            <strong>(Optional) Set your currency.</strong> On Stake.com you pick which currency the bonus credits in (USDT, BTC, etc). Default is USDT. On Stake.us it's always Sweeps Coins.
          </li>
          <li>
            <strong>Confirm it works.</strong> Send <code>/all</code> in the bot DM — your slot shows as <em>active</em>. The next bonus-code drop on your platform gets claimed automatically.
          </li>
        </ol>

        <p className="manifest-tut-note">
          <strong>Safety:</strong> we never see your password. The Stake API key only has <em>Claim Bonus</em> scope — it can't withdraw funds, change settings, or place bets. If you revoke the key in Stake, claims stop immediately on our side.
        </p>
      </section>

      {/* ── HELP ────────────────────────────────────────────────────── */}
      <section className="manifest-section">
        <div className="manifest-rule">if you get stuck</div>
        <p className="manifest-tut-intro">
          DM <a href={brand.supportBotUrl} target="_blank" rel="noopener">{brand.timepassBotUser}</a> on Telegram with <code>/support</code> and a quick description of what step you're on. An admin gets back fast.
        </p>
      </section>

      <footer className="manifest-foot">
        <a
          href="#landing"
          onClick={(e) => { e.preventDefault(); goto && goto("landing"); }}
        >
          ← back to landing
        </a>
        <span className="manifest-foot-sep">·</span>
        <a href={brand.supportBotUrl} target="_blank" rel="noopener">support</a>
        <span className="manifest-foot-sep">·</span>
        <span>claim engine: <strong>online</strong></span>
      </footer>
    </main>
  );
};

// ── SIGNUP — unchanged from original ──────────────────────────────
const Signup = ({ goto, signIn }) => {
  const [mode, setMode]   = React.useState("telegram");
  const [isSignIn, setIsSignIn] = React.useState(false);
  const [busy, setBusy]   = React.useState(false);
  const [error, setError] = React.useState("");

  const [tgUser, setTgUser]   = React.useState("");
  const [tgCode, setTgCode]   = React.useState(null);
  const [tgPolling, setTgPolling] = React.useState(false);
  const [tgToken, setTgToken] = React.useState(null);
  const pollRef = React.useRef(null);

  const [email, setEmail] = React.useState("");
  const [pw, setPw]       = React.useState("");

  const [settingCreds, setSettingCreds] = React.useState(false);
  const [credEmail, setCredEmail] = React.useState("");
  const [credPw, setCredPw]       = React.useState("");
  const [credError, setCredError] = React.useState("");
  const [credBusy, setCredBusy]   = React.useState(false);

  const tgValid    = tgUser.replace("@", "").length > 2;
  const emailValid = /\S+@\S+\.\S+/.test(email) && pw.length >= 6;

  const stopPoll = () => {
    if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; }
  };

  const startPoll = (code) => {
    stopPoll();
    setTgPolling(true);
    pollRef.current = setInterval(async () => {
      try {
        const r = await fetch(`${API_BASE}/api/auth/telegram/poll`, {
          method: "POST",
          headers: { "content-type": "application/json" },
          body: JSON.stringify({ code }),
        });
        const d = await r.json();
        if (d.verified) {
          stopPoll();
          setTgPolling(false);
          if (d.needs_credentials) {
            setTgToken(d.token);
            setSettingCreds(true);
          } else {
            localStorage.setItem("cc_token", d.token);
            signIn(d.user);
            goto(d.user?.plan && d.user.plan !== "free" ? "dashboard" : "subscription");
          }
        }
      } catch (_) {}
    }, 2000);
  };

  const submitTg = async (e) => {
    e?.preventDefault();
    if (!tgValid) return;
    setError(""); setBusy(true);
    try {
      const r = await fetch(`${API_BASE}/api/auth/telegram/request`, {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ username: tgUser.replace("@", "") }),
      });
      const d = await r.json();
      if (d.error) { setError(d.error); setBusy(false); return; }
      setTgCode(d.code);
      setBusy(false);
      startPoll(d.code);
    } catch { setError("Network error"); setBusy(false); }
  };

  const submitEmail = async (e) => {
    e?.preventDefault();
    if (!emailValid) return;
    setError(""); setBusy(true);
    const endpoint = isSignIn ? "/api/signin" : "/api/signup";
    try {
      const r = await fetch(`${API_BASE}${endpoint}`, {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ email, password: pw }),
      });
      const d = await r.json();
      if (d.error) { setError(d.error); setBusy(false); return; }
      localStorage.setItem("cc_token", d.token);
      signIn(d.user);
      goto(d.user?.plan && d.user.plan !== "free" ? "dashboard" : "subscription");
    } catch { setError("Network error"); setBusy(false); }
  };

  const submitCreds = async (e) => {
    e?.preventDefault();
    if (!/\S+@\S+\.\S+/.test(credEmail) || credPw.length < 6) return;
    setCredError(""); setCredBusy(true);
    try {
      const r = await fetch(`${API_BASE}/api/me/set-credentials`, {
        method: "POST",
        headers: { "content-type": "application/json", "Authorization": `Bearer ${tgToken}` },
        body: JSON.stringify({ email: credEmail, password: credPw }),
      });
      const d = await r.json();
      if (d.error) { setCredError(d.error); setCredBusy(false); return; }
      localStorage.setItem("cc_token", d.token);
      signIn(d.user);
      goto(d.user?.plan && d.user.plan !== "free" ? "dashboard" : "subscription");
    } catch { setCredError("Network error"); setCredBusy(false); }
  };

  if (settingCreds) {
    const credValid = /\S+@\S+\.\S+/.test(credEmail) && credPw.length >= 6;
    return (
      <div className="container fade-in auth-card">
        <span className="eyebrow">one more thing</span>
        <h2 style={{ fontSize: 26, marginTop: 6, marginBottom: 14 }}>Set a password</h2>
        <Card lift>
          <form onSubmit={submitCreds} className="stack">
            <Field label="Email">
              <Input type="email" placeholder="you@example.com" value={credEmail} onChange={e => setCredEmail(e.target.value)} />
            </Field>
            <Field label="Password" hint="6+ characters">
              <Input type="password" placeholder="••••••••" value={credPw} onChange={e => setCredPw(e.target.value)} />
            </Field>
            {credError && <p className="err-text">{credError}</p>}
            <Btn type="submit" kind="primary" block lg disabled={!credValid || credBusy}>
              {credBusy ? "Saving…" : <>Continue <Icon name="arrow" /></>}
            </Btn>
          </form>
        </Card>
      </div>
    );
  }

  if (tgCode) {
    return (
      <div className="container fade-in auth-card">
        <Btn kind="ghost" sm onClick={() => { stopPoll(); setTgCode(null); }}><Icon name="left" /> Back</Btn>
        <h2 style={{ fontSize: 24, marginTop: 18, marginBottom: 6 }}>Send to @CCUclaimerbot</h2>
        <p className="muted" style={{ marginBottom: 18, fontSize: 13 }}>
          Open Telegram. Paste this code to the bot.
        </p>
        <Card lift>
          <div className="tg-code">{tgCode}</div>
          <p className="muted" style={{ textAlign: "center", marginTop: 8, fontSize: 12 }}>
            {tgPolling ? "⏳ waiting…" : ""}
          </p>
        </Card>
      </div>
    );
  }

  return (
    <div className="container fade-in auth-card">
      <Btn kind="ghost" sm onClick={() => goto("landing")}><Icon name="left" /> Back</Btn>
      <h2 style={{ fontSize: 28, marginTop: 18, marginBottom: 6 }}>
        {isSignIn ? "API sign in" : "API sign up"}
      </h2>
      <p className="muted" style={{ fontSize: 13, marginBottom: 18 }}>
        Manage your API slots, view claim history, and configure per-slot toggles.
      </p>
      <Card lift>
        <div className="row" style={{ gap: 0, marginBottom: 14, borderBottom: "1px solid var(--border)" }}>
          <button
            type="button"
            onClick={() => { setMode("telegram"); setError(""); }}
            style={{
              flex: 1, padding: "10px 0", background: "none", border: "none",
              borderBottom: mode === "telegram" ? "2px solid var(--accent)" : "2px solid transparent",
              cursor: "pointer", fontSize: 13, fontWeight: 600,
              color: mode === "telegram" ? "var(--text-1)" : "var(--text-3)",
            }}>
            <Icon name="tg" /> Telegram
          </button>
          <button
            type="button"
            onClick={() => { setMode("email"); setError(""); }}
            style={{
              flex: 1, padding: "10px 0", background: "none", border: "none",
              borderBottom: mode === "email" ? "2px solid var(--accent)" : "2px solid transparent",
              cursor: "pointer", fontSize: 13, fontWeight: 600,
              color: mode === "email" ? "var(--text-1)" : "var(--text-3)",
            }}>
            Email
          </button>
        </div>
        {mode === "telegram" ? (
          <form onSubmit={submitTg} className="stack">
            <Field label="Telegram username">
              <Input placeholder="@alice" value={tgUser} onChange={e => setTgUser(e.target.value)} />
            </Field>
            {error && <p className="err-text">{error}</p>}
            <Btn type="submit" kind="primary" block lg disabled={!tgValid || busy}>
              {busy ? "…" : <><Icon name="tg" /> Continue with Telegram</>}
            </Btn>
          </form>
        ) : (
          <form onSubmit={submitEmail} className="stack">
            <Field label="Email">
              <Input type="email" placeholder="you@example.com" value={email} onChange={e => setEmail(e.target.value)} />
            </Field>
            <Field label="Password" hint={isSignIn ? "" : "6+ characters"}>
              <Input type="password" placeholder="••••••••" value={pw} onChange={e => setPw(e.target.value)} />
            </Field>
            {error && <p className="err-text">{error}</p>}
            <Btn type="submit" kind="primary" block lg disabled={!emailValid || busy}>
              {busy ? "…" : isSignIn ? <>Sign in <Icon name="arrow" /></> : <>Create account <Icon name="arrow" /></>}
            </Btn>
          </form>
        )}
      </Card>
      <p className="muted" style={{ textAlign: "center", marginTop: 14, fontSize: 12 }}>
        {isSignIn ? "New here?" : "Already have an account?"}
        {" "}
        <button className="auth-switch inline" onClick={() => { setIsSignIn(!isSignIn); setError(""); }}>
          {isSignIn ? "Sign up" : "Sign in"}
        </button>
      </p>
    </div>
  );
};

Object.assign(window, { Landing, Tutorial, Signup });
