---
title: Reserve league home's article column so team-beat and the positional-value chart stop moving
type: task
status: completed
description: >-
  Anonymous league home on production measures CLS 0.21, almost all from team-beat mounting above
  the positional-value chart and an untracked block growing 487px above team-beat. Reserve both in
  the first commit.
base_uri: user:task/league/reserve-league-home-article-column-in-production.md
created_at: '2026-10-10T04:31:56.775Z'
entity_id: 9e7c1022-7b45-4e04-b333-83af508bc8a6
finished_at: '2026-10-12T14:00:09.892Z'
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
priority: Low
public_read: true
relations:
  - succeeds [[user:task/league/close-spa-api-response-to-store-gap.md]]
started_at: '2026-10-12T02:49:42.935Z'
tags:
  - user:tag/league-xo-football.md
updated_at: '2026-10-12T14:47:19.997Z'
visibility_analyzed_at: '2026-11-05T23:50:11.665Z'
---

## Overview

Anonymous league home on `https://xo.football` measures CLS 0.21. The figure is stable across nine warm runs at 1400px (min 0.2100, max 0.2239). Almost all of it is in the article column, in one stage between about 640ms and 900ms:

- `div.section.league-positional-value` contributes 0.12. At 642ms `.team-beat` mounts at 820px between `.league-edition` and the chart, and pushes the chart down 849px and out of the viewport.
- `section.team-beat` contributes 0.07. At 782ms a block between the edition and team-beat, which the probe does not track, grows by 487px and pushes team-beat down 488px.

The league record is not involved. It is in the store about 150ms before the rail paints (see the predecessor).

## Plan

- [x] **Name the 487px block** that grows above team-beat at ~782ms
  - Add it to `KEY_SELECTORS` in `scripts/measure-layout-shift.mjs`, then re-run `--origin=https://xo.football --runs=9 --token-file=/nonexistent` on `/leagues/1`
- [x] **Reserve team-beat's frame in the commit that paints the edition**, rather than mounting it at 820px after the first paint
  - `will_ask` in team-beat.js: a block that will be asked renders its skeleton from the first commit; the `team_wire` with no pids still renders nothing (parity preserved)
- [x] **Reserve the 487px block's height**, or move it below the fold-critical blocks
  - Moved `LeagueWire` last in the article column. Reservation was the wrong trade: empty is the wire's common state, so a reserved strip would collapse on the clean load
- [x] **Verify on the production origin after deploy:** anonymous CLS median below 0.1 over nine warm runs, and the member page (`--require-auth`) does not regress
  - Measure ordering on the production origin only. A `localhost` page against the live API misorders load races; see `docs/guides/spa.md` § Skeletons and layout shift
  - Shipped at 5f3a19def (deploy 2026-10-12), verified on `https://xo.football`: anonymous median **0.0205** (min 0.0198, max 0.0270), from 0.21 — the team-beat and wire mounts no longer shift
  - Member median 0.1559: the two removed mounts are gone; the residual is the pre-existing member-only desk settling above the edition (+511, same y157 signature as the 2026-09-25 baseline), outside this task's scope

## Key locations

- `repository/active/league/scripts/measure-layout-shift.mjs`: `--origin`, plus the response-to-store hop section
- `repository/active/league/app/views/pages/league-home/`
- `repository/active/league/docs/guides/spa.md` § Skeletons and layout shift
