Offline caching: - BackgroundRefreshManager.preCacheArticles() fetches top article per story (score ≥60, up to 20 stories) and stores as CachedArticle in SwiftData - Runs after every BG fetch AND after every foreground sync via StoryStore - Articles are available in ArticleReaderView offline without ever opening them Pull-to-refresh reshuffle when nothing new: - loadStories(refresh:) now returns newCount (genuinely new story IDs) - If server returns 0 new stories, feed merges in any BG-cached stories not already in the live feed, then re-sorts by signal score (reshuffle) - seenSnapshot is always cleared so everything re-ranks fresh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>