Once the readout held a time, drawReadout ran a canvas filter blur on the
graph canvas three times a frame (LED halo, digits, tenths). Chrome sends
every filtered draw through an offscreen layer the size of the whole
canvas, so the entire graph redrew about 5x slower: 60 -> ~17 fps while
panning a test graph (issue #77).
The blurred passes now go into a small cached layer (cachedLayer in
js/shared/run_timer.mjs) that is repainted only when the digits, LED,
size or zoom bucket change; each frame copies it with drawImage and draws
the crisp LED and digits directly. The readout is pixel-identical within
one colour step.