BPM lower bound dropped 30 -> 5 (engine + ramp + slave-clock-in interval filter; pure
clamp choice, no engine reason for the higher floor). Very slow practice is now
possible. Sub-musical (<5) sits below the slave-decay timeout so wasn't worth pursuing.
Hamburger menu (☰ at the far right of the header, 3 thin recolorable rects; tap zone
covers the corner). Reuses the existing overlay / _ovbtns pattern - no new framework.
- Main menu (_show_menu): Save edits / Revert edits (dimmed when not _dirty) / Continue
on-off (live) / Settings > / Help > / About / Done.
- Settings sub-modal: LED brightness 5..50% in 5% steps, Speaker mode (Auto / Always /
Off, combining MUTE_SPEAKER + SPEAKER_AUTO_MUTE), MIDI Out on/off, MIDI Channel 1..16,
Clock Out on/off, Clock In on/off. < value > adjusters reusing the lane-editor row
pattern. Each tap calls _save_settings(); the modal redraws live.
- Help sub-modal: 3 paginated pages (Transport & Nav / Editing / Status & Hardware)
with < Done > nav.
- About sub-modal: version, free RAM, uptime, CircuitPython version, site URL. Defensive
about gc.mem_free and sys.implementation (CircuitPython-specific).
- Persistence to /settings.json: read in __init__ (_load_settings overrides defaults),
written on every change (settings are small + infrequent). NAKs silently if read-only.
Verified in the harness: all 4 modals render, settings.json round-trips (channel 10->11,
clock_out off->on persisted), tap zones populate as expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>