The minutes+seconds stepper is 302px wide. With a label beside it the Time
row needs about 422px of viewport, so it has been running off the right edge
of the settings sheet on every phone narrower than that — measured 19px off
a 390pt iPhone, 34px off a 375pt SE and 89px at 320. The "00 SEC" value and
its + button were the part that got cut.
Below 420px the row now stacks: label on one line, stepper right-aligned
underneath with slightly narrower value columns. That needs 262px against
the 276px available at 320px. Wider screens keep the inline layout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two real bugs, both worst on iOS:
The frame was taller than the screen in Safari. .app declared
`height:100dvh;height:100vh`, so the fallback won and 100vh on iOS is the
large viewport — the control bar and part of the bottom panel sat behind
the toolbar. The declarations are now in the right order.
The wake lock never came back. iOS drops it whenever the app backgrounds,
but `lock` was never cleared, so the `!lock` guard blocked every later
re-request and the screen started sleeping mid-game. It now listens for
`release` and clears the handle; against a stubbed API the old code stays
at one request after a release-and-return, the new code makes a second.
Smaller iOS fixes: claim a playback audio session so the ringer switch
doesn't silence the clock (this pauses other audio — the README says how
to drop it), resume the audio context when returning from the background,
suppress the long-press callout, keep sheet scrolling from rubber-banding
the app, back 88dvh with 88vh, and name the home-screen icon.
Untested on real hardware — there's no WebKit engine here, so this is a
code audit plus a Chromium regression run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three buttons left 84.7px each at a 320px viewport against 81.2px of
intrinsic content, so the horizontal padding drops to 6px and the label is
nowrap — about 11px of slack instead of 3.5px.
paintPresets() needed no change: it reads .preset from the DOM and matches
on both base and delay, which the new preset makes load-bearing since two
now share a delay and two share a base. Stepping the delay down from
3m / 15s correctly lights 3m / 12s rather than staying dark.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The armed ring looked a couple of pixels low. The ring was already exactly
centred on the button — measured 0.00px off — but the glyph wasn't: its arc
is a circle centred at (12,11) in a 24-unit viewBox, so the ring and the
glyph's circle were drawn as two almost-concentric circles about 1.8px
apart, which reads as misalignment much louder than a single shape would.
Shifting the glyph down one unit puts its circle at (12,12), concentric with
the ring to 0.00px. It also fixes the icon sitting high next to its
neighbours — reset was the only one in the bar whose ink was off centre
(dy=-1.32 against 0.00 for the gear and speaker).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The old confirmation ring was a scaling, fading border. It sat off-centre —
the ::before had no top/left, so it landed on its static position in the
grid rather than over the icon — and it read as a shrinking circle rather
than time running out.
It's now an SVG ring animated on stroke-dashoffset (0 to 113.1, the
circumference at r=18) and rotated -90deg to start at 12 o'clock, so it
unwinds like a progress ring in reverse over the same 2s as the timeout.
Explicitly centred on the button.
The stroke is currentColor against #reset.armed{color:var(--icon-hot)},
so it uses the pale flash every button already shows on :active instead of
the theme accent, and no longer changes with the colour setting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The play/pause and sound icons never toggled: SVGElement doesn't inherit
from HTMLElement, so it has no .hidden property and `svg.hidden = true`
only set a JS expando. Both icons then rendered at once because
`.btn svg{display:block}` out-specifies the UA's `[hidden]{display:none}`.
Fixed on both sides — a showIcon() helper sets the attribute, and the CSS
now honours [hidden]. Starting the clock by tapping a panel didn't repaint
the button either, which the working toggle made visible.
Also:
- conventional gear for the settings icon, replacing the clock glyph
- opening settings pauses the clock, and leaves it paused on close
- reset needs two taps within 2s, with a ring that drains over the window
- 2m/12s and 3m/15s presets atop the settings sheet; the highlight is
derived from cfg, so it clears and returns as the steppers move
- ask for persistent storage so settings aren't evicted, and fall back to
the defaults rather than NaN if a stored value is ever corrupt
sw.js cache bumped to v2 so installed devices pick up the new index.html.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>