The flash line reserves one line, so a message that wrapped pushed the
screen below it down. #flash-msg no longer wraps: text too long for it is
cut with an ellipsis, and showFlash() puts the whole message in its title.
Every message is also reworded to at most 50 characters so none is cut,
and the add-token screens flash a fixed line for any error other than the
two lookup messages, logging the detail.
A new end-to-end test writes a message several lines long into the line
and fails if the line or the screen below it moves.
Model: opus-5-5
The dust-threshold field was the only validated input in Settings that rejected
without saying anything: the value silently changed back to the stored one with
no explanation. It now flashes "Please enter a whole number of gwei, zero or
greater." alongside the existing resync, matching the idiom the RPC URL field
already uses.
The parse moves to its own module and accepts plain decimal digits only, zero
or greater. Hex and exponent notation are refused rather than accepted: Number()
reads "0x10" as 16 and "1e3" as 1000, neither of which the previous parseInt
produced, and storing a number the user did not type is the same silent
substitution this change exists to remove.
The message must fit one line of the reserved flash area -- a wrapped message
pushes the settings view down, which the No Layout Shift policy forbids. That is
pinned by an end-to-end test measuring the rendered line height and the position
of the elements below it, in a single round trip because the flash clears after
two seconds.