# Netflix-Style Sidebar — Homeflix Fixed-Rail Pattern

## The Problem
The old `NetflixSideNavigation` / `NexSidebar` / `UnspooledSidebar` had an expand/collapse system (80dp→260dp width animation) with HazeState blur, `focusGroup()`, and multiple pending-state booleans. This caused:
- Focus getting stuck or moving behind the sidebar
- Sidebar remaining open when it should close
- D-pad keys being eaten or blocked
- Back handlers conflicting with content navigation

## The Fix: Homeflix Fixed-Rail Pattern
From `/home/rurouni/Repos to copy/homeflix-tv-app-app-v2 (1).0/homeflix-tv-app-app-v2.0/`

### Architecture
- **Fixed 48dp icon rail** — no expansion, no labels, no width animation
- **Row layout**: `Row { sidebar(48dp Column) + Box(content, weight=1f) }`
- **NO global wrapper** — each screen owns its own sidebar if it needs one
- **Home screen** embeds the sidebar directly: `Row { NetflixSideNavigation() + Box(content) }`
- **Other screens** (Search, Movies, etc.) can use the same Row pattern or no sidebar

### Sidebar Component (138 lines)
```kotlin
@Composable
fun NetflixSideNavigation(
    selectedRoute: String,
    onNavigate: (String) -> Unit,
    modifier: Modifier = Modifier,
    onNavigateToContent: (() -> Unit)? = null,
) {
    Column(
        modifier = modifier
            .width(48.dp)
            .fillMaxHeight()
            .background(Color.Black.copy(alpha = 0.92f)),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        navItems.forEachIndexed { index, item ->
            NetflixNavIcon(...)
            if (index < navItems.size - 1) Spacer(Modifier.height(16.dp))
        }
    }
}
```

### Nav Icon (per-item)
```kotlin
@Composable
private fun NetflixNavIcon(
    item: NavItem, isSelected: Boolean,
    onClick: () -> Unit, onNavigateRight: (() -> Unit)?,
) {
    val scale by animateFloatAsState(
        targetValue = if (isFocused) 1.5f else 1.0f,
        animationSpec = tween(200),
    )
    Box(
        modifier = Modifier
            .size(36.dp).scale(scale)
            .background(
                when { isSelected -> accent; isFocused -> White(0.20f); else -> Transparent },
                RoundedCornerShape(6.dp),
            )
            .focusRequester(focusRequester)
            .onFocusChanged { isFocused = it.isFocused }
            .focusable()
            .onKeyEvent { event ->
                if (event.type == KeyEventType.KeyDown) {
                    when {
                        event.key == Key.DirectionRight -> { onNavigateRight?.invoke(); true }
                        event.key == Key.Enter || event.key == Key.DirectionCenter -> { onClick(); true }
                        else -> false
                    }
                } else false
            }
            .clickable(onClick = onClick),
        contentAlignment = Alignment.Center,
    ) {
        Icon(item.icon, contentDescription = null, tint = Color.White, modifier = Modifier.size(20.dp))
    }
}
```

### Home Screen Integration
```kotlin
Row(modifier = Modifier.fillMaxSize()) {
    NetflixSideNavigation(
        selectedRoute = "home",
        onNavigate = { route -> sidebarNavigate(navController, route) },
        onNavigateToContent = {
            currentFocusArea = FocusArea.HERO
            heroPlayButtonFocusRequester.requestFocus()
        },
        modifier = Modifier.focusRequester(sideNavFocusRequester),
    )
    Box(
        modifier = Modifier.fillMaxSize().weight(1f).background(Color.Black)
            .onKeyEvent { event ->
                if (event.type == KeyEventType.KeyDown && event.key == Key.Back) {
                    currentFocusArea = FocusArea.SIDEBAR
                    sideNavFocusRequester.requestFocus()
                    true
                } else false
            }
    ) { /* LazyColumn content */ }
}
```

### What was REMOVED (broken patterns)
- ❌ HazeState / haze / hazeChild (blur overlay)
- ❌ animateDpAsState for width expansion
- ❌ `focusGroup()` on sidebar Column
- ❌ `BackHandler` intercepts (conflicts with navigation)
- ❌ `collapsePending` / `pendingContentFocusTransfer` / `pendingSidebarFocusRequest` state booleans
- ❌ `derivedStateOf` for `sidebarBlocksContentKeys`
- ❌ `Card` usage on nav items (use simple Box)
- ❌ `CompositionLocalProvider` / `LocalSidebarExpanded` / `LocalContentFocusRequester`

### Key Principles
1. **Fixed width** — sidebar never changes size
2. **Passive focus** — each icon manages its own focus independently
3. **No key eating** — D-pad flows naturally between sidebar and content
4. **Back on content → sidebar** — only the content area handles Back, not the sidebar
5. **Right on icon → content** — explicit callback, not auto-collapse
