diff --git a/.claude/worktrees/relaxed-mcclintock b/.claude/worktrees/relaxed-mcclintock deleted file mode 160000 index 2ebe237..0000000 --- a/.claude/worktrees/relaxed-mcclintock +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2ebe237aab189a1827a8263b166707f45d4bd965 diff --git a/.gitignore b/.gitignore index b22f8a0..0680ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ dist/ # generated types .astro/ +# Claude Code agent worktrees / local config +.claude/ + # dependencies node_modules/ diff --git a/astro.config.mjs b/astro.config.mjs index a183d63..10b8ea8 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -41,10 +41,6 @@ export default defineConfig({ label: 'CLI', autogenerate: { directory: 'cli' }, }, - { - label: 'x402 Proxy', - autogenerate: {directory:'x402proxy'}, - }, { label: 'Facilitator', autogenerate: {directory:'facilitator'}, diff --git a/opentui-drafts/tunnel-setup.html b/opentui-drafts/tunnel-setup.html new file mode 100644 index 0000000..1c7eb32 --- /dev/null +++ b/opentui-drafts/tunnel-setup.html @@ -0,0 +1,741 @@ + + + + + Consensus · Tunnel Setup (opentui-faithful) + + + + + + + + +
+ +
+
+
+
consensus — ~/code/consensus — 168×42
+
$ consensus tunnel
+
+ +
+ + +
+
+ CONSENSUS + your private network, on demand +
+
+ connected + acct bob + bal $24.18 + v 2.4.1 +
+
+ + +
+
+
+ + Tunnels/New tunnel +
+
pick a local process or LAN device — we'll mint the public URL
+
+
+ Protocol +
+ + +
+
+
+ + +
+ + +
+
Local processes
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#PortProcess
1:3000node · my-api
2:5173vite
3:8000python -m http
:5432postgres · system
+
R rescan local · 4 ports
+
+ + +
+
LAN devices
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#IPHostPorts
4192.168.1.1gateway:80, :443
5192.168.1.66esp32-sensor:80
6192.168.1.42pi-camera:8554
7192.168.1.55homelab-ha:8123
+
+ 3 devices hidden + A show all + · + L rescan LAN +
+
+ +
+ + +
+
Target
+
+
+
+
+ Target + localhost +
+
IP address or hostname
+
+
+
+ Port + 3000 + optional — leave blank to use default +
+
+
✕ placeholder
+
+ +
+ Will create + https://amber-otter.consensus.canister.software + + + localhost:3000 + · + http · region auto · free tier + +
+ + or press +
+
+
+
+ + +
+
+ Bookmarks + M save current · O load +
+
+
+ 1 + my-api + http + localhost:3000 + 2h ago +
+
+ 2 + homelab-ha + http + 192.168.1.55:8123 + 1d ago +
+
+ 3 + db-tunnel + tcp + 192.168.1.42:22 + 3d ago +
+
+
+ + +
+ 1-7select + Rrescan local + Lrescan LAN + Ashow all + Mbookmark + ↑↓navigate + start + Bback + + tunnel setup +
+ +
+
+ +
+ screen tunnel setup (pick a target) + grid 168×42 cells · jetbrains mono + palette rosé pine + toggle use the Tweaks button to flip protocol / theme / tier +
+ +
+ + + + + + + +
+ + + + + diff --git a/public/JavaScript-logo.png b/public/JavaScript-logo.png new file mode 100644 index 0000000..0da1dcd Binary files /dev/null and b/public/JavaScript-logo.png differ diff --git a/public/chains/ethereum.png b/public/chains/ethereum.png new file mode 100644 index 0000000..19f0aa0 Binary files /dev/null and b/public/chains/ethereum.png differ diff --git a/public/chains/icp.png b/public/chains/icp.png new file mode 100644 index 0000000..ba5346a Binary files /dev/null and b/public/chains/icp.png differ diff --git a/public/chains/solana.svg b/public/chains/solana.svg new file mode 100644 index 0000000..14c18b3 --- /dev/null +++ b/public/chains/solana.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/public/logo-light.svg b/public/logo-light.svg new file mode 100644 index 0000000..838623f --- /dev/null +++ b/public/logo-light.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/opentui/nodes.html b/public/opentui/nodes.html new file mode 100644 index 0000000..a07217e --- /dev/null +++ b/public/opentui/nodes.html @@ -0,0 +1,484 @@ + + + + + Consensus · Nodes (opentui-faithful) + + + + + + + + +
+ +
+
+
+
consensus — ~/code/consensus — 168×46
+
$ consensus nodes
+
+ +
+ + +
+
+ CONSENSUS + your private network, on demand +
+
+ connected + acct bob + bal $24.18 + v 2.4.1 +
+
+ + +
+
+
+ + Nodes +
+
lease a node to pin all tunnel, proxy & socket traffic to it
+
+
148 nodes · 5 regions · refreshed 12s ago
+
+ + +
+ + No lease active — traffic uses automatic node selection +
+ + +
+ + + + + + + sort: score ↓ +
+ + +
+
Available nodes
+ + + + + + + + + + + + + + + +
NodeDomainRegionIPScoreLatencyLoadCaps
+
+ ↑↓ navigate + lease selected + · + showing 8 of 148 · pin all proxy/tunnel/ws traffic to this node +
+
+ + +
+ ↑↓navigate + lease selected + Drelease + /filter + Rrefresh + Bback + + node browser +
+ +
+ + +
+ +
+ +
+ +
+ screen nodes (browse & lease) + grid 168×46 cells · jetbrains mono + palette rosé pine + toggle click a row then ↵ / Lease · use Tweaks for theme / tier +
+ +
+ + + + + + diff --git a/public/opentui/proxy.html b/public/opentui/proxy.html new file mode 100644 index 0000000..cd2a23a --- /dev/null +++ b/public/opentui/proxy.html @@ -0,0 +1,490 @@ + + + + + Consensus · Proxy Live (opentui-faithful) + + + + + + + + +
+ +
+
+
+
consensus — ~/code/consensus — 168×46
+
$ consensus proxy forward
+
+ +
+ + +
+
+ CONSENSUS + your private network, on demand +
+
+ live + acct bob + tier free + v 2.4.1 +
+
+ + +
+
RUNNING :8080
+
+ app :3000consensus·preload +
+
uptime 00:42:18
+
+ + +
+
+ Requests + 1,204 + ~26 / min +
+
+ Last status + 200 + success +
+
+ Cache hits + n/a + reverse only +
+ + +
+ Success rate + 98% + last 40 checks +
+
+ + +
+ + +
+
+
Latency · last 40
+
+
+ current38 ms + avg52 ms + p95180 ms + samples40 +
+
+ +
+
Throughput
+
+
+ ↑ Sent + 8.42 MB + 112.4 KB/s +
+
+ ↓ Received + 41.7 MB + 486.1 KB/s +
+
+
+ +
+
Recent checks
+
+
39 ok · 1 failed · last 40 health probes
+
+
+ + +
+
+
App control
+
+ App status + running pid 4821 +
+
+ Last probe + reachable · 200 /healthz · 31 ms · 2s ago +
+
+ Launch cmd + bun --preload .consensus-preload.ts ~/code/my-api/server.ts +
+
+ Fetch mode + preload → globalThis.fetch → consensus +
+
+ Preload + .consensus-preload.ts · auto restart enabled +
+
+ Routing + inclusive · /api, /v2 · subroutes on +
+
+ Node + us-west-1 · auto · 38 ms +
+
+ + +
+
+
+ +
+ + +
+ Llaunch + Ttest + ↑↓scroll + Sstop proxy + Bback + + forward proxy · live +
+ +
+
+ +
+ screen proxy live (running dashboard) + grid 168×46 cells · jetbrains mono + palette rosé pine + toggle use Tweaks to flip type / theme / tier +
+ +
+ + + + + + diff --git a/public/opentui/tunnel.html b/public/opentui/tunnel.html new file mode 100644 index 0000000..76907b8 --- /dev/null +++ b/public/opentui/tunnel.html @@ -0,0 +1,673 @@ + + + + + Consensus · Active Tunnel (opentui-faithful) + + + + + + + + +
+ +
+
+
+
consensus — ~/code/consensus — 168×42
+
$ consensus tunnel http localhost:3000
+
+ +
+ + +
+
+ CONSENSUS + your private network, on demand +
+
+ live + acct bob + bal $24.18 + v 2.4.1 +
+
+ + +
+
CONNECTED
+
+ https://amber-otter.consensus.canister.software + +
+
uptime 01:24:07
+
+ + +
+
+ Forwarding to + localhost:3000 + http · node · my-api +
+
+ Requests + 3,418 + ~14 / min +
+
+ Active + 2streams + live connections +
+
+ ↑ Sent + 8.42MB + ↓ 41.7 MB recv +
+
+ Error rate + 1.2% + last 100 reqs +
+
+ + +
+
Activity
+
+ streaming + + 20 most recent · newest on top +
+ + + + + + + + + + +
TimeMethodPathStatusLatencySize
+
+ + +
+
latency 38ms
+
avg 52ms
+
p95 180ms
+
last 40 + +
+
+
region sfo · auto
+
+ + +
+ Cclear log + Ffilter + Ppause stream + ↑↓scroll + inspect + Qstop tunnel + + active tunnel +
+ +
+
+ +
+ screen active tunnel (live traffic) + grid 168×42 cells · jetbrains mono + palette rosé pine + toggle use Tweaks to flip theme / protocol / live stream +
+ +
+ + + + + + diff --git a/public/opentui/websocket.html b/public/opentui/websocket.html new file mode 100644 index 0000000..edaed89 --- /dev/null +++ b/public/opentui/websocket.html @@ -0,0 +1,379 @@ + + + + + Consensus · WebSocket Live (opentui-faithful) + + + + + + + + +
+ +
+
+
+
consensus — ~/code/consensus — 168×42
+
$ consensus ws · hybrid 60min 500MB
+
+ +
+ + +
+
+ CONSENSUS + your private network, on demand +
+
+ live + acct bob + bal $24.18 + v 2.4.1 +
+
+ + +
+
CONNECTED
+
HYBRID · 60 min · 500 MB · node sfo-3
+
expires 59:41 remaining
+
+ + +
+
Messages
+ + + + + + +
TimeDirMessageBytes
+
waiting for messages…
+
+ + + + + +
+
data + + 3.1 KB/ 500 MB +
+
rtt
+
avg
+
p95
+
msgs0
+
+
uptime00:00:18
+
+ + +
+ Ssend + Cclear + Qclose session + + websocket · live +
+ +
+
+ +
+ screen websocket live (metered socket) + grid 168×42 cells · jetbrains mono + palette rosé pine + try press S to compose · type · ↵ to send (server echoes back) +
+ +
+ + + + + + diff --git a/public/typescript_logo.webp b/public/typescript_logo.webp new file mode 100644 index 0000000..d90a4c9 Binary files /dev/null and b/public/typescript_logo.webp differ diff --git a/src/components/Head.astro b/src/components/Head.astro index 33e2753..68becfd 100644 --- a/src/components/Head.astro +++ b/src/components/Head.astro @@ -31,6 +31,14 @@ const hasTwitterCard = hasMeta('name', 'twitter:card'); {!hasTwitterImage && } {!hasTwitterCard && } + + + + + diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx deleted file mode 100644 index 05a3ef5..0000000 --- a/src/content/docs/index.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Consensus Protocol -description: Get started building with Consensus. -template: splash -hero: - tagline: A decentralised x402 HTTPS proxy and websocket service network. - image: - dark: ../../assets/logo-light.svg - light: ../../assets/logo-dark.svg - actions: - - text: Learn more - link: /protocol/info/ - icon: right-arrow - - text: Read the Whitepaper - link: "#whitepaper" - variant: minimal - attrs: - class: wp-cta - aria-haspopup: dialog ---- - -import WhitepaperModal from "../../components/WhitepaperModal.astro"; - - diff --git a/src/content/docs/x402proxy/networks.md b/src/content/docs/x402proxy/networks.md deleted file mode 100644 index 3efbf00..0000000 --- a/src/content/docs/x402proxy/networks.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Supported Tokens & Networks -description: Define supported tokens and networks ---- - - \ No newline at end of file diff --git a/src/content/docs/x402proxy/x402.md b/src/content/docs/x402proxy/x402.md deleted file mode 100644 index ab4796d..0000000 --- a/src/content/docs/x402proxy/x402.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: What is x402? -description: The HTTP payment protocol that powers Consensus — how 402 challenges work, what clients and servers exchange, and how the flow is implemented -sidebar: - order: 1 ---- - -x402 is an open payment protocol built on top of HTTP. It gives any HTTP endpoint the ability to require a micropayment before responding, using the standard `402 Payment Required` status code as a machine-readable payment challenge. - -The protocol is network-agnostic — the same flow works over ICP, EVM, and Solana. Consensus implements x402 on both sides: the server issues challenges and the client handles them transparently. - ---- - -## The Payment Flow - -Every x402 interaction follows four steps: - -``` -Client Resource Server Facilitator - │ │ │ - ├─── GET /api/data ────────────►│ │ - │ │ │ - │◄── 402 Payment Required ──────┤ │ - │ X-Payment-Required: {...} │ │ - │ │ │ - │ (client signs payment) │ │ - │ │ │ - ├─── GET /api/data ────────────►│ │ - │ X-Payment: {...} │ │ - │ ├─── verify payment ────────►│ - │ │◄── verified ───────────────┤ - │◄── 200 OK ────────────────────┤ │ -``` - -**Step 1 — Initial request** -The client sends a normal HTTP request. No special headers are required. - -**Step 2 — Payment challenge** -The server responds `402 Payment Required` with a `X-Payment-Required` header containing a JSON object that describes what payment is needed: - -```json -{ - "scheme": "exact", - "network": "icp:1:xafvr-biaaa-aaaai-aql5q-cai", - "maxAmountRequired": "100000", - "payTo": "", - "description": "Premium data endpoint", - "mimeType": "application/json" -} -``` - -**Step 3 — Client pays** -The client reads the challenge, signs and submits a payment on the specified network, then retries the original request with the signed proof in the `X-Payment` header. - -**Step 4 — Verification and response** -The server forwards the payment proof to the facilitator. The facilitator verifies on-chain settlement and returns confirmation. The server then processes the request and returns the response. - -From the client's perspective, steps 2–4 are invisible. `wrapFetchWithPayment` intercepts the `402`, handles the payment, and returns the final `200` response. - ---- - -## The `X-Payment-Required` Header - -When the server issues a `402`, the `X-Payment-Required` header contains a JSON object with the following fields: - -| Field | Type | Description | -|---|---|---| -| `scheme` | `string` | Payment scheme — always `"exact"` for Consensus | -| `network` | `string` | Network identifier — see [Supported Networks](/x402proxy/networks/) | -| `maxAmountRequired` | `string` | Maximum amount the server will accept as payment | -| `payTo` | `string` | Address or principal that receives the payment | -| `description` | `string` | Human-readable description of what is being paid for | -| `mimeType` | `string` | MIME type of the response once payment is accepted | - -A single route can advertise multiple accepted networks simultaneously. The client picks one. - ---- - -## The `X-Payment` Header - -After paying, the client attaches proof in the `X-Payment` header. The exact structure is scheme- and network-specific, but always includes: - -| Field | Type | Description | -|---|---|---| -| `scheme` | `string` | Must match the scheme from the challenge | -| `network` | `string` | Must match the network from the challenge | -| `payload` | `string` | Signed payment proof — format is network-specific | - -The server does not validate this itself — it forwards it to the facilitator, which does the chain-level verification. - ---- - -## The `exact` Scheme - -Consensus uses the `exact` scheme exclusively. Under this scheme: - -- The client pays **exactly** the amount specified in `maxAmountRequired` -- No range, no estimation, no partial payment -- Payment goes directly to `payTo` on-chain -- The facilitator confirms that the exact transfer occurred before the server responds - -This makes pricing deterministic and auditable — both the client and server know the cost before any payment is made. - ---- - -## Implementation - -For complete setup guides on both sides of the payment flow: - -- **[Facilitator — Resource Server](/facilitator/resource-server/)** — protect Express routes with `paymentMiddleware`, connect to the facilitator, accept multiple networks -- **[Facilitator — Client](/facilitator/client/)** — build a client with `wrapFetchWithPayment` across ICP, EVM, and Solana -- **[Supported Networks](/facilitator/networks/)** — every network and token the facilitator accepts diff --git a/src/pages/index.astro b/src/pages/index.astro new file mode 100644 index 0000000..cb60157 --- /dev/null +++ b/src/pages/index.astro @@ -0,0 +1,486 @@ + + + + + + Consensus | Tunnels, proxies, and stable IPs + + + + + + + + + +
+ + +
+ + +
+ + +
+
+ +
+
Proxies & tunnels on-demand
+

+ Tunnels, proxies, and stable IPs. + No accounts. No API keys. +

+

Expose local HTTP/TCP services, route traffic via forward/reverse proxies, and instantly get stable IPs for whitelisted gateways.

+
+ $ + npm i @canister-software/consensus-cli + +
+
+
+ + +
+
The CLI & TUI
+

The whole network, from the terminal.

+

A CLI and a full-screen TUI, built with OpenTUI. Four primitives, one binary: tunnels, deduplicated proxies, leased IPs, and metered sockets.

+ + +
+
+ 01 +

+ TUNNELS: Expose local services natively via the CLI +

+
+
+ +
+
+
+
$ consensus tunnel http localhost:3000
+
+ Tunnel online
+  https://amber-otter.consensus.canister.software  localhost:3000
+  
+
+
+
One command to Live
+

Put a local port or device on a public HTTPS URL in seconds. No signup, monitor every request in real time.

+
+
+
+ + +
+
+ 02 +

+ PROXIES: Wrap fetch(). Ship secured. +

+
+
+ +
+
+
+
import { ProxyClient } from '@canister-software/consensus-cli'
+
+// intercepts outbound HTTP transparently
+const fetch = ProxyClient.wrap(globalThis.fetch)
+
+const res = await fetch('https://external.com', {
+  region:   'us-east',
+  caching:  true,
+  spendCap: '0.05',   // stands down to direct fetch when hit
+})
+
+
+
Drop-in SDK
+

Wrap fetch() once and every outbound call routes through Consensus: protected, deduplicated, cached, and metered per request. Existing route handlers stay untouched.

+
+
+
+ + +
+
+ 03 +

+ STABLE IPs: Verify and pin traffic to a static IP +

+
+
+ +
+
+
+
$ consensus ip list --region us-east
+NODE ID   DOMAIN                                     REGION   SCORE
+7f3a91    cobalt-heron.consensus.canister.software   us-east  94
+
+$ consensus ip lease cobalt-heron.consensus.canister.software
+ Leased: cobalt-heron.consensus.canister.software (traffic pinned)
+
+
+
Pin the IP
+

Lease a verified, performant node and pin every tunnel, proxy, and socket to one static IP. Whitelist once, reconnect automatically, stop fighting dynamic firewalls.

+
+
+
+ + +
+
+ 04 +

+ WEBSOCKETS: Prepaid, metered sessions for stateless apps +

+
+
+ +
+
+
+
import { SocketClient } from '@canister-software/consensus-sdk'
+
+const client = SocketClient(fetchWithPayment)
+
+// prepay a bounded, metered session
+const auth = await client.requestToken({
+  model: 'hybrid', minutes: 60, mb: 500,
+})
+
+const session = await client.connect(auth)
+session.on('message', (m) => console.log('recv', m))
+
+
+
Prepaid & metered
+

Prepay time, data, or both. Each persistent session is metered by the protocol and closed cleanly once the budget runs out. No accounts, no state.

+
+
+
+
+ + +
+
+
+

Pay on any of three networks.

+ one facilitator · the exact scheme +
+
+
+ Ethereum +
+ Ethereum + Mainnet +
+
+
+ Solana +
+ Solana + Mainnet +
+
+
+ Internet Computer +
+ Internet Computer + Mainnet +
+
+
+
+
+ + +
+
+
+
+

Pure application-level routing with a Cache.

+
+

Wire native proxy handlers directly into your JavaScript/TypeScript processes using clean dependency injection, and manage parameters locally via secure profiles.

+
+ +
+ +
+
+ Integration + 01 +
+
Drop-in SDK, or dependency injection
+

Two ways to wire into a codebase. Import the SDK and call ProxyClient or SocketClient as middleware directly in application code, or hand the protocol native handlers through dependency injection. Both paths run at the application level and never decrypt HTTPS, so existing request logic and TLS stay exactly as written.

+
+ +
+
+ Configuration + 02 +
+
No accounts. Local profiles.
+

Nothing to sign up for and no keys to rotate. Configuration lives in local profiles on the machine. Create named profiles, customize defaults and spend limits per project, and switch between them instantly, with nothing held on a remote server.

+
+ +
+
+ Security + 03 +
+
Vetted nodes, encrypted channels
+

Every node earns its place. Before serving any traffic a node clears a performance benchmark, and a heartbeat every five minutes keeps only healthy, responsive nodes in rotation. Traffic between the runtime and each node travels over encrypted channels, so data in transit stays protected across every hop.

+
+ +
+ +
+ Built for JavaScript & TypeScript runtimes + + JavaScript + TypeScript + +
+
+
+ + +
+ +
+
+
Built for speed · shipped via the CLI
+

One command. You're on the network.

+ +
+ $ + npm i -g @canister-software/consensus-cli + +
+ +

Looking to host infrastructure? Join the network as a node operator →

+
+
+ + + + +
+ + + + + diff --git a/src/styles/custom.css b/src/styles/custom.css index d4506a2..9e1fae0 100644 --- a/src/styles/custom.css +++ b/src/styles/custom.css @@ -1,3 +1,36 @@ +/* ============================================================ + Consensus docs theme — matches the landing page. + Fonts: Space Grotesk (UI/headings) + JetBrains Mono (code/labels). + Requires the font in Head.astro (see note at bottom). + ============================================================ */ + +/* ---- Type system ---- */ +:root { + --sl-font: 'Space Grotesk', system-ui, -apple-system, sans-serif; + --sl-font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace; +} + +/* Headings a touch tighter, like the landing */ +.sl-markdown-content h1, +.sl-markdown-content h2, +.sl-markdown-content h3, +.content-panel h1, +h1, h2, h3 { + letter-spacing: -0.02em; + font-weight: 600; +} + +/* Mono for eyebrows / sidebar group labels for the protocol-grade feel */ +.sidebar-content summary, +.sidebar-content .large, +nav.sidebar .top-level > li > a[aria-current] { + font-family: var(--sl-font-mono); + font-size: 0.72rem; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +/* ---- Accent + surface tokens (monochrome) ---- */ :root { --sl-color-accent: #fff; --sl-color-accent-high: #fff; @@ -17,10 +50,56 @@ :root[data-theme='dark'] { --sl-color-black: #000; --sl-color-bg: #000; - --sl-color-bg-nav: #000; + --sl-color-bg-nav: rgba(0, 0, 0, 0.55); --sl-color-bg-sidebar: #000; + /* hairline borders to echo the landing */ + --sl-color-hairline-shade: rgba(255, 255, 255, 0.07); + --sl-color-hairline: rgba(255, 255, 255, 0.07); + --sl-color-gray-5: #0a0a0b; + --sl-color-gray-6: #060607; +} + +/* Blurred sticky header, like the landing nav */ +:root[data-theme='dark'] .header { + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); + border-bottom: 1px solid rgba(255, 255, 255, 0.07); } +/* Code blocks: bordered panel on near-black, matching the landing snippets */ +:root[data-theme='dark'] .sl-markdown-content pre { + background: #060607 !important; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; +} +.sl-markdown-content code { + font-family: var(--sl-font-mono); +} + +/* Inline code chips */ +:root[data-theme='dark'] .sl-markdown-content :not(pre) > code { + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 6px; +} + +/* Subtle link underline in prose */ +.sl-markdown-content a { + text-underline-offset: 0.2em; +} + +/* Cards / asides pick up the hairline look in dark mode */ +:root[data-theme='dark'] .card, +:root[data-theme='dark'] starlight-aside { + border-color: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.018); + border-radius: 14px; +} + +/* ============================================================ + Existing rules (diagrams, lightbox, whitepaper CTA) + ============================================================ */ + .consensus-diagram { width: 100%; display: none;