function HomePage({ go }) {
  const [lang, setLang] = React.useState("ts");
  return (
    <div className="content home" data-screen-label="00 Home">
      <CountdownBanner />
      <div className="hero-grid">
        <div>
          <h1 className="page-title">A 9-chapter field guide to surviving Polymarket's V2 migration.</h1>
          <p className="lede">
            On April 28, Polymarket cuts over to V2.
          </p>
          <p>
            This guide is a working repo of nine scripts — one per subsystem — tested against clob-v2 with the community's V2 makers
          </p>
          <p>
            Where the official docs are stale or contradicted by on-chain behavior, we say so and show what actually works.
          </p>
          <div className="hero-cta">
            <a href="#/chapter/clob-client" className="btn primary" onClick={(e) => { e.preventDefault(); go("chapter", "clob-client"); }}>
              Start chapter 01 <span className="arrow">→</span>
            </a>
            <a href="#/about" className="btn" onClick={(e) => { e.preventDefault(); go("about"); }}>
              Who wrote this
            </a>
          </div>
        </div>
        <div>
          <DualTerminal
            linesTs={CH1_TERMINAL_TS} linesPy={CH1_TERMINAL_PY}
            labelTs="bash — 01-clob-client.ts" labelPy="bash — 01_clob_client.py"
            lang={lang} setLang={setLang} />
        </div>
      </div>

      <hr className="hr-dashed" />

      <h2 className="section-title">Who this is for</h2>
      <div className="audience-grid">
        <div className="audience-card">
          <div className="tag">01 · MM</div>
          <h3>Market makers</h3>
          <p>Your pre-signed grid just got retraced — Polymarket retracted the
            timestamp semantics and your assumptions about nonce monotonicity
            are wrong</p>
        </div>
        <div className="audience-card">
          <div className="tag">02 · Integrator</div>
          <h3>Integration teams</h3>
          <p>You pushed a V2 build, got "not enough balance / allowance" despite
            MAX approvals, and realized the allowance dict still has V1 contract
            addresses.
            .</p>
        </div>
        <div className="audience-card">
          <div className="tag">03 · RAW API</div>
          <h3>RAW API /  non-SDK stacks</h3>
          <p>You sign orders by hand (Rust, Go, custom TS), the migration doc's
            wire-body screenshot doesn't match what the server accepts, and the
            official Rust SDK is still "EOD" for the fifth day in a row..</p>
        </div>
      </div>

      <h2 className="section-title">The nine chapters</h2>
      <div className="chapter-index">
        {CHAPTERS.map(c => (
          <a key={c.slug} href={"#/chapter/" + c.slug} onClick={(e) => { e.preventDefault(); go("chapter", c.slug); }}>
            <span className="num">{String(c.n).padStart(2, "0")}</span>
            <span>
              <span className="title">{c.title}</span>
              <span className="sub">{c.file} &nbsp;·&nbsp; {c.why.split(".")[0]}.</span>
            </span>
            <span className="go">cat →</span>
          </a>
        ))}
      </div>
    </div>
  );
}

function ChapterPage({ slug, go }) {
  const c = CHAPTERS.find(x => x.slug === slug) ?? CHAPTERS[0];
  const prev = CHAPTERS[c.n - 2];
  const next = CHAPTERS[c.n];
  const isFull = c.n === 1;
  const [lang, setLang] = React.useState("ts");

  return (
    <div className="content" data-screen-label={String(c.n).padStart(2, "0") + " " + c.title}>
      <div className="chapter-eyebrow">CHAPTER {String(c.n).padStart(2, "0")} / 09</div>
      <h1 className="page-title">{c.title}</h1>
      <p className="lede">{c.why}</p>

      {isFull ? (
        <>
          <h2 className="section-title" id="why">Why this module exists</h2>
          <div className="prose">
            <p>V1 treats the order book as two disjoint surfaces: a REST snapshot you poll and a WebSocket stream you subscribe to. The V2 CLOB client collapses both into one authenticated connection, with an explicit <code>book_hash</code> on every frame. Your job is to snapshot, subscribe, and reconcile — <strong>in that order</strong>.</p>
            <p>Everything else in this guide assumes a working connection layer. If the client silently resyncs on every delta or you chase stale hashes, nothing downstream will behave.</p>
          </div>

          <h2 className="section-title" id="install">Install</h2>
          <DualInstallBlock ts={INSTALL_TS} py={INSTALL_PY} lang={lang} setLang={setLang} />

          <h2 className="section-title" id="code">The module</h2>
          <div className="prose">
            <p>Below is the full <code>{lang === "py" ? "01_clob_client.py" : "01-clob-client.ts"}</code>. It is deliberately plain — no retry wrapper, no reconnect strategy. Those belong in your framework code; this is the protocol.</p>
          </div>
          <DualCodeBlock
            filenameTs="01-clob-client.ts" filenamePy="01_clob_client.py"
            codeTs={CH1_CODE_TS} codePy={CH1_CODE_PY}
            lang={lang} setLang={setLang} />

          <h2 className="section-title" id="run">Run it</h2>
          <div className="prose">
            <p>With a funded signer in <code>PK</code>, this should produce a single snapshot and a live delta stream. Any hash drift triggers a resync.</p>
          </div>
          <DualTerminal
            linesTs={CH1_TERMINAL_TS} linesPy={CH1_TERMINAL_PY}
            labelTs="bash — 01-clob-client.ts" labelPy="bash — 01_clob_client.py"
            lang={lang} setLang={setLang} />

          <h2 className="section-title" id="pitfalls">Common pitfalls</h2>

          <div className="admonition">
            <div className="title"><span className="glyph">▲</span> Subscribing before snapshotting</div>
            <p>It's tempting to open the WebSocket first and use the first frame as your base book. Don't. The V2 stream is delta-only — your initial state <strong>must</strong> come from <code>getOrderBook()</code>, and the first delta you apply must have <code>prev_hash === snapshot.hash</code>.</p>
          </div>

          <div className="admonition">
            <div className="title"><span className="glyph">▲</span> Silent hash drift</div>
            <p>Log <code>prev_hash</code> on every frame. If it disagrees with your local hash, resync immediately — don't apply the delta "best effort." A single bad apply poisons the book until the next restart.</p>
          </div>

          <div className="admonition danger">
            <div className="title"><span className="glyph">✕</span> Reusing the V1 <code>/markets</code> endpoint</div>
            <p>V1's <code>/markets</code> still responds during the pause window and returns <strong>stale</strong> data. Pin your client to <code>clob.polymarket.com</code> and the V2 schema; if you see <code>tick_size</code> as a string, you're on the wrong endpoint.</p>
          </div>

          <div className="admonition info">
            <div className="title"><span className="glyph">ℹ</span> Connection multiplexing</div>
            <p>V2 allows a single WS connection to carry up to 64 market subscriptions. If you're running a fleet of single-market connections, collapse them before cutover — V1's per-market connection pattern is no longer the right shape.</p>
          </div>

          <h2 className="section-title" id="verify">How you know it works</h2>
          <div className="prose">
            <p>Run the module for ~5 minutes against a liquid market. You should see zero <code>resync()</code> calls under steady state, a monotonically increasing <code>seq</code>, and <code>hash</code> rotating on every frame. If any of those three are off, stop and read chapter 02 before moving on.</p>
          </div>
        </>
      ) : (
        <>
          <h2 className="section-title">Draft</h2>
          <div className="prose">
            <p>This chapter is scaffolded but not yet expanded in this preview. The full version mirrors chapter 01: <em>why the module exists · install · the module · run it · common pitfalls · how you know it works</em> — with TypeScript and Python side-by-side.</p>
          </div>
          <div className="admonition info">
            <div className="title"><span className="glyph">ℹ</span> Coming soon</div>
            <p>Chapter {String(c.n).padStart(2, "0")} — {c.title.toLowerCase()} — is being finalized against a live V2 staging endpoint. Subscribe on the home page to get pinged when it lands.</p>
          </div>
        </>
      )}

      <div className="chapter-footer">
        {prev ? (
          <a href={"#/chapter/" + prev.slug} onClick={(e) => { e.preventDefault(); go("chapter", prev.slug); }}>
            <span className="label">← Previous</span>
            <span className="name">{String(prev.n).padStart(2, "0")} · {prev.title}</span>
          </a>
        ) : (
          <a href="#/" onClick={(e) => { e.preventDefault(); go("home"); }}>
            <span className="label">← Back</span>
            <span className="name">README</span>
          </a>
        )}
        {next && (
          <a className="next" href={"#/chapter/" + next.slug} onClick={(e) => { e.preventDefault(); go("chapter", next.slug); }}>
            <span className="label">Next →</span>
            <span className="name">{String(next.n).padStart(2, "0")} · {next.title}</span>
          </a>
        )}
      </div>
    </div>
  );
}

function AboutPage({ go }) {
  return (
    <div className="content" data-screen-label="About">
      <div className="chapter-eyebrow">$ WHOAMI</div>
      <h1 className="page-title">Polymarket Infrastructure Builder</h1>
      <p className="lede">
        Since early 2026, full-time on Polymarket:

        published the only open-source
        <a href="https://github.com/OrderBookTrade/rs-builder-relayer-client" target="_blank" rel="noopener noreferrer">Rust builder & relayer sdk</a>,
        shipped <a href="https://ghostguard.orderbook.trade/" target="_blank" rel="noopener noreferrer"> GhostGuard</a>,
        and spent the last three weeks in

        <a href="https://discord.com/channels/710897173927297116/1494725100103139550" target="_blank" rel="noopener noreferrer">
          #dev-v2-migration-questions
        </a>

        doing the on-chain forensics behind this guide.
      </p>

      <h2 className="section-title">What I actually do</h2>
      <div className="prose">

        <p>
          Read the protocol source until I understand it better
          than the docs, write the smallest reference implementation
          that works, run it against the live network until the
          edge cases stop.
        </p>

        <p>
          That loop produced the rs-builder-relayer-client
          (paid, unsolicited, by a V2 integrator), a Cantina bounty
          submission on the V1 CTF Exchange, and this guide.

        </p>


        <p>
          Why this guide exists.
        </p>

        <p>
          I ran the V1→V2 migration on my own stack first. Six places
          where the official docs are stale, contradicted by on-chain
          behavior, or publicly retracted by the Polymarket team —
          I have the Discord screenshots. Rather than write a thread,
          I wrote nine scripts.
        </p>

        <p>
          <strong> Hire me for </strong>
          <p>Per-maker V2 migration audit</p>
          <p>20-min paid scoping to figure out whether you need the audit or just the checklist.</p>
          <p>Rust / TS / Python — all V2, all tested against clob-v2 live.</p>
        </p>
      </div>

      <h2 className="section-title">Selected work</h2>
      <div className="prose">
        {/* <p><strong>A top-5 Polymarket MM · 2024–present.</strong> Full CLOB client + signing layer in Rust. Cutover from their internal V0 to V1 with zero missed quotes.</p> */}
        {/* <p><strong>A dYdX v3 → v4 migration · 2024.</strong> Position reconciliation across two completely different chains. 14 days, $0 stuck capital.</p> */}
        {/* <p><strong>An HFT desk on Hyperliquid · 2023.</strong> Sub-millisecond order router, direct WS multiplexing, custom nonce strategy.</p> */}
      </div>
    </div>
  );
}

function HirePage({ go }) {
  return (
    <div className="content" data-screen-label="Hire">
      <div className="chapter-eyebrow">$ ./hire.sh --v2-migration</div>
      <h1 className="page-title">Get your team through 4/28 without losing a session.</h1>
      <p className="lede">
        Three lanes, sized for where you are. All start with a 30-minute call where I read your current integration and tell you — honestly — whether you need me.
      </p>

      <div className="hire-shell">
        <div className="line"><span className="prompt">$</span> ./hire.sh --list-packages</div>
        <div className="line"><span className="muted">» resolving availability…  loading packages.json</span></div>
        <div className="line"><span className="ok">✓ 3 packages</span>   <span className="muted">· 4/28 cutover: T−4d · slots: 2 remaining</span></div>
        <div className="line"><span className="divider">──────────────────────────────────────────────</span></div>

        <div className="hire-packages">
          <div className="hire-pkg">
            <div className="pkg-head">
              <span className="pkg-name">scoping-call</span>
              <span className="pkg-tag">lane 01</span>
            </div>
            <div className="pkg-price">$300<span className="unit">· 30 min · credit against any further work</span></div>
            <ul>
              <li>I read your V1 integration before the call</li>
              <li>On the call: which of the 6 known V2 doc gaps hit you, which approval targets you're missing, whether your signing path survives 4/28</li>
              <li>Written follow-up within 24h: prioritized checklist, estimated surface area, go/no-go on whether you need me</li>
            </ul>
            <a href="#" className="pkg-cta">./book --lane=scope →</a>
          </div>

          <div className="hire-pkg featured">
            <div className="pkg-head">
              <span className="pkg-name">migration-audit</span>
              <span className="pkg-tag">lane 02</span>
            </div>
            <div className="pkg-price">$2k–$8k<span className="unit">· 3–7 days · fixed scope from the scoping call</span></div>
            <ul>
              <li>Full read of your V1 integration against V2 spec</li>
              <li>Written gap analysis, exact fields + contract addresses + approval targets</li>
              <li>Tested repro of the gaps that apply to you</li>
              <li>One 90-min walkthrough; one async Q&A round</li>
              <li>Scope and price locked in writing after lane 01</li>
            </ul>
            <a href="#" className="pkg-cta">./book --lane=audit →</a>
          </div>

          <div className="hire-pkg">
            <div className="pkg-head">
              <span className="pkg-name">cutover-day</span>
              <span className="pkg-tag">lane 03</span>
            </div>
            <div className="pkg-price">$3k flat<span className="unit">· 4/28 only · 2 slots</span></div>
            <ul>
              <li>I'm in your Slack from 09:00 UTC through 13:00 UTC (90 min before cutover, 90 min after)</li>
              <li>Live diagnosis while the migration runs</li>
              <li>Post-cutover balance/allowance sanity check</li>
              <li>Requires lane 02 completed, or equivalent stack read I've done</li>
            </ul>
            <a href="#" className="pkg-cta">./book --lane=cutover →</a>
          </div>
        </div>

        <div className="line"><span className="divider">──────────────────────────────────────────────</span></div>
        <div className="line"><span className="prompt">$</span> <span className="muted"># Rust V2 stack licensing / sponsorship: rust@orderbook.trade</span></div>
        <div className="line"><span className="prompt">$</span> <span className="muted"># Post-4/28 retainer: available from May, talk to me then</span></div>
        <div className="line"><span className="prompt">$</span> <span className="cursor" style={{ display: "inline-block", width: 7, height: 14, background: "var(--accent)", verticalAlign: "text-bottom", animation: "blink 1.1s steps(2,start) infinite" }}></span></div>
      </div>

      <div className="admonition info">
        <div className="title"><span className="glyph">ℹ</span> No-bullshit guarantee</div>
        <p>If on our intro call I don't think I'm the right fit — too small, too big, already handled — I'll say so and point you at someone who is. I'd rather skip a project than ship a bad one.</p>
      </div>
    </div>
  );
}

Object.assign(window, { HomePage, ChapterPage, AboutPage, HirePage });
