# Profile Selection Screen — NuvioTV-style

## Key Patterns

### 1. focusProgress animation (0→1 float)
Use `animateFloatAsState` with custom easing instead of boolean-driven states:
```kotlin
val focusProgress by animateFloatAsState(
    targetValue = if (focused) 1f else 0f,
    animationSpec = tween(210, easing = CubicBezierEasing(0.22f, 1f, 0.36f, 1f)),
)
```
Then `lerp()` all visual properties:
```kotlin
val scale = 1f + 0.09f * focusProgress
val avatarSize = lerp(96.dp, 102.dp, focusProgress)
val ringWidth = lerp(1.dp, 3.dp, focusProgress)
val nameColor = lerp(TextSecondary, TextPrimary, focusProgress)
```

### 2. graphicsLayer vs scale() modifier
Use `graphicsLayer { scaleX = scale; scaleY = scale }` instead of `Modifier.scale(scale)` — the graphicsLayer version doesn't trigger relayout, smoother for animations.

### 3. Per-item FocusRequester array
Pre-compute `List(totalItems) { FocusRequester() }` and assign via `.focusRequester()`. Auto-focus with frame delay:
```kotlin
LaunchedEffect(Unit) {
    delay(180)
    delay(50)
    try { focusRequesters.first().requestFocus() } catch (_: Exception) {}
}
```

### 4. Animated gradient background
Two-layer background that tracks focused accent color:
```kotlin
Brush.radialGradient(
    colors = listOf(
        focusedColor.copy(alpha = 0.38f),
        BackgroundElevated.copy(alpha = 0.94f),
        Background,
    ),
    radius = 1100f,
)
```

### 5. PIN overlay with shake
4 animated boxes with hidden BasicTextField. Shake on error using `Animatable`:
```kotlin
LaunchedEffect(error) {
    if (error) shakeOffset.animateTo(0f, keyframes {
        durationMillis = 400
        -22f at 50; 18f at 100; -14f at 150; 10f at 200; -6f at 250; 0f at 400
    })
}
```

### 6. Compact mode
When `totalItems >= 6`, use smaller card width (128dp vs 158dp) and tighter spacing (20dp vs 30dp).

### 7. lerp helper for Dp and Color
```kotlin
private fun lerp(start: Dp, end: Dp, fraction: Float): Dp = start + (end - start) * fraction
private fun lerp(start: Color, end: Color, fraction: Float): Color = Color(
    red = start.red + (end.red - start.red) * fraction,
    green = start.green + (end.green - start.green) * fraction,
    blue = start.blue + (end.blue - start.blue) * fraction,
    alpha = start.alpha + (end.alpha - start.alpha) * fraction,
)
```
