Say Paused on both halves while the clock is stopped
A stopped clock looked exactly like a running one. The panel keeps its accent while paused, and isLive() counts a paused side as live, so the delay bar just freezes mid-drain — nothing about either half says the clocks aren't moving. The only tell was the play glyph in the bar, which is small, grey, and upside down for one of the two players. It matters most in the state the app is designed to land in: a match restored from localStorage comes back paused on purpose, and nothing said so. So both halves say it in words, under the delay bar, sized to sit between the bar and the clock: wider than the bar at every screen size, narrower than the clock at m:ss. The band is tighter than it sounds, since "3:00" is only about 2.2x the bar, so part of the width comes from the tracking rather than the glyph size. Measured from 320 to 1024px wide it lands at 1.3-1.4x the delay row and 74-82% of the clock. It is wider than the clock in the last ten seconds of a reserve, where the readout drops to three narrow characters — unavoidable inside these bounds, and the two are never confusable at four times the height. The word hangs off the delay row rather than joining .stack, so the big clock does not move by a pixel when the clock stops. It cannot live inside .delay either: that is opacity:0 whenever no delay is running, and a child can never be more opaque than its parent, which would lose the word on the waiting half, on a spent delay, and at a delay of 0. It takes no colour of its own, so it wears whatever ink the clock above it is wearing, in every theme. The play button lights up while paused, the same --icon-hot a held Reset uses. Both toggles live in render() rather than in paintPlay(), for the reason the comment there already gives: state written from the render loop cannot go stale. Screenshot 2 is redone — the score sheet pauses, so the word shows behind the scrim. The other four are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+66
-7
@@ -182,6 +182,49 @@
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
/* ---------- paused ----------
|
||||
A stopped clock used to look exactly like a running one: the panel keeps its
|
||||
accent, and the delay bar simply freezes mid-drain. The only tell was the
|
||||
play glyph in the bar — small, grey, and upside down for one of the two
|
||||
players. So both halves say it in words.
|
||||
|
||||
Hung off the delay row rather than added to .stack, so the big clock does
|
||||
not move a pixel when the clock stops — the same promise .btn--vacant makes
|
||||
in the bar, and the reason .delay fades rather than hides. It also cannot
|
||||
live *inside* .delay: that is opacity:0 whenever no delay is running, and a
|
||||
child can never be more opaque than its parent, which would lose the word on
|
||||
the waiting half, on a spent delay, and at a delay of 0. */
|
||||
.foot{position:relative}
|
||||
.paused{
|
||||
position:absolute;
|
||||
top:100%;
|
||||
left:50%;
|
||||
/* the bar and its number sit dead centre of the panel (see .dnum), so
|
||||
centring on that row centres on the panel, whatever the count reads */
|
||||
transform:translateX(-50%);
|
||||
/* a clear step below the bar rather than .stack's gap: near enough to belong
|
||||
to the delay row, far enough not to crowd it */
|
||||
margin-top:clamp(21px,5.8vw,41px);
|
||||
white-space:nowrap;
|
||||
line-height:1;
|
||||
/* Wider than the delay bar, narrower than the clock — the band is tighter
|
||||
than it sounds, since "3:00" is only about 2.2x the bar. The crossovers
|
||||
are .track's own (20vw between 360 and 700px wide), so the word holds its
|
||||
proportion to the bar at every size instead of drifting at the ends.
|
||||
Part of the width comes from the tracking rather than the glyph size:
|
||||
spaced letters carry "held" without shouting over the clock. */
|
||||
font-size:clamp(34px,9.4vw,66px);
|
||||
font-weight:700;
|
||||
letter-spacing:.08em;
|
||||
/* no colour of its own: it inherits the panel's, which is what the clock and
|
||||
the delay count are already wearing. Each theme picks its own --accent-ink
|
||||
(white on most of them), so the word follows the palette without a rule
|
||||
per theme, and the paused half never has two different inks on it. */
|
||||
opacity:0;
|
||||
transition:opacity .16s ease;
|
||||
}
|
||||
.paused.on{opacity:1}
|
||||
|
||||
/* ---------- control bar ---------- */
|
||||
.bar{
|
||||
background:var(--bar);
|
||||
@@ -199,6 +242,9 @@
|
||||
cursor:pointer;
|
||||
}
|
||||
.btn:active{color:var(--icon-hot)}
|
||||
/* the way back from a paused clock, lit like a held Reset: the bar is the only
|
||||
thing either player can act on while the clocks are stopped */
|
||||
#playpause.lit{color:var(--icon-hot)}
|
||||
.btn[aria-pressed="false"]{color:#5E5954}
|
||||
.btn svg{width:clamp(23px,6.4vw,32px);height:auto;display:block}
|
||||
.btn svg[hidden]{display:none}
|
||||
@@ -432,9 +478,12 @@
|
||||
<div class="stack">
|
||||
<div class="time" data-time>3:00</div>
|
||||
<div class="out" data-out hidden>Out of<br>time</div>
|
||||
<div class="delay" data-delay>
|
||||
<span class="track"><i class="fill" data-fill></i></span>
|
||||
<span class="dnum" data-dnum>15</span>
|
||||
<div class="foot">
|
||||
<div class="delay" data-delay>
|
||||
<span class="track"><i class="fill" data-fill></i></span>
|
||||
<span class="dnum" data-dnum>15</span>
|
||||
</div>
|
||||
<div class="paused" data-paused>Paused</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -498,9 +547,12 @@
|
||||
<div class="stack">
|
||||
<div class="time" data-time>3:00</div>
|
||||
<div class="out" data-out hidden>Out of<br>time</div>
|
||||
<div class="delay" data-delay>
|
||||
<span class="track"><i class="fill" data-fill></i></span>
|
||||
<span class="dnum" data-dnum>15</span>
|
||||
<div class="foot">
|
||||
<div class="delay" data-delay>
|
||||
<span class="track"><i class="fill" data-fill></i></span>
|
||||
<span class="dnum" data-dnum>15</span>
|
||||
</div>
|
||||
<div class="paused" data-paused>Paused</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -709,7 +761,8 @@
|
||||
scoreLines: [].slice.call(p.querySelectorAll(".line:not(.line--moves)")),
|
||||
delay: p.querySelector("[data-delay]"),
|
||||
fill: p.querySelector("[data-fill]"),
|
||||
dnum: p.querySelector("[data-dnum]")
|
||||
dnum: p.querySelector("[data-dnum]"),
|
||||
paused: p.querySelector("[data-paused]")
|
||||
};
|
||||
});
|
||||
var btnPlay = document.getElementById("playpause");
|
||||
@@ -886,6 +939,11 @@
|
||||
setText(el[i].dnum, Math.ceil(dLeft / 1000));
|
||||
}
|
||||
|
||||
// both halves, not just the one whose turn it is: the waiting player's
|
||||
// clock is stopped too, and they are the one who can't read the bar's
|
||||
// play glyph the right way up
|
||||
el[i].paused.classList.toggle("on", st.phase === PAUSE);
|
||||
|
||||
setAttr(el[i].root, "data-state",
|
||||
(st.phase === FLAG && i === st.active) ? "flagged"
|
||||
: (i === st.active && st.phase !== IDLE) ? "active" : "idle");
|
||||
@@ -901,6 +959,7 @@
|
||||
// nothing running to pause: before a game's first tap, and after a flag,
|
||||
// where togglePause is inert anyway — the game is over, Reset is the way out
|
||||
btnPlay.classList.toggle("btn--vacant", st.phase === IDLE || st.phase === FLAG);
|
||||
btnPlay.classList.toggle("lit", st.phase === PAUSE);
|
||||
}
|
||||
|
||||
function loop(){ render(); requestAnimationFrame(loop); }
|
||||
|
||||
Reference in New Issue
Block a user