diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png index 2ab9808..357d5d8 100644 Binary files a/web/apple-touch-icon.png and b/web/apple-touch-icon.png differ diff --git a/web/favicon-16.png b/web/favicon-16.png index 402e203..9db65e1 100644 Binary files a/web/favicon-16.png and b/web/favicon-16.png differ diff --git a/web/favicon-32.png b/web/favicon-32.png index cb5cc79..352e9b8 100644 Binary files a/web/favicon-32.png and b/web/favicon-32.png differ diff --git a/web/favicon.ico b/web/favicon.ico index 3181779..26f0d39 100644 Binary files a/web/favicon.ico and b/web/favicon.ico differ diff --git a/web/icon-512.png b/web/icon-512.png index 3fb1612..dc3a143 100644 Binary files a/web/icon-512.png and b/web/icon-512.png differ diff --git a/web/index.html b/web/index.html index 17da9cc..ec6ee48 100644 --- a/web/index.html +++ b/web/index.html @@ -3,15 +3,15 @@ -QuantaDB - +QuantaDB — an OLTP database measured in the open + - + - + @@ -19,284 +19,186 @@ -
-
- QuantaDB - v0.2.0, experimental -
-
+ -
- -
-
-

A durable OLTP engine, written in Rust

-

A database that shows its work.

-

- Every page is checksummed. Every commit waits for the log. Every - benchmark names the machine it ran on, and a result is thrown out if a - single correctness test fails. QuantaDB is being built the slow way: - storage first, proofs before promises. +

+
+
+

An OLTP database, measured in the open.

+

+ QuantaDB is a storage engine written in Rust and spoken to over the + PostgreSQL wire protocol. Every benchmark names the machine it ran on, + runs beside PostgreSQL, MySQL and MariaDB, and gets published whether it + wins or loses.

-
-
- data page 42, byte for byte -
-
-
- 0000 - 51 4E 50 47 - magic "QNPG": this is a page -
-
- 0004 - 01 00  00 00 - format v1, reserved -
-
- 0008 - 2A 00 00 00 00 00 00 00 - page ID 42, little endian -
-
- 0010 - C4 01 00 00 00 00 00 00 - last applied log sequence number -
-
- 0018 - 9A 00 00 00 - payload length, 154 bytes -
-
- 001C - 7B 3D 91 C8 - CRC32 over the whole page -
-
- 0020 - 00 00 00 00 … - 32 reserved bytes -
-
- 0040 - 51 4E 4D 56 01 00 00 00 - payload: an MVCC version record, "QNMV" +
+
+
22,528Reads per second, ahead of PostgreSQL
+
<1 msRead latency at the 99th percentile
+
5Machine profiles benched per change
+
Apache-2.0Open source, no paid tier
+
+
+
+ +
+
+
+

Why it exists

+

Most database benchmarks are marketing. These are not.

+

+ Performance claims usually arrive without the hardware, the + competitors, or the runs that went badly. QuantaDB publishes all + three, because a number you cannot reproduce is not a number. +

+
+
+
+

Durable by default

+

+ A commit returns once its record is on disk. Pages carry checksums, + the log is replayed on restart, and corruption is detected rather + than assumed away. There is no faster mode that quietly drops this. +

-
- 0048 - 1D 00 00 00 00 00 00 00 - committed at timestamp 29 +
+

Readers never wait for writers

+

+ Snapshot isolation with multi-version reads. A query sees a + consistent moment in time and takes no locks, so a long read cannot + be blocked by a slow commit. +

-
- 0050 - - key, value, zero padding to 8192 +
+

Speaks PostgreSQL

+

+ Connect with psql, psycopg, or any Postgres driver you already use. + There is a native protocol and a browser client too, but nothing + forces you onto them. +

-

- A page is never written before its log record and batch commit are on - disk. Recovery replays complete batches only, so a crash exposes all of - a commit or none of it. -

- +
-
-
-

On disk

-

Five magics, one rule: versioned, checksummed, documented.

-

- Everything QuantaDB persists starts with four bytes that say what it is - and a version that says how to read it. Readers verify before trusting. - The formats are documented in the repository down to the byte, because a - storage engine you cannot audit is a storage engine you cannot trust. +

+
+
+

Benchmarks

+

Four engines, identical containers, one driver.

+

+ Each database runs alone at 2 CPUs and 2 GiB with default durability, + driven by the same client over the same protocol. Operations per + second, higher is better. +

+
+ +
+ + + + + + + + + + +
EngineReadsMixed 80/20Writes
QuantaDB22,52816,7748,374
PostgreSQL 1817,06017,00611,404
MariaDB 11.43,7354,0066,741
MySQL 8.43,8043,8454,847
+
+

+ QuantaDB leads on reads and ties on mixed. PostgreSQL still leads on + writes, and the gap is tracked in the open. Read throughput for MySQL and + MariaDB is limited by the shared Python driver; their write numbers are + server bound.

-
-
    -
  • QNPGdata page8192 bytes, CRC32, identity checked on every read
  • -
  • QNWLlog recordphysical page image, batch commit, or checkpoint
  • -
  • QNMVversion recordkey, optional value, commit timestamp
  • -
  • QNIXindex nodeimmutable B+ tree leaf or internal node
  • -
  • QNIRindex root48 byte manifest publishing one generation
  • -
+
-
-
-

Architecture

-

Six crates, one direction.

-

- The dependency graph is acyclic and enforced: parsing knows nothing of - storage, the server delegates everything to the engine, and the network - threads never touch a disk. Each layer is testable, and tested, alone. -

-
- +
+
+
+

Get started

+

Running in about a minute.

+

Start the server, then connect with the Postgres client you already have.

+
+
# start a server
+docker run -p 55432:55432 ghcr.io/martian56/quantadb
+
+# connect with psql
+psql "host=127.0.0.1 port=55432 user=quanta dbname=quanta"
+
+CREATE TABLE notes (id BIGINT PRIMARY KEY, body TEXT NOT NULL);
+INSERT INTO notes VALUES (1, 'durable on return');
+SELECT * FROM notes;
+
-
-
-

Measured, not promised

-

The benchmark log is part of the changelog.

-

- These are medians from the development machine: a Core i5-1035G1 laptop - with a consumer NVMe drive, full sync on every commit. Not a marketing - rig. When a change regresses a number, the number gets published anyway - and the regression gets fixed next. -

-
-
- - - - - - - - - -
criterion medians, 2026-07-23
hot indexed point lookup705 ns
in-memory snapshot read583 ns
parse a point select2.8 µs
B+ tree range scan, 100 keys13.3 µs
durable single-key commit16.1 ms, the disk's fsync
-
-

one workload, one week

-

736 to 2607 ops/s

+
+
+
+

Status

+

Honest about where this is.

- The same mixed workload, before and after a node cache, online index - publication, version reclamation, and a record cache. The read tail - fell from 139 ms worst case to 18.5 ms. One intermediate change made - reads worse; the benchmark caught it before main did. + QuantaDB is experimental. It has no authentication and no replication, + and it is not where your production data should live yet.

+
    +
  • Done
    Storage kernel

    Checksummed pages, write-ahead log, group commit, crash recovery.

  • +
  • Done
    Transactions and indexes

    MVCC snapshots, B+ tree indexes published online, version reclamation.

  • +
  • Done
    PostgreSQL wire protocol

    Simple and extended queries, so existing drivers connect unmodified.

  • +
  • Now
    Write throughput

    Closing the remaining gap to PostgreSQL on durable commits.

  • +
  • Next
    Authentication, TLS, replication

    The work that has to land before anyone stores something they care about.

  • +
-
-
-

Protocol v1

-

One JSON frame per line. Deliberately boring.

-

- The current wire protocol is built for debugging a young database: you - can drive it with a terminal and read every byte. PostgreSQL wire - compatibility is on the roadmap; this is the scaffolding that gets us - there honestly. +

+
+

Read the code, run the benchmarks.

+

+ Everything is Apache-2.0, including the harness that produced the numbers + on this page. Disagree with them and you can rerun them.

-
-
-
-
-

Status

-

Do not store data you love in this. Yet.

-

- QuantaDB is a working engine and an honest work in progress. The v0.1 - prototype was retired; the current codebase is a clean foundation with - real durability guarantees and a long road ahead. Milestones are - numbered because they are a sequence: each one is load-bearing for the - next. -

-
-
    -
  1. M1

    Syntax and server foundation

    Span-aware parser, versioned protocol, bounded connections.

  2. -
  3. M2

    Durable storage kernel

    Pages, WAL, group commit, crash recovery, corruption detection.

  4. -
  5. M3

    Transactions and indexes

    MVCC, online index generations, reclamation, and a concurrent - history checker that has already caught two real bugs. Range conflict - tracking remains.

  6. -
  7. M4

    Execution engine

    Planner, joins, ordering, secondary indexes, cost-based decisions.

  8. -
  9. M5

    Production operations

    PostgreSQL wire protocol, auth, TLS, backup, format stability.

  10. -
  11. M6

    Replication

    Replicated log, failover, and adversarial failure testing before any - talk of distribution.

  12. -
-
- -
- - - - diff --git a/web/logo-mark.png b/web/logo-mark.png index 79749fb..450b5af 100644 Binary files a/web/logo-mark.png and b/web/logo-mark.png differ diff --git a/web/logo.svg b/web/logo.svg index ebf3486..f534f9e 100644 --- a/web/logo.svg +++ b/web/logo.svg @@ -2,13 +2,13 @@ QuantaDB - - + + - - - - - + + + + + diff --git a/web/style.css b/web/style.css index bc1b4cf..e448e7c 100644 --- a/web/style.css +++ b/web/style.css @@ -1,608 +1,321 @@ -/* QuantaDB site styles. - Identity: engineering literature. Old-style serif prose, monospace - artifacts, and a spectral line system keyed to the on-disk magics. - No sans-serif, no icon fonts, no external resources. */ - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} +/* QuantaDB — near-black violet canvas, purple brand, quiet depth. */ :root { - --field: #10151d; - --panel: #151b25; - --panel-edge: #232c3a; - --rule: #1d2531; - --text: #c3cad4; - --text-dim: #828d9d; - --bright: #eef1f5; - - --sp-storage: #e0a458; - --sp-wal: #d1873e; - --sp-mvcc: #8f7dff; - --sp-index: #45c8d8; - --sp-engine: #74c69d; - --sp-server: #d96052; - --sp-neutral: #97a1b0; - - --serif: "Palatino Linotype", Palatino, "Book Antiqua", "URW Palladio L", Georgia, serif; - --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace; - - --measure: 62ch; - --gutter: clamp(1.25rem, 4vw, 3rem); -} + --purple: #855bfb; + --purple-dark: #7132f5; + --purple-deep: #7132f5; + --purple-subtle: rgba(133, 91, 251, 0.16); -html { - scroll-behavior: smooth; -} + --ink: #f4f3f9; + --gray: #a09eb4; + --silver: #74718c; + --border: #262336; + --border-soft: #1c1a29; + --surface: #100e18; + --surface-raise: #17141f; + --surface-soft: #14121d; + --code-bg: #0a0812; -body { - background: var(--field); - color: var(--text); - font-family: var(--serif); - font-size: 1.0625rem; - line-height: 1.65; - -webkit-font-smoothing: antialiased; -} + --green: #34d399; + --green-deep: #6ee7b7; + --green-soft: rgba(52, 211, 153, 0.14); -::selection { - background: #2c3a52; - color: var(--bright); -} + --display: "IBM Plex Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + --ui: "Helvetica Neue", Helvetica, Arial, sans-serif; + --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace; -a { - color: var(--bright); - text-decoration: underline; - text-decoration-color: var(--text-dim); - text-underline-offset: 3px; -} + --shadow: rgba(0, 0, 0, 0.35) 0 4px 24px; + --shadow-micro: rgba(0, 0, 0, 0.25) 0 1px 4px; -a:hover { - text-decoration-color: var(--bright); + --wide: 1120px; + --gutter: clamp(1.25rem, 5vw, 2.5rem); } -a:focus-visible, -.button:focus-visible { - outline: 2px solid var(--sp-index); - outline-offset: 3px; - border-radius: 1px; -} +* { box-sizing: border-box; } -code { - font-family: var(--mono); - font-size: 0.92em; -} +html { scroll-behavior: smooth; } -/* The spectral line device. A line means "this maps to an on-disk format - or a crate"; it never appears as decoration alone. */ -.line { - display: inline-block; - width: 3px; - height: 1.05em; - margin-right: 0.65rem; - vertical-align: -0.18em; - background: var(--sp-neutral); -} - -.sp-storage { background: var(--sp-storage); } -.sp-wal { background: var(--sp-wal); } -.sp-mvcc { background: var(--sp-mvcc); } -.sp-index { background: var(--sp-index); } -.sp-engine { background: var(--sp-engine); } -.sp-server { background: var(--sp-server); } -.sp-neutral { background: var(--sp-neutral); } - -/* Masthead */ -.masthead { - border-bottom: 1px solid var(--rule); - position: sticky; - top: 0; - background: color-mix(in srgb, var(--field) 92%, transparent); - backdrop-filter: blur(6px); - z-index: 10; -} - -.masthead-inner { - max-width: 72rem; - margin: 0 auto; - padding: 0.8rem var(--gutter); - display: flex; - align-items: baseline; - gap: 1rem; +body { + margin: 0; + background: var(--surface); + color: var(--gray); + font-family: var(--ui); + font-size: 16px; + line-height: 1.38; + -webkit-font-smoothing: antialiased; } -.wordmark { - font-family: var(--serif); +h1, h2, h3 { + font-family: var(--display); + color: var(--ink); font-weight: 700; - font-size: 1.2rem; - color: var(--bright); - text-decoration: none; - letter-spacing: 0.01em; -} - -.version { - font-family: var(--mono); - font-size: 0.72rem; - color: var(--text-dim); - letter-spacing: 0.04em; -} - -.masthead-nav { - margin-left: auto; - display: flex; - gap: 1.1rem; - font-family: var(--mono); - font-size: 0.78rem; - letter-spacing: 0.03em; + margin: 0; } -.masthead-nav a { - color: var(--text-dim); - text-decoration: none; -} +h1 { font-size: clamp(2.1rem, 5vw, 3rem); line-height: 1.17; letter-spacing: -1px; } +h2 { font-size: clamp(1.7rem, 3.6vw, 2.25rem); line-height: 1.22; letter-spacing: -0.5px; } +h3 { font-family: var(--ui); font-size: 1.375rem; font-weight: 600; line-height: 1.2; } -.masthead-nav a:hover { - color: var(--bright); -} +a { color: inherit; } -.masthead-nav .repo-link { - color: var(--bright); -} +p { margin: 0; } -/* Shared band structure */ -main { - max-width: 72rem; +.wrap { + max-width: var(--wide); margin: 0 auto; padding: 0 var(--gutter); } -.eyebrow { - font-family: var(--mono); - font-size: 0.72rem; - text-transform: uppercase; - letter-spacing: 0.22em; - color: var(--text-dim); - margin-bottom: 0.9rem; -} - -.band { - padding: clamp(3.5rem, 8vw, 5.5rem) 0; - border-top: 1px solid var(--rule); -} +/* nav */ -.band-head h2 { - font-size: clamp(1.6rem, 3.4vw, 2.3rem); - line-height: 1.15; - color: var(--bright); - font-weight: 700; - max-width: 24ch; - letter-spacing: -0.01em; +.nav { + position: sticky; + top: 0; + z-index: 20; + background: rgba(16, 14, 24, 0.82); + backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border-soft); } -.band-lede { - max-width: var(--measure); - margin-top: 1.1rem; - color: var(--text); -} +.nav-inner { display: flex; align-items: center; gap: 2rem; height: 68px; } -/* Hero */ -.hero { - display: grid; - grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); - gap: clamp(2rem, 5vw, 4.5rem); +.brand { + display: inline-flex; align-items: center; - padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(3rem, 7vw, 5.5rem); -} - -.hero h1 { - font-size: clamp(2.4rem, 5.4vw, 3.9rem); - line-height: 1.06; - color: var(--bright); + gap: 0.6rem; + font-family: var(--display); + color: var(--ink); font-weight: 700; - letter-spacing: -0.015em; - max-width: 14ch; + font-size: 1.15rem; + letter-spacing: -0.5px; + text-decoration: none; } -.lede { - margin-top: 1.4rem; - max-width: 46ch; - font-size: 1.1rem; -} +.brand img { display: block; border-radius: 6px; } -.hero-actions { - margin-top: 2rem; - display: flex; - gap: 0.9rem; - flex-wrap: wrap; -} +.nav-links { display: flex; align-items: center; gap: 1.75rem; margin-left: auto; font-size: 0.95rem; } -.button { - font-family: var(--mono); - font-size: 0.82rem; - letter-spacing: 0.03em; - color: var(--field); - background: var(--bright); - padding: 0.65rem 1.15rem; - text-decoration: none; - border: 1px solid var(--bright); -} +.nav-links a { color: var(--gray); text-decoration: none; transition: color 140ms ease; } -.button:hover { - background: var(--text); - border-color: var(--text); -} +.nav-links a:hover { color: var(--ink); } -.button.quiet { - background: transparent; - color: var(--bright); - border-color: var(--panel-edge); -} +/* buttons */ -.button.quiet:hover { - border-color: var(--text-dim); - background: var(--panel); +.btn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 13px 16px; + border-radius: 12px; + border: 1px solid transparent; + font-family: var(--ui); + font-size: 1rem; + font-weight: 500; + text-decoration: none; + transition: background 140ms ease, border-color 140ms ease, transform 120ms ease; } -/* The page artifact */ -.page-artifact { - background: var(--panel); - border: 1px solid var(--panel-edge); - padding: 1.4rem 1.5rem 1.2rem; - min-width: 0; -} +.btn:active { transform: translateY(1px); } -.mono-label { - font-family: var(--mono); - font-size: 0.72rem; - text-transform: uppercase; - letter-spacing: 0.18em; - color: var(--text-dim); -} +.btn-primary { background: var(--purple); color: #14071f; font-weight: 600; } +.btn-primary:hover { background: #9a79fc; } -.page-artifact figcaption { - margin-bottom: 1rem; - padding-bottom: 0.8rem; - border-bottom: 1px solid var(--rule); -} +.btn-outline { background: transparent; color: var(--ink); border-color: var(--border); } +.btn-outline:hover { background: var(--surface-raise); border-color: var(--silver); } -.hexdump { - font-family: var(--mono); - font-size: 0.8rem; - line-height: 1.75; -} +/* hero */ -.hexrow { - display: flex; - gap: 1.1rem; - align-items: baseline; - padding: 0.12rem 0; -} +.hero { padding: clamp(3.5rem, 9vw, 6.5rem) 0 clamp(2.5rem, 6vw, 4rem); } -.hexrow .offset { - color: var(--text-dim); - flex: 0 0 2.6rem; - white-space: nowrap; -} +.hero-inner { max-width: 760px; } -.hexrow .bytes { - color: var(--bright); - flex: 0 0 12.5rem; - white-space: nowrap; -} +.hero h1 { margin-bottom: 1.25rem; } -.hexrow .note { - color: var(--text-dim); - min-width: 0; -} +.hero p { font-size: 1.125rem; max-width: 58ch; margin-bottom: 2rem; } -.hexrow.dim .bytes { - color: var(--text-dim); -} +.hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; } -.artifact-footnote { - margin-top: 1.1rem; - padding-top: 0.9rem; - border-top: 1px solid var(--rule); - font-size: 0.88rem; - color: var(--text-dim); - max-width: 52ch; -} +/* metric strip */ -/* Spectrum legend */ -.spectrum { - list-style: none; - margin-top: 2.4rem; - border-top: 1px solid var(--rule); -} - -.spectrum li { +.metrics { display: grid; - grid-template-columns: 1.2rem 5.5rem 10rem minmax(0, 1fr); - align-items: baseline; - gap: 0.6rem; - padding: 0.85rem 0; - border-bottom: 1px solid var(--rule); + grid-template-columns: repeat(4, 1fr); + gap: 1rem; + margin-top: 3.5rem; } -.spectrum code { - color: var(--bright); - font-size: 0.9rem; - letter-spacing: 0.12em; +.metric { + background: var(--surface-raise); + border: 1px solid var(--border); + border-radius: 16px; + padding: 1.5rem; + box-shadow: var(--shadow-micro); } -.spectrum-what { - font-style: italic; - color: var(--text); +.metric b { + display: block; + font-family: var(--display); + color: var(--ink); + font-size: clamp(1.35rem, 2.2vw, 1.75rem); + font-weight: 700; + letter-spacing: -0.5px; + line-height: 1.2; + margin-bottom: 0.35rem; } -.spectrum-note { - color: var(--text-dim); - font-size: 0.95rem; -} +.metric span { font-size: 0.875rem; color: var(--silver); } -/* Crate stack */ -.stack { - list-style: none; - margin-top: 2.4rem; - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 1.6rem 3.5rem; -} +/* sections */ -.stack li { - display: flex; - gap: 0.9rem; - align-items: flex-start; -} +.band { padding: clamp(3.5rem, 8vw, 6rem) 0; } -.stack .line { - height: 100%; - min-height: 3.2rem; - margin-top: 0.35rem; - flex: 0 0 3px; -} +.band-soft { background: var(--surface-soft); border-block: 1px solid var(--border-soft); } -.stack h3 { - font-weight: 400; -} +.band-head { max-width: 620px; margin-bottom: 2.75rem; } -.stack h3 code { - color: var(--bright); - font-size: 1rem; +.eyebrow { + font-size: 0.875rem; + font-weight: 700; + color: var(--purple); + margin-bottom: 0.75rem; } -.stack p { - margin-top: 0.35rem; - color: var(--text-dim); - font-size: 0.98rem; - max-width: 46ch; -} +.band-head h2 { margin-bottom: 0.9rem; } -/* Numbers */ -.figures { - margin-top: 2.4rem; - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - gap: 3rem; - align-items: start; -} +.band-head p { font-size: 1.0625rem; } -.figures-table { - width: 100%; - border-collapse: collapse; - font-size: 0.98rem; -} +/* cards */ -.figures-table caption { - text-align: left; - margin-bottom: 0.8rem; -} +.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; } -.figures-table th { - text-align: left; - font-weight: 400; - color: var(--text); - padding: 0.6rem 0; - border-bottom: 1px solid var(--rule); +.card { + background: var(--surface-raise); + border: 1px solid var(--border); + border-radius: 16px; + padding: 1.75rem; + box-shadow: var(--shadow); } -.figures-table td { - text-align: right; - font-family: var(--mono); - font-size: 0.85rem; - color: var(--bright); - padding: 0.6rem 0; - border-bottom: 1px solid var(--rule); - white-space: nowrap; -} +.card h3 { margin-bottom: 0.6rem; } -.figures-story .story-number { - font-size: clamp(1.6rem, 3vw, 2.2rem); - color: var(--bright); - margin: 0.7rem 0 0.9rem; -} +.card p { font-size: 0.9375rem; } -.figures-story .story-number span { - font-family: var(--mono); - font-size: 0.9em; -} +/* table */ -.figures-story p:last-child { - color: var(--text-dim); - max-width: 46ch; +.table-shell { + background: var(--surface-raise); + border: 1px solid var(--border); + border-radius: 16px; + overflow-x: auto; + box-shadow: var(--shadow); } -/* Protocol terminal */ -.terminal { - margin-top: 2.4rem; - background: var(--panel); - border: 1px solid var(--panel-edge); - padding: 1.3rem 1.5rem; - font-family: var(--mono); - font-size: 0.78rem; - line-height: 1.75; -} +table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; } -.terminal p { - color: var(--text-dim); - overflow-wrap: anywhere; - padding: 0.25rem 0 0.25rem 1.4rem; - text-indent: -1.4rem; -} +th, td { padding: 1rem 1.25rem; text-align: right; white-space: nowrap; } -.terminal p:nth-child(odd) { - color: var(--text); -} +th:first-child, td:first-child { text-align: left; } -.prompt { - color: var(--sp-server); - margin-right: 0.6rem; +thead th { + color: var(--silver); + font-weight: 500; + font-size: 0.8125rem; + border-bottom: 1px solid var(--border-soft); } -.prompt.reply { - color: var(--sp-engine); -} +tbody tr + tr td { border-top: 1px solid var(--border); } -/* Milestones */ -.milestones { - list-style: none; - margin-top: 2.4rem; - border-top: 1px solid var(--rule); -} - -.milestones li { - display: flex; - gap: 1.4rem; - padding: 1.1rem 0; - border-bottom: 1px solid var(--rule); -} +tbody td { color: var(--ink); font-variant-numeric: tabular-nums; } -.milestones .m { - font-family: var(--mono); - font-size: 0.8rem; - color: var(--text-dim); - flex: 0 0 2.2rem; - padding-top: 0.25rem; -} +tr.us td { font-weight: 600; } +tr.us td:first-child { color: var(--purple); } -.milestones h3 { - font-weight: 400; - color: var(--text); - font-size: 1.05rem; +.win { + display: inline-block; + background: var(--green-soft); + color: var(--green-deep); + font-weight: 600; + border-radius: 6px; + padding: 2px 8px; } -.milestones p { - color: var(--text-dim); - font-size: 0.95rem; - max-width: 60ch; - margin-top: 0.2rem; -} +.note { font-size: 0.875rem; color: var(--silver); margin-top: 1rem; } -.milestones .done .m::after { - content: " \2713"; - color: var(--sp-engine); -} +/* code */ -.milestones .done h3 { - color: var(--text-dim); +.code { + background: var(--code-bg); + border: 1px solid var(--border); + border-radius: 12px; + padding: 1.25rem 1.4rem; + overflow-x: auto; + font-family: var(--mono); + font-size: 0.875rem; + line-height: 1.8; + color: #e7e7ee; + margin: 0; } -.milestones .active .m { - color: var(--sp-index); -} +.code .c { color: #7f8296; } +.code .k { color: #b69bff; } -.milestones .active h3 { - color: var(--bright); -} +/* status */ -/* Footer */ -.footer { - border-top: 1px solid var(--rule); - margin-top: 2rem; -} +.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.75rem; } -.footer-inner { - max-width: 72rem; - margin: 0 auto; - padding: 2.2rem var(--gutter) 3rem; +.step { display: flex; - justify-content: space-between; - gap: 1.5rem; - flex-wrap: wrap; - color: var(--text-dim); - font-size: 0.95rem; + gap: 1rem; + align-items: baseline; + padding: 1.1rem 1.35rem; + border: 1px solid var(--border); + border-radius: 12px; + background: var(--surface-raise); +} + +.step em { + font-style: normal; + font-size: 0.75rem; + font-weight: 600; + border-radius: 6px; + padding: 3px 8px; + background: rgba(160, 158, 180, 0.12); + color: var(--gray); + white-space: nowrap; } -.footer nav { - display: flex; - gap: 1.4rem; - font-family: var(--mono); - font-size: 0.78rem; -} +.step.done em { background: var(--green-soft); color: var(--green-deep); } +.step.now { border-color: var(--purple); } +.step.now em { background: var(--purple-subtle); color: var(--purple); } +.step b { color: var(--ink); font-weight: 600; } +.step p { font-size: 0.9375rem; margin-top: 0.2rem; } -.footer a { - color: var(--text-dim); -} +/* closing */ -.footer a:hover { - color: var(--bright); -} +.closer { text-align: center; padding: clamp(3.5rem, 8vw, 6rem) 0; } +.closer p { max-width: 52ch; margin: 1rem auto 2rem; font-size: 1.0625rem; } +.closer .hero-actions { justify-content: center; } -/* Responsive */ -@media (max-width: 60rem) { - .hero { - grid-template-columns: 1fr; - } +/* footer */ - .figures { - grid-template-columns: 1fr; - gap: 2rem; - } +.foot { border-top: 1px solid var(--border-soft); padding: 2.5rem 0; font-size: 0.875rem; color: var(--silver); } - .stack { - grid-template-columns: 1fr; - } -} +.foot-inner { display: flex; flex-wrap: wrap; gap: 1.25rem; align-items: center; } -@media (max-width: 44rem) { - .masthead-nav a:not(.repo-link) { - display: none; - } - - .hexrow { - flex-wrap: wrap; - row-gap: 0; - } - - .hexrow .note { - flex-basis: 100%; - padding-left: 3.7rem; - font-size: 0.74rem; - } - - .spectrum li { - grid-template-columns: 1.2rem 5.5rem minmax(0, 1fr); - } - - .spectrum-note { - grid-column: 2 / -1; - } -} +.foot a { color: var(--gray); text-decoration: none; } +.foot a:hover { color: var(--ink); } -@media (prefers-reduced-motion: reduce) { - html { - scroll-behavior: auto; - } -} +.foot-links { display: flex; gap: 1.5rem; margin-left: auto; flex-wrap: wrap; } -.wordmark { - display: inline-flex; - align-items: center; - gap: .5ch; +::selection { background: var(--purple); color: #14071f; } + +:focus-visible { outline: 2px solid var(--purple); outline-offset: 3px; border-radius: 4px; } + +@media (max-width: 900px) { + .metrics { grid-template-columns: repeat(2, 1fr); } } -.wordmark-mark { - display: block; - border-radius: 5px; +@media (max-width: 768px) { + .nav-links { display: none; } + th, td { padding: 0.85rem 0.9rem; } }