# TvLayoutMetrics Wiring Pattern

## Context

`TvLayoutMetrics` is a 3-tier responsive layout system (720p/1080p/4K) that computes correct DP/SP values from actual screen resolution. It existed but was only wired to 4 files. The 2026-06-03 session wired it into `TvAppScaffold` and replaced hardcoded values in Home, sidebar, scaffold padding, and cards.

## Steps to wire a new screen

1. Add `import com.unspooled.app.ui.theme.LocalTvLayoutMetrics`
2. At the composable level: `val metrics = LocalTvLayoutMetrics.current`
3. Replace hardcoded dp/sp values with metrics tokens

## All available token names

```
metrics.posterWidth          — card width (96–190dp)
metrics.posterHeight         — card height, 2:3 aspect (144–285dp)
metrics.heroHeight           — hero/banner height (280–460dp, 62% screen height)
metrics.contentPadding       — row left/right padding (16–28dp)
metrics.cardGap              — horizontal gap between cards (12–16dp)
metrics.cardCornerRadius     — card corner radius (14–18dp)
metrics.settingsRailWidth    — sidebar expanded width (200–260dp)
metrics.titleSp              — title font size in SP (22–28)
metrics.bodySp               — body font size in SP (13–15)
metrics.inputHeight          — button/input height in dp (44–52)
metrics.screenWidthDp        — raw screen width
metrics.screenHeightDp       — raw screen height
metrics.isCompact            — true for <960dp (720p TVs)
metrics.posterColumns        — computed column count (5–7)
```

## 3-tier value reference

| Token | 720p (<960dp) | 1080p (<1280dp) | 4K (≥1280dp) |
|-------|---------------|-----------------|---------------|
| posterWidth | ~96dp | ~142dp | ~190dp |
| posterHeight | ~144dp | ~213dp | ~285dp |
| heroHeight | 280dp | ~360dp | 460dp |
| contentPadding | 16dp | 24dp | 28dp |
| cardGap | 12dp | 14dp | 16dp |
| cardCornerRadius | 14dp | 16dp | 18dp |
| settingsRailWidth | 200dp | 220dp | 260dp |
| titleSp | 22 | 26 | 28 |
| bodySp | 13 | 14 | 15 |
| inputHeight | 44dp | 48dp | 52dp |
| posterColumns | 5 | 6 | 7 |

Poster width formula: `usableWidth / (columns + 0.6f)` where `usableWidth = screenWidth - railWidth - padding*2`, with a peek factor of +0.6 to show part of the next card.

## Files wired (2026-06-03)

- `TvAppScaffold.kt` — `LocalTvLayoutMetrics` CompositionLocal provided; content padding uses `metrics.contentPadding`
- `GlassSidebar.kt` — expanded width uses `metrics.settingsRailWidth`
- `UnspooledHomeScreen.kt` — hero height, card dimensions, row content padding, card gap, skeleton placeholder padding
- `TvLayoutMetrics.kt` — `LocalTvLayoutMetrics` declaration; `posterHeight`, `cardGap`, `cardCornerRadius` fields added

## Non-breaking safety

Other screens that don't yet call `LocalTvLayoutMetrics.current` continue to work with their hardcoded values — they just won't auto-scale. The `LocalTvLayoutMetrics` provider in `TvAppScaffold` is passive until read. This makes incremental wiring safe.
