Prior: clockoutRemainingSec rolled forward to tomorrow the moment
target <= now, so the panel jumped 1s → 86399s with no observable
"zero" — the most expected moment of the day was silent.
Now:
- clockoutRemainingSec returns 0 when past today's clockout (sits
at 0 until midnight rolls the calendar component)
- WorkerStore detects the >0 → 0 edge in tickFire, fires per-day-
deduped celebration (notification + Glass × 3 + panel banner ~5s)
- SoundPlayer.playClockoutCelebration: Glass.aiff × 3 with 0.6s gap
(joyful 1.8s shot, not the sit Morse's 15s nag)
- ClockoutView overlays a lime→tomato gradient banner driven by
store.clockoutCelebrationActive
- tipText rewrite — old text said "不会响铃" which contradicts
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Office-survival toolkit. Five tabs in the notch:
- 🍅 番茄钟: 25/5 focus/break with circular ring timer + tally.
- 🪑 久坐: count-up since last break, dock-bounce alert at 45min.
- 💧 喝水: animated cup, daily goal tracking with progress dots.
- 🏃 下班: H:M:S countdown to clock-out hour with gradient bar.
- 🎉 周末: 天/时/分 to next Saturday + rotating 打工语录.
100% local. UNUserNotificationCenter for alerts, dock-bounce
fallback when authorization denied. UserDefaults persistence.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>