Cargo.lock | 1 + apps/ios/Snowbound/App.swift | 44 +- apps/ios/Snowbound/CanvasView.swift | 170 ++++++- apps/ios/Snowbound/FormatBar.swift | 25 +- apps/ios/Snowbound/Lists.swift | 148 +++--- apps/ios/Snowbound/Notebooks.swift | 17 + apps/ios/Snowbound/PageViewController.swift | 107 ++++- apps/ios/Snowbound/PaperViewController.swift | 183 ++++++++ apps/ios/Snowbound/Script.swift | 5 +- apps/ios/Snowbound/Sync.swift | 260 ++++++++++ apps/ios/Snowbound/Tags.swift | 193 ++++++++ arc/canvas.md | 21 +- arc/file-format.md | 11 +- arc/sync.md | 7 + arc/ui.md | 10 +- corpus/attachment-edit/README.md | 3 +- corpus/attachment-floating/README.md | 38 ++ corpus/attachment-floating/candidate/Open Notebook.onetoc2 | Bin 0 -> 1604 bytes corpus/attachment-floating/candidate/files.one | Bin 0 -> 2106848 bytes corpus/attachment-floating/cold/commands.jsonl | 3 + corpus/attachment-floating/cold/machine.json | 1 + corpus/attachment-floating/cold/read/1dec2d4ce43ad4fb609d5ec604ed9cc5a602f5930c9726e553dbcf5b4d51ee3a.attachment | Bin 0 -> 2097152 bytes corpus/attachment-floating/cold/read/78b7cac526a295294b0a4f001cfdc3a8a30ea5dad8d18cc53022a6a5285ca58f.attachment | 1 + corpus/attachment-floating/cold/read/environment.json | 7 + corpus/attachment-floating/cold/read/hierarchy.xml | 2 + corpus/attachment-floating/cold/read/page-000.navigation.json | 13 + corpus/attachment-floating/cold/read/page-000.png | Bin 0 -> 37175 bytes corpus/attachment-floating/cold/read/page-000.xml | 2 + corpus/attachment-floating/cold/read/payloads.json | 18 + corpus/attachment-floating/cold/run.json | 18 + corpus/attachment-floating/cold/scripts/cold.ps1 | 27 ++ corpus/attachment-floating/cold/scripts/read.ps1 | 144 ++++++ corpus/attachment-floating/cold/source.json | 14 + corpus/attachment-floating/cold/teardown.json | 1 + corpus/attachment-floating/native/files.one | Bin 0 -> 21160 bytes corpus/attachment-insert/README.md | 42 ++ corpus/attachment-insert/candidate/Open Notebook.onetoc2 | Bin 0 -> 1604 bytes corpus/attachment-insert/candidate/files.one | Bin 0 -> 2108416 bytes corpus/attachment-insert/cold/commands.jsonl | 3 + corpus/attachment-insert/cold/machine.json | 1 + corpus/attachment-insert/cold/read/1dec2d4ce43ad4fb609d5ec604ed9cc5a602f5930c9726e553dbcf5b4d51ee3a.attachment | Bin 0 -> 2097152 bytes corpus/attachment-insert/cold/read/6762b4d4a7d68d79ade02f878b9c64dbce0b0d4830d7ef6dd36d932339bb8ed3.attachment | 1 + corpus/attachment-insert/cold/read/environment.json | 7 + corpus/attachment-insert/cold/read/hierarchy.xml | 2 + corpus/attachment-insert/cold/read/page-000.navigation.json | 13 + corpus/attachment-insert/cold/read/page-000.png | Bin 0 -> 37912 bytes corpus/attachment-insert/cold/read/page-000.xml | 2 + corpus/attachment-insert/cold/read/payloads.json | 18 + corpus/attachment-insert/cold/run.json | 18 + corpus/attachment-insert/cold/scripts/cold.ps1 | 27 ++ corpus/attachment-insert/cold/scripts/read.ps1 | 142 ++++++ corpus/attachment-insert/cold/source.json | 14 + corpus/attachment-insert/cold/teardown.json | 1 + corpus/attachment-insert/without-icon.png | Bin 0 -> 43796 bytes corpus/custom-tags/README.md | 29 ++ corpus/custom-tags/candidate/Open Notebook.onetoc2 | Bin 0 -> 1612 bytes corpus/custom-tags/candidate/custom-tags.one | Bin 0 -> 8296 bytes corpus/custom-tags/cold/commands.jsonl | 3 + corpus/custom-tags/cold/machine.json | 1 + corpus/custom-tags/cold/notebook/Open Notebook.onetoc2 | Bin 0 -> 3780 bytes corpus/custom-tags/cold/notebook/custom-tags.one | Bin 0 -> 9808 bytes corpus/custom-tags/cold/read/environment.json | 7 + corpus/custom-tags/cold/read/hierarchy.xml | 2 + corpus/custom-tags/cold/read/page-000.navigation.json | 13 + corpus/custom-tags/cold/read/page-000.png | Bin 0 -> 40401 bytes corpus/custom-tags/cold/read/page-000.xml | 2 + corpus/custom-tags/cold/read/payloads.json | 3 + corpus/custom-tags/cold/run.json | 18 + corpus/custom-tags/cold/scripts/cold.ps1 | 27 ++ corpus/custom-tags/cold/scripts/read.ps1 | 142 ++++++ corpus/custom-tags/cold/source.json | 14 + corpus/custom-tags/cold/teardown.json | 1 + corpus/custom-tags/native/shapes.one | Bin 0 -> 259536 bytes corpus/page-background/README.md | 20 +- corpus/page-background/candidate/Rules.one | Bin 132704 -> 324016 bytes corpus/page-background/cold/commands.jsonl | 2 +- corpus/page-background/cold/machine.json | 2 +- corpus/page-background/cold/read/environment.json | 2 +- corpus/page-background/cold/read/hierarchy.xml | 2 +- corpus/page-background/cold/read/page-000.navigation.json | 2 +- corpus/page-background/cold/read/page-000.png | Bin 40103 -> 43163 bytes corpus/page-background/cold/read/page-000.xml | 2 +- corpus/page-background/cold/read/page-001.navigation.json | 2 +- corpus/page-background/cold/read/page-001.png | Bin 41559 -> 41466 bytes corpus/page-background/cold/read/page-001.xml | 2 +- corpus/page-background/cold/read/page-002.navigation.json | 2 +- corpus/page-background/cold/read/page-002.png | Bin 47443 -> 94951 bytes corpus/page-background/cold/read/page-002.xml | 353 +++++++++++++- corpus/page-background/cold/read/page-003.navigation.json | 2 +- corpus/page-background/cold/read/page-003.png | Bin 46391 -> 88597 bytes corpus/page-background/cold/read/page-003.xml | 353 +++++++++++++- corpus/page-background/cold/read/page-004.navigation.json | 2 +- corpus/page-background/cold/read/page-004.png | Bin 41480 -> 41666 bytes corpus/page-background/cold/read/page-004.xml | 2 +- corpus/page-background/cold/read/page-005.navigation.json | 2 +- corpus/page-background/cold/read/page-005.png | Bin 40354 -> 199448 bytes corpus/page-background/cold/read/page-005.xml | 770 +++++++++++++++++++++++++++++- corpus/page-background/cold/read/page-006.navigation.json | 2 +- corpus/page-background/cold/read/page-006.png | Bin 88594 -> 92949 bytes corpus/page-background/cold/read/page-006.xml | 2 +- corpus/page-background/cold/read/page-007.navigation.json | 2 +- corpus/page-background/cold/read/page-007.png | Bin 49709 -> 41483 bytes corpus/page-background/cold/read/page-007.xml | 2 +- corpus/page-background/cold/read/page-008.navigation.json | 2 +- corpus/page-background/cold/read/page-008.png | Bin 41663 -> 40355 bytes corpus/page-background/cold/read/page-008.xml | 2 +- corpus/page-background/cold/read/page-009.navigation.json | 2 +- corpus/page-background/cold/read/page-009.png | Bin 43163 -> 40091 bytes corpus/page-background/cold/read/page-009.xml | 2 +- corpus/page-background/cold/read/page-010.navigation.json | 2 +- corpus/page-background/cold/read/page-010.png | Bin 41463 -> 41562 bytes corpus/page-background/cold/read/page-010.xml | 2 +- corpus/page-background/cold/run.json | 2 +- corpus/page-background/cold/source.json | 6 +- crates/canvas/assets/file.svg | 9 + crates/canvas/assets/tags/arrow-down-blue.svg | 9 + crates/canvas/assets/tags/arrow-down-green.svg | 9 + crates/canvas/assets/tags/arrow-down-yellow.svg | 9 + crates/canvas/assets/tags/arrow-left-blue.svg | 9 + crates/canvas/assets/tags/arrow-left-green.svg | 9 + crates/canvas/assets/tags/arrow-left-yellow.svg | 9 + crates/canvas/assets/tags/arrow-right-blue.svg | 9 + crates/canvas/assets/tags/arrow-right-green.svg | 9 + crates/canvas/assets/tags/arrow-right-yellow.svg | 9 + crates/canvas/assets/tags/arrow-up-blue.svg | 9 + crates/canvas/assets/tags/arrow-up-green.svg | 9 + crates/canvas/assets/tags/arrow-up-yellow.svg | 9 + crates/canvas/assets/tags/bell.svg | 15 + crates/canvas/assets/tags/binoculars.svg | 14 + crates/canvas/assets/tags/calendar.svg | 25 + crates/canvas/assets/tags/car.svg | 13 + crates/canvas/assets/tags/checkbox-green.svg | 24 + crates/canvas/assets/tags/checkbox-yellow.svg | 24 + crates/canvas/assets/tags/circle-1-blue.svg | 9 + crates/canvas/assets/tags/circle-1-green.svg | 9 + crates/canvas/assets/tags/circle-1-yellow.svg | 9 + crates/canvas/assets/tags/circle-2-blue.svg | 9 + crates/canvas/assets/tags/circle-2-green.svg | 9 + crates/canvas/assets/tags/circle-2-yellow.svg | 9 + crates/canvas/assets/tags/circle-3-blue.svg | 9 + crates/canvas/assets/tags/circle-3-green.svg | 9 + crates/canvas/assets/tags/circle-3-yellow.svg | 9 + crates/canvas/assets/tags/circle-blue.svg | 8 + crates/canvas/assets/tags/circle-green.svg | 8 + crates/canvas/assets/tags/circle-yellow.svg | 8 + crates/canvas/assets/tags/clock.svg | 21 + crates/canvas/assets/tags/cloud.svg | 9 + crates/canvas/assets/tags/coins.svg | 30 ++ crates/canvas/assets/tags/date.svg | 43 ++ crates/canvas/assets/tags/dollar.svg | 5 + crates/canvas/assets/tags/envelope-open.svg | 11 + crates/canvas/assets/tags/envelope.svg | 8 + crates/canvas/assets/tags/flag-next-week.svg | 7 + crates/canvas/assets/tags/flag-no-date.svg | 7 + crates/canvas/assets/tags/flag-this-week.svg | 7 + crates/canvas/assets/tags/flag-today.svg | 7 + crates/canvas/assets/tags/flag-tomorrow.svg | 7 + crates/canvas/assets/tags/follow-up.svg | 7 + crates/canvas/assets/tags/frown.svg | 11 + crates/canvas/assets/tags/globe.svg | 12 + crates/canvas/assets/tags/green-square.svg | 19 + crates/canvas/assets/tags/heart.svg | 8 + crates/canvas/assets/tags/im-contact.svg | 10 + crates/canvas/assets/tags/key.svg | 8 + crates/canvas/assets/tags/laptop.svg | 10 + crates/canvas/assets/tags/lightning.svg | 7 + crates/canvas/assets/tags/mark-arrow-blue.svg | 6 + crates/canvas/assets/tags/mark-arrow-green.svg | 6 + crates/canvas/assets/tags/mark-arrow-yellow.svg | 6 + crates/canvas/assets/tags/mark-arrow.svg | 6 - crates/canvas/assets/tags/mark-client.svg | 9 - crates/canvas/assets/tags/mark-exclamation-blue.svg | 9 + crates/canvas/assets/tags/mark-exclamation-green.svg | 9 + crates/canvas/assets/tags/mark-exclamation-yellow.svg | 9 + crates/canvas/assets/tags/mark-flag-blue.svg | 7 + crates/canvas/assets/tags/mark-flag-green.svg | 7 + crates/canvas/assets/tags/mark-flag-yellow.svg | 7 + crates/canvas/assets/tags/mark-manager.svg | 9 - crates/canvas/assets/tags/mark-one-blue.svg | 7 + crates/canvas/assets/tags/mark-one-green.svg | 7 + crates/canvas/assets/tags/mark-one-yellow.svg | 7 + crates/canvas/assets/tags/mark-one.svg | 7 - crates/canvas/assets/tags/mark-person-blue.svg | 9 + crates/canvas/assets/tags/mark-person-green.svg | 9 + crates/canvas/assets/tags/mark-person-yellow.svg | 9 + crates/canvas/assets/tags/mark-person.svg | 9 - crates/canvas/assets/tags/mark-star-blue.svg | 7 + crates/canvas/assets/tags/mark-star-green.svg | 7 + crates/canvas/assets/tags/mark-star-yellow.svg | 7 + crates/canvas/assets/tags/mark-three-blue.svg | 7 + crates/canvas/assets/tags/mark-three-green.svg | 7 + crates/canvas/assets/tags/mark-three-yellow.svg | 7 + crates/canvas/assets/tags/mark-two-blue.svg | 7 + crates/canvas/assets/tags/mark-two-green.svg | 7 + crates/canvas/assets/tags/mark-two-yellow.svg | 7 + crates/canvas/assets/tags/mark-two.svg | 7 - crates/canvas/assets/tags/mobile.svg | 19 + crates/canvas/assets/tags/notebook.svg | 32 ++ crates/canvas/assets/tags/orange-square.svg | 19 + crates/canvas/assets/tags/paper.svg | 14 + crates/canvas/assets/tags/paperclip.svg | 4 + crates/canvas/assets/tags/people.svg | 12 + crates/canvas/assets/tags/person.svg | 11 + crates/canvas/assets/tags/phone-clock.svg | 26 + crates/canvas/assets/tags/pink-square.svg | 19 + crates/canvas/assets/tags/plane.svg | 6 + crates/canvas/assets/tags/presentation.svg | 15 + crates/canvas/assets/tags/pushpin.svg | 8 + crates/canvas/assets/tags/question-balloon.svg | 9 + crates/canvas/assets/tags/quote.svg | 7 + crates/canvas/assets/tags/research.svg | 14 + crates/canvas/assets/tags/ribbon.svg | 11 + crates/canvas/assets/tags/rose.svg | 10 + crates/canvas/assets/tags/schedule.svg | 30 ++ crates/canvas/assets/tags/smiley.svg | 11 + crates/canvas/assets/tags/solid-target-blue.svg | 11 + crates/canvas/assets/tags/solid-target-green.svg | 11 + crates/canvas/assets/tags/solid-target-yellow.svg | 11 + crates/canvas/assets/tags/star-blue.svg | 7 + crates/canvas/assets/tags/star-green.svg | 7 + crates/canvas/assets/tags/star8-blue.svg | 4 + crates/canvas/assets/tags/star8-yellow.svg | 4 + crates/canvas/assets/tags/sun-blue.svg | 16 + crates/canvas/assets/tags/sun-green.svg | 16 + crates/canvas/assets/tags/sun-yellow.svg | 16 + crates/canvas/assets/tags/sunflower.svg | 31 ++ crates/canvas/assets/tags/target-blue.svg | 9 + crates/canvas/assets/tags/target-green.svg | 9 + crates/canvas/assets/tags/target-yellow.svg | 9 + crates/canvas/assets/tags/tick-blue.svg | 6 + crates/canvas/assets/tags/tick-green.svg | 6 + crates/canvas/assets/tags/tick-yellow.svg | 6 + crates/canvas/assets/tags/triangle-blue.svg | 7 + crates/canvas/assets/tags/triangle-green.svg | 7 + crates/canvas/assets/tags/triangle-yellow.svg | 7 + crates/canvas/assets/tags/umbrella-blue.svg | 9 + crates/canvas/assets/tags/umbrella-green.svg | 9 + crates/canvas/assets/tags/umbrella-yellow.svg | 9 + crates/canvas/assets/tags/x-blue.svg | 3 + crates/canvas/assets/tags/x-dots-blue.svg | 7 + crates/canvas/assets/tags/x-dots-green.svg | 7 + crates/canvas/assets/tags/x-dots-yellow.svg | 7 + crates/canvas/assets/tags/x-green.svg | 3 + crates/canvas/assets/tags/x-yellow.svg | 3 + crates/canvas/src/bin/page_probe.rs | 3 + crates/canvas/src/editor.rs | 692 ++++++++++++++++++++++++--- crates/canvas/src/editor/evidence.rs | 19 +- crates/canvas/src/editor/format.rs | 464 +++++++++--------- crates/canvas/src/editor/ops.rs | 4 + crates/canvas/src/editor/page.rs | 44 +- crates/canvas/src/editor/space.rs | 3 +- crates/canvas/src/gpu/mod.rs | 332 ++++++++----- crates/canvas/src/gpu/page.rs | 178 +++++-- crates/canvas/src/gpu/page/background.rs | 71 ++- crates/canvas/src/interaction/accessibility.rs | 39 +- crates/canvas/src/interaction/mod.rs | 166 ++++++- crates/canvas/src/interaction/tests.rs | 271 ++++++++++- crates/canvas/src/outline.rs | 405 +++++++++++----- crates/canvas/src/template.rs | 30 ++ crates/canvas/tests/attachment_insert.rs | 256 ++++++++++ crates/canvas/tests/custom_tags.rs | 207 ++++++++ crates/canvas/tests/ops_differential.rs | 199 +++++++- crates/canvas/tests/search.rs | 3 +- crates/draw/src/draw.glsl | 32 +- crates/draw/src/draw.wgsl | 38 +- crates/draw/src/render.rs | 225 +++++++-- crates/draw/src/render/gl.rs | 11 +- crates/draw/src/render/webgpu.rs | 88 ++-- crates/mobile/Cargo.toml | 1 + crates/mobile/include/snowbound.h | 15 +- crates/mobile/src/lib.rs | 234 ++++++++- crates/mobile/src/library.rs | 321 +++++++++++-- crates/mobile/src/tests.rs | 216 ++++++++- crates/notebook/src/lib.rs | 27 +- crates/notebook/src/merge.rs | 7 +- crates/notebook/src/queue.rs | 4 + crates/notebook/src/session.rs | 48 +- crates/notebook/tests/copy.rs | 7 +- crates/notebook/tests/sync_outline.rs | 90 ++++ crates/onestore/README.md | 4 +- crates/onestore/src/op/apply.rs | 58 ++- crates/onestore/src/op/content.rs | 29 +- crates/onestore/src/op/lower.rs | 88 +++- crates/onestore/src/op/mod.rs | 6 +- crates/onestore/src/op/model.rs | 59 ++- crates/onestore/src/op/properties.rs | 8 +- crates/onestore/src/op/tests.rs | 18 + crates/onestore/src/outline.rs | 13 +- crates/onestore/src/page/mod.rs | 17 +- crates/onestore/src/tree.rs | 5 +- crates/onestore/tests/page_attachments.rs | 138 ++++++ crates/onestore/tests/page_model.rs | 5 +- crates/onestore/tests/protected.rs | 1 + crates/onestore/tests/support/page_edits.rs | 1 + crates/snowbound/src/art.rs | 3 - crates/snowbound/src/attachment.rs | 94 ++++ crates/snowbound/src/commands.rs | 151 +++--- crates/snowbound/src/link.rs | 88 ++-- crates/snowbound/src/linux.rs | 48 +- crates/snowbound/src/macos.rs | 117 ++++- crates/snowbound/src/main.rs | 153 ++++-- crates/snowbound/src/manage.rs | 149 +++--- crates/snowbound/src/menubar.rs | 79 ++-- crates/snowbound/src/palette.rs | 9 + crates/snowbound/src/settings.rs | 9 + crates/snowbound/src/sync.rs | 39 +- crates/snowbound/src/tags.rs | 810 ++++++++++++++++++++++++++++++++ crates/ui/src/lib.rs | 41 +- crates/ui/src/popup.rs | 70 ++- tools/native/read.ps1 | 4 +- tools/test_attachment_floating.py | 43 ++ tools/test_attachment_insert.py | 42 ++ tools/test_custom_tags.py | 45 ++ tools/test_page_background.py | 26 +- tools/verify-document.py | 3 +- 315 files changed, 10688 insertions(+), 1481 deletions(-)