Tablet touch targets were cramped (30px +/- buttons). Swap to modal UX:
- New TimerModal component handles both 'control existing' and
'create new'. 84px countdown, 56px min button height, 3×2 adjust
grid (-5m, -1m, -10s, +10s, +1m, +5m), big destructive cancel/stop.
Create view has 7 duration presets (1..60 min), label input with
shortcut chips (Чайник, Паста, Яйца…), gradient 'Запустить' CTA.
- TimerHomeWidget cards are now full tap targets — open control modal
on press. + button in header opens create modal. Inline buttons
removed. Subtle hint text 'тап чтобы изменить'.
- Ticking countdown inside modal stays fresh via shared timers state:
while modal is open we look up the current timer in active[] by id
and re-pass to modal on every tick. When timer disappears
(cancelled / expired >30s), modal auto-closes.
UI:
- Replace Notes column on Home bento with TimerHomeWidget. Shows all
active timers as stacked cards with big 30px countdowns, per-timer
+1/-1 minute buttons and cancel. Colors: indigo default, amber in
last 10s, red when expired. Empty state suggests voice command.
- Existing chip TimerWidget (bottom-right) kept for ambient view on
other tabs — redundant on Home, but harmless.
API:
- /api/voice/timer accepts cookie OR bearer (browser widget cancel
works with user's auth_token cookie; Python script uses bearer).
- New action 'adjust' — shifts endsAt by delta_seconds. Clamps so
endsAt never goes into the past.
- Cancel now supports {label} in addition to {id} (fuzzy substring
match, most-recently-started wins). Emits timer_cancel with id+label
so clients can refresh.
- findByLabel / adjustTimer helpers in lib/timers.ts.