hypercal 2.1.6

Repeat rules you can actually edit, a Firefox extension, and one Settings
dialog.

**Custom repeat rules.** The Repeat controls no longer rewrite a rule they
cannot express. A rule such as "the 2nd and 4th Tuesday", often written by a
CalDAV client, now opens in a Custom mode that edits it as controls and as
raw RFC 5545 text side by side, with a live preview of the dates it makes. A
series can take extra dates, and its cancelled dates are listed and can be
restored, offline too. A malformed rule is refused with a message that says
what is wrong, instead of being stored and silently producing nothing.

**Firefox extension.** Firefox on the desktop cannot install the PWA, so
there is now an extension:

- today's and next week's agenda in the toolbar popup and the sidebar, with
  a countdown badge and a Join button for meeting links;
- quick add from the popup, the sidebar or the address bar
  (`cal fri 14:00 standup`);
- right-click an .ics link to import or subscribe to it, or selected text to
  open hypercal's new-event editor filled in from it, in English or German;
- reminders as Firefox notifications.

It talks to a new `/ext` API, authenticated with an app password. The API is
off until an admin turns on Settings, Admin, Browser extension access. The
`.xpi` attached to this release is unsigned: Firefox release and ESR refuse
it, while LibreWolf, Developer Edition and Nightly install it once
`xpinstall.signatures.required` is set to false.

**One Settings dialog.** "Manage account" in the avatar menu is now
Settings, with Account, Connectors (CalDAV, MCP and app passwords) and Tasks
as tabs. The separate gear button is gone. The week, day and month titles
leave out the year while it is the current one.

**Copy by dragging.** Hold Ctrl when you drop an event in the week view to
copy it rather than move it, as a drop between two windows already did.

**Removed: voice control.** The microphone button, the voice setting and the
Vosk speech model are gone, and the Android app no longer asks to keep the
screen awake.

**Fixed.**

- A repeat rule that can never match, such as the 30th of February, arriving
  over CalDAV or MCP could stall every request that touched it. Expansion
  now stops at the end of the range it needs.
- Exporting to .ics or syncing over CalDAV could rewrite a rule with
  positioned weekdays, such as the last Friday of the month, into a
  different one. The rule now goes out exactly as stored.

**Under the hood.** The CI pipeline is split into one file per stage, and
lint now enforces that the backend only imports what the Android build can
run, and flags promises nobody awaits.