Chunks 1–10 built every v1 flow, and each one works end to end on preprod. Chunk 11 gets the wallet ready for its first testers. It’s too big for one session, so it runs as three, each with its own branch and PR into seedelf-web-wallet:
| Part | Branch | What | Size |
|---|---|---|---|
| 11a | web-wallet/polish (this plan’s branch) |
The Lace style and flow pass: the whole UI | The biggest |
| 11b | web-wallet/size-and-live |
A smaller WebAssembly module, live preprod runs of every flow, and loose ends | Medium |
| 11c | web-wallet/store |
The unlisted Chrome Web Store listing for the first testers | Small, and the user submits it |
Do them in order: 11c’s screenshots should show 11a’s look, and its build should carry 11b’s smaller module.
seedelf-web-wallet once the previous part has merged:
git fetch origin
git checkout web-wallet/polish && git merge origin/seedelf-web-wallet # 11a
git checkout -b web-wallet/size-and-live origin/seedelf-web-wallet # 11b
git checkout -b web-wallet/store origin/seedelf-web-wallet # 11c
git log --oneline origin/seedelf-web-wallet..origin/main # merge main first if this lists anything
seedelf-platform/):
cargo test --workspace # about 209 tests
./seedelf-web-wallet/wasm/build.sh && node --test "seedelf-web-wallet/wasm/tests/*.test.mjs"
cd seedelf-web-wallet/extension
npm ci && npm run build && npm test && npx playwright install chromium && npm run e2e
Expect cargo 209, WASM Node 29, Vitest 117 (+2 live, skipped) and Playwright 19 (as of 11b). CI (.github/workflows/web-wallet.yml) runs all of it on the PR.
#8B2BEC and friends). Seedelf keeps its own navy #011833 and teal #00c4bc (see brand/).extension/src/background/secret-box/ does.default-src 'self'. Fonts, images and icons must ship inside the extension. There are no web fonts from a CDN.data-testid, not by class. Restyling is safe; renaming a button or a label means updating e2e/extension.spec.ts in the same commit.Start by asking the user for their list of CSS and UX fixes. In chunk 7 they said those belong in this pass (memory: Style polish later). Then confirm the decisions.
Done (2026-09-24). The user chose dark only (no light theme), Inter bundled, Lucide icons, and the switch with round actions for Home. The palette and form layout follow the suggestions below, and there was no fix list. See the roadmap’s handoff note.
extension/src/ui/styles.css (the tokens are at the top), ui/App.tsx, ui/screens/*.tsx and ui/components/*.tsx.npm run e2e writes extension/test-results/*.png, for every screen in the tab (1280 px) and the popup (360 px). Use them to compare before and after.seedelf-platform/_reference/lace, gitignored; _reference/README.md is the reading map). Paths are under packages/lib/ui-toolkit/src/:
design-tokens/theme/dark.ts and light.ts: the colours.
#1E1E1E; surfaces are white at 5% and 8% (#FFFFFF0D, #FFFFFF14); text #FFFFFF, #EFEFEF and #CCCCCC.#008080, negative #E01E5A.design-tokens/tokens/radius.ts, spacing.ts and shadows.ts.
rounded 100 for pills.0 2px 14px in a faint drop colour.design-system/atoms/{button,card,text,input,iconButton,actionButton,pill,toggle}, molecules/{navigationHeader,detailRows,buttonGroup,modal}, organisms/tabBar and templates/{lock,onboarding,pageContainerTemplate}.packages/module/{send-flow,onboarding,app-lock}.| Decision | Suggestion | Notes |
|---|---|---|
| Theme | Dark by default, Lace’s dark structure in Seedelf’s colours. Light stays for prefers-color-scheme: light, built the same way from Lace’s light.ts |
Today it follows the system and light is the default. The roadmap asks for “much more Lace’s dark mode”. |
| Accent and palette | Teal #00c4bc is the accent (buttons, links, focus); navy for the light theme’s text. Lace’s neutrals, radii, spacing and shadows |
“The look but not the brand”. |
| Font | The system font stack, as today | The alternative is to bundle one OFL font (for example Inter or Montserrat, a variable woff2 of about 100–300 KB) with its licence, and add font-src 'self' to the CSP. |
| Icons | Lucide (ISC), copied as inline SVG, only the icons used | The icons are hand-drawn today (components/Icons.tsx). Lace’s own icons are Apache-2.0, but they sit close to its brand. |
| Home’s structure | A header with the Seedelf balance; tabs or a segmented switch for Seedelf and Cardano account; round action buttons (Send, Withdraw, Move in, Receive) like Lace’s action buttons; Your Seedelfs as a list | Today Home is one long scroll of three cards. Confirm with a sketch, or a screenshot of a first cut, before restyling every screen. |
| Forms and review screens | One shared layout: a step header, a title, fields, notes as callouts, and a sticky primary button. The review uses Lace’s detail-row style | Today every screen repeats this markup, and a Row component is copied in five files. Pull it into components/. |
styles.css: colours, surfaces, borders, radii, spacing and shadows for dark and light, named after what they’re for. Check the contrast of text on surfaces (WCAG AA) in both themes.Button (primary, secondary, link, icon, round action), Card, StepHeader, ReviewRows (the five copies of Row), Callout, Field (label, input and note).AdaInput, TokenAmounts, CopyButton and TokenList restyled.colorScheme: "dark" in Playwright’s context) so both themes are seen.Done when every screen follows the new tokens and components in both themes and both sizes, the user has seen the screenshots, and the tests pass.
Done (2026-09-24). opt-level = "z" with LTO, and no wasm-opt (it grew the compressed size). Every flow ran live on the private test wallet, which also turned up a lagging Koios backend and a Koios node outage. See the roadmap’s handoff note.
wasm/build.sh and the workspace Cargo.toml, which has no [profile.*] yet.extension/e2e/live/{move-in,mint}.mjs and development.md Testing layers.| Decision | Suggestion | Notes |
|---|---|---|
| How to shrink the module | A wasm-release cargo profile (inherits = "release", lto = true, codegen-units = 1, opt-level = "s" or "z", strip = true), used only by build.sh, then wasm-opt -Oz if it pays |
The CLI’s release build stays as it is. wasm-opt isn’t installed here: binaryen comes from apt, GitHub releases, or npm’s binaryen. CI needs it too, or build.sh must skip it cleanly. |
| What “small enough” means | Measure each step, and keep only what pays. Proofs and builds must not get noticeably slower | Today it’s 2.3 MB (582 KB gzipped). Time a proof (about 10 ms now) and a whole mint draft, before and after. opt-level = "z" can slow the BLS arithmetic. |
| Live runs | One script per flow, run by hand, never in CI: move in → mint (account) → transfer → withdraw → remove, on the private test wallet | The user funds extension/.preprod-test-wallet.txt (gitignored) from the faucet. Each run records its tx hash in the roadmap. |
wasm-opt step to build.sh and to CI’s WASM build, keeping the output’s name and path.
wasm-opt” in Crypto, and the 2.3 MB in Transaction building.e2e/live/{transfer,withdraw,remove}.mjs in the shape of mint.mjs (restore, act, wait for the banner to confirm, print the hash and every host contacted), or one e2e/live/all.mjs running the whole lifecycle.
Done when the module is as small as it usefully gets without slowing proofs, every flow has a recorded live preprod transaction from the built extension, and the loose ends are closed or written down.
The user owns the Chrome Web Store developer account and submits the listing. This part prepares everything, so that submitting is copy and paste.
Done (2026-09-24) — the materials only; the listing was never submitted. The decisions below were preprod only, unlisted, the policy on GitHub, Authentication and Financial declared, and framed screenshots. Everything to submit is in store/. See the roadmap’s handoff note.
test-results/popup-*.png).snap() in e2e/extension.spec.ts for full-page shots. It turns animations off, and unsticks each screen’s foot through the CSSOM, because the page CSP refuses an injected stylesheet.public/licenses/). The zip should also carry notices for:
src/background/secret-box/);@noble/*, uqr);cargo about or cargo license can list them).One licenses/THIRD-PARTY.txt, made by a script, is enough.
key, Chrome gives the unpacked build its own ID, but e2e/extension.spec.ts pins jfekiogplaamnceifeehipmomhojngcb. For “passes the same tests”, read the ID from the service worker’s URL instead.dist/ is about 873 KB. The module is 1.2 MB (424 KB gzipped). Proofs take about 2 ms.node e2e/live/run.mjs all) submit real preprod transactions from the private test wallet. The user approved that for 11b only, so ask again before running them.extension/src/manifest.ts (VITE_STORE_BUILD=true drops the dev key; VITE_ENABLE_MAINNET adds mainnet).| Decision | Suggestion | Notes |
|---|---|---|
| Network | Preprod only for the first testers | Mainnet is “after v1” in the roadmap and needs its own review (the fees are real, and so are the risks). |
| Visibility | Unlisted: anyone with the link | The alternative is private (named testers only). development.md recommends either. |
| Where the privacy policy lives | A page in the repo (seedelf-web-wallet/docs/store/privacy-policy.md), linked by its GitHub URL |
It says nothing is collected, and that the wallet talks to Koios and giveme.my, each of which sees the user’s IP (privacy.md Network). |
| Version | 1.0.0, as package.json says today |
Every new upload needs a higher version. |
| Who submits | The user, by hand | This is outward-facing: prepare it, never submit it. |
VITE_STORE_BUILD=true npm run build, then a zip of dist/ (an npm run package script).key, only the preprod hosts, and the strict CSP.seedelf-web-wallet/docs/store/:
storage, alarms, and the Koios and giveme.my hostsDone when the user has everything needed to submit, and a store build passes the same tests as the dev build.