An amateur football club: recent results, the coming fixtures, the Division Two table, and how to join. Brief #15.
Direction
| Lever | Decision |
|---|---|
| Archetype | Document. One column, scrolled top to bottom. No shell, no rail, no dashboard. |
| Data stance | Table-first. The league table takes the full measure; prose sits either side of it. |
| Density | Bootstrap default spacing, with button padding tightened through --bs-btn-padding-y. |
| The one bold thing | It does not look like Bootstrap, and no competing selector was written to achieve that. |
Generator
tokens.css is generated output and is linked, never edited. The command that produced it:
bootstrap_tokens.py --both
Read before the palette moved, and cited in the spec panel:
bootstrap_tokens.py --buttons
bootstrap_tokens.py --component .btn
bootstrap_tokens.py --component .table
--buttons exits 0 both before and after the palette change. It reads the pinned bootstrap@5.3.8 release rather than this page, so its answer is the baseline the page's own claret is measured against: white on #0d6efd is exactly 4.50:1, and white on this page's --bs-primary #7a1e30 is 10.21:1 (contrast.py).
Stylesheet order
bootstrap@5.3.8/dist/css/bootstrap.min.css (CDN, pinned)
tokens.css (generated)
<style> (the brand layer)
Bootstrap comes first. tokens.css writes its dark values to [data-theme="dark"], which ties with :root on specificity and would lose to any framework file loaded after it.
Themes
<html> carries both data-theme and data-bs-theme, set before first paint by a blocking script. Bootstrap's dark block redefines 52 of 117 variables and inherits --bs-primary, so all 26 brand variables are restated under :root[data-theme="dark"] and under @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) }.
The second state
The standings table has a real control above it — a .btn-check radio pair, CSS only, no script — that swaps between the league-confirmed table and the table after Saturday's round. In the provisional view:
- Trinity Rovers' points are withheld pending a protest, rendered as an em dash with a footnote, and the row carries no position. Withheld is a different mark from zero.
- Whitcombe Athletic & Old Boys Association carry a
−3deduction shown inside the points cell. - The 40-character club name wraps in the club column and moves no number.
Measured
| Pair | Ratio |
|---|---|
white on --bs-primary #7a1e30 | 10.21:1 |
body ink #22191b on paper #f7f3ec | 15.53:1 |
body ink #ede6da on #171311 (dark) | 14.88:1 |
--bs-border-color #8a7e6c on paper | 3.60:1 |
--bs-border-color #736858 on #171311 | 3.38:1 |
| focus ring on paper | 3.46:1 |
focus ring on #171311 | 4.34:1 |
dark solid claret #fbf7f0 on #8f2438 | 7.94:1 |
What Bootstrap does not expose
One blue literal is compiled into bootstrap.min.css and no --bs-* variable reaches it: #86b7fe in .form-control:focus, so a focused field carries a blue border for as long as it has focus. Bootstrap's own .focus-ring utility puts a claret ring around it. The supported fix is a Sass rebuild, which a single no-build file cannot do, so it stays and is named in the spec panel.
#0d6efd in .form-check-input:checked is a second such literal, and it is no longer on the page: the side picker is a checkbox toggle group (.btn-check plus .btn), which is Bootstrap's own component, reads the same --bs-btn-* variables as every other button here and carries a 36px target rather than 17px. The select chevron is not a literal either — --bs-form-select-bg-img reaches it, and it is brand ink in both themes.
.form-control does compile its padding, height and font size as literals, so a text field keeps Bootstrap's geometry at this page's radius, colours and type. That is the honest remaining limit of theming through variables.
Colour mode is read from data-bs-theme and from no media query, so the pre-paint script sets it; the system-preference block is defined against a consumer that drops the attribute.
Layout
The two fixtures tables are one spread above 75em and stack below it. Side by side they share a column model (table-layout: fixed, date 4.5rem, ground 9rem, kick-off 5rem) so the pair reads as one decision and the headers line up across the gutter; stacked and on a phone the layout is auto, so the date and score shrink to fit and never overflow into the column beside them.
Every points cell reserves the same mark gutter, so the withheld em dash, the −3 deduction and the footnote letters hang outside the number and every figure in the column right-aligns on one axis.