diff --git a/plans/2026-07-25-bookmark-list-favorites-design.md b/plans/2026-07-25-bookmark-list-favorites-design.md
new file mode 100644
index 0000000..380380e
--- /dev/null
+++ b/plans/2026-07-25-bookmark-list-favorites-design.md
@@ -0,0 +1,163 @@
+# Bookmark list ordering, latest-chapter display, and favorites
+
+Date: 2026-07-25
+Status: Approved by user, pending implementation plan
+
+## Context
+
+Three requested additions to the Bromite userscript's bookmark panel
+(`userscript/manga-bookmark.user.js`) plus one incidental bug found while
+verifying feasibility live:
+
+1. Bookmark list should show the most-recently-read manga first.
+2. Show not just the last chapter *read*, but the latest chapter *available*
+ for that manga, if feasible.
+3. A favorites mechanism: a second list/tab showing only favorited manga,
+ without removing favorited manga from the normal list.
+
+## 1. Reorder by latest read (already implemented)
+
+`reindex()` in `manga-bookmark.user.js` has sorted `state.list` by
+`(b.updated_at || 0)` descending since the very first commit
+(`f58d113`). `updated_at` is set whenever progress is recorded
+(`bookmarkCurrent`, `updateToCurrentChapter`, `setChapterManual`). No code
+change needed here — confirmed by decision: only an actual progress advance
+should reorder the list (not simply opening/re-reading an old chapter).
+
+The only risk to this existing behavior is introduced by features 2 and 3
+below, since both add new fields synced through the same PUT endpoint that
+currently (per existing CLAUDE.md) has the server set `updated_at`
+unconditionally on every upsert. See section 4.
+
+## 2. Latest available chapter
+
+### Feasibility (verified live via Playwright, 2026-07-25)
+
+- **Chapter reader pages only expose immediate neighbors.** On
+ `asurascans.com/comics/dungeon-odyssey-f886a8af/chapter/160`, the DOM
+ contains only chapters 159–161 (prev/next nav) — not the full list.
+- **Series pages list every chapter, newest first by default.** On
+ `asurascans.com/comics/dungeon-odyssey-f886a8af`, the series page's chapter
+ list panel contains one `Chapter N ...` per
+ chapter (verified: 162 links for a 162-chapter series, first is Chapter
+ 162). This is therefore the only reliable place to learn the true latest
+ chapter number.
+- Demonic's series page (`demonicscans.org/manga/Dungeon-Odyssey`) similarly
+ lists every chapter via `chaptered.php?manga=&chapter=` links,
+ interleaved with a "first chapter" quick-jump link. Taking `max()` of all
+ parsed chapter numbers (rather than assuming list order) is used for
+ robustness on this site.
+
+**Conclusion: latest-available-chapter data can only be refreshed when the
+user visits a bookmarked series' series page** (not on every chapter open).
+This is a real, disclosed limitation — not solved by polling, since the
+backend cannot fetch these sites itself (Cloudflare blocks server-side
+fetch, per existing CLAUDE.md constraint) and there is no reader-page source
+for it.
+
+### Behavior
+
+- New adapter capability: on `detect()` returning `type: "series"` for an
+ already-bookmarked series (`state.byKey[key]` exists), scan the page for
+ chapter links per the site-specific pattern below and compute the max
+ chapter number + its display label.
+ - Asura: `a[href*="/chapter/"]` where the href matches
+ `/chapter/([\d.]+)$/` and the link text matches `/Chapter\s+[\d.]+/`
+ (excludes the unrelated "First Chapter" quick-jump button, which lacks
+ that text pattern).
+ - Demonic: all `a[href]` matching
+ `/chaptered\.php\?manga=\d+&chapter=([\d.]+)/`; take the max parsed
+ chapter number across all matches (list order is not assumed reliable).
+- If the computed max differs from the bookmark's stored
+ `latest_chapter_num`, silently update `latest_chapter` (label) and
+ `latest_chapter_num` via the API — but this update must **not** change
+ `updated_at` / list order (see section 4).
+- Display: each list item's subtitle line becomes e.g.
+ `"Read: Chapter 12 · Latest: Chapter 15"` when latest is known and differs
+ from last-read; otherwise unchanged (`"Chapter 12 · asura"` as today).
+ Plain inline text, no separate badge/count UI.
+
+## 3. Favorites
+
+- New field `favorite: bool` on the bookmark record, synced through the
+ existing PUT endpoint (chosen over local-only storage so favorites persist
+ across devices/reinstalls, consistent with how the rest of the data
+ syncs).
+- Each list item gets a star toggle (☆ / ★) that flips `favorite` and PUTs
+ the updated bookmark. Toggling **must not** change `updated_at` / list
+ order (see section 4).
+- The panel gains two tabs above the bookmark list: **All** and
+ **★ Favorites**. Both apply the same sort (section 1). Switching tabs is
+ local UI state (not persisted) defaulting to "All". A favorited manga
+ continues to appear in "All" — tabs only filter which array is rendered,
+ favoriting never removes the bookmark from `state.list`.
+
+## 4. Backend change required: conditional `updated_at`
+
+Current CLAUDE.md / `store.go` behavior: `PUT /bookmarks/{key}` always sets
+`updated_at` server-side on every upsert. Once latest-chapter-capture and
+favorite-toggle both PUT through that same endpoint, this would reorder the
+list on every series-page visit or star click — contradicting the
+"reorder only on progress advance" decision from section 1.
+
+**Change:** `Store.Upsert` sets `updated_at = now()` only when:
+- the bookmark is new (no existing row for that key), or
+- `last_chapter_num` in the incoming payload differs from the currently
+ stored value.
+
+Otherwise the existing stored `updated_at` is preserved, even though other
+fields (`favorite`, `latest_chapter`, `latest_chapter_num`, cover, title,
+etc.) are still updated. This centralizes "what counts as a progress
+advance" as a single authoritative rule in the backend, applied consistently
+regardless of which device/browser performed the write.
+
+This is a deliberate deviation from the current CLAUDE.md wording ("server
+sets `updated_at`" unconditionally) and needs the doc updated to match.
+
+## 5. Asura redirect bug (bundled into this work)
+
+Verified live: `https://asuracomic.net/comics/dungeon-odyssey-f886a8af`
+returns an HTTP **301** with `Location: https://asurascans.com/` (root, no
+path) — a Cloudflare-edge redirect that discards the path *before any JS on
+asuracomic.net executes*. This contradicts the existing code comment
+("asuracomic.net currently 301s to asurascans.com", implying path
+preservation) and means any deep link on `asuracomic.net` currently lands
+the user on the asurascans.com homepage with page type `"other"` —
+bookmark/progress detection silently does nothing.
+
+There is no client-side fix: the userscript's `@match` for
+`asuracomic.net/*` never gets a chance to run for these URLs, since the
+redirect happens at the edge before the browser has a document to inject
+into. **Fix is documentation-only**: correct the misleading comment in
+`asura.matches()`/adapter notes and README to state that `asuracomic.net`
+deep links are currently broken, and the user should navigate via
+`asurascans.com` links directly. No behavior change to ship.
+
+## Data model summary
+
+`Bookmark` (backend `store.go`) gains:
+
+| field | type | notes |
+|---|---|---|
+| `favorite` | `bool` | default `false` |
+| `latest_chapter` | `string` | display label, e.g. `"Chapter 162"`; empty if never captured |
+| `latest_chapter_num` | `*float64` | nullable; null if never captured |
+
+SQLite migration: additive `ALTER TABLE bookmarks ADD COLUMN ...` for each,
+guarded against "duplicate column" errors so it's safe to run against the
+already-deployed database.
+
+## Testing
+
+- Go: table-driven tests for `Store.Upsert`'s conditional `updated_at` logic
+ (new bookmark, unchanged progress, changed progress, favorite-only change,
+ latest-chapter-only change).
+- Userscript: manual on-device verification (per existing project
+ convention — no JS test harness in this repo). Verify:
+ - list reorders only when a chapter is actually advanced, not on
+ plain re-visit or favorite toggle.
+ - latest-chapter capture fires on series-page visits and displays
+ correctly for both sites.
+ - favorite toggle persists across a panel close/reopen and a
+ `refresh()` (i.e. round-trips through the backend correctly).
+ - favorited manga still appears in "All" tab.