/* THEME */

:root {
	--line: 2.6px; /* every border and outline */
	/* Sizes inside the keypad and the darts column: 1vmin, but smaller where
	   those are narrower than usual (landscape squarer than 4:3; see PORTRAIT
	   for the band), so text never outgrows its key. */
	--u: min(1vmin, 0.75vw);
	--border: var(--line) solid white;
	--border-muted: var(--line) solid #969696;
	--radius: 10px;
	--text: white;
	--text-muted: #969696;
	--text-soft: #c8c8c8;
	--value: white; /* the thrower's stats and past visits */
	--value-idle: #d4d4d4; /* everyone else's: lighter than their labels (--text-soft at most) */
	--panel: linear-gradient(#484848, #161616);
	--button: linear-gradient(#808080, #404040);
	--button-disabled: linear-gradient(#404040, #202020);
	--button-pressed: linear-gradient(#484848, #202020);
	--row: #161616;
	--checkout: #00c800;
	--checkout-now: #00fa00; /* the thrower's finish */
	--go-top: #2e8a22; /* the main button (Start) and the button that sends a score */
	--go-bottom: #1a5212;
	--active-top: #6fb4ff; /* the player throwing */
	--active-bottom: #2f6fb0;
	--active-big-middle: #3f80c4; /* the same, 1-2 players: where their name and stats meet */
	--active-line: #173450; /* their history and stats lines */
	--dim: brightness(0.5); /* players out of focus while a score is entered or a player edited */
	--edit: #e6b84a; /* a player whose menu is open, and the menu */
	--edit-dark: #8a6414; /* the bottom of its gradient */
	--menu-row: linear-gradient(var(--edit), var(--edit-dark));
	--menu-line: #3a2e0e; /* their history and stats lines */
	--menu-panel: linear-gradient(#4a3c18, #1a1508);
	--history-muted: #6e6e6e; /* zero and bust visits */
	--ton-forty: #ffa64d; /* 140+ visits */
	--max: #ff6a3c; /* 180s */
	--star-game: #ffd24d; /* the star on a player's best visit of the game */
	--font: "Roboto Flex", sans-serif;
	--font-condensed: "Roboto Condensed", sans-serif;
	--bust: #ff3216;
	/* Dartboard */
	--board-black: #000000;
	--board-white: #ffffff;
	--board-red: #af3215;
	--board-green: #63af4a;
	--board-legend: #000000;
	--board-number: #ffffff;
	--board-seam: rgba(0, 0, 0, 0.6);
	--board-hit: #ffd24d;
	--dart-edit: #ffd24d; /* a dart picked up to move: always this yellow, whatever the highlight colour */
	--dart-flight: #2f7de1; /* blue for now: one day, your own darts */
	--ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
	--ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);
	--fast: 120ms;
	--medium: 220ms;
	--slow: 400ms;
}

input,
select,
textarea {
	user-select: text;
	-webkit-user-select: text;
}

[hidden] {
	display: none !important;
}

/* GENERAL */

html, body {
	margin: 0;
	padding: 0;
	height: 100%;
	width: 100%;
	overflow: hidden;
	font-family: var(--font);
}

body {
	/* Clear of a phone's notch and home bar, once, and within the screen's height. */
	box-sizing: border-box;
	padding-top: env(safe-area-inset-top);
	padding-right: env(safe-area-inset-right);
	padding-bottom: env(safe-area-inset-bottom);
	padding-left: env(safe-area-inset-left);
	/* A scoreboard, not a document: taps and double taps never select text. */
	user-select: none;
	-webkit-user-select: none;
	-webkit-touch-callout: none;
	-webkit-tap-highlight-color: transparent;
	transform: scale(1);
	transform-origin: 0 0;
	overscroll-behavior: none;
	touch-action: manipulation;
}

main {
	display: flex;
	height: 100%;
	background: linear-gradient(#242424, #000000);
}

section {
	position: relative;
}

aside {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 30%;
	border-right: var(--border);
	background: var(--panel);
	z-index: 1;
}

/* The keypad folds away to give the players the whole column. */
aside.keypad-hidden .scores-section {
	height: 100%;
}

aside.keypad-hidden .calc-section {
	height: 0;
	visibility: hidden;
}

/* With nothing under it, the list needs no line at its bottom. */
aside.keypad-hidden .scores-section.overflowing,
aside.keypad-hidden .scores-section .history-row:last-child .history-cell {
	border-bottom: none;
}

/* Set for a moment while the list is laid out for where the keypad is going. */
aside.keypad-instant :is(.scores-section, .calc-section) {
	transition: none !important;
}


/* SETTINGS */

.settings-background {
	position: absolute;
	width: 100%;
	height: 100%;
	background: rgba(0, 0, 0, 0.8);
	display: flex;
	justify-content: center;
	align-items: center;
	z-index: 100;
}

.settings-section {
	background: var(--panel);
	border: var(--border);
	border-radius: var(--radius);
	padding: 2vmin;
	width: 50%;
	max-height: 90%;
	overflow-y: auto;
	box-sizing: border-box;
}

.settings-tbl {
	width: 100%;
	border-spacing: 1vmin;
	color: var(--text);
	font-size: 3vmin;
}

.settings-tbl td {
	padding: 1vmin;
	vertical-align: bottom;
}

.new-game-section .settings-check {
	display: flex;
	align-items: center;
	gap: 1vmin;
	margin: 0;
	color: var(--text);
	cursor: pointer;
}

.new-game-section .settings-check input {
	flex: none;
	width: 3vmin;
	height: 3vmin;
	margin: 0;
	accent-color: var(--checkout);
}

/* Settings never scrolls as a whole; only the player list does. */
.settings-main {
	/* Half the screen, but wide enough for the game settings row on 4:3. Full
	   height, the room left over going to the player list. */
	width: max(50%, 78vmin);
	height: 95%;
	max-height: 95%;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.new-game-section .settings-check:has(input:disabled) {
	opacity: 0.4;
}

.settings-version {
	float: right;
	padding-top: 0.8vmin;
	font-size: 2vmin;
	font-weight: normal;
	color: var(--text-muted);
}

/* Dialogs take the focus when they open (for the keyboard), without a ring. */
.settings-background:focus {
	outline: none;
}

.settings-heading {
	margin: 1vmin 1vmin 0;
	padding-bottom: 0.6vmin;
	border-bottom: 1px solid var(--text-muted);
	font-family: var(--font-condensed);
	font-size: 3.2vmin;
	font-weight: 600;
	color: var(--text);
}

@property --fade-top {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --fade-bottom {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

.players-scroll {
	flex: 1 1 auto;
	min-height: 12vmin;
	/* In line with the fields and buttons in the tables around it. The few px
	   of padding keep the fields' side borders off the clipped edge, where
	   they lost a sliver at fractional screen scaling. */
	margin: 1vmin calc(2vmin - 3px) 0;
	padding: 0 3px;
	overscroll-behavior: contain;
}

/* Names scrolled out of view fade out at that edge. */
.players-scroll,
.draft-list {
	overflow-y: auto;
	scrollbar-width: none;
	mask-image: linear-gradient(transparent, black var(--fade-top), black calc(100% - var(--fade-bottom)), transparent);
	transition: --fade-top var(--medium), --fade-bottom var(--medium);
}

.players-scroll::-webkit-scrollbar,
.draft-list::-webkit-scrollbar {
	display: none;
}

.players-scroll.fade-top,
.draft-list.fade-top {
	--fade-top: 5vmin;
}

.players-scroll.fade-bottom,
.draft-list.fade-bottom {
	--fade-bottom: 5vmin;
}

.players-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.player-item {
	padding: 0.5vmin 0;
}

/* While a player is dragged the others slide aside to make room (JS sets
   their transforms); on release the player settles into its slot. */
.players-list.sorting .player-item {
	transition: transform var(--medium) var(--ease-out);
}

.player-item:is(.dragging, .dropping, .moving) {
	position: relative;
	z-index: 1;
}

.players-list.sorting .player-item.dragging {
	transition: none;
	opacity: 0.9;
}

.players-list.sorting .player-item.dropping {
	transition: transform var(--fast) var(--ease-out);
}

.player-item:is(.dragging, .dropping, .moving) .player-field {
	border-color: var(--text);
	box-shadow: 0 1vmin 2vmin rgba(0, 0, 0, 0.6);
}

/* Name with its controls inside the field: grip, name, up, down, remove. */
.player-field {
	display: flex;
	align-items: center;
	height: 5vmin;
	background: #242424;
	border: 1px solid var(--text-muted);
	border-radius: var(--radius);
	color: var(--text);
}

.settings-section .player-field input {
	flex: 1;
	min-width: 0;
	height: 100%;
	padding: 0 0.5vmin;
	font-family: var(--font);
	font-size: 2.6vmin;
	color: var(--text);
	background: none;
	border: none;
	outline: none;
}

/* The handle to drag a player by, three lines (see pressPlayer). */
.grip {
	align-self: stretch;
	touch-action: none; /* a drag here moves the player, not the list */
	cursor: grab;
	width: 2.2vmin;
	padding: 0 1.2vmin;
	color: var(--text-muted);
	--bar: linear-gradient(currentColor 0 0);
	background:
		var(--bar) center calc(50% - 0.7vmin) / 2.2vmin 0.3vmin no-repeat content-box,
		var(--bar) center / 2.2vmin 0.3vmin no-repeat content-box,
		var(--bar) center calc(50% + 0.7vmin) / 2.2vmin 0.3vmin no-repeat content-box;
}

.dragging .player-field,
.dragging .player-field * {
	cursor: grabbing;
}

.field-btn {
	width: 5vmin;
	height: 100%;
	padding: 0;
	font-size: 2.2vmin;
	color: var(--text);
	background: none;
	border: none;
	border-left: 1px solid #3a3a3a;
	cursor: pointer;
}

.field-btn:active {
	transform: scale(0.85);
}

.field-btn:disabled {
	color: #4a4a4a;
	cursor: default;
}

.delete-player {
	color: var(--bust);
}

.players-add {
	width: 100%;
	height: 5vmin;
	margin: 0.5vmin 0;
	font-family: inherit;
	font-size: 3.6vmin;
	line-height: 1;
	color: var(--text);
	border: var(--border);
	border-radius: var(--radius);
	background: var(--panel);
	cursor: pointer;
}

/* Settings, at the top: the game being played in a line, and New game beside it. */
.current-game {
	display: flex;
	align-items: center;
	gap: 2vmin;
	margin: 2vmin 2vmin 1vmin;
}

.settings-summary {
	flex: 1;
	min-width: 0;
	margin: 0;
	font-family: var(--font-condensed);
	font-size: 2.8vmin;
	color: var(--text);
}

.settings-summary b {
	font-size: 3.2vmin;
	font-weight: 600;
}

.current-game .settings-btn-action {
	flex: none;
	width: auto;
	padding: 1vmin 3vmin;
	font-size: 3vmin;
}

/* New game: what to play as tiles, grouped, then its options and who plays. */
.new-game-section {
	width: max(50%, 78vmin);
}

.game-group {
	margin: 1.6vmin 1vmin 1vmin;
	font-family: var(--font-condensed);
	font-size: 2.2vmin;
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--text-muted);
}

.game-tiles {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 1.4vmin;
	padding: 0 1vmin;
}

.game-tile {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.3vmin;
	min-height: 9vmin;
	padding: 1vmin;
	font-family: var(--font-condensed);
	color: var(--text);
	text-shadow: 0 0 8px black;
	border: var(--border);
	border-radius: var(--radius);
	background: var(--button);
	cursor: pointer;
}

.game-tile:active {
	transform: scale(0.96);
}

.game-tile b {
	font-size: 3vmin;
	font-weight: 500;
}

/* X01's tiles are just the start score: bigger. */
.game-tile:not(:has(small)) b {
	font-size: 4.4vmin;
}

.game-tile small {
	font-size: 2vmin;
	color: var(--text-soft);
}

.game-tile[aria-checked="true"] {
	border-color: var(--checkout);
	background: linear-gradient(var(--go-top), var(--go-bottom));
}

/* Under the tiles, only what the picked game has: the match, with legs and
   sets as − n + steppers, then its options. */
.match-row {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	margin: 2vmin 1vmin 0;
	color: var(--text);
	font-size: 3vmin;
}

/* Sliding between its two steps, the panel shows no scrollbar. */
.new-game-section.sliding {
	overflow: hidden;
}

/* First to: the legs and sets slide out beside the match picker; Endless
   (no winner) folds them away. It takes the rest of the row, so 0fr really is
   nothing: sized to its content, the column never folded and only the fade showed. */
.counts-reveal {
	flex: 1 1 0;
	min-width: 0;
	display: grid;
	grid-template-columns: 0fr;
	opacity: 0;
	transition: grid-template-columns var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

.counts-reveal.open {
	grid-template-columns: 1fr;
	opacity: 1;
}

.counts-reveal.instant {
	transition: none;
}

.counts {
	display: flex;
	gap: 2.5vmin;
	min-width: 0;
	overflow: hidden;
	padding-left: 3vmin;
	white-space: nowrap;
}

.stepper,
.option-choice {
	display: flex;
	flex-direction: column;
	gap: 0.75vmin;
}

.stepper-label {
	font-family: var(--font-condensed);
	color: var(--text-soft);
}

.stepper-row {
	display: flex;
	align-items: center;
}

.stepper-btn {
	width: 5.5vmin;
	height: 5.5vmin;
	padding: 0;
	font-family: var(--font);
	font-size: 3.4vmin;
	line-height: 1;
	color: var(--text);
	border: var(--border);
	border-radius: var(--radius);
	background: var(--button);
	cursor: pointer;
}

.stepper-btn:active {
	transform: scale(0.92);
}

.stepper-btn:disabled {
	opacity: 0.35;
	cursor: default;
}

.stepper output {
	min-width: 6vmin;
	font-family: var(--font-condensed);
	font-size: 3.6vmin;
	font-weight: 500;
	text-align: center;
	font-variant-numeric: tabular-nums;
}

/* Options: Double out, or the game's own choice (around the clock's beds)
   and checkboxes, labelled like Match. A game with none has no section. */
.game-options-group {
	display: flex;
	flex-direction: column;
	gap: 0.75vmin;
	margin: 2vmin 1vmin 0;
	font-size: 3vmin;
}

.game-options-group:not(:has(.check-line:not([hidden]))) {
	display: none;
}

.game-checks {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.8vmin 4vmin;
	/* Always as tall as around the clock's bed buttons, so picking another
	   game never resizes the screen. */
	min-height: 7vmin;
	color: var(--text);
	white-space: nowrap;
}


/* ⓘ: a small circled i beside something that may need explaining (app.js). */
.info-btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.4vmin;
	height: 2.4vmin;
	padding: 0;
	margin-left: 0.8vmin;
	font-family: var(--font);
	font-size: 1.6vmin;
	font-weight: 600;
	line-height: 1;
	touch-action: manipulation;
	color: var(--text-soft);
	background: none;
	border: 1px solid var(--text-muted);
	border-radius: 50%;
	cursor: help;
	transition: color var(--fast), border-color var(--fast);
}

/* A finger-sized tap area round the small circle, so a tap just beside it
   still opens the tip rather than ticking the checkbox it sits in. */
.info-btn::before {
	content: '';
	position: absolute;
	inset: -1.6vmin;
	border-radius: 50%;
}

.info-btn:hover,
.info-btn[aria-describedby] {
	color: var(--text);
	border-color: var(--text);
}

/* Anything with an ⓘ lines it up the same way: centred on the text, the same
   gap after it. A checkbox's ⓘ sits beside its label rather than in it, so
   pressing the ⓘ doesn't flash the checkbox. */
.check-line,
.stepper-label,
.range-name {
	display: flex;
	align-items: center;
}

/* The bubble it opens, over everything. */
.info-tip {
	position: fixed;
	z-index: 200;
	max-width: min(40vmin, 90vw);
	box-sizing: border-box;
	padding: 1.2vmin 1.6vmin;
	font-family: var(--font-condensed);
	font-size: 2.4vmin;
	line-height: 1.35;
	color: var(--text);
	background: #1e1e1e;
	border: 1px solid var(--text-muted);
	border-radius: var(--radius);
	box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.6);
	pointer-events: none;
}

.info-tip.opening {
	animation: fade-in var(--medium) var(--ease-out);
}

.info-tip.closing {
	animation: fade-out var(--medium) var(--ease-out) forwards;
}

/* Cancel and the next step, edge to edge with the tiles above. */
.dialog-actions {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 1.4vmin;
	margin: 2.4vmin 1vmin 0;
}

/* A row of buttons where one is picked (around the clock's beds, Solo or not). */
.segmented {
	display: inline-flex;
	border: var(--border);
	border-radius: var(--radius);
	overflow: hidden;
}

.segmented button {
	flex: 1;
	padding: 1vmin 2.2vmin;
	font-family: var(--font-condensed);
	font-size: 2.6vmin;
	white-space: nowrap;
	color: var(--text);
	text-shadow: 0 0 8px black;
	border: none;
	background: var(--button-disabled);
	cursor: pointer;
}

.segmented button + button {
	border-left: 1px solid var(--text-muted);
}

.segmented button[aria-checked="true"] {
	background: linear-gradient(var(--go-top), var(--go-bottom));
}

/* As tall as the legs and sets steppers beside it, so their labels line up too. */
.match-format {
	box-sizing: border-box;
	height: 5.5vmin;
}

/* Who's playing: Solo is one name; otherwise a list to add to and reorder. */
.segmented.who {
	display: flex;
	margin: 2vmin 1vmin 0;
}

.segmented.who button {
	padding: 1.4vmin;
	font-size: 3vmin;
}

.who-solo,
.who-group {
	margin: 2vmin 1vmin 0;
}

.solo-name {
	width: 100%;
	height: 6.5vmin;
	box-sizing: border-box;
	padding: 0 1.5vmin;
	font-family: var(--font);
	font-size: 3.2vmin;
	color: var(--text);
	background: #242424;
	border: 1px solid var(--text-muted);
	border-radius: var(--radius);
	outline: none;
}

.solo-name:focus {
	border-color: var(--text);
}

.draft-list {
	max-height: 42vmin;
	margin: 0;
	padding: 0;
	list-style: none;
}

.draft-list .player-field input {
	padding-left: 1.5vmin;
}

.settings-btn-action {
	width: 100%;
	padding: 1vmin;
	font-family: var(--font-condensed);
	font-size: 4vmin;
	font-weight: 500;
	color: var(--text);
	text-shadow: 0 0 8px black;
	border: var(--border);
	border-radius: var(--radius);
	background: var(--button);
	cursor: pointer;
}

.settings-btn-action:active {
	background: var(--button-pressed);
}

/* The action that settings changes are waiting on (Start new game). */
.settings-btn-action.primary {
	border-color: var(--checkout);
	background: linear-gradient(var(--go-top), var(--go-bottom));
	animation: fade-in var(--medium) var(--ease-out);
}

/* Smaller link-style button that opens a sub-page of Settings. */
.settings-btn-action.settings-link {
	font-size: 3vmin;
	font-weight: normal;
	background: var(--button-disabled);
}

/* Settings > Board layout: the controls take the place of the scores and
   keypad, and the board beside them is the preview. The rest of the screen
   sleeps until Done. */
body.visuals-open :is(.scores-section, .calc-section) {
	display: none;
}

body.visuals-open :is(.ctrl-section, .btn-section) {
	opacity: 0.4;
	pointer-events: none;
}


/* A colour row with its name above it (Highlight). */
.swatch-group {
	display: flex;
	flex-direction: column;
	gap: 1vmin;
	color: var(--text-soft);
}

.visuals-panel {
	display: flex;
	flex-direction: column;
	gap: 2vmin;
	height: 100%;
	box-sizing: border-box;
	padding: 1vmin 2vmin 2vmin;
	color: var(--text);
	font-family: var(--font-condensed);
	font-size: 2.8vmin;
	overflow-y: auto;
	scrollbar-width: none;
	outline: none;
	animation: fade-in var(--medium) var(--ease-out);
}

.visuals-panel .settings-heading {
	margin: 0;
}

.visuals-controls {
	display: flex;
	flex-direction: column;
	gap: 1.7vmin;
	padding: 0 1vmin;
}

/* Reset and Done side by side at the bottom. */
.visuals-actions {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 2vmin;
	margin-top: auto;
}

.range {
	display: grid;
	grid-template-columns: 1fr auto;
	row-gap: 0.3vmin;
	color: var(--text-soft);
}

.range output {
	color: var(--text);
	font-variant-numeric: tabular-nums;
}

.range input {
	grid-column: 1 / -1;
	width: 100%;
	margin: 0;
	accent-color: var(--checkout);
}

.swatches {
	display: flex;
	gap: 1.5vmin;
}

.swatch {
	width: 4.5vmin;
	height: 4.5vmin;
	padding: 0;
	border: var(--border-muted);
	border-radius: 50%;
	cursor: pointer;
	transition: transform var(--fast) var(--ease-out);
}

.swatch[aria-pressed="true"] {
	border-color: var(--checkout);
	transform: scale(1.15);
}

.visuals-panel .settings-check {
	display: flex;
	align-items: center;
	gap: 1vmin;
	cursor: pointer;
}

.visuals-panel .settings-check input {
	width: 2.6vmin;
	height: 2.6vmin;
	margin: 0;
	accent-color: var(--checkout);
}

/* Match stats (also under the winner): one column per player, each line's
   leader in green. Many players scroll sideways. */
.stats-section {
	width: auto;
	min-width: 40%;
	max-width: 90%;
}

.stats-scroll {
	overflow-x: auto;
	scrollbar-width: none;
}

.stats-tbl {
	margin: 1vmin auto 1.5vmin;
	border-collapse: collapse;
	font-family: var(--font-condensed);
	font-size: 2.6vmin;
	color: var(--text);
	font-variant-numeric: tabular-nums;
}

.stats-tbl :is(th, td) {
	padding: 0.5vmin 1.6vmin;
	text-align: center;
	white-space: nowrap;
}

.stats-tbl thead th {
	max-width: 18vmin;
	overflow: hidden;
	text-overflow: ellipsis;
	font-weight: 600;
	border-bottom: 1px solid var(--text-muted);
}

.stats-tbl tbody th {
	text-align: left;
	font-weight: normal;
	color: var(--text-soft);
}

.stats-tbl tbody tr + tr {
	border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.stats-tbl .lead {
	color: var(--checkout);
	font-weight: 600;
}

.stats-tbl small {
	font-size: 0.8em;
	font-weight: normal;
	color: var(--text-muted);
}

.winner-section {
	width: auto;
	min-width: 40%;
	text-align: center;
}

/* "Back to the last leg?" and the like, before an undo that takes back more than a turn. */
.confirm-section {
	width: auto;
	min-width: 40%;
	max-width: 60%;
	text-align: center;
}

.confirm-title {
	margin: 1vmin 1vmin 0;
	font-family: var(--font-condensed);
	font-size: 5vmin;
	font-weight: 500;
	color: var(--text);
}

.confirm-detail {
	margin: 1vmin 1vmin 1.5vmin;
	font-family: var(--font-condensed);
	font-size: 3vmin;
	color: var(--text-soft);
}

.winner-text {
	margin: 2vmin;
	font-family: var(--font-condensed);
	font-size: 7vmin;
	font-weight: 500;
	line-height: 1.1;
	color: var(--text);
	text-shadow: 0 0 8px black;
}

.winner-icon {
	font-size: 10vmin;
}

/* SCORES */

/* Sizes below are for four players; JS sets --s to grow or shrink them
   to the number of players (see layoutScores and SCORES_LAYOUT). */

.scores-section {
	height: 60%;
	flex: none;
	box-sizing: border-box;
	font-weight: 500;
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: none;
}

.scores-section::-webkit-scrollbar {
	display: none;
}

/* The last row's own border divides the scores from the keypad. Only when the
   list scrolls (a row is cut off) does the list draw the line itself, and the
   last row drops its own so the two never double up. */
.scores-section.overflowing {
	border-bottom: var(--border);
}

.scores-section.overflowing .history-row:last-child .history-cell {
	border-bottom: none;
}

/* Rows scrolled out of view fade out at that edge; the bottom one is taller
   and fades harder, so more players below are plain to see. The mask leaves
   the section's own borders (bottom, and right in portrait) untouched. */
.scores-section {
	mask-image:
		linear-gradient(transparent, black var(--fade-top), black calc(100% - var(--fade-bottom)), rgba(0, 0, 0, 0.3) calc(100% - var(--fade-bottom) * 0.4), transparent),
		linear-gradient(black, black),
		linear-gradient(black, black);
	mask-size: 100% 100%, 100% var(--line), var(--line) 100%;
	mask-position: 0 0, bottom, right;
	mask-repeat: no-repeat;
	mask-origin: padding-box, border-box, border-box;
	mask-clip: padding-box, border-box, border-box;
	transition: height var(--medium) var(--ease-out), --fade-top var(--medium), --fade-bottom var(--medium);
}

.scores-section.fade-top {
	--fade-top: 4vmin;
}

.scores-section.fade-bottom {
	--fade-bottom: 8vmin;
}

/* The cards' scale (layoutScores), as a number so it can ease: the cards grow
   with the room as the keypad folds away. */
@property --s {
	syntax: "<number>";
	inherits: true;
	initial-value: 1;
}

.scores-tbl.growing {
	transition: --s var(--medium) var(--ease-out);
}

.scores-tbl {
	--s: 1;
	/* The player rows' background layers (z-index -1, see .player-row) sit
	   in here, under every row's text. */
	isolation: isolate;
	table-layout: fixed;
	width: 100%;
	height: 100%;
	border-spacing: 0;
	color: #f0f0f0;
	line-height: 1;
}

.scores-tbl .active {
	color: white;
}

/* Chrome paints a row's background cell by cell, which leaves faint seams
   where the cells meet. Instead the first cell draws one layer behind the
   whole row. The layer goes under the whole table, not just this
   row, so text shadows from the line below aren't cut off at the row's edge;
   and it reaches a pixel into that line, so no hairline of the dark page shows
   between the two where the edge falls between screen pixels. Its two colours
   are registered, so the turn passing fades them (a gradient itself can't). */
@property --row-top {
	syntax: "<color>";
	inherits: true;
	initial-value: transparent;
}

@property --row-bottom {
	syntax: "<color>";
	inherits: true;
	initial-value: transparent;
}

.player-row {
	--row-top: #484848;
	--row-bottom: #242424;
	position: relative;
	height: calc(10vmin * var(--s));
}

.scores-tbl .player-row.active {
	--row-top: var(--active-top);
	--row-bottom: var(--active-bottom);
}

.player-wins::before,
.player-wins::after {
	content: '';
	position: absolute;
	inset: 0 0 -1px;
	z-index: -1;
	background: linear-gradient(var(--row-top), var(--row-bottom));
}

/* The menu tint, over the row's own background so it can fade in and out. */
.player-wins::after {
	background: var(--menu-row);
	opacity: 0;
	transition: opacity var(--medium) var(--ease-out);
}

.player-wins {
	width: 0.6vmin;
	font-size: calc(3.5vmin * var(--s));
	font-weight: 600;
	text-align: center;
	text-shadow: 0 0 0.5vmin black;
	line-height: 1.1;
	padding-left: 1vw;
	text-underline-offset: calc(0.5vmin * var(--s));
}

.player-wins u {
	text-decoration-color: var(--text-soft);
}

/* Endless: just the count of legs, "legs" under it. */
.player-wins:is(.endless, .one-set) u {
	text-decoration: none;
}

.player-wins.endless .player-sets {
	font-family: var(--font-condensed);
	font-size: 0.55em;
	font-weight: normal;
	color: var(--text-soft);
}

.active .player-wins {
	color: white;
}

.active .player-wins u {
	text-decoration-color: #e1e1e1;
}

.target-wins {
	font-family: var(--font-condensed);
	color: var(--text-soft);
	padding-top: 0.15vmin;
	width: calc(4vmin * var(--s));
	font-size: calc(2.5vmin * var(--s));
	font-weight: normal;
	text-align: center;
	text-shadow: 0 0 0.5vmin black;
	line-height: 1.25;
}

.active .target-wins {
	color: #e1e1e1;
}

/* The name and stats open a player's menu; in the history line, only what has a
   tap of its own shows it (a board turn, a leg dot, a finish). */
.player-row,
.stats-row,
.history .leg-dot {
	cursor: pointer;
}

/* Who threw first this leg: a small dot just before the name, in room every
   name keeps for it (so names don't move when the dot does). */
.player-name {
	position: relative;
}

.throw-first {
	position: absolute;
	top: calc(50% - 0.75vmin * var(--s));
	left: calc(0.5vmin * var(--s));
	width: calc(1.5vmin * var(--s));
	height: calc(1.5vmin * var(--s));
	border-radius: 50%;
	background: var(--text-soft);
	box-shadow: 0 0 0.5vmin black;
	opacity: 0;
	transform: scale(0.4);
	transition: opacity var(--medium) var(--ease-out), transform var(--medium) var(--ease-out);
}

.starts .throw-first {
	opacity: 1;
	transform: none;
}

.active .throw-first {
	background: white;
}

/* The name as shown; fitName in js/app.js narrows, wraps or shrinks it to fit. */
.name-text {
	display: flex;
	align-items: center;
	height: calc(9vmin * var(--s));
	padding: 0 1vmin 0 calc(2.6vmin * var(--s)); /* room for the throw-first dot */
	/* Cut off what doesn't fit, but leave room for the text shadow. */
	overflow: clip;
	overflow-clip-margin: 1vmin;
	font-family: var(--font-condensed);
	font-weight: normal;
	font-size: calc(6.5vmin * var(--s) * var(--name-size, 1));
	line-height: 1;
	text-shadow: 0 0 1vmin black;
	white-space: nowrap;
}

.name-text span {
	flex: none;
}

.name-text.narrow {
	font-family: var(--font);
}

.name-text.two-lines {
	font-size: calc(4.2vmin * var(--s) * var(--name-size, 1));
	line-height: 0.95;
	white-space: normal;
}

.name-text.two-lines span {
	flex: 1;
	min-width: 0;
}

.name-text.clipped span {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Everyone else steps back while a score is being entered (the thrower stays
   lit) or a player's menu is open (that player stays lit). JS sets .inputting.
   On the rows, not their cells: see .player-row. */
.scores-tbl tr {
	transition: filter var(--medium) var(--ease-out), background-color var(--slow) var(--ease-out), --row-top var(--slow) var(--ease-out), --row-bottom var(--slow) var(--ease-out);
}

.scores-tbl.inputting:not(:has(tr.menu-open)) tr:not(.active),
.scores-tbl:has(tr.menu-open) tr:not(.menu-open) {
	filter: var(--dim);
}

/* While a player's menu is open, or a past turn is on show, the rest of the
   screen steps back and stops reacting to the pointer (no hover lights or
   key presses); a tap anywhere just closes it. A past turn keeps the board,
   which shows its darts. JS sets the body classes; the reviewed player's
   rows get .review-focus. */
.ctrl-section,
.dartboard-section,
.btn-section {
	transition: opacity var(--medium) var(--ease-out);
}

body.menu-focus :is(.ctrl-section, .dartboard-section, .btn-section),
body.review-focus :is(.ctrl-section, .btn-section) {
	opacity: 0.4;
}

/* The keypad sits on the lighter side panel, where fading would wash it out:
   it darkens like the player rows above it instead (its transition is set
   with its fold-away one, under CALCULATOR). */
body:is(.menu-focus, .review-focus) .calc-section {
	filter: var(--dim);
}

/* Which way the score is going in, and the button that sends it, in the
   green of the New game screen's main button (Start). Typing: ✓ turns green,
   and the board's darts (still shown) turn grey with the darts column
   stepping back. Darts on the board: Done turns green. Nothing is cleared:
   using the other one switches. JS sets the body classes (renderInputting).
   The green is a gradient over each button's own fill, its two colours
   see-through until in use, so it fades in and out. */
@property --send-top {
	syntax: "<color>";
	inherits: false;
	initial-value: transparent;
}

@property --send-bottom {
	syntax: "<color>";
	inherits: false;
	initial-value: transparent;
}

.darts {
	transition: opacity var(--medium) var(--ease-out), margin-bottom var(--medium) var(--ease-out);
}

body.keypad-input:not(.visuals-open) .darts {
	opacity: 0.45;
}

/* Likewise the keypad's score rocker while the board is in use. (On its plate
   and what's on it: a table cell's own opacity didn't reach them.) */
td.calc-score::before,
td.calc-score > * {
	transition: opacity var(--medium) var(--ease-out);
}

body.board-input td.calc-score::before,
body.board-input td.calc-score > * {
	opacity: 0.45;
}

/* (Pressed, ✓ shows the keypad's pressed fill.) */
.calc-tbl td.check-score:not(.disabled, :active) {
	background: linear-gradient(var(--send-top), var(--send-bottom)), linear-gradient(#808080, #484848);
}

.done-btn:not(.disabled) {
	background: linear-gradient(var(--send-top), var(--send-bottom)), var(--button);
}

.calc-tbl td.check-score,
.side-btn.done-btn {
	transition: transform var(--fast) var(--ease-out), color var(--medium), border-color var(--medium), opacity var(--medium), box-shadow var(--hover-speed), --send-top var(--medium) var(--ease-out), --send-bottom var(--medium) var(--ease-out);
}

body.keypad-input .calc-tbl td.check-score:not(.disabled),
body.board-input .done-btn:not(.disabled) {
	--send-top: var(--go-top);
	--send-bottom: var(--go-bottom);
	border-color: var(--checkout);
}

/* The turn's darts, still on the board but not what is being entered. */
.light.hit {
	transition: fill var(--medium), stroke var(--medium), filter var(--medium);
}

body.keypad-input:not(.visuals-open) .light.hit {
	fill: color-mix(in srgb, white 12%, transparent); /* a mix, as the lit colours are: see light-from-hover */
	stroke: #9a9a9a;
	filter: none;
}

/* The sections themselves let taps through; their buttons and the board opt back in. */
body:is(.menu-focus, .review-focus) :is(.ctrl-section, .dartboard-section, .btn-section, .calc-section) *,
body:is(.menu-focus, .review-focus) #dartboard {
	pointer-events: none;
}

/* The tap that closed it stays asleep until it lifts (see 'dismissing' in app.js). */
body.dismissing * {
	pointer-events: none !important;
}

.scores-tbl:has(tr.review-focus) tr:not(.review-focus) {
	filter: var(--dim);
}

/* The player whose menu is open is tinted amber, like the menu. */
.scores-tbl tr.player-row.menu-open .player-wins::after {
	opacity: 1;
}

.scores-tbl tr.history-row.menu-open,
.scores-tbl tr.stats-row.menu-open,
.scores-tbl.big tr.stats-row.menu-open {
	background: var(--menu-line);
}

.player-score {
	width: calc(12vmin * var(--s));
	padding-right: 1.4vmin;
	font-size: calc(7.5vmin * var(--s));
	text-align: right;
	text-shadow: 0 0 1vmin black;
}

/* 121: the target under what is left of it, when there's no room for the
   stats line that shows it. */
.player-score[data-note] {
	position: relative;
}

.scores-tbl:not(.roomy) .player-score[data-note]::after {
	content: attr(data-note);
	position: absolute;
	right: 1.4vmin;
	bottom: 0;
	font-size: calc(1.8vmin * var(--s));
	line-height: 1;
	color: var(--text-soft);
}

.history-row {
	height: calc(5vmin * var(--s));
	background: var(--row);
}

.scores-tbl .hidden {
	display: none;
}

.history-cell {
	padding: 0;
	border-bottom: var(--border);
	border-top: var(--border-muted);
}

/* History on the left, checkout on the right at its full width, one line. */
.history-line {
	display: flex;
	align-items: center;
	height: 100%;
}

@property --fade-left {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --fade-right {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

.history {
	flex: 1 1 auto;
	align-self: stretch;
	display: flex;
	align-items: center;
	min-width: 0;
	padding-left: 1vw;
	/* Older turns fade out at the left edge when they scroll past it. */
	mask-image: linear-gradient(to right, transparent, black var(--fade-left), black calc(100% - var(--fade-right)), transparent);
	transition: --fade-left var(--medium), --fade-right var(--medium), filter var(--medium) var(--ease-out);
}

.history.fade-left {
	--fade-left: 6vmin;
}

.history.fade-right {
	--fade-right: 3vmin;
}

.history span {
	flex: none;
	color: var(--text-soft);
	font-size: calc(2.25vmin * var(--s));
	font-weight: normal;
	padding-right: 0.5vw;
	line-height: 1.35;
}

.history span b {
	color: var(--value);
	transition: color var(--medium) var(--ease-out), background-color var(--medium) var(--ease-out), box-shadow var(--medium) var(--ease-out);
}

/* The whole height of the line and a little either side, so a tap on a finish
   is a tap on the finish, not on the card behind it (which opens the menu). */
.checkout {
	flex: none;
	align-self: stretch;
	display: flex;
	flex-wrap: wrap; /* never wraps (it is as wide as its content): lets one baseline-aligned line be centred */
	align-content: center;
	align-items: baseline;
	padding: 0 1vw 0 2vmin;
	font-size: calc(3vmin * var(--s));
	white-space: nowrap;
	color: var(--text-soft); /* the thrower's is green: what to throw now */
	cursor: pointer;
}

.history-row.active .checkout:not(.muted) {
	color: var(--checkout-now);
}

.checkout-steps {
	margin-left: 0.25em;
}

/* Which of how many: slides out beside the target for a moment after a tap. */
.checkout-count {
	flex: none;
	max-width: 0;
	margin-left: 0;
	overflow: hidden;
	opacity: 0;
	font-size: 0.68em;
	/* On the finish's baseline, then up so the digits' middle meets the finish's. */
	position: relative;
	bottom: 0.167em;
	font-style: normal;
	color: var(--text-soft);
	transition: max-width var(--medium) var(--ease-out), margin-left var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

.checkout.counting .checkout-count {
	max-width: 3.2em;
	margin-left: 0.35em;
	opacity: 1;
}

/* What's been thrown of the finish being followed. */
.checkout-steps span {
	transition: opacity var(--medium) var(--ease-out);
}

.checkout-steps span.done {
	opacity: 0.35;
}

.checkout.hint {
	cursor: default;
}

.checkout.hint.muted {
	color: var(--history-muted);
}

/* Only when there is room: a line of match stats between the name and the history. */
.stats-row {
	position: relative; /* see the player-wins layer below */
	height: calc(5vmin * var(--s));
	background: var(--row);
}

.scores-tbl:not(.roomy) .stats-row {
	display: none;
}

.scores-tbl .stats-row.active,
.scores-tbl .history-row.active {
	background: var(--active-line);
}

/* With darts on the board, the thrower's past turns can't be tapped to show:
   their bar steps back (the checkout beside them stays lit, and tappable). */
.scores-tbl.darts-down .history-row.active:not(.menu-open) {
	background: color-mix(in srgb, var(--active-line) 45%, black);
}

.scores-tbl.darts-down .history-row.active:not(.menu-open) .history {
	filter: var(--dim);
}

.scores-tbl.darts-down .history-row.active:not(.menu-open) .history span {
	pointer-events: none;
}

/* With the score beside the name, the stats line is part of the player's
   field: the name row's layer (and menu tint) reaches down behind it. The line
   is positioned so it still paints over that layer when its row is dimmed. */
.scores-tbl.roomy:not(.big) .player-wins::before,
.scores-tbl.roomy:not(.big) .player-wins::after {
	/* The stats line is half the name row (5 to 10vmin), also when the table
	   stretches its rows to fill the list: as a share of the row it always
	   reaches the bottom, where a fixed 5vmin fell short. */
	bottom: calc(-50% - 1px);
}

.scores-tbl.roomy:not(.big) .stats-row,
.scores-tbl.roomy:not(.big) .stats-row.active,
.scores-tbl.roomy:not(.big) tr.stats-row.menu-open {
	background: none;
}

/* On the thrower's bright field the labels need the lighter grey, as in .big. */
.scores-tbl.roomy:not(.big) .stats-row.active .stats {
	color: var(--text-soft);
	text-shadow: 0 0 0.5vmin black;
}

.stats-cell {
	padding: 0 1.4vmin 0 1vw;
}

.stats-line {
	display: flex;
	align-items: center;
	justify-content: space-between;
	height: 100%;
}

.stats {
	display: flex;
	gap: 2.5vmin;
	font-family: var(--font-condensed);
	font-size: calc(2.5vmin * var(--s));
	font-weight: normal;
	color: var(--text-muted);
	white-space: nowrap;
	overflow: clip;
	overflow-clip-margin: 1vmin; /* room for the text shadow */
}

.stats b {
	color: var(--value);
	font-weight: 500;
	transition: color var(--slow) var(--ease-out);
}

.stats-row:not(.active),
.history-row:not(.active) {
	--value: var(--value-idle);
}

/* The labels' short forms, unless stacked on a card wide enough for them in full. */
.stat-full,
.full-labels .stat-short {
	display: none;
}

.full-labels .stat-full {
	display: inline;
}

.big-score {
	display: none;
}

/* Big layout: the name takes the whole top line, the score sits large below it. */
.big .player-score {
	width: 0;
	padding: 0;
	font-size: 0;
}

.big .player-row {
	--row-bottom: #363636;
}

.big .player-row.active {
	--row-bottom: var(--active-big-middle);
}

.big .stats-row {
	--row-top: #363636;
	--row-bottom: #242424;
	height: calc(15vmin * var(--s));
	background: linear-gradient(var(--row-top), var(--row-bottom));
}

.scores-tbl.big .stats-row.active {
	--row-top: var(--active-big-middle);
	--row-bottom: var(--active-bottom);
	color: white;
	background: linear-gradient(var(--row-top), var(--row-bottom));
}

/* A thin line between the name and the big score, short of the sides so it
   separates the two without splitting the player's field. */
.big .stats-cell {
	position: relative;
}

.big .stats-cell::before {
	content: '';
	position: absolute;
	top: 0;
	left: 1.5vmin;
	right: 1.5vmin;
	height: 2px;
	background: rgba(255, 255, 255, 0.28);
}

.big .stats {
	flex-direction: column;
	gap: 0.6vmin;
	font-size: calc(2.8vmin * var(--s));
	color: var(--text-soft);
	text-shadow: 0 0 0.5vmin black;
}

.big .big-score {
	display: block;
	font-size: calc(13vmin * var(--s));
	line-height: 1;
	text-shadow: 0 0 1vmin black;
}

.scrollable {
	overflow-x: auto;
	white-space: nowrap;
	scrollbar-width: none;
}

.scrollable::-webkit-scrollbar {
	display: none;
}

/* CALCULATOR */

.calc-section {
	height: 40%;
	flex: none;
	overflow: hidden;
	transition: height var(--medium) var(--ease-out), visibility var(--medium), filter var(--medium) var(--ease-out), background var(--medium) var(--ease-out);
	font-family: var(--font);
	font-weight: 500;
}

/* Its full size whatever the panel's doing, held to the panel's moving edge, so
   the keypad slides out of sight as a whole (the keys don't change size). */
.calc-tbl {
	position: absolute;
	top: 0;
	left: 0;
	table-layout: fixed;
	border-spacing: 5px;
	width: 100%;
	height: 40vmin;
	text-align: center;
	font-size: calc(6 * var(--u));
	text-shadow: 0 0 calc(0.5 * var(--u)) black;
	line-height: calc(1 * var(--u));
	color: white;
}

.calc-tbl td {
	border: var(--border);
	border-radius: var(--radius);
	/* Four rows, their gaps, borders and padding fit a short screen's 40vmin too. */
	height: min(calc(7.5 * var(--u)), calc((40vmin - 25px) / 4 - 2 * var(--line) - 2px));
	background: linear-gradient(#808080, #484848);
	cursor: pointer;
}

.calc-tbl td:not(.calc-score):active {
	background: var(--button-pressed);
	font-size: calc(5.5 * var(--u));
}

.calc-tbl td.back-score:active {
	font-size: calc(4.2 * var(--u));
}

.calc-tbl td.disabled {
	color: var(--text-muted);
	background: var(--panel);
	border: var(--border-muted);
	pointer-events: none;
}

/* The box itself is a "plate" behind the text (::before), so it can tip
   like a rocker switch while the number stays put. */
td.calc-score {
	position: relative;
	isolation: isolate;
	font-family: var(--font-condensed);
	font-weight: 500;
	line-height: calc(5.25 * var(--u));
	background: none;
	text-shadow: 0 0 calc(1 * var(--u)) black;
}

/* The cell draws no border of its own, so the plate (inset 0) is exactly the
   cell, edge for edge with the buttons around it. Reaching out by --line over
   a border instead left its edges between screen pixels (borders snap to whole
   pixels, --line doesn't), and Chrome drew them a pixel wider while tipping. */
.calc-tbl td.calc-score,
.calc-tbl td.calc-score.disabled {
	border: none;
}

td.calc-score::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border: var(--border);
	border-radius: var(--radius);
	background: linear-gradient(#404040, #262626);
}

td.calc-score.disabled {
	background: none;
}

td.calc-score.disabled::before {
	border: var(--border-muted);
	background: #242424;
}

td.calc-score.tip-up:not(.disabled)::before,
td.calc-score.tip-up:not(.disabled) .score-face {
	animation: tip-up 260ms var(--ease-out);
}

td.calc-score.tip-down:not(.disabled)::before,
td.calc-score.tip-down:not(.disabled) .score-face {
	animation: tip-down 260ms var(--ease-out);
}

/* Seen in perspective, a tipping box looks like it slides (both edges drift the
   same way). The 1.9% shift cancels that, so it rocks in place. It holds while the
   perspective depth is about 1.5x the box height (--tip-depth, set for portrait). */
@keyframes tip-up {
	30% { transform: perspective(var(--tip-depth, calc(30 * var(--u)))) translateY(-1.9%) rotateX(7deg); }
}

@keyframes tip-down {
	30% { transform: perspective(var(--tip-depth, calc(30 * var(--u)))) translateY(1.9%) rotateX(-7deg); }
}

/* Same box as the plate, so it tips exactly with it. The arrows sit one line
   above and below the middle, where the number is. */
/* Always on its own layer, as it is while tipping: text on a layer sits a
   fraction of a pixel differently, so the arrows would flinch as it ended. */
.score-face {
	position: absolute;
	inset: 0;
	will-change: transform;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: calc(5.25 * var(--u));
	pointer-events: none;
}

.score-face > * {
	display: block;
	height: calc(5.25 * var(--u));
}

td.calc-score b {
	font-weight: normal;
	color: var(--text-muted);
}

td.calc-score i {
	font-style: normal;
	font-weight: normal;
	text-shadow: none;
}

td.back-score {
	font-size: calc(4.6 * var(--u));
	line-height: 1;
}

/* BUTTONS */

/* Beside the board, buttons in the New game screen's style: each its own
   rounded, white-edged button on the grey gradient, a little apart. Left:
   undo and redo at the top; the keypad, Settings and full screen at the
   bottom, the keypad on the left above Settings where the board leaves room.
   Right: Settings, the turn's darts, and Done. */
:root {
	--side-pad: 1.2vmin; /* from the screen's edges, and between buttons */
	--ctrl-size: 8vmin;
	/* The right column's one width, a keypad key's (four across the panel, five 5px gaps
	   and its edge): the darts card and Pass are this wide, Done two keys and the gap between. */
	--card-w: calc((30vw - 26px) / 4);
	--done-h: calc((40vmin - 26px) / 4 * 1.5); /* Done: a key and a half tall (four keys down the panel, 40% of the screen) */
	--hint-h: calc(6.6 * var(--u)); /* the darts card's Tap again to remove */
}

.board-btn {
	display: grid;
	place-items: center;
	padding: 0;
	font-family: var(--font-condensed);
	font-weight: 500;
	color: var(--text);
	text-shadow: 0 0 8px black;
	background: var(--button);
	border: var(--border);
	border-radius: var(--radius);
	cursor: pointer;
	pointer-events: auto;
}

.board-btn.disabled {
	color: var(--text-muted);
	background: var(--button-disabled);
	border: var(--border-muted);
	cursor: default;
}

/* Line icons (the controls, the darts' Clear): drawn in the text colour. */
.icon {
	display: block;
	fill: none;
	stroke: currentColor;
	stroke-width: 2.2;
	stroke-linecap: round;
	stroke-linejoin: round;
	filter: drop-shadow(0 0 0.6vmin black);
}

.icon.flip {
	transform: scaleX(-1);
}

.ctrl-section {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-items: flex-start;
	width: 0;
	padding: var(--side-pad) 0;
	box-sizing: border-box;
	pointer-events: none;
	z-index: 1;
}

.ctrl-top,
.ctrl-bottom {
	margin-left: var(--side-pad);
}

.ctrl-row {
	display: flex;
	gap: var(--side-pad);
}

.ctrl-btn {
	width: var(--ctrl-size);
	height: var(--ctrl-size);
}

.ctrl-btn .icon {
	width: 4.4vmin;
	height: 4.4vmin;
}

/* Keypad show/hide: a keypad, and an arrow that points down to hide it, up to show it. */
.ctrl-btn.keypad-btn {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 0.2vmin;
}

.ctrl-btn .keypad-icon {
	width: 3.6vmin;
	height: 3.6vmin;
	fill: currentColor;
	stroke: none;
}

.ctrl-btn .keypad-arrow {
	width: 2.6vmin;
	height: 2.6vmin;
	transition: transform var(--medium) var(--ease-out);
}

.keypad-btn[aria-expanded="false"] .keypad-arrow {
	transform: rotate(180deg);
}

/* Full screen: four corners pointing out; in full screen each turns to point in. */
.fs-icon path {
	transform-box: fill-box;
	transform-origin: center;
	transition: transform var(--medium) var(--ease-out);
}

.full-screen.active .fs-icon path {
	transform: rotate(180deg);
}

/* The right-hand column, its buttons lined up on the right edge (wider than
   the column, they reach over the board's corners as the left ones do). */
.btn-section {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-items: flex-end;
	width: 8vw;
	padding: var(--side-pad);
	box-sizing: border-box;
	pointer-events: none;
}

.side-btn {
	width: calc(2 * var(--card-w) + 5px);
	height: var(--done-h);
	font-size: 6vmin;
	white-space: nowrap;
}

/* Pass: a plain small button on Done's right end, there only until a dart is down. */
.side-btn.bust-btn {
	position: absolute;
	right: var(--side-pad);
	bottom: calc(2 * var(--side-pad) + var(--done-h));
	width: var(--card-w);
	height: var(--ctrl-size);
	font-size: 3.6vmin;
}

.side-btn.bust-btn.away {
	opacity: 0;
	pointer-events: none;
}

/* Settings, as far from the darts card as Done is, so the card stays centred. */
.btn-section .settings-btn {
	width: var(--card-w);
	margin-bottom: calc(var(--done-h) - var(--ctrl-size));
}

/* Done: a ✓ like the keypad's, with what the darts make beside it (and under
   that, what sending them would do: Bust, Leg, Set or Game). */
.done-btn {
	display: flex;
	align-items: center;
	justify-content: center;
}

.done-score {
	display: flex;
	flex-direction: column;
	align-items: center;
	line-height: 1;
}

.done-btn:not(.disabled) .done-score {
	margin-right: 1.4vmin;
}

.done-total:not(:empty) {
	font-size: 5.4vmin;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

/* The word slides out from under the score, and back up. */
.done-note {
	display: grid;
	grid-template-rows: 0fr;
	width: 0; /* takes no room until it shows, so the score and ✓ stay put */
	overflow: hidden;
	font-size: 2.8vmin;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--bust) 40%, white);
	white-space: nowrap;
	transition: grid-template-rows var(--medium) var(--ease-out), width var(--medium) var(--ease-out);
}

.done-note > span {
	min-height: 0;
	transform: translateY(-100%);
	transition: transform var(--medium) var(--ease-out);
}

.done-btn.noting .done-note {
	grid-template-rows: 1fr;
	width: 7.2vmin;
}

.done-btn.noting .done-note > span {
	transform: none;
}

/* Winning something: a warm white, not the bust's red. */
.done-btn.winning .done-note {
	color: color-mix(in srgb, var(--dart-edit) 55%, white);
}

.done-check {
	font-family: var(--font);
	font-size: 6vmin;
}

/* The darts card: as tall as what's in it. The player's three darts until the
   first one lands; then Clear across the top, a slot for each dart thrown, and
   small darts under them for those left. */
.darts {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: var(--card-w);
	padding: calc(0.6 * var(--u)) 0 calc(0.8 * var(--u));
	box-sizing: border-box;
	font-size: calc(3 * var(--u));
	text-align: center;
	line-height: 1.05;
	color: white;
	background: linear-gradient(#2a2a2a, #161616);
	border: var(--border-muted);
	border-radius: var(--radius);
}

.darts-reveal {
	display: grid;
	grid-template-rows: 0fr;
	width: 100%;
	opacity: 0;
	transition: grid-template-rows var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

/* Cut off while it unfolds; after that, a slot's glow can reach past the card. */
.darts-reveal > div {
	display: flex;
	flex-direction: column;
	align-items: center;
	min-height: 0;
	overflow: hidden;
}

.darts:not(.has-darts) .darts-idle,
.darts.has-darts .darts-turn {
	grid-template-rows: 1fr;
	opacity: 1;
}

.darts:not(.has-darts) .darts-idle > div,
.darts.has-darts .darts-turn > div {
	animation: darts-unfolded 0s linear var(--medium) forwards;
}

@keyframes darts-unfolded {
	to { overflow: visible; }
}

/* The card's own margin takes back what the hint adds, so it grows down only:
   the slots stay under the finger for the second tap. */
.darts.moving {
	margin-bottom: calc(-1 * var(--hint-h));
}

.darts-hint {
	display: grid;
	place-items: center;
	flex: none;
	width: 90%;
	height: 0;
	overflow: hidden;
	opacity: 0;
	font-family: var(--font-condensed);
	font-size: min(calc(2.3 * var(--u)), calc(var(--card-w) * 0.21)); /* two lines, even on the narrower 4:3 card */
	line-height: 1.1;
	color: color-mix(in srgb, var(--bust) 40%, white);
	transition: height var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

.darts.moving .darts-hint {
	height: var(--hint-h);
	opacity: 1;
}

.dart-behind {
	filter: brightness(0.6);
	opacity: 0.5;
}

/* The darts left: side by side, one fewer with each dart thrown. */
.darts-left {
	display: flex;
	justify-content: center;
	align-items: center;
	height: calc(14 * var(--u));
	transition: height var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

.darts[data-left="0"] .darts-left {
	height: 0;
	opacity: 0;
}

.left-dart {
	flex: none;
	width: calc(3.2 * var(--u));
	height: calc(12 * var(--u));
	margin: 0 calc(0.4 * var(--u));
	filter: drop-shadow(0 0 calc(0.3 * var(--u)) black);
	transition: width var(--medium) var(--ease-out), margin var(--medium) var(--ease-out), opacity var(--medium) var(--ease-out);
}

.darts[data-left="1"] .left-dart:nth-child(2),
.darts[data-left="0"] .left-dart:nth-child(2) {
	width: 0;
	margin: 0;
	opacity: 0;
}

.idle-dart {
	display: block;
	flex: none;
	height: min(calc(30 * var(--u)), calc(var(--card-w) * 2.6)); /* the fan fits the narrower 4:3 card */
	margin: calc(1.2 * var(--u)) 0 calc(0.8 * var(--u));
	filter: drop-shadow(0 0 calc(0.5 * var(--u)) black);
}

.darts-clear {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: calc(0.4 * var(--u));
	width: 100%;
	margin-top: calc(-0.6 * var(--u)); /* up to the card's edge: all of it is there to tap */
	padding: calc(2 * var(--u)) 0 calc(1.4 * var(--u));
	font-family: var(--font-condensed);
	font-size: calc(2.8 * var(--u));
	line-height: 1;
	color: var(--text);
	background: none;
	border: none;
	border-radius: calc(var(--radius) * 0.7);
	cursor: pointer;
	pointer-events: auto;
	transition: background var(--hover-speed), color var(--medium), transform var(--fast) var(--ease-out);
}

.darts-clear:disabled {
	color: var(--text-muted);
	cursor: default;
}

.darts-clear:not(:disabled):active {
	transform: scale(0.9);
}

.darts-clear .icon {
	flex: none;
	width: calc(2.4 * var(--u));
	height: calc(2.4 * var(--u));
}

/* Each dart's value centred in its slot, with room round it. */
.darts span {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	width: 86%;
	height: calc(10.4 * var(--u));
	margin: calc(1 * var(--u)) 0;
	border: var(--line) solid transparent;
	border-radius: var(--radius);
	text-shadow: 0 0 calc(0.5 * var(--u)) black;
	pointer-events: auto;
}

/* A double, treble or bull: the letter over its value, evenly spaced (the
   column stacks them; a <br> would add an empty line). */
.darts span br {
	display: none;
}

.darts span:has(br),
.darts span:has(br) u {
	line-height: 1;
}

.darts span:has(br) {
	gap: calc(0.8 * var(--u));
}

.darts u {
	font-size: calc(5 * var(--u));
	text-decoration-thickness: calc(0.25 * var(--u));
	text-underline-offset: calc(0.5 * var(--u));
}

.darts :is(.black, .white, .red, .green, .zero) {
	border-color: white;
	cursor: pointer;
}

.darts :is(.black, .white, .zero) {
	line-height: calc(8 * var(--u));
}

.darts .black {
	background: linear-gradient(#646464, #161616);
}

.darts .white {
	background: linear-gradient(#c8c8c8, #808080);
}

.darts .red {
	background: linear-gradient(#ff3216, #962412);
}

.darts .green {
	background: linear-gradient(#48c832, #368024);
}

.darts .zero {
	background: black;
}

/* A dart still to throw takes no room: its slot unfolds as it lands. */
.darts span.empty {
	height: 0;
	margin: 0;
	border-width: 0;
	opacity: 0;
	pointer-events: none;
}


/* DARTBOARD */

.dartboard-section {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 62%;
	max-width: 62%;
}

/* Over a dart's marker (once they can be tapped): a pointer. */
#dartboard.on-mark {
	cursor: pointer;
}

/* Over the board: a white crosshair outlined in black, visible on any bed. */
#dartboard.aiming {
	cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cg stroke-linecap='round'%3E%3Cpath d='M12 2v7M12 15v7M2 12h7M15 12h7' stroke='black' stroke-width='4'/%3E%3Cpath d='M12 2v7M12 15v7M2 12h7M15 12h7' stroke='white' stroke-width='2'/%3E%3C/g%3E%3Ccircle cx='12' cy='12' r='1.6' fill='white' stroke='black'/%3E%3C/svg%3E") 12 12, crosshair;
}

/* The board's place. The SVG has a 1% margin for the outline, hence × 1.01. */
.board-frame {
	position: relative;
	width: calc(min(99%, 99vmin) * 1.01);
	aspect-ratio: 1;
	margin-right: -0.25vmin;
}

/* The board's shadow, on a plain circle behind it (the board's edge, inside
   the 1% margin). A drop-shadow filter on the board itself blurred the whole
   board again every time anything on it changed, the pointer's light
   included, which was slow on integrated graphics. This is drawn once.
   A faint light rim on top of it keeps the edge from melting into the dark
   background when the outline is set to black. */
.board-frame::before {
	content: '';
	position: absolute;
	inset: 0.495%;
	border-radius: 50%;
	box-shadow: 0 0 0 0.15vmin rgba(255, 255, 255, 0.15), 0 0 1.2vmin rgba(255, 255, 255, 0.22), 0 0 4vmin black;
	pointer-events: none;
}

/* Drawn in js/dartboard.js. */
#dartboard {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	overflow: visible; /* darts lean out past the board, and fly in from beyond it */
	pointer-events: auto;
	-webkit-tap-highlight-color: transparent;
}

.seg {
	fill-rule: evenodd; /* the outer bull is a ring around the bull */
	stroke: var(--board-seam);
	stroke-width: 0.3;
	stroke-linejoin: round;
}

.seg.black { fill: var(--board-black); }
.seg.white { fill: var(--board-white); }
.seg.red { fill: var(--board-red); }
.seg.green { fill: var(--board-green); }
.seg.legend { fill: var(--board-legend); stroke: none; }

/* Optional wires around every bed (Settings > Board layout). Not round the
   number ring: its outer edge is the board's edge, where the outline is, and
   a wire there thickened it. */
.beds.wired .seg:not(.legend) {
	stroke: var(--wire);
	stroke-width: var(--wire-width);
}

.numbers text {
	fill: var(--board-number);
	font-family: var(--font);
	font-weight: 400;
	text-anchor: middle;
	dominant-baseline: central;
}

/* PLAYER MENU */

/* Opens beside a player's rows, over the board (placed by JS). */
.player-menu {
	position: absolute;
	z-index: 60;
	display: flex;
	flex-direction: column;
	min-width: 22vmin;
	padding: 0.8vmin;
	gap: 0.4vmin;
	background: var(--menu-panel);
	border: var(--line) solid var(--edit);
	border-radius: var(--radius);
	box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.7);
	font-family: var(--font-condensed);
}

.player-menu.opening {
	animation: menu-in var(--medium) var(--ease-out);
}

.player-menu.closing {
	pointer-events: none;
	animation: menu-out var(--fast) ease-in forwards;
}

/* The player's name, with a pencil on the right to rename them. */
.player-menu-head {
	display: flex;
	align-items: center;
	gap: 1vmin;
	max-width: 30vmin;
	padding-left: 1vmin;
	border-bottom: 1px solid color-mix(in srgb, var(--edit) 50%, transparent);
}

/* All of it (name and pencil) is one button to rename, until renaming. */
.player-menu:not(.renaming) .player-menu-head {
	border-radius: calc(var(--radius) * 0.7) calc(var(--radius) * 0.7) 0 0;
	cursor: pointer;
	transition: background var(--hover-speed);
}

.player-menu-name {
	flex: 1;
	min-width: 0;
	font-size: 2.6vmin;
	color: var(--edit);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Renaming: the name becomes a text field with an amber underline. */
.player-menu-input {
	flex: 1;
	min-width: 0;
	margin: 0.4vmin 0;
	padding: 0.3vmin 0.4vmin;
	font-family: inherit;
	font-size: 2.6vmin;
	color: white;
	background: rgba(0, 0, 0, 0.35);
	border: none;
	border-bottom: 2px solid var(--edit);
	border-radius: 0.4vmin 0.4vmin 0 0;
	outline: none;
}

.player-menu .player-menu-rename {
	flex: none;
	margin: 0.2vmin 0 0.4vmin;
	padding: 0.6vmin 0.8vmin;
	color: white;
}

.player-menu button {
	display: flex;
	align-items: center;
	gap: 1.2vmin;
	padding: 1vmin 1.2vmin;
	font-family: inherit;
	font-size: 3vmin;
	color: var(--text);
	text-align: left;
	background: none;
	border: none;
	border-radius: calc(var(--radius) * 0.7);
	cursor: pointer;
}

.player-menu button span {
	width: 3vmin;
	font-size: 2.4vmin;
	text-align: center;
}

/* The pencil points down to the left. */
.player-menu button span.flip {
	transform: scaleX(-1);
}

.player-menu button:active {
	background: color-mix(in srgb, var(--edit) 22%, transparent);
}

.player-menu button:disabled {
	color: #5a5a5a;
	cursor: default;
}

.player-menu .danger {
	color: var(--bust);
}

@keyframes menu-in {
	from { opacity: 0; transform: translateX(-2vmin); }
}

@keyframes menu-out {
	to { opacity: 0; transform: translateX(-1vmin); }
}

/* In portrait the menu opens above the scores, so it rises from them. */
@keyframes menu-up {
	from { opacity: 0; transform: translateY(2vmin); }
}

@keyframes menu-down {
	to { opacity: 0; transform: translateY(1vmin); }
}

/* TOAST */

.toast {
	position: absolute;
	top: calc(var(--side-pad) + var(--ctrl-size) / 2); /* level with the middle of undo, redo and Settings */
	left: 61%;
	z-index: 50;
	width: max-content; /* as wide as its text, up to its max, wherever it's centred */
	max-width: 40vw;
	padding: 1vmin 2.5vmin;
	box-sizing: border-box;
	font-family: var(--font-condensed);
	font-size: 3.5vmin;
	line-height: 1.2;
	white-space: nowrap;
	color: var(--text);
	text-shadow: 0 0 1vmin black;
	background: var(--panel);
	border: var(--border);
	border-radius: var(--radius);
	box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.6);
	pointer-events: none;
	transform: translate(-50%, -50%);
	animation: toast-in var(--medium) var(--ease-back);
}

.toast.leaving {
	animation: toast-out var(--medium) var(--ease-out) forwards;
}

.toast-text {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
}

.toast-title {
	font-weight: 600;
}

.toast-detail {
	color: var(--text-soft);
}

.toast.bust {
	border-color: var(--bust);
}

.toast.bust .toast-title {
	color: var(--bust);
}

.toast.win {
	border-color: var(--checkout);
	box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.6), 0 0 2vmin rgba(0, 200, 0, 0.35);
}

.toast.win .toast-title {
	color: var(--checkout);
}

/* Beside a past turn's toast, which stays centred: Close, in the room on its
   right. Any tap closes a past turn (the pointerdown listener in app.js), this
   one included: it's there to show that it can be closed. */
.toast-close {
	display: none;
	position: absolute;
	top: calc(-1 * var(--line));
	bottom: calc(-1 * var(--line));
	left: 100%;
	margin-left: var(--side-pad);
	align-items: center;
	gap: 0.6vmin;
	padding: 0 1.6vmin;
	box-sizing: border-box;
	font: inherit;
	font-size: 3vmin;
	color: var(--text);
	background: linear-gradient(#2a2a2a, #161616);
	border: var(--border-muted);
	border-radius: var(--radius);
	cursor: pointer;
	pointer-events: auto;
	transition: box-shadow var(--hover-speed);
}

.toast.review .toast-close {
	display: flex;
}

.toast.tight .toast-close {
	padding: 0 1.2vmin;
}

.toast.tight .toast-close-word {
	display: none;
}

.toast-close .icon {
	flex: none;
	width: 2.6vmin;
	height: 2.6vmin;
}

/* A past turn on show, in the board's highlight colour. */
.toast.review {
	border-color: var(--board-hit);
	box-shadow: 0 1vmin 3vmin rgba(0, 0, 0, 0.6), 0 0 2vmin color-mix(in srgb, var(--board-hit) 35%, transparent);
}

.toast.review .toast-title {
	color: var(--board-hit);
}

@keyframes toast-in {
	from { opacity: 0; transform: translate(-50%, calc(-50% - 2vmin)) scale(0.9); }
}

@keyframes toast-out {
	to { opacity: 0; transform: translate(-50%, calc(-50% - 1.5vmin)) scale(0.95); }
}

/* HOVER: with a mouse, whatever can be pressed lights up a little under the
   pointer (the board has its own: .light.hover), fading in and out (see
   MOTION). Only with a pointer that hovers, and not since the last touch
   (app.js sets .touching on the root: a touch screen laptop has both), so a
   tap leaves nothing lit. */

:root {
	--hover-veil: inset 0 0 0 100vmax rgba(255, 255, 255, 0.15); /* over a button's own fill */
	--hover-tint: rgba(255, 255, 255, 0.1); /* buttons with no fill of their own */
	--hover-speed: 150ms; /* the hover lights fade a little quicker than other changes (--medium) */
}

@media (hover: hover) {
	:root:not(.touching) :is(
		.settings-btn-action:not(:disabled),
		.stepper-btn:not(:disabled),
		.game-tile,
		.segmented button,
		.players-add,
		.calc-tbl td:not(.disabled),
		.ctrl-btn:not(.disabled),
		.side-btn:not(.disabled),
		.darts span:not(.empty)
	):hover {
		box-shadow: var(--hover-veil);
	}

	/* A dart being moved keeps its veil under the pulsing glow. */
	:root:not(.touching) .darts span.editing:hover {
		--slot-veil: var(--hover-veil);
	}

	:root:not(.touching) :is(.field-btn, .player-menu button, .darts-clear):not(:disabled):hover {
		background: var(--hover-tint);
	}

	:root:not(.touching) .toast-close:hover {
		box-shadow: var(--hover-veil);
	}

	/* The player menu's name row lights as one; its pencil not on its own. */
	:root:not(.touching) .player-menu:not(.renaming) .player-menu-head:hover {
		background: var(--hover-tint);
	}

	:root:not(.touching) .player-menu:not(.renaming) .player-menu-rename:hover {
		background: none;
	}

	:root:not(.touching) .swatch:not([aria-pressed="true"]):hover {
		transform: scale(1.08);
	}

	:root:not(.touching) .settings-check:has(input:not(:disabled)):hover {
		color: white;
	}

	:root:not(.touching) .history-row:not(.active) .checkout:not(.hint):hover {
		color: white;
	}

	:root:not(.touching) .checkout:not(.hint):hover .checkout-count {
		max-width: 3.2em;
		margin-left: 0.35em;
		opacity: 1;
	}

	:root:not(.touching) .history span.has-hits:not(.reviewing):hover b {
		background: var(--hover-tint);
		border-radius: 0.5vmin;
		box-shadow: 0 0 0 0.35vmin var(--hover-tint);
	}

	:root:not(.touching) .history .leg-dot:not(.open):hover::before {
		box-shadow: 0 0 0 calc(0.3vmin * var(--s)) color-mix(in srgb, var(--text-soft) 30%, transparent);
	}

	/* A player's card, all of it (app.js sets .card-hover on its rows). */
	:root:not(.touching) .card-hover .player-wins::before,
	:root:not(.touching) :is(.history-row.card-hover, .big .stats-row.card-hover) > td {
		box-shadow: inset 0 0 0 100vmax rgba(255, 255, 255, 0.07);
	}
}

/* MOTION */

/* Buttons sink slightly when pressed, and their hover light fades. */
.calc-tbl td,
.ctrl-btn,
.side-btn,
.players-add,
.settings-btn-action {
	transition: transform var(--fast) var(--ease-out), color var(--medium), border-color var(--medium), opacity var(--medium), box-shadow var(--hover-speed);
}

.darts span {
	transition: transform var(--fast) var(--ease-out), color var(--medium), border-color var(--medium), opacity var(--medium), box-shadow var(--hover-speed), height var(--medium) var(--ease-out), margin var(--medium) var(--ease-out);
}

/* The other hover lights fade too, with each one's own transitions. */
.stepper-btn {
	transition: transform var(--fast) var(--ease-out), opacity var(--medium), box-shadow var(--hover-speed);
}

.game-tile {
	transition: transform var(--fast) var(--ease-out), border-color var(--medium), background var(--medium), box-shadow var(--hover-speed);
}

.segmented button {
	transition: background var(--medium), box-shadow var(--hover-speed);
}

.field-btn {
	transition: transform var(--fast) var(--ease-out), background var(--hover-speed);
}

.player-menu button,
.settings-check {
	transition: background var(--hover-speed), color var(--hover-speed);
}

.checkout {
	transition: color var(--medium) var(--ease-out);
}

.player-wins::before,
.history-row > td,
.stats-row > td {
	transition: box-shadow var(--hover-speed);
}

.calc-tbl td:not(.disabled, .calc-score):active,
.ctrl-btn:not(.disabled):active,
.side-btn:not(.disabled):active,
.darts span:not(.empty):active,
.players-add:active,
.settings-btn-action:active {
	transform: scale(0.94);
}

/* A row slides in when it is added; the active row brightens as the turn passes to it. */
.player-row,
.history-row,
.stats-row {
	animation: fade-in var(--medium) var(--ease-out);
}

/* On the whole player row: a filter on its cells would cut the row's layer down to one cell. */
.player-row.active {
	animation: fade-in var(--medium) var(--ease-out), row-activate var(--slow) var(--ease-out);
}

.big .stats-row.active td {
	animation: row-activate var(--slow) var(--ease-out);
}

/* JS adds .bump when a score changes, .pop when a dart lands, .enter on a new history entry. */
.player-score.bump,
.big-score.bump {
	animation: score-bump var(--slow) var(--ease-out);
}

.darts span.pop {
	animation: dart-pop var(--medium) var(--ease-back);
}

.history span.enter,
.history .leg-dot.enter {
	animation: history-enter var(--medium) var(--ease-out);
}

/* A leg opening out of its dot: its turns slide out of it in turn. Folding
   back, they draw into it before it closes. */
.history .unfold {
	animation: history-unfold var(--medium) var(--ease-out) backwards;
	animation-delay: calc(var(--i, 0) * 20ms);
}

.history span.folding {
	animation: history-fold var(--fast) ease-in forwards;
}

/* An undone turn: fades and closes up at the end of the line. */
.history span.leaving {
	overflow: hidden;
	white-space: nowrap;
	animation: history-leave var(--medium) var(--ease-out) forwards;
}

@keyframes history-unfold {
	from { opacity: 0; transform: translateX(1.5vmin) scale(0.8); }
}

@keyframes history-fold {
	to { opacity: 0; transform: translateX(1.5vmin) scale(0.8); }
}

@keyframes history-leave {
	to { opacity: 0; max-width: 0; padding-right: 0; }
}

.checkout,
td.calc-score:not(.disabled) {
	animation: fade-in var(--medium) var(--ease-out);
}

/* Dialogs fade in and the panel rises; JS adds .closing to play it back out. */
.settings-background {
	animation: fade-in var(--medium) var(--ease-out);
}

.settings-background .settings-section {
	animation: dialog-in var(--medium) var(--ease-back);
}

/* Opened straight from another dialog: the backdrop is already there. */
.settings-background.handoff {
	animation: none;
}

.settings-background.closing {
	pointer-events: none;
	animation: fade-out var(--fast) ease-in forwards;
}

.settings-background.closing .settings-section {
	animation: dialog-out var(--fast) ease-in forwards;
}

.winner-icon {
	display: inline-block;
	animation: trophy var(--slow) var(--ease-back) 120ms backwards, trophy-glow 1.6s ease-in-out 600ms infinite alternate;
}

.winner-name {
	display: inline-block;
	animation: dialog-in var(--slow) var(--ease-back) 220ms backwards;
}

@keyframes fade-in {
	from { opacity: 0; }
}

@keyframes fade-out {
	to { opacity: 0; }
}

@keyframes dialog-in {
	from { opacity: 0; transform: translateY(3vmin) scale(0.94); }
}

@keyframes dialog-out {
	to { opacity: 0; transform: translateY(2vmin) scale(0.96); }
}

@keyframes row-activate {
	40% { filter: brightness(1.25); }
}

@keyframes score-bump {
	30% { transform: scale(1.12); }
}

@keyframes dart-pop {
	from { opacity: 0; transform: scale(0.6); }
}

@keyframes history-enter {
	from { opacity: 0; transform: translateX(-2vmin); }
}

@keyframes trophy {
	from { opacity: 0; transform: scale(0.3) rotate(-20deg); }
}

@keyframes trophy-glow {
	to { transform: scale(1.08); filter: drop-shadow(0 0 2vmin rgba(255, 200, 0, 0.6)); }
}

/* PORTRAIT */

/* Built for landscape (16:10, 4:3). In portrait the board goes on top and
   the scores and keypad become a band along the bottom. Sizes are in vmin,
   so they follow the screen's width here. */
@media (orientation: portrait) {
	/* The keypad is a little taller than wide (4:5). On a narrow screen the band
	   gets shorter rather than the keypad getting any narrower than that. */
	main {
		/* The one use of vh: here vmin is the width, and the band must also
		   leave the board enough of the height. */
		--band: min(42vh, 60vw);
		--tip-depth: calc(var(--band) * 0.76); /* the score box is about half the keypad */
		--u: calc(var(--band) / 60); /* 1vmin while the band is 60vw tall; less when it's shorter */
		display: grid;
		grid-template-columns: 100%;
		grid-template-rows: minmax(0, 1fr) var(--band);
	}

	/* The board, its left buttons and its right column share the top area. */
	.ctrl-section,
	.dartboard-section,
	.btn-section {
		grid-row: 1;
		grid-column: 1;
	}

	.ctrl-section {
		justify-self: start;
		height: 100%;
	}

	.dartboard-section {
		width: 100%;
		max-width: none;
		height: 100%;
		container-type: size;
	}

	/* Fits between the buttons on the left and the darts column on the right. */
	.board-frame {
		width: calc(min(100cqw - 30vmin, 98cqh) * 1.01);
		margin: 0;
	}

	/* The right-hand column at the right edge; a key's width here too (the keypad is
	   the band's, inset to line up with it: see .calc-tbl below). */
	.btn-section {
		--card-w: calc((var(--band) * 0.82 - 2 * var(--side-pad) - 15px) / 4);
		--done-h: calc((var(--band) - 2 * var(--side-pad) - 15px) / 4); /* one key tall here */
		justify-self: end;
		height: 100%;
		width: auto;
	}

	/* Less height here: the darts card goes in the middle of the room between
	   Settings and Pass (it's held clear of it, darts or not), not the column's. */
	.btn-section .settings-btn {
		margin-bottom: 0;
	}

	.side-btn.done-btn {
		margin-top: calc(var(--ctrl-size) + var(--side-pad));
		transition: transform var(--fast) var(--ease-out), color var(--medium), border-color var(--medium), opacity var(--medium), box-shadow var(--hover-speed), --send-top var(--medium) var(--ease-out), --send-bottom var(--medium) var(--ease-out), margin-top var(--medium) var(--ease-out);
	}

	/* With darts down Pass is away: only the card's hint needs the room. */
	.darts.has-darts ~ .side-btn.done-btn {
		margin-top: var(--hint-h);
	}

	aside {
		grid-row: 2;
		flex-direction: row;
		width: auto;
		height: auto;
		border-right: none;
		border-top: var(--border);
	}

	.scores-section {
		width: auto;
		flex: 1;
		min-width: 0;
		height: 100%;
		border-bottom: none;
		border-right: var(--border);
		transition: width var(--medium) var(--ease-out), --fade-top var(--medium), --fade-bottom var(--medium);
	}

	/* The list ends at the bottom of the screen: no line there. */
	.scores-section.overflowing,
	.scores-section .history-row:last-child .history-cell {
		border-bottom: none;
	}

	/* The keys stand in from the panel's edges as far as the board's buttons do from
	   the screen's, so the keypad's columns line up with Settings, the darts card, Pass
	   and Done above them (the table's own 5px gaps count towards it). */
	.calc-tbl {
		width: calc(var(--band) * 0.82);
		height: calc(var(--band) - var(--line)); /* the band's top border is the panel's too */
		padding: max(0px, calc(var(--side-pad) - 5px));
	}

	.calc-section {
		width: calc(var(--band) * 0.82);
		height: 100%;
		transition: width var(--medium) var(--ease-out), visibility var(--medium), filter var(--medium) var(--ease-out);
	}

	aside.keypad-hidden .scores-section {
		width: 100%;
		height: 100%;
		border-right: none;
	}

	aside.keypad-hidden .calc-section {
		width: 0;
		height: 100%;
	}

	/* The keypad folds away to the right here: the arrow points right to hide it,
	   left to bring it back. */
	.keypad-btn .keypad-arrow {
		transform: rotate(-90deg);
	}

	.keypad-btn[aria-expanded="false"] .keypad-arrow {
		transform: rotate(90deg);
	}

	.player-menu.opening {
		animation-name: menu-up;
	}

	.player-menu.closing {
		animation-name: menu-down;
	}

	.toast {
		left: 50%;
		max-width: 80vw;
	}

	/* Leaves room for Close before Settings; a little more when it's just the ✕. */
	.toast.review {
		max-width: 46vw;
	}

	.toast.review.tight {
		max-width: 56vw;
	}

	.settings-section {
		width: 90%;
	}

	/* Tall screen: only as tall as it needs. */
	.settings-main {
		height: auto;
	}

	/* Board layout fills the band along the bottom: the controls go into
	   columns, with Reset and Done down the right. */
	.visuals-panel {
		display: grid;
		grid-template-columns: 1fr 18vmin;
		grid-template-rows: auto 1fr;
		width: 100%;
		column-gap: 2vmin;
		row-gap: 1.5vmin;
	}

	.visuals-panel .settings-heading {
		grid-column: 1 / -1;
	}

	.visuals-controls {
		display: grid;
		grid-template-columns: repeat(3, 1fr);
		column-gap: 2vmin;
		row-gap: 1.6vmin;
		align-content: start;
	}

	/* Its label is long for one column: it would push Reset and Done off the screen. */
	.visuals-panel .check-line {
		grid-column: span 2;
		align-self: start;
	}

	.visuals-actions {
		grid-template-columns: none;
		align-content: end;
		margin-top: 0;
	}
}

/* PHONE */

/* A portrait screen narrower than a tablet's (3:5, so a 9:16 phone still counts
   with its browser's bars taking some of the height). Stacked: the board on top,
   the players under it across the whole width, and under them the keypad, hidden
   to begin with. Along the top a strip of buttons; the board's corners and its
   right side keep the rest. */
@media (orientation: portrait) and (max-aspect-ratio: 3/5) {
	:root {
		--side-pad: 2vmin;
		--ctrl-size: 11vmin;
		--strip-h: calc(var(--ctrl-size) + var(--side-pad));
	}

	main {
		--band: 50vw; /* the keypad's height */
		--u: 1.15vmin;
		--card-w: 14.5vmin;
		grid-template-rows: calc(var(--strip-h) + 100vw - var(--card-w) - 2 * var(--side-pad)) minmax(0, 1fr);
	}

	.dartboard-section {
		justify-content: flex-start;
		box-sizing: border-box;
		padding: var(--strip-h) 0 0 var(--side-pad);
	}

	.board-frame {
		width: calc(min(100cqw - var(--card-w) - 2 * var(--side-pad), 100cqh - var(--side-pad)) * 1.01);
	}

	.ctrl-btn .icon {
		width: 6vmin;
		height: 6vmin;
	}

	.ctrl-btn .keypad-icon {
		width: 5vmin;
		height: 5vmin;
	}

	.ctrl-btn .keypad-arrow {
		width: 3.4vmin;
		height: 3.4vmin;
	}

	/* Full screen joins undo and redo along the top: the board's corner has room for one. */
	.ctrl-section .full-screen {
		position: absolute;
		top: var(--side-pad);
		left: calc(var(--side-pad) + 2 * (var(--ctrl-size) + var(--side-pad)));
	}

	.btn-section {
		--card-w: 14.5vmin;
		--done-h: 12vmin;
	}

	.side-btn {
		width: calc(1.7 * var(--card-w));
	}

	aside {
		flex-direction: column;
	}

	.scores-section {
		flex: 1;
		width: 100%;
		height: auto;
		border-right: none;
		transition: --fade-top var(--medium), --fade-bottom var(--medium);
	}

	/* The last row's line divides the players from the keypad (when it's there). */
	aside:not(.keypad-hidden) .scores-section {
		border-bottom: var(--border);
	}

	aside.keypad-hidden .scores-section {
		height: auto;
	}

	.calc-tbl {
		width: 100vw;
		height: var(--band);
	}

	.calc-section {
		flex: none;
		width: 100%;
		height: var(--band);
		transition: height var(--medium) var(--ease-out), visibility var(--medium), filter var(--medium) var(--ease-out);
	}

	aside.keypad-hidden .calc-section {
		width: 100%;
		height: 0;
	}

	/* The keypad folds away downward here, as in landscape. */
	.keypad-btn .keypad-arrow {
		transform: none;
	}

	.keypad-btn[aria-expanded="false"] .keypad-arrow {
		transform: rotate(180deg);
	}
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 1ms !important;
		animation-iteration-count: 1 !important;
		animation-delay: 0ms !important;
		transition-duration: 1ms !important;
	}
}

/* BOARD MARKERS AND LIGHTS (inside the board SVG, in board units: radius 100) */

.dartboard .shading,
.dartboard .outlines,
.dartboard .numbers,
.dartboard .lit,
.dartboard .marks {
	pointer-events: none;
}

/* Where this turn's darts landed: the segment glows. */
.light {
	fill-rule: evenodd; /* rings (the outer bull, the number ring) light as rings */
	stroke-linejoin: round;
}

.light.hit {
	fill: color-mix(in srgb, var(--board-hit) 35%, transparent);
	stroke: var(--board-hit);
	stroke-width: 0.9;
	filter: drop-shadow(0 0 1.5px var(--board-hit));
	animation: fade-in var(--medium) var(--ease-out);
}

/* A past turn being looked back at. */
.light.review {
	fill: color-mix(in srgb, var(--board-hit) 45%, transparent);
	stroke: var(--board-hit);
	stroke-width: 1;
	filter: drop-shadow(0 0 1.5px var(--board-hit));
}

/* Under the mouse pointer; and a dart in the number ring (a miss), lit the same. */
.light.hover,
.light.miss {
	fill: color-mix(in srgb, white 14%, transparent); /* a mix, like the lit colours: see light-from-hover */
	stroke: rgba(255, 255, 255, 0.45);
	stroke-width: 0.4;
}

.light.miss {
	animation: fade-in var(--medium) var(--ease-out);
}

/* Lit where the pointer was: from the pointer's light to its own (for the
   number ring, the same look, so no flicker). */
.light.from-hover {
	animation: light-from-hover var(--medium) var(--ease-out);
}

@keyframes light-from-hover {
	from {
		/* A mix like the lit colours: between a mix and a plain rgba() the
		   browser blends through red or black. */
		fill: color-mix(in srgb, white 14%, transparent);
		stroke: rgba(255, 255, 255, 0.45);
		stroke-width: 0.4;
		filter: none;
	}
}

/* The bed of a dart picked up to move: flashes in the moving yellow, in time
   with its marker (whatever the highlight colour). */
.light.editing {
	fill: color-mix(in srgb, var(--dart-edit) 40%, transparent);
	stroke: var(--dart-edit);
	stroke-width: 0.9;
	filter: drop-shadow(0 0 1.5px var(--dart-edit));
	animation: editing-light 0.9s ease-in-out infinite alternate;
}

@keyframes editing-light {
	from { opacity: 0.35; }
}

/* Centred on where the dart landed. */
.mark circle {
	fill: rgba(0, 0, 0, 0.55);
	stroke: white;
	stroke-width: var(--line);
	vector-effect: non-scaling-stroke;
}

.mark text {
	fill: white;
	font-family: var(--font-condensed);
	font-size: 3.9px;
	font-weight: 600;
	text-anchor: middle;
	dominant-baseline: central;
}

/* The marker's line to its dart's point, fading towards it (a gradient from dartboard.js). */
.mark-leader {
	stroke-width: 0.4;
	stroke-linecap: round;
}

.mark-leader.pop {
	animation: fade-in var(--medium) var(--ease-out) calc(var(--dart-flight-time, 0ms) * 0.8) backwards;
}

.mark-leader.review {
	opacity: 0.7;
}

/* A past turn's markers fade in; when its darts are thrown in again, they pop as those land. */
.mark-leader.review:not(.pop),
.mark.review:not(.pop) {
	animation: fade-in var(--medium) var(--ease-out);
}

.mark.review circle {
	stroke-dasharray: 3 2;
}

/* The marker pops as its dart lands (--dart-flight-time is set from config.js). */
.mark.pop {
	transform-box: fill-box;
	transform-origin: center;
	animation: mark-pop var(--medium) var(--ease-back) calc(var(--dart-flight-time, 0ms) * 0.8) backwards;
}

/* A dart in the board, in perspective (dart3d.js). Its barrel and shaft are
   shaded in dartboard.js. */

/* Its shadow on the board, faded along its length by a mask (dartboard.js). */
.dart-shadow {
	fill: black;
	opacity: 0.4;
}

/* Darts show in full, unless see-through: picked up to move (--see, 0 to 1,
   from dartboard.js). */
.dart-body {
	opacity: calc(1 - 0.15 * var(--see, 0));
}

.dart-point {
	fill: black;
}

/* Soft edges, a darker tone of each part rather than a hard line. */
.dart-steel,
.dart-face {
	stroke: rgba(0, 0, 0, 0.35);
	stroke-width: 0.12;
	stroke-linejoin: round;
}

/* Grip rings round the barrel. */
.dart-grip {
	stroke: #050607;
	stroke-dasharray: 0.7 1.1;
	opacity: 0.4;
}

.dart-shaft {
	stroke: rgba(0, 0, 0, 0.4);
	stroke-width: 0.1;
	opacity: calc(1 - 0.4 * var(--see, 0));
}

.dart:not(.seeing) .dart-shaft {
	mask: none;
}

.dart-flight {
	opacity: calc(1 - 0.62 * var(--see, 0));
}

.dart-flight polygon {
	stroke: color-mix(in srgb, var(--dart-flight) 55%, black);
	stroke-width: 0.25;
	stroke-opacity: 0.5;
	stroke-linejoin: round;
}

/* Lit beds and markers on their way out. */
.dartboard .leaving {
	animation: fade-out var(--medium) var(--ease-out) forwards;
}

@keyframes mark-pop {
	from { opacity: 0; transform: scale(2); }
}

/* A dart picked up to move: its slot and its marker pulse, and its bed
   flashes. The slot's edge is the moving yellow, its glow red, and the card
   grows downward to say another tap removes it. */
.darts span.editing {
	--slot-veil: inset 0 0 0 0 transparent; /* the hover veil, if any: both frames list it, so the glow fades */
	border-color: var(--dart-edit);
	animation: editing 0.9s ease-in-out infinite alternate;
}

/* A dart picked up to move: its marker steps aside (fades), back when it's put down. */
.mark-place.lifted {
	opacity: 0;
	pointer-events: none;
}

.mark-place.lifting {
	animation: fade-out var(--fast) var(--ease-out);
}

.mark-place.landing {
	animation: fade-in var(--fast) var(--ease-out);
}

@keyframes editing {
	from { box-shadow: var(--slot-veil), 0 0 0 transparent; }
	to { box-shadow: var(--slot-veil), 0 0 calc(2.6 * var(--u)) calc(0.3 * var(--u)) var(--bust); }
}

/* History turns entered on the board can be tapped to show their darts. */
.history span.has-hits {
	cursor: pointer;
}

.history span.has-hits b {
	text-decoration: underline dotted var(--text-muted);
	text-underline-offset: 0.3vmin;
}

/* The turn whose darts are on the board, in the board's highlight colour. */
.history span.reviewing b {
	color: black;
	background: var(--board-hit);
	border-radius: 0.5vmin;
	box-shadow: 0 0 0 0.35vmin var(--board-hit);
	text-decoration: none;
	text-shadow: none;
}

/* What each visit was (see historyMarks in feedback.js). */
.history span.zero b,
.history span.bust b {
	color: var(--history-muted);
	font-weight: normal;
}

.history span.bust b {
	text-decoration: line-through color-mix(in srgb, var(--bust) 70%, transparent);
}

.history span.ton b {
	font-weight: 700;
}

.history span.ton-forty b {
	color: var(--ton-forty);
	font-weight: 700;
}

.history span.max b {
	color: var(--max);
	font-weight: 800;
	text-shadow: 0 0 0.8vmin color-mix(in srgb, var(--max) 70%, transparent);
}

.history span.finish b {
	color: var(--checkout);
	font-weight: 700;
}

/* A finished leg, folded into a dot: filled green if this player won it, a
   grey ring if not. Open, the leg's visits sit before it. The dot is drawn
   inside a wider tap area. */
.history .leg-dot {
	flex: none;
	align-self: stretch;
	display: flex;
	align-items: center;
	padding: 0 calc(0.9vmin * var(--s)) 0 calc(0.4vmin * var(--s));
}

.history .leg-dot::before {
	content: '';
	box-sizing: border-box;
	width: calc(1.5vmin * var(--s));
	height: calc(1.5vmin * var(--s));
	border-radius: 50%;
	transition: box-shadow var(--medium) var(--ease-out);
}

.history .leg-dot.won::before {
	background: var(--checkout);
}

.history .leg-dot.lost::before {
	border: calc(0.25vmin * var(--s)) solid var(--history-muted);
}

/* Open: a soft ring, so it reads as the end of the visits before it. */
.history .leg-dot.open::before {
	box-shadow: 0 0 0 calc(0.3vmin * var(--s)) color-mix(in srgb, var(--text-soft) 45%, transparent);
}

/* The player's best visit of the leg: a small star on its corner like a badge,
   taking no room and leaving its colour alone. Of the game: a green one. */
.history span:is(.best, .best-game) b {
	position: relative;
}

.history span:is(.best, .best-game) b::before {
	content: '\2605';
	position: absolute;
	top: -0.22em;
	right: -0.35em;
	font-size: 0.55em;
	font-weight: normal;
	line-height: 1;
	color: var(--text-soft);
	text-shadow: none;
}

.history span.best-game b::before {
	color: var(--star-game);
}

/* Settings > Privacy */
.privacy-section {
	width: 60%;
}

.privacy-text {
	margin: 1vmin;
	font-family: var(--font-condensed);
	font-size: 2.8vmin;
	line-height: 1.3;
	color: var(--text-soft);
}

.privacy-text p {
	margin: 0 0 1.5vmin;
}

.privacy-text b {
	color: var(--text);
	font-weight: 500;
}

.privacy-text a {
	color: var(--text);
}

.privacy-switch {
	color: var(--text);
}

.privacy-date {
	color: var(--text-muted);
}

@media (orientation: portrait) {
	.privacy-section {
		width: 90%;
	}

	.privacy-text {
		font-size: 3.6vmin;
	}
}

/* Full screen is a shortcut for F11: for computers (touch screen laptops too:
   any pointer that hovers keeps it, and .touching doesn't matter), not for phones and tablets. */
@media (any-hover: none) {
	.ctrl-section .full-screen {
		display: none;
	}
}
