- README: add lock-screen section, refresh test list (13 offline tests),
updater fallback order, data locations, architecture tree
- STATE.md: v1.0.20, current release.cjs flow (no --skip-github), M11-M13
- ci.yml: actions/cache for the ~100MB Electron binary keyed on lockfile
- .gitignore: ignore .env.* but keep committed templates
- scripts/archive-releases.cjs moved in from tmp-test; KEEP_TAG is now a
required CLI arg (a hardcoded default is how the wrong version gets wiped)
- lockShortcuts: isPanicLockChord matches input.code ('KeyL') so Dvorak and
non-Latin layouts trigger Ctrl+L lock correctly
- settings: drop the dead single-option update-channel Select from About tab
- Workspace/App: memo(IconRail/LayoutFlyout), useMemo layoutMenu keyed on
language, useCallback onOpenSettings; drop unused IconRail onSplit prop
- remove the application menu while locked (lockMenu.ts): Alt reveals the
default menu and its mouse-clickable Reload/DevTools/Zoom items bypass
before-input-event entirely; menu is rebuilt from the default template on
unlock, startup-restored locks covered from initLockController
- extract the keyboard classification into pure lockShortcuts.ts
(isLockBlockedShortcut/isPanicLockChord) with a table-driven test
(lock-shortcuts.mjs, 29 cases) — the v1.0.17 lockout escaped CI because
this decision lived inline in createWindow()
- reserve Ctrl+L in the global show/hide shortcut recorder: a global
registration intercepts the chord at OS level and silently disables the
panic lock
- skip auto-repeat keydowns in the panic-lock branch (held Ctrl+L on an
unconfigured app re-read lock.json + settings.json per repeat)
- LockScreen: re-sync the cooldown clock on visibilitychange/focus/pageshow
so a suspended renderer timer cannot leave the password input disabled
past the real deadline