/* The league pages.
 *
 * Deliberately NOT in forms.css: the transfer boxes below are one page's
 * furniture rather than a shared component, and forms.css is the UI chat's
 * component layer. If any of this turns out to be worth having everywhere, it
 * should move there rather than grow here.
 *
 * Every value is a token. Loaded only by the league pages that ask for it.
 */

/* ── The three lists a director moves people between ──
 *
 * One column on a phone, three side by side once there is room. A grid with
 * explicit tracks rather than a flex line, because a list that collapses to
 * nothing beside its neighbour is the bug this project has already had twice.
 */
.transfer {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--space-4);
	margin-bottom: var(--space-5);
}

@media (min-width: 900px) {
	.transfer { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.transfer-box {
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	padding: var(--space-3);
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.transfer-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-2);
	margin-bottom: var(--space-2);
}

.transfer-head h3 {
	margin: 0;
	font-size: 1rem;
}

.transfer-head .sub {
	font-size: 0.8rem;
	color: var(--text-muted);
}

/* Scrollable, so twenty names do not push the arrows off the screen. Capped
 * in rem rather than vh: on a phone in landscape vh is almost nothing. */
.transfer-list {
	overflow-y: auto;
	max-height: 18rem;
	border-top: 1px solid var(--border-color);
}

.transfer-row {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-2) 0;
	border-bottom: 1px solid var(--border-color);
}

.transfer-row:last-child { border-bottom: none; }

.transfer-row label {
	flex: 1 1 auto;
	min-width: 0;
	display: block;
	cursor: pointer;
}

.transfer-row .sub {
	display: block;
	font-size: 0.78rem;
	color: var(--text-muted);
}

/* The checkbox keeps its own width whatever the name does. */
.transfer-row input[type="checkbox"] {
	flex: 0 0 auto;
	margin: 0;
}

.transfer-empty {
	padding: var(--space-4) 0;
	color: var(--text-muted);
	font-size: 0.85rem;
	text-align: center;
}

/* The arrows. Under each list, where they are reachable one-handed and read
 * the same whether the boxes are stacked or side by side. */
.transfer-actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-top: var(--space-3);
}

.transfer-actions .btn {
	width: auto;
	flex: 1 1 auto;
	margin-bottom: 0;
}

/* The link a director shares. Wide enough to show a whole URL, and selected
 * on focus by the script so one tap copies it. */
.share-link { font-family: inherit; }

/* ── The rotation table on a league's settings ──
 *
 * Up to ten sessions by ten home positions, each cell a two-character menu.
 * Narrow fixed cells so five fit across a phone at 420px; more than that
 * scrolls sideways inside .table-scroll rather than crushing the menus.
 * The session column and the session-1 row are text, not menus: session 1 is
 * the captains' own order and not the LD's to change. Under the standard
 * rotation every cell is text: it is fixed.
 *
 * Beside it, the same night as head-to-heads (H1 : A1): a second table
 * with the same classes, so its headings, rows and lines match, one column
 * per session. A line separates the two: down the middle when they sit side
 * by side, across when a phone stacks them. Above 60rem they never stack;
 * a table too wide for its half scrolls sideways in its own box.
 * Every frame carries its number in small grey, in both.
 */
.rotation-views {
	display: flex;
	flex-direction: column;
	align-items: center;
	margin-bottom: var(--space-3);
}
.rotation-views .table-scroll { max-width: 100%; margin-bottom: 0; }
.rotation-views .table-scroll + .table-scroll {
	margin-top: var(--space-3);
	border-top: 1px solid var(--border-color);
}
@media (min-width: 60rem) {
	.rotation-views {
		flex-direction: row;
		justify-content: center;
		align-items: stretch;
	}
	.rotation-views .table-scroll { flex: 0 1 auto; min-width: 0; }
	.rotation-views .table-scroll + .table-scroll {
		margin: 0 0 0 var(--space-4);
		padding-left: var(--space-4);
		border-top: 0;
		border-left: 1px solid var(--border-color);
	}
}
.rotation-frame {
	display: inline-block;
	min-width: 1.4em;
	margin-right: 0.3em;
	font-size: 0.7rem;
	color: var(--text-muted);
	text-align: right;
}
/* The two tables' rows line up only if they are the same height: text,
 * badges and (in "My own table") menus all sit in one fixed row. */
.rotation-views tbody td,
.rotation-views tbody th { height: 2.4rem; }
.rotation-views.own tbody td,
.rotation-views.own tbody th { height: 3.1rem; }
.rotation-pairs td > * { vertical-align: middle; }
.rotation-pairs .badge {
	min-width: 2rem;
	padding: 0.05rem 0.35rem;
	line-height: 1.3;
	text-align: center;
}
.rotation-pairs .rotation-vs { margin: 0 0.1rem; color: var(--text-muted); }
.rotation-grid { width: auto; margin-top: var(--space-3); }
.rotation-grid th,
.rotation-grid td { padding: var(--space-2) var(--space-2) var(--space-2) 0; text-align: center; white-space: nowrap; }
.rotation-grid td:last-child,
.rotation-grid th:last-child { text-align: center; }
.rotation-grid tbody th { color: var(--text-muted); }
/* The standard rotation as a scorecard: every cell a frame number, centred
 * (the shared table rules right-align the last column). */
.rotation-scorecard th,
.rotation-scorecard td,
.rotation-scorecard th:last-child,
.rotation-scorecard td:last-child { text-align: center; padding-right: var(--space-2); padding-left: var(--space-2); }
.rotation-scorecard td { font-variant-numeric: tabular-nums; }
.tdc-card .rotation-grid select {
	width: 3.4rem;
	padding: 0.35rem 1.1rem 0.35rem 0;
	text-align: center;
}

/* ── Who runs it: the role, then the name search ──
 *
 * Two equal halves rather than the row's narrow columns, where the role's
 * pill took two and squeezed the search into one. The search box fills its
 * half so its line runs as wide as its hint. One above the other on a
 * phone, where two halves are too narrow for either.
 */
.official-row { grid-template-columns: 1fr 1fr; column-gap: var(--space-6); }
.official-row > .field:has(> .tdc-select) { grid-column: auto; }
.official-row > .field > input[type="search"] { justify-self: stretch; text-align: center; }
@media (max-width: 40rem) {
	.official-row { grid-template-columns: minmax(0, 1fr); }
	/* Between the two fields, not inside each one's label, control and hint. */
	.official-row > .field + .field { margin-top: var(--space-4); }
}

/* A warning under a field: allowed, but worth a second look. */
.field .hint.warn { color: var(--color-warning); }

/* ── Sections divided by a line ──
 *
 * The same rule the profile page carries inline. If a third page wants it,
 * it belongs in forms.css.
 */
.section { border-top: 1px solid var(--border-color); padding-top: var(--space-2); margin-top: var(--space-6); }
.section:first-of-type { border-top: none; margin-top: 0; padding-top: 0; }

/* ── Your leagues on /leagues/ ──
 *
 * A .row-table (forms.css) with a strip and a picture. Only its PC column
 * tracks are this page's: the picture, the name, the badges, starts, ends,
 * ranking, teams.
 */
.row-table.league-rows { --row-cols: 2.75rem minmax(0, 1fr) 9rem 6.5rem 6.5rem 4.5rem 6.5rem; }

/* A season's status colour, on the row's strip and the search tile's edge.
 * The keys are TDCMatchDef.LEAGUE_STATUS; a new status needs a line here. */
.league-status-taking_entries { --strip-color: var(--color-primary); }
.league-status-running        { --strip-color: var(--color-success); }
.league-status-on_break       { --strip-color: var(--color-warning); }
.league-status-finished       { --strip-color: var(--text-muted); }

/* ── Search for a League ──
 *
 * The search bar and its filters as wide as Your Leagues above (UV, 24 Oct);
 * the results one row of tiles that scrolls sideways. The first tile starts
 * in the middle and the rest wait to its right: scrolling right brings them
 * in, filling the left as it goes. Each tile snaps to the middle.
 */
.league-search { margin-bottom: var(--space-4); }
.league-search > .field label,
.league-search input[type="search"],
.league-search .hint { text-align: center; }

/* Each filter is a select pill (24 Oct), which needs room to show its
   options: one a row on a phone, side by side only where each gets 18rem. */
.league-filters {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
	gap: 0 var(--space-3);
}
.league-filters .field { margin-bottom: var(--space-3); }

.league-tiles {
	--tile-w: 12.5rem;
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: var(--tile-w);
	gap: var(--space-3);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	/* Above and below: room for the glow, which overflow would otherwise clip.
	   Either side: half the row less half a tile, so the first and the last
	   tile can each sit in the middle. */
	padding: var(--space-3) max(var(--space-1), calc(50% - var(--tile-w) / 2)) var(--space-4);
	margin-bottom: var(--space-4);
}
/* Nothing found: a sentence, not a column of tiles. */
.league-tiles.is-empty { display: block; padding: 0; text-align: center; }

/* A result: badge-shaped, the league's picture on top (a default icon until
 * leagues have their own), the name and details under it, and the status
 * along the top edge. */
.league-tile {
	scroll-snap-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: var(--space-1);
	padding: var(--space-4) var(--space-3) var(--space-3);
	border: 1px solid var(--border-color);
	border-top: var(--space-1) solid var(--strip-color, var(--color-primary));
	border-radius: var(--radius-lg);
	background: var(--bg-surface);
	color: inherit;
	text-decoration: none;
	transition: box-shadow 0.15s;
	min-width: 0;
}
.league-tile:hover,
.league-tile:focus-visible { box-shadow: var(--glow-primary); outline: none; }

.league-tile-pic {
	width: 3.5rem;
	height: 3.5rem;
	border-radius: var(--radius-round);
	display: grid;
	place-items: center;
	background: var(--hover-wash);
	color: var(--color-primary);
	margin-bottom: var(--space-2);
}
.league-tile-pic svg { width: 60%; height: 60%; }

.league-tile-name {
	font-weight: 600;
	line-height: 1.25;
	overflow-wrap: anywhere;
}
.league-tile-meta {
	font-size: 0.78rem;
	color: var(--text-muted);
	line-height: 1.35;
}
.league-tile .badge { margin-top: auto; }
.league-tile-meta:last-of-type { margin-bottom: var(--space-2); }

/* ── The fixtures page: the planner and every fixture (UV, 24 Oct) ──
 *
 * The calendar is the months side by side, scrolling sideways; a night the
 * league plays is a green dot, the button's own colour, and the chosen one
 * carries the glow. The weekend's headings are badges.
 *
 * A fixture is home | menu | away in one table row, the menu column fixed,
 * so names and menus line up down the page; names wrap rather than push.
 * Not inside a .table-scroll: a scroller clips the menu that drops out of
 * the middle cell. Every button rule below is written against
 * .tdc-card button, which otherwise makes every button a full-width pill.
 */
.cal-months {
	position: relative;
	display: flex;
	gap: var(--space-6);
	overflow-x: auto;
	padding: var(--space-2) 0 var(--space-3);
	margin-bottom: var(--space-3);
}
.cal-month { flex: 0 0 auto; }
/* Centred while they fit; auto margins rather than justify-content, which
 * would push the first month out of reach once they scroll. */
.cal-month:first-child { margin-left: auto; }
.cal-month:last-child { margin-right: auto; }
.cal-month-name {
	text-align: center;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
	margin-bottom: var(--space-2);
}
.cal { border-collapse: collapse; }
.cal th {
	padding: 0 0 var(--space-2);
	font-size: 0.68rem;
	font-weight: 600;
	color: var(--text-muted);
	text-align: center;
}
.cal th .badge { padding: 0.1rem 0.4rem; font-size: 0.66rem; }
.cal td { width: 2.4rem; height: 2.4rem; padding: 0; text-align: center; }
.cal-num { font-size: 0.85rem; color: var(--text-muted); }
.cal-today .cal-num { color: var(--text-primary); font-weight: 700; text-decoration: underline; }
.tdc-card .cal button.cal-day {
	width: 2rem;
	height: 2rem;
	padding: 0;
	margin: 0;
	border-radius: var(--radius-round);
	background: var(--color-primary);
	color: var(--color-on-primary);
	font-size: 0.85rem;
	font-weight: 700;
	letter-spacing: 0;
}
.tdc-card .cal button.cal-day.on { box-shadow: var(--glow-primary); outline: 2px solid var(--text-primary); outline-offset: 2px; }

/* Rounds with no date, and a new round, under the calendar. */
.undated-rounds {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-2);
	margin-bottom: var(--space-4);
}

.fx-day-title { text-align: center; margin: var(--space-3) 0; }

/* The chosen night's own buttons, and its Move, centred under the title:
 * the fixtures' icons, each with a caption under it. */
.fx-day-actions { justify-content: center; gap: var(--space-5); }
.fx-night-btn {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-1);
}
.tdc-card .fx-night-btn button.fx-icon { width: 2.6rem; height: 2.6rem; }
.fx-night-caption {
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--text-muted);
}
.fx-night-move { margin-bottom: var(--space-4); }
.fx-night-move .btn-row { justify-content: center; }
.fx-night-move .btn-row > .btn { flex: 0 1 auto; }

/* Only as wide as the fixtures need, centred (UV, 24 Oct); names wrap on a
 * phone rather than push the table past the card. */
.fx-table {
	width: auto;
	max-width: 100%;
	margin: 0 auto var(--space-4);
	border-collapse: separate;
	border-spacing: 0;
}
/* Everything in a fixture sits in the middle of its cell (UV, 25 Oct). */
.fx-table td { padding: var(--space-2) 0; vertical-align: middle; text-align: center; }
.fx-table td.fx-mid { text-align: center; padding-inline: var(--space-3); white-space: nowrap; }
/* Home and away share what the middle leaves, equally, so neither side is
 * squeezed and the middle sits in the middle. */
.fx-table td.fx-side { width: 50%; }
/* Your own team's fixture: its row and its tables row (UV, 25 Oct). */
.fx-table tr.fx-mine td { background: var(--hover-wash); }

/* Each fixture in a faint outline, as a panel is, so one reads apart from
 * the next (UV, 25 Oct). A table cannot outline a group of rows, so the
 * cells draw it: the strip the left side (it spans both rows), the main row
 * the top, its away cell the top right, the tables row the right and
 * bottom. A bye has no tables row, so its main row closes the box. */
.fx-table tr { --fx-line: var(--border-color); }
.fx-table tr.fx-row > td { border-top: 1px solid var(--fx-line); }
.fx-table tr.fx-row > td.fx-state {
	border-left: 1px solid var(--fx-line);
	border-bottom: 1px solid var(--fx-line);
	border-radius: var(--radius-md) 0 0 var(--radius-md);
}
.fx-table tr.fx-row > td:last-child {
	border-right: 1px solid var(--fx-line);
	border-top-right-radius: var(--radius-md);
}
.fx-table tr.fx-tables > td {
	padding-right: var(--space-2);
	border-right: 1px solid var(--fx-line);
	border-bottom: 1px solid var(--fx-line);
	border-bottom-right-radius: var(--radius-md);
}
.fx-table tr.fx-row-bye > td { border-bottom: 1px solid var(--fx-line); }
.fx-table tr.fx-row-bye > td:last-child { border-bottom-right-radius: var(--radius-md); }

/* A fixture your team plays in (UV, 29 Oct): the outline green, glowing
 * outwards, so a player or captain sees at once which are theirs. The glow
 * is drawn by the same edge cells as the outline, each pushing its shadow
 * out of its own edge only (a negative spread), so none shows on the seams
 * inside the box. */
.fx-table tr.fx-mine {
	--fx-line: color-mix(in srgb, var(--color-primary) 70%, transparent);
	--fx-glow: color-mix(in srgb, var(--color-primary) 45%, transparent);
	--fx-up: 0 -7px 9px -7px var(--fx-glow);
	--fx-down: 0 7px 9px -7px var(--fx-glow);
	--fx-left: -7px 0 9px -7px var(--fx-glow);
	--fx-right: 7px 0 9px -7px var(--fx-glow);
}
.fx-table tr.fx-row.fx-mine > td { box-shadow: var(--fx-up); }
.fx-table tr.fx-row.fx-mine > td.fx-state { box-shadow: var(--fx-up), var(--fx-left), var(--fx-down); }
.fx-table tr.fx-row.fx-mine > td:last-child { box-shadow: var(--fx-up), var(--fx-right); }
.fx-table tr.fx-tables.fx-mine > td { box-shadow: var(--fx-right), var(--fx-down); }
.fx-table tr.fx-row-bye.fx-mine > td { box-shadow: var(--fx-up), var(--fx-down); }
.fx-table tr.fx-row-bye.fx-mine > td:last-child { box-shadow: var(--fx-up), var(--fx-right), var(--fx-down); }

/* A finished fixture is its card's link (UV, 25 Oct): pointing at either
 * of its rows, or focusing it, lights the whole box in the brand colour,
 * the outline as a link's glow and the inside washed. */
.fx-table tr.fx-link { cursor: pointer; }
.fx-table tr.fx-link:focus-visible { outline: none; }
.fx-table tr.fx-link:is(:hover, :focus-visible),
.fx-table tr.fx-link:is(:hover, :focus-visible) + tr.fx-link,
.fx-table tr.fx-link:has(+ tr.fx-link:hover) {
	--fx-line: color-mix(in srgb, var(--color-primary) 55%, transparent);
}
.fx-table tr.fx-link:is(:hover, :focus-visible) > td,
.fx-table tr.fx-link:is(:hover, :focus-visible) + tr.fx-link > td,
.fx-table tr.fx-link:has(+ tr.fx-link:hover) > td { background: var(--hover-wash); }

/* A fixture's state: a strip down the left of the fixture, the full height
 * of its row and its tables row (the cell spans both), as the leagues list
 * draws a season's (UV, 24 Oct). Its name is in the strip for a screen
 * reader and in its title on hover. */
.fx-table td.fx-state {
	position: relative;
	width: var(--space-1);
	min-width: var(--space-1);
	padding: 0 var(--space-2);
}
.fx-table td.fx-state::before {
	content: '';
	position: absolute;
	top: var(--space-2);
	bottom: var(--space-2);
	left: var(--space-2);
	width: var(--space-1);
	border-radius: var(--radius-pill);
	background: var(--strip-color, transparent);
	box-shadow: var(--strip-glow, none);
}
/* Playing is the warning amber and finished the site's green, both lit
 * (UV, 25 Oct): a finished night was grey, which read as not started. */
.fx-state-none        { --strip-color: var(--border-color); }
.fx-state-scheduled   { --strip-color: var(--color-primary); }
.fx-state-in_progress { --strip-color: var(--color-warning); }
.fx-state-complete    { --strip-color: var(--color-primary); }
.fx-state-abandoned   { --strip-color: var(--color-error); }
.fx-state-reopened    { --strip-color: var(--color-warning); }
.fx-state-in_progress,
.fx-state-reopened,
.fx-state-complete    { --strip-glow: 0 0 10px color-mix(in srgb, var(--strip-color) 60%, transparent); }

/* A team: its picture, then its name and how many play for it, a link to
 * its page (still to come) that glows like a row. The home side faces the
 * middle from the left, the away side from the right. */
.fx-team {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-width: 0;
	padding: var(--space-1);
	border-radius: var(--radius-md);
	color: inherit;
	text-align: center;
	text-decoration: none;
	transition: box-shadow 0.15s;
}
/* A finished fixture's teams are not links (the box is), so only a link glows. */
a.fx-team:hover,
a.fx-team:focus-visible { box-shadow: var(--glow-primary); outline: none; }
.fx-home .fx-team { flex-direction: row-reverse; }
.fx-names { display: flex; flex-direction: column; align-items: center; min-width: 0; }
.fx-name { font-weight: 600; line-height: 1.25; overflow-wrap: break-word; }
.fx-sub { font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; }
.fx-bye { display: block; color: var(--text-muted); font-style: italic; }
.team-pic {
	flex: 0 0 auto;
	width: 2rem;
	height: 2rem;
	border-radius: var(--radius-round);
	display: grid;
	place-items: center;
	background: var(--hover-wash);
	color: var(--color-primary);
	overflow: hidden;
}
.team-pic svg { width: 60%; height: 60%; }
/* A team's own picture fills the circle (TDC.teamPic, 29 Oct). */
.team-pic img { width: 100%; height: 100%; object-fit: cover; }

/* A fixture's buttons, side by side in the middle column: Start, Move,
 * Remove (or the card and Take off once there is a match), each a ring
 * icon that draws itself in (ring-status.js, status.css). Remove's icon is
 * the error colour. Each says what it does in its title and label. */
.fx-actions { display: flex; justify-content: center; gap: var(--space-1); }
.tdc-card button.fx-icon {
	flex: 0 0 auto;
	width: 2.1rem;
	height: 2.1rem;
	padding: 0;
	margin: 0;
	border: none;
	border-radius: var(--radius-round);
	background: transparent;
	cursor: pointer;
	transition: box-shadow 0.15s ease;
	-webkit-tap-highlight-color: transparent;
}
.tdc-card button.fx-icon:hover,
.tdc-card button.fx-icon:focus-visible { box-shadow: var(--glow-primary); outline: none; }
.fx-icon-danger .tdc-ring .mark { stroke: var(--color-error); }
.fx-icon-danger .tdc-ring .dots { fill: var(--color-error); }
.fx-icon .sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}
.fx-v { color: var(--text-muted); }

/* The middle line: home score, the buttons, away score. Each score sits
 * against its own team's badge (UV, 25 Oct). */
.fx-mid-line { display: flex; align-items: center; justify-content: center; gap: var(--space-2); }
/* Between two scores the colon is their size. */
.fx-score + .fx-v,
.fx-v-busy { font-size: 2rem; line-height: 1; }
.fx-v-busy { display: none; }

/* A score and buttons together are wider than a phone (434px with a
 * director's three buttons, against a 380px card at 420px; measured 25
 * Oct). There the score closes up round its colon and the buttons take the
 * line under it. A finished fixture has no buttons, so it is never here. */
@media (max-width: 34rem) {
	.fx-mid-busy { flex-wrap: wrap; row-gap: var(--space-2); }
	.fx-mid-busy .fx-score-home { order: 1; }
	.fx-mid-busy .fx-v-busy     { order: 2; display: inline; }
	.fx-mid-busy .fx-score-away { order: 3; }
	.fx-mid-busy .fx-actions    { order: 4; flex-basis: 100%; }
}
/* The score as tall as a team's picture (2rem, .team-pic; UV, 25 Oct). */
.fx-score {
	min-width: 1.2em;
	font-size: 2rem;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	line-height: 1;
	text-align: center;
}
.fx-mid-sub { display: block; margin-top: var(--space-1); font-size: 0.7rem; color: var(--text-muted); white-space: nowrap; }

/* The tables a fixture is played on, in a small row under it: steppers on
 * their side that scroll sideways when there are many, and a + and a -. */
.fx-table tr.fx-tables td:not(.fx-state) { padding: 0 0 var(--space-1); }
.fx-tables-line {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--space-2);
	min-width: 0;
}
.fx-tables-line .stepper-row { min-width: 0; }
.fx-tables-label {
	flex: 0 0 auto;
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--text-muted);
}
.fx-tables-read { font-size: 0.85rem; color: var(--text-muted); }
.tdc-card .fx-tables-line button.fx-table-btn {
	flex: 0 0 auto;
	width: 1.6rem;
	height: 1.6rem;
	padding: 0;
	margin: 0;
	border: var(--control-border) solid var(--control-line) !important;
	border-radius: var(--radius-round);
	background: transparent;
	color: var(--control-line);
	font-size: 0.95rem;
	line-height: 1;
	letter-spacing: 0;
}
.tdc-card .fx-tables-line button.fx-table-btn:hover { box-shadow: var(--glow-primary); color: var(--color-primary); }

/* The gap between one fixture and the next. Its line went when each fixture
 * got its outline (UV, 25 Oct). */
.fx-table tr.fx-sep td { padding: var(--space-1) 0; }

/* Moving a fixture: the date and time under its row. */
.fx-table tr.fx-edit td { padding: var(--space-3) 0; }
.fx-edit .field-row { margin-bottom: var(--space-3); }
.fx-edit .btn-row { justify-content: center; }
.fx-edit .btn-row > .btn { flex: 0 1 auto; }

/* Every fixture: each date and time a centred heading across the table. */
.fx-table tr.fx-when td {
	padding: var(--space-4) 0 var(--space-2);
	text-align: center;
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
	border-bottom: 1px solid var(--border-color);
}
.fx-add-to { text-align: center; }

/* ── The season page: the banner, the numbers, the teams (UV, 24 Oct) ──
 *
 * The banner is the league at a glance: its picture in a large circle, the
 * name big, the season under it and its status as a badge, the top edge the
 * status colour (as a search tile's); then how it is played, as label and
 * value pairs that run into columns on a PC. Then the numbers so far as
 * tiles. Teams are boxes with their shield, name and counts in the header,
 * each player a picture, a name and a role, linked to their profile.
 */
.jumbo {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: center;
	gap: var(--space-4) var(--space-5);
	padding: var(--space-5);
	margin-bottom: var(--space-4);
	border: 1px solid var(--border-color);
	border-top: var(--space-1) solid var(--strip-color, var(--color-primary));
	border-radius: var(--radius-lg);
	background:
		radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--strip-color, var(--color-primary)) 14%, transparent), transparent 60%),
		var(--bg-surface);
}
.jumbo-pic {
	width: 5rem;
	height: 5rem;
	border-radius: var(--radius-round);
	display: grid;
	place-items: center;
	background: var(--hover-wash);
	color: var(--color-primary);
}
.jumbo-pic svg { width: 58%; height: 58%; }
.jumbo-main { min-width: 0; text-align: left; }
/* The name with its status badge to the right, on the heading's bottom
 * line (UV, 24 Oct). The badge sits in the heading after the name, so when a
 * long name wraps it stays beside the last line. In the body's type, not
 * the heading's capitals. */
.jumbo-main h1 { margin: 0; text-align: left; overflow-wrap: break-word; }
.jumbo-title .jumbo-status {
	margin-left: var(--space-2);
	vertical-align: baseline;
	font-family: var(--font-body);
	text-transform: none;
	letter-spacing: normal;
	white-space: nowrap;
}
.tdc-card .jumbo-season { margin: var(--space-1) 0 0; color: var(--text-muted); text-align: left; }
.jumbo-status { border-color: var(--strip-color, var(--color-primary)); color: var(--strip-color, var(--color-primary)); }

.jumbo-facts {
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr));
	gap: var(--space-3) var(--space-5);
	margin: 0;
	padding-top: var(--space-4);
	border-top: 1px solid var(--border-color);
}
.jumbo-fact { min-width: 0; }
.jumbo-fact dt {
	font-size: 0.66rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
}
.jumbo-fact dd { margin: var(--space-1) 0 0; overflow-wrap: break-word; }

@media (max-width: 30rem) {
	.jumbo { padding: var(--space-4); gap: var(--space-3) var(--space-4); }
	.jumbo-pic { width: 3.5rem; height: 3.5rem; }
}

/* The numbers so far: tiles, as many to a row as fit. */
.league-stats {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 6.25rem), 1fr));
	gap: var(--space-2);
	margin-bottom: var(--space-5);
}
.league-stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-1);
	padding: var(--space-3) var(--space-2);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	background: var(--bg-surface);
	text-align: center;
}
.league-stat-value { font-size: 1.5rem; font-weight: 700; color: var(--color-primary); line-height: 1.1; }
.league-stat-label { font-size: 0.7rem; color: var(--text-muted); letter-spacing: 0.04em; }

/* A team: a box whose header is its shield, name and numbers. */
.team-boxes { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); }
.team-box {
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	background: var(--bg-surface);
	scroll-margin-top: var(--space-6);
}
.team-box.is-mine { border-color: color-mix(in srgb, var(--color-primary) 55%, var(--border-color)); }
.team-box > summary {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	padding: var(--space-3);
	cursor: pointer;
	list-style: none;
	border-radius: var(--radius-md);
	transition: box-shadow 0.15s;
}
.team-box > summary::-webkit-details-marker { display: none; }
.team-box > summary::after { content: '+'; margin-left: auto; padding-left: var(--space-2); color: var(--color-primary); font-weight: 700; transition: opacity var(--dots-dim) ease; }
/* A team loading its players: the dots sit on the + / – (TDC.groupDots),
   which is in the heading's padding at the right; it hides meanwhile. */
.team-box > summary { position: relative; }
.team-box > summary > .group-dots { right: calc(var(--space-3) - (var(--group-dots-size) - 0.6em) / 2); }
.team-box[open] > summary::after { content: '\2013'; }
.team-box > summary:hover,
.team-box > summary:focus-visible { box-shadow: var(--glow-primary); outline: none; }
.team-box > summary .team-pic { width: 2.75rem; height: 2.75rem; }
.team-box-names { display: flex; flex-direction: column; min-width: 0; }
.team-box-name { font-size: 1.05rem; font-weight: 700; overflow-wrap: break-word; }
.team-box-sub { font-size: 0.78rem; color: var(--text-muted); }
.team-box > :not(summary) { margin-inline: var(--space-3); }
.team-box > :last-child:not(summary) { margin-bottom: var(--space-3); }
/* Opening a team fades its players in (UV, 24 Oct: fade what changes). */
.team-box[open] > :not(summary) { animation: team-in var(--control-reveal) ease; }
@keyframes team-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .team-box[open] > :not(summary) { animation: none; } }

/* A player's row in a team: the captain's buttons drop under the name when
 * the row is narrow, rather than squeezing the name to a letter a line (the
 * .list-row-actions trap in docs/ui.md). */
.team-box .list-row { flex-wrap: wrap; row-gap: var(--space-2); }
.team-box .list-row-main { flex: 1 1 12rem; }
.team-box .list-row-actions { flex-wrap: wrap; }

/* A person: their picture (or initials), name and role, one link to their
 * profile that glows like a row. */
.person {
	display: inline-flex;
	align-items: center;
	gap: var(--space-3);
	max-width: 100%;
	padding: var(--space-1) var(--space-2) var(--space-1) var(--space-1);
	border-radius: var(--radius-pill);
	color: inherit;
	text-decoration: none;
	transition: box-shadow 0.15s;
}
.person:hover,
.person:focus-visible { box-shadow: var(--glow-primary); outline: none; }
.person-pic {
	flex: 0 0 auto;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: var(--radius-round);
	overflow: hidden;
	display: grid;
	place-items: center;
	background: var(--hover-wash);
	color: var(--color-primary);
	font-size: 0.8rem;
	font-weight: 700;
}
.person-pic img { width: 100%; height: 100%; object-fit: cover; }
.person-names { display: flex; flex-direction: column; min-width: 0; }
.person-name { font-weight: 600; overflow-wrap: break-word; }
.person-sub { font-size: 0.78rem; color: var(--text-muted); }

/* ── A league's own picture (24 Oct) ──
 * In the banner, a search tile and the settings page's preview: the round
 * frame clips it, the picture fills it. Without one, the trophy. */
.jumbo-pic,
.league-tile-pic { overflow: hidden; }
.jumbo-pic img,
.league-tile-pic img { width: 100%; height: 100%; object-fit: cover; }

/* The settings page: the preview beside its two buttons. */
.league-pic-row {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	margin-top: var(--space-2);
}
.league-pic-row .btn-row { margin-bottom: 0; }
.league-pic-row .btn-row > .btn { flex: 0 1 auto; }
.league-pic-field .status { margin-top: var(--space-2); }

/* ── Teams and payment on the manage page: a heading row for each team ──
 * (UV, 24 Oct) The team's name and how many of the table's players are on
 * it, across the whole table, a line above it to part one team from the
 * next. */
.tdc-table tr.team-sep td {
	padding: var(--space-4) 0 var(--space-2);
	border-top: 1px solid var(--color-primary);
	border-bottom: 1px solid var(--border-color);
	text-align: left;
}
.tdc-table tr.team-sep:first-child td { border-top: none; padding-top: var(--space-2); }
.team-sep-name {
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
}
.team-sep-count { margin-left: var(--space-2); font-size: 0.75rem; color: var(--text-muted); }

/* ── The team card (UV, 24 Oct) ─────────────────────────────────────────
 * A banner with both teams and the card's state; the sessions, each frame a
 * row of home player, L and W switches for each side, away player; every
 * player's frames as a table; the result as a banner; the signatures as a
 * form waiting to be signed. */
.card-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

/* The card's state: the banner's top edge, glow and badge. The keys are the
 * script's stateOf(); a new state needs a line here. */
.card-state-lineups  { --strip-color: var(--color-primary); }
.card-state-playing  { --strip-color: var(--color-success); }
.card-state-awaiting { --strip-color: var(--color-warning); }
.card-state-reopened { --strip-color: var(--color-warning); }
.card-state-disputed { --strip-color: var(--color-error); }
.card-state-agreed   { --strip-color: var(--color-success); }
.card-state-approved { --strip-color: var(--text-muted); }

/* A player named on the card: their picture and name. */
.card-person {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	min-width: 0;
	max-width: 100%;
}
.card-person .person-pic { width: 1.75rem; height: 1.75rem; font-size: 0.68rem; }
.card-person-sm .person-pic { width: 1.4rem; height: 1.4rem; font-size: 0.6rem; }
.card-person-name { min-width: 0; overflow-wrap: break-word; line-height: 1.25; }

/* The banner: two teams either side of the state (or the score). */
.card-jumbo { grid-template-columns: minmax(0, 1fr); text-align: center; }
.cj-head {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	align-items: center;
	gap: var(--space-3);
}
.cj-team {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-2);
	min-width: 0;
}
.card-jumbo .cj-pic { width: 4.5rem; height: 4.5rem; }
.cj-name {
	font-family: var(--font-display);
	font-size: 1.35rem;
	line-height: 1.15;
	overflow-wrap: anywhere;
}
.cj-mid { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.cj-mid .jumbo-status { white-space: nowrap; }
.cj-v { font-family: var(--font-display); font-size: 1.5rem; color: var(--text-muted); }
.tdc-card .cj-detail { margin: 0; color: var(--text-muted); text-align: center; }
.card-jumbo .jumbo-facts { text-align: left; grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.5rem), 1fr)); }

/* The result: the score big in the middle, the side ahead in the brand
 * colour. */
.card-summary { margin-top: var(--space-6); }
.cj-score {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-3);
	font-family: var(--font-display);
	font-size: 3rem;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	color: var(--color-primary);
}
.cj-dash { color: var(--text-muted); font-size: 2rem; }
.card-summary[data-lead="home"] .cj-team:first-child .cj-name,
.card-summary[data-lead="away"] .cj-team:last-child .cj-name { color: var(--color-primary); }

@media (max-width: 30rem) {
	.card-jumbo .cj-pic { width: 3.25rem; height: 3.25rem; }
	.cj-name { font-size: 1.1rem; }
	.cj-score { font-size: 2.4rem; }
}

/* A session: a box of frame rows, each on the same four tracks so the
 * switches line up down the session and the totals sit under them. */
.cs-session {
	margin-bottom: var(--space-4);
	padding: var(--space-3) var(--space-3) var(--space-2);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	background: var(--bg-surface);
}
.tdc-card .cs-title { margin: 0 0 var(--space-2); font-size: 0.95rem; }
/* A session folds (UV, 29 Oct). It is a set-group for the fold's motion, but
 * keeps its own box and heading rather than the settings groups' look. */
.cs-session.set-group { border-top: 1px solid var(--border-color); padding: var(--space-3) var(--space-3) var(--space-2); }
.cs-session.set-group:not([open]) { padding-bottom: 0; }
.cs-session.set-group > summary.cs-title {
	display: flex;
	align-items: baseline;
	gap: var(--space-2);
	font-family: var(--font-display);
	font-size: 0.95rem;
	font-weight: inherit;
	letter-spacing: normal;
	text-transform: none;
	color: var(--text-primary);
	margin: 0 0 var(--space-2);
}
.cs-title-score { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-muted); }
.cs-grid { --cs-mid: calc(var(--tri-width) + 2.6rem); }
.cs-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) var(--cs-mid) minmax(0, 1fr);
	align-items: center;
	gap: var(--space-2);
	padding: var(--space-2) 0;
	border-bottom: 1px solid var(--border-color);
}
.cs-head { padding-top: 0; }
.cs-team {
	font-size: 0.68rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
	overflow-wrap: anywhere;
}
.cs-head .cs-home { grid-column: 1; text-align: right; }
.cs-head .cs-away { grid-column: 3; text-align: left; }

.cs-player { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.cs-player.cs-home { align-items: flex-end; text-align: right; }
.cs-player.cs-away { align-items: flex-start; text-align: left; }
.cs-player.is-won .card-person-name { color: var(--color-primary); font-weight: 700; }
.cs-sub { font-size: 0.7rem; color: var(--text-muted); }
.cs-empty { color: var(--text-muted); font-style: italic; }

/* A seat: the player, and a Reserve badge when it is not the position's
 * own player. Where a reserve can go in, the seat is the way in: the
 * picker lies invisibly over it, so a tap opens the phone's own list. */
.cs-seat {
	position: relative;
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-1) var(--space-2);
	max-width: 100%;
	border-radius: var(--radius-pill);
}
.cs-player.cs-home .cs-seat,
.cs-player.cs-home .card-person { flex-direction: row-reverse; }
.cs-seat.is-pickable { padding: 2px var(--space-2) 2px 2px; cursor: pointer; transition: box-shadow 0.15s; }
.cs-player.cs-home .cs-seat.is-pickable { padding: 2px 2px 2px var(--space-2); }
.cs-seat.is-pickable:hover,
.cs-seat.is-pickable:focus-within { box-shadow: var(--glow-primary); }
.cs-seat.is-pickable .card-person-name,
.cs-seat.is-pickable .cs-empty { text-decoration: underline dotted; text-underline-offset: 3px; }
.tdc-card .cs-seat > select.cs-reserve {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	padding: 0;
	opacity: 0;
	cursor: pointer;
	font-size: 16px;
}
.tdc-card .cs-badge {
	padding: 0.05rem 0.4rem;
	font-size: 0.62rem;
	border-color: var(--color-warning);
	color: var(--color-warning);
}
/* On a phone the picture goes above the name, so the name has the column. */
@media (max-width: 30rem) {
	.cs-seat,
	.cs-player.cs-home .cs-seat { flex-direction: column; }
	.cs-player .card-person,
	.cs-player.cs-home .card-person { flex-direction: column; gap: var(--space-1); }
	.cs-player .card-person-name { font-size: 0.88rem; }
	.cs-seat.is-pickable,
	.cs-player.cs-home .cs-seat.is-pickable { padding: var(--space-1); border-radius: var(--radius-md); }
}

/* L over W in the middle: home at the left end, nobody in the middle, away
 * at the right, its letter either side. */
.cs-toggles { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); }
.cs-tog { display: flex; align-items: center; gap: var(--space-2); }
.cs-tog-key {
	width: 0.8rem;
	font-size: 0.72rem;
	font-weight: 700;
	color: var(--text-muted);
	text-align: center;
	transition: color 0.2s ease, text-shadow 0.2s ease;
}
/* The letter beside the chosen end lights up. */
.cs-tog-key.is-on {
	color: var(--color-primary);
	text-shadow: 0 0 8px color-mix(in srgb, var(--color-primary) 75%, transparent);
}
.cs-tog-lag .cs-tog-key.is-on {
	color: var(--color-warning);
	text-shadow: 0 0 8px color-mix(in srgb, var(--color-warning) 75%, transparent);
}

/* Changed since this person last signed (UV, 29 Oct): the switch's outer
 * bar turns the edited blue with a soft glow; the knob and its icon are left
 * as they are. It was the knob's ring (28 Oct). */
.cs-tog.is-edited .tdc-tri-track,
.cs-tog.is-edited .tdc-tri:hover .tdc-tri-track {
	border-color: var(--color-edited);
	box-shadow: 0 0 10px color-mix(in srgb, var(--color-edited) 60%, transparent);
}

/* The totals, either side of the middle, under each team's end. */
.cs-total { border-bottom: none; }
.cs-tots {
	grid-column: 2;
	display: flex;
	justify-content: space-between;
	padding: 0 calc(1.3rem + var(--tri-height) / 2 - 1.25rem);
}
.cs-tot { display: flex; flex-direction: column; align-items: center; width: 2.5rem; }
.cs-tot-label { font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }
.cs-tot-value { font-size: 1.35rem; font-weight: 700; color: var(--color-primary); font-variant-numeric: tabular-nums; }

/* On a PC the sessions sit two to a row (UV, 28 Oct): 1 and 2, then 3 and
 * 4. A phone keeps one under another. */
@media (min-width: 992px) {
	#session-list {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 0 var(--space-4);
		align-items: start;
	}
}

.tdc-card .card-hint { margin: 0 0 var(--space-4); font-size: 0.85rem; text-align: center; }

/* The two views of every player's frames, a pill like the league's pages
 * with an icon in each option (UV, 28 Oct). */
.cp-views {
	display: flex;
	gap: 2px;
	width: fit-content;
	max-width: 100%;
	margin: 0 auto var(--space-4);
	padding: var(--space-1);
	border: var(--control-border) solid var(--control-line);
	border-radius: var(--radius-pill);
}
.tdc-card button.cp-view {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	width: auto;
	margin: 0;
	padding: var(--space-2) var(--space-3);
	border: none;
	border-radius: var(--radius-pill);
	background: transparent;
	color: var(--text-primary);
	font-size: var(--select-text);
	font-weight: 600;
	letter-spacing: 0;
	text-transform: none;
	white-space: nowrap;
	transition: background-color 0.15s ease;
}
.tdc-card button.cp-view:hover,
.tdc-card button.cp-view:focus-visible { background: var(--hover-wash); outline: none; }
.tdc-card button.cp-view[aria-pressed="true"] { background: var(--color-primary); color: var(--color-on-primary); }
.cp-view svg {
	width: 1.15rem;
	height: 1.15rem;
	flex: none;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linejoin: round;
}
.cp-view svg circle { fill: currentColor; stroke: none; }

/* Head to head: a table per team, side by side when both fit, one under
 * the other when they do not. */
.h2h-tables {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
	gap: var(--space-5);
	align-items: start;
}
.tdc-card .h2h-title { margin: 0 0 var(--space-2); font-size: 0.95rem; color: var(--color-primary); text-align: center; }
.card-players th.h2h-when { vertical-align: bottom; font-size: 0.7rem; white-space: normal; min-width: 4.5rem; color: var(--text-muted); text-transform: none; letter-spacing: normal; text-align: left; }
.card-players.h2h-table th.cp-player { min-width: 3rem; padding-left: var(--space-1); padding-right: var(--space-1); white-space: normal; }
.h2h-table .cp-name { font-size: 0.72rem; }
.card-players th.h2h-row { min-width: 6rem; text-align: left; white-space: normal; text-transform: none; letter-spacing: normal; font-weight: 600; }
.h2h-row .card-person-name { font-size: 0.8rem; }
.h2h-row .cp-pos { margin-left: calc(1.4rem + var(--space-2)); }
.card-players td.h2h-cell { vertical-align: middle; white-space: nowrap; padding-left: var(--space-1); padding-right: var(--space-1); }
.card-players td.h2h-cell.is-none,
.card-players td.cp-cell.is-none { background: var(--hover-wash); }
/* A frame changed since a captain signed: the edited blue round the cell. */
/* A changed frame's cells glow blue inside (UV, 29 Oct; a hard border before). */
.card-players td.is-edited { box-shadow: inset 0 0 10px color-mix(in srgb, var(--color-edited) 70%, transparent); }
.card-players .h2h-won { font-weight: 700; }

/* A frame's mark: a green dot for a win, a yellow ring for the lag, round
 * the dot or on its own; a dash while it is not played. A frame lost
 * without the lag is the empty space. */
.h2h-mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.5rem;
	height: 1.5rem;
	border: 2px solid transparent;
	border-radius: 50%;
	vertical-align: middle;
}
.h2h-mark.is-won::before {
	content: '';
	width: 0.75rem;
	height: 0.75rem;
	border-radius: 50%;
	background: var(--color-success);
	box-shadow: 0 0 8px color-mix(in srgb, var(--color-success) 70%, transparent);
}
.h2h-mark.is-lag {
	border-color: var(--color-warning);
	box-shadow: 0 0 6px color-mix(in srgb, var(--color-warning) 55%, transparent);
}
.h2h-mark.is-open::before { content: '–'; color: var(--text-muted); line-height: 1; }
/* A break & finish or a golden break: BF or GB in the win's green, glowing
 * as the dot does, in place of it (UV, 29 Oct); the lag's ring still round
 * it. */
.h2h-mark.is-special::before { content: none; }
.h2h-mark.is-special {
	font-size: 0.62rem;
	font-weight: 800;
	letter-spacing: 0.02em;
	line-height: 1;
	color: var(--color-success);
	text-shadow: 0 0 6px color-mix(in srgb, var(--color-success) 70%, transparent);
}
/* On a phone a five-man table fits without scrolling: the row's names lose
 * their pictures (the column headings keep theirs) and the marks shrink. */
@media (max-width: 30rem) {
	.card-players th.h2h-row { min-width: 4.5rem; }
	.h2h-row .person-pic { display: none; }
	.h2h-row .cp-pos { margin-left: 0; }
	.card-players.h2h-table th.cp-player { min-width: 2.6rem; }
	.h2h-table .cp-name { font-size: 0.64rem; overflow-wrap: normal; }
	.h2h-table .h2h-mark { width: 1.3rem; height: 1.3rem; }
	.h2h-table .h2h-mark.is-won::before { width: 0.65rem; height: 0.65rem; }
}
.h2h-key .h2h-mark { width: 1.1rem; height: 1.1rem; margin-left: var(--space-2); }
.h2h-key .h2h-mark.is-won::before { width: 0.55rem; height: 0.55rem; }

/* Every player's frames: a column per position each side, a gap between
 * the two teams, a row per session. */
.card-players th,
.card-players td,
.card-players td.num,
.card-players td:last-child,
.card-players th:last-child { text-align: center; padding-left: var(--space-2); padding-right: var(--space-2); }
.card-players .cp-label { white-space: nowrap; }
.card-players .cp-team { color: var(--color-primary); border-bottom: none; }
.card-players th.cp-player { vertical-align: bottom; min-width: 4.5rem; text-transform: none; letter-spacing: normal; }
.cp-player .person-pic { width: 1.75rem; height: 1.75rem; margin: 0 auto var(--space-1); font-size: 0.68rem; }
.cp-name { display: block; font-size: 0.78rem; font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere; }
.cp-pos { display: block; font-size: 0.62rem; color: var(--text-muted); }
/* Between the teams: the score, each session's and the night's. */
.card-players .cp-sep {
	padding-left: var(--space-3);
	padding-right: var(--space-3);
	border-left: 1px solid var(--border-color);
	border-right: 1px solid var(--border-color);
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}
.card-players th.cp-sep { vertical-align: bottom; }
.card-players .cp-score { font-weight: 700; color: var(--color-primary); }
.cp-colon { margin: 0 var(--space-1); color: var(--text-muted); font-weight: 400; }
.card-players .cp-cell.is-won { color: var(--color-primary); font-weight: 700; }
.card-players .cp-cell.is-open { color: var(--text-muted); }
.card-players tfoot td { border-top: 1px solid var(--color-primary); border-bottom: none; font-weight: 700; }

/* The result and the signatures: one section in the banner's style (UV,
 * 29 Oct; the result was a banner of its own above a plain form). On a PC
 * only as wide as it needs, centred; on a phone the width of the page. The
 * frames' tables sit side by side in it while they fit (a flex row, which,
 * unlike an auto-fit grid, gives the section a width to shrink to). */
.sign-form.jumbo {
	width: fit-content;
	max-width: 100%;
	margin: var(--space-6) auto var(--space-4);
	text-align: center;
}
@media (max-width: 40rem) {
	.sign-form.jumbo { width: auto; }
}
.sf-top { min-width: 0; }
.sf-frames { min-width: 0; padding-top: var(--space-4); border-top: 1px solid var(--border-color); }
.sign-form .h2h-tables { display: flex; flex-wrap: wrap; justify-content: center; }
.sign-form .h2h-team { flex: 0 1 auto; min-width: 0; }
.sign-form .h2h-key { margin-bottom: 0; }

/* The player's view (UV, 29 Oct): their frames as one session block, as
 * wide as a session on a PC, then their two small tables side by side
 * while they fit, centred. */
#mine-frames .cs-mine { max-width: 40rem; margin-inline: auto; }
.mine-tables {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: flex-start;
	gap: var(--space-5);
	margin-top: var(--space-5);
}
.mine-tables > div { min-width: 0; max-width: 100%; }
.mine-table td.mine-opp { text-align: left; }
.tdc-card .sf-league {
	margin: 0;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--color-primary);
}
.tdc-card .sf-date { margin: var(--space-1) 0 0; color: var(--text-muted); }
/* Each side's line under its team in the banner's head. The two share two
 * rows (line, captain), so the lines stay level whatever wraps. */
.sf-sides {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	grid-template-rows: repeat(2, auto);
	gap: var(--space-2) var(--space-5);
	padding-top: var(--space-2);
	border-top: 1px solid var(--border-color);
}
.sf-side { display: grid; grid-row: span 2; grid-template-rows: subgrid; justify-items: center; min-width: 0; }
/* The line a captain signs on: empty until they sign, then "Signed" and
 * when, in the success colour, or the warning colour once the card has
 * changed since. */
.sf-line {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	align-items: center;
	width: 100%;
	min-height: 3.5rem;
	margin-top: var(--space-3);
	padding-bottom: var(--space-1);
	border-bottom: 1px solid var(--text-muted);
}
.sf-signed { font-family: var(--font-display); font-size: 1.2rem; color: var(--color-success); }
.sf-when { font-size: 0.72rem; color: var(--text-muted); }
.sf-line.is-stale .sf-signed { color: var(--color-warning); }
.sf-cap { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--space-1) var(--space-2); font-size: 0.8rem; }
.sf-cap-label { width: 100%; font-size: 0.62rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }
.tdc-card .sf-note { margin: var(--space-5) 0; font-size: 0.9rem; color: var(--text-muted); }
.tdc-card .sf-note.is-disputed { color: var(--color-error); }
/* The changelog (UV, 29 Oct): a group per signature, newest first, each
   change as rows of Frame · Change · Was · Now with who and when beneath. */
/* Each signature's set of changes folds on its own (UV, 29 Oct): a set-group
   for the fold's motion, with the signature as its heading. */
.cl-group.set-group { margin: 0; padding: var(--space-3) 0 0; text-align: left; }
.cl-group.set-group:first-child { border-top: none; }
.cl-group.set-group > summary.cl-head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 var(--space-2);
	margin: 0 0 var(--space-2);
	font-size: 1rem;
	font-weight: inherit;
	letter-spacing: normal;
	text-transform: none;
	color: var(--text-primary);
}
.cl-count { margin-left: auto; font-size: 0.75rem; color: var(--text-muted); }
.cl-by { font-size: 0.75rem; color: var(--text-muted); }
.tdc-card .cl-since,
.tdc-card .cl-none { margin: 0 0 var(--space-2); font-size: 0.8rem; color: var(--text-muted); }
.cl-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.cl-table th { padding: var(--space-1); font-size: 0.62rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); text-align: left; }
.cl-table td { padding: var(--space-1); vertical-align: top; }
.cl-table td.num { width: 3.2rem; text-align: center; font-variant-numeric: tabular-nums; }
.cl-table th:first-child { text-align: center; }
.cl-was { color: var(--text-muted); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--text-muted) 60%, transparent); }
.cl-now { color: var(--color-edited); }
.cl-team, .cl-player { display: block; }
.cl-player { font-size: 0.75rem; }
/* The lag in its yellow and the winner in its green, as their switches. */
.cl-change.is-lag .cl-what,
.cl-change.is-lag .cl-now { color: var(--color-warning); }
.cl-change.is-win .cl-what,
.cl-change.is-win .cl-now { color: var(--color-primary); }
.cl-who td { padding-bottom: var(--space-2); border-bottom: 1px solid color-mix(in srgb, var(--border-color) 60%, transparent); font-size: 0.72rem; color: var(--text-muted); }
.cl-who td::before { content: ''; display: inline-block; width: 3.2rem; }
.cl-table tbody tr:last-child td { border-bottom: none; }
.sf-buttons { display: flex; flex-direction: column; gap: var(--space-3); }
.sf-buttons > .btn { width: 100%; margin: 0; }

/* The lineup (UV, 29 Oct): one row per player, here tonight's switch and
   their position's stepper side by side at the right. */
.card-lineup-row { align-items: center; }
/* The stepper loses a chevron at its limit and shrinks (UV, 24 Oct): in a
   slot as wide as a whole one, so the switches stay in one column. */
.card-lineup-controls { display: grid; grid-template-columns: auto 4.6rem; align-items: center; justify-items: center; gap: var(--space-3); }
/* As tall as the switch beside it (UV, 29 Oct). */
.card-lineup-controls .tdc-stepper.is-across {
	box-sizing: border-box;
	height: var(--switch-height);
	--sn: calc(var(--stepper-across-number) * 1.25);
}

/* ── Standings (UV, 29 Oct) ───────────────────────────────────────────
   The Standings tab's two tables (league-standings.js) and the columns
   builder on the Settings tab (league-standings-edit.js). Both pills are
   the card's .cp-views. */
/* Every column centred, the numbers large (UV, 29 Oct). Headings wrap, so
   a long column name does not widen its column. */
.tdc-card .sd-table th,
.tdc-card .sd-table td { text-align: center; }
.tdc-card .sd-table th { white-space: normal; vertical-align: bottom; }
.tdc-card .sd-table td.num { font-size: 1.15rem; font-weight: 600; }
.tdc-card .sd-nested .sd-table td.num { font-size: 1rem; }
.sd-table .sd-rank { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.sd-table .team-pic { width: 2rem; height: 2rem; }
/* A player's picture no taller than a line of their name (UV, 29 Oct):
   the name's size times the table's line height, so it never sets the
   row's height. */
.sd-table { --sd-name-size: 0.92rem; --sd-line: 1.25; --sd-pic: calc(var(--sd-name-size) * var(--sd-line)); line-height: var(--sd-line); }
.sd-nested .sd-table { --sd-name-size: 0.85rem; }
.sd-table .person-pic { width: var(--sd-pic); height: var(--sd-pic); font-size: 0.5rem; }
/* Centred in their column (UV, 29 Oct): the circles are blocks, so margins,
   not text-align. */
.sd-table .person-pic,
.sd-table .team-pic { margin-left: auto; margin-right: auto; }
/* The names left-aligned, heading included (UV, 29 Oct); every other
   column stays centred. */
.tdc-card .sd-table td.sd-name,
.tdc-card .sd-table th.sd-name { text-align: left; }
/* The rank at the name's size, smaller than the numbers (UV, 29 Oct). */
.tdc-card .sd-table td.sd-rank { font-size: var(--sd-name-size); }
.sd-table .sd-name { font-weight: 600; overflow-wrap: break-word; }
.sd-table .sd-name a { color: var(--text-primary); text-decoration: none; }
.sd-table .sd-name a:hover,
.sd-table .sd-name a:focus-visible { color: var(--color-primary); outline: none; }
.tdc-card .sd-by { text-align: center; font-size: 0.85rem; margin-top: calc(-1 * var(--space-3)); }
.sd-switches { margin-bottom: var(--space-4); }

/* The names at the table's own size, the numbers alone large (UV, 29 Oct:
   "revert the size of the names"). Stated, and the phone told not to
   enlarge the text in this wide box itself (Chrome's font boosting on
   Android, Safari turned sideways), which nothing on the site had said. */
.sd-table { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
.tdc-card .sd-table td.sd-name { font-size: var(--sd-name-size); }

/* As tight as it can be, both ways (UV, 29 Oct, which replaced "at least
   --space-3 above and below"): a quarter rem round every cell, a team's
   players included, and no minimum column width. */
.tdc-card .sd-table td,
.tdc-card .sd-table th { padding: var(--space-1); }

/* Every second row tinted (UV, 29 Oct; .sd-alt, set by the script, since a
   team's hidden players row would upset nth-child). */
.sd-table { --sd-tint: color-mix(in srgb, var(--text-primary) 5%, transparent); }
.sd-table > tbody > tr.sd-alt > td { background-color: var(--sd-tint); }

/* A team's + / – smaller than the fixtures page's (UV, 29 Oct). */
.tdc-card .sd-teams button.sd-toggle { width: 1.5rem; height: 1.5rem; }

/* Rank, picture and name frozen at the left as the table scrolls sideways
   (UV, 29 Oct), in Team Rankings after the + / –. The picture freezes too:
   between two frozen columns it would slide under the name. Each has a
   fixed width so the next knows where to stop: --sd-lead is the + / –
   column (none in Individual Rankings, nor in a team's players, who start
   at the left edge). A frozen cell
   needs a solid background, the page's, with the row's tint laid over it. */
.sd-table { --sd-lead: 0rem; --sd-w-rank: 1.75rem; --sd-w-pic: 2.5rem; --sd-w-lead: 2rem; }
.sd-table.sd-teams { --sd-lead: var(--sd-w-lead); }
/* A team's players start at the left edge (UV, 29 Oct: no left padding),
   so their frozen columns do too. */
.sd-nested .sd-table { --sd-lead: 0rem; }
.sd-table .sd-rank,
.sd-table .sd-pic,
.sd-table .sd-name,
.sd-teams > * > tr > .sd-toggle-cell {
	position: sticky;
	z-index: 1;
	background-color: var(--bg-base);
}
.tdc-card .sd-teams > * > tr > .sd-toggle-cell {
	left: 0;
	width: var(--sd-w-lead);
	min-width: var(--sd-w-lead);
	max-width: var(--sd-w-lead);
	box-sizing: border-box;
	padding-left: 0;
	padding-right: var(--space-2);
}
.tdc-card .sd-table .sd-rank {
	left: var(--sd-lead);
	width: var(--sd-w-rank);
	min-width: var(--sd-w-rank);
	max-width: var(--sd-w-rank);
	box-sizing: border-box;
	padding-left: 0;
	padding-right: 0;
}
.tdc-card .sd-table .sd-pic {
	left: calc(var(--sd-lead) + var(--sd-w-rank));
	width: var(--sd-w-pic);
	min-width: var(--sd-w-pic);
	max-width: var(--sd-w-pic);
	box-sizing: border-box;
	padding-left: 0;
	padding-right: 0;
}
.sd-table .sd-name { left: calc(var(--sd-lead) + var(--sd-w-rank) + var(--sd-w-pic)); }
.sd-table > tbody > tr.sd-alt > td.sd-rank,
.sd-table > tbody > tr.sd-alt > td.sd-pic,
.sd-table > tbody > tr.sd-alt > td.sd-name,
.sd-teams > tbody > tr.sd-alt > td.sd-toggle-cell {
	background-color: var(--bg-base);
	--sd-g-tint: linear-gradient(var(--sd-tint), var(--sd-tint));
}
/* The heading rows frozen too (UV, 29 Oct). A frozen heading sticks to the
   box that scrolls, and the page's own scroll does not count, so each
   table's box scrolls both ways, at most three-quarters of the screen tall.
   The heading's line is a shadow: a collapsed table's border stays behind
   when the row moves. The frozen corner sits over both. */
/* At most one screen tall (UV, 29 Oct), and edge to edge: the card's
   side padding (1.25rem, .tdc-card in forms.css) taken back, so the table
   has the whole width of a phone. A team's players stay inside it. */
.table-scroll.sd-scroll { max-height: 100vh; max-height: 100dvh; overflow: auto; }
.tdc-card .league-panel > div > .table-scroll.sd-scroll { margin-left: -1.25rem; margin-right: -1.25rem; }
.sd-table > thead > tr > th {
	position: sticky;
	top: 0;
	z-index: 2;
	background-color: var(--bg-base);
	box-shadow: inset 0 -1px 0 var(--border-color);
}
.sd-table > thead > tr > th.sd-rank,
.sd-table > thead > tr > th.sd-pic,
.sd-table > thead > tr > th.sd-name,
.sd-teams > thead > tr > th.sd-toggle-cell { z-index: 3; }
/* A team's players keep their heading in place: the team table's heading
   is the one frozen at the top. */
.sd-nested .sd-table > thead > tr > th { top: auto; z-index: 1; }
/* The sideways fade only at the right: at the left it would dim the
   frozen columns. */
@supports (animation-timeline: scroll()) {
	.table-scroll.sd-scroll {
		-webkit-mask-image: linear-gradient(to right, black calc(100% - var(--fade-r)), transparent);
		mask-image: linear-gradient(to right, black calc(100% - var(--fade-r)), transparent);
	}
}

/* A team's players, under it, from the left edge. As narrow as
   they need, so their numbers sit beside their names. Their box does not
   scroll on its own: the team table's does, so their columns freeze too. */
.tdc-card .sd-nested > td { padding: 0; text-align: left; }
.sd-nested .table-scroll.sd-scroll {
	margin-bottom: 0;
	max-height: none;
	overflow: visible;
	-webkit-mask-image: none;
	mask-image: none;
	animation: none;
}
.sd-nested .sd-table { width: auto; font-size: 0.85rem; }
.sd-nested .empty { padding: var(--space-3); }

/* A cell hovered or tapped lights its row and column with a green inner
   glow (UV, 29 Oct; league-standings.js). Each edge is a gradient layer,
   so a row's glow runs unbroken across its cells (a shadow's spread left a
   gap at every cell's edge): the row lights its cells' top and bottom (and
   its two ends), the column its cells' sides (and its two ends), so the two
   meet as one cross. The last layer is a frozen cell's row tint. */
.sd-table {
	--sd-glow: color-mix(in srgb, var(--color-primary) 70%, transparent);
	--sd-edge: 5px;
}
.sd-table th,
.sd-table td {
	--sd-g-t: linear-gradient(transparent, transparent);
	--sd-g-b: linear-gradient(transparent, transparent);
	--sd-g-l: linear-gradient(transparent, transparent);
	--sd-g-r: linear-gradient(transparent, transparent);
	--sd-m-t: linear-gradient(transparent, transparent);
	--sd-m-b: linear-gradient(transparent, transparent);
	--sd-m-l: linear-gradient(transparent, transparent);
	--sd-m-r: linear-gradient(transparent, transparent);
	--sd-g-tint: linear-gradient(transparent, transparent);
	background-image: var(--sd-g-t), var(--sd-g-b), var(--sd-g-l), var(--sd-g-r),
		var(--sd-m-t), var(--sd-m-b), var(--sd-m-l), var(--sd-m-r), var(--sd-g-tint);
}
.sd-table td { cursor: pointer; }
.sd-table tr.sd-hl-row > * {
	--sd-g-t: linear-gradient(to bottom, var(--sd-glow), transparent var(--sd-edge));
	--sd-g-b: linear-gradient(to top, var(--sd-glow), transparent var(--sd-edge));
}
.sd-table tr.sd-hl-row > :first-child { --sd-g-l: linear-gradient(to right, var(--sd-glow), transparent var(--sd-edge)); }
.sd-table tr.sd-hl-row > :last-child { --sd-g-r: linear-gradient(to left, var(--sd-glow), transparent var(--sd-edge)); }
.sd-table .sd-hl-col {
	--sd-g-l: linear-gradient(to right, var(--sd-glow), transparent var(--sd-edge));
	--sd-g-r: linear-gradient(to left, var(--sd-glow), transparent var(--sd-edge));
}
.sd-table .sd-hl-col.sd-hl-top { --sd-g-t: linear-gradient(to bottom, var(--sd-glow), transparent var(--sd-edge)); }
.sd-table .sd-hl-col.sd-hl-bottom { --sd-g-b: linear-gradient(to top, var(--sd-glow), transparent var(--sd-edge)); }

/* The signed-in person's own rows glow yellow, always (UV, 29 Oct): their
   player row and their team's row. Drawn the same way, under the green,
   so a highlight on their own row still shows. */
.sd-table { --sd-mine: color-mix(in srgb, var(--color-warning) 75%, transparent); }
.sd-table tr.sd-me > * {
	--sd-m-t: linear-gradient(to bottom, var(--sd-mine), transparent var(--sd-edge));
	--sd-m-b: linear-gradient(to top, var(--sd-mine), transparent var(--sd-edge));
}
.sd-table tr.sd-me > :first-child { --sd-m-l: linear-gradient(to right, var(--sd-mine), transparent var(--sd-edge)); }
.sd-table tr.sd-me > :last-child { --sd-m-r: linear-gradient(to left, var(--sd-mine), transparent var(--sd-edge)); }

/* The builder: the columns as a table of three rows. */
.sc-cols th,
.sc-cols td { text-align: center; vertical-align: middle; }
.tdc-card .sc-cols td:last-child,
.tdc-card .sc-cols th:last-child { text-align: center; }
.sc-cols .sc-row-label { text-align: left; color: var(--text-muted); white-space: nowrap; }
.sc-cols .sc-name { white-space: normal; min-width: 6.5rem; color: var(--text-primary); letter-spacing: 0.04em; }
.sc-cols .sc-name .sub { margin-top: var(--space-1); font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--text-muted); }
.sc-tool-row { display: flex; justify-content: center; gap: var(--space-1); }
.tdc-card .sc-tool-row button.fx-icon:disabled { opacity: 0.3; cursor: default; box-shadow: none; }
/* A hint outside a .field, so it is given the field hint's look here. */
.tdc-card .sc-hint { text-align: center; font-size: 0.8rem; color: var(--text-muted); margin: calc(-1 * var(--space-3)) 0 var(--space-3); }
.sc-reset-row { justify-content: center; margin-bottom: var(--space-5); }
.sc-reset-row > .btn { flex: 0 1 auto; }

.sc-label {
	margin: var(--space-4) 0 var(--space-2);
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-muted);
}
/* One button per value and per operator, wrapping. */
.sc-keys { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tdc-card .sc-keys > .sc-key { width: auto; flex: 0 0 auto; margin: 0; text-transform: none; letter-spacing: 0; }
/* The operators and brackets bigger (UV, 29 Oct): a sign alone is small. */
.tdc-card .sc-keys > .sc-key.sc-op { min-width: 3.2rem; padding: var(--space-2) var(--space-3); font-size: 1.5rem; line-height: 1; }
.sc-num-row { display: flex; align-items: center; gap: var(--space-3); }
.sc-num-row input { flex: 0 1 8rem; min-width: 0; text-align: center; }
.tdc-card .sc-num-row > .btn { width: auto; flex: 0 0 auto; margin: 0; }

/* The equation as it is built: each part a small pill. */
.sc-eq {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-1);
	min-height: 2.75rem;
	padding: var(--space-2) var(--space-3);
	border: var(--control-border) solid var(--control-line);
	border-radius: var(--radius-md);
	margin-bottom: var(--space-2);
}
.sc-part { padding: 0 var(--space-2); border-radius: var(--radius-pill); line-height: 1.8; }
.sc-part-var { background: var(--hover-wash); color: var(--color-primary); font-weight: 600; }
.sc-part-num { background: var(--hover-wash); font-variant-numeric: tabular-nums; }
.sc-part-op,
.sc-part-paren { font-weight: 700; }
.sc-eq-tools { margin-bottom: var(--space-4); }
