// FPDS Docs — full documentation system.
// Layout: fixed sidebar + scrollable content with breadcrumbs, language-tagged
// code blocks, prev/next navigation, and rich cross-linking.

// ============================================================================
// SIDEBAR TREE
// ============================================================================

const DOCS_SIDEBAR = [
  {
    id: 'getting-started', label: 'Getting Started', top: true,
    icon: <><path d="M12 2l8 4v6c0 5-3.4 9.3-8 10-4.6-.7-8-5-8-10V6z"/><polyline points="9 12 11 14 15 10"/></>,
  },
  {
    id: 'api', label: 'REST API Reference', children: [
      { id: 'api', label: 'Overview' },
      { id: 'api/discovery', label: 'Discovery & Navigation' },
      { id: 'api/spending', label: 'Spending & Market Structure' },
      { id: 'api/vendors', label: 'Vendor Intelligence' },
      { id: 'api/topics', label: 'Topic Intelligence' },
      { id: 'api/keywords', label: 'Keyword Graph' },
      { id: 'api/contracts', label: 'Contract & Pipeline' },
      { id: 'api/search', label: 'Semantic Search' },
      { id: 'api/evidence', label: 'Evidence & Claims' },
      { id: 'api/graph', label: 'Knowledge Graph' },
      { id: 'api/analytics', label: 'Advanced Analytics' },
      { id: 'api/artifacts', label: 'Intelligence Artifacts' },
      { id: 'api/source-material', label: 'Source Material' },
      { id: 'api/sql-lookup', label: 'SQL Lookup' },
    ],
  },
  {
    id: 'mcp', label: 'MCP Server', top: true,
    icon: <><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></>,
  },
  {
    id: 'sdk', label: 'Python SDK', top: true,
    icon: <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>,
  },
  {
    id: 'reference', label: 'Glossary', children: [
      { id: 'reference', label: 'Overview' },
      { id: 'reference/glossary/core', label: 'Glossary: Core Concepts' },
      { id: 'reference/glossary/ontology', label: 'Glossary: Object Types' },
      { id: 'reference/glossary/links', label: 'Glossary: Link Types' },
      { id: 'reference/glossary/codes', label: 'Glossary: Department Codes' },
      { id: 'reference/glossary/tiers', label: 'Glossary: Tiered Access' },
      { id: 'reference/glossary/families', label: 'Glossary: API & Tool Families' },
      { id: 'reference/glossary/data', label: 'Glossary: Data Terms' },
      { id: 'reference/glossary/methodology', label: 'Glossary: Methodology' },
      { id: 'reference/glossary/tools', label: 'Glossary: Tools & Technologies' },
      { id: 'reference/conventions', label: 'Error Codes & Conventions' },
    ],
  },
];

// ============================================================================
// SVG ICON HELPER (mini inline SVGs, matching site's Icon component)
// ============================================================================

const SideIcon = ({ children }) => (
  <svg
    className="docs-sidebar-icon"
    viewBox="0 0 24 24" fill="none"
    stroke="currentColor" strokeWidth="1.8"
    strokeLinecap="round" strokeLinejoin="round"
    width={15} height={15}
  >
    {children}
  </svg>
);

// ============================================================================
// SIDEBAR COMPONENT
// ============================================================================

const DocsSidebar = ({ current, onNavigate }) => {
  const mobileMenu = useMobileSidebar(current, onNavigate);
  const [openSections, setOpenSections] = React.useState(() => {
    const open = new Set();
    for (const group of DOCS_SIDEBAR) {
      if (group.children && (current === group.id || current.startsWith(group.id + '/') || group.id === 'api')) {
        open.add(group.id);
      }
    }
    return open;
  });

  const toggleSection = (id) => {
    setOpenSections(prev => { const next = new Set(prev); next.has(id) ? next.delete(id) : next.add(id); return next; });
  };

  const isActive = (id) => {
    if (id === current) return true;
    if (id === 'getting-started' && !current) return true;
    return false;
  };

  const isParentActive = (children) => children.some(c => c.id === current || current.startsWith(c.id + '/'));

  const renderSidebar = () => (
    <aside className="docs-sidebar">
      {DOCS_SIDEBAR.map(group => {
        if (group.top) {
          return (
            <a key={group.id} href={'#/docs/' + group.id}
              className={'docs-sidebar-link--top' + (isActive(group.id) ? ' docs-sidebar-link--active' : '')}
              onClick={(e) => { e.preventDefault(); onNavigate(group.id); }}
            >
              <SideIcon>{group.icon}</SideIcon>
              {group.label}
            </a>
          );
        }
        const isOpen = openSections.has(group.id);
        const hasActiveChild = isParentActive(group.children);
        return (
          <div key={group.id} className="docs-sidebar-section">
            <button
              className={'docs-sidebar-heading' + (isOpen ? ' docs-sidebar-heading--open' : '')}
              onClick={() => toggleSection(group.id)}
              style={hasActiveChild ? { color: 'var(--kenosa-navy)' } : {}}
            >
              {group.label}
              <svg className="chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                <polyline points="9 6 15 12 9 18"/>
              </svg>
            </button>
            <div className={'docs-sidebar-children' + (isOpen ? ' docs-sidebar-children--open' : '')}>
              {group.children.map(child => (
                <a key={child.id} href={'#/docs/' + child.id}
                  className={'docs-sidebar-link' + (isActive(child.id) ? ' docs-sidebar-link--active' : '')}
                  onClick={(e) => { e.preventDefault(); onNavigate(child.id); }}
                >
                  {child.label}
                </a>
              ))}
            </div>
          </div>
        );
      })}
    </aside>
  );

  return (
    <>
      <button className="docs-mobile-nav-toggle" onClick={mobileMenu.toggle} aria-label={mobileMenu.open ? 'Close nav' : 'Open nav'}>
        {mobileMenu.open ? (
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
        ) : (
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
        )}
      </button>
      {renderSidebar()}
      {mobileMenu.open && (
        <div role="dialog" aria-modal="true" aria-label="Docs navigation"
          style={{ position:'fixed', inset:0, zIndex:25, background:'var(--white)', padding:'88px 0 24px', overflowY:'auto', animation:'mobileMenuFade 0.18s ease-out' }}>
          {DOCS_SIDEBAR.map(group => {
            if (group.top) {
              return (
                <a key={group.id} href={'#/docs/' + group.id}
                  style={{ display:'block', padding:'14px 24px', fontSize:16, fontWeight:700,
                    color: isActive(group.id) ? 'var(--kenosa-navy)' : 'var(--slate-700)',
                    borderBottom:'1px solid var(--slate-100)', textDecoration:'none',
                    background: isActive(group.id) ? 'rgba(0,0,128,0.04)' : 'transparent' }}
                  onClick={(e) => { e.preventDefault(); mobileMenu.close(); onNavigate(group.id); }}
                >{group.label}</a>
              );
            }
            const isOpen = openSections.has(group.id);
            return (
              <div key={group.id}>
                <button onClick={() => toggleSection(group.id)}
                  style={{ display:'flex', alignItems:'center', justifyContent:'space-between',
                    width:'100%', padding:'14px 24px', border:'none', borderBottom:'1px solid var(--slate-100)',
                    background:'transparent', fontSize:16, fontWeight:700, color:'var(--slate-700)', cursor:'pointer' }}>
                  {group.label}
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"
                    style={{ transform: isOpen ? 'rotate(90deg)' : 'none', transition:'transform 0.2s' }}>
                    <polyline points="9 6 15 12 9 18"/>
                  </svg>
                </button>
                {isOpen && group.children.map(child => (
                  <a key={child.id} href={'#/docs/' + child.id}
                    style={{ display:'block', padding:'12px 24px 12px 40px', fontSize:14,
                      color: isActive(child.id) ? 'var(--kenosa-navy)' : 'var(--slate-500)',
                      borderBottom:'1px solid var(--slate-50)', textDecoration:'none',
                      background: isActive(child.id) ? 'rgba(0,0,128,0.04)' : 'transparent',
                      fontWeight: isActive(child.id) ? 600 : 400 }}
                    onClick={(e) => { e.preventDefault(); mobileMenu.close(); onNavigate(child.id); }}
                  >{child.label}</a>
                ))}
              </div>
            );
          })}
        </div>
      )}
    </>
  );
};

const useMobileSidebar = (current, onNavigate) => {
  const [open, setOpen] = React.useState(false);
  React.useEffect(() => { document.body.style.overflow = open ? 'hidden' : ''; return () => { document.body.style.overflow = ''; }; }, [open]);
  React.useEffect(() => { const onHash = () => setOpen(false); window.addEventListener('hashchange', onHash); return () => window.removeEventListener('hashchange', onHash); }, []);
  return { open, toggle: () => setOpen(o => !o), close: () => setOpen(false) };
};

// ============================================================================
// REUSABLE COMPONENTS
// ============================================================================

const TierBadge = ({ tier }) => {
  const map = { 'Public':'public', 'T0.5':'t05', 'T1':'t1', 'T2':'t2', 'T3':'t3', 'Enterprise':'custom', 'Custom':'custom' };
  return <span className={'docs-tier docs-tier--' + (map[tier] || 'public')}>{tier}</span>;
};

const Breadcrumb = ({ items }) => (
  <nav className="docs-breadcrumb">
    {items.map((item, i) => (
      <React.Fragment key={i}>
        {i > 0 && <span className="docs-breadcrumb-sep">/</span>}
        {item.href
          ? <a href={item.href} onClick={item.onClick ? (e) => { e.preventDefault(); item.onClick(); } : undefined}>{item.label}</a>
          : <span className="docs-breadcrumb-current">{item.label}</span>}
      </React.Fragment>
    ))}
  </nav>
);

const EndpointTable = ({ endpoints }) => (
  <div className="docs-table-wrap">
    <table className="docs-table">
      <thead><tr><th>Method &amp; Path</th><th>Tier</th><th>Description</th></tr></thead>
      <tbody>
        {endpoints.map((ep, i) => (
          <tr key={i}>
            <td><strong>{ep.method}</strong> <code>{ep.path}</code></td>
            <td><TierBadge tier={ep.tier}/></td>
            <td>{ep.desc}</td>
          </tr>
        ))}
      </tbody>
    </table>
  </div>
);

const ToolTable = ({ tools }) => (
  <div className="docs-table-wrap">
    <table className="docs-table">
      <thead><tr><th>Tool</th><th>Tier</th><th>Description</th></tr></thead>
      <tbody>
        {tools.map((t, i) => (
          <tr key={i}>
            <td><code>{t.name}</code></td>
            <td><TierBadge tier={t.tier}/></td>
            <td>{t.desc}</td>
          </tr>
        ))}
      </tbody>
    </table>
  </div>
);

const CodeBlock = ({ lang, code }) => {
  const [copied, setCopied] = React.useState(false);
  const langClass = {
    curl: 'curl', python: 'python', json: 'json', bash: 'bash', text: 'text',
    js: 'js', javascript: 'js',
  };
  const langDot = {
    curl: 'blue', python: 'green', json: 'yellow', bash: 'red', text: 'gray', js: 'purple',
  };
  const lc = langClass[lang] || 'text';
  const ld = langDot[lang] || 'gray';

  const copy = () => {
    navigator.clipboard.writeText(code).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1800);
    }).catch(() => {});
  };

  return (
    <div className="docs-code-block">
      <div className="docs-code-header">
        <span className={'docs-code-lang docs-code-lang--' + lc}>
          <span className={'docs-code-lang-dot docs-code-dot--' + ld}/> {lang}
        </span>
        <button className={'docs-code-copy' + (copied ? ' docs-code-copy--done' : '')} onClick={copy}>
          {copied ? 'COPIED' : 'COPY'}
        </button>
      </div>
      <pre className="docs-code-body">{code}</pre>
    </div>
  );
};

const PrevNext = ({ prev, next, onNavigate }) => (
  <div className="docs-prevnext">
    {prev ? (
      <a href={'#/docs/' + prev.id} className="docs-prevnext-link docs-prevnext-link--prev"
        onClick={(e) => { e.preventDefault(); onNavigate(prev.id); }}>
        <span className="docs-prevnext-label">Previous</span>
        <span className="docs-prevnext-title">{prev.label}</span>
      </a>
    ) : <div/>}
    {next ? (
      <a href={'#/docs/' + next.id} className="docs-prevnext-link docs-prevnext-link--next"
        onClick={(e) => { e.preventDefault(); onNavigate(next.id); }}>
        <span className="docs-prevnext-label">Next</span>
        <span className="docs-prevnext-title">{next.label}</span>
      </a>
    ) : <div/>}
  </div>
);

const Note = ({ type, children }) => (
  <div className={'docs-note' + (type ? ' docs-note--' + type : '')}>{children}</div>
);

// ============================================================================
// GETTING STARTED
// ============================================================================

const GettingStarted = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[{ label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') }, { label:'Getting Started' }]} />
    <div className="docs-hero">
      <h1>Getting Started with FPDS</h1>
      <p>
        FPDS provides a unified API for federal procurement intelligence — spanning
        REST endpoints, an MCP server for AI agents, and a typed Python SDK. This
        guide walks you through your first request in under 3 minutes.
      </p>
    </div>

    <h2>1. Get an API Key</h2>
    <p>Request a free <strong>Public-tier key</strong> at the <a href="#/signup?tier=public">signup page</a>. It's email-verified: we send a 6-digit code, and the key is issued once (also emailed). Or do it directly with the API:</p>
    <CodeBlock lang="curl" code={`# Step 1: request (a 6-digit code is emailed to you)
curl -X POST https://analytics-api.kenosaconsulting.com/v1/keys/request \\
  -H "Content-Type: application/json" \\
  -d '{"email": "you@example.com", "name": "Your Name",
       "organization": "Acme", "intended_use": "Capture research", "tier": "public"}'

# Response
{ "request_id": "8b0858f6-...", "message": "Verification code sent to your email.",
  "expires_in_seconds": 900, "email_sent": true }

# Step 2: verify the emailed code (key returned ONCE)
curl -X POST https://analytics-api.kenosaconsulting.com/v1/keys/verify \\
  -H "Content-Type: application/json" \\
  -d '{"request_id": "8b0858f6-...", "code": "123456"}'

# Response
{ "api_key": "fpds_public_k...", "tier": "public", "expires_at": null,
  "message": "Store this key securely; it will not be shown again." }`} />
    <Note>Store your key securely. Keys have a <code>fpds_&lt;tier&gt;_k...</code> prefix that encodes your tier. We store a SHA-256 hash, not the key itself. Paid tiers (Explorer, Professional, Advanced) purchase via Stripe checkout — your key arrives by email after payment.</Note>

    <h2>2. Make Your First Call</h2>
    <p>Every FPDS workflow starts by resolving an agency name to a code:</p>
    <CodeBlock lang="curl" code={`curl -s "https://analytics-api.kenosaconsulting.com/v1/resolve?q=Defense" \\
  -H "X-Api-Key: fpds_public_k..."`} />

    <h2>3. Explore What's Available</h2>
    <div className="docs-card-grid">
      <a href="#/docs/api/discovery" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('api/discovery'); }}>
        <h3>Discovery Tools</h3>
        <p>List datasets, look up codes, resolve names — the entry points to every procurement workflow.</p>
      </a>
      <a href="#/docs/api/spending" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('api/spending'); }}>
        <h3>Spending Data</h3>
        <p>Query 91 pre-built analytics datasets — competition, pricing, concentration, geography, and more.</p>
      </a>
      <a href="#/docs/api/vendors" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('api/vendors'); }}>
        <h3>Vendor Intelligence</h3>
        <p>Profile federal contractors by spend, NAICS concentration, agency footprint, and recompete pipeline.</p>
      </a>
      <a href="#/docs/mcp" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('mcp'); }}>
        <h3>MCP Server</h3>
        <p>Use FPDS tools inside Claude and other AI agents via the Model Context Protocol.</p>
      </a>
      <a href="#/docs/sdk" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('sdk'); }}>
        <h3>Python SDK</h3>
        <p>Typed Python client with ontology entity classes. Link traversals ship with the knowledge graph.</p>
      </a>
      <a href="#/docs/analytics" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('analytics'); }}>
        <h3>Methodology</h3>
        <p>How topic modeling, keyword extraction, embeddings, and evidence scoring work under the hood.</p>
      </a>
    </div>

    <h2>4. Choose Your Tier</h2>
    <p>FPDS offers 6 access tiers — from free discovery to custom enterprise contracts. Each tier unlocks deeper layers of the procurement substrate.</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Tier</th><th>Price/seat/mo</th><th>Key Capabilities</th><th>Rate Limit</th></tr></thead>
        <tbody>
          <tr><td><TierBadge tier="Public"/></td><td>Free</td><td>7 discovery tools, ~10 demo datasets</td><td>50 req/day</td></tr>
          <tr><td><TierBadge tier="T0.5"/></td><td>$75</td><td>Keyword and topic tools, 40 datasets, 3 depts</td><td>250 req/day</td></tr>
          <tr><td><TierBadge tier="T1"/></td><td>$800</td><td>Full data surfaces, vendor profiles, corpus_search (capped, 500/mo)</td><td>1,250 req/day</td></tr>
          <tr><td><TierBadge tier="T2"/></td><td>$5,000</td><td>Full keyword graph, analytics_query, evidence claims, KG edges, all depts, full history</td><td>5,000 req/day</td></tr>
          <tr><td><TierBadge tier="T3"/></td><td>$18,000</td><td>Full corpus_search, AI artifacts (5/day ours, 10/day BYO), orchestrate_capture, KG full</td><td>12,500 req/day</td></tr>
          <tr><td><TierBadge tier="Custom"/></td><td>Negotiated</td><td>Convergence scoring, Markov transitions, tensor decomposition, anomaly detection, graph traversal, white-label, dedicated capacity</td><td>Negotiated</td></tr>
        </tbody>
      </table>
    </div>
    <Note type="tip">Multi-seat discounts available at 10+ seats for T2 and T3. Annual billing saves 20% across the self-serve tiers (Explorer, Professional, Advanced) — Enterprise annual saves 30%. See the <a href="#/pricing">pricing page</a> for full details.</Note>

    <h2>Authentication Methods</h2>
    <p>The REST API validates every request against our key store — tier, rate limits, expiry, and revocation are all enforced server-side. Pass your key in the <code>X-Api-Key</code> header.</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Method</th><th>Header</th><th>Best For</th></tr></thead>
        <tbody>
          <tr><td>API Key</td><td><code>X-Api-Key: fpds_tier1_k...</code></td><td>REST calls from scripts, backends, curl</td></tr>
          <tr><td>Bearer Token</td><td><code>Authorization: Bearer fpds_...</code></td><td>MCP server connections, same key</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Rate Limits & Headers</h2>
    <p>Every keyed response carries rate-limit headers; exceeding a cap returns <code>429</code> with a <code>rate_limited</code> error envelope:</p>
    <CodeBlock lang="http" code={`X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 43

// 429 envelope
{ "error": { "type": "rate_limited", "code": "rate_limited",
             "message": "Rate limit exceeded. Retry after the reset window." } }`} />
    <p>Errors use one envelope everywhere: <code>{`{"error": {type, code, message, param, request_id}}`}</code>. Insufficient tier returns <code>upgrade_required</code> pointing at the pricing page.</p>

    <h2>Keys & Billing Endpoints</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Endpoint</th><th>Purpose</th></tr></thead>
        <tbody>
          <tr><td><code>POST /v1/keys/request</code></td><td>Request a Public key (email-verified, 6-digit code)</td></tr>
          <tr><td><code>POST /v1/keys/verify</code></td><td>Redeem the code — key returned once</td></tr>
          <tr><td><code>GET /v1/keys</code></td><td>List your keys (requires any valid key)</td></tr>
          <tr><td><code>POST /v1/keys/revoke</code></td><td>Revoke one of your keys</td></tr>
          <tr><td><code>POST /v1/billing/checkout</code></td><td>Create a Stripe checkout session for <code>t05</code> (Explorer), <code>tier1</code> (Professional), or <code>tier2</code> (Advanced)</td></tr>
          <tr><td><code>POST /v1/billing/webhook</code></td><td>Stripe checkout delivery endpoint</td></tr>
        </tbody>
      </table>
    </div>
    <Note>Explorer, Professional, and Advanced are self-serve via Stripe checkout. Enterprise and Custom are provisioned after a conversation with our team — schedule a call on the <a href="#/signup?tier=enterprise">signup page</a>.</Note>

    <PrevNext
      prev={null}
      next={{ id: 'api', label: 'REST API Reference — Overview' }}
      onNavigate={onNavigate}
    />
  </div>
);

// ============================================================================
// API: OVERVIEW
// ============================================================================

const APIOverview = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API Reference' },
    ]} />
    <div className="docs-hero">
      <h1>REST API Reference</h1>
      <p>
        The FPDS REST API serves 80+ endpoints organized into 14 families — from
        discovery and spending datasets to semantic search, evidence claims, and
        advanced analytics. All tier-gated with cumulative access levels.
        All endpoints live under <code>https://analytics-api.kenosaconsulting.com/v1/</code>.
      </p>
    </div>

    <h2>Base URL &amp; Versioning</h2>
    <p>All endpoints are versioned under <code>/v1/</code>. Breaking changes will increment to <code>/v2/</code> with a deprecation window. Non-breaking additions (new endpoints, new fields, new optional parameters) are added within the current version.</p>
    <CodeBlock lang="text" code={`Base:  https://analytics-api.kenosaconsulting.com/v1/
MCP:   https://analytics-api.kenosaconsulting.com/mcp`} />

    <h2>Authentication</h2>
    <p>Three methods — all resolve to the same tier:</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Method</th><th>Header</th><th>Use Case</th></tr></thead>
        <tbody>
          <tr><td><strong>API Key</strong></td><td><code>X-Api-Key: fpds_tier1_k...</code></td><td>REST calls from scripts, backends, curl</td></tr>
          <tr><td><strong>Bearer Token</strong></td><td><code>Authorization: Bearer fpds_tier1_k...</code></td><td>MCP connections (same key format)</td></tr>
        </tbody>
      </table>
    </div>
    <CodeBlock lang="curl" code={`# API Key (preferred for REST)
curl -s "https://analytics-api.kenosaconsulting.com/v1/resolve?q=Defense" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Bearer Token (MCP, programmatic)
curl -s "https://analytics-api.kenosaconsulting.com/v1/catalog" \\
  -H "Authorization: Bearer fpds_tier2_k..."`} />

    <h2>Request Format</h2>
    <p>All endpoints accept <strong>GET</strong> requests with query parameters. No POST bodies for data retrieval. Filters are passed as query string parameters:</p>
    <CodeBlock lang="text" code={`/v1/datasets/{dataset_id}/rows?department_code=7000&fy_min=2022&fy_max=2025&limit=25`} />
    <p><strong>Path parameters</strong> use <code>{'{'}{'}'}</code> notation (e.g. <code>{'{'}dataset_id{'}'}</code>). <strong>Query parameters</strong> use standard <code>?key=value&amp;key=value</code> format. <strong>Array parameters</strong> accept comma-separated values.</p>

    <h2>Response Envelope</h2>
    <p>All successful responses return 200 and follow this envelope:</p>
    <CodeBlock lang="json" code={`{
  "notice": "Data from FPDS Analytics API. Obligations are nominal.",
  "data": { ... },
  "pagination": { "limit": 25, "next_cursor": "eyJvZmZz..." },
  "meta": {
    "api_version": "2026-06-02",
    "row_count": 5,
    "caveats": [
      "Obligation data updated through FY2026 Q2"
    ],
    "notices": [
      "Award counts may be sparse for some departments"
    ],
    "access": "tier2",
    "source_fiscal_years": [2018, 2025],
    "data_as_of": "2026-07-31T00:00:00"
  }
}`} />
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Field</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td><code>notice</code></td><td>Standard FPDS data usage notice</td></tr>
          <tr><td><code>data</code></td><td>The response payload — varies by endpoint</td></tr>
          <tr><td><code>pagination.limit</code></td><td>Rows requested (default 25)</td></tr>
          <tr><td><code>pagination.next_cursor</code></td><td>Opaque cursor for the next page; null if no more results</td></tr>
          <tr><td><code>meta.api_version</code></td><td>API version date (YYYY-MM-DD)</td></tr>
          <tr><td><code>meta.row_count</code></td><td>Number of rows in this response</td></tr>
          <tr><td><code>meta.caveats</code></td><td>Data quality caveats specific to this response</td></tr>
          <tr><td><code>meta.notices</code></td><td>General notices about data coverage or limitations</td></tr>
          <tr><td><code>meta.access</code></td><td>Your resolved tier level (public, beta, tier1, tier2, tier3)</td></tr>
          <tr><td><code>meta.source_fiscal_years</code></td><td>Min and max FY in the underlying data</td></tr>
          <tr><td><code>meta.data_as_of</code></td><td>ISO 8601 timestamp of last data refresh</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Pagination</h2>
    <p>All list endpoints use <strong>cursor-based pagination</strong>. Pass the <code>next_cursor</code> value from a response as the <code>cursor</code> parameter to get the next page. When <code>next_cursor</code> is null, you've reached the end. Cursor tokens are opaque and may expire — do not store them long-term.</p>
    <CodeBlock lang="curl" code={`# Page 1
curl -s ".../datasets/competition.trend_fy/rows?department_code=7000&limit=25" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Page 2 (using cursor from page 1's pagination.next_cursor)
curl -s ".../datasets/competition.trend_fy/rows?cursor=eyJvZmZzIjoyNX0" \\
  -H "X-Api-Key: fpds_tier1_k..."`} />

    <h2>Filtering &amp; Sorting</h2>
    <p>Each dataset and dimension has an <strong>allowlist</strong> of accepted filter keys, sort columns, and returnable fields. Use <code>fpds_describe_dataset</code> to inspect what's available before querying. Invalid filters, fields, or sort values return a 400 error with the offending parameter named.</p>

    <h2>Error Responses</h2>
    <p>Errors return the appropriate HTTP status (400, 401, 403, 404, 429, 500) with this envelope:</p>
    <CodeBlock lang="json" code={`{
  "error": {
    "type": "not_found",
    "code": "dataset_not_found",
    "message": "Unknown dataset_id 'nonexistent'.",
    "param": "dataset_id",
    "request_id": "req_a1b2c3d4e5f6"
  }
}`} />
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Code</th><th>HTTP</th><th>When</th></tr></thead>
        <tbody>
          <tr><td><code>dataset_not_found</code></td><td>404</td><td>Unknown dataset_id</td></tr>
          <tr><td><code>dimension_not_found</code></td><td>404</td><td>Unknown dimension_id</td></tr>
          <tr><td><code>invalid_filter</code></td><td>400</td><td>Filter key or value not in allowlist</td></tr>
          <tr><td><code>invalid_field</code></td><td>400</td><td>Requested field not in allowlist</td></tr>
          <tr><td><code>invalid_sort</code></td><td>400</td><td>Sort column not in allowlist</td></tr>
          <tr><td><code>rate_limited</code></td><td>429</td><td>Daily or burst limit exceeded — check <code>X-RateLimit-Reset</code></td></tr>
          <tr><td><code>upgrade_required</code></td><td>403</td><td>Tool requires a higher tier — upgrade URL in message</td></tr>
          <tr><td><code>unauthorized</code></td><td>401</td><td>Missing or invalid API key</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Rate Limiting</h2>
    <p>Rate limits are per API key (not per IP) and tier-dependent. Every response includes:</p>
    <CodeBlock lang="text" code={`X-RateLimit-Limit: 120       # per-minute burst ceiling for your tier
X-RateLimit-Remaining: 117   # remaining calls in current minute
X-RateLimit-Reset: 43        # seconds until the minute window resets`} />
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Tier</th><th>Daily Limit</th><th>Burst (req/min)</th><th>Rows/req</th></tr></thead>
        <tbody>
          <tr><td><TierBadge tier="Public"/></td><td>50</td><td>20</td><td>50</td></tr>
          <tr><td><TierBadge tier="T0.5"/></td><td>250</td><td>50</td><td>125</td></tr>
          <tr><td><TierBadge tier="T1"/></td><td>1,250</td><td>120</td><td>250</td></tr>
          <tr><td><TierBadge tier="T2"/></td><td>5,000</td><td>300</td><td>500</td></tr>
          <tr><td><TierBadge tier="T3"/></td><td>12,500</td><td>600</td><td>1,000</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Tool Families at a Glance</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th></th><th>Family</th><th>What It Answers</th><th>Tools</th></tr></thead>
        <tbody>
          <tr><td>A</td><td><a href="#/docs/api/discovery" onClick={(e) => { e.preventDefault(); onNavigate('api/discovery'); }}>Discovery &amp; Navigation</a></td><td>What's available and how do I find things?</td><td>7</td></tr>
          <tr><td>B</td><td><a href="#/docs/api/spending" onClick={(e) => { e.preventDefault(); onNavigate('api/spending'); }}>Spending &amp; Market Structure</a></td><td>Who spends how much on what?</td><td>91 datasets</td></tr>
          <tr><td>C</td><td><a href="#/docs/api/vendors" onClick={(e) => { e.preventDefault(); onNavigate('api/vendors'); }}>Vendor Intelligence</a></td><td>Who are the players and where are they strong?</td><td>3</td></tr>
          <tr><td>D</td><td><a href="#/docs/api/topics" onClick={(e) => { e.preventDefault(); onNavigate('api/topics'); }}>Topic Intelligence</a></td><td>What does the government actually buy?</td><td>8+</td></tr>
          <tr><td>E</td><td><a href="#/docs/api/keywords" onClick={(e) => { e.preventDefault(); onNavigate('api/keywords'); }}>Keyword Graph</a></td><td>What capabilities appear in contract language?</td><td>5 (coming soon)</td></tr>
          <tr><td>F</td><td><a href="#/docs/api/contracts" onClick={(e) => { e.preventDefault(); onNavigate('api/contracts'); }}>Contract &amp; Pipeline</a></td><td>What was awarded and when does it expire?</td><td>5</td></tr>
          <tr><td>G</td><td><a href="#/docs/api/search" onClick={(e) => { e.preventDefault(); onNavigate('api/search'); }}>Semantic Search</a></td><td>What do strategic documents say about a topic?</td><td>1</td></tr>
          <tr><td>H</td><td><a href="#/docs/api/evidence" onClick={(e) => { e.preventDefault(); onNavigate('api/evidence'); }}>Evidence &amp; Claims</a></td><td>What's the evidence behind a statement?</td><td>5 reads</td></tr>
          <tr><td>I</td><td><a href="#/docs/api/graph" onClick={(e) => { e.preventDefault(); onNavigate('api/graph'); }}>Knowledge Graph</a></td><td>How are entities connected?</td><td>8 reads</td></tr>
          <tr><td>J</td><td><a href="#/docs/api/analytics" onClick={(e) => { e.preventDefault(); onNavigate('api/analytics'); }}>Advanced Analytics</a></td><td>What patterns and anomalies emerge?</td><td>6+</td></tr>
          <tr><td>K</td><td><a href="#/docs/api/artifacts" onClick={(e) => { e.preventDefault(); onNavigate('api/artifacts'); }}>Intelligence Artifacts</a></td><td>Generate structured reports.</td><td>3</td></tr>
          <tr><td>M</td><td><a href="#/docs/api/sql-lookup" onClick={(e) => { e.preventDefault(); onNavigate('api/sql-lookup'); }}>SQL Lookup</a></td><td>Scaffolding for tables not yet in REST.</td><td>1</td></tr>
          <tr><td>N</td><td><a href="#/docs/api/source-material" onClick={(e) => { e.preventDefault(); onNavigate('api/source-material'); }}>Source Material</a></td><td>Access raw documents and records.</td><td>7</td></tr>
        </tbody>
      </table>
    </div>

    <PrevNext prev={{ id:'getting-started', label:'Getting Started' }} next={{ id:'api/discovery', label:'Discovery & Navigation' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// API FAMILY A: DISCOVERY & NAVIGATION
// ============================================================================

const APIDiscovery = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Discovery & Navigation' },
    ]} />
    <div className="docs-hero">
      <h1>Discovery &amp; Navigation</h1>
      <p>
        Family A tools help you discover what data is available, look up codes, and
        resolve plain-English names to FPDS identifiers. These are the entry points to
        every workflow — all available at the <TierBadge tier="Public"/> tier.
      </p>
    </div>

    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/catalog', tier:'Public', desc:'List all available datasets, filterable by domain. Returns dataset IDs, names, descriptions, grain, and row counts. Accepts ?domain=pricing|competition|...' },
      { method:'GET', path:'/v1/datasets/{dataset_id}', tier:'Public', desc:'Describe one dataset: fields, filters, grain, caveats, example query, and allowed sort columns. Always call this before querying an unfamiliar dataset.' },
      { method:'GET', path:'/v1/datasets/{dataset_id}/rows', tier:'Public*', desc:'Query dataset rows with filters, field selection, sorting, and pagination. *Only public_bounded datasets without auth; gated datasets require T3.' },
      { method:'GET', path:'/v1/dimensions', tier:'Public', desc:'List all 7 code-lookup dimensions with counts. Each returns its dimension_id for use in lookup queries.' },
      { method:'GET', path:'/v1/dimensions/{dimension_id}', tier:'Public', desc:'Search dimension values by substring (q=) or exact filters. Supports pagination via cursor. Returns code, name, and related mappings.' },
      { method:'GET', path:'/v1/health', tier:'Public', desc:'Health check: database reachable, catalog loaded. Returns version, uptime, and DB status.' },
      { method:'GET', path:'/v1', tier:'Public', desc:'Service root: name, version, docs link, and public tool inventory.' },
    ]} />

    <h2>Dimensions Reference</h2>
    <p>The 7 dimension types available for code lookup. Each is queried via <code>/v1/dimensions/{'{'}dimension_id{'}'}</code>:</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>dimension_id</th><th>Contains</th><th>Example Query</th></tr></thead>
        <tbody>
          <tr><td><code>naics</code></td><td>NAICS industry codes (2-6 digit)</td><td><code>?q=541512</code></td></tr>
          <tr><td><code>pricing_codes</code></td><td>Contract pricing structures</td><td><code>?q=fixed</code></td></tr>
          <tr><td><code>competition_codes</code></td><td>Extent competed values</td><td><code>?q=full</code></td></tr>
          <tr><td><code>business_size_codes</code></td><td>Business size designations</td><td><code>?q=small</code></td></tr>
          <tr><td><code>bundling_codes</code></td><td>Contract bundling categories</td><td><code>?q=bundled</code></td></tr>
          <tr><td><code>financing_codes</code></td><td>Contract financing types</td><td><code>?q=progress</code></td></tr>
          <tr><td><code>states</code></td><td>US states and territories</td><td><code>?q=Virginia</code></td></tr>
        </tbody>
      </table>
    </div>

    <h2>fpds_resolve — Universal Name Resolution</h2>
    <p><code>fpds_resolve</code> searches across all dimension types simultaneously. It's the fastest way to find the right code for a plain-English query:</p>
    <CodeBlock lang="curl" code={`# Resolve "Homeland Security" — returns department + agency + NAICS + PSC matches
curl -s "https://analytics-api.kenosaconsulting.com/v1/resolve?q=homeland" \\
  -H "X-Api-Key: fpds_public_k..."

# Response maps "homeland" → department "7000" (DHS) with FPDS/USASpending codes`} />

    <h2>Example: Discover + Query a Dataset</h2>
    <CodeBlock lang="curl" code={`# Step 1: List datasets in the 'competition' domain
curl -s "https://analytics-api.kenosaconsulting.com/v1/catalog?domain=competition" \\
  -H "X-Api-Key: fpds_public_k..."

# Step 2: Describe the trend_fy dataset to see its filters and fields
curl -s "https://analytics-api.kenosaconsulting.com/v1/datasets/competition.trend_fy" \\
  -H "X-Api-Key: fpds_public_k..."

# Step 3: Query it with filters
curl -s "https://analytics-api.kenosaconsulting.com/v1/datasets/competition.trend_fy/rows?department_code=7000&fy_min=2023&limit=10" \\
  -H "X-Api-Key: fpds_tier1_k..."`} />

    <CodeBlock lang="python" code={`from fpds import Substrate
fpds = Substrate(api_key="fpds_tier1_k...")

# List all competition datasets
datasets = fpds.list_datasets(domain="competition")

# Describe one
info = fpds.describe_dataset("competition.trend_fy")
print(info.fields, info.filters, info.caveats)

# Query with filters
rows = fpds.query_dataset("competition.trend_fy",
    department_code="7000", fy_min=2023, limit=10)`} />

    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'fpds_list_datasets', tier:'Public', desc:'List available datasets by domain with descriptions and grain.' },
      { name:'fpds_describe_dataset', tier:'Public', desc:'Inspect a dataset: fields, filters, caveats, example query.' },
      { name:'fpds_query_dataset', tier:'Public', desc:'Query bounded rows from public datasets with filters and sorting.' },
      { name:'fpds_list_dimensions', tier:'Public', desc:'List 7 code-lookup dimension types with counts.' },
      { name:'fpds_lookup_dimension', tier:'Public', desc:'Search any dimension by substring or exact filter.' },
      { name:'fpds_resolve', tier:'Public', desc:'Resolve plain-English names to FPDS codes across all dimension types.' },
      { name:'fpds_onboarding', tier:'Public', desc:'Getting-started guide loaded directly into the MCP context.' },
    ]} />

    <PrevNext prev={{ id:'api', label:'REST API — Overview' }} next={{ id:'api/spending', label:'Spending & Market Structure' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// API FAMILY B: SPENDING & MARKET STRUCTURE
// ============================================================================

const APISpending = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Spending & Market Structure' },
    ]} />
    <div className="docs-hero">
      <h1>Spending &amp; Market Structure</h1>
      <p>
        Family B covers 91 pre-built analytics datasets across 17 domains — pricing,
        competition, concentration, NAICS, geography, customer, market, incumbent,
        set-aside, PSC, acquisition, pipeline, seasonality, topics, contacts,
        entrants, and OPM. Query everything through a single endpoint.
      </p>
    </div>

    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/datasets/{dataset_id}/rows', tier:'Public*', desc:'Query any dataset by ID with filters, field selection, sorting, and pagination. *Public: 10 demo datasets. T1+: all bounded. T3: all including gated.' },
      { method:'GET', path:'/v1/profiles/customer', tier:'T1', desc:'Customer 360 for a department: spend summary, top NAICS, competition landscape, pricing trends, set-aside mix, incumbent roster, active vehicles, recompete pipeline. Accepts department_code, agency_code, and fy_min parameters.' },
      { method:'GET', path:'/v1/datasets/{dataset_id}/rows (analytics_query)', tier:'T2', desc:'Unrestricted dataset access via analytics_query MCP tool — all filters, sorts, and full row limits. Available at T2+ (MCP only, no REST path yet).' },
    ]} />

    <h2>Example: Customer Profile</h2>
    <CodeBlock lang="curl" code={`# Get a full customer 360 for DHS
curl -s "https://analytics-api.kenosaconsulting.com/v1/profiles/customer?department_code=7000&fy_min=2021" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Response includes:
# - Spend summary: total obligations, award counts, FY trends
# - Top NAICS codes with spend and vendor concentration
# - Competition landscape: competed vs sole-source breakdown
# - Pricing trends: fixed-price vs cost-type mix
# - Set-aside utilization by type
# - Top incumbent vendors with market share
# - Active contract vehicles and utilization
# - Recompete pipeline: contracts expiring within 6/12/18/24 months`} />

    <h2>Example: Query a Dataset</h2>
    <CodeBlock lang="curl" code={`# Competition trend at DHS, FY2022-2025
curl -s "https://analytics-api.kenosaconsulting.com/v1/datasets/competition.trend_fy/rows?department_code=7000&fy_min=2022&fy_max=2025&limit=10" \\
  -H "X-Api-Key: fpds_tier2_k..."

# HHI concentration trend by NAICS at DoD
curl -s ".../v1/datasets/concentration.trend_fy/rows?department_code=9700&fy=2024&limit=20" \\
  -H "X-Api-Key: fpds_tier2_k..."`} />

    <h2>Dataset Domains</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Domain</th><th>Count</th><th>Example IDs</th><th>What It Answers</th></tr></thead>
        <tbody>
          <tr><td>pricing</td><td>5</td><td><code>pricing.rate_analysis</code></td><td>Are we paying fair prices?</td></tr>
          <tr><td>competition</td><td>6</td><td><code>competition.trend_fy</code></td><td>Who wins the most?</td></tr>
          <tr><td>concentration</td><td>7</td><td><code>concentration.trend_fy</code></td><td>Is the market concentrated?</td></tr>
          <tr><td>customer</td><td>7</td><td><code>customer.leaders</code></td><td>Who are the biggest buyers?</td></tr>
          <tr><td>market</td><td>5</td><td><code>market.overview</code></td><td>What does the market look like?</td></tr>
          <tr><td>incumbent</td><td>3</td><td><code>incumbent.roster</code></td><td>Who holds which contracts?</td></tr>
          <tr><td>pipeline</td><td>4</td><td><code>pipeline.recompete_watchlist</code></td><td>What's expiring soon?</td></tr>
          <tr><td>naics</td><td>4</td><td><code>naics.kpi_summary</code></td><td>Which industries are growing?</td></tr>
          <tr><td>set</td><td>6</td><td><code>set.utilization</code></td><td>How are set-asides used?</td></tr>
          <tr><td>psc</td><td>6</td><td><code>psc.distribution</code></td><td>What's actually being bought?</td></tr>
          <tr><td>geography</td><td>8</td><td><code>geography.state_distribution</code></td><td>Where is the work performed?</td></tr>
          <tr><td>topics</td><td>12</td><td><code>topics.department_topics</code></td><td>What topics dominate?</td></tr>
          <tr><td>contacts</td><td>6</td><td><code>contacts.activity_patterns</code></td><td>Who are the key COs?</td></tr>
          <tr><td>seasonality</td><td>2</td><td><code>seasonality.monthly_patterns</code></td><td>When do agencies buy?</td></tr>
          <tr><td>entrants</td><td>1</td><td><code>entrants.cohort_analysis</code></td><td>Who's new to the market?</td></tr>
          <tr><td>acquisition</td><td>6</td><td><code>acquisition.vehicle_program_vendors</code></td><td>How is the acquisition structured?</td></tr>
          <tr><td>opm</td><td>3</td><td><code>opm.workforce</code></td><td>What does the federal workforce look like?</td></tr>
        </tbody>
      </table>
    </div>
    <p>Use <code>fpds_list_datasets</code> to see the full 91-dataset catalog with descriptions, fields, filters, caveats, and sort options for each.</p>

    <PrevNext prev={{ id:'api/discovery', label:'Discovery & Navigation' }} next={{ id:'api/vendors', label:'Vendor Intelligence' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// API FAMILY C: VENDOR INTELLIGENCE
// ============================================================================

const APIVendorIntelligence = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Vendor Intelligence' },
    ]} />
    <div className="docs-hero">
      <h1>Vendor Intelligence</h1>
      <p>Profile federal contractors by award history, NAICS concentration, agency footprint, competitive positioning, and recompete pipeline. All vendor intelligence flows through a single UEI.</p>
    </div>
    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/profiles/vendor', tier:'T1', desc:'Vendor 360 by UEI: spend summary, top agencies, cross-agency footprint, NAICS distribution, recompete pipeline, vehicle portfolio, competitive landscape.' },
      { method:'GET', path:'/v1/profiles/vendors/compare', tier:'T1', desc:'Side-by-side comparison of two vendors: shared agencies, overlapping NAICS, relative market position. Accepts uei_a and uei_b parameters.' },
    ]} />
    <h2>Example: Vendor Profile</h2>
    <CodeBlock lang="curl" code={`# Get a full vendor intelligence profile
curl -s "https://analytics-api.kenosaconsulting.com/v1/profiles/vendor?uei=C6FQH2VLCVL9&department_code=7000" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Also available via MCP:
# vendor_profile({ uei: "C6FQH2VLCVL9", department_code: "7000" })`} />
    <h2>Example: Compare Vendors</h2>
    <CodeBlock lang="curl" code={`# Side-by-side comparison of two competitors
curl -s "https://analytics-api.kenosaconsulting.com/v1/profiles/vendors/compare?uei_a=ABC123&uei_b=XYZ789" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Response includes:
# - Side-by-side spend totals and FY trends
# - Shared agencies with market share comparison
# - Overlapping NAICS codes
# - Relative competitive positioning`} />
    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'vendor_profile', tier:'T1', desc:'Comprehensive vendor profile by UEI: spend, agencies, NAICS, competitors, vehicles, recompete pipeline.' },
      { name:'vendor_compare', tier:'T1', desc:'Side-by-side comparison of two vendors with shared-agency and NAICS overlap analysis.' },
      { name:'keyword_vendor_profile', tier:'T1', desc:'All keywords a vendor appears in across federal awards, with award counts, obligations, and agency coverage per keyword.' },
    ]} />
    <PrevNext prev={{ id:'api/spending', label:'Spending & Market Structure' }} next={{ id:'api/topics', label:'Topic Intelligence' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// API FAMILY D: TOPIC INTELLIGENCE
// ============================================================================

const APITopicIntelligence = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Topic Intelligence' },
    ]} />
    <div className="docs-hero">
      <h1>Topic Intelligence</h1>
      <p>What does the government actually buy, beyond NAICS codes? BERTopic models trained on the 161.9M-record substrate surface what agencies purchase in their own language.</p>
    </div>
    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/topics/search', tier:'T1', desc:'Search topic names and descriptions by keyword. Multi-word queries split into tokens with OR logic.' },
      { method:'GET', path:'/v1/topics/canonical', tier:'T1', desc:'Govwide canonical theme catalog with alignment scores and cross-department coverage.' },
      { method:'GET', path:'/v1/topics/canonical/{id}', tier:'T1', desc:'Single canonical theme: lineage, sub-topics, representative terms, stability metrics.' },
      { method:'GET', path:'/v1/topics/canonical/{id}/agencies', tier:'T1', desc:'Departments where this theme is active, ranked by assignment weight.' },
      { method:'GET', path:'/v1/topics/departments/{code}', tier:'T1', desc:'Ranked topic profile for a department.' },
      { method:'GET', path:'/v1/topics/backbone', tier:'T2', desc:'Advanced topic catalog from the second-generation topic models.' },
    ]} />
    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'fpds_topic_search', tier:'T1', desc:'Search procurement topics by keyword — finds topics matching your terms.' },
      { name:'topic_profile', tier:'T1', desc:'Top procurement topics for a department by assignment frequency.' },
    ]} />
    <Note>Govwide canonical themes are live. The advanced backbone catalog is served under <code>/v1/topics/backbone</code> with its own topic id space.</Note>
    <PrevNext prev={{ id:'api/vendors', label:'Vendor Intelligence' }} next={{ id:'api/keywords', label:'Keyword Graph' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// API FAMILIES E-J, K, M, N (Concise)
// ============================================================================

const APIKeywordGraph = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Keyword Graph' },
    ]} />
    <div className="docs-hero">
      <h1>Keyword Graph</h1>
      <p>Specific capabilities, technologies, and vendors extracted from contract language via YAKE + KeyBERT matched across all source material via Aho-Corasick matching, creating over 1.8 Billion links. Keywords are categorized as <strong>product_vendor</strong>, <strong>method_service</strong>, or <strong>system_program</strong> — noise categories are excluded by default.</p>
      <Note type="warn"><strong>Keyword REST endpoints are coming soon.</strong> Legacy keyword tools are available today through the MCP server (<code>keyword_search</code>, <code>keyword_analytics</code>, <code>keyword_compare</code>, <code>keyword_vs_topic</code>). This section documents the upcoming REST surface.</Note>
    </div>

    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/keywords/search', tier:'T1', desc:'Substring search on keyword text. Returns keyword metadata with link counts and top departments. Supports department_code filter, category filter, min_link_count, and keyword_type filter.' },
      { method:'GET', path:'/v1/keywords/analytics', tier:'T1', desc:'Award count, obligations, FY trend, breakdown by agency/vendor/fy/naics/set_aside. Supports department_code, fy_start, fy_end, group_by, and limit parameters.' },
      { method:'GET', path:'/v1/keywords/compare', tier:'T1', desc:'Side-by-side multi-keyword comparison with FY trends, top 3 agencies each, unique vendor/agency counts. Accepts keywords[] or keyword_ids[] arrays.' },
      { method:'GET', path:'/v1/keywords/vs-topic', tier:'T1', desc:'Bidirectional keyword↔topic bridge. keyword→topics mode or topic→keywords mode.' },
      { method:'GET', path:'/v1/keywords/{id}/neighbors', tier:'T2*', desc:'Related keywords by co-occurrence in the link graph. Returns neighbor keywords with co-occurrence strength.' },
      { method:'GET', path:'/v1/keywords/{id}/lifecycle', tier:'T2*', desc:'Emergence, peak, decline phases for a keyword at an agency. Returns FY time series with growth rates.' },
    ]} />
    <Note>*Neighbors, lifecycle, and velocity views are coming soon.</Note>

    <h2>keyword_search — Finding Keywords</h2>
    <p>Search by substring. Filter by department, category, type, and minimum popularity:</p>
    <CodeBlock lang="curl" code={`# Find cybersecurity-related keywords
curl -s "https://analytics-api.kenosaconsulting.com/v1/keywords/search?q=cyber&department_code=070&limit=20" \\
  -H "X-Api-Key: fpds_tier1_k..."

# Search only product_vendor categories with high link counts
curl -s ".../v1/keywords/search?q=cloud&category=product_vendor&min_link_count=10" \\
  -H "X-Api-Key: fpds_tier1_k..."`} />
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Parameter</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td><code>q</code></td><td>string (req)</td><td>—</td><td>Substring to match against keyword text (case-insensitive)</td></tr>
          <tr><td><code>department_code</code></td><td>string</td><td>—</td><td>USASpending 3-digit sub-agency code (e.g. 070 for DHS)</td></tr>
          <tr><td><code>category</code></td><td>string[]</td><td>product_vendor, method_service, system_program</td><td>Filter by keyword category. Noise categories excluded by default.</td></tr>
          <tr><td><code>keyword_type</code></td><td>string[]</td><td>phrase, term</td><td>Filter by type: 'phrase' (multi-word) or 'term' (single word)</td></tr>
          <tr><td><code>min_link_count</code></td><td>integer</td><td>2</td><td>Popularity filter — only return keywords with at least this many links</td></tr>
          <tr><td><code>limit</code></td><td>integer</td><td>25</td><td>Max results (1-100)</td></tr>
        </tbody>
      </table>
    </div>

    <h2>keyword_analytics — Keyword Deep Dive</h2>
    <p>Get award counts, spending, and breakdowns for a specific keyword:</p>
    <CodeBlock lang="curl" code={`# Analytics for "cybersecurity" at DHS, FY2020-2025
curl -s "https://analytics-api.kenosaconsulting.com/v1/keywords/analytics?keyword_text=cybersecurity&department_code=070&fy_start=2020&fy_end=2025&group_by=agency" \\
  -H "X-Api-Key: fpds_tier2_k..."

# Response includes: keyword_link_count, total_obligated_amount,
# breakdown by agency/vendor/fy/naics/set_aside, plus FY spending trend`} />
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Parameter</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td><code>keyword_id</code> or <code>keyword_text</code></td><td>integer / string</td><td>—</td><td>Identify the keyword (one required)</td></tr>
          <tr><td><code>department_code</code></td><td>string</td><td>—</td><td>Agency filter (USASpending 3-digit)</td></tr>
          <tr><td><code>fy_start</code></td><td>integer</td><td>2018</td><td>Start fiscal year</td></tr>
          <tr><td><code>fy_end</code></td><td>integer</td><td>2026</td><td>End fiscal year</td></tr>
          <tr><td><code>group_by</code></td><td>string</td><td>agency</td><td>Breakdown dimension: agency, vendor, fy, naics, set_aside</td></tr>
          <tr><td><code>limit</code></td><td>integer</td><td>25</td><td>Max rows in breakdown (1-100)</td></tr>
        </tbody>
      </table>
    </div>
    <Note type="tip">keyword_link_count is always reliable. total_obligated_amount is reliable. total_award_count may be sparse — depends on award_number enrichment coverage for each department.</Note>

    <h2>keyword_compare — Side-by-Side Comparison</h2>
    <CodeBlock lang="curl" code={`# Compare Salesforce vs ServiceNow vs Oracle at DHS
curl -s "https://analytics-api.kenosaconsulting.com/v1/keywords/compare?keywords=Salesforce,ServiceNow,Oracle&department_code=070" \\
  -H "X-Api-Key: fpds_tier2_k..."

# Returns: award_count, total_obligation, unique_vendors, unique_agencies,
# FY trend series, and top 3 agencies for each keyword`} />

    <h2>keyword_vs_topic — Cross-Modal Bridge</h2>
    <p>Two modes:</p>
    <ul>
      <li><strong>keyword → topics:</strong> Provide keyword_id or keyword_text to see which BERTopic topics the keyword maps to</li>
      <li><strong>topic → keywords:</strong> Provide topic_id to see which keywords are most associated with that topic</li>
    </ul>
    <CodeBlock lang="curl" code={`# What topics is "artificial intelligence" associated with?
curl -s ".../v1/keywords/vs-topic?keyword_text=artificial+intelligence&limit=15" \\
  -H "X-Api-Key: fpds_tier2_k..."`} />

    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'keyword_search', tier:'T1', desc:'Find keywords by text substring with department, category, and popularity filters.' },
      { name:'keyword_analytics', tier:'T1', desc:'Award count, obligations, breakdowns by agency/vendor/fy/naics/set_aside, plus FY trend.' },
      { name:'keyword_compare', tier:'T1', desc:'Side-by-side comparison of multiple keywords with FY trends and agency breakdowns.' },
      { name:'keyword_vs_topic', tier:'T1', desc:'Bidirectional keyword↔topic bridge. keyword→topics or topic→keywords modes.' },
      { name:'keyword_vendor_profile', tier:'T1', desc:'All keywords a vendor appears in, with award counts, obligations, and agency coverage per keyword.' },
    ]} />
    <PrevNext prev={{ id:'api/topics', label:'Topic Intelligence' }} next={{ id:'api/contracts', label:'Contract & Pipeline' }} onNavigate={onNavigate} />
  </div>
);

const APIContractPipeline = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Contract & Pipeline' },
    ]} />
    <div className="docs-hero">
      <h1>Contract &amp; Pipeline</h1>
      <p>What was awarded, to whom, through what vehicle, and when does it expire?</p>
    </div>
    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/contracts/search', tier:'T1', desc:'Search contracts by PIID, vendor, department, NAICS, or date range. Backed by ent_awards ⋈ ent_vendors.' },
      { method:'GET', path:'/v1/contracts/{piid}', tier:'T1', desc:'Contract detail for a PIID: award info, vendor, topics, and modification actions.' },
      { method:'GET', path:'/v1/opportunities/search', tier:'T1', desc:'Search solicitations by number, title, department, or NAICS, with points of contact.' },
      { method:'GET', path:'/v1/opportunities/{solicitation_number}', tier:'T1', desc:'Opportunity detail: scope, incumbent, POCs, deadlines.' },
      { method:'GET', path:'/v1/pipeline/recompete', tier:'T2', desc:'Recompete watchlist with contract family data and points of contact.' },
      { method:'GET', path:'/v1/graph/contracts/{piid}/modifications', tier:'T1', desc:'Full modification chain for a contract (PIID).' },
    ]} />
    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'orchestrate_capture', tier:'T3', desc:'Full capture workflow from a PIID: agency fit, opportunity profile, customer intel, competitive landscape, contacts, recompete signals.' },
    ]} />
    <Note>Coming soon: contract vehicle lookup and opportunity-to-award links. Recompete confidence scores and the survival model are planned.</Note>
    <PrevNext prev={{ id:'api/keywords', label:'Keyword Graph' }} next={{ id:'api/search', label:'Semantic Search' }} onNavigate={onNavigate} />
  </div>
);

const APISemanticSearch = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Semantic Search' },
    ]} />
    <div className="docs-hero">
      <h1>Semantic Search</h1>
      <p>Search the full federal procurement document corpus by meaning, not keywords. Queries are embedded via Qwen3-8B (1024-dim) and matched against 51.4M vectors across records and chunks simultaneously, returning citable passages ranked by cosine similarity.</p>
    </div>

    <h2>How It Works</h2>
    <ol>
      <li>Your query is embedded using the same Qwen3-8B model used for all corpora, with the shared instruction prefix</li>
      <li>Cosine similarity is computed against the unified embedding space — records AND document chunks simultaneously</li>
      <li>Results are sorted by similarity and returned with snippet text, source citations, and topic assignments</li>
      <li>The instruction prefix creates a ~2% cosine offset across record/chunk surfaces; the system accounts for this in ranking</li>
    </ol>

    <h2>MCP Tool</h2>
    <ToolTable tools={[
      { name:'corpus_search', tier:'T2', desc:'Semantic search across federal procurement documents. Returns ranked passages with citations, source metadata, and topic assignments.' },
    ]} />

    <h2>Search Parameters</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Parameter</th><th>Type</th><th>Required</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td><code>query</code></td><td>string</td><td>Yes</td><td>Natural language search query describing the procurement topic</td></tr>
          <tr><td><code>doc_types</code></td><td>string[]</td><td>No</td><td>Filter by document type (see reference below). Accepts comma-separated list.</td></tr>
          <tr><td><code>corpus_types</code></td><td>string[]</td><td>No</td><td>Filter by corpus shorthand: awards, sam, nih, sbir. Also accepts full corpus_ids like awards_prime.</td></tr>
          <tr><td><code>dept_codes</code></td><td>string[]</td><td>No</td><td>4-digit FPDS department codes. Works on record surface only (chunk surface dept_id backfill pending).</td></tr>
          <tr><td><code>fy_min</code></td><td>integer</td><td>No</td><td>Minimum fiscal year (e.g. 2022 for FY22+). Filters records by their action FY.</td></tr>
          <tr><td><code>top_k</code></td><td>integer</td><td>No</td><td>Number of results. Default 10. Ceiling varies by tier: T1 max 10, T2 max 10, T3 max 50.</td></tr>
          <tr><td><code>snippet_chars</code></td><td>integer</td><td>No</td><td>Max characters per passage snippet. Default 500, max 5000. Ignored when full_content=true.</td></tr>
          <tr><td><code>full_content</code></td><td>boolean</td><td>No</td><td>Return complete passages instead of truncated snippets. Warning: passages can exceed 100K chars.</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Doc Type Reference</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>doc_type</th><th>Source</th><th>Examples</th></tr></thead>
        <tbody>
          <tr><td><code>agency-strategic-plan</code></td><td>Agency websites</td><td>DHS Strategic Plan, VA FY24 Planning</td></tr>
          <tr><td><code>agency-budget</code></td><td>Agency CFO offices</td><td>Congressional budget justifications</td></tr>
          <tr><td><code>agency-oversight</code></td><td>GAO, OIG</td><td>Agency-specific audit reports, IG semiannual reports</td></tr>
          <tr><td><code>agency-policy</code></td><td>Agency directives</td><td>Acquisition regulations, policy memos</td></tr>
          <tr><td><code>agency-other</code></td><td>Agency websites</td><td>Press releases, fact sheets, testimony</td></tr>
          <tr><td><code>govwide-legislative</code></td><td>Congress.gov</td><td>Public laws, appropriations bills, NDAA</td></tr>
          <tr><td><code>govwide-oversight</code></td><td>GAO, CRS, CBO</td><td>GAO high-risk list, CRS reports, CBO cost estimates</td></tr>
          <tr><td><code>govwide-policy</code></td><td>White House, OMB</td><td>Executive orders, OMB circulars, federal register notices</td></tr>
          <tr><td><code>govwide-executive</code></td><td>White House</td><td>Presidential memoranda, national security directives</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Example: Cross-Corpus Search</h2>
    <CodeBlock lang="curl" code={`# Search for "Army Corps of Engineers small business construction levees"
# This query hits awards, oversight reports, appropriations bills, and strategic plans
curl -s "https://analytics-api.kenosaconsulting.com/v1/search?query=Army%20Corps%20of%20Engineers%20flood%20control&doc_types=agency-oversight,govwide-legislative&top_k=10" \\
  -H "X-Api-Key: fpds_tier2_k..."

# Response: ranked passages from oversight reports and legislation,
# each with source document citation, FY, and cosine similarity score`} />

    <h2>Surface Tiering</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Tier</th><th>Access</th><th>Search Surface</th><th>FY History</th><th>Monthly Cap</th><th>Overage</th></tr></thead>
        <tbody>
          <tr><td><TierBadge tier="T1"/></td><td>Capped</td><td>Records only</td><td>5 FY</td><td>500 (hard)</td><td>—</td></tr>
          <tr><td><TierBadge tier="T2"/></td><td>Unlimited</td><td>Records + Chunks</td><td>Full</td><td>None</td><td>—</td></tr>
          <tr><td><TierBadge tier="T3"/></td><td>Full</td><td>All surfaces (records, chunks, documents)</td><td>Full</td><td>2,500 (soft)</td><td>Metered per call</td></tr>
        </tbody>
      </table>
    </div>
    <Note>The embedding space uses Qwen3-8B (qwen3_8b_1024_base_v1). The instruction prefix is applied to records but not chunks (~2% cosine offset — negligible for retrieval ranking). All vectors are L2-normalized.</Note>

    <PrevNext prev={{ id:'api/contracts', label:'Contract & Pipeline' }} next={{ id:'api/evidence', label:'Evidence & Claims' }} onNavigate={onNavigate} />
  </div>
);

const APIEvidenceClaims = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Evidence & Claims' },
    ]} />
    <div className="docs-hero">
      <h1>Evidence &amp; Claims</h1>
      <p>Evidence reads are live: retrieve claims, their signals, and subject-level claim lists. The Evidence Integrity Framework implements a three-layer model for procurement intelligence.</p>
    </div>

    <h2>Live Reads (T2+)</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/evidence/claims', tier:'T2', desc:'List claims with filters (subject, tier, status).' },
      { method:'GET', path:'/v1/evidence/claims/{id}', tier:'T2', desc:'Single claim with immutable version history.' },
      { method:'GET', path:'/v1/evidence/claims/{id}/signals', tier:'T2', desc:'Signals for/against a claim with citations (signal_judgments).' },
      { method:'GET', path:'/v1/evidence/subjects/{type}/{id}/claims', tier:'T2', desc:'All claims about a subject — contract_family and topic_dept are live.' },
      { method:'GET', path:'/v1/evidence/claim-types', tier:'T2', desc:'The claim-type registry.' },
    ]} />

    <h2>Tier Access</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Capability</th><th>Status</th><th>Tier</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td>Evidence reads (above)</td><td><strong>Live</strong></td><td><TierBadge tier="T2"/></td><td>Claims, signals, versions, and subject lists — with a growing claim base.</td></tr>
          <tr><td>Submit claim for evidence grounding</td><td>Coming soon</td><td><TierBadge tier="T2"/></td><td>Submit a natural-language claim to be analyzed for supporting/refuting evidence across the substrate.</td></tr>
          <tr><td>Document forensics</td><td>Coming soon</td><td><TierBadge tier="T2"/></td><td>Keyword register alignment — compare a document's language to an agency's vocabulary.</td></tr>
          <tr><td><strong>Convergence scoring</strong></td><td>Coming soon</td><td><TierBadge tier="Custom"/></td><td>Multi-model evidence weighting: Dempster-Shafer belief functions + Analysis of Competing Hypotheses + Bayesian updating + ICD-203 analytic standards. <strong>Custom tier only — core Evidence Integrity Framework IP.</strong></td></tr>
        </tbody>
      </table>
    </div>
    <Note type="warn"><strong>Custom tier required for convergence scoring.</strong> The convergence scoring engine (Dempster-Shafer + ACH + Bayesian + ICD-203) is the core intellectual property of the Evidence Integrity Framework. It is available exclusively through custom enterprise contracts — not through any subscription tier.</Note>
    <PrevNext prev={{ id:'api/search', label:'Semantic Search' }} next={{ id:'api/graph', label:'Knowledge Graph' }} onNavigate={onNavigate} />
  </div>
);

const APIKnowledgeGraph = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Knowledge Graph' },
    ]} />
    <div className="docs-hero">
      <h1>Knowledge Graph</h1>
      <p>Typed edge traversal across 11 entity types using 28 ontology link types: <code>COMPETES_WITH</code>, <code>TEAMS_WITH</code>, <code>AWARDED_TO</code>, <code>ACTIVE_IN_THEME</code>, and more.</p>
    </div>
    <h2>Live Reads</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/graph/vendors/{uei}/agencies', tier:'T1', desc:'Vendor agency footprint from the incumbent view.' },
      { method:'GET', path:'/v1/graph/vendors/{uei}/awards', tier:'T1', desc:'Vendor award history (ent_awards).' },
      { method:'GET', path:'/v1/graph/vendors/{uei}/topics', tier:'T2', desc:'Vendor topics from the competitive-landscape view.' },
      { method:'GET', path:'/v1/graph/vendors/{uei}/subcontractors', tier:'T2', desc:'Sub-award relationships from sub-award records.' },
      { method:'GET', path:'/v1/graph/departments/{code}/vendors', tier:'T2', desc:'Top vendors at a department.' },
      { method:'GET', path:'/v1/graph/departments/{code}/topics', tier:'T1', desc:'Top topics at a department.' },
      { method:'GET', path:'/v1/graph/officers/search', tier:'T2', desc:'Search contracting-officer profiles (ent_person_co_profiles).' },
      { method:'GET', path:'/v1/graph/contracts/{piid}/topics', tier:'T1', desc:'Topics assigned to a contract (link_award_topic).' },
    ]} />
    <Note>Coming soon: <code>COMPETES_WITH</code>, <code>TEAMS_WITH</code>, and <code>RECOMPETES_AGAINST</code> edges. Graph traversal operations (shortest path, neighborhood) are <TierBadge tier="Custom"/> only.</Note>
    <PrevNext prev={{ id:'api/evidence', label:'Evidence & Claims' }} next={{ id:'api/analytics', label:'Advanced Analytics' }} onNavigate={onNavigate} />
  </div>
);

const APIAdvancedAnalytics = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Advanced Analytics' },
    ]} />
    <div className="docs-hero">
      <h1>Advanced Analytics</h1>
      <p>Patterns, anomalies, and predictions from the procurement substrate. Statistical modeling operations that require deep computational access to the underlying data.</p>
    </div>

    <h2>Tier Access</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Capability</th><th>Status</th><th>Tier</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td>Competition concentration trends (HHI)</td><td><strong>Live</strong></td><td><TierBadge tier="T2"/></td><td>Herfindahl-Hirschman Index trends by NAICS/topic — market concentration monitoring.</td></tr>
          <tr><td>Department topic seasonality</td><td><strong>Live</strong></td><td><TierBadge tier="T2"/></td><td>Quarterly patterns in topic assignment — when agencies buy specific things.</td></tr>
          <tr><td>Topic emergence trends</td><td><strong>Live</strong></td><td><TierBadge tier="T2"/></td><td>Emerging/growing/stable/declining/fading topic classification.</td></tr>
          <tr><td>Anomaly detection reads</td><td><strong>Live</strong></td><td><TierBadge tier="T3"/></td><td>Detection reads over the 15-class anomaly registry (preview — scores are being calibrated). Custom detectors via contract.</td></tr>
          <tr><td>Markov lifecycle transitions</td><td><strong>Live</strong></td><td><TierBadge tier="T3"/></td><td>Transition probabilities between lifecycle stages (preview). Custom model building via contract.</td></tr>
          <tr><td>Procurement tensor (CP) factors</td><td><strong>Live</strong></td><td><TierBadge tier="T3"/></td><td>Tensor decomposition factor reads (preview). Custom model building via contract.</td></tr>
          <tr><td>Topic time series / lifecycle stages</td><td>Coming soon</td><td><TierBadge tier="T2"/></td><td>Per-topic emergence curves and stage detection.</td></tr>
          <tr><td><strong>Strategy-to-award lag analysis</strong></td><td>Coming soon</td><td><TierBadge tier="Custom"/></td><td>Cross-corpus temporal modeling: forecast → solicitation → award timelines. <strong>Custom tier only.</strong></td></tr>
          <tr><td><strong>Vendor win prediction</strong></td><td>Coming soon</td><td><TierBadge tier="Custom"/></td><td>ML-based prediction of future contract wins by topic/agency. <strong>Custom tier only.</strong></td></tr>
        </tbody>
      </table>
    </div>
    <Note type="warn"><strong>Custom tier required for the statistical models themselves.</strong> Reading results at T3 (with caveats) is available; building Markov, tensor, and anomaly models — plus lag analysis and win prediction — is available exclusively through custom enterprise contracts.</Note>
    <PrevNext prev={{ id:'api/graph', label:'Knowledge Graph' }} next={{ id:'api/artifacts', label:'Intelligence Artifacts' }} onNavigate={onNavigate} />
  </div>
);

const APIIntelligenceArtifacts = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Intelligence Artifacts' },
    ]} />
    <div className="docs-hero"><h1>Intelligence Artifacts</h1><p>Generate structured, citable reports from the substrate using AI.</p></div>
    <h2>Report Templates (9)</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Template</th><th>Purpose</th></tr></thead>
        <tbody>
          <tr><td><code>research_brief</code></td><td>Topic/market landscape overview</td></tr>
          <tr><td><code>agency_profile</code></td><td>Deep agency intelligence</td></tr>
          <tr><td><code>capture_plan</code></td><td>Full opportunity capture strategy</td></tr>
          <tr><td><code>competitive_brief</code></td><td>Vendor competitive analysis</td></tr>
          <tr><td><code>diligence_memo</code></td><td>Vendor diligence: past performance, risk</td></tr>
          <tr><td><code>recompete_watchlist</code></td><td>Expiring contracts by agency/NAICS</td></tr>
          <tr><td><code>market_entry</code></td><td>Market entry feasibility</td></tr>
          <tr><td><code>teaming_analysis</code></td><td>Partner identification</td></tr>
          <tr><td><code>budget_alignment</code></td><td>Budget → forecast → award pipeline check</td></tr>
        </tbody>
      </table>
    </div>
    <h2>MCP Tools</h2>
    <ToolTable tools={[
      { name:'generate_artifact', tier:'T3', desc:'Compose styled intelligence documents from NL queries. Supports our models (DeepSeek) and BYO model (Ollama).' },
      { name:'orchestrate_capture', tier:'T3', desc:'Full capture workflow from a PIID. All 6 intelligence modules in one call.' },
    ]} />
    <PrevNext prev={{ id:'api/analytics', label:'Advanced Analytics' }} next={{ id:'api/source-material', label:'Source Material' }} onNavigate={onNavigate} />
  </div>
);

const APISourceMaterial = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'Source Material' },
    ]} />
    <div className="docs-hero"><h1>Source Material</h1><p>Unified access to raw source material — 161.9M records across 20+ corpora with embeddings, chunks, and document metadata.</p></div>
    <h2>REST Endpoints</h2>
    <EndpointTable endpoints={[
      { method:'GET', path:'/v1/sources/corpora', tier:'T1', desc:'List all ingested corpora with record counts, embedding coverage, FY range, refresh cadence.' },
      { method:'GET', path:'/v1/sources/documents/{id}', tier:'T1', desc:'Full document metadata: title, type, corpus, FY, source URL, topic assignments.' },
      { method:'GET', path:'/v1/sources/documents/{id}/chunks', tier:'T1', desc:'All chunks for a document with section headers, text, topic assignments.' },
      { method:'GET', path:'/v1/sources/records/{corpus_id}/{source_id}', tier:'T1', desc:'Single record by corpus + source PK — raw text, department, FY, NAICS, PSC.' },
      { method:'GET', path:'/v1/sources/records/search', tier:'T1', desc:'Search records by corpus, department, FY range, NAICS, or text substring.' },
      { method:'GET', path:'/v1/sources/crosswalk/departments', tier:'T1', desc:'Department code mappings: FPDS 4-digit ↔ USASpending 3-digit ↔ CGAC ↔ agency name.' },
      { method:'GET', path:'/v1/sources/crosswalk/naics-to-topics', tier:'T2', desc:'NAICS code → dominant topic mappings from topic assignments.' },
    ]} />
    <PrevNext prev={{ id:'api/artifacts', label:'Intelligence Artifacts' }} next={{ id:'api/sql-lookup', label:'SQL Lookup' }} onNavigate={onNavigate} />
  </div>
);

const APISQLLookup = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'REST API', href:'#/docs/api', onClick:() => onNavigate('api') },
      { label:'SQL Lookup' },
    ]} />
    <div className="docs-hero"><h1>SQL Lookup</h1><p>Direct, read-only access to selected substrate tables for data not yet exposed via REST. Parameterized queries only — no raw SQL.</p></div>
    <Note type="warn">7 read-only tables. Parameterized WHERE clauses only. <TierBadge tier="T2"/>+.</Note>
    <h2>Allowlisted Tables</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Table</th><th>Purpose</th></tr></thead>
        <tbody>
          <tr><td><code>v2.topic_assignments</code></td><td>Record-level topic assignments with confidence scores</td></tr>
          <tr><td><code>v2.topic_labels</code></td><td>Human-readable topic labels</td></tr>
          <tr><td><code>v2.keywords</code></td><td>Keyword text, type, category metadata</td></tr>
          <tr><td><code>v2.keyword_links</code></td><td>Keyword→document link graph (600M+ links)</td></tr>
          <tr><td><code>v2.keyword_topic_map</code></td><td>Keyword↔topic bridge</td></tr>
          <tr><td><code>v2.keyword_stoplist</code></td><td>Filtered/noise keywords</td></tr>
          <tr><td><code>v2.contract_vehicles</code></td><td>Contract vehicle metadata</td></tr>
        </tbody>
      </table>
    </div>
    <PrevNext prev={{ id:'api/source-material', label:'Source Material' }} next={null} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// MCP SERVER
// ============================================================================

const MCPDocs = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'MCP Server' },
    ]} />
    <div className="docs-hero">
      <h1>MCP Server</h1>
      <p>21 tools via the Model Context Protocol — enabling AI agents to navigate the federal procurement substrate natively. MCP tools map to the same intelligence surface as REST. One key, one tier, one rate-limit pool.</p>
    </div>

    <h2>Architecture</h2>
    <p>The MCP server speaks <strong>JSON-RPC 2.0</strong> over <strong>Streamable HTTP</strong> at <code>https://analytics-api.kenosaconsulting.com/mcp</code>. It provides structured tool descriptions with JSON Schema input definitions, prompt templates for common procurement workflows, and inline resources for methodology and dataset reference.</p>
    <Note>MCP tier labels (Professional / Advanced / Enterprise) match the REST tiers T1 / T2 / T3 exactly. MCP access is included with Enterprise and Custom, and available as a <strong>$200/mo add-on</strong> for Professional and Advanced — with a separate 5,000 tool-call monthly allowance. The public MCP tools are free.</Note>
    <p>MCP is a <strong>consumption accelerator</strong>, not a separate product. You don't pay separately for MCP access. The MCP protocol enables AI agents to discover tools dynamically and call them with typed parameters — making LLMs first-class consumers of the substrate.</p>

    <h2>Connecting Claude Desktop</h2>
    <p>Add to <code>claude_desktop_config.json</code>:</p>
    <CodeBlock lang="json" code={`{
  "mcpServers": {
    "fpds": {
      "url": "https://analytics-api.kenosaconsulting.com/mcp",
      "headers": {
        "Authorization": "Bearer fpds_tier2_k..."
      }
    }
  }
}`} />

    <h2>Connecting Cursor / Other MCP Clients</h2>
    <p>Any MCP-compatible client can connect using the same URL and bearer token. The server advertises capabilities via the standard <code>initialize</code> handshake and supports <code>tools/list</code>, <code>tools/call</code>, <code>prompts/list</code>, <code>prompts/get</code>, <code>resources/list</code>, and <code>resources/read</code> methods.</p>

    <h2>Tool Gating</h2>
    <p>Tools are gated by tier. Public tools work without authentication. Tiered tools require a bearer token with the appropriate tier level. If a tool is called without sufficient tier, the server returns a structured error with an upgrade URL:</p>
    <CodeBlock lang="json" code={`{
  "error": {
    "code": "upgrade_required",
    "message": "Tool 'corpus_search' requires Advanced tier. Your token has Professional tier. Upgrade at https://fpds.kenosaconsulting.com/pricing"
  }
}`} />

    <h2>Complete Tool Inventory</h2>
    <h3>Public Tools (5 — no auth required)</h3>
    <ToolTable tools={[
      { name:'fpds_list_datasets', tier:'Public', desc:'List available datasets by domain with descriptions, grain, and row counts.' },
      { name:'fpds_describe_dataset', tier:'Public', desc:'Inspect a dataset: fields, filters, caveats, example query, sort options.' },
      
      { name:'fpds_list_dimensions', tier:'Public', desc:'List all 7 code-lookup dimension types with counts.' },
      { name:'fpds_lookup_dimension', tier:'Public', desc:'Search any dimension by substring or exact filter. Supports pagination.' },
      { name:'fpds_resolve', tier:'Public', desc:'Resolve plain-English names to FPDS codes across all dimension types simultaneously.' },
      
      
    ]} />

    <h3>Professional — T1 (5 tools: keyword_search, topic_profile, fpds_query_dataset, fpds_customer_profile, fpds_topic_search)</h3>
    <ToolTable tools={[
      { name:'keyword_search', tier:'T1', desc:'Find keywords by text substring with department, category, and popularity filters.' },
      { name:'topic_profile', tier:'T1', desc:'Top procurement topics for a department by assignment frequency.' },
    ]} />

    <h3>Advanced — T2 (8 tools)</h3>
    <ToolTable tools={[
      { name:'keyword_analytics', tier:'T2', desc:'Award count, obligations, breakdowns by agency/vendor/fy/naics/set_aside, plus FY trend.' },
      { name:'keyword_compare', tier:'T2', desc:'Side-by-side comparison of multiple keywords with FY trends and breakdowns.' },
      { name:'keyword_vs_topic', tier:'T2', desc:'Bidirectional keyword↔topic bridge. Two modes: keyword→topics and topic→keywords.' },
      { name:'keyword_vendor_profile', tier:'T2', desc:'All keywords for a vendor by UEI with award counts and agency coverage.' },
      { name:'vendor_profile', tier:'T2', desc:'Comprehensive vendor intelligence: spend, agencies, NAICS, competitors, recompete pipeline.' },
      { name:'sql_lookup', tier:'T2', desc:'Parameterized read-only queries against selected substrate tables. Deprecates as REST coverage grows.' },
      { name:'corpus_search', tier:'T2', desc:'Semantic search across document corpus. Qwen3-8B embeddings, cosine similarity, citable passages with source metadata.' },
      { name:'bert_graph_rag', tier:'T2', desc:'Multi-surface BERT-GraphRAG retrieval with Dempster-Shafer convergence scoring. Full graph + evidence chains at T3.' },
    ]} />

    <h3>Enterprise — T3 (3 tools)</h3>
    <ToolTable tools={[
      { name:'analytics_query', tier:'T3', desc:'Raw dataset queries with full filter/sort support across all analytics datasets.' },
      { name:'orchestrate_capture', tier:'T3', desc:'Full capture workflow from a PIID. Runs agency fit, opportunity profile, customer intel, competitive landscape, contact mapping, and recompete signals in optimal parallel groups.' },
      { name:'generate_artifact', tier:'T3', desc:'Compose styled intelligence documents (research briefs, capture plans, competitive briefs, diligence memos, etc.) from natural language queries. Uses our models (DeepSeek) or your own (Ollama).' },
    ]} />

    <h2>Prompts (16)</h2>
    <h3>Analytical (8)</h3>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Prompt</th><th>What It Does</th></tr></thead>
        <tbody>
          <tr><td><code>assess_market_entry_difficulty</code></td><td>Evaluate barriers to entry for a NAICS/agency combination using concentration, incumbency, and set-aside data</td></tr>
          <tr><td><code>find_expiring_contracts</code></td><td>Surface contracts approaching expiration at an agency, ranked by value and recompete likelihood</td></tr>
          <tr><td><code>discover_what_agency_actually_buys</code></td><td>Topic-based discovery: what an agency purchases beyond surface-level NAICS codes</td></tr>
          <tr><td><code>profile_customer_agency</code></td><td>Full agency 360: spending patterns, top vendors, NAICS concentration, set-aside mix, vehicle usage</td></tr>
          <tr><td><code>find_contracting_officers_for_naics</code></td><td>Map COs actively awarding in a specific NAICS code with activity patterns and tenure</td></tr>
          <tr><td><code>find_growth_naics_with_weak_competition</code></td><td>Identify NAICS codes with growing spend but low competition — opportunity hotspots</td></tr>
          <tr><td><code>map_vendor_competitive_landscape</code></td><td>Build a competitive map for a vendor: who they compete with, where, and on what topics</td></tr>
          <tr><td><code>find_agency_set_aside_opportunities</code></td><td>Surface set-aside-rich agencies and NAICS codes matching a vendor's socioeconomic status</td></tr>
        </tbody>
      </table>
    </div>

    <h3>Skill-Based (8)</h3>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Prompt</th><th>What It Does</th></tr></thead>
        <tbody>
          <tr><td><code>vendor_market_analysis</code></td><td>Deep vendor market position: spend trends, agency footprint, topic specialization, competitive threats</td></tr>
          <tr><td><code>recompete_pipeline</code></td><td>Build a recompete watchlist: expiring contracts ranked by value, incumbent strength, and win probability</td></tr>
          <tr><td><code>contracting_officer_patterns</code></td><td>Analyze CO behavior: who they award to, what NAICS, sole-source tendency, set-aside patterns</td></tr>
          <tr><td><code>account_plan_builder</code></td><td>Build an agency account plan: org structure, key buyers, spending trends, vehicle landscape, pipeline</td></tr>
          <tr><td><code>naics_opportunity_scan</code></td><td>Scan NAICS codes for growth, competition intensity, set-aside friendliness, and vehicle availability</td></tr>
          <tr><td><code>cross_agency_opportunity_radar</code></td><td>Find agencies buying similar things: cross-agency topic overlap and spending comparison</td></tr>
          <tr><td><code>teaming_partner_finder</code></td><td>Identify potential teaming partners based on complementary capabilities and shared agency presence</td></tr>
          <tr><td><code>vehicle_strategy_advisor</code></td><td>Analyze which contract vehicles an agency uses for a given NAICS/topic and which are accessible</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Resources (7)</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>URI</th><th>Content</th></tr></thead>
        <tbody>
          <tr><td><code>fpds://docs/methodology</code></td><td>Full methodology documentation: topic modeling, keyword extraction, embedding space, evidence framework</td></tr>
          <tr><td><code>fpds://docs/datasets</code></td><td>Complete dataset catalog with descriptions, domains, fields, and grain for all 91 datasets</td></tr>
          <tr><td><code>fpds://docs/caveats</code></td><td>Data quality caveats: known gaps, FY coverage limitations, obligation vs. award count reliability</td></tr>
          <tr><td><code>fpds://docs/ai-assistant-guide</code></td><td>Instructions for LLM agents on how to use the API effectively, including workflow patterns</td></tr>
          <tr><td><code>fpds://docs/notices</code></td><td>Generated per-response data notices about freshness, coverage, and methodology</td></tr>
          <tr><td><code>fpds://catalog/datasets</code></td><td>Live dataset catalog — dynamically generated from the current API state</td></tr>
          <tr><td><code>fpds://catalog/dimensions</code></td><td>Live dimension catalog — all 7 code-lookup types with current row counts</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Streaming</h2>
    <p>The MCP server uses Streamable HTTP, supporting both request-response and server-initiated notifications. Tool calls return complete results (non-streaming). The <code>generate_artifact</code> tool supports Server-Sent Events (SSE) for streaming artifact generation progress when called from compatible clients.</p>

    <PrevNext prev={{ id:'api/sql-lookup', label:'SQL Lookup' }} next={{ id:'sdk', label:'Python SDK' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// PYTHON SDK
// ============================================================================

const SDKDocs = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Python SDK' },
    ]} />
    <div className="docs-hero">
      <h1>Python SDK</h1>
      <p>Typed Python client for the FPDS substrate. <code>pip install fpds-substrate</code> — same API key as REST and MCP. Requires Python 3.12+.</p>
      <p style={{marginTop:12, fontSize:14, color:'#B45309', background:'#FEF3C7', border:'1px solid #FDE68A', borderRadius:8, padding:'10px 14px'}}>
        <strong>Status: early preview.</strong> Entity resolution for departments, vendors, awards, opportunities, and documents is live. Link Type traversal methods are defined on every entity but not yet implemented — they raise <code>NotYetImplementedError</code> rather than returning empty results. This page describes the real, working surface only (updated 2026-08-19).
      </p>
    </div>

    <h2>Install</h2>
    <CodeBlock lang="bash" code={`pip install fpds-substrate`} />

    <h2>Quickstart</h2>
    <CodeBlock lang="python" code={`from fpds import Substrate

# Initialize with your API key
fpds = Substrate(api_key="fpds_tier1_k...")

# Resolve a department (Professional tier+)
dhs = fpds.department("7000")
print(dhs.name, dhs.spending_profile.total_obligated)

# Resolve a vendor by UEI (Professional tier+)
vendor = fpds.vendor("C6FQH2VLCVL9")
print(vendor.name, vendor.agency_coverage)

# Resolve an award by PIID (Explorer tier+)
award = fpds.award("FA872624FB071")
print(award.obligated_amount, award.incumbent.name)
print(award.modification_profile.total_modifications)`} />

    <h2>Substrate Class</h2>
    <p>The <code>Substrate</code> class is the main entry point. It manages authentication and the HTTP connection. Factory methods return typed ontology entities.</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Parameter</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
        <tbody>
          <tr><td><code>api_key</code></td><td>str</td><td>—</td><td>FPDS API key (required)</td></tr>
          <tr><td><code>base_url</code></td><td>str</td><td>analytics-api.kenosaconsulting.com</td><td>Override for self-hosted or proxy</td></tr>
          <tr><td><code>timeout</code></td><td>float</td><td>30</td><td>Request timeout in seconds</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Entity Resolution</h2>
    <p>Resolve identifiers to typed entity objects:</p>
    <CodeBlock lang="python" code={`dept      = fpds.department("7000")     # → Department
vendor    = fpds.vendor("C6FQH2VLCVL9") # → Company
award     = fpds.award("FA872624FB071") # → Award
opp       = fpds.opportunity("SOL123")  # → Opportunity
doc       = fpds.document(42)           # → Document`} />

    <h2>Ontology Classes (9 typed entities)</h2>
    <p>Entity classes are typed with annotated properties. Every entity carries Link Type traversal methods (e.g. <code>department.topics()</code>, <code>vendor.competitors()</code>, <code>award.vehicle()</code>) that map to the locked T-box. Traversals are the Phase-1 build target and raise <code>NotYetImplementedError</code> until implemented.</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Class</th><th>Classification</th><th>Primary Key</th><th>Key Properties</th></tr></thead>
        <tbody>
          <tr><td><code>Department</code></td><td>Independent Continuant</td><td>code (4-digit FPDS)</td><td>name, spending_profile, competition_profile, topic_fingerprint</td></tr>
          <tr><td><code>Company</code></td><td>Independent Continuant</td><td>uei</td><td>name, socioeconomic_flags, agency_coverage, topic_fingerprint</td></tr>
          <tr><td><code>Award</code></td><td>Generically Dependent</td><td>piid</td><td>obligated_amount, current_value, period_of_performance, incumbent, modification_profile</td></tr>
          <tr><td><code>Opportunity</code></td><td>Generically Dependent</td><td>piid (solicitation number)</td><td>title, naics_code, notice_type</td></tr>
          <tr><td><code>Document</code></td><td>Generically Dependent</td><td>id</td><td>title, doc_type, corpus, source_url</td></tr>
          <tr><td><code>Topic</code></td><td>Generically Dependent</td><td>id</td><td>label, description, is_canonical, assignment_count</td></tr>
          <tr><td><code>Keyword</code></td><td>Generically Dependent</td><td>id</td><td>text, category</td></tr>
          <tr><td><code>ContractVehicle</code></td><td>Independent Continuant</td><td>id</td><td>name, vehicle_type, predecessor, successor</td></tr>
          <tr><td><code>ContractingOfficer</code></td><td>Independent Continuant</td><td>id</td><td>name, agency, career_span_years, obligation_history</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Error Handling</h2>
    <CodeBlock lang="python" code={`from fpds import Substrate
from fpds.exceptions import (
    AuthenticationError,  # 401 — missing/invalid key
    AuthorizationError,   # 403 — tier too low for the endpoint
    NotFoundError,        # 404 — unknown identifier
    RateLimitError,       # 429 — rate limit exceeded
    QueryError,           # 422 — invalid query parameters
    NotYetImplementedError,
)

fpds = Substrate(api_key="fpds_tier1_k...")

try:
    award = fpds.award("FA872624FB071")
except AuthorizationError as e:
    print(f"Upgrade required: {e}")   # endpoint needs a higher tier
except RateLimitError as e:
    print("Retry shortly")            # 429`} />

    <h2>What's next</h2>
    <p>Link Type traversals (<code>awarded_to()</code>, <code>competes_with()</code>, <code>under_vehicle()</code>, …) are documented on each entity and land with the knowledge-graph surface. Async support and retry/backoff are on the roadmap; the client is synchronous today.</p>

    <PrevNext prev={{ id:'mcp', label:'MCP Server' }} next={{ id:'reference', label:'Glossary' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// DATA & ONTOLOGY
// ============================================================================

const DataDocs = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Data & Ontology' },
    ]} />
    <div className="docs-hero">
      <h1>Data &amp; Ontology</h1>
      <p>FPDS ingests 20+ corpora into a BFO-aligned ontology with a 48-table substrate schema. 161.9M source objects, 31.1M record embeddings, 18.9M chunk embeddings, 1.3M document embeddings.</p>
    </div>

    <h2>Source Corpora (partial)</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Corpus</th><th>Records</th><th>Type</th><th>FY Range</th></tr></thead>
        <tbody>
          <tr><td><code>awards_prime</code></td><td>74.3M</td><td>Record</td><td>1979–2026</td></tr>
          <tr><td><code>sam_opportunities</code></td><td>7.9M</td><td>Record</td><td>2018–2026</td></tr>
          <tr><td><code>agency_policy</code></td><td>336K</td><td>Document</td><td>2018–2026</td></tr>
          <tr><td><code>agency_oversight</code></td><td>22.2K</td><td>Document</td><td>2018–2026</td></tr>
          <tr><td><code>govwide_legislative</code></td><td>371K</td><td>Document</td><td>2018–2026</td></tr>
          <tr><td><code>govwide_oversight</code></td><td>5.8K</td><td>Document</td><td>2018–2026</td></tr>
          <tr><td><code>cfr</code></td><td>—</td><td>Document</td><td>—</td></tr>
          <tr><td><code>nih_reporter</code></td><td>2.3M</td><td>Record</td><td>2018–2026</td></tr>
          <tr><td><code>sbir_awards</code></td><td>171K</td><td>Record</td><td>2018–2026</td></tr>
          <tr><td><code>github_register</code></td><td>12.5K</td><td>Document</td><td>2018–2026</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Ontology Fundamentals</h2>
    <p>BFO-aligned classification. Every primitive is a <strong>continuant</strong> (persists through time) or an <strong>occurrent</strong> (unfolds in time).</p>
    <ul>
      <li><strong>Independent continuants:</strong> Department, Subagency, Office, Company, ContractingOfficer, ContractVehicle</li>
      <li><strong>Generically dependent:</strong> Contract, Opportunity, Document, CanonicalTheme, Forecast</li>
      <li><strong>Specifically dependent:</strong> TopicEmbedding, Claim, Signal, ReliabilityWeight, ProcurementArea</li>
      <li><strong>Occurrents:</strong> AwardAction, Modification, Amendment, Recompete, VehicleTransition</li>
    </ul>

    <PrevNext prev={{ id:'sdk', label:'Python SDK' }} next={{ id:'analytics', label:'Analytics & Methodology' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// ANALYTICS & METHODOLOGY
// ============================================================================

const AnalyticsDocs = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Analytics & Methodology' },
    ]} />
    <div className="docs-hero">
      <h1>Analytics &amp; Methodology</h1>
      <p>How the FPDS substrate works — from topic modeling and keyword extraction to embeddings, retrieval, and evidence scoring.</p>
    </div>

    <h2>Topic Modeling (BERTopic)</h2>
    <p>Per-corpus BERTopic models using Qwen3-8B 1024-dim embeddings, trained at scale for large corpora with cross-corpus merging via semantic overlap analysis. Canonical themes promoted when: stable Leiden community, alignment ≥ 0.70, and ≥ 3 departments.</p>
    <CodeBlock lang="bash" code={`# Pipeline: clean → embed → train → merge → label
python cleaning.py      # Strip boilerplate, normalize text
python embed.py         # Qwen3-8B 1024-dim embeddings
python shard_trainer.py # BERTopic training (74.3M awards)
python semantic_merging.py  # Cross-corpus topic alignment
python label.py         # Claude Haiku topic labeling`} />

    <h2>Keyword Extraction</h2>
    <p>Aho-Corasick multi-pattern matching across 600M+ keyword links. Keywords categorized as product_vendor, method_service, or system_program. The keyword-topic bridge maps keyword↔topic pairs across the link graph.</p>

    <h2>Embedding Space</h2>
    <p>All corpora share a <strong>Qwen3-8B</strong> 1024-dim embedding space with instruction prefixes for cross-corpus unity — enabling direct vector comparison across awards, SAM, strategic plans, budgets, and oversight without alignment steps.</p>

    <h2>BERT-GraphRAG</h2>
    <p>Multi-surface retrieval engine fusing five layers (vector search, keyword matching, topic routing, graph traversal, LLM reasoning) with Dempster-Shafer belief fusion for entity scoring.</p>

    <h2>Evidence Integrity Framework</h2>
    <ol>
      <li><strong>Layer 1 (deterministic):</strong> Signal extraction — cross-source alignment, keyword presence, topic coverage.</li>
      <li><strong>Layer 2 (bounded LLM):</strong> Per-signal likelihood-ratio classification with rationale.</li>
      <li><strong>Layer 3 (deterministic):</strong> Mathematical convergence — Dempster-Shafer + ACH + Bayesian + ICD-203.</li>
    </ol>

    <h2>Government-Native Procurement LLM</h2>
    <p>R&D initiative: domain-adapt Llama-3.2-3B-Instruct on ~500M procurement tokens (QLoRA + full DAPT). A small, specialized model that understands PIIDs, UEIs, NAICS, PSC, clauses, and procurement legalese natively.</p>

    <PrevNext prev={{ id:'data', label:'Data & Ontology' }} next={{ id:'reference', label:'Reference' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// SECTION: REFERENCE — Overview
// ============================================================================

const ReferenceOverview = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary' },
    ]} />
    <div className="docs-hero">
      <h1>Glossary</h1>
      <p>Canonical terminology of the FPDS substrate — organized by domain with independent sub-pages.</p>
    </div>

    <h2>Glossary</h2>
    <p>Comprehensive definitions organized by domain. Each section is independently navigable.</p>
    <div className="docs-card-grid">
      <a href="#/docs/reference/glossary/core" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/core'); }}>
        <h3>Core Concepts</h3>
        <p>FPDS, Substrate, Seven Dimensions, Evidence Integrity Framework.</p>
      </a>
      <a href="#/docs/reference/glossary/ontology" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/ontology'); }}>
        <h3>Object Types</h3>
        <p>Continuants, occurrents, Government Entity, Award, Grant, Keyword, Topic, and all 30+ ontology entities.</p>
      </a>
      <a href="#/docs/reference/glossary/links" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/links'); }}>
        <h3>Link Types</h3>
        <p>The 28 ontology link types organized by domain: Execution, Theme, Competitive, Evidence, and more.</p>
      </a>
      <a href="#/docs/reference/glossary/codes" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/codes'); }}>
        <h3>Department Codes & Crosswalk</h3>
        <p>How CGAC, FPDS, FAC, OPM, and Grants.gov codes map to canonical department identifiers.</p>
      </a>
      <a href="#/docs/reference/glossary/tiers" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/tiers'); }}>
        <h3>Tiered Access</h3>
        <p>Public through Custom — what each tier unlocks and how API keys work.</p>
      </a>
      <a href="#/docs/reference/glossary/families" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/families'); }}>
        <h3>API & Tool Families</h3>
        <p>Families A-N: what each intelligence domain answers and what tools it exposes.</p>
      </a>
      <a href="#/docs/reference/glossary/data" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/data'); }}>
        <h3>Data Terms</h3>
        <p>Corpora, embeddings, unified embedding space, records, chunks, datasets, dimensions.</p>
      </a>
      <a href="#/docs/reference/glossary/methodology" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/methodology'); }}>
        <h3>Methodology & Analytics</h3>
        <p>Topic modeling, keyword extraction, semantic search, convergence scoring, recompete prediction.</p>
      </a>
      <a href="#/docs/reference/glossary/tools" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/glossary/tools'); }}>
        <h3>Tools & Technologies</h3>
        <p>The full technology stack: BERTopic, Qwen3-8B, Aho-Corasick, pgvector, FastAPI, Claude, and more.</p>
      </a>
    </div>

    <h2>Error Codes & Conventions</h2>
    <div className="docs-card-grid">
      <a href="#/docs/reference/conventions" className="docs-card" onClick={(e) => { e.preventDefault(); onNavigate('reference/conventions'); }}>
        <h3>Error Codes & Conventions</h3>
        <p>API error codes, naming conventions, hedge prefixes, department code formats, and data freshness.</p>
      </a>
    </div>
  </div>
);

// ============================================================================
// GLOSSARY A: CORE CONCEPTS
// ============================================================================

const GlossaryCore = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
      { label:'Glossary: Core Concepts' },
    ]} />
    <div className="docs-hero">
      <h1>Core Concepts</h1>
      <p>Foundational terms that frame what FPDS is and how it organizes procurement intelligence.</p>
    </div>

    <h2>FPDS</h2>
    <p>Federal Procurement Data Science — an evidence-grounded, cross-source intelligence layer for federal procurement.</p>

    <h2>Substrate</h2>
    <p>The compounding intelligence asset underpinning all product surfaces: data cleaning methodology, embedding quality, cross-corpus alignment, entity resolution, topic discovery, and reliability calibration.</p>

    <h2>Seven Dimensions (D1-D7)</h2>
    <p>The seven intelligence lenses through which procurement data converges to produce insight. Data is classified by the dimension it serves, not by source alone.</p>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>#</th><th>Dimension</th><th>What It Answers</th></tr></thead>
        <tbody>
          <tr><td>D1</td><td>Political Durability &amp; Structural Intent</td><td>Is the money real? Will it persist? Appropriations, executive orders, budget documents.</td></tr>
          <tr><td>D2</td><td>Accountability &amp; Oversight Signals</td><td>What has the oversight ecosystem said? GAO reports, OIG audits, CRS analyses, FAC audit findings.</td></tr>
          <tr><td>D3</td><td>Forward Intent</td><td>What is the agency planning to buy? Forecasts, strategic plans, industry days, Grants.gov opportunities.</td></tr>
          <tr><td>D4</td><td>Market Demand Formalization</td><td>What has the government solicited? SAM.gov solicitations, RFIs, sources-sought notices.</td></tr>
          <tr><td>D5</td><td>Execution Reality</td><td>What got awarded, to whom, by whom? Prime awards, sub-awards, grant assistance, loan programs.</td></tr>
          <tr><td>D6</td><td>Contract Vehicle Mechanics</td><td>Through what mechanism? IDVs, BPAs, GWACs, GSA Schedules, vehicle transitions.</td></tr>
          <tr><td>D7</td><td>The Human Network</td><td>Who are the contracting officers? CO roster, activity patterns, tenure, grade distribution.</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Evidence Integrity Framework</h2>
    <p>Three-layer evidence model underlying all claims and intelligence products:</p>
    <ol>
      <li><strong>Layer 1 (deterministic):</strong> Signal extraction from source data — cross-source alignment, keyword presence, topic coverage.</li>
      <li><strong>Layer 2 (bounded LLM judgment):</strong> Per-signal likelihood-ratio classification with rationale.</li>
      <li><strong>Layer 3 (mathematical convergence):</strong> Multi-model evidence weighting using Dempster-Shafer belief functions, Analysis of Competing Hypotheses, Bayesian updating, and ICD-203 analytic standards.</li>
    </ol>

    <PrevNext prev={null} next={{ id:'reference/glossary/ontology', label:'Glossary: Object Types' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// GLOSSARY B: ONTOLOGY — OBJECT TYPES
// ============================================================================

const GlossaryOntology = ({ onNavigate }) => {
  const types = [
    ['Meta','Continuant','An entity that persists through time and has current state (e.g. a department, a company, a contract).'],
    ['Meta','Occurrent','An entity that unfolds in time as an event or transaction (e.g. a modification, a recompete).'],
    ['Independent Continuant','Government Entity','A government organization. Subtypes: Department, Sub-Agency, Office. One node per real organization, FPDS-anchored.'],
    ['Independent Continuant','Department','Top-level agency (e.g. DoD, VA, HHS). Primary ID: 4-digit fpds_dept_id. Carries CFO Act flag.'],
    ['Independent Continuant','Sub-Agency','Subdivision (e.g. Army, Navy, NIH). Primary ID: fpds_agency_id.'],
    ['Independent Continuant','Office','Contracting office (e.g. N00019, W91CRB). Primary ID: contracting_office_id.'],
    ['Independent Continuant','Vendor / Company','Organization receiving awards or grants. Identity: UEI (primary), CAGE. Carries socioeconomic status.'],
    ['Independent Continuant','Person / Contracting Officer','Procurement official. Identity node with linked behavioral profile. Roles borne on relationship edges.'],
    ['Independent Continuant','Contract Vehicle','Curated government-wide vehicle (GWAC, IDIQ, BPA, GSA Schedule). Carries pool structure and lineage.'],
    ['Continuant','Award','The persisting contract instrument at PIID-family grain. Subtypes: Definitive Contract, Delivery/Task Order, IDV.'],
    ['Generically Dependent','Contract','Alias for Award.'],
    ['Independent Continuant','Grant','Assistance instrument. Uses ALN/grant_number identity. Separate lifecycle from contracts.'],
    ['Occurrent','Contract Action','A single transaction against an Award (base award or modification). Carries per-action dollar deltas.'],
    ['Occurrent','Grant Action','A transaction against a Grant. Subtypes: new award, continuation, revision, supplement.'],
    ['Generically Dependent','Subcontract / Sub Award','Subcontractor award under a prime contract (FFATA/FSRS). Links to its prime Award.'],
    ['Generically Dependent','Opportunity','A solicitation — covers SAM.gov solicitations and Grants.gov funding opportunities.'],
    ['Generically Dependent','Document','A typed government document: strategic plans, budgets, oversight reports, legislation, executive orders.'],
    ['Generically Dependent','Document Chunk','Passage-level slice of a Document — the citable unit returned by semantic search.'],
    ['Generically Dependent','Canonical Theme / Topic','A procurement topic cluster discovered via BERTopic. Hierarchy: subtopic → topic → canonical theme.'],
    ['Generically Dependent','Corpus Topic','A topic scoped to a single corpus.'],
    ['Generically Dependent','Forecast','An anticipated procurement, pre-solicitation.'],
    ['Generically Dependent','Keyword','A domain procurement term extracted from contract language. Categories: product_vendor, method_service, system_program.'],
    ['Generically Dependent','Page','A crawled agency web page.'],
    ['Specifically Dependent','Topic Embedding','The vector representation of a topic centroid.'],
    ['Specifically Dependent','Claim','A submitted assertion about procurement — immutable and versioned.'],
    ['Specifically Dependent','Signal','An evidence cue (for or against a Claim) extracted from source data.'],
    ['Specifically Dependent','Reliability Weight','A calibration score assigned to a data source.'],
    ['Specifically Dependent','Procurement Area','A Scope × Canonical Theme intersection.'],
    ['Specifically Dependent','Anomaly','A detected irregularity in procurement patterns.'],
    ['Specifically Dependent','Audit Finding','A FAC (Federal Audit Clearinghouse) audit finding. Bridges oversight signals to award data.'],
    ['Occurrent','Award Action','A base award or modification event.'],
    ['Occurrent','Modification','A change to an Award (option exercise, funding, administrative, scope, novation, closeout).'],
    ['Occurrent','Amendment','A modification to a solicitation.'],
    ['Occurrent','Recompete','An Award\'s re-competition event.'],
    ['Occurrent','Vehicle Transition','A Contract Vehicle lineage event (successor/predecessor).'],
    ['Occurrent','Calibration Event','A reliability adjustment to source data.'],
    ['Reference Entity','ALN Code','Assistance Listing Number — the grant equivalent of NAICS. ~2,300 programs.'],
    ['Value Object','Location','Reusable address structure (street, city, state, zip, country, congressional district). Borne by Awards, Vendors, Offices, and Opportunities.'],
  ];

  return (
    <div>
      <Breadcrumb items={[
        { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
        { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
        { label:'Glossary: Object Types' },
      ]} />
      <div className="docs-hero">
        <h1>Ontology — Object Types</h1>
        <p>The complete catalog of entity types in the FPDS ontology. Each is classified as a continuant (persists through time), occurrent (unfolds in time), or a supporting construct.</p>
      </div>
      <div className="docs-table-wrap">
        <table className="docs-table">
          <thead><tr><th>Classification</th><th>Object Type</th><th>Definition</th></tr></thead>
          <tbody>
            {types.map((t, i) => (
              <tr key={i}>
                <td>{t[0]}</td>
                <td><strong>{t[1]}</strong></td>
                <td>{t[2]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <PrevNext prev={{ id:'reference/glossary/core', label:'Glossary: Core Concepts' }} next={{ id:'reference/glossary/links', label:'Glossary: Link Types' }} onNavigate={onNavigate} />
    </div>
  );
};

// ============================================================================
// GLOSSARY C: ONTOLOGY — LINK TYPES
// ============================================================================

const GlossaryLinks = ({ onNavigate }) => {
  const groups = [
    { category:'Execution (10)', links:'AWARDED_TO, AWARDED_BY, FUNDED_BY, FUNDED_BY_OFFICE, POSTED_BY, UNDER_VEHICLE, HELD_BY, HAS_SUBCONTRACT, PERFORMED_BY, PARENT_VENDOR_OF' },
    { category:'Solicitation (2)', links:'HAS_AMENDMENT, RESULTS_IN (confidence-weighted, 0..1)' },
    { category:'Theme (4)', links:'ABOUT_THEME, BELONGS_TO_THEME, ACTIVE_IN_THEME, SPECIALIZES_IN' },
    { category:'Vehicle (2)', links:'SUPERSEDES, AUTHORIZES' },
    { category:'Competitive (3)', links:'COMPETES_WITH (symmetric, weighted), TEAMS_WITH, RECOMPETES_AGAINST' },
    { category:'Evidence (4)', links:'HAS_SIGNAL, ABOUT_SUBJECT (polymorphic), EVIDENCED_BY (polymorphic), CITES_CHUNK' },
    { category:'Hierarchy (1)', links:'PART_OF' },
  ];

  return (
    <div>
      <Breadcrumb items={[
        { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
        { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
        { label:'Glossary: Link Types' },
      ]} />
      <div className="docs-hero">
        <h1>Ontology — Link Types</h1>
        <p>The 28 ontology link types that define how entities connect. Each has a defined domain, range, cardinality, and derivation method (direct from source data or computed through aggregation).</p>
      </div>
      <div className="docs-table-wrap">
        <table className="docs-table">
          <thead><tr><th>Category</th><th>Link Types</th></tr></thead>
          <tbody>
            {groups.map((g, i) => (
              <tr key={i}>
                <td><strong>{g.category}</strong></td>
                <td><code>{g.links}</code></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <PrevNext prev={{ id:'reference/glossary/ontology', label:'Glossary: Object Types' }} next={{ id:'reference/glossary/codes', label:'Glossary: Department Codes' }} onNavigate={onNavigate} />
    </div>
  );
};

// ============================================================================
// GLOSSARY D: DEPARTMENT CODES & CROSSWALK
// ============================================================================

const GlossaryCodes = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
      { label:'Glossary: Department Codes' },
    ]} />
    <div className="docs-hero">
      <h1>Department Codes &amp; Crosswalk</h1>
      <p>The canonical identity system maps multiple source coding systems to canonical department and office identifiers.</p>
    </div>

    <h2>Source Systems</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Source System</th><th>What It Maps</th></tr></thead>
        <tbody>
          <tr><td><code>cgac</code></td><td>USASpending 3-digit CGI Agency Codes → canonical department codes (e.g. "097" → DEP-DOD)</td></tr>
          <tr><td><code>fpds</code></td><td>FPDS contracting office codes → canonical office codes (e.g. "N00019" → OFF-N00019)</td></tr>
          <tr><td><code>fac</code></td><td>Federal Audit Clearinghouse agency codes → canonical department codes</td></tr>
          <tr><td><code>opm</code></td><td>OPM workforce agency codes → canonical department codes</td></tr>
          <tr><td><code>grants_gov</code></td><td>Grants.gov agency codes → canonical department codes</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Canonical Code Prefixes</h2>
    <ul>
      <li><code>DEP-*</code> — Department level (e.g. DEP-DOD, DEP-VA, DEP-HHS)</li>
      <li><code>OFF-*</code> — Office level (e.g. OFF-N00019, OFF-W91CRB)</li>
      <li><code>AGY-*</code> — Sub-Agency level</li>
    </ul>

    <h2>The Crosswalk</h2>
    <p>The <code>usaspending_fpds_dept_crosswalk</code> resolves 3-digit CGAC codes to 4-digit FPDS department codes. This crosswalk is load-bearing — all USAspending-sourced data (awards, sub-awards, opportunities, documents) arrives CGAC-keyed and must resolve through it.</p>

    <Note>The full interactive crosswalk lookup, including Treasury Account Codes, is available on the Department Codes reference page.</Note>

    <PrevNext prev={{ id:'reference/glossary/links', label:'Glossary: Link Types' }} next={{ id:'reference/glossary/tiers', label:'Glossary: Tiered Access' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// GLOSSARY E: TIERED ACCESS
// ============================================================================

const GlossaryTiers = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
      { label:'Glossary: Tiered Access' },
    ]} />
    <div className="docs-hero">
      <h1>Tiered Access</h1>
      <p>FPDS uses a six-tier access model. Each tier unlocks progressively deeper layers of the substrate.</p>
    </div>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Tier</th><th>Key Capabilities</th></tr></thead>
        <tbody>
          <tr><td><TierBadge tier="Public"/></td><td>7 discovery tools, ~10 demo datasets</td></tr>
          <tr><td><TierBadge tier="T0.5"/></td><td>Keyword and topic tools, 40 datasets, 3 departments</td></tr>
          <tr><td><TierBadge tier="T1"/></td><td>Full data surfaces, vendor profiles, capped semantic search (500/mo)</td></tr>
          <tr><td><TierBadge tier="T2"/></td><td>Full keyword graph, analytics queries, evidence claims, knowledge graph edges, all departments</td></tr>
          <tr><td><TierBadge tier="T3"/></td><td>Full semantic search, AI-generated artifacts, orchestrated capture workflows, full knowledge graph</td></tr>
          <tr><td><TierBadge tier="Custom"/></td><td>Statistical models, convergence scoring, anomaly detection, graph traversal, dedicated capacity</td></tr>
        </tbody>
      </table>
    </div>
    <h2>API Keys</h2>
    <p>A single API key (<code>fpds_&lt;tier&gt;_k&lt;random&gt;</code>) works across the REST surface and the MCP server. Keys are validated against our key store on every request — tier, per-minute limits, expiry, and revocation are enforced server-side. Keys are SHA-256 hashed in storage and shown only once at creation. Authentication is via the <code>X-Api-Key</code> header (REST) or <code>Authorization: Bearer</code> (MCP).</p>
    <Note>Full pricing, rate limits, and detailed capability matrix: see <strong>Pricing</strong> page.</Note>
    <PrevNext prev={{ id:'reference/glossary/codes', label:'Glossary: Department Codes' }} next={{ id:'reference/glossary/families', label:'Glossary: API & Tool Families' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// GLOSSARY F: API & TOOL FAMILIES
// ============================================================================

const GlossaryFamilies = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
      { label:'Glossary: API & Tool Families' },
    ]} />
    <div className="docs-hero">
      <h1>API &amp; Tool Families</h1>
      <p>13 intelligence-domain families organize ~100 tools across the REST API, MCP server, and Python SDK.</p>
    </div>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Family</th><th>Label</th><th>What It Answers</th></tr></thead>
        <tbody>
          <tr><td>A</td><td><a href="#/docs/api/discovery" onClick={(e) => { e.preventDefault(); onNavigate('api/discovery'); }}>Discovery &amp; Navigation</a></td><td>What's available and how do I find things?</td></tr>
          <tr><td>B</td><td><a href="#/docs/api/spending" onClick={(e) => { e.preventDefault(); onNavigate('api/spending'); }}>Spending &amp; Market Structure</a></td><td>Who spends how much on what?</td></tr>
          <tr><td>C</td><td><a href="#/docs/api/vendors" onClick={(e) => { e.preventDefault(); onNavigate('api/vendors'); }}>Vendor Intelligence</a></td><td>Who are the players and where are they strong?</td></tr>
          <tr><td>D</td><td><a href="#/docs/api/topics" onClick={(e) => { e.preventDefault(); onNavigate('api/topics'); }}>Topic Intelligence</a></td><td>What does the government actually buy, beyond NAICS codes?</td></tr>
          <tr><td>E</td><td><a href="#/docs/api/keywords" onClick={(e) => { e.preventDefault(); onNavigate('api/keywords'); }}>Keyword Graph</a></td><td>What capabilities, technologies, and vendors appear in contract language?</td></tr>
          <tr><td>F</td><td><a href="#/docs/api/contracts" onClick={(e) => { e.preventDefault(); onNavigate('api/contracts'); }}>Contract &amp; Pipeline</a></td><td>What was awarded, to whom, and when does it expire?</td></tr>
          <tr><td>G</td><td><a href="#/docs/api/search" onClick={(e) => { e.preventDefault(); onNavigate('api/search'); }}>Semantic Search</a></td><td>What do strategic documents say about a topic?</td></tr>
          <tr><td>H</td><td><a href="#/docs/api/evidence" onClick={(e) => { e.preventDefault(); onNavigate('api/evidence'); }}>Evidence &amp; Claims</a></td><td>What's the evidence behind a statement?</td></tr>
          <tr><td>I</td><td><a href="#/docs/api/graph" onClick={(e) => { e.preventDefault(); onNavigate('api/graph'); }}>Knowledge Graph</a></td><td>How are entities connected?</td></tr>
          <tr><td>J</td><td><a href="#/docs/api/analytics" onClick={(e) => { e.preventDefault(); onNavigate('api/analytics'); }}>Advanced Analytics</a></td><td>What patterns, anomalies, and predictions emerge?</td></tr>
          <tr><td>K</td><td><a href="#/docs/api/artifacts" onClick={(e) => { e.preventDefault(); onNavigate('api/artifacts'); }}>Intelligence Artifacts</a></td><td>Generate structured reports from the substrate.</td></tr>
          <tr><td>M</td><td><a href="#/docs/api/sql-lookup" onClick={(e) => { e.preventDefault(); onNavigate('api/sql-lookup'); }}>SQL Lookup</a></td><td>Direct database access for tables not yet exposed via REST.</td></tr>
          <tr><td>N</td><td><a href="#/docs/api/source-material" onClick={(e) => { e.preventDefault(); onNavigate('api/source-material'); }}>Source Material</a></td><td>Access raw source documents, records, and crosswalks.</td></tr>
        </tbody>
      </table>
    </div>
    <h2>MCP Server</h2>
    <p>JSON-RPC 2.0 over Streamable HTTP at <code>/v1/mcp</code>. Tools map 1:1 to REST endpoints. Includes 16 prompt templates (8 analytical, 8 skill-based) for AI agent workflows, plus 7 inline resources providing methodology, dataset catalog, caveats, and notices.</p>
    <h2>Python SDK</h2>
    <p><code>pip install fpds-substrate</code> — typed Python client with a <code>Substrate</code> class and 9 ontology entity classes. Entity resolution is live; link traversals ship with the knowledge graph. Same API key as REST and MCP.</p>
    <PrevNext prev={{ id:'reference/glossary/tiers', label:'Glossary: Tiered Access' }} next={{ id:'reference/glossary/data', label:'Glossary: Data Terms' }} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// GLOSSARY G: DATA TERMS
// ============================================================================

const GlossaryData = ({ onNavigate }) => {
  const terms = [
    ['Corpus','A collection of source records from one system.'],
    ['awards_prime','FPDS prime contract award records. The largest record corpus.'],
    ['sam_opportunities','SAM.gov solicitation notices.'],
    ['agency_strategic_plans','Agency-published strategic plans and planning documents.'],
    ['agency_budget','Agency budget justification documents.'],
    ['agency_oversight','Agency-specific oversight reports (GAO, OIG).'],
    ['agency_policy','Agency-published policy documents and directives.'],
    ['govwide_legislative','Congressional legislation, bills, and public laws.'],
    ['govwide_oversight','Government-wide oversight reports (GAO, CRS).'],
    ['govwide_executive','Executive orders, presidential memoranda, OMB circulars.'],
    ['cfr','Code of Federal Regulations — procurement-related titles and sections.'],
    ['nih_reporter','NIH research project records (RePORTER database).'],
    ['sbir_awards','Small Business Innovation Research awards.'],
    ['far_clauses','Federal Acquisition Regulation clause text.'],
    ['federal_github','Federal agency open-source repositories and code.'],
    ['grants_prime','Federal grant and cooperative agreement awards.'],
    ['fac_audits','Federal Audit Clearinghouse single audit reports and findings.'],
    ['opm_workforce','OPM federal civilian workforce employment snapshots.'],
    ['Record','A single source object in the registry.'],
    ['Document','A typed government document, decomposed into chunks for retrieval.'],
    ['Document Chunk','A passage-level excerpt of a Document — the citable unit returned by semantic search.'],
    ['Embedding','A 1024-dimension vector representation of text generated by Qwen3-8B.'],
    ['Unified Embedding Space','The shared 1024-dimensional space where all corpora coexist, L2-normalized. A single query retrieves results across awards, solicitations, oversight reports, legislation, and strategic plans simultaneously — scored by cosine similarity, not keyword match.'],
    ['Instruction Prefix','Instruct: Identify the federal procurement topic of this document — the prompt prepended to text before embedding, shared across all vectors.'],
    ['reg_source_objects','The canonical source record registry. Foundation table of the entire substrate.'],
    ['Dataset','A pre-built analytics view in the catalog.'],
    ['Dimension','A code-lookup table (departments, NAICS, PSC, set-asides, vehicles, etc.).'],
    ['Cleaned Text','Text after AC boilerplate is stripped and artifacts are removed via the cleaning pipeline.'],
    ['FTS','Full-Text Search — PostgreSQL tsvector indexing for hybrid retrieval alongside vector search.'],
    ['Shard','A partition of a large corpus used for parallel training.'],
  ];

  return (
    <div>
      <Breadcrumb items={[
        { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
        { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
        { label:'Glossary: Data Terms' },
      ]} />
      <div className="docs-hero">
        <h1>Data Terms</h1>
        <p>Corpora, embeddings, records, chunks — the vocabulary of the FPDS data layer.</p>
      </div>
      <div className="docs-table-wrap">
        <table className="docs-table">
          <thead><tr><th>Term</th><th>Definition</th></tr></thead>
          <tbody>
            {terms.map((t, i) => (
              <tr key={i}>
                <td><strong>{t[0]}</strong></td>
                <td>{t[1]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <PrevNext prev={{ id:'reference/glossary/families', label:'Glossary: API & Tool Families' }} next={{ id:'reference/glossary/methodology', label:'Glossary: Methodology' }} onNavigate={onNavigate} />
    </div>
  );
};

// ============================================================================
// GLOSSARY H: METHODOLOGY & ANALYTICS
// ============================================================================

const GlossaryMethodology = ({ onNavigate }) => {
  const terms = [
    ['Topic Modeling','Discovering procurement topic clusters from text using BERTopic. Per-corpus training followed by cross-corpus merging and canonical theme promotion.'],
    ['Keyword Extraction','Multi-pattern string matching (Aho-Corasick) across procurement text to surface domain-specific capabilities, technologies, and vendors.'],
    ['Semantic Search','Vector-based retrieval across the unified embedding space. Queries are embedded and matched via cosine similarity, returning citable passages from any corpus.'],
    ['Entity Resolution','Mapping multiple source identifiers (CGAC, FPDS, AAC, DUNS, UEI) to a single canonical entity node.'],
    ['Convergence Scoring','Multi-model evidence weighting combining Dempster-Shafer belief functions, Analysis of Competing Hypotheses, Bayesian updating, and ICD-203 analytic standards.'],
    ['Delta Intelligence','Detecting topics present in one corpus but absent from another (e.g. oversight topics absent from awards data).'],
    ['Recompete Prediction','Estimating which contracts are likely to recompete and when, using survival modeling and temporal signals.'],
    ['Fiscal Year (FY)','Federal FY: Oct 1 of year N-1 through Sep 30 of year N. FY2026 = Oct 2025 – Sep 2026.'],
    ['Leiden Community Detection','Graph clustering used to validate topic stability before canonical promotion.'],
    ['Cosine Similarity','The distance metric for all vector comparisons in the embedding space.'],
  ];

  return (
    <div>
      <Breadcrumb items={[
        { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
        { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
        { label:'Glossary: Methodology' },
      ]} />
      <div className="docs-hero">
        <h1>Methodology &amp; Analytics</h1>
        <p>How the FPDS substrate works — the analytical methods and processes that produce procurement intelligence.</p>
      </div>
      <div className="docs-table-wrap">
        <table className="docs-table">
          <thead><tr><th>Term</th><th>Definition</th></tr></thead>
          <tbody>
            {terms.map((t, i) => (
              <tr key={i}>
                <td><strong>{t[0]}</strong></td>
                <td>{t[1]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <PrevNext prev={{ id:'reference/glossary/data', label:'Glossary: Data Terms' }} next={{ id:'reference/glossary/tools', label:'Glossary: Tools & Technologies' }} onNavigate={onNavigate} />
    </div>
  );
};

// ============================================================================
// GLOSSARY I: TOOLS & TECHNOLOGIES
// ============================================================================

const GlossaryTools = ({ onNavigate }) => {
  const tools = [
    ['BERTopic','Topic modeling framework using UMAP dimensionality reduction, HDBSCAN clustering, and c-TF-IDF term scoring.'],
    ['Qwen3-8B','The embedding model producing 1024-dimension vectors for all corpora.'],
    ['Aho-Corasick','Multi-pattern string matching algorithm for keyword extraction at scale.'],
    ['pgvector + IVFFlat','PostgreSQL vector indexing for similarity search across embeddings.'],
    ['Claude (Anthropic)','LLM used for topic labeling and artifact generation.'],
    ['DeepSeek','LLM backend for artifact generation and capture orchestration.'],
    ['Ollama','Local LLM runtime — supported as a BYO-model option for artifact generation.'],
    ['Supabase','Database platform (PostgreSQL + pgvector) hosting the substrate.'],
    ['FastAPI','Python web framework powering the REST API service.'],
    ['React (18)','Frontend framework for the chat interface and documentation site.'],
    ['Dempster-Shafer (pyDS)','Belief function library for evidence fusion in convergence scoring.'],
    ['Lifelines','Survival analysis library for Fine-Gray competing risks modeling.'],
    ['scikit-learn','Core ML library for clustering, classification, and evaluation.'],
    ['UMAP','Dimensionality reduction algorithm used in BERTopic for projecting embeddings into clusterable space.'],
    ['HDBSCAN','Hierarchical density-based clustering algorithm used to discover topic boundaries.'],
    ['YAKE','Keyword extraction algorithm used in the zero-cost extraction pipeline.'],
    ['KeyBERT','Keyword extraction using BERT embeddings — used for query-side keyword extraction in BERT-GraphRAG.'],
    ['Jinja2','Template engine for report generation in the Artifact Factory.'],
    ['PyTorch','Deep learning framework for embedding generation and LLM training.'],
    ['LlamaFactory / Unsloth','Training frameworks for domain-adaptive pretraining of the procurement LLM.'],
    ['Llama-3.2-3B-Instruct','Base model for the Government-Native Procurement LLM R&D initiative.'],
  ];

  return (
    <div>
      <Breadcrumb items={[
        { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
        { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
        { label:'Glossary: Tools & Technologies' },
      ]} />
      <div className="docs-hero">
        <h1>Tools &amp; Technologies</h1>
        <p>The full technology stack powering the FPDS substrate — from embedding models to clustering libraries to deployment infrastructure.</p>
      </div>
      <div className="docs-table-wrap">
        <table className="docs-table">
          <thead><tr><th>Tool / Technology</th><th>What It Is</th></tr></thead>
          <tbody>
            {tools.map((t, i) => (
              <tr key={i}>
                <td><strong>{t[0]}</strong></td>
                <td>{t[1]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <PrevNext prev={{ id:'reference/glossary/methodology', label:'Glossary: Methodology' }} next={{ id:'reference/conventions', label:'Error Codes & Conventions' }} onNavigate={onNavigate} />
    </div>
  );
};

// ============================================================================
// SECTION: ERROR CODES & CONVENTIONS (moved from old ReferenceDocs)
// ============================================================================

const ConventionsRef = ({ onNavigate }) => (
  <div>
    <Breadcrumb items={[
      { label:'Docs', href:'#/docs', onClick:() => onNavigate('getting-started') },
      { label:'Glossary', href:'#/docs/reference', onClick:() => onNavigate('reference') },
      { label:'Error Codes & Conventions' },
    ]} />
    <div className="docs-hero"><h1>Error Codes &amp; Conventions</h1><p>API error codes, naming conventions, and usage standards.</p></div>

    <h2>Error Codes</h2>
    <div className="docs-table-wrap">
      <table className="docs-table">
        <thead><tr><th>Code</th><th>HTTP</th><th>Meaning</th></tr></thead>
        <tbody>
          <tr><td><code>dataset_not_found</code></td><td>404</td><td>Unknown dataset_id</td></tr>
          <tr><td><code>dimension_not_found</code></td><td>404</td><td>Unknown dimension_id</td></tr>
          <tr><td><code>invalid_filter</code></td><td>400</td><td>Filter name/value not in allowlist</td></tr>
          <tr><td><code>invalid_field</code></td><td>400</td><td>Requested field not in allowlist</td></tr>
          <tr><td><code>invalid_sort</code></td><td>400</td><td>Sort column not in allowlist</td></tr>
          <tr><td><code>rate_limit_exceeded</code></td><td>429</td><td>Too many requests in window</td></tr>
          <tr><td><code>upgrade_required</code></td><td>403</td><td>Tool requires higher tier</td></tr>
          <tr><td><code>unauthorized</code></td><td>401</td><td>Missing or invalid API key</td></tr>
          <tr><td><code>internal_error</code></td><td>500</td><td>Unhandled server error</td></tr>
        </tbody>
      </table>
    </div>

    <h2>Conventions</h2>
    <ul>
      <li><strong>Naming:</strong> <code>snake_case</code> paths, <code>fpds_</code> prefix for discovery tools, domain prefix for specialized tools (<code>keyword_*</code>, <code>topic_*</code>).</li>
      <li><strong>Hedge prefixes:</strong> <code>suggested_*</code>, <code>assessed_*</code>, <code>estimated_*</code>, <code>inferred_*</code>, <code>pattern_*</code> on computed fields.</li>
      <li><strong>Dept codes:</strong> FPDS 4-digit (<code>7000</code>) or USASpending 3-digit (<code>070</code>). Use <code>fpds_resolve</code>.</li>
      <li><strong>FY:</strong> Oct 1 – Sep 30. FY2026 = Oct 2025 – Sep 2026.</li>
      <li><strong>Freshness:</strong> Awards/SAM: daily. Web docs: weekly. Check <code>meta.data_as_of</code>.</li>
    </ul>

    <PrevNext prev={{ id:'reference/glossary/tools', label:'Glossary: Tools & Technologies' }} next={null} onNavigate={onNavigate} />
  </div>
);

// ============================================================================
// MAIN DOCS COMPONENT
// ============================================================================

const DOCS_SECTION_MAP = {
  'getting-started': GettingStarted,
  'api': APIOverview,
  'api/discovery': APIDiscovery,
  'api/spending': APISpending,
  'api/vendors': APIVendorIntelligence,
  'api/topics': APITopicIntelligence,
  'api/keywords': APIKeywordGraph,
  'api/contracts': APIContractPipeline,
  'api/search': APISemanticSearch,
  'api/evidence': APIEvidenceClaims,
  'api/graph': APIKnowledgeGraph,
  'api/analytics': APIAdvancedAnalytics,
  'api/artifacts': APIIntelligenceArtifacts,
  'api/source-material': APISourceMaterial,
  'api/sql-lookup': APISQLLookup,
  'mcp': MCPDocs,
  'sdk': SDKDocs,
  'reference': ReferenceOverview,
  'reference/glossary/core': GlossaryCore,
  'reference/glossary/ontology': GlossaryOntology,
  'reference/glossary/links': GlossaryLinks,
  'reference/glossary/codes': GlossaryCodes,
  'reference/glossary/tiers': GlossaryTiers,
  'reference/glossary/families': GlossaryFamilies,
  'reference/glossary/data': GlossaryData,
  'reference/glossary/methodology': GlossaryMethodology,
  'reference/glossary/tools': GlossaryTools,
  'reference/conventions': ConventionsRef,
};

const Docs = () => {
  const [current, setCurrent] = React.useState('getting-started');

  React.useEffect(() => {
    const parseHash = () => {
      const raw = window.location.hash;
      const section = raw.replace('#/docs/', '').replace('#/docs', '') || 'getting-started';
      const clean = section.replace(/\/$/, '');
      setCurrent(clean || 'getting-started');
      window.scrollTo({ top: 0, behavior: 'instant' });
    };
    parseHash();
    window.addEventListener('hashchange', parseHash);
    return () => window.removeEventListener('hashchange', parseHash);
  }, []);

  const navigate = React.useCallback((section) => {
    window.location.hash = '#/docs/' + section;
  }, []);

  const getContent = () => {
    if (DOCS_SECTION_MAP[current]) return DOCS_SECTION_MAP[current];
    const parts = current.split('/');
    for (let i = parts.length - 1; i >= 1; i--) {
      const parent = parts.slice(0, i).join('/');
      if (DOCS_SECTION_MAP[parent]) return DOCS_SECTION_MAP[parent];
    }
    return GettingStarted;
  };

  const Content = getContent();

  return (
    <>
      <PageCanvas variant="engineering"/>
      <div className="docs-shell">
        <DocsSidebar current={current} onNavigate={navigate} />
        <main className="docs-content">
          <Content onNavigate={navigate} />
        </main>
      </div>
    </>
  );
};

window.Docs = Docs;
