Replace the innerHTML full-rebuild in _render() with two paths:
- _renderFull(): used for first load, group-mode change, and deletions
- _appendBatch(n): append-only for infinite-scroll pages — O(batch)
instead of O(total). Existing <img> nodes are never destroyed,
eliminating the visual flash and unnecessary DOM churn.
Also:
- Extract _renderTile() helper (DRY tile HTML generation)
- Extract _observeSentinel() helper
- Scope _setupVideoThumbnails(startIndex) to only process new tiles
- Add data-group attribute on headers for efficient CSS.escape lookup
- Fix stale WebP references in comments (now JPEG)
- Add virtual scrolling idea to TODO-LIST.md for future evaluation
- JWT secret auto-generates and persists to <STORAGE_PATH>/.jwt_secret
- Remove setup token: first admin setup is open until system initialized
- Fix schema.sql: move CREATE EXTENSION pg_trgm/ltree to top
- Update login UI and auth.js to remove setup token fields