diff --git a/website/STYLE.md b/website/STYLE.md
index 24ee9c8..2612101 100644
--- a/website/STYLE.md
+++ b/website/STYLE.md
@@ -104,6 +104,17 @@ This is planned and not yet available.
- **One command per line** in an `rdbms` block; a multi-line single
statement (e.g. advanced `CREATE TABLE`) belongs in a ` ```sql ` block,
where no prompt is added.
+- **Command output → a plain unlabelled ` ``` ` fence** placed immediately
+ after the command block (no language, so no `> ` prompt and no
+ highlighting). Output must be **captured from the real app**, never
+ hand-drawn — box-drawing diagrams, query-plan trees, and data tables are
+ copied verbatim (trailing padding spaces trimmed). The capture method: a
+ throwaway in-crate test that builds the canonical library schema and prints
+ the rendered output (`render_structure_with_diagrams`,
+ `render_relationship_diagram`, `render_data_table`, `render_explain_plan`,
+ `show_list`), removed once the output is pasted. Colour is lost in a static
+ block (the structure still reads); the coloured/animated rendering is
+ earmarked for casts.
### Canonical library schema (source of truth for examples)
diff --git a/website/src/content/docs/reference/columns.md b/website/src/content/docs/reference/columns.md
index 77f2906..06b4686 100644
--- a/website/src/content/docs/reference/columns.md
+++ b/website/src/content/docs/reference/columns.md
@@ -5,12 +5,92 @@ sidebar:
order: 3
---
-:::note[In progress]
-The syntax below is complete and accurate; worked examples on the library
-schema are being added.
-:::
+A table's columns are not fixed once it exists. You can add new ones, rename
+them, change their type, and remove them — in both simple and advanced mode.
+The examples below use the [example library](/getting-started/example-library/);
+to see a table's current columns at any time, use `show table`:
-After a table exists, you add and change its columns. In simple mode:
+```rdbms
+show table books
+```
+
+```
+books
+┌───────────┬────────┬─────────────┐
+│ Name │ Type │ Constraints │
+├───────────┼────────┼─────────────┤
+│ book_id │ serial │ PK │
+│ title │ text │ NOT NULL │
+│ author_id │ int │ │
+│ published │ int │ │
+│ isbn │ text │ UNIQUE │
+└───────────┴────────┴─────────────┘
+```
+
+## Add a column
+
+```rdbms
+add column to books: page_count (int)
+```
+
+The new column goes at the end of the table and is empty for existing rows.
+After the change, the updated structure is shown automatically. If you add a
+`serial` or `shortid` column — or change a column *to* one of those types —
+the empty cells are filled with freshly generated values in the same step (see
+[Types](/reference/types/)).
+
+## Rename a column
+
+```rdbms
+rename column in books: page_count to pages
+```
+
+## Change a column's type
+
+```rdbms
+change column in books: pages (text)
+```
+
+Changing a type re-interprets every existing value. When the conversion could
+lose information — turning `text` into `int`, say, where some rows do not look
+like numbers — the playground refuses by default and shows you exactly which
+rows are the problem, so nothing is silently corrupted. Two flags let you
+decide what should happen instead:
+
+- `--force-conversion` — go ahead and convert, accepting the loss.
+- `--dont-convert` — keep the column's stored values as they are under the new
+ type.
+
+A primary-key column, or a column taking part in a
+[relationship](/reference/relationships/), is protected — remove the
+relationship first if you need to restructure it.
+
+## Drop a column
+
+```rdbms
+drop column from books: pages
+```
+
+If the column is covered by an [index](/reference/indexes/), the drop is
+refused so you do not lose the index by surprise. Add `--cascade` to drop the
+column and the index that covers it together:
+
+```rdbms
+drop column from books: pages --cascade
+```
+
+## In advanced mode
+
+The same operations are written as standard `ALTER TABLE` statements:
+
+```sql
+alter table books add column page_count int
+alter table books rename column page_count to pages
+alter table books alter column pages type text
+alter table books drop column pages
+```
+
+## Syntax
```rdbms-syntax
add column [to] [table]
: () [--force-conversion | --dont
drop column [from] [table]
: [--cascade]
```
-Changing a column to `serial` or `shortid` fills existing rows with generated
-values. A primary-key column, or one involved in a relationship, is refused
-until you remove the relationship first.
-
-In advanced mode the same operations are `ALTER TABLE … ADD/DROP/RENAME
-COLUMN` and `ALTER TABLE … ALTER COLUMN … TYPE`.
-
-See also [Types](/reference/types/) and [Constraints](/reference/constraints/).
+See also [Types](/reference/types/), [Constraints](/reference/constraints/),
+and [Tables](/reference/tables/).
diff --git a/website/src/content/docs/reference/constraints.md b/website/src/content/docs/reference/constraints.md
index 5989932..431b895 100644
--- a/website/src/content/docs/reference/constraints.md
+++ b/website/src/content/docs/reference/constraints.md
@@ -1,17 +1,99 @@
---
title: Constraints
-description: NOT NULL, UNIQUE, DEFAULT, and CHECK constraints on columns.
+description: NOT NULL, UNIQUE, DEFAULT, and CHECK constraints that keep data valid.
sidebar:
order: 6
---
-:::note[In progress]
-The syntax below is complete and accurate; worked examples on the library
-schema are being added.
-:::
+Constraints are rules the database enforces on a column's values, so invalid
+data can never be stored in the first place. There are four:
-Constraints keep your data valid. Declare them in the column spec at
-`create table` / `add column` time, or change them on an existing column:
+| Constraint | Rule |
+|---|---|
+| `not null` | The column must always have a value. |
+| `unique` | No two rows may share a value (empty values aside). |
+| `default ` | The value to use when an `insert` omits the column. |
+| `check ()` | Every value must satisfy a condition you write. |
+
+## Adding constraints
+
+You can add a constraint to an existing column at any time. In the
+[example library](/getting-started/example-library/), a book's publication year
+should be positive, and a sensible fallback is useful when it is unknown:
+
+```rdbms
+add constraint default 2000 to books.published
+add constraint check (published > 1400) to books.published
+```
+
+Constraints show up in the column's **Constraints** cell in `show table`:
+
+```rdbms
+show table books
+```
+
+```
+books
+┌───────────┬────────┬──────────────────────────────────────────┐
+│ Name │ Type │ Constraints │
+├───────────┼────────┼──────────────────────────────────────────┤
+│ book_id │ serial │ PK │
+│ title │ text │ NOT NULL │
+│ author_id │ int │ │
+│ published │ int │ DEFAULT 2000, CHECK ("published" > 1400) │
+│ isbn │ text │ UNIQUE │
+└───────────┴────────┴──────────────────────────────────────────┘
+```
+
+Here `title` is `NOT NULL` and `isbn` is `UNIQUE` — both were declared when the
+table was built (see below). `PK` marks the primary key, which is fixed at
+creation time ([Tables](/reference/tables/)).
+
+## Declaring constraints when you build the table
+
+Constraints can also be part of a column's spec from the start. In advanced
+mode they sit inline in `CREATE TABLE`:
+
+```sql
+create table books (
+ book_id serial primary key,
+ title text not null,
+ author_id int,
+ published int default 2000 check (published > 1400),
+ isbn text unique
+)
+```
+
+## Adding a constraint to existing data
+
+When you add a constraint to a column that already holds rows, the playground
+checks the current data first. If any row would break the new rule — a `null`
+where you are adding `not null`, a duplicate where you are adding `unique`, or a
+value that fails a `check` — the change is **refused** and the offending rows
+are listed, so you can fix the data and try again. Nothing is changed until the
+constraint can hold for every row.
+
+## Removing a constraint
+
+Name the kind to drop it (there is at most one of each kind per column):
+
+```rdbms
+drop constraint check from books.published
+drop constraint default from books.published
+```
+
+## In advanced mode
+
+A table-level `check` or `unique` can be added and dropped with `ALTER TABLE`;
+a named constraint can then be dropped by that name:
+
+```sql
+alter table books add constraint published_range check (published > 1400)
+alter table books add unique (title, author_id)
+alter table books drop constraint published_range
+```
+
+## Syntax
```rdbms-syntax
add constraint not null to
.
@@ -21,10 +103,5 @@ add constraint check () to
.
drop constraint (not null | unique | default | check) from
.
```
-Adding a constraint to a column that already has rows is checked first — if
-existing data would violate it, the change is refused and the offending rows
-are shown.
-
-In advanced mode these are the standard column- and table-level constraints
-in `CREATE TABLE` / `ALTER TABLE`. The primary key is fixed at creation (see
-[Tables](/reference/tables/)).
+See also [Columns](/reference/columns/), [Types](/reference/types/), and
+[Inserting & editing data](/reference/inserting-and-editing-data/).
diff --git a/website/src/content/docs/reference/indexes.md b/website/src/content/docs/reference/indexes.md
index 1246acd..c694124 100644
--- a/website/src/content/docs/reference/indexes.md
+++ b/website/src/content/docs/reference/indexes.md
@@ -1,16 +1,92 @@
---
title: Indexes
-description: Create and drop indexes to speed up lookups.
+description: Create and drop indexes to speed up lookups, and see their effect with query plans.
sidebar:
order: 5
---
-:::note[In progress]
-The syntax below is complete and accurate; worked examples on the library
-schema are being added.
-:::
+An index is a lookup structure that lets the database find matching rows
+without scanning the whole table. Looking up a book by its author is a common
+query in the [example library](/getting-started/example-library/), so an index
+on `books.author_id` is worthwhile:
-An index speeds up lookups on one or more columns. In simple mode:
+```rdbms
+add index as idx_books_author on books (author_id)
+```
+
+`show indexes` lists every index in the project, qualified by its table:
+
+```rdbms
+show indexes
+```
+
+```
+Indexes (1):
+ books.idx_books_author (author_id)
+```
+
+## Seeing the difference an index makes
+
+Prefix a query with `explain` to see *how* the database would run it, without
+running it (see [Query plans](/reference/querying-and-inspecting/#query-plans)).
+With the index in place, a lookup on `author_id` uses it:
+
+```rdbms
+explain show data books where author_id = 1
+```
+
+```
+SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "author_id" = 1
+└─ SEARCH books USING INDEX idx_books_author (author_id=?)
+```
+
+A filter on a column with no index has to read every row instead — a **scan**:
+
+```rdbms
+explain show data books where published > 1968
+```
+
+```
+SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "published" > 1968
+└─ SCAN books
+```
+
+`SEARCH … USING INDEX` is the fast path; `SCAN` reads the whole table. On a few
+rows the difference is invisible, but it is the core idea behind why indexes
+exist — and the plan tree lets you see which one your query gets.
+
+## Multi-column indexes
+
+An index can cover more than one column; list them in order. This helps
+queries that filter or sort on that same leading combination:
+
+```rdbms
+add index as idx_loans_book_member on loans (book_id, member_id)
+```
+
+## Dropping an index
+
+Drop it by name, or by the columns it covers:
+
+```rdbms
+drop index idx_books_author
+drop index on books (author_id)
+```
+
+## In advanced mode
+
+```sql
+create index idx_books_author on books (author_id)
+create unique index idx_books_isbn on books (isbn)
+drop index idx_books_author
+```
+
+A `unique` index doubles as a uniqueness constraint — it both speeds up
+lookups and rejects duplicate values. (In simple mode, uniqueness is a
+[constraint](/reference/constraints/) on the column rather than an index
+option.)
+
+## Syntax
```rdbms-syntax
add index [as ] on
(
[, ...])
@@ -18,8 +94,5 @@ drop index
drop index on
(
[, ...])
```
-In advanced mode, `CREATE [UNIQUE] INDEX … ON
(…)` and `DROP INDEX`.
-Unique indexes are available on the advanced surface.
-
-To see how an index changes the way a query runs, use
-[Query plans](/reference/querying-and-inspecting/).
+See also [Constraints](/reference/constraints/) and
+[Querying & inspecting](/reference/querying-and-inspecting/).
diff --git a/website/src/content/docs/reference/inserting-and-editing-data.md b/website/src/content/docs/reference/inserting-and-editing-data.md
index bcba77b..f7ef9c2 100644
--- a/website/src/content/docs/reference/inserting-and-editing-data.md
+++ b/website/src/content/docs/reference/inserting-and-editing-data.md
@@ -1,26 +1,117 @@
---
title: Inserting & editing data
-description: Add, change, and remove rows.
+description: Add, change, and remove rows — with required filters and automatic confirmation of what changed.
sidebar:
order: 7
---
-:::note[In progress]
-The syntax below is complete and accurate; worked examples on the library
-schema are being added.
-:::
+Once your tables exist, you fill them with rows and keep them up to date. The
+examples use the [example library](/getting-started/example-library/). After
+every write, the playground shows you the rows that changed, so you can confirm
+the effect at a glance.
+
+## Inserting rows
+
+List the columns you are providing, then the matching values:
+
+```rdbms
+insert into members (name, joined) values ('Katherine Johnson', '2024-06-01')
+```
+
+```
+ 1 row(s) inserted
+┌───────────┬───────────────────┬────────────┐
+│ member_id │ name │ joined │
+├───────────┼───────────────────┼────────────┤
+│ 3 │ Katherine Johnson │ 2024-06-01 │
+└───────────┴───────────────────┴────────────┘
+```
+
+Notice that `member_id` was filled in automatically — it is a `serial` column,
+so you leave it out of the `insert` and the database assigns the next value.
+The same applies to `shortid` columns and to any column with a
+[default](/reference/constraints/) (see [Types](/reference/types/)).
+
+## Updating rows
+
+`update` changes columns on the rows that match a filter:
+
+```rdbms
+update books set published = 1970 where book_id = 2
+```
+
+```
+ 1 row(s) updated
+┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐
+│ book_id │ title │ author_id │ published │ isbn │
+├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤
+│ 2 │ The Left Hand of Darkness │ 1 │ 1970 │ 978-0441478125 │
+└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘
+```
+
+## Deleting rows
+
+```rdbms
+delete from authors where author_id = 3
+```
+
+When the deleted row has children linked by an `on delete cascade`
+[relationship](/reference/relationships/), those children are removed too, and
+the result reports each affected relationship:
+
+```
+ 1 row(s) deleted
+ related: 1 row(s) deleted in `books` for relationship `books_author` (on delete cascade)
+```
+
+## The required filter
+
+`update` and `delete` **must** have a `where` clause. This is a safety rail: it
+is far too easy to wipe or rewrite a whole table by forgetting one. When you
+really do mean every row, say so explicitly with `--all-rows`:
+
+```rdbms
+update books set published = 2000 --all-rows
+delete from loans --all-rows
+```
+
+```rdbms-syntax
+update
set
=[, ...] (where | --all-rows)
+delete from
(where | --all-rows)
+```
+
+## Richer filters
+
+A `where` clause is more than simple equality. It accepts `and` / `or` /
+`not`, the comparison operators, and `like`, `is null`, `in`, and `between`:
+
+```rdbms
+delete from loans where returned_on is null and loaned_on < '2024-01-01'
+```
+
+The same expression grammar drives `show data` — see
+[Querying & inspecting](/reference/querying-and-inspecting/).
+
+## In advanced mode
+
+The simple-mode commands above already use SQL-like syntax; advanced mode is
+full SQL, including multi-row inserts and `returning`:
+
+```sql
+insert into members (name, joined) values
+ ('Katherine Johnson', '2024-06-01'),
+ ('Dorothy Vaughan', '2024-06-02')
+update books set published = 1970 where book_id = 2
+delete from authors where author_id = 3
+```
+
+## Syntax
```rdbms-syntax
insert into
[(
[, ...])] [values] ([, ...])
-update
set
=[, ...] (where
= | --all-rows)
-delete from
(where
= | --all-rows)
+update
set
=[, ...] (where | --all-rows)
+delete from
(where | --all-rows)
```
-`update` and `delete` require a `where` clause; to act on every row you must
-opt in explicitly with `--all-rows`. Auto-generated columns (`serial`,
-`shortid`) fill themselves in, so you can leave them out of an `insert`. After
-a write, the affected rows are shown automatically.
-
-`where` accepts more than simple equality — `and` / `or` / `not`,
-comparisons, `like`, `is null`, `in`, and `between`. See
-[Querying & inspecting](/reference/querying-and-inspecting/).
+See also [Querying & inspecting](/reference/querying-and-inspecting/) and
+[Constraints](/reference/constraints/).
diff --git a/website/src/content/docs/reference/querying-and-inspecting.md b/website/src/content/docs/reference/querying-and-inspecting.md
index 7dde7c4..56ab87b 100644
--- a/website/src/content/docs/reference/querying-and-inspecting.md
+++ b/website/src/content/docs/reference/querying-and-inspecting.md
@@ -1,43 +1,185 @@
---
title: Querying & inspecting
-description: View rows and schema, run SQL queries, and explain how a query runs.
+description: View rows and schema, run SQL queries with joins, and explain how a query runs.
sidebar:
order: 8
---
-:::note[In progress]
-The syntax below is complete and accurate; worked examples on the library
-schema are being added.
-:::
+This page covers reading what is in your project: the rows in a table, the
+shape of the schema, full SQL queries, and the plan the database uses to run a
+query. Examples use the [example library](/getting-started/example-library/).
-## Viewing rows and schema (simple mode)
+## Viewing rows
-```rdbms-syntax
-show data
[where ] [limit ]
-show table
-show tables
-show relationships
-show indexes
-show relationship
-show index
+`show data` prints a table's rows:
+
+```rdbms
+show data books
```
-## Querying (advanced mode)
+```
+┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐
+│ book_id │ title │ author_id │ published │ isbn │
+├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤
+│ 1 │ A Wizard of Earthsea │ 1 │ 1968 │ 978-0553383041 │
+│ 2 │ The Left Hand of Darkness │ 1 │ 1969 │ 978-0441478125 │
+│ 3 │ Invisible Cities │ 2 │ 1972 │ 978-0156453806 │
+│ 4 │ Kindred │ 3 │ 1979 │ 978-0807083697 │
+└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘
+```
-Advanced mode runs full SQL `select`, including joins, `group by`, `order
-by`, set operations, and `with` (CTEs):
+Add a `where` clause to filter, and `limit` to cap the number of rows:
-```rdbms-syntax
-select (* | [as ][, ...]) from
[where ] [order by [asc|desc][, ...]] [limit ]
+```rdbms
+show data books where published > 1968
+```
+
+```
+┌─────────┬───────────────────────────┬───────────┬───────────┬────────────────┐
+│ book_id │ title │ author_id │ published │ isbn │
+├─────────┼───────────────────────────┼───────────┼───────────┼────────────────┤
+│ 2 │ The Left Hand of Darkness │ 1 │ 1969 │ 978-0441478125 │
+│ 3 │ Invisible Cities │ 2 │ 1972 │ 978-0156453806 │
+│ 4 │ Kindred │ 3 │ 1979 │ 978-0807083697 │
+└─────────┴───────────────────────────┴───────────┴───────────┴────────────────┘
+```
+
+The `where` grammar is the same one used by `update` and `delete` — see
+[Inserting & editing data](/reference/inserting-and-editing-data/#richer-filters).
+
+## Inspecting the schema
+
+`show table` describes one table's columns, relationships, and indexes (see
+[Columns](/reference/columns/) and [Relationships](/reference/relationships/)
+for the full output). The plural forms give a project-wide overview:
+
+```rdbms
+show tables
+```
+
+```
+Tables (4):
+ authors
+ books
+ loans
+ members
+```
+
+```rdbms
+show relationships
+```
+
+```
+Relationships (3):
+ books_author: authors.author_id → books.author_id on delete cascade
+ loans_book: books.book_id → loans.book_id on delete cascade
+ loans_member: members.member_id → loans.member_id on delete cascade
+```
+
+```rdbms
+show indexes
+```
+
+```
+Indexes (1):
+ books.idx_books_author (author_id)
+```
+
+The singular `show relationship ` and `show index ` show one item
+in detail — `show relationship` draws the two-table diagram covered in
+[Relationships](/reference/relationships/#viewing-a-relationship).
+
+## Querying in advanced mode
+
+Advanced mode runs full SQL `select`, including projections, `order by`,
+joins, `group by`, set operations, and `with` (CTEs). A projection of two
+columns, newest first:
+
+```sql
+select title, published from books where published > 1968 order by published desc
+```
+
+```
+┌───────────────────────────┬───────────┐
+│ title │ published │
+├───────────────────────────┼───────────┤
+│ Kindred │ 1979 │
+│ Invisible Cities │ 1972 │
+│ The Left Hand of Darkness │ 1969 │
+└───────────────────────────┴───────────┘
+```
+
+A **join** follows a relationship to combine rows from two tables — here, each
+book with its author's name:
+
+```sql
+select authors.name, books.title from books
+ join authors on books.author_id = authors.author_id
+ order by authors.name
+```
+
+```
+┌───────────────────┬───────────────────────────┐
+│ name │ title │
+├───────────────────┼───────────────────────────┤
+│ Italo Calvino │ Invisible Cities │
+│ Octavia E. Butler │ Kindred │
+│ Ursula K. Le Guin │ A Wizard of Earthsea │
+│ Ursula K. Le Guin │ The Left Hand of Darkness │
+└───────────────────┴───────────────────────────┘
+```
+
+Add `group by` with an aggregate to summarise — how many books each author has:
+
+```sql
+select authors.name, count(*) as book_count from books
+ join authors on books.author_id = authors.author_id
+ group by authors.name
+ order by book_count desc
+```
+
+```
+┌───────────────────┬────────────┐
+│ name │ book_count │
+├───────────────────┼────────────┤
+│ Ursula K. Le Guin │ 2 │
+│ Octavia E. Butler │ 1 │
+│ Italo Calvino │ 1 │
+└───────────────────┴────────────┘
```
## Query plans
-Prefix a query with `explain` to see how the database would run it, rendered
-as an annotated tree — without running it (so it is safe even over `update`
-or `delete`):
+Prefix a query with `explain` to see *how* the database would run it, drawn as
+an annotated tree. `explain` never runs the statement — it only reports the
+plan — so it is safe even over a `delete`:
+
+```rdbms
+explain show data books where author_id = 1
+```
+
+```
+SELECT "book_id", "title", "author_id", "published", "isbn" FROM "books" WHERE "author_id" = 1
+└─ SEARCH books USING INDEX idx_books_author (author_id=?)
+```
+
+`SEARCH … USING INDEX` means the query found its rows through an
+[index](/reference/indexes/) instead of reading the whole table. A filter on an
+un-indexed column shows a `SCAN` instead. In advanced mode, `explain` also
+wraps a `select`, `with`, `insert`, `update`, or `delete`.
+
+## Syntax
```rdbms-syntax
+show data
[where ] [limit ]
+show table
+show tables | show relationships | show indexes
+show relationship | show index
+select (* | [as ][, ...]) from
[join …] [where ] [group by …] [order by [asc|desc]] [limit ]
explain show data