The heading sat on the right edge of the column and every value on the left. It looked like a layout problem; it was a CSS specificity collision in the stylesheet I wrote.
The cause
The heading and the value were aligned by two different selectors, and only one of them won:
Selector
Specificity
Declares
Outcome
.table td
(0,1,1)
text-align: left
won for the value
.num
(0,1,0)
text-align: right
lost
.table th:last-child
(0,2,1)
text-align: right
won for the heading
So the heading went right, the numbers stayed left, and the column read as broken on every place page.
The fix
The heading cell and the value cell now carry the same class, matched by one rule. They cannot drift apart again regardless of what else changes around them — which is a stronger guarantee than getting the specificity right twice.
The column also stretched to half the table, because nothing constrained it. It now hugs its content with width: 1% and white-space: nowrap, so the school name takes the remaining width. That is what made the gap between heading and value read as misalignment on desktop, and what crowded the name column on mobile.
Verification
Frontend 255 · tsc --noEmit clean · next build green · backend 100 unaffected.
Two new tests. One asserts the heading and value cells share a class — the specific thing that was wrong, rather than the symptom. The other asserts the name column stays unclassed so it keeps taking the spare width.
Note
Worth saying plainly: a unit test cannot see a specificity collision, because jsdom does not apply CSS module rules. What the new test pins is the invariant that prevents it — one class, one rule — which is checkable. The collision itself was only ever going to be caught by looking at the page.
The heading sat on the right edge of the column and every value on the left. It looked like a layout problem; it was a **CSS specificity collision** in the stylesheet I wrote.
## The cause
The heading and the value were aligned by two different selectors, and only one of them won:
| Selector | Specificity | Declares | Outcome |
|---|---|---|---|
| `.table td` | (0,1,1) | `text-align: left` | **won** for the value |
| `.num` | (0,1,0) | `text-align: right` | lost |
| `.table th:last-child` | (0,2,1) | `text-align: right` | **won** for the heading |
So the heading went right, the numbers stayed left, and the column read as broken on every place page.
## The fix
The heading cell and the value cell now carry **the same class**, matched by **one rule**. They cannot drift apart again regardless of what else changes around them — which is a stronger guarantee than getting the specificity right twice.
The column also stretched to half the table, because nothing constrained it. It now hugs its content with `width: 1%` and `white-space: nowrap`, so the school name takes the remaining width. That is what made the gap between heading and value read as misalignment on desktop, and what crowded the name column on mobile.
## Verification
Frontend 255 · `tsc --noEmit` clean · `next build` green · backend 100 unaffected.
Two new tests. One asserts the heading and value cells share a class — the specific thing that was wrong, rather than the symptom. The other asserts the name column stays unclassed so it keeps taking the spare width.
## Note
Worth saying plainly: a unit test cannot see a specificity collision, because jsdom does not apply CSS module rules. What the new test pins is the *invariant that prevents it* — one class, one rule — which is checkable. The collision itself was only ever going to be caught by looking at the page.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
The heading sat on the right edge of the column and every value on the left.
A specificity collision, not a layout problem: the two were aligned by
different selectors and only one of them won.
.table td (0,1,1) text-align: left <- won for the value
.num (0,1,0) text-align: right <- lost
.table th:last-child (0,2,1) text-align: right <- won for the heading
The heading and the value cell now share one class and one rule, so they
cannot drift apart again whatever else changes around them.
The column also stretched to half the table. It now hugs its content with
width:1% and nowrap, so the school name takes the remaining width — which is
what made the gap read as misalignment on a wide screen, and what crowded the
name column on a narrow one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
This PR fixes a CSS specificity bug where the measure column's header and values were misaligned due to differing selector specificity, by unifying them under a single shared class .num applied to both the th and td elements, plus adding width:1%/nowrap so the column hugs its content. Tests are added to verify alignment and that the school-name column remains unclassed. The change is low-risk, purely presentational, and well-tested.
✅ No issues found.
## 🤖 AI Code Review (Claude Code)
This PR fixes a CSS specificity bug where the measure column's header and values were misaligned due to differing selector specificity, by unifying them under a single shared class `.num` applied to both the th and td elements, plus adding width:1%/nowrap so the column hugs its content. Tests are added to verify alignment and that the school-name column remains unclassed. The change is low-risk, purely presentational, and well-tested.
✅ No issues found.
tudor
merged commit 4cea26b813 into main2026-08-21 21:21:04 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The heading sat on the right edge of the column and every value on the left. It looked like a layout problem; it was a CSS specificity collision in the stylesheet I wrote.
The cause
The heading and the value were aligned by two different selectors, and only one of them won:
.table tdtext-align: left.numtext-align: right.table th:last-childtext-align: rightSo the heading went right, the numbers stayed left, and the column read as broken on every place page.
The fix
The heading cell and the value cell now carry the same class, matched by one rule. They cannot drift apart again regardless of what else changes around them — which is a stronger guarantee than getting the specificity right twice.
The column also stretched to half the table, because nothing constrained it. It now hugs its content with
width: 1%andwhite-space: nowrap, so the school name takes the remaining width. That is what made the gap between heading and value read as misalignment on desktop, and what crowded the name column on mobile.Verification
Frontend 255 ·
tsc --noEmitclean ·next buildgreen · backend 100 unaffected.Two new tests. One asserts the heading and value cells share a class — the specific thing that was wrong, rather than the symptom. The other asserts the name column stays unclassed so it keeps taking the spare width.
Note
Worth saying plainly: a unit test cannot see a specificity collision, because jsdom does not apply CSS module rules. What the new test pins is the invariant that prevents it — one class, one rule — which is checkable. The collision itself was only ever going to be caught by looking at the page.
🤖 Generated with Claude Code
https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
🤖 AI Code Review (Claude Code)
This PR fixes a CSS specificity bug where the measure column's header and values were misaligned due to differing selector specificity, by unifying them under a single shared class
.numapplied to both the th and td elements, plus adding width:1%/nowrap so the column hugs its content. Tests are added to verify alignment and that the school-name column remains unclassed. The change is low-risk, purely presentational, and well-tested.✅ No issues found.