diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..b10438d
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,64 @@
+# Contributing to SQLwak
+
+Thanks for helping make SQLwak better! The most valuable contributions are new
+levels, clearer task descriptions, and bug reports about queries that were
+graded incorrectly.
+
+## Development
+
+```bash
+npm install
+npm run dev # http://localhost:3000
+```
+
+Before opening a PR, make sure all four CI gates pass locally:
+
+```bash
+npm run lint
+npm run typecheck
+npm test
+npm run build
+```
+
+## How validation works
+
+A level is solved when the user's query returns the same result as the level's
+`solutionQuery`, both executed against the seeded in-memory SQLite database
+(`src/lib/seed.ts`). The comparison (`src/lib/validator.ts`):
+
+- only permits a single read-only `SELECT`/`WITH` statement;
+- requires row order **only** when the solution query has a top-level
+ `ORDER BY` (a per-level `orderMatters` field can override this);
+- matches column names case-insensitively, strings exactly, and numbers with a
+ relative tolerance.
+
+## Authoring a level
+
+Levels live in `src/data/levels/` (one file per epoch, combined in
+`index.ts`). When adding one:
+
+1. **Append to the correct epoch file** with the next sequential `id`. Epochs
+ must stay contiguous — the test suite enforces this.
+2. **Write the description as a business request**, ending with an explicit
+ contract: which columns to return (use backticked names matching the
+ solution's aliases), and — if order matters — the exact ordering, phrased
+ like "ordered by `balance` descending".
+3. **Only add `ORDER BY` to the solution when the description asks for it.**
+ If the description doesn't mention ordering, leave the solution unordered;
+ the validator then accepts any row order.
+4. **`seedQuery`** is a scaffold with blanks, not a near-answer. Keep clause
+ keywords on their own lines with a single trailing space where the user
+ should type.
+5. **`hint`** should name the technique (e.g. "use `LAG() OVER`"), not the
+ answer.
+6. **Run `npm test`.** The suite executes every solution against the real
+ seed and fails if a solution errors, returns zero rows, or if a seed
+ scaffold already passes validation.
+
+If a level needs new data, extend `src/lib/seed.ts` — and check existing
+levels still pass, since they share the seed.
+
+## Code style
+
+Match the surrounding code. UI work should respect the design principles in
+`PRODUCT.md` (terminal-first, WCAG AA contrast, reduced-motion alternatives).
diff --git a/IMPROVEMENT_PLAN.md b/IMPROVEMENT_PLAN.md
index b5ef000..855a291 100644
--- a/IMPROVEMENT_PLAN.md
+++ b/IMPROVEMENT_PLAN.md
@@ -25,9 +25,22 @@ Implemented in this PR:
unused types, unused `p5` dependency, no-op callbacks, and the `sqlawk` name typo removed
(3.3); seed extracted to `src/lib/seed.ts` for Node test reuse.
-Still open: level 49 simplification and seed-blank audit (1.6), store tests (2.4),
-`levels.ts` split and build-time expected results (3.4), Pillar 4 UX/a11y work, and Pillar 5
-docs (LICENSE choice is the owner's call).
+Implemented in the follow-up PR:
+
+- **Remainder of 1.6:** level 49 rewritten with the `AVG(x²) − AVG(x)²` variance identity
+ (no more correlated subqueries); seed-scaffold whitespace normalized.
+- **2.4:** store tests for XP accrual, streak, navigation history, and reset — which surfaced
+ and fixed three real bugs (XP farming by replaying levels, `currentLevel` advancing past the
+ final level, and back-navigation never consuming history).
+- **3.4 (partial):** `levels.ts` split into per-epoch modules under `src/data/levels/`.
+- **Pillar 4:** escalating disclosure (expected result *shape* revealed after 3 failed
+ attempts), dialog semantics/focus/Escape handling for the modal and level navigator,
+ aria-labels on icon buttons, and a stacking responsive layout below the `lg` breakpoint.
+- **Pillar 5:** MIT LICENSE, CONTRIBUTING.md with a level-authoring guide.
+
+Still open: build-time expected results (3.4), the expected-vs-actual value diff (4.1 — the
+shape reveal shipped; a value-level diff is a deliberate product decision), and a deeper
+mobile/touch pass (4.4).
---
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..779160e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 martinl5
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index bdbda46..a136ef3 100644
--- a/README.md
+++ b/README.md
@@ -88,7 +88,11 @@ npm run build # Production build
## Contributing
-Issues and PRs welcome! Ideas for new levels, challenge themes, or schema additions are especially appreciated.
+Issues and PRs welcome! Ideas for new levels, challenge themes, or schema additions are especially appreciated — see [CONTRIBUTING.md](CONTRIBUTING.md) for the level-authoring guide.
+
+## License
+
+[MIT](LICENSE)
---
diff --git a/src/components/FlockStatus.tsx b/src/components/FlockStatus.tsx
index 4dbacda..afbd46c 100644
--- a/src/components/FlockStatus.tsx
+++ b/src/components/FlockStatus.tsx
@@ -32,6 +32,7 @@ export default function FlockStatus({ onOpenLevelNavigator }: FlockStatusProps)
className="p-1.5 transition-colors hover:opacity-70"
style={{ color: 'var(--lcb-muted)', background: 'rgba(255,255,255,0.04)', border: '1px solid var(--lcb-border)', borderRadius: 4 }}
title="Browse levels"
+ aria-label="Browse levels"
>
@@ -47,6 +48,7 @@ export default function FlockStatus({ onOpenLevelNavigator }: FlockStatusProps)
cursor: canGoBack ? 'pointer' : 'not-allowed',
}}
title="Previous level"
+ aria-label="Go to previous level"
>