hypercal 2.1.7

Typed times, search that ignores accents, readable text in every theme, and
a long list of fixes found by a new round of property, mutation and browser
tests.

**Type a time.** With a mouse, the time panel has a text field above the
hour and minute sliders. It takes "14:30", "2:30pm" or "1430", so any minute
can be set, not just quarter hours. While focused it lists times in
15-minute steps, filtered by what was typed. It follows the 12-hour clock
setting. Touch keeps the wheel.

**Search ignores accents.** "munchen" finds "München", "strasse" finds
"Straße", "soren" finds "Søren", and case is ignored in any script, not
just A to Z. This holds for encrypted calendars, offline search and the
Android app too.

**Readable in every theme.** All text now meets WCAG AA contrast: faint
labels, accent-coloured text, event titles on every event colour, and avatar
initials. The accessibility check runs with no exceptions.

**Open .ics files on the desktop.** hypercal appears under "Open With" for
calendar files and can be their default app. A file opened while hypercal
is running is handed to the running window.

**Fixed on Android.**

- Tapping an event opens its details and keeps them open.
- Deleting an event worked, but was reported as failed.
- Reminders match the server's: events from a phone calendar are no longer
  announced twice, and reminders set after the start are no longer dropped.

**Fixed: dates and daylight saving.**

- The week grid, the editor and "this and following" on the days clocks
  change, and "find a time" keeps working hours right on the day DST ends.
- The Repeat preview shows the dates the server will store.
- Search kept a repeating event out when its next date fell exactly on the
  end of the searched range.

**Fixed: iCal.**

- Events whose TZID is a bare UTC offset, such as REWE's delivery slots,
  import instead of being rejected.
- Events in the hour a zone falls back keep their time through export and
  import.
- A long rule with cancelled dates, a folded Outlook UID, and quotes or line
  breaks in text no longer change or break an event on its way through iCal.
- CalDAV clients asking for events by hrefs with `&`, or in their own
  namespace, get them.

**Fixed: everything else.**

- Files added while editing one date of a repeating event are saved with
  "All events"; with a narrower scope the app says why they are not.
- An offline edit followed by a delete no longer conflicts with itself, and
  a replaced offline conflict no longer returns after a reload.
- A dropped .hypercalendar file imports again.
- A 30-day reminder whose moment lands exactly on a tick is sent.
- An empty `VAPID_SUBJECT` no longer turns off push notifications.
- A second quick key press is no longer lost, and every switch in Settings
  has a name for screen readers.
- Live updates stop when you sign out right after start.

**Under the hood.** Property tests with fast-check across recurrence, iCal,
offline sync and the Android backend; mutation testing with Stryker; the
Android backend checked against the server's; browser specs for the feed,
calendar settings, attachments, account and admin flows, with the mock API
checked against the real response schemas; and one coverage report merging
unit and browser tests. CI keeps Playwright traces, hunts flaky tests
weekly, and gives lint the memory it needs.