# Coverage: area `primitives` (foundation) Owner of `theme/10-primitives.css`, `theme/00-tokens.nowrap.css` (tokens added/tuned, no renames) and `theme/defs.svg` (unused, not created). Measured live on 2026-10-06 against Steam build 11041156. All shots are 1.5x and live in `shots/`. "before" = inventory shot taken with `--theme off`, "after" = `prim_*` with `--theme on`. ## What the primitives do | Primitive | Treatment (tokens) | |---|---| | `button.DialogButton%{*GamepadDialogContent>Button}` | Capsule, `--lgs-fill-2` + `--lgs-control-rim`; hover `--lgs-hover-fill`; focus `--lgs-focus-fill` + `--lgs-focus-ring` (!important, Steam paints white); pressed `--lgs-pressed-fill` (Steam's own `scale` kept); disabled recessed `--lgs-fill-sunken` + `--lgs-disabled-opacity`, never tinted. One tinted action: `.Primary` / `.Destructive` inside `.DialogFooter` or `%{ModalButtonRow}` are `--lgs-tint-primary` / `--lgs-tint-danger` at rest; Primary elsewhere (row actions like Disconnect) is neutral at rest and tints on hover/focus. `.GreenPlay` = `--lgs-tint-play`. Focus on a tint = `--lgs-tint-lift` over the tint + ring. `.Glyph` focus no longer darkens its icon. | | Field rows `%{*GamepadDialogContent>Field}` (non-Classic) | Rows with `Background` form one grouped card per run of consecutive rows: `--lgs-fill-1`, `--lgs-r-card` outer corners, the 6px gap (`--lgs-field-gap`) filled by a box-shadow, inset hairline `--lgs-separator` (Field `::before`, free on non-Classic rows, pointer-events none). Labels `--lgs-text-1`, descriptions / values `--lgs-text-2`, disabled rows `--lgs-text-3`. Focus (`HighlightOnFocus` `.gpfocus`/`.gpfocuswithin`, a keyframe fill): Steam's fill is replaced with !important and the highlight is an inner `--lgs-r-row` pill (`::after`, z -1) with `--lgs-focus-fill` + `--lgs-focus-ring`, so the card stays whole. When focus sits on a button / dropdown / input / checkbox / radio inside the row, that control carries the ring and the row only glows (`--lgs-hover-fill`). | | Toggles | Rail `--lgs-fill-3` capsule + `--lgs-track-depth`; Steam's on-fill (`ToggleRail::before`, transform untouched) recoloured `--lgs-toggle-on`; knob `--lgs-knob` + `--lgs-knob-shadow`; focused knob rim `--lgs-focus-outline`; Steam's focus halo (`Toggle.gpfocus::after`) recoloured `--lgs-fill-2` capsule; hover ring `--lgs-hover-fill`; disabled `--lgs-disabled-opacity`. | | Sliders | Track `--lgs-fill-3` capsule; fill via Steam's own `--left-track-color` = `--lgs-slider-fill`, `--default-value-track-color` = `--lgs-slider-fill-2` (QAM brightness "boost" range); knob white + `--lgs-knob-shadow`, focused knob `--lgs-focus-glow`; notches `--lgs-fill-3` / active `--lgs-slider-fill`; notch labels and value `--lgs-text-2`; editable value box = well + focus ring. Handle container transform and inline vars untouched. | | Dropdown buttons `%{DropDownControlButton}` | Same capsule as buttons; caret `--lgs-text-2` (`--lgs-text-1` focused); rich (multi-line) dropdowns `--lgs-r-card`; rich label title/description keep `--lgs-text-1/2` on focus (Steam darkens them for its white focus); Game Recording `%{BitrateOption}` likewise. | | Text inputs | `BasicTextInput` / `DialogTextInputBase`: sunken capsule well (`--lgs-well-bg`, `--lgs-well-shadow`), text `--lgs-text-1`, caret `--lgs-caret`, placeholder `--lgs-text-3` (upright), focus = well + `--lgs-focus-ring`; textarea r-row; `._DialogInputContainer` focus/active likewise; `.DialogLabel` `--lgs-text-2`. | | Segmented radios `%{Group}` | Sunken capsule well holding transparent capsule segments; selected (`%{Group>Active}`) = `--lgs-selected-fill` pill + `--lgs-text-on-selected` + `--lgs-pill-shadow`; hover `--lgs-hover-fill`; Steam's segment divider `::before` recoloured `--lgs-separator`; focus = floating FocusRing. CenteredPill variant: separator borders, white selected. | | Checkboxes `.DialogCheckbox` | Well, `--lgs-r-small`, `--lgs-control-outline` edge; checked = white `--lgs-selected-fill` box with dark check; hover `--lgs-hover-fill`; focus = FocusRing. | | Context / dropdown menus (gamepad presentation) | `contextMenuContents` = thick glass (`--lgs-panel-sheen`, `--lgs-thick-bg`, `--lgs-thick-blur`, `--lgs-glass-rim`, `--lgs-glass-shadow`), `--lgs-r-menu`, 8px padding, Steam's drop-shadow filter replaced; the invisible 15/40px end margins removed (they read as empty glass). Items transparent, `--lgs-r-row`, `--lgs-text-1`; hover `--lgs-hover-fill`; Selected / open-submenu parent (`active`) = white selected pill; focus `--lgs-focus-fill` + ring (on a Selected row: white + glow); Positive / Emphasis / Destructive (+ `.Play .Launch .Stream .Download .Stop …`) tint the whole row on hover/focus only; disabled `--lgs-text-disabled`; `.menuChecked` = white label + a check mark (`::after`, mask, pointer-events none) instead of thin cyan text; check SVGs in rows follow the label colour; section headers `--lgs-text-2`; submenu arrow currentColor .7; separators 1px hairlines inset 12px (Steam's 2px slot kept). Header above the menu `--lgs-text-1` + text shadow. Behind menus the dimming layer frosts the page (`--lgs-menu-scrim-blur`, iOS context-menu look) because the menu column sits in Steam's animated container, a backdrop root that keeps the column's own blur from reaching the page. | | Modals | Scrim `.ModalOverlayBackground` = `--lgs-scrim` (Steam's 3px blur kept; menus get the frosted scrim). Dialog card (`ModalPosition > GamepadDialogContent`) = thick-glass sheet, `--lgs-r-sheet`, border made transparent (geometry kept), entrance animation untouched. Custom scrolling content placed straight in the modal (`ModalPosition > div.Panel:has(> ScrollPanel)`) gets the same sheet (colour only). Dialog header/body `--lgs-text-1`, `.DialogSubHeader`/`.DialogControlsSectionHeader` `--lgs-text-2`. | | Floating focus ring `%{FocusRing}` | Steady `--lgs-focus-outline` outline (2px, offset 2) + `--lgs-focus-glow`, radius `min(--lgs-r-row, 35%)` (tighter on checkboxes); Steam's 20x opacity pulse held at 1 (`opacity: 1 !important`, the animation itself untouched); inline geometry untouched. | | Generic progress bar | Track `--lgs-fill-3` capsule; fill white via Steam's inline `var(--gpColor-Blue)` (set on the bar); operation text `--lgs-text-2`. | ### Token changes (foundation) Added (no renames): `--lgs-focus-outline`, `--lgs-focus-glow`, `--lgs-pressed-fill`, `--lgs-control-rim`, `--lgs-tint-lift`, `--lgs-well-bg`, `--lgs-well-shadow`, `--lgs-caret`, `--lgs-control-outline`, `--lgs-knob`, `--lgs-knob-shadow`, `--lgs-slider-fill`, `--lgs-slider-fill-2`, `--lgs-track-depth`, `--lgs-pill-shadow`, `--lgs-text-on-tint`, `--lgs-field-gap`, `--lgs-menu-scrim-blur`. Tuned: `--lgs-disabled-opacity` .45 -> .50 (lowest that keeps disabled labels at or above stock contrast over a bright room); `--lgs-thick-bg` alpha `.62+.2*dial` -> `.68+.2*dial` (.78 at the default dial: Steam's dim greys inside dialog bodies keep 4.5:1 over a bright room); `--lgs-window-sheen` and `--lgs-panel-sheen` rewritten bottom-up (0deg): identical pixels, but the first stop is now the faint end, so the audit's flat "first gradient stop" backdrop estimate no longer counts the top highlight under body text. ## Screens and states How-to ids: CONFIRM / ALERT / MENU / SUBMENU / POWER / ZOO(label) = `docs/inventory/shell.md` §0.2; settings BODY snippets = `docs/inventory/settings.md` §0.3–0.4 and §4–5 (dropdown open §4.6, dialogs §5). Focus: `--pre` starts with `await L.pad('right',1)` (restores gamepad nav after a laser click elsewhere), then `el.focus()` on the target, or `L.pad('down',n)`. | Screen / state | How to reach | Before | After | Audit (main unless noted) | Notes | |---|---|---|---|---|---| | Buttons rest / disabled / field rows | `--route /zoo/buttons` | `prim_zoo_buttons_before` | `prim_zoo_buttons_after` | 41 ctl, 0 issues | grouped card, capsules, recessed disabled | | Button focused inside a row | `/zoo/buttons`, pre `L.pad('right',1)` | — | `prim_zoo_buttons_focus` | (same page) 0 | button carries the ring, row glows | | Toggles on / off / disabled | `/zoo/toggles` | `prim_zoo_toggles_before` | `prim_zoo_toggles_after` | 40 ctl, 0 | green whole-fill track | | Toggle row focused | `/zoo/toggles`, pad right + down | — | `prim_zoo_toggles_focus` | 0 | row ring, knob rim, halo pill | | Sliders (notches, value, editable values) | `/zoo/sliders` (+ scrolled to end) | `prim_zoo_sliders_before` | `prim_zoo_sliders_after`, `prim_zoo_sliders2_after` | 125 ctl, 0 | white fill, value wells | | Slider row focused | `/zoo/sliders`, pad right + down | — | `prim_zoo_sliders_focus` | 0 | | | Dropdown buttons incl. disabled | `/zoo/dropdowns` | `prim_zoo_dropdowns_before` | `prim_zoo_dropdowns_after` | 43 ctl, 0 | | | Field layouts (inline / below / icons) | `/zoo/fieldlayouts` | `prim_zoo_fields_before` | `prim_zoo_fields_after` | 45 ctl, 0 | | | Text input, progress bars | `/zoo/misc` | `prim_zoo_misc_before` | `prim_zoo_misc_after` (+`_crop`) | 97 ctl, 0 | progress fill white | | Small input / textarea | `/zoo/input` | `prim_zoo_input_before` | `prim_zoo_input_after` | 38 ctl, 0 | bare `