diff --git a/site/live.html b/site/live.html
index dd121c0c9..b53a0a916 100644
--- a/site/live.html
+++ b/site/live.html
@@ -238,9 +238,9 @@ main{padding-bottom:var(--sec)}
-
blockschainincluded, paidpendingexcludedjust arrivedselected chainone lane per miner, colour from its id; hover or tap a block
+
blockschainincluded, paidpendingexcludedjust arrivedselected chainone lane per miner, colour from its id; hover a block, or tap it to keep its details up
finalityfinallocked checkpointproposedreads "paused" whenever under two thirds of the weight is signing
-
provingshard plannedprovingverified, prover colourpaidwhere proofs land behind the tiphover or tap a cell
+
provingshard plannedprovingverified, prover colourpaidwhere proofs land behind the tiphover a cell, or tap it to keep its details up
@@ -325,7 +325,10 @@ main{padding-bottom:var(--sec)}
var pxPerSec=40,targetPx=40,bps=0,live=false,serverNow=0,serverAt=0,frozenAt=null,note='';
// ?window=N (30 to 300 s): a fixed long view for diagnosis, the API returns the same span; the default stays the adaptive scale
var fixedWindow=Math.max(0,Math.min(300,Number(new URLSearchParams(location.search).get('window'))||0));if(fixedWindow&&fixedWindow<30)fixedWindow=30;
- var running=false,needSize=true,inView=true,ptrX=-1,ptrY=-1,pin=null,laneLast=[],laneRun=[],lagNote='';
+ var running=false,needSize=true,inView=true,ptrX=-1,ptrY=-1,laneLast=[],laneRun=[],lagNote='';
+ // pin: a tapped or clicked block (i = -1) or shard cell (i = shard index). It stays until a tap or click lands elsewhere,
+ // Escape, or the block leaves the strip (then pinFade holds it for a 200 ms fade). Hover never touches it.
+ var pin=null,pinFade=null,PIN_FADE=200,closeRect=null,panelRect=null,down=null,TAP_SLOP=10;
var TOP=20,BOT=12;
// 12 hues that sit beside ember on obsidian; the index comes from the short id, so a miner (or a prover) keeps its colour across reloads
var PAL=['#5CB8FF','#3FD39A','#F5C542','#C49BFF','#FF7AA8','#8FD15F','#FFB08A','#6F8CFF','#D9E25A','#FF8FD6','#4FD8D8','#E0A96D'];
@@ -393,20 +396,41 @@ main{padding-bottom:var(--sec)}
function link(a,b){var d=Math.max(S*0.6,Math.min(48,Math.abs(b.px-a.px)*0.5));x.moveTo(a.px,a.py);x.bezierCurveTo(a.px+d,a.py,b.px-d,b.py,b.px,b.py);}
// shard cells: a column under each chain block, shard 0 at the top; sizes from the zoom level, never wider than the block
function cellGeom(n){var avail=PROV_H-12,gap=2,ch=Math.min(narrow?7:9,Math.floor((avail-(n-1)*gap)/Math.max(1,n))),cw=Math.max(3,Math.min(narrow?10:12,Math.round(S*0.7),Math.round(pxPerSec*0.85)));return {ch:ch,cw:cw,gap:gap,top:BH+FIN_H+6+Math.max(0,Math.floor((avail-(n*ch+(n-1)*gap))/2))};}
- function hit(){
- // returns {b, i}: a block (i = -1) in the blocks strip, or a shard cell (i = shard index) in the proving strip
- var qx=ptrX,qy=ptrY;
- if(pin){var p=byHash[pin.h];return p&&p.on?{b:p,i:pin.i}:null;}
+ function hitAt(qx,qy,touch){
+ // returns {b, i}: a block (i = -1) in the blocks strip, or a shard cell (i = shard index) in the proving strip.
+ // A finger is wider than a pointer: a touch gets a larger radius, the nearest target still wins; hover is unchanged
if(qx<0)return null;
- if(qy