---
title: Fix dashboard players table waiver header styling
type: task
status: in_progress
description: >-
  Header and column defects in the dashboard__players-table roster and waiver heads. The 2026-09-23
  styling lane is landed and deployed; 2026-09-24 gave every cluster one band horizon and the totals
  row its missing bye cell. Open: an operator call on the aligned band rule, the live logged-in
  look, and a column-contract audit across the untested modes.
base_uri: user:task/league/fix-dashboard-players-table-waiver-header-styling.md
created_at: '2026-09-23T17:48:27.120Z'
entity_id: 1a342fb8-a0dc-45e7-b09e-2682d681d440
observations:
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
  - ████████████████████████████████████████████████
owner_identity_uri: █████████████████████████
public_read: true
tags:
  - user:tag/league-xo-football.md
  - user:tag/software-task.md
updated_at: '2026-09-24T18:08:05.895Z'
visibility_analyzed_at: '2026-11-05T23:49:20.250Z'
---

## Goal

Make the `dashboard__players-table` waiver/cutlist header clean and uniform. The operator reviewed the current header and called out three remaining problems (2026-09-23):

1. Mixing row groups and single cells is awkward — they read as different heights, so the vertical separators between them look inconsistent.
2. The sticky leading header cell (`table__cell sticky__column text lead-cell`) is missing its label.
3. Header `table__cell`s need left/right padding.

## Landed (commits, all in `repository/active/league`)

- `16ce6026f`, `d918736b3` — dropped the reorder affordance from the head (a neutral 45px
  `.table__reorder-cell` spacer holds the column alignment) and reset `border-bottom: none` on
  `.table__head .table__cell`, so the head closes on its single line.
- `6e372e97a` — the `leadColumn = 'Player'` default, so the sticky lead cell carries its label.
  Its other half, a forced caption horizon, is superseded by `bd5cb70ca`.
- `bd5cb70ca` — each head column centers its own content in the full head instead of sharing a
  forced caption horizon, so a cluster's label-plus-captions stack and a standalone caption sit on
  one midline. Head cells take `padding 0 10px`. A cluster preceded by a standalone cell now draws
  the same left rule a cluster followed by one always drew. **The centering half is superseded by
  `70df54211`**; the padding and the left rule stand.
- `498e37479` — removes the two declarations in `league-home.styl` that were overriding all of the
  above on the waiver page. `.league__home .table__head` carried `height: auto` and
  `.table__cell { padding: 8px 0 }`; the page keeps only the rule colour now.
- `c0bd29487` — restores the rule under each group label, at the operator's call. It had been
  dropped because it runs only beneath its own columns, which read as a broken head-wide line while
  the label band was a full-width top zone. Centering the cluster retired that reason; `70df54211`
  reinstates the top zone, so the objection is live again and unresolved — see Plan step 1.
- `8fe7ad47d` — the lesson below, written into `STYLE.md` § Verifying a Style Change as item 12.

2026-09-24:

- `70df54211` — the head owns both of a cluster's zones: a fixed 24px band across the top, captions
  centered in the 40px below it. Centering a content-sized stack held the captions on one horizon
  and moved the BAND instead, because a cluster whose captions wrap is 12.6px taller — Expected
  Points and Projected carried their bands at 5.2px from the head's top while the four single-line
  clusters carried theirs at 11.5px. Band top spread and height spread both read 0.00 after,
  against 6.30 before, at 1400px and 390px on both call sites.
- `99d689be9` — the totals row (`player-roster-total.js`) renders its bye cell, and its extension
  block moved after the in-season groups to match the head's order. It had been rendering 17 cells
  against the head's 18 since `5c4bebd2a` (2025-09-02) added the bye column to the head and the
  player row only.
- `888558588` — the column contract and its server-render oracle written into `docs/guides/spa.md`.

## Why three rounds of table.styl edits did not land

`DashboardPlayersTable` is the only component on league-home that renders a `.table__head`, so
everything in the page block reached it alone — and the page block won.

`height: auto` leaves the head an indefinite cross size, so `.table__head .table__cell`'s
`height: 100%` resolves to auto: the standalone cells collapse to their own content while the
`.row__group` clusters stand at theirs. That is the two-heights-in-one-row reading, measured at
30.3px against 59.59px. The zero horizontal padding is the other half — at (0,3,0) it tied with the
component's own head padding and won on source order, so every inset the component asked for was
dropped on this page only.

Nothing about this is visible from `table.styl`, and the team page — where the same component
renders without the page block — reads correct at every stage. That is why the replica agreed with
the team page and both disagreed with the operator.

## Verification

Computed style and `getBoundingClientRect` off the live `yarn dev:live` DOM, never the source.

- Team page at 1280 and 390: every cluster stack and every standalone caption centers on 31.5px in
  a 63px head, two-line Projected sub-captions included.
- Waiver head under the real league-home stylesheet, built into the live page per STYLE.md's
  unreachable-state rule: 30.3px / 59.59px before `498e37479`, a uniform 63px for all eleven head
  children after, with `padding: 0 10px` on every cell.
- `yarn verify` passed 20 checks on both commits.

2026-09-24, for `70df54211`, `99d689be9` and `888558588`:

- Static harness built per STYLE.md's unreachable-state rule from the app's shared style index, the
  component's own sheet, `league-team.styl` and `league-home.styl`, rendered in Chrome at
  `deviceScaleFactor: 3`. Band top spread and height spread 0.00 at 1400px and 390px on both call
  sites, against 6.30 before. A forced-wrap label fills its band rather than growing it: the head
  stays 64px and no neighbouring band moves.
- The 18 head columns and the 18 totals-row columns now match on left edge pairwise; one mismatch
  before.
- `player-roster-total.js` server-rendered with `react-dom/server` against the live clock, which is
  inside the fantasy regular season: 17 leaf cells before, 18 after.
- `verify` verdict `pass` on `df0ef5908`, which carries `70df54211` and `99d689be9`.
- Harness and oracles in `repository/active/league/scratch/header-row/` (gitignored, macbook only).

## Plan

Code work for the operator's three 2026-09-23 problems is done and deployed. Four things remain,
and the first is the only one that needs a decision rather than a session.

- [ ] **Operator call on the band rule.** `70df54211` puts every cluster's under-rule at the same
      offset, which is what makes the label row read as one row — and it also makes the rules line up
      across clusters with gaps where the standalone columns sit. That is close to the reading the
      rule was dropped for in an earlier round ("one head-wide line stopping and starting between
      columns") before centering retired the objection. Nobody has looked at the rendered result yet;
      the screenshot is `scratch/header-row/head-1400.png`.
- [ ] **Operator looks at the waiver claims head on a logged-in league home.** Unchanged from the
      2026-09-23 gate, and now also covers the two 2026-09-24 commits: no session in this chain has
      seen this table React-rendered, because the dashboard table needs a logged-in team and the probes
      are injected markup. What that leaves unproven is the components' props and their place in the
      page, not the CSS and not the cell counts.
- [ ] **Audit the column contract across the remaining modes.** The bye miss was found by eye, and the
      same drift can sit in any mode a session has not counted: waiver, claim, poach, restricted free
      agency, and the offseason and extension branches of the totals row. The oracle and its limits are
      in `docs/guides/spa.md` § "A table split across three components".
- [ ] **Render the totals row's offseason and extension branches.** The 2026-09-24 count oracle reads
      the live clock, so it exercised the regular season only; the other branches were verified by
      reading the gates against the head's.
