diff --git a/.planning/quick/17-refactor-playlist-view-to-use-subpages-l/17-PLAN.md b/.planning/quick/17-refactor-playlist-view-to-use-subpages-l/17-PLAN.md
new file mode 100644
index 0000000..cd8730f
--- /dev/null
+++ b/.planning/quick/17-refactor-playlist-view-to-use-subpages-l/17-PLAN.md
@@ -0,0 +1,289 @@
+---
+phase: quick-17
+plan: 1
+type: execute
+wave: 1
+depends_on: []
+files_modified:
+ - frontend/src/components/playlist-details/playlist-details.ts
+ - frontend/src/components/playlist-view/playlist-view.ts
+ - frontend/index.ts
+autonomous: true
+requirements: [QUICK-17]
+
+must_haves:
+ truths:
+ - "Clicking a playlist in playlist-view navigates to a dedicated playlist-details subpage"
+ - "Playlist-details shows a header with back button, playlist icon, playlist name, and track count"
+ - "Playlist-details shows the full track list for that playlist with all existing interactions (click, dblclick, context menu, drag, phantom handling)"
+ - "Back button in playlist-details navigates back to the playlist list"
+ - "Playlist-view no longer expands/collapses playlists inline"
+ artifacts:
+ - path: "frontend/src/components/playlist-details/playlist-details.ts"
+ provides: "Playlist detail subpage component"
+ - path: "frontend/src/components/playlist-view/playlist-view.ts"
+ provides: "Playlist list view (no more inline track expansion)"
+ - path: "frontend/index.ts"
+ provides: "Navigation routing for playlist-details"
+ key_links:
+ - from: "frontend/src/components/playlist-view/playlist-view.ts"
+ to: "frontend/index.ts"
+ via: "CustomEvent('navigate', { view: 'playlist-details', playlistId, playlistName })"
+ pattern: "navigate.*playlist-details"
+ - from: "frontend/src/components/playlist-details/playlist-details.ts"
+ to: "frontend/index.ts"
+ via: "CustomEvent('navigate', { view: 'playlists' })"
+ pattern: "navigate.*playlists"
+---
+
+
+Refactor the playlist view from an expand/collapse dropdown pattern to a subpage navigation pattern, matching how genre-details and artist-details work. Clicking a playlist navigates to a dedicated playlist-details page with a header (back button + playlist icon + title + track count) and the full track list below.
+
+Purpose: Consistent navigation UX across playlists, genres, and artists — all use the subpage pattern.
+Output: New `playlist-details` component, simplified `playlist-view`, updated navigation routing.
+
+
+
+@/home/caleb/.config/Claude/get-shit-done/workflows/execute-plan.md
+@/home/caleb/.config/Claude/get-shit-done/templates/summary.md
+
+
+
+@frontend/src/components/genre-details/genre-details.ts (reference pattern — header + back button + content)
+@frontend/src/components/genres-view/genres-view.ts (reference pattern — click navigates to details)
+@frontend/src/components/playlist-view/playlist-view.ts (source — refactor this)
+@frontend/index.ts (navigation routing — add playlist-details case)
+@frontend/wailsjs/go/playlist/Service.d.ts (available backend APIs)
+@frontend/src/store/playlist-store.ts (playlist data store)
+@frontend/src/store/search-store.ts (search store — update SEARCHABLE_VIEWS if needed)
+
+
+
+
+From frontend/src/components/genre-details/genre-details.ts:
+```typescript
+// Header: back-button → avatar → genre-info (title + track count)
+// Content:
+// Back navigation: dispatches CustomEvent('navigate', { view: 'genres' })
+```
+
+From frontend/index.ts — navigation handler:
+```typescript
+// Genre details routing (line 73-82):
+case 'genre-details': {
+ const { genreName } = (e as CustomEvent).detail;
+ const genreEl = document.createElement('genre-details');
+ genreEl.setAttribute('genre-name', genreName);
+ mainContent.innerHTML = '';
+ mainContent.appendChild(genreEl);
+ break;
+}
+```
+
+From frontend/wailsjs/go/playlist/Service.d.ts:
+```typescript
+export function GetPlaylistTracks(arg1:number):Promise>;
+export function GetAllPlaylistsWithTracks():Promise>;
+export function AddTracksToPlaylist(arg1:number,arg2:Array):Promise;
+export function RemoveTracksFromPlaylist(arg1:number,arg2:Array):Promise;
+export function RenamePlaylist(arg1:number,arg2:string):Promise;
+export function DeletePlaylist(arg1:number):Promise;
+export function RemovePhantomTracks(arg1:number,arg2:Array):Promise;
+export function FindDuplicateTracksInPlaylist(arg1:number,arg2:Array):Promise;
+```
+
+From frontend/src/components/playlist-view/playlist-view.ts:
+```typescript
+// PlaylistEntry = { summary: playlist.Summary, expanded: boolean, tracks: playlist.Track[] }
+// SelectionHost + ContextMenuHost interfaces
+// Uses: PlayerController, PlaylistController, SearchController, SelectionController, ContextMenuController, FavoritesController
+// Track interactions: click (select), dblclick (play), contextmenu, drag source, phantom handling
+// Playlist-level: context menu (rename, delete, set-default), drag target, multi-select, sort
+```
+
+From frontend/wailsjs/go/models.ts:
+```typescript
+// playlist.Summary: { ID: number, Name: string, CreatedAt: string, UpdatedAt: string }
+// playlist.Track: { ID, Position, FilePath, Title, Artist, Album, CoverArtPath, CoverArtSmall, CoverArtMedium, CoverArtLarge, Duration, Phantom }
+// playlist.WithTracks: { Summary: Summary, Tracks: Track[] }
+```
+
+
+
+
+
+
+ Task 1: Create playlist-details component
+ frontend/src/components/playlist-details/playlist-details.ts, frontend/index.ts
+
+Create `frontend/src/components/playlist-details/playlist-details.ts` — a new LitElement component modeled closely on `genre-details.ts` but with all the track interaction capabilities currently in `playlist-view`'s `renderPlaylistBody`.
+
+**Component structure:**
+
+1. **Properties:** `playlistId` (Number attribute), `playlistName` (String attribute).
+
+2. **Header** (same layout as genre-details):
+ - Back button (dispatches `navigate` with `{ view: 'playlists' }`)
+ - Playlist avatar: 80×80 rounded square with `list` icon (wa-icon name="list") centered inside, using the same gradient background as genre-details' `.genre-avatar`
+ - Playlist info: h1 title + track count subtitle
+
+3. **Content area:** Render playlist tracks using the same track-item rendering pattern currently in `playlist-view`'s `renderPlaylistBody` method. This includes:
+ - "Play All" button at the top
+ - Track list with `` for normal tracks and phantom row rendering for phantom tracks
+ - All track interactions: click (selection), dblclick (play from playlist), right-click context menu, drag source
+ - Phantom track interactions: click (select), right-click context menu, locate button, remove button
+ - Active track highlighting (uses PlayerController)
+ - Track selection (uses SelectionController — this component is the SelectionHost)
+
+4. **Context menus:** Move the track-level context menu (play, add to queue, play next, remove from playlist, add to playlist submenu, favorites toggle, track details) and the playlist submenu from `playlist-view` into this component. Include ``, ``, and `` elements.
+
+5. **Data loading:**
+ - On connectedCallback, call `GetPlaylistTracks(this.playlistId)` to load tracks
+ - Listen for `Events.PlaylistTracksChanged` and `Events.PlaylistDeleted` to refresh/navigate back
+ - Implement a `refreshTracks()` method that re-fetches tracks after mutations
+
+6. **Drag target:** Support dropping tracks onto this playlist (from queue, track-list, or other playlists). Use the same `AddTracksToPlaylist` + `FindDuplicateTracksInPlaylist` flow currently in `playlist-view`'s `onPlaylistDrop`.
+
+7. **Drag source:** Support dragging tracks from this playlist to queue or other destinations. Same pattern as `playlist-view`'s `onTrackDragStart`/`onTrackDragEnd`.
+
+8. **Search integration:** Wire up SearchController. When search term is active, filter visible tracks (same logic as `playlist-view`'s `getVisibleTracks`). Add `playlist-details` to `SEARCHABLE_VIEWS` in `search-store.ts`.
+
+9. **Styles:** Use `designTokens` mixin. Copy the relevant styles from `genre-details` for the header section (`.back-button`, avatar, title, track-count). Copy track-item styles (`.track-item`, `.track-item.active`, `.track-item.selected`, `.phantom-row`, etc.) and context menu styles from `playlist-view`. Include `.play-all-button` styles.
+
+10. **Select-all support:** Listen for `shortcut:select-all` event (same as playlist-view does).
+
+**In `frontend/index.ts`:**
+- Add `import '@components/playlist-details/playlist-details.ts';` at the top with the other imports
+- Add a `case 'playlist-details':` block in the navigation switch, following the same pattern as `genre-details`:
+ ```
+ case 'playlist-details': {
+ const { playlistId, playlistName } = (e as CustomEvent).detail;
+ const el = document.createElement('playlist-details');
+ el.setAttribute('playlist-id', String(playlistId));
+ el.setAttribute('playlist-name', playlistName);
+ mainContent.innerHTML = '';
+ mainContent.appendChild(el);
+ break;
+ }
+ ```
+
+
+`npx tsc --noEmit` passes. The new component file exists with @customElement('playlist-details'), has back button, header, track rendering, context menus, drag support, and the index.ts routing case exists.
+
+ playlist-details component renders a header with back button + playlist icon + title + track count, displays playlist tracks with all interactions (select, play, context menu, drag, phantom handling), and navigating to `playlist-details` view works via index.ts routing.
+
+
+
+ Task 2: Simplify playlist-view to navigate instead of expand
+ frontend/src/components/playlist-view/playlist-view.ts
+
+Refactor `playlist-view.ts` to remove all inline track expansion and instead navigate to `playlist-details` on click. This is a significant simplification:
+
+**Remove from playlist-view:**
+1. The `expanded` field from `PlaylistEntry` interface (no longer needed — set type to just `{ summary: playlist.Summary; tracks: playlist.Track[] }`, keep tracks for count display and drag-drop track resolution)
+2. The `renderPlaylistBody` method entirely
+3. The chevron icon in `renderPlaylistItem` (no more expand/collapse)
+4. All track-level interaction handlers: `handleTrackClick`, `handleTrackDblClick`, `handleTrackContextMenu`, `onTrackDragStart`, `onTrackDragEnd`, `ensureSelectionScope`, `getSelectedTrackIDs`, `getSelectedFilePaths`, `removeSelectedTracks`, `removeSelectedPhantoms`, `handlePhantomClick`, `handlePhantomContextMenu`, `openPhantomResolver`, `removePhantomTrack`
+5. The `SelectionController` (no more track selection in the list view) and `SelectionHost` implementation (`getItemKey`, `getItemCount`, `onSelectionChanged`)
+6. The `ContextMenuController` and `ContextMenuHost` implementation, and all track-level context menu rendering (the `#context-menu` popup, `#playlist-submenu` popup)
+7. Remove `activePlaylistIndex` state
+8. The ``, ``, and `` elements from the render method (they move to playlist-details)
+9. The `isActiveTrack`, `isPhantomSelection`, `resolvePlaylistCoverArt`, `openTrackDetails` methods
+10. The `getVisibleTracks` and `filteredEntries` search-related track filtering (search on the list page can just filter playlist names)
+11. Remove `SelectionHost` and `ContextMenuHost` from the class declaration
+12. Remove imports that are no longer needed: `SelectionController`, track-info, track-details, phantom-resolver, duplicate-tracks-dialog, etc.
+13. Remove the `clearSelectionHandler` and `handleSelectAll` handlers since track selection is gone
+14. Remove the search-triggered auto-expand logic in `updated()` (the part that sets `expanded: true` based on track matches)
+
+**Keep in playlist-view:**
+1. Playlist list rendering (the grid of playlist items with name + track count)
+2. Playlist-level context menu (rename, delete, set-default) — the `#playlist-context-menu` popup
+3. Playlist-level selection (Ctrl/Shift+Click for multi-select of playlists for bulk delete)
+4. Create playlist functionality (new playlist button, create form)
+5. Import playlist button
+6. Sort toolbar (sort by name, created, modified, tracks)
+7. Drag-and-drop TARGET: dropping tracks onto a playlist item to add them (keep `onPlaylistDragOver`, `onPlaylistDragLeave`, `onPlaylistDrop`). Also keep empty zone drop and new-button drop.
+8. Search filtering (but simplified to just filter by playlist name, not tracks)
+9. Scroll position persistence
+10. PlaylistController for data loading
+
+**Modify `handlePlaylistHeaderClick`:**
+- Remove the expand/collapse toggle behavior for plain clicks
+- Instead, plain click dispatches navigation:
+ ```typescript
+ this.dispatchEvent(
+ new CustomEvent('navigate', {
+ bubbles: true,
+ composed: true,
+ detail: {
+ view: 'playlist-details',
+ playlistId: entry.summary.ID,
+ playlistName: entry.summary.Name,
+ },
+ }),
+ );
+ ```
+- Keep Ctrl+Click and Shift+Click for playlist multi-selection (same as before)
+
+**Modify `renderPlaylistItem`:**
+- Remove the chevron icon
+- Remove the `${entry.expanded ? this.renderPlaylistBody(...) : nothing}` conditional
+- The playlist-header row now just shows: playlist-icon (if favorites) + playlist-name + track-count
+- Keep the right-click context menu handler on the header
+- Keep the drag-over styling for drop targets
+
+**Simplify `filteredEntries`:**
+- Only filter by playlist name (remove the track title/artist matching since tracks aren't shown inline)
+
+**Remove styles that are no longer needed:**
+- `.chevron`, `.chevron.expanded`
+- `.playlist-body`
+- `.playlist-actions`, `.play-all-button`
+- `.track-item` and all its variants (`.active`, `.selected`, `.phantom`)
+- `.phantom-row`, `.phantom-caution`, `.phantom-path`, `.phantom-actions`, `.phantom-icon-btn`
+- `.tracks-empty`
+- Context menu styles for track-level menus
+
+**Update `loadPlaylists`/`refreshPlaylists`:**
+- Remove `expanded` from the mapped entries
+
+**Remove the `contextMenuStyles` import** if no longer needed (check if playlist-level context menu uses it — it does, so keep it).
+
+**Note:** The `PlaylistController`, `PlayerController`, `SearchController`, `FavoritesController` may still be needed. Keep `FavoritesController` for the favorites icon display. Remove `PlayerController` since active track highlighting is gone from the list. Keep `SearchController` for name-based search. Keep `PlaylistController` for data.
+
+
+`npx tsc --noEmit` passes. Verify playlist-view no longer has any `expanded`, `renderPlaylistBody`, `handleTrackClick`, `SelectionController`, or chevron references.
+
+ Playlist-view shows a clean list of playlists without inline track expansion. Plain-clicking a playlist navigates to playlist-details. Ctrl/Shift+Click still multi-selects. Right-click context menu still works for rename/delete/set-default. Drag-drop onto playlists still works. Create/import still works. Sort still works. Search filters by playlist name only.
+
+
+
+
+
+1. `npx tsc --noEmit` — TypeScript compilation passes with no errors
+2. Navigate to Playlists view — shows list of playlists without chevrons or expandable sections
+3. Click a playlist — navigates to playlist-details with header (back button, icon, title, track count) and track list
+4. Click back button — returns to playlist list
+5. Double-click a track in playlist-details — plays the track
+6. Right-click track in playlist-details — context menu works (play, queue, remove, etc.)
+7. Right-click playlist in list — context menu works (rename, delete, set-default)
+8. Ctrl+Click playlists in list — multi-select works for bulk delete
+9. Drag tracks from another view onto a playlist in the list — adds tracks
+10. Drag tracks from playlist-details to queue — works
+11. Create new playlist — form still works
+12. Import playlist — button still works
+13. Sort playlists — toolbar still works
+14. Search — filters playlist names in list view, filters tracks in detail view
+
+
+
+- Playlist navigation matches genre/artist pattern: list view → click → detail subpage → back button
+- No inline track expansion/collapse in playlist-view
+- All existing track interactions work in playlist-details (play, select, context menu, drag, phantom handling)
+- All existing playlist management works in playlist-view (create, import, rename, delete, sort, drag-drop target)
+- TypeScript compiles without errors
+
+
+