A lit pad kept its grey text and only its border turned orange, so pads
looked unhighlighted next to every other key. Cause was cascade order,
not logic: .pad is a single-class selector like .lit, so equal
specificity meant whichever came last won, and .pad was declared after.
The state classes now sit at the bottom of the file with a comment
saying why, and a lit pad computes rgb(255,74,0) for text and border.
native.ts reported nothing when haptics failed because I wrote
catch(() => {}) and discarded the reason. It now reports once per
distinct failure - enough to read in logcat, quiet enough not to spam on
every key press.
That reporting shows the software path is fine: isNativePlatform true,
Haptics available and bridged, VIBRATE granted, and both impact and
vibrate resolve without rejecting. So the silence is below the bridge -
most likely the phone's own touch-vibration setting - and not something
this code can detect.
141 tests, typecheck clean, installed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four things reported on the device, all real.
Tapping a modifier did nothing. setLayer was only reachable from a
search result or the layer sheet, so the reference's latch was simply
never ported. It is now, with the semantics intact rather than reduced
to a toggle: hold to peek and it lifts away, tap to lock and it stays,
tap again to release, and reading a lit key while holding a modifier
spends that modifier so lifting drops it. Knobs and pads never latch,
which is what NOLATCH is for. held is now the source of truth and the
layer key is derived from it, as in the reference.
That needed per-control release events. Panel knew which control each
pointer held and threw it away; it now reports onRelease before the
gesture-wide callback, because the latch decides hold-versus-tap from
how long one key was down.
Haptics and the hardware back button were missing entirely - Phase 1 did
both in native.js and the port had no equivalent. native.ts adds them,
no-ops in a browser so the dev server is unaffected. Back owns the whole
stack: sheet, then Explore, then exit.
Grade haptics fire from the transition into answered, not from the four
dispatch sites. Grading happens in the reducer, so deciding correctness
again at each call site would be a second source of truth free to drift.
PINGPONG overflowed its key. Lit keys show the entry's short label, which
comes from the data and can be one unbreakable word; the soft hyphens
only cover printed labels. Keys now break anywhere and clip.
141 tests, typecheck clean, installed and running on the device.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>