Lift the chat compose bar's byte budget into a reusable gauge and reuse it
wherever a field feeds a size-capped LoRa packet.
- prompt.py gains byte_counter/byte_style and the DM/CHANNEL byte limits, plus
a byte_limit option on TextScreen: a field so limited rides the shared
used/limit gauge (right-pinned, green→yellow→orange→red) and blocks Enter
once the text tops the cap, with a "Too long by n bytes" note. Ui.text and
session.text thread byte_limit through.
- chat.py drops its private copies and calls the shared byte_counter; the
limits now come from prompt.py.
- The courier's "Message for …" entry passes byte_limit=DM_BYTE_LIMIT so a
queued message is gauged and capped the same way a live chat message is.
Also fixes a courier scheduling bug uncovered here: the "When it's next heard"
row carried the value None, indistinguishable from session.select's own cancel
sentinel — backing out of the picker silently queued the message. It now
carries its own WHEN_HEARD sentinel, so Esc cancels and the row means no
schedule.
Full suite green (806).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>