diff --git a/badges-flow-mvp.svg b/badges-flow-mvp.svg
index 2feb65c6d8..22151dd171 100644
--- a/badges-flow-mvp.svg
+++ b/badges-flow-mvp.svg
@@ -1 +1 @@
-Supporter badges - every screen, in the app and on the web interaction design - the app in its native idiom, the site in its own plans/2026-08-21-badges-web-checkout.md editable SVG In the app iOS idiom shown; Android and desktop differ only in chrome Support SimpleX SimpleX is built by people who believe private messaging should not depend on advertising. A badge helps pay for it. Why SimpleX is built this way Choose your level Redeem badge code A1. Where it starts Both actions ship today. On iOS and Play, 'Redeem badge code' is not a secondary path - it is the only one, because store evidence is not verified and the store purchase was removed rather than left charging for nothing. ‹ Support Your level Both levels remove the file size limit. Legend raises it further. Supporter $7 / month 2 GB files Legend $70 / month 5 GB files Perks are app constants, not catalog data - the catalog carries prices only. Continue A2. Choose your level Prices come from CRBadgeCatalog, never the store products. One source, so the app and the site cannot disagree about what a badge costs. ‹ Your level Legend Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% 3 months is 2x the monthly price, 12 is 6x. The saving compares against the undiscounted total and is never sent anywhere - the server prices every charge it makes. Continue in browser Redeem badge code A3. How long - desktop and Android foss The only builds with more than one way to pay, and the only ones that link out. 'Continue in browser' carries the answers so far as URL parameters. ‹ Your level Legend Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% Buy a code at badges.simplex.chat from any browser, then redeem it here. Redeem badge code no purchase button on this build A4. How long - iOS and Play Same screen, different ending. The store purchase action is removed for the whole of this plan, and no link out replaces it: Apple and Google reject steering to outside purchase for digital goods, so the screen simply ends at redemption. ‹ Legend How to pay Checkout happens in your browser. Nothing is charged in the app. Card Visa, Mastercard Bitcoin on-chain Monero on-chain Continue in browser Opens badges.simplex.chat with tier, months and method already chosen. A5. Only where there is a choice Desktop and Android foss only. The store builds have no methods at all and never reach this screen. The choice is a hint: the site asks again if the parameter is unusable. ‹ Support Redeem code Paste the code from your receipt. SXB-9K2M4-7QRT1-XZ5W Paste Redeem Formats as you type and folds I and L to 1, O to 0 - the same normalisation the service does, so a code read off a screen cannot fail on ambiguity alone. A6. Redeeming Twenty Crockford characters in five groups. The check character is verified before anything is sent, so a mistyped code never reaches the service and never costs a throttle token. ‹ Settings Supporter perks Legend shown on your profile ENDS 24 August 2027 Prepaid months have no billing date. The badge is reissued each month from the balance you already paid for, and ends when it runs out. Add more months A7. After redeeming 'Ends', never 'renews' - nothing recurs and the copy must not imply it does. The date is the paid-through date from the ledger balance, not the credential's expiry, which is a week-aligned internal the user never sees. ‹ Chats Alice A Alice Legend last seen recently IN GROUPS A Alice Legend B Bob Supporter C Carol The badge travels with the profile, so it shows wherever a profile does - in chats, in a member list, on a contact card. A8. How everyone else sees it The point of the whole flow. The badge is a signed credential carried in the profile and verified by the recipient's own client against the issuer key it already ships - not a flag the server asserts, and not something a client can set for itself. For the operator the CLI that mints and resolves codes simplex-badge-service $ simplex-badge-service codes issue \ --type legend --months 12 --count 3 \ --batch conf-2026 --expires 2027-08-24 SXB-9K2M4-7QRT1-XZ5WB-3NHD8 SXB-2W7XP-4LMQ8-9DKR3-6TVZ5 SXB-8HYNC-1FGJ6-5PBW2-7QSXD 3 codes issued. Printed once; only hashes stored. OP1. Minting codes Compensation and promotional codes have no order behind them, so they are random rather than derived. Printed once to stdout and never again - the database holds only SHA-256 hashes, which is what makes a stolen copy useless. support $ simplex-badge-service codes status \ --ref K7M2Q order 8f3a...c21e paid 24 Aug badge legend, 12 months code redeemed 2 Sep --reveal refused: code already redeemed OP2. Resolving a reference The customer quotes the five-character reference from their receipt - never the order id, never the code. --reveal is refused once a code is redeemed or revoked, on the same reasoning that stops the web page disclosing it. On the web badges.simplex.chat - one centred column, max-width 560, the logo the only image badges.simplex.chat Support SimpleX SimpleX has no ads, no user accounts and nothing to sell. A supporter badge helps pay for the people who build it. Supporter $7 / month - 2 GB files Legend $70 / month - 5 GB files Choose your level Already bought a code? Redeem it in the app: Settings, Supporter perks. The badge shows on your profile. Nothing renews by itself, and no account is created. simplex.chat/contact B1. The landing page Not in the plan, and it should be. D3 specifies four screens starting at the tier question, which assumes everyone arrives from the app. Someone reaching the site from a link or a search needs to know what this is before being asked to choose a level - and someone who already has a code needs telling that redemption happens in the app, not here. badges.simplex.chat/#/tier Choose your level Support SimpleX and lift the file size limit. Supporter $7 / month 2 GB files Legend $70 / month 5 GB files Continue simplex.chat/contact B2. Question one: the level The wizard proper starts here. One centred column at max-width 560, generous whitespace, accent #0053D0 - deliberately not the app's chrome, because it is not the app. One question per screen, and a tier with no active price renders disabled rather than hidden. badges.simplex.chat/#/months How long? Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% Continue simplex.chat/contact B3. How long Every figure comes from GET /api/catalog, the same totals the RPC catalog gives the app. The browser formats minor units and computes the comparison only - it never multiplies a price by a month count. badges.simplex.chat/#/pay How would you like to pay? Card is handled by Stripe. Bitcoin and Monero are on-chain, through BTCPay. Card Visa, Mastercard Bitcoin on-chain Monero on-chain Continue simplex.chat/contact B4. Method A method whose provider is not configured is refused at checkout with provider_unavailable rather than hidden here, so a half-configured deployment fails loudly instead of quietly offering less. See C4. badges.simplex.chat/?tier=legend&months=12&pay=xmr Check your order Level Legend Duration 12 months Method Monero Total $420.00 Pay with Monero You will be shown an address and a QR code. simplex.chat/contact B5. Where the app hand-off lands A user arriving from the app skips B1 to B3 entirely: ?tier=legend&months=12&pay=xmr answers all three questions, so the summary is the first thing they see. POST /api/checkout then carries priceId, offerId and method - never an amount, never a badge type. Both are derived server-side from the ids, so a tampered request cannot buy a Legend badge at a Supporter price. badges.simplex.chat/?order=8f3a...c21e Send 1.482 XMR $420.00 - this rate is held for 58:12 MONERO ADDRESS 48HqK2...9fRtWc Copy Waiting for the payment to confirm REFERENCE K7M2Q Bookmark this page - the address and the countdown both live on this URL. simplex.chat/contact B6. Paying in crypto Polls GET /api/order every 2s for the first minute then every 10s, and stops while the tab is hidden. A partial payment stays 'pending' - partials are the normal first event of a multi-transaction payment, not a failure. badges.simplex.chat/?order=8f3a...c21e ✓ Paid. Here is your code. SXB-9K2M4-7QRT1-XZ5WB-3NHD8 Copy code scan to carry it to your phone REDEEM IT IN THE APP SimpleX -> Settings -> Supporter perks -> Redeem code This is the only place the code is shown. This page works until 23 September, and stops as soon as the code is redeemed. The link is the code - treat it so. simplex.chat/contact B7. The code, once Derived from the order id rather than stored, so a reload recomputes it while only its hash is ever at rest. Disclosure stops at redemption, at revocation, or 30 days after settlement - whichever comes first. badges.simplex.chat/?order=51c7...9d02 Payment received Waiting for the card network to confirm. Still processing This usually takes a few seconds. The page updates itself. If nothing happens for 15 minutes, we stop waiting and show you what to do next. simplex.chat/contact B8. Coming back from the card flow Stripe's success_url returns here with ?order=. The return is NOT proof of payment - only the webhook settles an order, so this screen polls rather than celebrating. The cancel URL deliberately carries no order reference at all. When it does not go to plan every failure the design has to answer for ‹ Support Your level Both levels remove the file size limit. Supporter — price unavailable Legend — price unavailable Could not reach the badge service internal Continue Disabled, not hidden - a level that exists but cannot be priced still exists. C1. The service is unreachable Every option renders disabled and nothing crashes. The same state covers a tier whose price was disabled by the operator - the app cannot tell the two apart, and does not need to. ‹ Support Redeem code This code isn't valid code_invalid This code has already been used code_used This code has expired code_expired Too many attempts. Try again in 4 minutes. rate_limited - retryAfter 240 Could not verify the credential internal One message per error the service can return. Anything else, including a credential that fails to verify locally, shows the service's own text rather than a blank screen. C2. Every redemption error A revoked code is deliberately indistinguishable from an unknown one - both say 'isn't valid', so a guesser learns nothing from a revocation. Support tells them apart with codes status; the wire does not. ‹ Settings Supporter perks Legend ended 24 August 2027 Your badge has ended The months you paid for have all been issued. The badge stopped showing on your profile; nothing was cancelled and nothing is owed. Add more months C3. The balance runs out An exhausted balance is not an error: the service returns no credential and a zero-balance statement, and the app says so plainly. Prepaid means it simply stops. badges.simplex.chat/#/pay How would you like to pay? Monero is temporarily unavailable Try another method, or come back later. Card Visa, Mastercard Bitcoin on-chain Monero unavailable Continue simplex.chat/contact C4. A provider is not configured 503 provider_unavailable from /api/checkout. The method is shown and disabled rather than omitted, so an operator who forgot a section sees it immediately instead of wondering why nobody pays in Monero. badges.simplex.chat/#/checkout These prices have changed Start again with the current prices The badge you chose was repriced while you were deciding. Nothing was charged. Start again price_disabled / offer_disabled / offer_mismatch simplex.chat/contact C5. The catalog moved underneath Prices are checked at checkout and only there. A deprecated price is still honoured for someone mid- flow; a disabled one is refused. Repricing appends a new price rather than editing the old, so this is rare but reachable. badges.simplex.chat/#/checkout Too many attempts Try again in 46 seconds The Pay button is disabled until then. Pay with Monero 429, with Retry-After. The polling loop backs off to that value rather than treating it as a failure. simplex.chat/contact C6. Rate limited Five checkout requests a minute per IP, because each one reaches a payment provider. Order polling gets sixty. The redemption path has no IP at all - it runs over SimpleX RPC and is throttled per signer instead. badges.simplex.chat/?order=8f3a...c21e This invoice expired 0.734 XMR arrived, which is not the full amount The rate window has closed, so the shortfall is no longer meaningful. Quote the reference below and we will sort it out. REFERENCE K7M2Q Start a new invoice Never shows the code, and never the ?order= URL. simplex.chat/contact C7. Expired, and underpaid The one state that needs a human. An expired-but-paid invoice still settles later - late on-chain settlement is routine and moves the order to paid - but an underpaid one stops here with the reference support resolves by. badges.simplex.chat/?order=8f3a...c21e This code has been redeemed The code is no longer shown here It was redeemed on 2 September. If that was not you, get in touch. Legend, 12 months paid 24 August The order stays; the capability does not. simplex.chat/contact C8. The page outlives the code Disclosure ends at redemption, at revocation, or 30 days after settlement. The order is still here because support resolves a reference against it - but the URL stops being equivalent to the code, which is the whole point. Continue in browser answers all three questions, so the site opens at B5 the code goes back to A6 the only thing that crosses from the site to the app Design document. App screens are drawn in the iOS idiom; Android and desktop differ only in chrome. The site is drawn in its own idiom - one centred column at max-width 560, generous whitespace, accent #0053D0 from website/tailwind.config.js - and is deliberately not a copy of the app's. Badge artwork is the shipped art, taken verbatim from MR/images/badge_{supporter,legend}.svg. One deliberate deviation from the plan: D2 specifies the SimpleX logo as the site's only image, but the tier cards here carry the badge art too, on the grounds that someone choosing between two badges should see them. Everything else follows D2 as written. Built today: the service schema, the pricing catalog, the ledger, code derivation and classification, credential signing, the RPC dispatcher and the operator CLI. Design, not yet built: every screen above, the web listener and its endpoints, both payment providers, and the client redeem path. Store purchase is removed on iOS and Play for the duration of this plan: store evidence is not verified, so a store purchase would charge for a badge that is never issued.
\ No newline at end of file
+Supporter badges - every screen, in the app and on the web interaction design - the app in its native idiom, the site in its own plans/2026-08-21-badges-web-checkout.md editable SVG In the app iOS idiom shown; Android and desktop differ only in chrome Support SimpleX SimpleX is built by people who believe private messaging should not depend on advertising. A badge helps pay for it. Why SimpleX is built this way Choose your level Redeem badge code A1. Where it starts Both actions ship today. On iOS and Play, 'Redeem badge code' is not a secondary path - it is the only one, because store evidence is not verified and the store purchase was removed rather than left charging for nothing. ‹ Support Your level Both levels remove the file size limit. Legend raises it further. Supporter $7 / month 2 GB files Legend $70 / month 5 GB files Perks are app constants, not catalog data - the catalog carries prices only. Continue A2. Choose your level Prices come from CRBadgeCatalog, never the store products. One source, so the app and the site cannot disagree about what a badge costs. ‹ Your level Legend Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% 3 months is 2x the monthly price, 12 is 6x. The saving compares against the undiscounted total and is never sent anywhere - the server prices every charge it makes. Continue in browser Redeem badge code A3. How long - desktop and Android foss The only builds with more than one way to pay, and the only ones that link out. 'Continue in browser' carries the answers so far as URL parameters. ‹ Your level Legend Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% Buy a code at badges.simplex.chat from any browser, then redeem it here. Redeem badge code no purchase button on this build A3b. How long - iOS and Play Same screen, different ending. The store purchase action is removed for the whole of this plan, and no link out replaces it: Apple and Google reject steering to outside purchase for digital goods, so the screen simply ends at redemption. ‹ Legend How to pay Checkout happens in your browser. Nothing is charged in the app. Card Visa, Mastercard Bitcoin on-chain Monero on-chain Continue in browser Opens badges.simplex.chat with tier, months and method already chosen. A4. Only where there is a choice Desktop and Android foss only. The store builds have no methods at all and never reach this screen. The choice is a hint: the site asks again if the parameter is unusable. ‹ Support Redeem code Paste the code from your receipt. SXB-9K2M4-7QRT1-XZ5W Paste Redeem Formats as you type and folds I and L to 1, O to 0 - the same normalisation the service does, so a code read off a screen cannot fail on ambiguity alone. A5. Redeeming Twenty Crockford characters in five groups. The check character is verified before anything is sent, so a mistyped code never reaches the service and never costs a throttle token. ‹ Settings Supporter perks Legend shown on your profile ENDS 24 August 2027 Prepaid months have no billing date. The badge is reissued each month from the balance you already paid for, and ends when it runs out. Add more months A6. After redeeming 'Ends', never 'renews' - nothing recurs and the copy must not imply it does. The date is the paid-through date from the ledger balance, not the credential's expiry, which is a week-aligned internal the user never sees. ‹ Chats Alice A Alice Legend last seen recently IN GROUPS A Alice Legend B Bob Supporter C Carol The badge travels with the profile, so it shows wherever a profile does - in chats, in a member list, on a contact card. A7. How everyone else sees it The point of the whole flow. The badge is a signed credential carried in the profile and verified by the recipient's own client against the issuer key it already ships - not a flag the server asserts, and not something a client can set for itself. For the operator the CLI that mints and resolves codes simplex-badge-service $ simplex-badge-service codes issue \ --type legend --months 12 --count 3 \ --batch conf-2026 --expires 2027-08-24 SXB-9K2M4-7QRT1-XZ5WB-3NHD8 SXB-2W7XP-4LMQ8-9DKR3-6TVZ5 SXB-8HYNC-1FGJ6-5PBW2-7QSXD 3 codes issued. Printed once; only hashes stored. OP1. Minting codes Compensation and promotional codes have no order behind them, so they are random rather than derived. Printed once to stdout and never again - the database holds only SHA-256 hashes, which is what makes a stolen copy useless. support $ simplex-badge-service codes status \ --ref K7M2Q order 8f3a...c21e paid 24 Aug badge legend, 12 months code redeemed 2 Sep --reveal refused: code already redeemed OP2. Resolving a reference The customer quotes the five-character reference from their receipt - never the order id, never the code. --reveal is refused once a code is redeemed or revoked, on the same reasoning that stops the web page disclosing it. On the web badges.simplex.chat - one centred column, max-width 560, the logo the only image badges.simplex.chat Support SimpleX SimpleX has no ads, no user accounts and nothing to sell. A supporter badge helps pay for the people who build it. Supporter $7 / month - 2 GB files Legend $70 / month - 5 GB files Choose your level Already bought a code? Redeem it in the app: Settings, Supporter perks. The badge shows on your profile. Nothing renews by itself, and no account is created. simplex.chat/contact B1. The landing page Not in the plan, and it should be. D3 specifies four screens starting at the tier question, which assumes everyone arrives from the app. Someone reaching the site from a link or a search needs to know what this is before being asked to choose a level - and someone who already has a code needs telling that redemption happens in the app, not here. badges.simplex.chat/#/tier Choose your level Support SimpleX and lift the file size limit. Supporter $7 / month 2 GB files Legend $70 / month 5 GB files Continue simplex.chat/contact B2. Question one: the level The wizard proper starts here. One centred column at max-width 560, generous whitespace, accent #0053D0 - deliberately not the app's chrome, because it is not the app. One question per screen, and a tier with no active price renders disabled rather than hidden. badges.simplex.chat/#/months How long? Prepaid months. Nothing renews by itself. 1 month $70 3 months $140 save 33% 12 months $420 save 50% Continue simplex.chat/contact B3. How long Every figure comes from GET /api/catalog, the same totals the RPC catalog gives the app. The browser formats minor units and computes the comparison only - it never multiplies a price by a month count. badges.simplex.chat/#/pay How would you like to pay? Card is handled by Stripe. Bitcoin and Monero are on-chain, through BTCPay. Card Visa, Mastercard Bitcoin on-chain Monero on-chain Continue simplex.chat/contact B4. Method A method whose provider is not configured is refused at checkout with provider_unavailable rather than hidden here, so a half-configured deployment fails loudly instead of quietly offering less. See C4. badges.simplex.chat/?tier=legend&months=12&pay=xmr Check your order Level Legend Duration 12 months Method Monero Total $420.00 Pay with Monero You will be shown an address and a QR code. simplex.chat/contact B5. Where the app hand-off lands A user arriving from the app skips B1 to B3 entirely: ?tier=legend&months=12&pay=xmr answers all three questions, so the summary is the first thing they see. POST /api/checkout then carries priceId, offerId and method - never an amount, never a badge type. Both are derived server-side from the ids, so a tampered request cannot buy a Legend badge at a Supporter price. badges.simplex.chat/?order=8f3a...c21e Send 1.482 XMR $420.00 - this rate is held for 58:12 MONERO ADDRESS 48HqK2...9fRtWc Copy Waiting for the payment to confirm REFERENCE K7M2Q Bookmark this page - the address and the countdown both live on this URL. simplex.chat/contact B6. Paying in crypto Polls GET /api/order every 2s for the first minute then every 10s, and stops while the tab is hidden. A partial payment stays 'pending' - partials are the normal first event of a multi-transaction payment, not a failure. badges.simplex.chat/?order=8f3a...c21e ✓ Paid. Here is your code. SXB-9K2M4-7QRT1-XZ5WB-3NHD8 Copy code scan to carry it to your phone REDEEM IT IN THE APP SimpleX -> Settings -> Supporter perks -> Redeem code This is the only place the code is shown. This page works until 23 September, and stops as soon as the code is redeemed. The link is the code - treat it so. simplex.chat/contact B7. The code, once Derived from the order id rather than stored, so a reload recomputes it while only its hash is ever at rest. Disclosure stops at redemption, at revocation, or 30 days after settlement - whichever comes first. badges.simplex.chat/?order=51c7...9d02 Payment received Waiting for the card network to confirm. Still processing This usually takes a few seconds. The page updates itself. If nothing happens for 15 minutes, we stop waiting and show you what to do next. simplex.chat/contact B8. Coming back from the card flow Stripe's success_url returns here with ?order=. The return is NOT proof of payment - only the webhook settles an order, so this screen polls rather than celebrating. The cancel URL deliberately carries no order reference at all. ‹ Support Your level Both levels remove the file size limit. Supporter — price unavailable Legend — price unavailable Could not reach the badge service internal Continue Disabled, not hidden - a level that exists but cannot be priced still exists. A2b. The service is unreachable Every option renders disabled and nothing crashes. The same state covers a tier whose price was disabled by the operator - the app cannot tell the two apart, and does not need to. ‹ Support Redeem code This code isn't valid code_invalid This code has already been used code_used This code has expired code_expired Too many attempts. Try again in 4 minutes. rate_limited - retryAfter 240 Could not verify the credential internal One message per error the service can return. Anything else, including a credential that fails to verify locally, shows the service's own text rather than a blank screen. A5b. Every redemption error A revoked code is deliberately indistinguishable from an unknown one - both say 'isn't valid', so a guesser learns nothing from a revocation. Support tells them apart with codes status; the wire does not. ‹ Settings Supporter perks Legend ended 24 August 2027 Your badge has ended The months you paid for have all been issued. The badge stopped showing on your profile; nothing was cancelled and nothing is owed. Add more months A6b. The balance runs out An exhausted balance is not an error: the service returns no credential and a zero-balance statement, and the app says so plainly. Prepaid means it simply stops. badges.simplex.chat/#/pay How would you like to pay? Monero is temporarily unavailable Try another method, or come back later. Card Visa, Mastercard Bitcoin on-chain Monero unavailable Continue simplex.chat/contact B4b. A provider is not configured 503 provider_unavailable from /api/checkout. The method is shown and disabled rather than omitted, so an operator who forgot a section sees it immediately instead of wondering why nobody pays in Monero. badges.simplex.chat/#/checkout These prices have changed Start again with the current prices The badge you chose was repriced while you were deciding. Nothing was charged. Start again price_disabled / offer_disabled / offer_mismatch simplex.chat/contact B5b. The catalog moved underneath Prices are checked at checkout and only there. A deprecated price is still honoured for someone mid- flow; a disabled one is refused. Repricing appends a new price rather than editing the old, so this is rare but reachable. badges.simplex.chat/#/checkout Too many attempts Try again in 46 seconds The Pay button is disabled until then. Pay with Monero 429, with Retry-After. The polling loop backs off to that value rather than treating it as a failure. simplex.chat/contact B5c. Rate limited Five checkout requests a minute per IP, because each one reaches a payment provider. Order polling gets sixty. The redemption path has no IP at all - it runs over SimpleX RPC and is throttled per signer instead. badges.simplex.chat/?order=8f3a...c21e This invoice expired 0.734 XMR arrived, which is not the full amount The rate window has closed, so the shortfall is no longer meaningful. Quote the reference below and we will sort it out. REFERENCE K7M2Q Start a new invoice Never shows the code, and never the ?order= URL. simplex.chat/contact B6b. Expired, and underpaid The one state that needs a human. An expired-but-paid invoice still settles later - late on-chain settlement is routine and moves the order to paid - but an underpaid one stops here with the reference support resolves by. badges.simplex.chat/?order=8f3a...c21e This code has been redeemed The code is no longer shown here It was redeemed on 2 September. If that was not you, get in touch. Legend, 12 months paid 24 August The order stays; the capability does not. simplex.chat/contact B7b. The page outlives the code Disclosure ends at redemption, at revocation, or 30 days after settlement. The order is still here because support resolves a reference against it - but the URL stops being equivalent to the code, which is the whole point. Continue in browser answers all three questions, so the site opens at B5 the code goes back to A5 the only thing that crosses from the site to the app Design document. App screens are drawn in the iOS idiom; Android and desktop differ only in chrome. The site is drawn in its own idiom - one centred column at max-width 560, generous whitespace, accent #0053D0 from website/tailwind.config.js - and is deliberately not a copy of the app's. Badge artwork is the shipped art, taken verbatim from MR/images/badge_{supporter,legend}.svg. One deliberate deviation from the plan: D2 specifies the SimpleX logo as the site's only image, but the tier cards here carry the badge art too, on the grounds that someone choosing between two badges should see them. Everything else follows D2 as written. Built today: the service schema, the pricing catalog, the ledger, code derivation and classification, credential signing, the RPC dispatcher and the operator CLI. Design, not yet built: every screen above, the web listener and its endpoints, both payment providers, and the client redeem path. Store purchase is removed on iOS and Play for the duration of this plan: store evidence is not verified, so a store purchase would charge for a badge that is never issued.
\ No newline at end of file