PLAN.md carries phase 1 (done), the v2 goal, the manifest v2 and v3 decisions, the SAT generator decision, measurements, and the ideas captured on 2026-08-25/26: scattered fields, chunkwise generation, the daily as chunks with random agent placement, the LOD tilemap viewer, identity (machine keys + shoo.dev), product UX, hourly-board feasibility. docs/: fishbowl architecture page, reference renderer, space-and-cache.
- commit
- a65f9ff488501777c8a7f3530c603c40149ba0e5
- author
- dami <gazey55@gmail.com>
| A | .gitignore | 8 | + |
| A | PLAN.md | 944 | +++++++++++++++++++++++++++ |
| A | README.md | 90 | +++ |
| A | docs/ | 1042 | ++++++++++++++++++++++++++++++ |
| A | docs/ | 185 | +++++ |
| A | docs/ | 713 | +++++++++++++++++++++ |
| A | docs/ | 245 | +++++++ |
@@ -0,0 +1,944 @@
1+# Mosaic2+3+A Takuzu mosaic that an agent has to *explore*, not one-shot. Phase 1 is a4+localhost referee + spectator for watching a single agent work a complicated5+space. Nostr and the shared daily world come only after that is worth scaling.6+7+Architecture reference: the 30b4 page (Mosaic Fishbowl). This file is the8+build order and the decisions that page left open.9+10+## Principles (do not relitigate per phase)11+12+- Every tile is under-determined alone (`m > 1` solutions); the mosaic is13+ determined as a whole. If a tile can be solved in isolation, the mosaic is a14+ for-loop and the exercise is pointless.15+- Givens are hidden until earned. The agent never has the whole board in16+ context. Code use is allowed; strategy still has to be the agent's.17+- State is a fold over an append-only log from a seed. The spectator and any18+ later replay are the same fold. Cells are derived, never stored.19+- One referee orders the world. In phase 1 it is a local process; in phase 320+ it is the single signer.21+- The human only spectates. Every change on screen comes from the agent, or22+ from scrubbing a replay. There is no human input to the board, ever.23+- **No fixed layout, ever.** `X` (tiles per side) is any value in 2..15 and24+ `n` is any even tile size in 6..12; every placement is computed from25+ `(tx, ty)`, pitch `n-1`, and the manifest. The seed tile is drawn from the26+ seed, the frontier is derived from what is solved, and the viewer never27+ assumes a size, a centre, or a symmetric wavefront. Anything that only28+ works at one `X` is a bug. `docs/mock-mosaic.py` takes `X` as an argument29+ for exactly this reason.30+31+## Tile standard (from the literature, not from puzzletea's presets)32+33+- Binary Puzzle is NP-complete (De Biasi 2012, planar-CNF reduction); the34+ bare variant without balance and uniqueness is already NP-hard.35+- Utomo and Makarim (Math.Comput.Sci. 2017), puzzles with ~75% blanks and a36+ unique solution: propagation-plus-backtracking takes 0.5 s at 8x8, 5-8 s at37+ 10x10-12x12, 79 s at 14x14, 975 s at 16x16. SAT is flat (0.3 s at 14x14).38+ Blank count barely moves SAT; it dominates search. The knee for "hard39+ without a SAT solver" is between 12x12 and 14x14.40+- Human technique ladder (same paper, and the tactic graders such as41+ Borroot/binairo): constraint-1 propagation (pairs, sandwiches),42+ constraint-2 (balance completion), constraint-3 (row/column uniqueness),43+ then bifurcation (guess, propagate to contradiction). Commercial ladders44+ top out at 14x14 hard (binarypuzzle.com, puzzle-binairo.com; 20x20 exists45+ but is volume, not a new technique).46+47+Decision: **a tile is 14x14 with at least 70% blanks, requires the48+uniqueness constraint, and requires at least one bifurcation.** That is the49+canonical hard Takuzu; anything smaller is a warm-up. `n = 12` is the floor50+for experiments that need faster generation; nothing below 12 counts.51+52+What overlap-by-one leaves unique to a tile with four solved neighbours:53+54+| n | unique interior (n-2)^2 | share of tile | one solved neighbour fixes |55+|----|--------------------------|---------------|----------------------------|56+| 4 | 4 | 25% | 25% |57+| 8 | 36 | 56% | 12.5% |58+| 12 | 100 | 69% | 8.3% |59+| 14 | 144 | 73% | 7.1% |60+61+At n=14 a seam hands the agent 7% of a tile; the other 93% is internal work62+on a hard puzzle. That is the intended effect: the frontier is slow, and a63+tile is not "easier because a neighbour fell". It also creates a generator64+obligation: the `m` solutions of a tile must *differ on its seam lines*,65+otherwise a neighbour can never pin it and the tile is just an unsolvable66+puzzle with extra steps. `gen` asserts this per tile.67+68+Mosaic envelope at the standard, `G = X*(n-1)+1`:69+70+| X | n=12 | n=14 | tiles | cells at n=14 |71+|----|-----------|-----------|-------|---------------|72+| 2 | 23x23 | 27x27 | 4 | 729 |73+| 4 | 45x45 | 53x53 | 16 | 2,809 |74+| 8 | 89x89 | 105x105 | 64 | 11,025 |75+| 15 | 166x166 | 196x196 | 225 | 38,416 |76+77+The top end is the same order as mcpsweeper's 224x224 cap, which the canvas78+already renders.79+80+Consequences taken into the design below:81+82+- **Forced vs guess is judged by technique, not by solution counting.**83+ Counting solutions of a 14x14 with 70% blanks is the 79 s row above. The84+ referee instead runs propagation (constraints 1-3) over revealed85+ information and, optionally, bifurcation to a configured depth `d`. A cell86+ is `forced` if that reaches it, `guess` otherwise. This is the same method87+ the difficulty-rating literature uses, and it is polynomial for `d = 0`.88+- **Generation is not on the request path.** Hard 14x14 tiles with a target89+ multiplicity and seam-straddling ambiguity cost seconds each in a90+ backtracking generator. The daily mosaic is generated ahead of time;91+ paired trials share one generation; `gen` is a batch job with a cache92+ keyed by manifest hash.93+94+## Phase 1 — localhost, one agent, exposed console95+96+### Goal97+98+**Watch one agent solve a 2x2 mosaic of hard 14x14 Takuzu tiles on99+localhost, live, with every step replayable.**100+101+The demo moment: open `http://127.0.0.1:8000/`, paste the printed prompt102+into Claude Code or Codex, and watch. The seed tile appears; intents scroll103+in the console; cells fill under their ownership washes; a solved tile's104+seam line lands in its neighbour; the agent works the neighbour with 93% of105+it still to do; all four tiles fall. Reload in replay mode and scrub it back106+to the first reveal.107+108+Done means all of these, each with a test or a command that proves it:109+110+1. `mosaic-engine gen` (Go) emits a 2x2, n=14 mosaic deterministically per111+ seed, and asserts per tile: m in {2,3} solutions alone, the m solutions112+ differ on a seam line, at least 70% blank, uniqueness plus one113+ bifurcation required; and for the mosaic: exactly one solution.114+2. `mosaic-engine judge` classifies a batch of commits as forced or guess115+ by propagation (constraints 1-3, bifurcation depth `d` configurable) in116+ under 50 ms per batch at n=14.117+3. `/mcp` serves `start_mosaic`, `observe`, `reveal`, `commit`, `retract`118+ with `expected_revision`, and a fresh agent given only the printed prompt119+ finishes a game with no human help.120+4. The viewer pans and zooms, colours cells by owner-hue mean at fixed121+ lightness with status by wash, shows the console and the scrubber, and122+ follows live over SSE.123+5. Replaying the JSONL reproduces the live run frame for frame; a test124+ asserts equality of every revision between the live fold and the replay125+ fold.126+6. The envelope holds: `gen` runs at X=15 (as a batch, minutes allowed) and127+ the viewer renders 196x196; both also run at X=2.128+129+Out of scope for this goal, on purpose: Nostr, identity and accounts, the130+analyzer, more than one agent, paired trials, visual identity, deployment.131+132+Build order, each step usable on its own: engine `gen` -> engine `judge` ->133+site log + referee + engine wrapper -> `/mcp` -> viewer -> replay test ->134+envelope test -> the demo.135+136+137+### Shape138+139+Two processes, split at the puzzle boundary:140+141+- **Engine** (`engine/`, Go, imports `github.com/FelineStateMachine/puzzletea`142+ via a local `replace`). Pure functions over JSON, no state, no ports:143+ `mosaic-engine gen` (seed -> tiles, givens, seams, m per tile, manifest) and144+ `mosaic-engine judge` (revealed cells + candidate commits -> forced/guess with145+ rule attribution). Invoked as a subprocess with JSON on stdin/stdout. It is146+ the only place Takuzu rules exist.147+- **Site** (`site/`, Deno 2 + Fresh 2, same pins as rect.run: `@fresh/core`,148+ Preact, Vite). Owns everything else: game state, the append-only JSONL log,149+ the MCP endpoint (`@modelcontextprotocol/server` + `@modelcontextprotocol/hono`,150+ as in mcpsweeper), SSE to the viewer, and the viewer itself as one island151+ with a canvas.152+153+```154+engine/ Go module: gen, judge, rules (puzzletea inside)155+site/deno.json Fresh 2 app156+site/routes/ / viewer page (spectate-only)157+ /mcp streamable HTTP MCP, authless on 127.0.0.1158+ /events/:id SSE, live fold159+ /log/:id JSONL download for replay160+site/islands/ Viewer.tsx canvas: map, cells, rule blends, console, scrubber161+site/lib/ referee.ts state, frontier gating, calls the engine162+ log.ts JSONL append + fold163+ engine.ts Deno.Command wrapper around mosaic-engine164+```165+166+The site never re-derives a rule; the engine never holds a game. Phase 3167+swaps the site's runtime (Deno -> Workers, where mcpsweeper and tribes live)168+without touching the engine.169+170+### Generator (`gen`)171+172+Inputs: `seed`, `X` (tiles per side, 2..15), `n` (tile size, even; 14 is173+the standard, 12 the floor), `m` (target solutions per tile alone, 2-4),174+coupling flags. Global grid is `X*(n-1)+1` cells per side: 23x23 at the175+smallest, 196x196 at the largest.176+177+1. Tiles in raster order. For each tile pre-fill the shared top row and left178+ column from already-generated neighbours (overlap-by-one seams), then179+ complete the tile with puzzletea's partial-grid fill180+ (`fillGridSeededWithStatsContext`). Needs a one-line exported wrapper in181+ puzzletea: `CompleteGridSeeded(ctx, partial, size, rng)`.182+2. Band uniqueness: reject a tile whose row set collides with another tile in183+ the same band (cheap set check; retry the fill).184+3. Givens: run puzzletea's clue removal per tile but stop at185+ `countSolutions(limit=m+1) == m` instead of `== 1`, with at least 70%186+ blanks and a technique check that the tile needs uniqueness plus one187+ bifurcation. Seam cells are never givens; they arrive from the neighbour.188+ Assert that the `m` solutions differ on at least one seam line.189+4. Global check: a propagator over the coupled system must find exactly one190+ solution. If not, add one given to the most ambiguous tile and repeat.191+5. Emit `manifest`: `sha256(seed||nonce)`, `X n m`, coupling flags, generator192+ version hash.193+194+Measured while building the mock: a whole-grid raster backtracker fills195+X=15, n=4 (61x61) in 50 ms but does not finish X=15, n=8 (106x106) in two196+minutes. So the generator is per-tile with seam prefill as written above,197+never whole-grid, and it needs a bounded retry: a tile whose fixed top row198+and left column admit no completion (a forced three-in-a-row across the199+prefilled corner, say) backjumps to regenerate its left or upper neighbour200+rather than failing the mosaic. Budget: the daily mosaic is a batch job,201+not a request; a 15x15 at n=14 may take minutes, and that is fine because202+its output is cached by manifest hash and shared by every paired trial.203+204+Deferred from v1: "rules across the seam" (no-three straddling a border is205+only partially enforced by overlap) and the coupling-depth metric `k`.206+Both are honest gaps; note them in the manifest as `k: unmeasured`.207+208+### Referee (`site/lib/referee.ts`)209+210+- `frontier` = hidden tiles adjacent to a solved tile; at start, one seed tile211+ (chosen from the seed, not the agent).212+- `reveal(tile)` allowed only on the frontier. Returns that tile's givens plus213+ any seam cells already fixed by solved neighbours.214+- `commit(cells[])` validated against the solution. For each cell the referee215+ also runs the solver over *revealed* information only and records216+ `forced | guess`. Guesses are accepted by default (config: `reject`).217+- **Rule attribution.** For a forced cell the referee records *which rules*218+ force it (`balance`, `run`, `unique`, `seam`), evaluated independently.219+ Givens are `given`; unforced commits are `guess`. This is analyzer data in220+ the batch event; the spectator does not colour by it in phase 1.221+- `retract(cells[])` allowed; counted.222+- A tile is `solved` when every cell is committed and correct.223+- Every accepted call appends one `batch` event. Refusals append nothing.224+225+### MCP (`site/routes/mcp`)226+227+Streamable HTTP at `http://127.0.0.1:8000/mcp`, no auth (localhost only).228+Mirror mcpsweeper's shape: an `expected_revision` on every write, cell229+arrays, a short `intent` string.230+231+```232+start_mosaic { X, n, m, rules } -> game_id, seed_commit, frontier233+observe { game_id } -> revision, revealed cells (delta-coded), frontier tile ids, per-tile status234+reveal { game_id, expected_revision, tile } -> givens + fixed seam cells235+commit { game_id, expected_revision, cells[], intent } -> accepted[], forced/guess split with rules, rejected[]236+retract { game_id, expected_revision, cells[] }237+```238+239+`intent` (<=160 chars) is the "exposed console": the agent's stated reason240+for the batch, shown verbatim in the spectator.241+242+### Spectator (`site/islands/Viewer.tsx`)243+244+One page at `http://127.0.0.1:8000/`, canvas, spectate-only. Fed live by SSE245+from the site's log; in replay mode fed by the same log from disk. Both are246+the same fold.247+248+- **Map.** The whole mosaic, pan (drag) and zoom (wheel), no minimum or249+ maximum beyond "fits" and "one tile fills the view". Tiles read as solved /250+ frontier / hidden at every zoom; seams drawn as shared edges.251+- **Cells.** A 0 and a 1 drawn as proper glyphs at the current scale, not252+ text-rendered characters. At overview zoom cells collapse to tone; at253+ detail zoom the glyph is the primary mark.254+- **Ownership as background blend.** Every tile has its own hue from a255+ 7-hue set, assigned by `(tx + 3*ty) mod 7` so no two tiles that share a256+ cell (all eight neighbours) share a hue. A cell's colour is the *mean* of257+ its owners' hues in OKLCH at a fixed lightness: a seam cell is the mix of258+ two hues, a corner cell of four, and none of them is lighter or more259+ opaque than a single-owner cell. Never stack alpha; a lightness pyramid on260+ the grid is a bug. Wash strength encodes status (solved strongest,261+ frontier lighter, hidden faintest) and a cell takes the highest status262+ among its owners. `docs/mock-mosaic.py` is the reference rendering263+ (`color-mix(in oklch, ...)` there; the canvas does the same in code).264+- **Agent console.** A side pane: tool calls in order, intent text,265+ forced/guess counts, reveal-to-commit ratio, batch size drift, wall-clock266+ between batches. Newest at the bottom, follows live.267+- **Scrubber.** Steps the fold; map, cells, and console all redraw to that268+ revision. Live mode is "scrubber pinned to the end".269+270+Nothing on the page is clickable except pan, zoom, and the scrubber.271+272+**Visual identity: neutral until the PoC is done.** Greys for chrome, a muted273+hue per rule for the blends (they are data, not decoration), system fonts,274+no marketing copy, no logo, no landing page. Do not use the middle-dot (U+00B7) character275+anywhere. Identity work is its own task after phase 1 exits.276+277+### Driving one agent278+279+`deno task dev` in `site/` prints a copyable prompt: install the MCP endpoint, then280+"start a 2x2 mosaic of 14x14 tiles and solve it autonomously with281+observe/reveal/commit". Point Claude Code or Codex at it and open the page.282+283+### Exit criteria284+285+- One agent solves a 2x2 mosaic of 14x14 tiles, `m = 2-3`, end to end,286+ watched live on the page. (2x2 is the minimum mosaic; 27x27 cells.)287+- Replaying that log through the viewer reproduces the identical final state and every288+ intermediate frame, including rule blends.289+- At least one tile in that run was *not* solvable before its seam arrived290+ (the generator must assert this, not hope for it).291+- `gen` and the viewer both work at `X=2` and `X=15` (the agent only has to292+ play the 2x2; the envelope has to render and replay at both ends).293+294+## Phase 2 (v2) — same board, two agents, measured295+296+Manifest v2 (packed tiles of mixed size, zones, segments, reward) is built297+and tested (decision block below; `docs/space-and-cache.md`). What v2 has298+to add is the reason to have built it: a board large enough that strategy299+matters, played by more than one agent under the same seed commit, with300+the run measured rather than eyeballed, and a tile library so that boards301+of that size are a stitch and not a twenty-minute generation.302+303+### Goal304+305+**Watch two agents solve the same big-first mosaic of mixed-size tiles306+(G = 100, ~100 tiles, 6..16) side by side on localhost, synced by307+revision, with an analyzer that says which one played better and why.**308+309+The demo moment: `deno task dev` prints a challenge (a seed commit) and310+two prompts. Paste one into Claude Code and one into Codex (or the same311+model at two batch sizes). Open `/?compare=<a>,<b>`: two maps, one312+scrubber, the analyzer pane between them: reward over revision, guess313+rate, reveal-to-commit ratio, mean tile size solved, frontier strategy314+(BFS / DFS / constraint-greedy). Scrub back to the reveal where they315+diverged.316+317+Done means all of these, each with a test or a command that proves it:318+319+1. **Real packed run.** `mosaic-engine gen --G 100 --kind big-first` is a320+ batch job (minutes, timed and written here), cached by manifest hash,321+ and a fresh agent given only the printed prompt solves it end to end322+ through `/mcp`. Proof: a game log under `site/data/games/` whose323+ manifest is `packer.kind: big-first`, plus the existing324+ live-fold == replay-fold test run over that log.325+2. **Run tags.** `start_mosaic` accepts `tags { model, batch, code_use,326+ initial_reveal, note }`; they are written as a `run` event at revision327+ 1 (the manifest at revision 0 is the board's identity and must stay328+ equal across paired runs, so tags do not go on the manifest). `/games`329+ lists games filterable by tag and by seed commit. Proof: a test that330+ two games of one challenge share `manifest.id` and differ in `run`.331+3. **Analyzer in the fold.** Every batch event folds into `analysis`332+ fields (guess rate, reveal-to-commit ratio, retractions, reward per333+ batch, mean n of solved tiles, wall-clock between batches, frontier334+ strategy classified from the reveal order against the seam graph:335+ BFS, DFS, or largest-tile-first / most-pinned-first greedy). The336+ analyzer is a pure function of the log, so live and replay agree.337+ Proof: `deno task test` asserts analysis equality at every revision338+ between live and replay, and classifies the scripted client's BFS and339+ DFS modes correctly.340+4. **Paired trials.** A `challenge` is a seed commit; `start_mosaic341+ { challenge }` joins it (same cached generation). The viewer at342+ `/?compare=a,b` renders both games on one scrubber, aligned by343+ revision, with the analyzer pane. Proof: two scripted clients (BFS vs344+ DFS, `--limit 6` vs `--limit 2`) on one challenge produce two logs the345+ compare page renders and the analyzer tells apart.346+5. **Coupling depth `k` measured.** Per tile, `k` is the size of the347+ smallest set of its seam segments that, once fixed by solved348+ neighbours, leaves the tile a single solution (a minimum hitting set349+ over its alternatives' differing segments; m <= 4, so exhaustive).350+ Mosaic `k` is the maximum, and the manifest carries the distribution351+ `k_hist`. Replaces `k: unmeasured`. Proof: `go test ./gen` re-derives352+ `k` from the emitted alternatives and asserts every tile has353+ `1 <= k <= segments`.354+6. **Tile library.** `site/data/library.sqlite` with the schema in355+ `docs/space-and-cache.md` §5; `mosaic-engine lib add` ingests gen356+ output (one canonical orientation per tile, all 16 edge tuples357+ indexed); `mosaic-engine stitch --seed --G --kind` resolves a packing358+ against the library, records misses, and `gen --drain` generates the359+ missing tiles with prefilled edges and appends them. Proof: stitching360+ a second seed at G = 100 after one drain is all hits; the stitched361+ mosaic passes every per-tile assertion (re-verified from JSON, as362+ today) and global uniqueness; `manifest.library` is the file hash.363+7. **Envelope.** `pack` at G = 1000 in under a second with zone share364+ under 3%; `stitch` at G = 1000 reports its hit rate and finishes in365+ under a minute (misses allowed, listed, not silently dropped); the366+ viewer renders a synthetic G = 1000 board (1M cells, tone-only at367+ overview zoom, glyphs when a tile fills the view) and the compare368+ page renders two of them. Everything above also still runs at G = 27.369+370+Out of scope for v2, on purpose: Nostr, identity, deployment, the cloud371+copy of the library (R2/D1 are phase 3; the file stays local), more than372+two agents on one compare page, visual identity, the daily seed.373+374+Build order, each step usable on its own: real packed run (1, the375+baseline; nothing else is worth doing if a packed board is not playable)376+-> tags (2) -> analyzer (3) -> paired trials and the compare page (4) ->377+`k` (5) -> library (6) -> envelope (7) -> the demo.378+379+### Exit criteria380+381+- Two agents (or one model at two settings) finish the same G = 100382+ big-first mosaic; both logs replay frame for frame; the compare page383+ shows both under one scrubber and the analyzer pane distinguishes them384+ on at least guess rate and frontier strategy.385+- The board they played was stitched from the library, not generated386+ live, and its manifest names the library hash.387+- `k` is a number in every manifest, and at least one tile in the played388+ board has `k >= 2` (needs two neighbours; the generator asserts this389+ for big-first boards, not hopes for it).390+- `gen`, `stitch`, the viewer and the compare page all work at G = 27 and391+ at G = 1000 (the agents only have to play the G = 100).392+393+### Measured while picking v2 up (2026-08-25/26)394+395+- Phase 1 exit report: `output/report/index.html`; every item passed.396+- No packed (big-first / bands) board had ever been generated for real:397+ `site/tests/fixture.ts` synthesises the big-first fixture (random398+ solution, random givens, judge stubbed), and every log under399+ `site/data/games/` was a grid. The previous session's attempt to play a400+ G=60 big-first board ran 24 minutes and died in generation.401+- Why it died, in order of discovery: (1) the big-first layout leaves 6x6402+ fillers with three prefilled sides and the id order filled them last,403+ (2) backjumps only ever targeted the latest dependency, (3) puzzletea's404+ MRV backtracker could neither refute an infeasible 6x6 nor complete a405+ 14x14 with fixed sides inside its timeout, (4) per-neighbour forward406+ checking misses neighbour-neighbour interactions across a boxed-in407+ tile's edge, (5) a tile pinned to one solution by its neighbours' seam408+ clues failed the whole attempt instead of being re-given. All five are409+ fixed (decision "Generator search" below); `gen.Version` is `gen-v4`.410+- `pack --G 60 --kind big-first`: instant; zone share 1-3% at G = 60,411+ 100, 200; by count ~40% of tiles are n = 6 but ~70% of the area is412+ n >= 12 at G = 100.413+- `gen` (gen-v4, 18-core Mac, wall clock, one attempt each):414+ 2x2 of 14x14 (27x27) 14 s; G=60 big-first (62 tiles) 45 s; G=100415+ big-first (103 tiles, 3 regivens) 2 min 36 s; X=15 grid (225 tiles,416+ 196x196) 12.5 min. Generation is a batch job cached by417+ `(generator version, seed, G, kind, n)` under `site/data/cache/`.418+- First real packed run: G=60 big-first, seed `a`, played by the scripted419+ client through `/mcp`; log `site/data/games/48edade0-...jsonl`, 183420+ revisions, 62 reveals, 120 commits, 1583 forced / 797 guess / 11 wrong,421+ reward 4232 (= sum of n^2), replay at `/?replay=48edade0-...`.422+ `deno task test` now folds every finished v2 log on disk and asserts a423+ solved end state with the right reward; the scripted client tolerates424+ SSE keepalive comments during a long `start_mosaic` (that was the425+ previous session's crash).426+- G=100 big-first, seed `a`, same client: log `bb7b5f61-...jsonl`, 300427+ revisions, 103 reveals, 197 commits, 4280 forced / 2693 guess / 25428+ wrong, reward 11492; generation on cache miss plus the whole game took429+ 141 s wall. Screenshots: `output/playwright/replay-bigfirst-{60,100}.png`.430+- Still open from item 1: a *fresh agent* (not the scripted client) on a431+ packed board. That is the next thing to do: `deno task dev` prints the432+ prompt; use `kind=big-first, G=100`.433+434+### Idea captured 2026-08-26: scattered field instead of a packing435+436+The two played boards read as a tiled quilt. The user would rather the437+board be a *field*: tiles of random size dropped at random positions,438+overlapping each other by arbitrary rectangles (not one shared edge),439+holes allowed, no filler zones. Each tile's rules are internal to its440+window; the only cross-mosaic rule is that shared cells agree. The441+generator already works this way underneath (`sat.CompleteRegion` is a442+joint solve over windows on one global grid, any overlap shape), so the443+change is in the layout and in what "seam" means:444+445+- `pack --kind scatter`: a seeded Poisson-style drop of squares (n even,446+ 6..16) onto a G x G field; accept a drop when it touches the growing447+ cluster with an overlap of at least one full row or column and at most448+ ~n/4 of the smaller tile (so no tile is given away by one neighbour),449+ and is not contained in another. Stop at a target coverage. Holes are450+ simply uncovered cells; zones go away.451+- Seam *segments* become overlap *regions* (rects in local coords, with452+ the partner id). Frontier, pins, `k`, seam clues and the coupled453+ uniqueness CSP all read regions instead of segments; the assertions454+ keep their meaning (every alternative differs inside some region; the455+ tile is under-determined alone; the field is unique as a whole).456+- Generation order is already WFC-shaped: most-constrained-first is the457+ minimum-entropy rule; nothing to add there. Randomness comes from the458+ seeded rng in the drop process and in SAT's diversification, not from459+ the CPU.460+- Viewer: the same colour model (mean owner hue at fixed lightness) draws461+ a multi-owner overlap region as a blend, which is what makes an overlap462+ legible; holes are void.463+464+Not a v2 item yet; decide after items 2-4 exist, since the compare page465+and analyzer are layout-agnostic.466+467+### Idea captured 2026-08-26: the field reads as texture, not information468+469+At overview zoom the cells are drawn as small outlined squares, and a470+balanced no-three binary field is by construction a maximum-entropy471+texture, so values cannot read at that scale no matter the glyph. The472+overview should be value-blind: known/unknown and ownership (status wash473+at owner hue, unknown dark, holes void, no per-cell borders); values474+appear only when a cell is >= ~12 px, as filled/empty discs rather than475+squares. Two zoom regimes, not one glyph scaled. Belongs with the visual476+identity task after v2.477+478+### Manifest v3 (decided 2026-08-26): a scattered field of shapes479+480+Decided the same day the ideas above were captured; the user wants the481+field now, before items 2-7, and the visual pass with it.482+483+**Tiles are shapes, not squares.** A tile is a set of cells: any union of484+axis-aligned rectangles whose every maximal horizontal and vertical run485+of cells (a *line*) has even length >= 4. Rectangles, L, T, plus,486+notched and holed shapes all qualify. The Takuzu rules are per line:487+no three equal in a row along a line, each line has as many 0s as 1s,488+and no two lines of the same orientation and length in one tile are489+equal. A square n x n is the special case where every line is n long.490+491+**Tiles are scattered, not packed.** `pack --kind scatter` drops shapes at492+seeded random positions, sizes and orientations onto a G x G field,493+growing one connected cluster from the seed tile: a drop is accepted when494+it overlaps the cluster by at least one full line of some existing tile495+and by at most a quarter of the smaller tile's cells, and is contained in496+no tile. Overlaps are arbitrary rectangles (or unions of them), not497+single edges. Uncovered cells are holes; there are no filler zones. Stop498+at a target coverage; the result should read as a field with scattered499+small gaps, not a quilt.500+501+**Cross-tile rule: shared cells agree.** Nothing else crosses a tile502+boundary. Every tile alone has 2..m solutions that differ on some503+overlap region; the field as a whole has one.504+505+```506+manifest v3 (public, rev 0)507+ version 3508+ id, seed_commit, G, packer { kind, params }, m_by_n, rules, seed_tile,509+ generator, library, k, k_hist (as v2)510+ tiles[] { id, x0, y0, w, h,511+ rects[]: [lx, ly, rw, rh] // union = the shape, local coords512+ cells, // count513+ m, hash,514+ overlaps[]: { with, cells }, // partner id, shared-cell count; the515+ // cell set is the intersection of the masks516+ pins[]: overlap indexes some alternative differs on }517+ (no zones)518+private: solution (G rows, '.' for holes), tiles[].givens, .flip, .ladder, .needs_*519+```520+521+- Engine `rules`: `Window` is replaced by `Shape {X0, Y0, W, H, Rects}`;522+ a `Board` carries shapes and precomputes their lines; every rule,523+ propagation, flip rectangle, ladder rating and the coupled CSP works on524+ lines and shared cells. `sat` encodes per line. The size policy525+ (`PolicyFor`) keys on the tile's cell count instead of n.526+- Site: owners from rect unions; the frontier is "shares a cell with a527+ solved tile"; hue colouring unchanged; the viewer draws a shape outline528+ as the edges between tile and non-tile cells and a hole as void.529+- Gates worth building because they are unfriendly to a human and530+ interesting to an agent (knobs on the manifest, off by default): lines531+ of length 4 (a T stem) that are almost fully forced but change what the532+ crossbar can be; a hole inside a tile that splits a line in two; a tile533+ whose rule mask differs from its neighbour's (no uniqueness on one side534+ of an overlap); overlap regions wide enough that two tiles are535+ effectively one puzzle; long lines (16) crossing several overlaps; a536+ tile with two disconnected overlaps to the same neighbour.537+538+**Visual pass (now, not after v2):** value-blind overview (status wash at539+owner hue, unknown dark, holes void, no per-cell borders), values as540+filled/empty discs only when a cell is >= ~12 px, tile outlines as541+shape outlines, overlap regions read as hue blends. Game feel: the user542+liked `../rect.run`'s motif but wants it less blocky here; Takuzu should543+feel like a smooth stream of calm water (Shikaku is the tile-laying,544+castle one). Soft edges, slow transitions, low contrast at rest, the545+field as a surface that fills rather than a grid that gets stamped.546+547+### Feasibility captured 2026-08-26: the hourly public board548+549+Question: what board size lets ~25 agents work one field together for an550+hour, after which a new board arrives and the old attempt is persisted;551+is generation disproportionate to play?552+553+Measured generation (gen-v4, 18-core Mac, one attempt): 0.7 s/tile at554+G=60 big-first, 1.5 s/tile at G=100 big-first, 3.3 s/tile for all-hard555+14x14 (X=15). Measured play: the phase-1 fresh agent did 4 hard 14x14556+tiles in 3 min with code (0.75 min/tile); the scripted client is not a557+measure. Model: 25 agents, 50% parallel efficiency (frontier contention,558+revision conflicts, waiting on a neighbour's seam), mean tile ~150 cells,559+85% coverage.560+561+| agent pace | tiles/hour | cells | G | generation (mixed / all-hard) |562+|--------------|-----------:|-------:|-----:|-------------------------------|563+| 1 min/tile | 750 | 112k | ~360 | 20 min / 41 min |564+| 2 min/tile | 375 | 56k | ~260 | 10 min / 21 min |565+| 3 min/tile | 250 | 38k | ~210 | 7 min / 14 min |566+567+So generation is 10-35% of the hour of play it feeds, on one machine,568+and it runs ahead (board N+1 generates while N is played), so it is not569+disproportionate; it only looked that way while the old generator could570+not finish at all. The tile library (v2 item 6) turns it into seconds.571+572+What actually limits 25 agents is not size but the frontier: a field573+grown from one seed has a frontier of a few dozen tiles only once a few574+dozen are solved, so the first minutes serialise. Use several seed tiles575+(5-10, drawn from the seed) so the wavefronts meet. The other cost is576+`observe`: delta-coded known cells are ~2 bytes/cell, so 56k cells is a577+~100 KB observation per call; at that scale observe should take a tile578+or viewport argument. Neither is a board-size problem.579+580+Plan: start hourly boards at G=200-260 with 5-10 seeds, measure agents'581+real tile rate with the analyzer (item 3), and move G to hit a ~45 min582+median completion. A board that does not finish in the hour is persisted583+as it stands; that is fine and is data.584+585+### Measured after the v3 pivot (2026-08-26, later the same day)586+587+- Built by three forks in parallel on one contract: site (visual pass,588+ then v3 in fold/referee/MCP/viewer/client/tests, v2 logs still replay589+ through `normaliseManifest`), pack (`scatter` with a hole-fill pass and590+ the distinct-lines bound), engine core (`rules` on shapes and lines,591+ `sat` per line, judge on shapes, gen over overlap regions; `gen-v5`).592+- A shape constraint the packer did not know and the generator's593+ validation caught: uniqueness needs at most D(L)/2 parallel lines of594+ length L, where D(L) is the number of distinct valid L-lines (D(4)=6,595+ D(6)=14, D(8)=34, D(10)=84, D(12)=208, D(14)=518, D(16)=1296). So no596+ 4-thick arms at all, 6-thick arms at most 6 long; the smallest tile is597+ 6x6 (or the 32-cell notched 6x6). `pack.ValidShape` and598+ `rules.Shape.Valid` both enforce it.599+- Packer (seed a, MaxHole 24): G=100 -> 119 tiles (47 from the fill600+ pass), coverage 0.90, 54 holes of mean 18 cells, 0.45 s; G=200 -> 470601+ tiles, coverage 0.91, 204 holes of mean 17 cells, 1.9 s. Holes over 24602+ cells that remain (13 at G=100) are concave pockets no valid shape fits603+ under the overlap rule.604+- First scatter field generated and played: G=60, seed a, 31 tiles (11605+ compound, 12 non-square rectangles), 1038 hole cells, generated in 41 s606+ (one attempt, no backjumps), solved by the scripted client in 71607+ revisions, 1112 forced / 726 guess / 3 wrong, reward 3032; log608+ `0687247b-...`, screenshot `output/playwright/v3-scatter-60-overview.png`.609+ G=100 scatter, seed a: 75 tiles, generated on cache miss and solved by610+ the scripted client in 383 s wall (three other generations were running611+ at the time), 99 commits, 3141 forced / 2445 guess / 7 wrong, reward612+ 9020; log `7b8941d3-...`, screenshot613+ `output/playwright/v3-scatter-100-overview.png`.614+- Engine-core fork final: `go test ./...` green (`gen` 130-154 s with615+ both fixtures; the 2x2 reproduces byte for byte under `MOSAIC_SLOW=1`);616+ pins are now recomputed at settle time; a layout is validated with617+ `Shape.Valid()` before any search (an invalid shape cost SAT 12-20 s to618+ refute). Manifest deviation from the contract: `rules` fields are619+ `overlaps`, `cross_tile` (not `seams`, `cross_seam`); `Output.Layout`620+ carries the packer's report. Timings under contention: G=100 scatter621+ 6.5 min (75 tiles, one attempt); X=15 grid 18.6 min.622+- Known generator gap: at G=200 scatter the first attempt failed after623+ 11 min ("repair tile 193: an alternative differs inside no overlap624+ region": the neighbours' seam clues had fully fixed the tile's only625+ pin-eligible overlap, and the regiven repair cannot widen it), so the626+ attempt restarts from scratch. Fix: a repair that releases the627+ neighbours' clues on that overlap (or plants across a different one)628+ instead of restarting. No G=200 number yet; chunkwise generation629+ (item 6a) makes single G=200 passes unnecessary anyway.630+- Visual pass screenshots: `output/playwright/v3-overview-100-dark.png`,631+ `v3-mid-100-dark.png`, `v3-detail-100-dark.png` (value-blind overview,632+ discs at zoom, no per-cell borders, ripple on newly known cells).633+634+### Idea captured 2026-08-26: chunkwise generation (checkerboard, not stitch)635+636+Generate a large field as a grid of chunks (~G=60 each) in parallel, then637+join them. The join does not need a stitcher or a library: a chunk is a638+`gen` run whose border tiles may have cells prefilled from neighbouring639+chunks, which the generator already handles (joint completion over fixed640+cells is what `fillTile` does). Order the chunks as a checkerboard: even641+chunks generate independently and in parallel (unique alone, as today);642+odd chunks generate with their border tiles overlapping the even643+neighbours' border tiles, prefilled from them, and are asserted unique644+given that context. Two rounds, each the wall clock of one chunk.645+646+- Per-tile assertions are unchanged (2..m alone, alternatives differ in647+ an overlap region, technique checks); per chunk the coupled CSP runs648+ over the chunk plus its fixed context; the whole is unique because even649+ chunks are unique alone and odd chunks are unique given them.650+- Determinism: chunk seed = (seed, chunk index); the result does not651+ depend on how many run at once. Tile ids offset per chunk; one manifest652+ for the union; the frontier crosses chunk borders like any overlap.653+- Separate processes, not goroutines: gophersat's package-level buffer654+ serialises every SAT call inside one process (the `sat` mutex), so one655+ `gen` uses about one core for the solution phase. Chunks as processes656+ is the way to use the 18 cores.657+- Estimate from today's numbers: G=260 as 4x4 chunks of ~G=65 is two658+ rounds of ~45-60 s, ~2 min wall, versus ~15-20 min serial. That is the659+ hourly-board generation cost solved with far less machinery than the660+ tile library; the library (item 6) stays as the finer-grained version661+ for the daily.662+- Needs: `gen --context <cells+tiles>` (prefilled cells and the identity663+ of the tiles that own them, so overlaps and pins are computed against664+ them), a `chunks` orchestrator in the site (`lib/engine.ts`) or a665+ `mosaic-engine field` subcommand that plans the checkerboard, runs the666+ processes, and merges manifests; a test that a 2x2 of G=60 chunks667+ passes every assertion re-verified from the merged JSON and has one668+ coupled solution. Slot it as item 6a, before the library.669+670+### Idea captured 2026-08-26: the daily as 9x9 chunks, agents placed at random671+672+Follow-on from chunkwise generation. The checkerboard is flat, so a daily673+board of 9x9 chunks of G=60 (G ~ 530, ~280k cells, ~2500 tiles) is still674+two rounds: 41 even chunks then 40 odd, 18 at a time, roughly 3 waves of675+~45-60 s each way, so ~5-6 min on the Mac. Recursion (chunks of chunks)676+buys nothing for cost; the orchestrator is not the bottleneck. Large-G677+single passes are no longer needed for anything.678+679+Each agent joining the board is placed at its own seed tile drawn at a680+random uncovered-frontier spot; from there it can dig toward an ally's681+region or route toward open space. Rules to decide (gates, not settled):682+683+- Per-agent frontier: an agent may reveal only tiles overlapping tiles it684+ solved itself, until its region touches another agent's region, at685+ which point the regions merge and both share the frontier (the meeting686+ is an event the analyzer records). This is what makes "dig out an687+ ally" mean something; a global frontier would blur positions.688+- Ownership colouring becomes per agent (the 30b4 owner-hue idea, at689+ last): a cell's wash is the mean hue of the agents who solved the tiles690+ covering it; overlaps between two agents' tiles read as their blend.691+- A daily of ~2500 tiles at 25 agents and 1-3 min/tile lasts 3-8 hours692+ of play; new agents keep joining at empty spots; the board persists693+ through the day and is archived as it stands at midnight.694+- Hard requirement at this size: `observe` scoped to a region (the695+ agent's own tiles plus a radius, or a viewport), never the whole field;696+ the whole field is for the spectator over SSE, tiled by chunk.697+698+### Decided 2026-08-26: the viewer is a tilemap with levels of detail699+700+Hue means the agent who solved it, not the tile. Tile identity, rules701+and values are detail that draws in as you zoom, like a map: at every702+zoom the question "where does this belong" has one answer at the scale703+you are looking at.704+705+| level | cell size | what is drawn |706+|-------|-------------|----------------------------------------------------------------|707+| L0 | < 3 px | territory: agent-hue washes (mean hue where agents' tiles overlap), unknown dark, holes void; no edges |708+| L1 | 3-12 px | + shape outlines (tile/non-tile boundary), overlap regions as blends, status wash (revealed lighter than solved), the ripple |709+| L2 | 12-30 px | + values as discs (filled 1, ring 0), givens muted vs commits in ink, forced vs guess as two ink weights |710+| L3 | >= 30 px | + the lines: a faint bar along each line of the tile under the centre, line length, pins marked on the overlap, tile id |711+712+- Rendering: the field is cut into map tiles (256 px per level, keyed by713+ chunk and level), rasterised once and cached; an event dirties only714+ the map tiles its cells touch; the spectator subscribes to SSE per715+ chunk in view. The same cache serves the replay scrubber.716+- Nothing is decoration: every mark at a level answers a question that717+ level can ask (whose, which tile, what value, which rule). Rules are718+ not coloured; they are read off the lines at L3.719+- The current two-regime viewer is L0/L1 + L2 without the tilemap; the720+ tilemap becomes necessary at the daily's ~280k cells.721+722+### Kept from the earlier phase-2 list723+724+- Larger mosaics, tile size 10-12, `m = 4`: superseded by packings and725+ `m(n)` (decision block below).726+- **Tile cache for stitching (idea captured 2026-08-25).** Generate many727+ n-size tiles ahead of time and store them so that a daily mosaic is a728+ stitch, not a generation. The generator already splits per tile: the729+ expensive part (givens, planted flip, uniqueness rectangle, ladder rating)730+ depends only on the tile's own solution grid and on which of its sides are731+ seams, so the cache key is `(n, hash(solution grid), seam sides)` and the732+ value is the givens plus the assertion record. Completions are keyed by733+ `(n, top row, left column)`, and "failed to fit" (no completion for that734+ prefill) is stored too, as a negative entry, so retries are free. Growing735+ or refreshing the set is a batch job; the referee only ever reads it.736+ Edges are binary lines, so store them as ints: at n=14 an edge is a 14-bit737+ value (a balanced one is one of C(14,7)=3432), a completion key is two738+ ints, a stored tile carries its four edge ints, and stitching is integer739+ matching over a table rather than grid comparison.740+## Phase 3 — Nostr and the shared daily world741+742+- Events become signed Nostr events with the kinds on the 30b4 page. The743+ referee is the single signer; the JSONL from phase 1 is already the event744+ shape, so this is a serializer, not a rewrite.745+- Private relay (strfry or HAVEN) as world and archive.746+- "Shared space" = authless MCP endpoint exposed beyond localhost, where any747+ npub-identified agent contributes to the **daily world**: one mosaic per748+ date from `puzzletea/daily.Seed(date)`, many agents, one referee, every749+ contribution attributed by key. tribes.pub already has the "submit via750+ /mcp, compose a deterministic sim, watch" pattern to borrow from.751+- Spectator subscribes to the relay by tile filter for a viewport.752+753+### Product UX (decided 2026-08-26): the daily, for humans first754+755+Everything is viewable logged out. Login (shoo.dev) only adds "yours":756+your machines, your territory, your replays.757+758+Pages:759+- `/` today's board: live if the day is running ("view live" follows760+ SSE), else the finished replay. Explore by pan and zoom in the browser;761+ no agent required. A "copy prompt" button hands off to an agent: the762+ prompt bootstraps it (install the MCP endpoint, generate a machine763+ key, register, join today's board at a random spot, play) and ends764+ with "give your human the link when asked".765+- `/day/<date>` the replay of any past day, with the same viewer.766+- `/calendar` a month grid; every day is a summary tile: agents767+ participated (a contributions graph by harness/model), time to768+ completion or time remaining, guess %, tiles solved / total, territory769+ shares, meetings. Click through to the day.770+- `/link?t=...` claim a machine token (identity decision above).771+772+Replay UX (improve): a timeline that shows event density, jump to773+markers (tile solved, agents met, a big guess run), playback speed,774+"follow this agent", and the same scrubber at every zoom of the tilemap.775+776+Persistence is ours: per day the manifest, the private generator output777+(never served), the JSONL log, and the analysis summary; a SQLite index778+`days(date, seed_commit, stats json)` for the calendar; archive copies779+to R2. A daily at ~2500 tiles is ~10k events, ~10 MB; trivial.780+781+Contributions by model: MCP `initialize` carries `clientInfo {name,782+version}`, which identifies the harness (Claude Code, Codex, ...), not783+the model, and is free. The model is self-reported: the bootstrap784+prompt asks the agent to state it in the `run`/join tags, and the785+calendar labels it "as reported". Verifying the model is not possible786+from the protocol; do not pretend to.787+788+The viewer is the tilemap with levels of detail (decision above); at789+the daily's size that is a requirement, not a nicety.790+791+### Machine identity (captured 2026-08-25, phase 3, not built in phase 1)792+793+How an agent gets a durable identity and hands its human a web session:794+795+1. The agent generates its keypair, registers the pubkey with the API, and796+ gets back a `machine_id`.797+2. When the user wants the web UI, the agent hits the API with a request798+ signed by that key and gets a short-lived, single-use pairing token.799+3. The agent opens the default browser to `https://<site>/link?t=<token>`800+ (and prints the URL as a fallback for headless/SSH).801+4. The server validates the token's signature chain, ties the session to802+ `machine_id`, and sets a long-lived `Set-Cookie`.803+5. Every visit after that: cookie present -> "welcome back, here's your stuff."804+805+Identity and accounts stay out of phase 1 on purpose; this is the shape to806+build against when phase 3 makes the referee a signer and agents npubs.807+808+### Identity decided 2026-08-26: machine keys for agents, shoo.dev for humans809+810+Builds on "Machine identity (captured 2026-08-25)" above. Two identities,811+one link between them:812+813+- **Agent = machine key.** The agent generates its keypair, registers the814+ pubkey, gets a `machine_id`; every write it makes is attributed to it815+ (this is the "whose" hue in the viewer and the per-agent frontier).816+ Phase 3 makes the same key its Nostr npub.817+- **Human = shoo.dev account.** When the agent wants to hand its human a818+ session, it asks the API for a single-use pairing token signed by its819+ key and opens `https://<domain>/link?t=<token>` (prints the URL for820+ headless). That page sends the human through shoo.dev login; on return821+ the server ties the shoo.dev account to the `machine_id`, sets the822+ long-lived cookie, and every later visit shows the human their agents,823+ their territory and their replays.824+- One human may have many machines (several agents, several hosts); a825+ machine belongs to at most one human; unlinked machines still play,826+ they just have no human to show it to.827+- Open: the project needs a name and a domain before `/link` exists; the828+ shoo.dev integration details (OIDC or its own flow) are to be read829+ from its docs when this is built, not assumed.830+831+## Decisions taken (change here, not in code)832+833+### Manifest v2 (decided 2026-08-26): packed tiles of mixed size834+835+Phase 2 replaces the `X, n` grid with an explicit packing. The phase-1 grid836+is emitted in the same shape (a regular tile list), so one manifest format837+serves both. Design background: `docs/space-and-cache.md`.838+839+- **Packer: big-first-then-fill.** Large squares (n 14..16) are placed840+ first at seeded positions with free edges; the gaps are filled by bands841+ and Euclid cuts with smaller squares; remainders under n = 6 become842+ filler zones. The library only ever has to answer one-constrained-side843+ lookups for large tiles, which is the cheap regime.844+- **m scales with n, and is capped.** `m(n)`: 2 for n in {6, 8}, 3 for845+ {10, 12, 14}, 4 for {16}. Hard cap 4, never a free parameter per run;846+ the generator asserts each tile lands in 2..m(n) and reports its actual847+ count. Rationale: a small tile with 4 solutions is a coin toss, a848+ 16-tile with 2 is pinned by any single seam segment.849+- **Sizes** n even in 6..16 (16 is new; the rules engine is size-agnostic,850+ the generator's timings at 16 are to be measured before it is used in a851+ daily).852+- **Assertions scale with n** (`gen.PolicyFor`): every tile has 2..m(n)853+ solutions alone and every alternative differs on a seam segment; the854+ blank floor is 55% at n <= 8, 65% at n = 10, 70% from 12 (cap 75%, 73% at855+ 16 where counting gets expensive); the technique checks (needs the856+ uniqueness constraint, needs a bifurcation) apply from n = 12, which is857+ the canonical hard standard. Small tiles are fillers around the hard858+ ones, not hard puzzles themselves.859+- **Generation** is two phases: the solution, tile by tile in id order with860+ forward checking (a completion is kept only if every later neighbour861+ still has one) and backjumping to the latest neighbour on a NOFIT; then862+ the givens, in waves of tiles that share no cell, in parallel. Cells863+ where three or more tiles meet are never planted; they may be seam clues.864+- **Symmetries**: rotations, reflections and 0/1 complement (16 in all)865+ preserve every rule and every assertion, so a library tile is stored once866+ and indexed under all 16 edge tuples.867+868+```869+manifest (public, rev 0 of every log)870+ version 2871+ id sha256(seed || nonce) seed_commit = id872+ G cells per side of the board873+ packer { kind: "big-first" | "bands" | "grown" | "grid", params }874+ m_by_n { "6": 2, "8": 2, "10": 3, "12": 3, "14": 3, "16": 4 }875+ rules { seams, cross_seam, seam_clues, band_unique, zones: "filler" }876+ seed_tile tile id877+ tiles[] { id, x0, y0, n, hash, m,878+ seams[]: { side, from, len, with }, // segments, in local coords879+ pins[]: segment indexes some alternative differs on }880+ zones[] { id, rects[]: { x0, y0, w, h } } // filler, fully given881+ k "unmeasured"882+ generator version hash883+ library hash of the tile library file the tiles came from, or null884+private (gen output, never in the log)885+ solution G rows886+ tiles[].givens, .flip, .ladder, .needs_*887+```888+889+- Cell id stays `y * G + x`. A cell's owners are derived from `tiles[]`890+ (and at most one zone); hue is a greedy 7-colouring of the tile adjacency891+ graph, computed by the fold, not stored.892+- Seam *segments* replace seam sides everywhere: frontier = hidden tiles893+ sharing a segment with a solved tile; `pins` are segment indexes; the894+ global-uniqueness CSP runs over segments; cells where three or more895+ tiles meet are never planted and never seam clues.896+- Zones are filler in v2: fully given on reveal of any neighbour, never on897+ the frontier, zero reward. The manifest shape leaves room for a rule set898+ per zone later.899+- Reward: n^2 per solved tile; the analyzer records reward per batch and900+ the mean n of solved tiles over time.901+902+### Generator search (decided 2026-08-26): SAT for answers, propagation for technique903+904+Completing a window with fixed edges, deciding whether one exists, and905+counting solutions up to a limit are ordinary CSP questions, not something906+to hand-roll. The engine's `sat` package encodes one window (balance as907+cardinality constraints, no-three as clauses, line uniqueness through XOR908+auxiliaries, fixed cells as units) for gophersat, a pure-Go CDCL solver.909+Measured: a 16x16 with all four sides fixed completes in ~4 ms, a 14x14 at910+72% blank counts to limit 4 in ~8 ms, a contradiction is refuted in911+microseconds; puzzletea's MRV backtracker took its whole 6 s timeout on the912+first two and could not refute an infeasible 6x6 at all, which is why a913+G=60 packing never finished before. puzzletea is no longer a dependency.914+The `rules` propagation solver stays for what it is for: forced/guess915+attribution and the technique ladder model human deduction, and SAT has916+nothing to say about that. gophersat keeps a package-level buffer for917+clause learning, so `sat` serialises `Solve` behind a mutex; calls are918+milliseconds and the parallel givens waves lose nothing measurable.919+920+Fill order is most-constrained-first (`gen.fillOrder`): from the seed921+tile, the next tile is the one with the largest share of its cells already922+fixed, ties to the smaller n. Small fillers are therefore completed while923+they have one or two fixed sides and their remaining edges constrain the924+large tiles, which have room; id order (big tiles first) left 6x6 fillers925+for last with three fixed sides and, at G=60, 18 of them, most with no926+completion. Backjumps escalate: every second failure of the same tile927+targets the next earlier dependency, and a tile whose forward check fails928+for every completion keeps the one that leaves the most later neighbours929+feasible, so the neighbour that then fails is the one with the real930+conflict.931+932+- Home: new repo. The Go engine owns the puzzle rules (`rules`, `sat`);933+ the Deno site is where state, MCP, and the viewer live. Nothing outside934+ the engine knows a Takuzu rule.935+- Spectator: Fresh 2 island with a canvas, not TUI. Pan/zoom, background936+ blends, and drawn glyphs are the point of the view. Same framework and pins937+ as rect.run so there is nothing new to learn.938+- MCP library: `@modelcontextprotocol/server` + `@modelcontextprotocol/hono`,939+ the pair mcpsweeper already runs, mounted inside Fresh.940+- Seams: overlap-by-one. Simplest coupling that makes tiles under-determined941+ alone; rules-across-seam and seam clues are phase-2 knobs.942+- Rule attribution is computed by the referee at commit time and stored in943+ the batch event for the analyzer. The spectator's colour layer is tile944+ ownership (semi-transparent washes that combine on seams), not rules.@@ -0,0 +1,90 @@
1+# Mosaic2+3+A Takuzu field an agent has to explore: tiles of mixed shape and size4+(rectangles, L, T, plus, notched) scattered over a grid with holes,5+overlapping each other by shared cells. Every tile is a binary puzzle on6+its own lines (each maximal horizontal or vertical run of its cells:7+balanced, no three in a row, no two equal lines of one orientation and8+length); the only rule across tiles is that shared cells agree. Every tile9+alone has 2-4 solutions; the field as a whole has one. This repo state is10+a localhost referee and spectator for watching agents work it live, with11+every step replayable. `PLAN.md` is the build order and the decisions12+(manifest v3 is the current shape).13+14+## Layout15+16+```17+engine/ Go: mosaic-engine gen | judge | pack (pure JSON in/out; the only place Takuzu rules exist)18+site/ Deno 2 + Fresh 2: referee, append-only JSONL log, /mcp, SSE, canvas viewer19+docs/ architecture page (fishbowl.html) and the reference renderer (mock-mosaic.py)20+```21+22+The engine's only dependency is `github.com/crillab/gophersat` (pure Go23+CDCL SAT solver) behind `engine/sat`: completion, feasibility and counting24+of one tile window. `engine/rules` is the propagation solver that models25+human technique (forced/guess attribution, difficulty ladder).26+27+## Run28+29+```30+cd engine && go test ./... && go build -o bin/mosaic-engine .31+cd site && deno install && deno task dev # prints the agent prompt, serves http://127.0.0.1:800032+```33+34+Open `http://127.0.0.1:8000/`, paste the printed prompt into Claude Code or35+Codex, and watch. Replay a finished game at `/?replay=<game_id>`; its log is36+at `/log/<game_id>`.37+38+Scripted client (also the protocol smoke test; both boards below have been39+played end to end, logs under `site/data/games/`):40+41+```42+cd site && deno task solve -- --seed a --G 27 --kind grid --n 14 # the phase-1 2x243+cd site && deno task solve -- --seed a --G 60 --kind big-first # packed, mixed sizes44+```45+46+Boards are scattered fields of shapes (manifest v3, see PLAN.md):47+`mosaic-engine pack --kind scatter --G N` drops shapes at seeded random48+positions with rectangular overlaps and small holes (`--coverage`,49+`--compound`, `--max-hole`), `mosaic-engine gen --seed S --G N --kind50+scatter` fills it. `grid` (X-by-X squares of side n, `--X --n`) is kept51+for the 2x2 standard and the X=15 envelope; `big-first` and `bands` are52+square packings. Generation is a batch job cached under53+`site/data/cache/`, keyed by generator version (`mosaic-engine version`),54+seed, G, kind and n. Measured timings are in PLAN.md ("Measured").55+56+## Tests57+58+- `engine`: `go test ./...` covers rules on shapes and lines (attribution,59+ enumeration with rule masks, coupling on shared cells, flip rectangles60+ on shared lines, the coupled-tile CSP, shape validity incl. the61+ distinct-lines bound), the SAT encoding (completions valid and varied,62+ joint completion keeps neighbours feasible, counts agree with the63+ propagation solver, determinism under concurrency), the packer (shape64+ validity, the overlap acceptance rule, hole statistics), the fill order,65+ generator determinism and every per-tile assertion (re-verified from66+ the JSON) on the 2x2 and X=15 fixtures and on scatter fields, and the67+ judge (classification and the <50 ms budget). `MOSAIC_SLOW=1` also regenerates the 2x268+ fixture from its seed and compares.69+- `site`: `deno task test` covers geometry and hue assignment at X=2 and70+ X=15, fixed-lightness colour mixing, delta coding, referee gating, the71+ guess policy, live-fold == replay-fold at every revision, and that every72+ finished game log on disk replays to a solved state with the right73+ reward.74+75+## What the generator guarantees (per tile, asserted; see `gen.PolicyFor`)76+77+- 2..m solutions alone (m by cell count: 2 up to 64 cells, 3 up to 196, 478+ above); every alternative differs from the truth inside an overlap79+ region shared with a neighbour (so a solved neighbour can pin it).80+- Blank floor 55% (<= 64 cells), 65% (<= 100), 70% above.81+- From 144 cells: with all its shared cells fixed the tile is unique, needs82+ at least one bifurcation (rules 1-3 stall), and needs the uniqueness83+ constraint (it has a second solution without it).84+- The whole field has exactly one coupled solution (CSP over the tiles'85+ solution sets and their shared cells).86+87+Shared cells are given only where blank overlaps would leave more than m88+solutions; the manifest records `rules.seam_clues: true` when any were89+used. Holes (cells no tile covers) are void. Coupling depth `k` is90+`unmeasured`.@@ -0,0 +1,1042 @@
1+<title>Mosaic Fishbowl</title>2+<link rel="preconnect" href="https://fonts.googleapis.com">3+<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Familjen+Grotesk:wght@500;700&family=IBM+Plex+Sans:wght@400;500&family=IBM+Plex+Mono:wght@400;500&display=swap">4+<style>5+ :root {6+ --ground: #EDEFF3;7+ --panel: #FFFFFF;8+ --ink: #1A1D24;9+ --muted: #667086;10+ --rule: #C7CCD6;11+ --faint: #E1E4EA;12+ --accent: #D9531E;13+ --accent-soft: #F6DED2;14+ --solved: #2E3340;15+ --t0: #C4574B; --t1: #C0912A; --t2: #6E9E3A; --t3: #2E9C8F; --t4: #3F7FBF; --t5: #7B5FC0; --t6: #BE5A93;16+ }17+ @media (prefers-color-scheme: dark) {18+ :root:not([data-theme="light"]) {19+ --ground: #14171D;20+ --panel: #1D2129;21+ --ink: #E7E9EE;22+ --muted: #9AA2B4;23+ --rule: #3A4050;24+ --faint: #262B35;25+ --accent: #F0784F;26+ --accent-soft: #3D2A22;27+ --solved: #C9CEDA;28+ --t0: #E06A5C; --t1: #DDB04A; --t2: #8ABF52; --t3: #4CB8A9; --t4: #5C9AD9; --t5: #9A7FE0; --t6: #D875A8;29+ }30+ }31+ :root[data-theme="dark"] {32+ --ground: #14171D;33+ --panel: #1D2129;34+ --ink: #E7E9EE;35+ --muted: #9AA2B4;36+ --rule: #3A4050;37+ --faint: #262B35;38+ --accent: #F0784F;39+ --accent-soft: #3D2A22;40+ --solved: #C9CEDA;41+ --t0: #E06A5C; --t1: #DDB04A; --t2: #8ABF52; --t3: #4CB8A9; --t4: #5C9AD9; --t5: #9A7FE0; --t6: #D875A8;42+ }43+ body {44+ background: var(--ground);45+ color: var(--ink);46+ font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;47+ font-size: 16px;48+ line-height: 1.55;49+ margin: 0;50+ padding: 48px 24px 96px;51+ }52+ main { max-width: 960px; margin: 0 auto; display: grid; gap: 40px; }53+ h1, h2 {54+ font-family: "Familjen Grotesk", "Helvetica Neue", Arial, sans-serif;55+ font-weight: 700;56+ letter-spacing: -0.01em;57+ text-wrap: balance;58+ margin: 0;59+ }60+ h1 { font-size: 40px; line-height: 1.05; }61+ h2 { font-size: 22px; line-height: 1.2; }62+ .eyebrow {63+ font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;64+ font-size: 12px;65+ letter-spacing: 0.08em;66+ text-transform: uppercase;67+ color: var(--muted);68+ }69+ header { display: grid; gap: 12px; }70+ header p { max-width: 62ch; margin: 0; color: var(--muted); }71+ p { max-width: 68ch; margin: 0; }72+ section { display: grid; gap: 14px; }73+ figure {74+ margin: 0;75+ background: var(--panel);76+ border: 1px solid var(--rule);77+ padding: 20px;78+ overflow-x: auto;79+ }80+ figure svg { display: block; width: 100%; height: auto; max-width: 100%; color: var(--ink); }81+ figcaption { margin-top: 12px; font-size: 14px; color: var(--muted); max-width: 72ch; }82+ .mono { font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace; }83+ table {84+ border-collapse: collapse;85+ width: 100%;86+ font-size: 14px;87+ background: var(--panel);88+ border: 1px solid var(--rule);89+ }90+ th, td { text-align: left; padding: 10px 14px; border-top: 1px solid var(--faint); vertical-align: top; }91+ th { font-family: "IBM Plex Mono", monospace; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); border-top: 0; }92+ td.k { font-family: "IBM Plex Mono", monospace; white-space: nowrap; }93+ .wrap { overflow-x: auto; }94+ ul { margin: 0; padding-left: 20px; max-width: 68ch; }95+ li + li { margin-top: 6px; }96+ strong { font-weight: 500; }97+</style>98+99+<main>100+ <header>101+ <div class="eyebrow">Architecture, Takuzu mosaic on Nostr</div>102+ <h1>Mosaic Fishbowl</h1>103+ <p>One referee orders the world, one relay archives it, any number of agents inhabit it, and anyone who can read the log can rebuild the board. The orange path is the only thing that becomes truth.</p>104+ </header>105+106+ <section>107+ <h2>The system</h2>108+ <figure>109+ <svg viewBox="0 0 1000 560" role="img" aria-label="Agents send reveal and commit calls to a referee; the referee publishes signed manifest, batch, and seed-reveal events to a private relay; a spectator and an analyzer subscribe to the relay; a generator derives the board from the seed for the referee and for anyone verifying; the private relay syncs challenges and leaderboards to a public relay where outside agents can submit.">110+ <defs>111+ <marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">112+ <path d="M0 0 L10 5 L0 10 z" fill="currentColor"/>113+ </marker>114+ <marker id="aa" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">115+ <path d="M0 0 L10 5 L0 10 z" fill="var(--accent)"/>116+ </marker>117+ </defs>118+ <g font-family="IBM Plex Sans, Arial, sans-serif" font-size="13" fill="currentColor">119+120+ <!-- Agents -->121+ <text x="40" y="48" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)" letter-spacing="1">AGENTS, one npub each</text>122+ <rect x="40" y="60" width="170" height="46" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>123+ <text x="52" y="80" font-weight="500">Agent A</text>124+ <text x="52" y="97" font-size="12" fill="var(--muted)">claude, batch 20</text>125+ <rect x="40" y="118" width="170" height="46" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>126+ <text x="52" y="138" font-weight="500">Agent B</text>127+ <text x="52" y="155" font-size="12" fill="var(--muted)">same model, batch 80</text>128+ <rect x="40" y="176" width="170" height="46" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>129+ <text x="52" y="196" font-weight="500">Agent C</text>130+ <text x="52" y="213" font-size="12" fill="var(--muted)">other family, code tool</text>131+132+ <rect x="40" y="258" width="170" height="40" rx="2" fill="none" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3"/>133+ <text x="52" y="275" font-size="12">NIP-46 signer</text>134+ <text x="52" y="290" font-size="12" fill="var(--muted)">holds keys, policy per agent</text>135+ <line x1="125" y1="258" x2="125" y2="222" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3"/>136+137+ <!-- Agents -> Referee -->138+ <line x1="210" y1="83" x2="300" y2="128" stroke="currentColor" stroke-width="1.2"/>139+ <line x1="210" y1="141" x2="300" y2="141" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>140+ <line x1="210" y1="199" x2="300" y2="154" stroke="currentColor" stroke-width="1.2"/>141+ <text x="255" y="126" text-anchor="middle" font-size="11" fill="var(--muted)">reveal(tile), commit(cells)</text>142+ <line x1="300" y1="176" x2="210" y2="176" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>143+ <text x="255" y="192" text-anchor="middle" font-size="11" fill="var(--muted)">observation, delta-coded</text>144+145+ <!-- Referee -->146+ <rect x="300" y="96" width="200" height="116" rx="2" fill="none" stroke="currentColor" stroke-width="1.6"/>147+ <text x="314" y="118" font-family="Familjen Grotesk, Arial, sans-serif" font-size="16" font-weight="700">Referee</text>148+ <text x="314" y="138" font-size="12" fill="var(--muted)">single writer, holds the seed</text>149+ <text x="314" y="156" font-size="12" fill="var(--muted)">validates against solution</text>150+ <text x="314" y="174" font-size="12" fill="var(--muted)">forced vs. guess per cell</text>151+ <text x="314" y="192" font-size="12" fill="var(--muted)">MCP endpoint today</text>152+153+ <!-- Generator -->154+ <rect x="300" y="360" width="200" height="86" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>155+ <text x="314" y="382" font-family="Familjen Grotesk, Arial, sans-serif" font-size="16" font-weight="700">Generator</text>156+ <text x="314" y="402" font-size="12" fill="var(--muted)">seed → solution + givens</text>157+ <text x="314" y="420" font-size="12" fill="var(--muted)">each tile has m > 1 solutions</text>158+ <text x="314" y="438" font-size="12" fill="var(--muted)">certifies coupling depth k</text>159+ <line x1="400" y1="360" x2="400" y2="212" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>160+ <text x="410" y="292" font-size="11" fill="var(--muted)">board, deterministic</text>161+162+ <!-- Referee -> Relay (accent) -->163+ <line x1="500" y1="154" x2="590" y2="154" stroke="var(--accent)" stroke-width="2" marker-end="url(#aa)"/>164+ <text x="545" y="120" text-anchor="middle" font-size="11" fill="var(--accent)">manifest, seed commit</text>165+ <text x="545" y="136" text-anchor="middle" font-size="11" fill="var(--accent)">batch resolutions #tile</text>166+ <text x="545" y="176" text-anchor="middle" font-size="11" fill="var(--accent)">seed reveal at end</text>167+168+ <!-- Relay -->169+ <rect x="590" y="60" width="180" height="270" rx="2" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="1.6"/>170+ <text x="604" y="84" font-family="Familjen Grotesk, Arial, sans-serif" font-size="16" font-weight="700">Private relay</text>171+ <text x="604" y="104" font-size="12" fill="var(--muted)">strfry / HAVEN, NIP-42 auth</text>172+ <text x="604" y="134" font-size="12">the world and the archive</text>173+ <text x="604" y="158" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">manifest 30xxx d=game</text>174+ <text x="604" y="174" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">batch regular #tile</text>175+ <text x="604" y="190" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">reveal regular</text>176+ <text x="604" y="206" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">analysis regular e=game</text>177+ <text x="604" y="222" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">board 30xxx d=game</text>178+ <text x="604" y="252" font-size="12" fill="var(--muted)">state = fold(events)</text>179+ <text x="604" y="270" font-size="12" fill="var(--muted)">no retention cron:</text>180+ <text x="604" y="286" font-size="12" fill="var(--muted)">old games are the dataset</text>181+182+ <!-- Relay -> Spectator -->183+ <line x1="770" y1="100" x2="840" y2="100" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>184+ <text x="805" y="88" text-anchor="middle" font-size="11" fill="var(--muted)">REQ #tile</text>185+ <rect x="840" y="60" width="140" height="84" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>186+ <text x="852" y="82" font-family="Familjen Grotesk, Arial, sans-serif" font-size="16" font-weight="700">Spectator</text>187+ <text x="852" y="101" font-size="12" fill="var(--muted)">folds the log</text>188+ <text x="852" y="117" font-size="12" fill="var(--muted)">viewport = tile filter</text>189+ <text x="852" y="133" font-size="12" fill="var(--muted)">scrub, race view</text>190+191+ <!-- Relay <-> Analyzer -->192+ <line x1="770" y1="200" x2="840" y2="200" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>193+ <text x="805" y="188" text-anchor="middle" font-size="11" fill="var(--muted)">game end</text>194+ <line x1="840" y1="226" x2="770" y2="226" stroke="var(--accent)" stroke-width="1.6" marker-end="url(#aa)"/>195+ <text x="805" y="243" text-anchor="middle" font-size="11" fill="var(--accent)">fingerprints</text>196+ <rect x="840" y="170" width="140" height="84" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>197+ <text x="852" y="192" font-family="Familjen Grotesk, Arial, sans-serif" font-size="16" font-weight="700">Analyzer</text>198+ <text x="852" y="211" font-size="12" fill="var(--muted)">guess rate, risk</text>199+ <text x="852" y="227" font-size="12" fill="var(--muted)">frontier strategy</text>200+ <text x="852" y="243" font-size="12" fill="var(--muted)">leaderboards</text>201+202+ <!-- Verify (anyone) -->203+ <rect x="840" y="360" width="140" height="70" rx="2" fill="none" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3"/>204+ <text x="852" y="382" font-weight="500">Anyone</text>205+ <text x="852" y="399" font-size="12" fill="var(--muted)">regenerate from seed</text>206+ <text x="852" y="415" font-size="12" fill="var(--muted)">refold, confirm result</text>207+ <line x1="500" y1="403" x2="840" y2="403" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3" marker-end="url(#a)"/>208+ <text x="670" y="392" text-anchor="middle" font-size="11" fill="var(--muted)">same generator, revealed seed</text>209+ <line x1="910" y1="360" x2="910" y2="254" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3"/>210+211+ <!-- Public relay row -->212+ <rect x="590" y="470" width="180" height="60" rx="2" fill="none" stroke="var(--accent)" stroke-width="1.2" stroke-dasharray="5 3"/>213+ <text x="604" y="492" font-family="Familjen Grotesk, Arial, sans-serif" font-size="15" font-weight="700">Public relay</text>214+ <text x="604" y="511" font-size="12" fill="var(--muted)">challenges, leaderboards</text>215+ <line x1="680" y1="330" x2="680" y2="470" stroke="var(--accent)" stroke-width="1.2" marker-end="url(#aa)" marker-start="url(#aa)"/>216+ <text x="692" y="410" font-size="11" fill="var(--accent)">negentropy sync</text>217+ <text x="692" y="425" font-size="11" fill="var(--muted)">selected kinds only</text>218+219+ <rect x="40" y="470" width="170" height="60" rx="2" fill="none" stroke="currentColor" stroke-width="1" stroke-dasharray="4 3"/>220+ <text x="52" y="492" font-weight="500">Outside agents</text>221+ <text x="52" y="509" font-size="12" fill="var(--muted)">any nsec, any language</text>222+ <line x1="210" y1="500" x2="590" y2="500" stroke="currentColor" stroke-width="1.2" marker-end="url(#a)"/>223+ <text x="400" y="489" text-anchor="middle" font-size="11" fill="var(--muted)">signed batches against a challenge; referee validates</text>224+ </g>225+ </svg>226+ <figcaption>Only the referee writes truth (orange). Agents never see the seed; the relay never runs rules; the spectator and analyzer are read-only folds over the same events, so any of them can be rebuilt from an empty disk.</figcaption>227+ </figure>228+ <p>This is mcpsweeper's shape with the log moved out of D1: the Worker stays as referee, D1 becomes a cache, and the spectator opens a WebSocket to the relay instead of polling.</p>229+ </section>230+231+ <section>232+ <h2>One game is one log</h2>233+ <figure>234+ <svg viewBox="0 0 1000 250" role="img" aria-label="A game's events in order: manifest with seed commit, then batch resolutions each tagged with the tiles they touch, then a seed reveal; the board state at any point is the deterministic generator applied to the seed, folded with the batches up to that point.">235+ <defs>236+ <marker id="b" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">237+ <path d="M0 0 L10 5 L0 10 z" fill="currentColor"/>238+ </marker>239+ </defs>240+ <g font-family="IBM Plex Sans, Arial, sans-serif" font-size="13" fill="currentColor">241+ <!-- event chain -->242+ <rect x="30" y="40" width="170" height="92" rx="2" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="1.4"/>243+ <text x="42" y="60" font-weight="500">manifest</text>244+ <text x="42" y="78" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">sha256(seed‖nonce)</text>245+ <text x="42" y="94" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">X=32 n=8 m=3 k=2</text>246+ <text x="42" y="110" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">model batch code_use</text>247+ <text x="42" y="126" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">agent=npub…</text>248+249+ <line x1="200" y1="86" x2="240" y2="86" stroke="currentColor" stroke-width="1.2" marker-end="url(#b)"/>250+ <rect x="240" y="40" width="150" height="92" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>251+ <text x="252" y="60" font-weight="500">batch 1</text>252+ <text x="252" y="78" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">reveal t(3,4)</text>253+ <text x="252" y="94" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">#tile 3,4</text>254+ <text x="252" y="110" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">seq=1 e=manifest</text>255+256+ <line x1="390" y1="86" x2="430" y2="86" stroke="currentColor" stroke-width="1.2" marker-end="url(#b)"/>257+ <rect x="430" y="40" width="150" height="92" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>258+ <text x="442" y="60" font-weight="500">batch 2</text>259+ <text x="442" y="78" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">commit 14 cells</text>260+ <text x="442" y="94" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">forced=12 guess=2</text>261+ <text x="442" y="110" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">#tile 3,4 and 3,5</text>262+263+ <line x1="580" y1="86" x2="620" y2="86" stroke="currentColor" stroke-width="1.2" marker-end="url(#b)"/>264+ <text x="650" y="90" font-size="18" fill="var(--muted)">…</text>265+ <line x1="680" y1="86" x2="720" y2="86" stroke="currentColor" stroke-width="1.2" marker-end="url(#b)"/>266+ <rect x="720" y="40" width="120" height="92" rx="2" fill="none" stroke="currentColor" stroke-width="1.2"/>267+ <text x="732" y="60" font-weight="500">batch N</text>268+ <text x="732" y="78" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">solved</text>269+270+ <line x1="840" y1="86" x2="870" y2="86" stroke="currentColor" stroke-width="1.2" marker-end="url(#b)"/>271+ <rect x="870" y="40" width="110" height="92" rx="2" fill="var(--accent-soft)" stroke="var(--accent)" stroke-width="1.4"/>272+ <text x="882" y="60" font-weight="500">seed reveal</text>273+ <text x="882" y="78" font-family="IBM Plex Mono, monospace" font-size="11" fill="var(--muted)">seed, nonce</text>274+ <text x="882" y="94" font-size="11" fill="var(--muted)">now anyone can</text>275+ <text x="882" y="110" font-size="11" fill="var(--muted)">regenerate</text>276+277+ <!-- fold -->278+ <line x1="115" y1="132" x2="115" y2="190" stroke="currentColor" stroke-width="1" stroke-dasharray="3 3"/>279+ <line x1="315" y1="132" x2="315" y2="190" stroke="currentColor" stroke-width="1" stroke-dasharray="3 3"/>280+ <line x1="505" y1="132" x2="505" y2="190" stroke="currentColor" stroke-width="1" stroke-dasharray="3 3"/>281+ <line x1="780" y1="132" x2="780" y2="190" stroke="currentColor" stroke-width="1" stroke-dasharray="3 3"/>282+ <line x1="30" y1="200" x2="980" y2="200" stroke="currentColor" stroke-width="1.6"/>283+ <text x="30" y="228" font-family="IBM Plex Mono, monospace" font-size="12">state(t) = fold( generate(seed), batches[0..t] )</text>284+ <text x="980" y="228" text-anchor="end" font-size="12" fill="var(--muted)">cells are derived, never stored; ~20 events per game</text>285+ </g>286+ </svg>287+ <figcaption>Cells never travel. A 224×224 board is a seed and a short list of batches; the spectator's scrubber is just choosing <span class="mono">t</span>. Same seed across agents gives a paired trial.</figcaption>288+ </figure>289+ </section>290+291+ <section>292+ <h2>What the agent can see</h2>293+ <figure>294+ <svg viewBox="0 0 1064 544" role="img" aria-label="A 7 by 7 mosaic of 4 by 4 Takuzu tiles that overlap by one cell. Each tile has its own semi-transparent tint; cells shared by two tiles show both tints combined. 9 solved tiles, grown from a seed tile by frontier expansion, show every 0 and 1. The 7 frontier tiles around them show only their givens plus the line they share with a solved tile. The remaining tiles are hidden.">295+<g font-family="IBM Plex Mono, monospace" font-size="12" text-anchor="middle">296+<rect x="30" y="30" width="484" height="484" fill="var(--panel)"/>297+<rect x="30" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>298+<rect x="52" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>299+<rect x="74" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>300+<rect x="96" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>301+<rect x="118" y="30" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>302+<rect x="140" y="30" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>303+<rect x="162" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>304+<rect x="184" y="30" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>305+<rect x="206" y="30" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>306+<rect x="228" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>307+<rect x="250" y="30" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>308+<rect x="272" y="30" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>309+<rect x="294" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>310+<rect x="316" y="30" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>311+<rect x="338" y="30" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>312+<rect x="360" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>313+<rect x="382" y="30" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>314+<rect x="404" y="30" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>315+<rect x="426" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>316+<rect x="448" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>317+<rect x="470" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>318+<rect x="492" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>319+<rect x="30" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>320+<rect x="52" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>321+<rect x="74" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>322+<rect x="96" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>323+<rect x="118" y="52" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>324+<rect x="140" y="52" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>325+<rect x="162" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>326+<rect x="184" y="52" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>327+<rect x="206" y="52" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>328+<rect x="228" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>329+<rect x="250" y="52" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>330+<rect x="272" y="52" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>331+<rect x="294" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>332+<rect x="316" y="52" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>333+<rect x="338" y="52" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>334+<rect x="360" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>335+<rect x="382" y="52" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>336+<rect x="404" y="52" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>337+<rect x="426" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>338+<rect x="448" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>339+<rect x="470" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>340+<rect x="492" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>341+<rect x="30" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>342+<rect x="52" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>343+<rect x="74" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>344+<rect x="96" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>345+<rect x="118" y="74" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>346+<rect x="140" y="74" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>347+<rect x="162" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>348+<rect x="184" y="74" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>349+<rect x="206" y="74" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>350+<rect x="228" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>351+<rect x="250" y="74" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>352+<rect x="272" y="74" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>353+<rect x="294" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>354+<rect x="316" y="74" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>355+<rect x="338" y="74" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>356+<rect x="360" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>357+<rect x="382" y="74" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>358+<rect x="404" y="74" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>359+<rect x="426" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>360+<rect x="448" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>361+<rect x="470" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>362+<rect x="492" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>363+<rect x="30" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>364+<rect x="52" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>365+<rect x="74" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>366+<rect x="96" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>367+<rect x="118" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>368+<rect x="140" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>369+<rect x="162" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.1"/>370+<rect x="184" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>371+<rect x="206" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>372+<rect x="228" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.1"/>373+<rect x="250" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>374+<rect x="272" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>375+<rect x="294" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>376+<rect x="316" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>377+<rect x="338" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>378+<rect x="360" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>379+<rect x="382" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>380+<rect x="404" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>381+<rect x="426" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.1"/>382+<rect x="448" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>383+<rect x="470" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>384+<rect x="492" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>385+<rect x="30" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>386+<rect x="52" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>387+<rect x="74" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>388+<rect x="96" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>389+<rect x="118" y="118" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>390+<rect x="140" y="118" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>391+<rect x="162" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>392+<rect x="184" y="118" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>393+<rect x="206" y="118" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>394+<rect x="228" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>395+<rect x="250" y="118" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>396+<rect x="272" y="118" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>397+<rect x="294" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>398+<rect x="316" y="118" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>399+<rect x="338" y="118" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>400+<rect x="360" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>401+<rect x="382" y="118" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>402+<rect x="404" y="118" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>403+<rect x="426" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>404+<rect x="448" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>405+<rect x="470" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>406+<rect x="492" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>407+<rect x="30" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>408+<rect x="52" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>409+<rect x="74" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>410+<rect x="96" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>411+<rect x="118" y="140" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>412+<rect x="140" y="140" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>413+<rect x="162" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>414+<rect x="184" y="140" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>415+<rect x="206" y="140" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>416+<rect x="228" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>417+<rect x="250" y="140" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>418+<rect x="272" y="140" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>419+<rect x="294" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>420+<rect x="316" y="140" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>421+<rect x="338" y="140" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>422+<rect x="360" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>423+<rect x="382" y="140" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>424+<rect x="404" y="140" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>425+<rect x="426" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>426+<rect x="448" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>427+<rect x="470" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>428+<rect x="492" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>429+<rect x="30" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>430+<rect x="52" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>431+<rect x="74" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>432+<rect x="96" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>433+<rect x="118" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>434+<rect x="140" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>435+<rect x="162" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>436+<rect x="184" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>437+<rect x="206" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>438+<rect x="228" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.1"/>439+<rect x="250" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>440+<rect x="272" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>441+<rect x="294" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.1"/>442+<rect x="316" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>443+<rect x="338" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>444+<rect x="360" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>445+<rect x="382" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>446+<rect x="404" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>447+<rect x="426" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.1"/>448+<rect x="448" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>449+<rect x="470" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>450+<rect x="492" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>451+<rect x="30" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>452+<rect x="52" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>453+<rect x="74" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>454+<rect x="96" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>455+<rect x="118" y="184" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>456+<rect x="140" y="184" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>457+<rect x="162" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>458+<rect x="184" y="184" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>459+<rect x="206" y="184" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>460+<rect x="228" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>461+<rect x="250" y="184" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>462+<rect x="272" y="184" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>463+<rect x="294" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>464+<rect x="316" y="184" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>465+<rect x="338" y="184" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>466+<rect x="360" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>467+<rect x="382" y="184" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>468+<rect x="404" y="184" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>469+<rect x="426" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>470+<rect x="448" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>471+<rect x="470" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>472+<rect x="492" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>473+<rect x="30" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>474+<rect x="52" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>475+<rect x="74" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>476+<rect x="96" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>477+<rect x="118" y="206" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>478+<rect x="140" y="206" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>479+<rect x="162" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>480+<rect x="184" y="206" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>481+<rect x="206" y="206" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>482+<rect x="228" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>483+<rect x="250" y="206" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>484+<rect x="272" y="206" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>485+<rect x="294" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>486+<rect x="316" y="206" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>487+<rect x="338" y="206" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>488+<rect x="360" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>489+<rect x="382" y="206" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>490+<rect x="404" y="206" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>491+<rect x="426" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>492+<rect x="448" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>493+<rect x="470" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>494+<rect x="492" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>495+<rect x="30" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>496+<rect x="52" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>497+<rect x="74" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>498+<rect x="96" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.1"/>499+<rect x="118" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>500+<rect x="140" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>501+<rect x="162" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>502+<rect x="184" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>503+<rect x="206" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>504+<rect x="228" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.34"/>505+<rect x="250" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>506+<rect x="272" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>507+<rect x="294" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>508+<rect x="316" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>509+<rect x="338" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>510+<rect x="360" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>511+<rect x="382" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>512+<rect x="404" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>513+<rect x="426" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>514+<rect x="448" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>515+<rect x="470" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>516+<rect x="492" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>517+<rect x="30" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>518+<rect x="52" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>519+<rect x="74" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>520+<rect x="96" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>521+<rect x="118" y="250" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>522+<rect x="140" y="250" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>523+<rect x="162" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>524+<rect x="184" y="250" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>525+<rect x="206" y="250" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>526+<rect x="228" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.34"/>527+<rect x="250" y="250" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>528+<rect x="272" y="250" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>529+<rect x="294" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>530+<rect x="316" y="250" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>531+<rect x="338" y="250" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>532+<rect x="360" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>533+<rect x="382" y="250" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>534+<rect x="404" y="250" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>535+<rect x="426" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>536+<rect x="448" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>537+<rect x="470" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>538+<rect x="492" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>539+<rect x="30" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>540+<rect x="52" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>541+<rect x="74" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>542+<rect x="96" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>543+<rect x="118" y="272" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>544+<rect x="140" y="272" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>545+<rect x="162" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>546+<rect x="184" y="272" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>547+<rect x="206" y="272" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>548+<rect x="228" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.34"/>549+<rect x="250" y="272" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>550+<rect x="272" y="272" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>551+<rect x="294" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>552+<rect x="316" y="272" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>553+<rect x="338" y="272" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>554+<rect x="360" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>555+<rect x="382" y="272" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>556+<rect x="404" y="272" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>557+<rect x="426" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>558+<rect x="448" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>559+<rect x="470" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>560+<rect x="492" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>561+<rect x="30" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>562+<rect x="52" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>563+<rect x="74" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>564+<rect x="96" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>565+<rect x="118" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>566+<rect x="140" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>567+<rect x="162" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.34"/>568+<rect x="184" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.34"/>569+<rect x="206" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.34"/>570+<rect x="228" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.62"/>571+<rect x="250" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>572+<rect x="272" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>573+<rect x="294" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>574+<rect x="316" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>575+<rect x="338" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>576+<rect x="360" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.34"/>577+<rect x="382" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>578+<rect x="404" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>579+<rect x="426" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>580+<rect x="448" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>581+<rect x="470" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>582+<rect x="492" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>583+<rect x="30" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>584+<rect x="52" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>585+<rect x="74" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>586+<rect x="96" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>587+<rect x="118" y="316" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>588+<rect x="140" y="316" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>589+<rect x="162" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.34"/>590+<rect x="184" y="316" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>591+<rect x="206" y="316" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>592+<rect x="228" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>593+<rect x="250" y="316" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>594+<rect x="272" y="316" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>595+<rect x="294" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>596+<rect x="316" y="316" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>597+<rect x="338" y="316" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>598+<rect x="360" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>599+<rect x="382" y="316" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>600+<rect x="404" y="316" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>601+<rect x="426" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>602+<rect x="448" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>603+<rect x="470" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>604+<rect x="492" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>605+<rect x="30" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>606+<rect x="52" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>607+<rect x="74" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>608+<rect x="96" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>609+<rect x="118" y="338" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>610+<rect x="140" y="338" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>611+<rect x="162" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.34"/>612+<rect x="184" y="338" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>613+<rect x="206" y="338" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>614+<rect x="228" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>615+<rect x="250" y="338" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>616+<rect x="272" y="338" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>617+<rect x="294" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>618+<rect x="316" y="338" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>619+<rect x="338" y="338" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>620+<rect x="360" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>621+<rect x="382" y="338" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>622+<rect x="404" y="338" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>623+<rect x="426" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>624+<rect x="448" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>625+<rect x="470" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>626+<rect x="492" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>627+<rect x="30" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>628+<rect x="52" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>629+<rect x="74" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>630+<rect x="96" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>631+<rect x="118" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>632+<rect x="140" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>633+<rect x="162" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.62"/>634+<rect x="184" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.62"/>635+<rect x="206" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.62"/>636+<rect x="228" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.62"/>637+<rect x="250" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>638+<rect x="272" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>639+<rect x="294" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.62"/>640+<rect x="316" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>641+<rect x="338" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>642+<rect x="360" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>643+<rect x="382" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>644+<rect x="404" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>645+<rect x="426" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>646+<rect x="448" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>647+<rect x="470" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>648+<rect x="492" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>649+<rect x="30" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>650+<rect x="52" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>651+<rect x="74" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>652+<rect x="96" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>653+<rect x="118" y="382" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>654+<rect x="140" y="382" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>655+<rect x="162" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.62"/>656+<rect x="184" y="382" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>657+<rect x="206" y="382" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>658+<rect x="228" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.62"/>659+<rect x="250" y="382" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>660+<rect x="272" y="382" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>661+<rect x="294" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>662+<rect x="316" y="382" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>663+<rect x="338" y="382" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>664+<rect x="360" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>665+<rect x="382" y="382" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>666+<rect x="404" y="382" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>667+<rect x="426" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>668+<rect x="448" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>669+<rect x="470" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>670+<rect x="492" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>671+<rect x="30" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>672+<rect x="52" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>673+<rect x="74" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>674+<rect x="96" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>675+<rect x="118" y="404" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>676+<rect x="140" y="404" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>677+<rect x="162" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.62"/>678+<rect x="184" y="404" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>679+<rect x="206" y="404" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>680+<rect x="228" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.62"/>681+<rect x="250" y="404" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>682+<rect x="272" y="404" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>683+<rect x="294" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>684+<rect x="316" y="404" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>685+<rect x="338" y="404" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>686+<rect x="360" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>687+<rect x="382" y="404" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>688+<rect x="404" y="404" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>689+<rect x="426" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>690+<rect x="448" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>691+<rect x="470" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>692+<rect x="492" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>693+<rect x="30" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>694+<rect x="52" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>695+<rect x="74" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>696+<rect x="96" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.62"/>697+<rect x="118" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.62"/>698+<rect x="140" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.62"/>699+<rect x="162" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.62"/>700+<rect x="184" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.62"/>701+<rect x="206" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.62"/>702+<rect x="228" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.62"/>703+<rect x="250" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.62"/>704+<rect x="272" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.62"/>705+<rect x="294" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.62"/>706+<rect x="316" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>707+<rect x="338" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>708+<rect x="360" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>709+<rect x="382" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>710+<rect x="404" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>711+<rect x="426" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.34"/>712+<rect x="448" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>713+<rect x="470" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>714+<rect x="492" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>715+<rect x="30" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>716+<rect x="52" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>717+<rect x="74" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>718+<rect x="96" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>719+<rect x="118" y="448" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>720+<rect x="140" y="448" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>721+<rect x="162" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>722+<rect x="184" y="448" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>723+<rect x="206" y="448" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>724+<rect x="228" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>725+<rect x="250" y="448" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>726+<rect x="272" y="448" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>727+<rect x="294" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>728+<rect x="316" y="448" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>729+<rect x="338" y="448" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>730+<rect x="360" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>731+<rect x="382" y="448" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>732+<rect x="404" y="448" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>733+<rect x="426" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>734+<rect x="448" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>735+<rect x="470" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>736+<rect x="492" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>737+<rect x="30" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>738+<rect x="52" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>739+<rect x="74" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>740+<rect x="96" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>741+<rect x="118" y="470" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>742+<rect x="140" y="470" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>743+<rect x="162" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>744+<rect x="184" y="470" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>745+<rect x="206" y="470" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>746+<rect x="228" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>747+<rect x="250" y="470" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>748+<rect x="272" y="470" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>749+<rect x="294" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>750+<rect x="316" y="470" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>751+<rect x="338" y="470" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>752+<rect x="360" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>753+<rect x="382" y="470" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>754+<rect x="404" y="470" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>755+<rect x="426" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>756+<rect x="448" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>757+<rect x="470" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>758+<rect x="492" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>759+<rect x="30" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>760+<rect x="52" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>761+<rect x="74" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>762+<rect x="96" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>763+<rect x="118" y="492" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>764+<rect x="140" y="492" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>765+<rect x="162" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>766+<rect x="184" y="492" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>767+<rect x="206" y="492" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>768+<rect x="228" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>769+<rect x="250" y="492" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>770+<rect x="272" y="492" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>771+<rect x="294" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>772+<rect x="316" y="492" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>773+<rect x="338" y="492" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>774+<rect x="360" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>775+<rect x="382" y="492" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>776+<rect x="404" y="492" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>777+<rect x="426" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>778+<rect x="448" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>779+<rect x="470" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>780+<rect x="492" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>781+<g stroke="var(--rule)" stroke-width="0.6">782+<line x1="30" y1="30" x2="514" y2="30"/>783+<line x1="30" y1="30" x2="30" y2="514"/>784+<line x1="30" y1="52" x2="514" y2="52"/>785+<line x1="52" y1="30" x2="52" y2="514"/>786+<line x1="30" y1="74" x2="514" y2="74"/>787+<line x1="74" y1="30" x2="74" y2="514"/>788+<line x1="30" y1="96" x2="514" y2="96"/>789+<line x1="96" y1="30" x2="96" y2="514"/>790+<line x1="30" y1="118" x2="514" y2="118"/>791+<line x1="118" y1="30" x2="118" y2="514"/>792+<line x1="30" y1="140" x2="514" y2="140"/>793+<line x1="140" y1="30" x2="140" y2="514"/>794+<line x1="30" y1="162" x2="514" y2="162"/>795+<line x1="162" y1="30" x2="162" y2="514"/>796+<line x1="30" y1="184" x2="514" y2="184"/>797+<line x1="184" y1="30" x2="184" y2="514"/>798+<line x1="30" y1="206" x2="514" y2="206"/>799+<line x1="206" y1="30" x2="206" y2="514"/>800+<line x1="30" y1="228" x2="514" y2="228"/>801+<line x1="228" y1="30" x2="228" y2="514"/>802+<line x1="30" y1="250" x2="514" y2="250"/>803+<line x1="250" y1="30" x2="250" y2="514"/>804+<line x1="30" y1="272" x2="514" y2="272"/>805+<line x1="272" y1="30" x2="272" y2="514"/>806+<line x1="30" y1="294" x2="514" y2="294"/>807+<line x1="294" y1="30" x2="294" y2="514"/>808+<line x1="30" y1="316" x2="514" y2="316"/>809+<line x1="316" y1="30" x2="316" y2="514"/>810+<line x1="30" y1="338" x2="514" y2="338"/>811+<line x1="338" y1="30" x2="338" y2="514"/>812+<line x1="30" y1="360" x2="514" y2="360"/>813+<line x1="360" y1="30" x2="360" y2="514"/>814+<line x1="30" y1="382" x2="514" y2="382"/>815+<line x1="382" y1="30" x2="382" y2="514"/>816+<line x1="30" y1="404" x2="514" y2="404"/>817+<line x1="404" y1="30" x2="404" y2="514"/>818+<line x1="30" y1="426" x2="514" y2="426"/>819+<line x1="426" y1="30" x2="426" y2="514"/>820+<line x1="30" y1="448" x2="514" y2="448"/>821+<line x1="448" y1="30" x2="448" y2="514"/>822+<line x1="30" y1="470" x2="514" y2="470"/>823+<line x1="470" y1="30" x2="470" y2="514"/>824+<line x1="30" y1="492" x2="514" y2="492"/>825+<line x1="492" y1="30" x2="492" y2="514"/>826+<line x1="30" y1="514" x2="514" y2="514"/>827+<line x1="514" y1="30" x2="514" y2="514"/>828+</g>829+<text x="239.0" y="243.84" fill="currentColor">0</text>830+<text x="283.0" y="243.84" fill="currentColor">1</text>831+<text x="305.0" y="265.84" fill="currentColor">0</text>832+<text x="283.0" y="287.84" fill="currentColor">0</text>833+<text x="41.0" y="309.84" fill="currentColor">0</text>834+<text x="85.0" y="309.84" fill="currentColor">0</text>835+<text x="107.0" y="309.84" fill="currentColor">1</text>836+<text x="217.0" y="309.84" fill="currentColor">0</text>837+<text x="239.0" y="309.84" fill="currentColor" font-weight="500">1</text>838+<text x="261.0" y="309.84" fill="currentColor" font-weight="500">0</text>839+<text x="283.0" y="309.84" fill="currentColor" font-weight="500">0</text>840+<text x="305.0" y="309.84" fill="currentColor" font-weight="500">1</text>841+<text x="349.0" y="309.84" fill="currentColor">0</text>842+<text x="173.0" y="331.84" fill="currentColor">1</text>843+<text x="195.0" y="331.84" fill="currentColor">1</text>844+<text x="239.0" y="331.84" fill="currentColor" font-weight="500">0</text>845+<text x="261.0" y="331.84" fill="currentColor" font-weight="500">0</text>846+<text x="283.0" y="331.84" fill="currentColor" font-weight="500">1</text>847+<text x="305.0" y="331.84" fill="currentColor" font-weight="500">1</text>848+<text x="85.0" y="353.84" fill="currentColor">1</text>849+<text x="239.0" y="353.84" fill="currentColor" font-weight="500">1</text>850+<text x="261.0" y="353.84" fill="currentColor" font-weight="500">1</text>851+<text x="283.0" y="353.84" fill="currentColor" font-weight="500">0</text>852+<text x="305.0" y="353.84" fill="currentColor" font-weight="500">0</text>853+<text x="327.0" y="353.84" fill="currentColor">1</text>854+<text x="349.0" y="353.84" fill="currentColor">1</text>855+<text x="371.0" y="353.84" fill="currentColor">0</text>856+<text x="41.0" y="375.84" fill="currentColor" font-weight="500">1</text>857+<text x="63.0" y="375.84" fill="currentColor" font-weight="500">0</text>858+<text x="85.0" y="375.84" fill="currentColor" font-weight="500">1</text>859+<text x="107.0" y="375.84" fill="currentColor" font-weight="500">0</text>860+<text x="173.0" y="375.84" fill="currentColor" font-weight="500">0</text>861+<text x="195.0" y="375.84" fill="currentColor" font-weight="500">1</text>862+<text x="217.0" y="375.84" fill="currentColor" font-weight="500">1</text>863+<text x="239.0" y="375.84" fill="currentColor" font-weight="500">0</text>864+<text x="261.0" y="375.84" fill="currentColor" font-weight="500">1</text>865+<text x="283.0" y="375.84" fill="currentColor" font-weight="500">1</text>866+<text x="305.0" y="375.84" fill="currentColor" font-weight="500">0</text>867+<text x="327.0" y="375.84" fill="currentColor">0</text>868+<text x="41.0" y="397.84" fill="currentColor" font-weight="500">0</text>869+<text x="63.0" y="397.84" fill="currentColor" font-weight="500">1</text>870+<text x="85.0" y="397.84" fill="currentColor" font-weight="500">1</text>871+<text x="107.0" y="397.84" fill="currentColor" font-weight="500">0</text>872+<text x="151.0" y="397.84" fill="currentColor">0</text>873+<text x="173.0" y="397.84" fill="currentColor" font-weight="500">1</text>874+<text x="195.0" y="397.84" fill="currentColor" font-weight="500">1</text>875+<text x="217.0" y="397.84" fill="currentColor" font-weight="500">0</text>876+<text x="239.0" y="397.84" fill="currentColor" font-weight="500">0</text>877+<text x="261.0" y="397.84" fill="currentColor" font-weight="500">0</text>878+<text x="283.0" y="397.84" fill="currentColor" font-weight="500">1</text>879+<text x="305.0" y="397.84" fill="currentColor" font-weight="500">1</text>880+<text x="371.0" y="397.84" fill="currentColor">0</text>881+<text x="41.0" y="419.84" fill="currentColor" font-weight="500">1</text>882+<text x="63.0" y="419.84" fill="currentColor" font-weight="500">0</text>883+<text x="85.0" y="419.84" fill="currentColor" font-weight="500">0</text>884+<text x="107.0" y="419.84" fill="currentColor" font-weight="500">1</text>885+<text x="129.0" y="419.84" fill="currentColor">0</text>886+<text x="173.0" y="419.84" fill="currentColor" font-weight="500">1</text>887+<text x="195.0" y="419.84" fill="currentColor" font-weight="500">0</text>888+<text x="217.0" y="419.84" fill="currentColor" font-weight="500">0</text>889+<text x="239.0" y="419.84" fill="currentColor" font-weight="500">1</text>890+<text x="261.0" y="419.84" fill="currentColor" font-weight="500">1</text>891+<text x="283.0" y="419.84" fill="currentColor" font-weight="500">0</text>892+<text x="305.0" y="419.84" fill="currentColor" font-weight="500">0</text>893+<text x="371.0" y="419.84" fill="currentColor">1</text>894+<text x="41.0" y="441.84" fill="currentColor" font-weight="500">0</text>895+<text x="63.0" y="441.84" fill="currentColor" font-weight="500">1</text>896+<text x="85.0" y="441.84" fill="currentColor" font-weight="500">0</text>897+<text x="107.0" y="441.84" fill="currentColor" font-weight="500">1</text>898+<text x="129.0" y="441.84" fill="currentColor" font-weight="500">0</text>899+<text x="151.0" y="441.84" fill="currentColor" font-weight="500">1</text>900+<text x="173.0" y="441.84" fill="currentColor" font-weight="500">0</text>901+<text x="195.0" y="441.84" fill="currentColor" font-weight="500">0</text>902+<text x="217.0" y="441.84" fill="currentColor" font-weight="500">1</text>903+<text x="239.0" y="441.84" fill="currentColor" font-weight="500">1</text>904+<text x="261.0" y="441.84" fill="currentColor" font-weight="500">0</text>905+<text x="283.0" y="441.84" fill="currentColor" font-weight="500">0</text>906+<text x="305.0" y="441.84" fill="currentColor" font-weight="500">1</text>907+<text x="327.0" y="441.84" fill="currentColor" font-weight="500">1</text>908+<text x="349.0" y="441.84" fill="currentColor" font-weight="500">0</text>909+<text x="371.0" y="441.84" fill="currentColor" font-weight="500">0</text>910+<text x="415.0" y="441.84" fill="currentColor">0</text>911+<text x="41.0" y="463.84" fill="currentColor" font-weight="500">1</text>912+<text x="63.0" y="463.84" fill="currentColor" font-weight="500">0</text>913+<text x="85.0" y="463.84" fill="currentColor" font-weight="500">0</text>914+<text x="107.0" y="463.84" fill="currentColor" font-weight="500">1</text>915+<text x="129.0" y="463.84" fill="currentColor" font-weight="500">0</text>916+<text x="151.0" y="463.84" fill="currentColor" font-weight="500">0</text>917+<text x="173.0" y="463.84" fill="currentColor" font-weight="500">1</text>918+<text x="195.0" y="463.84" fill="currentColor" font-weight="500">1</text>919+<text x="217.0" y="463.84" fill="currentColor" font-weight="500">0</text>920+<text x="239.0" y="463.84" fill="currentColor" font-weight="500">0</text>921+<text x="261.0" y="463.84" fill="currentColor" font-weight="500">0</text>922+<text x="283.0" y="463.84" fill="currentColor" font-weight="500">1</text>923+<text x="305.0" y="463.84" fill="currentColor" font-weight="500">1</text>924+<text x="327.0" y="463.84" fill="currentColor" font-weight="500">0</text>925+<text x="349.0" y="463.84" fill="currentColor" font-weight="500">1</text>926+<text x="371.0" y="463.84" fill="currentColor" font-weight="500">0</text>927+<text x="41.0" y="485.84" fill="currentColor" font-weight="500">0</text>928+<text x="63.0" y="485.84" fill="currentColor" font-weight="500">1</text>929+<text x="85.0" y="485.84" fill="currentColor" font-weight="500">1</text>930+<text x="107.0" y="485.84" fill="currentColor" font-weight="500">0</text>931+<text x="129.0" y="485.84" fill="currentColor" font-weight="500">1</text>932+<text x="151.0" y="485.84" fill="currentColor" font-weight="500">1</text>933+<text x="173.0" y="485.84" fill="currentColor" font-weight="500">0</text>934+<text x="195.0" y="485.84" fill="currentColor" font-weight="500">1</text>935+<text x="217.0" y="485.84" fill="currentColor" font-weight="500">1</text>936+<text x="239.0" y="485.84" fill="currentColor" font-weight="500">0</text>937+<text x="261.0" y="485.84" fill="currentColor" font-weight="500">1</text>938+<text x="283.0" y="485.84" fill="currentColor" font-weight="500">1</text>939+<text x="305.0" y="485.84" fill="currentColor" font-weight="500">0</text>940+<text x="327.0" y="485.84" fill="currentColor" font-weight="500">1</text>941+<text x="349.0" y="485.84" fill="currentColor" font-weight="500">0</text>942+<text x="371.0" y="485.84" fill="currentColor" font-weight="500">1</text>943+<text x="393.0" y="485.84" fill="currentColor">0</text>944+<text x="41.0" y="507.84" fill="currentColor" font-weight="500">1</text>945+<text x="63.0" y="507.84" fill="currentColor" font-weight="500">0</text>946+<text x="85.0" y="507.84" fill="currentColor" font-weight="500">1</text>947+<text x="107.0" y="507.84" fill="currentColor" font-weight="500">0</text>948+<text x="129.0" y="507.84" fill="currentColor" font-weight="500">1</text>949+<text x="151.0" y="507.84" fill="currentColor" font-weight="500">0</text>950+<text x="173.0" y="507.84" fill="currentColor" font-weight="500">1</text>951+<text x="195.0" y="507.84" fill="currentColor" font-weight="500">0</text>952+<text x="217.0" y="507.84" fill="currentColor" font-weight="500">0</text>953+<text x="239.0" y="507.84" fill="currentColor" font-weight="500">1</text>954+<text x="261.0" y="507.84" fill="currentColor" font-weight="500">1</text>955+<text x="283.0" y="507.84" fill="currentColor" font-weight="500">0</text>956+<text x="305.0" y="507.84" fill="currentColor" font-weight="500">0</text>957+<text x="327.0" y="507.84" fill="currentColor" font-weight="500">0</text>958+<text x="349.0" y="507.84" fill="currentColor" font-weight="500">1</text>959+<text x="371.0" y="507.84" fill="currentColor" font-weight="500">1</text>960+<text x="415.0" y="507.84" fill="currentColor">0</text>961+<text x="437.0" y="507.84" fill="currentColor">1</text>962+<rect x="228" y="228" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>963+<rect x="30" y="294" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>964+<rect x="162" y="294" width="88" height="88" fill="none" stroke="var(--t0)" stroke-width="1.6" stroke-dasharray="4 3"/>965+<rect x="228" y="294" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>966+<rect x="294" y="294" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>967+<rect x="30" y="360" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>968+<rect x="96" y="360" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>969+<rect x="162" y="360" width="88" height="88" fill="none" stroke="var(--t3)" stroke-width="1.6"/>970+<rect x="228" y="360" width="88" height="88" fill="none" stroke="var(--t4)" stroke-width="1.6"/>971+<rect x="294" y="360" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>972+<rect x="30" y="426" width="88" height="88" fill="none" stroke="var(--t4)" stroke-width="1.6"/>973+<rect x="96" y="426" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6"/>974+<rect x="162" y="426" width="88" height="88" fill="none" stroke="var(--t6)" stroke-width="1.6"/>975+<rect x="228" y="426" width="88" height="88" fill="none" stroke="var(--t0)" stroke-width="1.6"/>976+<rect x="294" y="426" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>977+<rect x="360" y="426" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>978+</g>979+<g font-family="IBM Plex Sans, Arial, sans-serif" font-size="13" fill="currentColor">980+<rect x="564" y="50" width="18" height="18" fill="var(--t3)" fill-opacity="0.62" stroke="var(--t3)" stroke-width="1.6"/>981+<text x="604" y="64" font-weight="500">Solved tile</text>982+<text x="604" y="82" font-size="12" fill="var(--muted)">every cell committed and correct; all 16 values visible</text>983+<text x="604" y="98" font-size="12" fill="var(--muted)">its tint at full strength, solid outline</text>984+<rect x="564" y="126" width="18" height="18" fill="var(--t0)" fill-opacity="0.34" stroke="var(--t0)" stroke-width="1.6" stroke-dasharray="4 3"/>985+<text x="604" y="140" font-weight="500">Frontier tile</text>986+<text x="604" y="158" font-size="12" fill="var(--muted)">touches a solved tile; the only place reveal() is accepted</text>987+<text x="604" y="174" font-size="12" fill="var(--muted)">shows its givens plus the line it shares with the solved tile</text>988+<text x="604" y="190" font-size="12" fill="var(--muted)">alone it has m solutions; the shared line is what pins it</text>989+<text x="604" y="206" font-size="12" fill="var(--muted)">lighter tint, dashed outline</text>990+<rect x="564" y="234" width="18" height="18" fill="var(--t5)" fill-opacity="0.10" stroke="var(--rule)" stroke-width="0.6"/>991+<text x="604" y="248" font-weight="500">Hidden tile</text>992+<text x="604" y="266" font-size="12" fill="var(--muted)">nothing revealed; never in the agent's context</text>993+<text x="604" y="282" font-size="12" fill="var(--muted)">faintest tint, no outline</text>994+<rect x="564" y="310" width="9" height="18" fill="var(--t3)" fill-opacity="0.62"/>995+<rect x="573" y="310" width="9" height="18" fill="color-mix(in oklch, var(--t3) 50%, var(--t0))" fill-opacity="0.62"/>996+<text x="604" y="324" font-weight="500">Seam</text>997+<text x="604" y="342" font-size="12" fill="var(--muted)">tiles overlap by one cell: that line belongs to both</text>998+<text x="604" y="358" font-size="12" fill="var(--muted)">its colour is the mean of both hues at the same lightness</text>999+<text x="604" y="374" font-size="12" fill="var(--muted)">opacity never stacks, so corners do not go brighter</text>1000+<text x="604" y="390" font-size="12" fill="var(--muted)">no two touching tiles share a hue: 7 hues, (tx + 3ty) mod 7</text>1001+<text x="604" y="406" font-size="12" fill="var(--muted)">pitch is n-1: a 7x7 mosaic of 4x4 tiles is 22x22 cells</text>1002+<text x="604" y="448" font-weight="500">Scale</text>1003+<text x="604" y="466" font-size="12" fill="var(--muted)">X is any value in 2..15; this figure is X=7, n=4, seed 7</text>1004+<text x="604" y="482" font-size="12" fill="var(--muted)">9 solved after 9 frontier steps from a seed tile</text>1005+<text x="604" y="498" font-size="12" fill="var(--muted)">the layout is never fixed: seed tile and wavefront come from the run</text>1006+</g></svg>1007+1008+1009+1010+1011+ <figcaption>Generated from a real mosaic (docs/mock-mosaic.py, seed 7, X=7, n=4, 9 steps): every tile window satisfies Takuzu on its own, and neighbours overlap by one cell. The solved region is grown from a seed tile by frontier picks, not placed; X is any value in 2..15 and the same script renders all of them. Each tile has its own tint; a shared line shows both tints combined. A solver only ever sees frontier tiles, each under-determined alone; where to expand, and how much to commit before a shared line resolves, is the agent's problem and the thing the analyzer fingerprints.</figcaption>1012+ </figure>1013+ </section>1014+1015+ <section>1016+ <h2>Events</h2>1017+ <div class="wrap">1018+ <table>1019+ <thead><tr><th>Kind</th><th>Signed by</th><th>Carries</th><th>Why this shape</th></tr></thead>1020+ <tbody>1021+ <tr><td class="k">manifest</td><td>referee</td><td>seed commit, X, n, m, k, rules, config tags, agent npub</td><td>param-replaceable on <span class="mono">d=game</span>; tags are the query language for the dataset</td></tr>1022+ <tr><td class="k">challenge</td><td>referee</td><td>seed commit + board params, no agent</td><td>many agents play one board — the paired trial</td></tr>1023+ <tr><td class="k">batch</td><td>referee</td><td>reveal or commit resolution, delta-coded, forced/guess split, <span class="mono">#tile</span> tags</td><td>regular event; spectators filter by tile for a viewport</td></tr>1024+ <tr><td class="k">board</td><td>referee</td><td>optional compressed snapshot at <span class="mono">seq</span></td><td>skips the refold for late joiners; ~30 KB at 224²</td></tr>1025+ <tr><td class="k">seed reveal</td><td>referee</td><td>seed, nonce</td><td>turns every spectator into a verifier</td></tr>1026+ <tr><td class="k">analysis</td><td>analyzer</td><td>fingerprints <span class="mono">e=game</span>; leaderboards as replaceable</td><td>derived, rebuildable, separately signed</td></tr>1027+ <tr><td class="k">intent</td><td>agent</td><td>stated reasoning per batch</td><td>the richest behavioural signal; Blossom if long</td></tr>1028+ </tbody>1029+ </table>1030+ </div>1031+ </section>1032+1033+ <section>1034+ <h2>Knobs</h2>1035+ <ul>1036+ <li><strong>Tile size n</strong> (6–12), <strong>mosaic X</strong>, <strong>multiplicity m</strong> per tile, <strong>coupling depth k</strong> the generator certifies.</li>1037+ <li><strong>Couplings on/off:</strong> shared seams, rules across seams, band uniqueness, seam clues.</li>1038+ <li><strong>Reveal cost</strong> and whether unforced commits are rejected, penalised, or merely counted.</li>1039+ <li><strong>Per-agent config tags</strong> — model, batch size, code use, initial reveal — so the relay answers "which configs explore badly" with one filter.</li>1040+ </ul>1041+ </section>1042+</main>@@ -0,0 +1,185 @@
1+#!/usr/bin/env python32+"""Generate the 'what the agent can see' figure from a real overlapping Takuzu mosaic.3+4+X by X tiles of n by n cells, overlap-by-one seams (pitch n-1). Every tile5+window satisfies Takuzu on its own: balanced rows/cols, no three in a row,6+distinct rows, distinct cols. Output is an inline SVG fragment.7+"""8+import random, sys9+10+# usage: mock-mosaic.py [seed] [X] [n] [steps]11+# X is tiles per side and must work for any value in 2..15; nothing below assumes a size.12+SEED = int(sys.argv[1]) if len(sys.argv) > 1 else 713+X = int(sys.argv[2]) if len(sys.argv) > 2 else 714+N = int(sys.argv[3]) if len(sys.argv) > 3 else 4 # tile size (mock scale; real runs use n=8)15+STEPS = int(sys.argv[4]) if len(sys.argv) > 4 else 9 # solved tiles after this many frontier expansions16+assert 2 <= X <= 15 and N % 2 == 0 and 4 <= N <= 1217+P = N - 1 # pitch18+G = X * P + 1 # global grid size19+rng = random.Random(SEED)20+21+grid = [[None] * G for _ in range(G)]22+23+def windows_of(x, y):24+ for ty in range(X):25+ for tx in range(X):26+ ox, oy = tx * P, ty * P27+ if ox <= x < ox + N and oy <= y < oy + N:28+ yield ox, oy29+30+def line_ok(vals):31+ filled = [v for v in vals if v is not None]32+ if filled.count(0) > N // 2 or filled.count(1) > N // 2:33+ return False34+ for i in range(len(vals) - 2):35+ a, b, c = vals[i:i + 3]36+ if a is not None and a == b == c:37+ return False38+ return True39+40+def window_ok(ox, oy):41+ rows = [[grid[oy + r][ox + c] for c in range(N)] for r in range(N)]42+ cols = [[grid[oy + r][ox + c] for r in range(N)] for c in range(N)]43+ for ln in rows + cols:44+ if not line_ok(ln):45+ return False46+ full_rows = [tuple(r) for r in rows if None not in r]47+ if len(full_rows) != len(set(full_rows)):48+ return False49+ full_cols = [tuple(c) for c in cols if None not in c]50+ if len(full_cols) != len(set(full_cols)):51+ return False52+ return True53+54+def solve(i=0):55+ if i == G * G:56+ return True57+ y, x = divmod(i, G)58+ vals = [0, 1]59+ rng.shuffle(vals)60+ for v in vals:61+ grid[y][x] = v62+ if all(window_ok(ox, oy) for ox, oy in windows_of(x, y)) and solve(i + 1):63+ return True64+ grid[y][x] = None65+ return False66+67+sys.setrecursionlimit(10000)68+assert solve(), "no mosaic for this seed"69+70+# status per tile: no fixed layout. The seed tile comes from the seed, and the71+# solved region grows by picking a frontier tile per step, exactly as a run would.72+def neighbours(t):73+ tx, ty = t74+ for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):75+ u = (tx + dx, ty + dy)76+ if 0 <= u[0] < X and 0 <= u[1] < X:77+ yield u78+solved = {(rng.randrange(X), rng.randrange(X))}79+for _ in range(min(STEPS, X * X) - 1):80+ fr = sorted({u for t in solved for u in neighbours(t)} - solved)81+ if not fr:82+ break83+ solved.add(rng.choice(fr))84+frontier = {u for t in solved for u in neighbours(t)} - solved85+86+def tile_cells(tx, ty):87+ return {(tx * P + cx, ty * P + cy) for cy in range(N) for cx in range(N)}88+89+solved_cells = set().union(*(tile_cells(*t) for t in solved))90+# givens on frontier tiles: ~40% of cells not already known from a solved neighbour91+given_cells = set()92+for t in sorted(frontier):93+ cand = sorted(tile_cells(*t) - solved_cells)94+ rng.shuffle(cand)95+ given_cells |= set(cand[: max(2, len(cand) * 2 // 5)])96+seam_cells = set()97+for t in frontier:98+ seam_cells |= tile_cells(*t) & solved_cells99+100+CELL, M = 22, 30101+W = H = G * CELL + 2 * M102+HUES = 7103+def hue(tx, ty):104+ # (tx + 3*ty) mod 7: every 8-neighbour differs, so no two tiles that share a cell share a hue105+ return (tx + 3 * ty) % HUES106+ALPHA = {"solved": 0.62, "frontier": 0.34, "hidden": 0.10}107+def status(t):108+ return "solved" if t in solved else "frontier" if t in frontier else "hidden"109+110+out = []111+out.append(f'<svg viewBox="0 0 {W + 520} {max(H, 420)}" role="img" aria-label="A {X} by {X} mosaic of {N} by {N} Takuzu tiles that overlap by one cell. Each tile has its own semi-transparent tint; cells shared by two tiles show both tints combined. {len(solved)} solved tiles, grown from a seed tile by frontier expansion, show every 0 and 1. The {len(frontier)} frontier tiles around them show only their givens plus the line they share with a solved tile. The remaining tiles are hidden.">')112+out.append('<g font-family="IBM Plex Mono, monospace" font-size="12" text-anchor="middle">')113+out.append(f'<rect x="{M}" y="{M}" width="{G * CELL}" height="{G * CELL}" fill="var(--panel)"/>')114+# one rect per cell, coloured by the mean of its owners' hues at a fixed115+# lightness. Overlaps change hue, never lightness or opacity: no pyramid.116+def owners(x, y):117+ return [(ox // P, oy // P) for ox, oy in windows_of(x, y)]118+def mix(hs):119+ # nested equal-weight color-mix in oklch; L stays flat because every token shares an L120+ if len(hs) == 1:121+ return f"var(--t{hs[0]})"122+ return f"color-mix(in oklch, {mix(hs[:-1])} {100 - 100 // len(hs)}%, var(--t{hs[-1]}))"123+RANK = {"hidden": 0, "frontier": 1, "solved": 2}124+for y in range(G):125+ for x in range(G):126+ ts = owners(x, y)127+ st = max((status(t) for t in ts), key=RANK.get)128+ fill = mix([hue(*t) for t in ts])129+ out.append(f'<rect x="{M + x * CELL}" y="{M + y * CELL}" width="{CELL}" height="{CELL}" fill="{fill}" fill-opacity="{ALPHA[st]}"/>')130+# cell grid lines131+out.append('<g stroke="var(--rule)" stroke-width="0.6">')132+for i in range(G + 1):133+ out.append(f'<line x1="{M}" y1="{M + i * CELL}" x2="{M + G * CELL}" y2="{M + i * CELL}"/>')134+ out.append(f'<line x1="{M + i * CELL}" y1="{M}" x2="{M + i * CELL}" y2="{M + G * CELL}"/>')135+out.append('</g>')136+# glyphs: solved cells and frontier givens137+for y in range(G):138+ for x in range(G):139+ v = grid[y][x]140+ if (x, y) in solved_cells:141+ weight = ' font-weight="500"'142+ elif (x, y) in given_cells:143+ weight = ''144+ else:145+ continue146+ out.append(f'<text x="{M + x * CELL + CELL / 2}" y="{M + y * CELL + CELL * 0.72}" fill="currentColor"{weight}>{v}</text>')147+# tile outlines in the tile's own hue; hidden tiles get none148+for ty in range(X):149+ for tx in range(X):150+ st = status((tx, ty))151+ if st == "hidden":152+ continue153+ dash = '' if st == "solved" else ' stroke-dasharray="4 3"'154+ out.append(f'<rect x="{M + tx * P * CELL}" y="{M + ty * P * CELL}" width="{N * CELL}" height="{N * CELL}" fill="none" stroke="var(--t{hue(tx, ty)})" stroke-width="1.6"{dash}/>')155+out.append('</g>')156+157+# legend158+LX = W + 20159+def sw(y, kind):160+ if kind == "solved":161+ out.append(f'<rect x="{LX}" y="{y}" width="18" height="18" fill="var(--t3)" fill-opacity="0.62" stroke="var(--t3)" stroke-width="1.6"/>')162+ elif kind == "frontier":163+ out.append(f'<rect x="{LX}" y="{y}" width="18" height="18" fill="var(--t0)" fill-opacity="0.34" stroke="var(--t0)" stroke-width="1.6" stroke-dasharray="4 3"/>')164+ elif kind == "hidden":165+ out.append(f'<rect x="{LX}" y="{y}" width="18" height="18" fill="var(--t5)" fill-opacity="0.10" stroke="var(--rule)" stroke-width="0.6"/>')166+ elif kind == "seam":167+ out.append(f'<rect x="{LX}" y="{y}" width="9" height="18" fill="var(--t3)" fill-opacity="0.62"/>')168+ out.append(f'<rect x="{LX + 9}" y="{y}" width="9" height="18" fill="color-mix(in oklch, var(--t3) 50%, var(--t0))" fill-opacity="0.62"/>')169+out.append('<g font-family="IBM Plex Sans, Arial, sans-serif" font-size="13" fill="currentColor">')170+y = 50171+for kind, title, lines in [172+ ("solved", "Solved tile", ["every cell committed and correct; all 16 values visible", "its tint at full strength, solid outline"]),173+ ("frontier", "Frontier tile", ["touches a solved tile; the only place reveal() is accepted", "shows its givens plus the line it shares with the solved tile", "alone it has m solutions; the shared line is what pins it", "lighter tint, dashed outline"]),174+ ("hidden", "Hidden tile", ["nothing revealed; never in the agent's context", "faintest tint, no outline"]),175+ ("seam", "Seam", ["tiles overlap by one cell: that line belongs to both", "its colour is the mean of both hues at the same lightness", "opacity never stacks, so corners do not go brighter", "no two touching tiles share a hue: 7 hues, (tx + 3ty) mod 7", f"pitch is n-1: a {X}x{X} mosaic of {N}x{N} tiles is {G}x{G} cells"]),176+ (None, "Scale", [f"X is any value in 2..15; this figure is X={X}, n={N}, seed {SEED}", f"{len(solved)} solved after {len(solved)} frontier steps from a seed tile", "the layout is never fixed: seed tile and wavefront come from the run"]),177+]:178+ if kind:179+ sw(y, kind)180+ out.append(f'<text x="{LX + 40}" y="{y + 14}" font-weight="500">{title}</text>')181+ for i, ln in enumerate(lines):182+ out.append(f'<text x="{LX + 40}" y="{y + 32 + i * 16}" font-size="12" fill="var(--muted)">{ln}</text>')183+ y += 44 + 16 * len(lines)184+out.append('</g></svg>')185+print("\n".join(out))@@ -0,0 +1,713 @@
1+<svg viewBox="0 0 1064 544" role="img" aria-label="A 7 by 7 mosaic of 4 by 4 Takuzu tiles that overlap by one cell. Each tile has its own semi-transparent tint; cells shared by two tiles show both tints combined. 9 solved tiles, grown from a seed tile by frontier expansion, show every 0 and 1. The 7 frontier tiles around them show only their givens plus the line they share with a solved tile. The remaining tiles are hidden.">2+<g font-family="IBM Plex Mono, monospace" font-size="12" text-anchor="middle">3+<rect x="30" y="30" width="484" height="484" fill="var(--panel)"/>4+<rect x="30" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>5+<rect x="52" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>6+<rect x="74" y="30" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>7+<rect x="96" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>8+<rect x="118" y="30" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>9+<rect x="140" y="30" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>10+<rect x="162" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>11+<rect x="184" y="30" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>12+<rect x="206" y="30" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>13+<rect x="228" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>14+<rect x="250" y="30" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>15+<rect x="272" y="30" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>16+<rect x="294" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>17+<rect x="316" y="30" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>18+<rect x="338" y="30" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>19+<rect x="360" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>20+<rect x="382" y="30" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>21+<rect x="404" y="30" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>22+<rect x="426" y="30" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>23+<rect x="448" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>24+<rect x="470" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>25+<rect x="492" y="30" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>26+<rect x="30" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>27+<rect x="52" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>28+<rect x="74" y="52" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>29+<rect x="96" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>30+<rect x="118" y="52" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>31+<rect x="140" y="52" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>32+<rect x="162" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>33+<rect x="184" y="52" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>34+<rect x="206" y="52" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>35+<rect x="228" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>36+<rect x="250" y="52" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>37+<rect x="272" y="52" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>38+<rect x="294" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>39+<rect x="316" y="52" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>40+<rect x="338" y="52" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>41+<rect x="360" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>42+<rect x="382" y="52" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>43+<rect x="404" y="52" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>44+<rect x="426" y="52" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>45+<rect x="448" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>46+<rect x="470" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>47+<rect x="492" y="52" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>48+<rect x="30" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>49+<rect x="52" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>50+<rect x="74" y="74" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>51+<rect x="96" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>52+<rect x="118" y="74" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>53+<rect x="140" y="74" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>54+<rect x="162" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>55+<rect x="184" y="74" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>56+<rect x="206" y="74" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>57+<rect x="228" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>58+<rect x="250" y="74" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>59+<rect x="272" y="74" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>60+<rect x="294" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>61+<rect x="316" y="74" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>62+<rect x="338" y="74" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>63+<rect x="360" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>64+<rect x="382" y="74" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>65+<rect x="404" y="74" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>66+<rect x="426" y="74" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>67+<rect x="448" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>68+<rect x="470" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>69+<rect x="492" y="74" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>70+<rect x="30" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>71+<rect x="52" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>72+<rect x="74" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>73+<rect x="96" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>74+<rect x="118" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>75+<rect x="140" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>76+<rect x="162" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.1"/>77+<rect x="184" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>78+<rect x="206" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>79+<rect x="228" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.1"/>80+<rect x="250" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>81+<rect x="272" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>82+<rect x="294" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>83+<rect x="316" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>84+<rect x="338" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>85+<rect x="360" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>86+<rect x="382" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>87+<rect x="404" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>88+<rect x="426" y="96" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.1"/>89+<rect x="448" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>90+<rect x="470" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>91+<rect x="492" y="96" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>92+<rect x="30" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>93+<rect x="52" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>94+<rect x="74" y="118" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>95+<rect x="96" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>96+<rect x="118" y="118" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>97+<rect x="140" y="118" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>98+<rect x="162" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>99+<rect x="184" y="118" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>100+<rect x="206" y="118" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>101+<rect x="228" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>102+<rect x="250" y="118" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>103+<rect x="272" y="118" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>104+<rect x="294" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>105+<rect x="316" y="118" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>106+<rect x="338" y="118" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>107+<rect x="360" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>108+<rect x="382" y="118" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>109+<rect x="404" y="118" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>110+<rect x="426" y="118" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>111+<rect x="448" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>112+<rect x="470" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>113+<rect x="492" y="118" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>114+<rect x="30" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>115+<rect x="52" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>116+<rect x="74" y="140" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>117+<rect x="96" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>118+<rect x="118" y="140" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>119+<rect x="140" y="140" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>120+<rect x="162" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>121+<rect x="184" y="140" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>122+<rect x="206" y="140" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>123+<rect x="228" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.1"/>124+<rect x="250" y="140" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>125+<rect x="272" y="140" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>126+<rect x="294" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>127+<rect x="316" y="140" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>128+<rect x="338" y="140" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>129+<rect x="360" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>130+<rect x="382" y="140" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>131+<rect x="404" y="140" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>132+<rect x="426" y="140" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>133+<rect x="448" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>134+<rect x="470" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>135+<rect x="492" y="140" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>136+<rect x="30" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>137+<rect x="52" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>138+<rect x="74" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>139+<rect x="96" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>140+<rect x="118" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>141+<rect x="140" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>142+<rect x="162" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>143+<rect x="184" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>144+<rect x="206" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>145+<rect x="228" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.1"/>146+<rect x="250" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>147+<rect x="272" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>148+<rect x="294" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.1"/>149+<rect x="316" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>150+<rect x="338" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>151+<rect x="360" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>152+<rect x="382" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>153+<rect x="404" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>154+<rect x="426" y="162" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.1"/>155+<rect x="448" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>156+<rect x="470" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>157+<rect x="492" y="162" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.1"/>158+<rect x="30" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>159+<rect x="52" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>160+<rect x="74" y="184" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>161+<rect x="96" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>162+<rect x="118" y="184" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>163+<rect x="140" y="184" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>164+<rect x="162" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>165+<rect x="184" y="184" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>166+<rect x="206" y="184" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>167+<rect x="228" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>168+<rect x="250" y="184" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>169+<rect x="272" y="184" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>170+<rect x="294" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>171+<rect x="316" y="184" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>172+<rect x="338" y="184" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>173+<rect x="360" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>174+<rect x="382" y="184" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>175+<rect x="404" y="184" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>176+<rect x="426" y="184" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>177+<rect x="448" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>178+<rect x="470" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>179+<rect x="492" y="184" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>180+<rect x="30" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>181+<rect x="52" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>182+<rect x="74" y="206" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>183+<rect x="96" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>184+<rect x="118" y="206" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>185+<rect x="140" y="206" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>186+<rect x="162" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>187+<rect x="184" y="206" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>188+<rect x="206" y="206" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>189+<rect x="228" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.1"/>190+<rect x="250" y="206" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>191+<rect x="272" y="206" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>192+<rect x="294" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>193+<rect x="316" y="206" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>194+<rect x="338" y="206" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>195+<rect x="360" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>196+<rect x="382" y="206" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>197+<rect x="404" y="206" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>198+<rect x="426" y="206" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.1"/>199+<rect x="448" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>200+<rect x="470" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>201+<rect x="492" y="206" width="22" height="22" fill="var(--t5)" fill-opacity="0.1"/>202+<rect x="30" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>203+<rect x="52" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>204+<rect x="74" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.1"/>205+<rect x="96" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.1"/>206+<rect x="118" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>207+<rect x="140" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>208+<rect x="162" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>209+<rect x="184" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>210+<rect x="206" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>211+<rect x="228" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.34"/>212+<rect x="250" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>213+<rect x="272" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>214+<rect x="294" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>215+<rect x="316" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>216+<rect x="338" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>217+<rect x="360" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>218+<rect x="382" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>219+<rect x="404" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>220+<rect x="426" y="228" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.1"/>221+<rect x="448" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>222+<rect x="470" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>223+<rect x="492" y="228" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.1"/>224+<rect x="30" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>225+<rect x="52" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>226+<rect x="74" y="250" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>227+<rect x="96" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>228+<rect x="118" y="250" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>229+<rect x="140" y="250" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>230+<rect x="162" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>231+<rect x="184" y="250" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>232+<rect x="206" y="250" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>233+<rect x="228" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.34"/>234+<rect x="250" y="250" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>235+<rect x="272" y="250" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>236+<rect x="294" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>237+<rect x="316" y="250" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>238+<rect x="338" y="250" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>239+<rect x="360" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>240+<rect x="382" y="250" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>241+<rect x="404" y="250" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>242+<rect x="426" y="250" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>243+<rect x="448" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>244+<rect x="470" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>245+<rect x="492" y="250" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>246+<rect x="30" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>247+<rect x="52" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>248+<rect x="74" y="272" width="22" height="22" fill="var(--t2)" fill-opacity="0.1"/>249+<rect x="96" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.1"/>250+<rect x="118" y="272" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>251+<rect x="140" y="272" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>252+<rect x="162" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>253+<rect x="184" y="272" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>254+<rect x="206" y="272" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>255+<rect x="228" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.34"/>256+<rect x="250" y="272" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>257+<rect x="272" y="272" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>258+<rect x="294" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>259+<rect x="316" y="272" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>260+<rect x="338" y="272" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>261+<rect x="360" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>262+<rect x="382" y="272" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>263+<rect x="404" y="272" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>264+<rect x="426" y="272" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.1"/>265+<rect x="448" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>266+<rect x="470" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>267+<rect x="492" y="272" width="22" height="22" fill="var(--t1)" fill-opacity="0.1"/>268+<rect x="30" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>269+<rect x="52" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>270+<rect x="74" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>271+<rect x="96" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>272+<rect x="118" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>273+<rect x="140" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>274+<rect x="162" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.34"/>275+<rect x="184" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.34"/>276+<rect x="206" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.34"/>277+<rect x="228" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.62"/>278+<rect x="250" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>279+<rect x="272" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>280+<rect x="294" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>281+<rect x="316" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>282+<rect x="338" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>283+<rect x="360" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.34"/>284+<rect x="382" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>285+<rect x="404" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>286+<rect x="426" y="294" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.1"/>287+<rect x="448" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>288+<rect x="470" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>289+<rect x="492" y="294" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.1"/>290+<rect x="30" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>291+<rect x="52" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>292+<rect x="74" y="316" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>293+<rect x="96" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>294+<rect x="118" y="316" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>295+<rect x="140" y="316" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>296+<rect x="162" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.34"/>297+<rect x="184" y="316" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>298+<rect x="206" y="316" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>299+<rect x="228" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>300+<rect x="250" y="316" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>301+<rect x="272" y="316" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>302+<rect x="294" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>303+<rect x="316" y="316" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>304+<rect x="338" y="316" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>305+<rect x="360" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>306+<rect x="382" y="316" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>307+<rect x="404" y="316" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>308+<rect x="426" y="316" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>309+<rect x="448" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>310+<rect x="470" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>311+<rect x="492" y="316" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>312+<rect x="30" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>313+<rect x="52" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>314+<rect x="74" y="338" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>315+<rect x="96" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>316+<rect x="118" y="338" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>317+<rect x="140" y="338" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>318+<rect x="162" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.34"/>319+<rect x="184" y="338" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>320+<rect x="206" y="338" width="22" height="22" fill="var(--t0)" fill-opacity="0.34"/>321+<rect x="228" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>322+<rect x="250" y="338" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>323+<rect x="272" y="338" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>324+<rect x="294" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>325+<rect x="316" y="338" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>326+<rect x="338" y="338" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>327+<rect x="360" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>328+<rect x="382" y="338" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>329+<rect x="404" y="338" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>330+<rect x="426" y="338" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.1"/>331+<rect x="448" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>332+<rect x="470" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>333+<rect x="492" y="338" width="22" height="22" fill="var(--t4)" fill-opacity="0.1"/>334+<rect x="30" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>335+<rect x="52" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>336+<rect x="74" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>337+<rect x="96" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>338+<rect x="118" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>339+<rect x="140" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>340+<rect x="162" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.62"/>341+<rect x="184" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.62"/>342+<rect x="206" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.62"/>343+<rect x="228" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t0) 50%, var(--t1)) 67%, var(--t3)) 75%, var(--t4))" fill-opacity="0.62"/>344+<rect x="250" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>345+<rect x="272" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>346+<rect x="294" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.62"/>347+<rect x="316" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>348+<rect x="338" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.34"/>349+<rect x="360" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.34"/>350+<rect x="382" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>351+<rect x="404" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.1"/>352+<rect x="426" y="360" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.1"/>353+<rect x="448" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>354+<rect x="470" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>355+<rect x="492" y="360" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.1"/>356+<rect x="30" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>357+<rect x="52" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>358+<rect x="74" y="382" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>359+<rect x="96" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>360+<rect x="118" y="382" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>361+<rect x="140" y="382" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>362+<rect x="162" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.62"/>363+<rect x="184" y="382" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>364+<rect x="206" y="382" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>365+<rect x="228" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.62"/>366+<rect x="250" y="382" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>367+<rect x="272" y="382" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>368+<rect x="294" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>369+<rect x="316" y="382" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>370+<rect x="338" y="382" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>371+<rect x="360" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>372+<rect x="382" y="382" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>373+<rect x="404" y="382" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>374+<rect x="426" y="382" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>375+<rect x="448" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>376+<rect x="470" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>377+<rect x="492" y="382" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>378+<rect x="30" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>379+<rect x="52" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>380+<rect x="74" y="404" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>381+<rect x="96" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>382+<rect x="118" y="404" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>383+<rect x="140" y="404" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>384+<rect x="162" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.62"/>385+<rect x="184" y="404" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>386+<rect x="206" y="404" width="22" height="22" fill="var(--t3)" fill-opacity="0.62"/>387+<rect x="228" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t4))" fill-opacity="0.62"/>388+<rect x="250" y="404" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>389+<rect x="272" y="404" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>390+<rect x="294" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>391+<rect x="316" y="404" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>392+<rect x="338" y="404" width="22" height="22" fill="var(--t5)" fill-opacity="0.34"/>393+<rect x="360" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.34"/>394+<rect x="382" y="404" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>395+<rect x="404" y="404" width="22" height="22" fill="var(--t6)" fill-opacity="0.1"/>396+<rect x="426" y="404" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.1"/>397+<rect x="448" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>398+<rect x="470" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>399+<rect x="492" y="404" width="22" height="22" fill="var(--t0)" fill-opacity="0.1"/>400+<rect x="30" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>401+<rect x="52" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>402+<rect x="74" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t4))" fill-opacity="0.62"/>403+<rect x="96" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t1) 50%, var(--t2)) 67%, var(--t4)) 75%, var(--t5))" fill-opacity="0.62"/>404+<rect x="118" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.62"/>405+<rect x="140" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t5))" fill-opacity="0.62"/>406+<rect x="162" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t2) 50%, var(--t3)) 67%, var(--t5)) 75%, var(--t6))" fill-opacity="0.62"/>407+<rect x="184" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.62"/>408+<rect x="206" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t3) 50%, var(--t6))" fill-opacity="0.62"/>409+<rect x="228" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t3) 50%, var(--t4)) 67%, var(--t6)) 75%, var(--t0))" fill-opacity="0.62"/>410+<rect x="250" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.62"/>411+<rect x="272" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t0))" fill-opacity="0.62"/>412+<rect x="294" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t4) 50%, var(--t5)) 67%, var(--t0)) 75%, var(--t1))" fill-opacity="0.62"/>413+<rect x="316" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>414+<rect x="338" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t1))" fill-opacity="0.62"/>415+<rect x="360" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t5) 50%, var(--t6)) 67%, var(--t1)) 75%, var(--t2))" fill-opacity="0.62"/>416+<rect x="382" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>417+<rect x="404" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t2))" fill-opacity="0.34"/>418+<rect x="426" y="426" width="22" height="22" fill="color-mix(in oklch, color-mix(in oklch, color-mix(in oklch, var(--t6) 50%, var(--t0)) 67%, var(--t2)) 75%, var(--t3))" fill-opacity="0.34"/>419+<rect x="448" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>420+<rect x="470" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>421+<rect x="492" y="426" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t3))" fill-opacity="0.1"/>422+<rect x="30" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>423+<rect x="52" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>424+<rect x="74" y="448" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>425+<rect x="96" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>426+<rect x="118" y="448" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>427+<rect x="140" y="448" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>428+<rect x="162" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>429+<rect x="184" y="448" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>430+<rect x="206" y="448" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>431+<rect x="228" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>432+<rect x="250" y="448" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>433+<rect x="272" y="448" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>434+<rect x="294" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>435+<rect x="316" y="448" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>436+<rect x="338" y="448" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>437+<rect x="360" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>438+<rect x="382" y="448" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>439+<rect x="404" y="448" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>440+<rect x="426" y="448" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>441+<rect x="448" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>442+<rect x="470" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>443+<rect x="492" y="448" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>444+<rect x="30" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>445+<rect x="52" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>446+<rect x="74" y="470" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>447+<rect x="96" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>448+<rect x="118" y="470" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>449+<rect x="140" y="470" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>450+<rect x="162" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>451+<rect x="184" y="470" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>452+<rect x="206" y="470" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>453+<rect x="228" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>454+<rect x="250" y="470" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>455+<rect x="272" y="470" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>456+<rect x="294" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>457+<rect x="316" y="470" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>458+<rect x="338" y="470" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>459+<rect x="360" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>460+<rect x="382" y="470" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>461+<rect x="404" y="470" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>462+<rect x="426" y="470" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>463+<rect x="448" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>464+<rect x="470" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>465+<rect x="492" y="470" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>466+<rect x="30" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>467+<rect x="52" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>468+<rect x="74" y="492" width="22" height="22" fill="var(--t4)" fill-opacity="0.62"/>469+<rect x="96" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t4) 50%, var(--t5))" fill-opacity="0.62"/>470+<rect x="118" y="492" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>471+<rect x="140" y="492" width="22" height="22" fill="var(--t5)" fill-opacity="0.62"/>472+<rect x="162" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t5) 50%, var(--t6))" fill-opacity="0.62"/>473+<rect x="184" y="492" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>474+<rect x="206" y="492" width="22" height="22" fill="var(--t6)" fill-opacity="0.62"/>475+<rect x="228" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t6) 50%, var(--t0))" fill-opacity="0.62"/>476+<rect x="250" y="492" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>477+<rect x="272" y="492" width="22" height="22" fill="var(--t0)" fill-opacity="0.62"/>478+<rect x="294" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t0) 50%, var(--t1))" fill-opacity="0.62"/>479+<rect x="316" y="492" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>480+<rect x="338" y="492" width="22" height="22" fill="var(--t1)" fill-opacity="0.62"/>481+<rect x="360" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t1) 50%, var(--t2))" fill-opacity="0.62"/>482+<rect x="382" y="492" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>483+<rect x="404" y="492" width="22" height="22" fill="var(--t2)" fill-opacity="0.34"/>484+<rect x="426" y="492" width="22" height="22" fill="color-mix(in oklch, var(--t2) 50%, var(--t3))" fill-opacity="0.34"/>485+<rect x="448" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>486+<rect x="470" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>487+<rect x="492" y="492" width="22" height="22" fill="var(--t3)" fill-opacity="0.1"/>488+<g stroke="var(--rule)" stroke-width="0.6">489+<line x1="30" y1="30" x2="514" y2="30"/>490+<line x1="30" y1="30" x2="30" y2="514"/>491+<line x1="30" y1="52" x2="514" y2="52"/>492+<line x1="52" y1="30" x2="52" y2="514"/>493+<line x1="30" y1="74" x2="514" y2="74"/>494+<line x1="74" y1="30" x2="74" y2="514"/>495+<line x1="30" y1="96" x2="514" y2="96"/>496+<line x1="96" y1="30" x2="96" y2="514"/>497+<line x1="30" y1="118" x2="514" y2="118"/>498+<line x1="118" y1="30" x2="118" y2="514"/>499+<line x1="30" y1="140" x2="514" y2="140"/>500+<line x1="140" y1="30" x2="140" y2="514"/>501+<line x1="30" y1="162" x2="514" y2="162"/>502+<line x1="162" y1="30" x2="162" y2="514"/>503+<line x1="30" y1="184" x2="514" y2="184"/>504+<line x1="184" y1="30" x2="184" y2="514"/>505+<line x1="30" y1="206" x2="514" y2="206"/>506+<line x1="206" y1="30" x2="206" y2="514"/>507+<line x1="30" y1="228" x2="514" y2="228"/>508+<line x1="228" y1="30" x2="228" y2="514"/>509+<line x1="30" y1="250" x2="514" y2="250"/>510+<line x1="250" y1="30" x2="250" y2="514"/>511+<line x1="30" y1="272" x2="514" y2="272"/>512+<line x1="272" y1="30" x2="272" y2="514"/>513+<line x1="30" y1="294" x2="514" y2="294"/>514+<line x1="294" y1="30" x2="294" y2="514"/>515+<line x1="30" y1="316" x2="514" y2="316"/>516+<line x1="316" y1="30" x2="316" y2="514"/>517+<line x1="30" y1="338" x2="514" y2="338"/>518+<line x1="338" y1="30" x2="338" y2="514"/>519+<line x1="30" y1="360" x2="514" y2="360"/>520+<line x1="360" y1="30" x2="360" y2="514"/>521+<line x1="30" y1="382" x2="514" y2="382"/>522+<line x1="382" y1="30" x2="382" y2="514"/>523+<line x1="30" y1="404" x2="514" y2="404"/>524+<line x1="404" y1="30" x2="404" y2="514"/>525+<line x1="30" y1="426" x2="514" y2="426"/>526+<line x1="426" y1="30" x2="426" y2="514"/>527+<line x1="30" y1="448" x2="514" y2="448"/>528+<line x1="448" y1="30" x2="448" y2="514"/>529+<line x1="30" y1="470" x2="514" y2="470"/>530+<line x1="470" y1="30" x2="470" y2="514"/>531+<line x1="30" y1="492" x2="514" y2="492"/>532+<line x1="492" y1="30" x2="492" y2="514"/>533+<line x1="30" y1="514" x2="514" y2="514"/>534+<line x1="514" y1="30" x2="514" y2="514"/>535+</g>536+<text x="239.0" y="243.84" fill="currentColor">0</text>537+<text x="283.0" y="243.84" fill="currentColor">1</text>538+<text x="305.0" y="265.84" fill="currentColor">0</text>539+<text x="283.0" y="287.84" fill="currentColor">0</text>540+<text x="41.0" y="309.84" fill="currentColor">0</text>541+<text x="85.0" y="309.84" fill="currentColor">0</text>542+<text x="107.0" y="309.84" fill="currentColor">1</text>543+<text x="217.0" y="309.84" fill="currentColor">0</text>544+<text x="239.0" y="309.84" fill="currentColor" font-weight="500">1</text>545+<text x="261.0" y="309.84" fill="currentColor" font-weight="500">0</text>546+<text x="283.0" y="309.84" fill="currentColor" font-weight="500">0</text>547+<text x="305.0" y="309.84" fill="currentColor" font-weight="500">1</text>548+<text x="349.0" y="309.84" fill="currentColor">0</text>549+<text x="173.0" y="331.84" fill="currentColor">1</text>550+<text x="195.0" y="331.84" fill="currentColor">1</text>551+<text x="239.0" y="331.84" fill="currentColor" font-weight="500">0</text>552+<text x="261.0" y="331.84" fill="currentColor" font-weight="500">0</text>553+<text x="283.0" y="331.84" fill="currentColor" font-weight="500">1</text>554+<text x="305.0" y="331.84" fill="currentColor" font-weight="500">1</text>555+<text x="85.0" y="353.84" fill="currentColor">1</text>556+<text x="239.0" y="353.84" fill="currentColor" font-weight="500">1</text>557+<text x="261.0" y="353.84" fill="currentColor" font-weight="500">1</text>558+<text x="283.0" y="353.84" fill="currentColor" font-weight="500">0</text>559+<text x="305.0" y="353.84" fill="currentColor" font-weight="500">0</text>560+<text x="327.0" y="353.84" fill="currentColor">1</text>561+<text x="349.0" y="353.84" fill="currentColor">1</text>562+<text x="371.0" y="353.84" fill="currentColor">0</text>563+<text x="41.0" y="375.84" fill="currentColor" font-weight="500">1</text>564+<text x="63.0" y="375.84" fill="currentColor" font-weight="500">0</text>565+<text x="85.0" y="375.84" fill="currentColor" font-weight="500">1</text>566+<text x="107.0" y="375.84" fill="currentColor" font-weight="500">0</text>567+<text x="173.0" y="375.84" fill="currentColor" font-weight="500">0</text>568+<text x="195.0" y="375.84" fill="currentColor" font-weight="500">1</text>569+<text x="217.0" y="375.84" fill="currentColor" font-weight="500">1</text>570+<text x="239.0" y="375.84" fill="currentColor" font-weight="500">0</text>571+<text x="261.0" y="375.84" fill="currentColor" font-weight="500">1</text>572+<text x="283.0" y="375.84" fill="currentColor" font-weight="500">1</text>573+<text x="305.0" y="375.84" fill="currentColor" font-weight="500">0</text>574+<text x="327.0" y="375.84" fill="currentColor">0</text>575+<text x="41.0" y="397.84" fill="currentColor" font-weight="500">0</text>576+<text x="63.0" y="397.84" fill="currentColor" font-weight="500">1</text>577+<text x="85.0" y="397.84" fill="currentColor" font-weight="500">1</text>578+<text x="107.0" y="397.84" fill="currentColor" font-weight="500">0</text>579+<text x="151.0" y="397.84" fill="currentColor">0</text>580+<text x="173.0" y="397.84" fill="currentColor" font-weight="500">1</text>581+<text x="195.0" y="397.84" fill="currentColor" font-weight="500">1</text>582+<text x="217.0" y="397.84" fill="currentColor" font-weight="500">0</text>583+<text x="239.0" y="397.84" fill="currentColor" font-weight="500">0</text>584+<text x="261.0" y="397.84" fill="currentColor" font-weight="500">0</text>585+<text x="283.0" y="397.84" fill="currentColor" font-weight="500">1</text>586+<text x="305.0" y="397.84" fill="currentColor" font-weight="500">1</text>587+<text x="371.0" y="397.84" fill="currentColor">0</text>588+<text x="41.0" y="419.84" fill="currentColor" font-weight="500">1</text>589+<text x="63.0" y="419.84" fill="currentColor" font-weight="500">0</text>590+<text x="85.0" y="419.84" fill="currentColor" font-weight="500">0</text>591+<text x="107.0" y="419.84" fill="currentColor" font-weight="500">1</text>592+<text x="129.0" y="419.84" fill="currentColor">0</text>593+<text x="173.0" y="419.84" fill="currentColor" font-weight="500">1</text>594+<text x="195.0" y="419.84" fill="currentColor" font-weight="500">0</text>595+<text x="217.0" y="419.84" fill="currentColor" font-weight="500">0</text>596+<text x="239.0" y="419.84" fill="currentColor" font-weight="500">1</text>597+<text x="261.0" y="419.84" fill="currentColor" font-weight="500">1</text>598+<text x="283.0" y="419.84" fill="currentColor" font-weight="500">0</text>599+<text x="305.0" y="419.84" fill="currentColor" font-weight="500">0</text>600+<text x="371.0" y="419.84" fill="currentColor">1</text>601+<text x="41.0" y="441.84" fill="currentColor" font-weight="500">0</text>602+<text x="63.0" y="441.84" fill="currentColor" font-weight="500">1</text>603+<text x="85.0" y="441.84" fill="currentColor" font-weight="500">0</text>604+<text x="107.0" y="441.84" fill="currentColor" font-weight="500">1</text>605+<text x="129.0" y="441.84" fill="currentColor" font-weight="500">0</text>606+<text x="151.0" y="441.84" fill="currentColor" font-weight="500">1</text>607+<text x="173.0" y="441.84" fill="currentColor" font-weight="500">0</text>608+<text x="195.0" y="441.84" fill="currentColor" font-weight="500">0</text>609+<text x="217.0" y="441.84" fill="currentColor" font-weight="500">1</text>610+<text x="239.0" y="441.84" fill="currentColor" font-weight="500">1</text>611+<text x="261.0" y="441.84" fill="currentColor" font-weight="500">0</text>612+<text x="283.0" y="441.84" fill="currentColor" font-weight="500">0</text>613+<text x="305.0" y="441.84" fill="currentColor" font-weight="500">1</text>614+<text x="327.0" y="441.84" fill="currentColor" font-weight="500">1</text>615+<text x="349.0" y="441.84" fill="currentColor" font-weight="500">0</text>616+<text x="371.0" y="441.84" fill="currentColor" font-weight="500">0</text>617+<text x="415.0" y="441.84" fill="currentColor">0</text>618+<text x="41.0" y="463.84" fill="currentColor" font-weight="500">1</text>619+<text x="63.0" y="463.84" fill="currentColor" font-weight="500">0</text>620+<text x="85.0" y="463.84" fill="currentColor" font-weight="500">0</text>621+<text x="107.0" y="463.84" fill="currentColor" font-weight="500">1</text>622+<text x="129.0" y="463.84" fill="currentColor" font-weight="500">0</text>623+<text x="151.0" y="463.84" fill="currentColor" font-weight="500">0</text>624+<text x="173.0" y="463.84" fill="currentColor" font-weight="500">1</text>625+<text x="195.0" y="463.84" fill="currentColor" font-weight="500">1</text>626+<text x="217.0" y="463.84" fill="currentColor" font-weight="500">0</text>627+<text x="239.0" y="463.84" fill="currentColor" font-weight="500">0</text>628+<text x="261.0" y="463.84" fill="currentColor" font-weight="500">0</text>629+<text x="283.0" y="463.84" fill="currentColor" font-weight="500">1</text>630+<text x="305.0" y="463.84" fill="currentColor" font-weight="500">1</text>631+<text x="327.0" y="463.84" fill="currentColor" font-weight="500">0</text>632+<text x="349.0" y="463.84" fill="currentColor" font-weight="500">1</text>633+<text x="371.0" y="463.84" fill="currentColor" font-weight="500">0</text>634+<text x="41.0" y="485.84" fill="currentColor" font-weight="500">0</text>635+<text x="63.0" y="485.84" fill="currentColor" font-weight="500">1</text>636+<text x="85.0" y="485.84" fill="currentColor" font-weight="500">1</text>637+<text x="107.0" y="485.84" fill="currentColor" font-weight="500">0</text>638+<text x="129.0" y="485.84" fill="currentColor" font-weight="500">1</text>639+<text x="151.0" y="485.84" fill="currentColor" font-weight="500">1</text>640+<text x="173.0" y="485.84" fill="currentColor" font-weight="500">0</text>641+<text x="195.0" y="485.84" fill="currentColor" font-weight="500">1</text>642+<text x="217.0" y="485.84" fill="currentColor" font-weight="500">1</text>643+<text x="239.0" y="485.84" fill="currentColor" font-weight="500">0</text>644+<text x="261.0" y="485.84" fill="currentColor" font-weight="500">1</text>645+<text x="283.0" y="485.84" fill="currentColor" font-weight="500">1</text>646+<text x="305.0" y="485.84" fill="currentColor" font-weight="500">0</text>647+<text x="327.0" y="485.84" fill="currentColor" font-weight="500">1</text>648+<text x="349.0" y="485.84" fill="currentColor" font-weight="500">0</text>649+<text x="371.0" y="485.84" fill="currentColor" font-weight="500">1</text>650+<text x="393.0" y="485.84" fill="currentColor">0</text>651+<text x="41.0" y="507.84" fill="currentColor" font-weight="500">1</text>652+<text x="63.0" y="507.84" fill="currentColor" font-weight="500">0</text>653+<text x="85.0" y="507.84" fill="currentColor" font-weight="500">1</text>654+<text x="107.0" y="507.84" fill="currentColor" font-weight="500">0</text>655+<text x="129.0" y="507.84" fill="currentColor" font-weight="500">1</text>656+<text x="151.0" y="507.84" fill="currentColor" font-weight="500">0</text>657+<text x="173.0" y="507.84" fill="currentColor" font-weight="500">1</text>658+<text x="195.0" y="507.84" fill="currentColor" font-weight="500">0</text>659+<text x="217.0" y="507.84" fill="currentColor" font-weight="500">0</text>660+<text x="239.0" y="507.84" fill="currentColor" font-weight="500">1</text>661+<text x="261.0" y="507.84" fill="currentColor" font-weight="500">1</text>662+<text x="283.0" y="507.84" fill="currentColor" font-weight="500">0</text>663+<text x="305.0" y="507.84" fill="currentColor" font-weight="500">0</text>664+<text x="327.0" y="507.84" fill="currentColor" font-weight="500">0</text>665+<text x="349.0" y="507.84" fill="currentColor" font-weight="500">1</text>666+<text x="371.0" y="507.84" fill="currentColor" font-weight="500">1</text>667+<text x="415.0" y="507.84" fill="currentColor">0</text>668+<text x="437.0" y="507.84" fill="currentColor">1</text>669+<rect x="228" y="228" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>670+<rect x="30" y="294" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>671+<rect x="162" y="294" width="88" height="88" fill="none" stroke="var(--t0)" stroke-width="1.6" stroke-dasharray="4 3"/>672+<rect x="228" y="294" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>673+<rect x="294" y="294" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>674+<rect x="30" y="360" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>675+<rect x="96" y="360" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>676+<rect x="162" y="360" width="88" height="88" fill="none" stroke="var(--t3)" stroke-width="1.6"/>677+<rect x="228" y="360" width="88" height="88" fill="none" stroke="var(--t4)" stroke-width="1.6"/>678+<rect x="294" y="360" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6" stroke-dasharray="4 3"/>679+<rect x="30" y="426" width="88" height="88" fill="none" stroke="var(--t4)" stroke-width="1.6"/>680+<rect x="96" y="426" width="88" height="88" fill="none" stroke="var(--t5)" stroke-width="1.6"/>681+<rect x="162" y="426" width="88" height="88" fill="none" stroke="var(--t6)" stroke-width="1.6"/>682+<rect x="228" y="426" width="88" height="88" fill="none" stroke="var(--t0)" stroke-width="1.6"/>683+<rect x="294" y="426" width="88" height="88" fill="none" stroke="var(--t1)" stroke-width="1.6"/>684+<rect x="360" y="426" width="88" height="88" fill="none" stroke="var(--t2)" stroke-width="1.6" stroke-dasharray="4 3"/>685+</g>686+<g font-family="IBM Plex Sans, Arial, sans-serif" font-size="13" fill="currentColor">687+<rect x="564" y="50" width="18" height="18" fill="var(--t3)" fill-opacity="0.62" stroke="var(--t3)" stroke-width="1.6"/>688+<text x="604" y="64" font-weight="500">Solved tile</text>689+<text x="604" y="82" font-size="12" fill="var(--muted)">every cell committed and correct; all 16 values visible</text>690+<text x="604" y="98" font-size="12" fill="var(--muted)">its tint at full strength, solid outline</text>691+<rect x="564" y="126" width="18" height="18" fill="var(--t0)" fill-opacity="0.34" stroke="var(--t0)" stroke-width="1.6" stroke-dasharray="4 3"/>692+<text x="604" y="140" font-weight="500">Frontier tile</text>693+<text x="604" y="158" font-size="12" fill="var(--muted)">touches a solved tile; the only place reveal() is accepted</text>694+<text x="604" y="174" font-size="12" fill="var(--muted)">shows its givens plus the line it shares with the solved tile</text>695+<text x="604" y="190" font-size="12" fill="var(--muted)">alone it has m solutions; the shared line is what pins it</text>696+<text x="604" y="206" font-size="12" fill="var(--muted)">lighter tint, dashed outline</text>697+<rect x="564" y="234" width="18" height="18" fill="var(--t5)" fill-opacity="0.10" stroke="var(--rule)" stroke-width="0.6"/>698+<text x="604" y="248" font-weight="500">Hidden tile</text>699+<text x="604" y="266" font-size="12" fill="var(--muted)">nothing revealed; never in the agent's context</text>700+<text x="604" y="282" font-size="12" fill="var(--muted)">faintest tint, no outline</text>701+<rect x="564" y="310" width="9" height="18" fill="var(--t3)" fill-opacity="0.62"/>702+<rect x="573" y="310" width="9" height="18" fill="color-mix(in oklch, var(--t3) 50%, var(--t0))" fill-opacity="0.62"/>703+<text x="604" y="324" font-weight="500">Seam</text>704+<text x="604" y="342" font-size="12" fill="var(--muted)">tiles overlap by one cell: that line belongs to both</text>705+<text x="604" y="358" font-size="12" fill="var(--muted)">its colour is the mean of both hues at the same lightness</text>706+<text x="604" y="374" font-size="12" fill="var(--muted)">opacity never stacks, so corners do not go brighter</text>707+<text x="604" y="390" font-size="12" fill="var(--muted)">no two touching tiles share a hue: 7 hues, (tx + 3ty) mod 7</text>708+<text x="604" y="406" font-size="12" fill="var(--muted)">pitch is n-1: a 7x7 mosaic of 4x4 tiles is 22x22 cells</text>709+<text x="604" y="448" font-weight="500">Scale</text>710+<text x="604" y="466" font-size="12" fill="var(--muted)">X is any value in 2..15; this figure is X=7, n=4, seed 7</text>711+<text x="604" y="482" font-size="12" fill="var(--muted)">9 solved after 9 frontier steps from a seed tile</text>712+<text x="604" y="498" font-size="12" fill="var(--muted)">the layout is never fixed: seed tile and wavefront come from the run</text>713+</g></svg>@@ -0,0 +1,245 @@
1+# Space filling and the tile library2+3+Design notes for phase 2. Two ideas that belong together: the daily board is4+a packing of square tiles of mixed size, and tiles come from a long-lived5+library that is generated locally and only stored and indexed in the cloud.6+7+## 1. Pitch space8+9+Tiles overlap by one cell, so a tile of side n occupies a square of side10+s = n-1 in "pitch space". With n in 6..16, s is in 5..15. In pitch space11+tiles are ordinary non-overlapping squares, seams are the shared borders,12+and the board of side G in cells is a square of side G-1 in pitch space13+(999 for G = 1000). Everything below is stated in pitch space.14+15+Useful arithmetic:16+17+- n is even, so pitch sides are odd: {5, 7, 9, 11, 13, 15}. Every odd18+ length >= 5 and every even length >= 10 is a sum of those (6 and 8 are19+ not, and neither is anything under 5). So a strip splits exactly into20+ allowed sub-bands unless its size is 1..4, 6 or 8, which is the whole21+ list of remainders a packer has to steer around.22+- A rectangle a x b can be cut into squares by the Euclidean algorithm23+ (repeatedly take the largest square). Sizes shrink toward gcd(a, b); when24+ a piece would fall under 5 it stops and that piece is a zone (below).25+- Tiling an integer rectangle with squares of side >= 2 is always possible26+ once both sides are >= 10 [1]. With the side floor raised to 5 and a cap27+ of 15 there is no such theorem; we do not need one because zones absorb28+ the remainder, but the amount of remainder is the quality metric of a29+ packer.30+- Deciding whether a given multiset of squares tiles a rectangle is31+ NP-complete [2]; guillotine (recursive straight cut) packings are the32+ tractable family and lose little for squares [3]. Everything proposed33+ here is guillotine or grown, never a search for an exact tiling.34+35+## 2. Packers36+37+Four candidate ways to choose the squares. All are seeded; the seed is the38+daily seed and the seed tile is drawn first so packers can favour it.39+40+**Bands (Mondrian).** Split the height into bands with heights drawn from41+5..15; fill each band left to right with squares of the band height; the42+last partial column of a band (width r < h) is cut by Euclid into smaller43+squares, remainders under 5 become zones. Simple, fast, zone area is44+bounded by roughly (number of bands) x 4 x 15 cells. Looks like a grid with45+uneven rows, which is honest but dull. Variant: sub-bands, where a band of46+height 15 sometimes holds two rows of 7 and 8, or three of 5, which breaks47+the row look.48+49+**Grown from the seed.** Place the seed tile, then repeatedly pick a free50+spot on the boundary of the placed region and drop the largest square that51+fits there (or a random size that fits, with a bias). This is the packing52+version of frontier expansion, so the layout has the same shape as a run:53+concentric, irregular, big tiles where there was room, small ones in the54+notches. Leftover notches become zones. Needs a boundary data structure55+(skyline or maximal free rectangles [4]); free-rectangle packers are56+standard for this and well understood.57+58+**Big first, then fill.** Draw a few large squares (13..15) at seeded59+positions on a coarse grid, then fill the gaps with a bands or Euclid pass.60+This is the packer that serves the library best (section 4): a large tile61+placed first has free edges, and the small tiles that fill around it only62+need to match one edge each, which is the cheap lookup.63+64+**Substitution.** A fixed recursive rule (a 15-square splits into a 9, a65+6 and three 5s, say) applied to a coarse grid. Deterministic, elegant, no66+zones at all if the rule closes, but the size distribution is fixed by the67+rule and the layout is self-similar, which an agent can learn. Keep as a68+knob, not the default.69+70+Recommendation: big-first-then-fill as the default because of the library,71+with grown-from-seed as the alternative layout when we want the map to72+read as the run's own shape. Bands is the fallback and the test fixture.73+74+## 3. What mixed sizes change in the engine and the site75+76+- The manifest lists tiles explicitly: `{id, x0, y0, n, hash}` plus zones77+ `{id, cells}`. `(tx, ty)` and a global `n` go away; phase 1's grid is the78+ special case where every tile has the same n and the list is regular.79+- Owners of a cell come from the tile list (an interval tree or a per-cell80+ owner index built once per manifest). Hues come from a greedy 7-colouring81+ of the tile adjacency graph (tiles sharing any cell), not from82+ `(tx + 3ty) mod 7`.83+- Seams become seam segments. A 15-tile abutting three 5-tiles has one84+ side split three ways. The generator's per-side `pins` become per-segment:85+ every alternative solution of a tile must differ on some seam segment,86+ and the CSP for global uniqueness runs over segments. The rules engine87+ already treats windows as arbitrary rectangles, so nothing changes there.88+- T-junctions replace corners. A cell where three or four tiles meet is89+ never planted and never a seam clue, same rule as today's corners, and90+ that is what keeps independent tiles independent during generation.91+- Generation order is a DAG, not a raster: a tile depends on every earlier92+ tile it shares a segment with. Wavefront parallelism becomes antichains93+ of that DAG. With a library, generation order matters only when94+ draining misses (section 4); stitching is a lookup, not a generation.95+- Zones: filler. Cells fully given, never on the frontier, no reward, drawn96+ in the panel grey with no hue. Playable zones with reduced rules are a97+ later knob; keep the manifest shape able to carry a rule set per zone.98+- Reward per tile is n^2 cells; the analyzer records reward per batch and99+ mean n of solved tiles over time so the "small tiles open the board,100+ large tiles pin more" tradeoff is measurable rather than argued.101+102+## 4. The tile library103+104+A tile is a fixed-shape record for a given n and will not change:105+106+```107+n 6..16108+solution n*n bits109+givens n*n bits (mask over solution)110+seam_mask which sides were seams when the givens were chosen (4 bits)111+edges four edge ints: top, right, bottom, left (n bits each)112+features m, blank ratio, bifurcations, used_unique, needs_unique,113+ needs_bifurcation, pins (4 bits), flip cells, generator version114+hash sha256 of (n, solution, givens, seam_mask)115+```116+117+Symmetries multiply the library by 16 at no generation cost: the four118+rotations, reflection, and the 0/1 complement all preserve balance, runs and119+line uniqueness, and they carry givens, planted cells, m and the ladder120+rating along unchanged (row or column shuffles do not survive the no-three121+rule, so 16 is the whole group). Store one canonical orientation per tile122+and index all 16 edge tuples (edges transform by bit reversal and123+complement), so a lookup by edge hits any orientation and the stitcher124+applies the transform on the way out.125+126+At n = 16 the payload is 64 bytes plus ~40 bytes of features. A million127+tiles is about 100 MB. The record is content-addressed and never mutated;128+a new generator version adds rows, it does not rewrite old ones.129+130+What the index has to answer (the stitcher's questions):131+132+1. Tiles of size n whose top edge equals E (one constrained side).133+2. Tiles of size n whose top edge equals E and left edge equals F.134+3. Tiles of size n, any edges, filtered by difficulty features (m, ladder135+ bifurcations, blank ratio) and by seam mask.136+4. Given a tile, its neighbours' constraints for the next placement.137+138+Questions 1 and 3 are exact-match and range filters over small ints: an139+index on `(n, top)`, `(n, left)`, `(n, right)`, `(n, bottom)` and on140+`(n, bifurcations, m)` answers them. Question 2 is where library size141+matters. Balanced edge patterns per n:142+143+| n | C(n, n/2) | one-side lookups | two-side pairs |144+|----|-----------|------------------|----------------|145+| 6 | 20 | trivial | 400 |146+| 8 | 70 | trivial | 4,900 |147+| 10 | 252 | cheap | 63,504 |148+| 12 | 924 | ~10k tiles | 853,776 |149+| 14 | 3,432 | ~50k tiles | 11.8 million |150+| 16 | 12,870 | ~200k tiles | 165 million |151+152+("one-side lookups" is the library size at which a random edge value has153+several matches.) So: a library of tens of thousands of tiles per n makes154+one-sided placement of any size reliable; two-sided placement is only155+reliable for n <= 10. That is the constraint the packer honours by placing156+large tiles with free edges first and small tiles into the gaps. Where a157+two-sided or three-sided placement of a large tile is unavoidable, the158+stitcher records a miss and falls back to a smaller size or a zone.159+160+Partial-edge constraints (a big tile matching a concatenation of small161+neighbours' edges) are just exact-match on the assembled edge int, so they162+need no special index; they are the expensive case only because the163+matching probability is low, which is the same table above.164+165+Misses are the DP part. Every miss is a row `(n, constrained sides and166+their values, packing id)` in a misses table; the local generator drains it167+by generating tiles that satisfy those exact edges (that is what the168+seam-prefilled completion in `gen` already does), pushes them, and the169+next stitch hits. "Failed to fit" entries are misses that the generator170+also could not satisfy (no completion exists for those edges); they are171+kept so the stitcher stops asking. The library therefore grows toward what172+packings actually need, and refreshing it is running the generator against173+the misses table, never a rebuild.174+175+## 5. Where it lives176+177+Nothing computes in the cloud. Generation, stitching, and the daily's178+referee all run locally (or wherever the referee runs); the cloud holds the179+library so it outlives any one machine and any collaborator can pull it.180+The design question is only format and ease of access.181+182+**Format: one SQLite file.** A tile row is ~120 bytes (record + features +183+edge ints); 1 GB is about 8 million tiles, several times what the edge184+table says we need even at n = 16. SQLite gives the indexes (four edge185+columns, difficulty features), the misses table, and an atomic file to copy186+around. Schema in short:187+188+```189+tiles(hash PRIMARY KEY, n, version, seam_mask, top, right, bottom, left,190+ m, blank, bifurcations, used_unique, needs_unique, needs_bifurcation,191+ pins, solution BLOB, givens BLOB, flip BLOB, created)192+ INDEX (n, top), (n, right), (n, bottom), (n, left), (n, bifurcations, m)193+misses(n, side_mask, top, right, bottom, left, packing, first_seen, nofit)194+manifests(day, seed_commit, json)195+```196+197+Rows are append-only and content-addressed; a generator version change adds198+rows with a new `version`, and old rows stay valid because the game199+representation for a given n does not change.200+201+**Access: R2 holds the file, optionally D1 mirrors the index.** The simplest202+that works: the library is an object in R2 (no egress cost, range reads203+supported [5]). A local job pulls the file, stitches, appends misses and any204+newly generated tiles, and pushes it back; a small version stamp avoids two205+writers clobbering each other, and since all writes are appends a conflict206+is a merge of rows, not a rewrite. If the referee ever needs single-tile207+lookups without holding the file, D1 is the same SQLite as a hosted208+database with an HTTP API and a 10 GB ceiling [6]; loading the file into D1209+is a one-off import, not a second source of truth. Workers, KV, and210+Containers are not needed for this.211+212+Daily flow: pull library, draw the packing from the day's seed, resolve it213+against the local file, record misses, run the generator on the misses,214+emit the manifest (tile list with hashes, zones, seed commit), append it,215+push. The referee reads tiles by hash from the same file. Anyone with the216+manifest and the file rebuilds the board, which is the phase-3217+verifiability story unchanged.218+219+## Open questions220+221+- Size distribution per day: uniform over 6..16, or weighted toward 12..16222+ with small tiles only as fillers? The reward curve will look very223+ different; start with big-first so large tiles dominate area.224+- Zones: how much area is acceptable (target under 3%), and should a zone225+ be allowed to be cut by seams of neighbouring tiles (it must, for the226+ neighbours' rules to hold inside their windows; zone cells inside a tile227+ window are simply given).228+- Whether `m` should vary with n (2 for 6..8, 3 for 10..14, 4 for 16) so229+ small tiles are not trivially pinned by a single seam.230+- Seam clues in a packing: a large tile fully surrounded by small ones has231+ many short seam segments; the "fewest seam clues to hold m" rule works232+ per segment, but the count may be higher than in a grid. Measure.233+234+## Sources235+236+1. Tiling of rectangles with squares via Diophantine approximation,237+ https://arxiv.org/pdf/2201.11545238+2. Minimum tiling of a rectangle by squares,239+ https://www.researchgate.net/publication/322233241_Minimum_tiling_of_a_rectangle_by_squares240+3. On Guillotine Separability of Squares and Rectangles,241+ https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.APPROX/RANDOM.2020.47242+4. Jukka Jylanki, A thousand ways to pack the bin (maximal rectangles,243+ skyline), the standard reference for free-rectangle packers.244+5. R2 pricing, https://developers.cloudflare.com/r2/pricing245+6. D1 limits, https://developers.cloudflare.com/d1/platform/limits