Signing in connects the shared client to the new account and stores its
credentials before the account registry takes it. With ten accounts the
registry refused, but nothing undid the connect: every request then went
out as the new account while the app still showed the old one. A
sign-in link made this easy to reach, since it opened "Add account"
without the limit check the menus have.
- A failed registration now restores the previous connection and drops
credentials the registry never took.
- Adding an account to a full registry is refused before a sign-in code
is spent or a browser sign-in starts, with "Remove an account in
Settings to add another one."
Every failed redeem read "That code has expired": a code already used,
a webmail without pairing (404), a rate limit, a server error and a
network failure all looked the same, and a non-JSON answer surfaced as a
raw parse error. The app now reads the webmail's `invalid_code`,
`expired_code` and `used_code` answers (webmail 1.11's catch-all 400
reads as "expired or already used"), gives up after 15 s, and names the
host involved; a failure after the code was redeemed says the phone was
signed in but could not reach the mail server.
- `loginViaPairing` accepts `flow: 'password'` bundles (an app password,
or the account password from servers without OAuth) in normal and
add-account mode, and never redeems the same code twice.
- A `pair` link must point at an https webmail (loopback http for
development); `pair/?` is accepted too.
- A token refresh that answers 200 with a non-JSON body keeps the
account instead of signing it out.
The sign-in screen showed the auth store's raw English error ("Session
expired", "Invalid username or password") as the notice title. It now
runs it through describeLoginError like every other sign-in failure,
which also learns to explain an expired session with the webmail's
login.session_expired copy. The back and close buttons of the sign-in
steps get screen reader labels, and the email placeholders use the
webmail's translated example address.