/* Custom controls: the visuals for scripts/tdc-controls.js. Loaded on every
   page by layout.html, after forms.css. Each control is an ordinary form
   element that opts in (data-control, or data-controls on a container); the
   script builds the furniture round it and this file draws it. Every size and
   colour is a token in variables.css, set from /sandbox/. */

/* ── Shared ───────────────────────────────────────────────────────────
   The outlined pill, its glow, and the chevron. A control glows on hover
   like a row, and keeps glowing while it is being typed into or has the
   keyboard (UV, 24 Oct). */
.tdc-stepper,
.tdc-select {
	position: relative;
	border: var(--control-border) solid var(--control-line);
	border-radius: var(--radius-pill);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.tdc-stepper:hover,
.tdc-select:hover,
.tdc-stepper:focus-within,
.tdc-select:focus-within { box-shadow: var(--glow-primary); }
.tdc-stepper:focus-within,
.tdc-select:focus-within { border-color: var(--color-primary); }
.is-disabled.tdc-stepper,
.is-disabled.tdc-select { opacity: 0.4; box-shadow: none; pointer-events: none; }

.tdc-stepper > .tdc-chevron,
.tdc-select > .tdc-chevron {
	display: block;
	margin: 0;
	border: none;
	border-radius: 0;
	background: none;
	color: var(--control-line);
	cursor: pointer;
	touch-action: manipulation;
	-webkit-tap-highlight-color: transparent;
}
.tdc-chevron svg {
	display: block;
	width: var(--chevron, var(--chevron-size));
	height: auto;
	margin: 0 auto;
	fill: none;
	stroke: currentColor;
	stroke-width: var(--chevron-stroke);
	stroke-linecap: round;
	stroke-linejoin: round;
}
.tdc-chevron:hover { color: var(--color-primary); }

/* Every drawn icon in a control (pathLength 100) can draw itself in and
   out: the script moves the dash offset, 100 hidden to 0 drawn. An icon
   undrawing cannot be pressed. */
.tdc-chevron svg [pathLength],
.tdc-date-tools svg [pathLength] { stroke-dasharray: 100 200; }
.tdc-chevron.is-going,
.tdc-date-tools > .is-going { pointer-events: none; }

.tdc-stepper-down svg { transform: rotate(180deg); }
.tdc-select-prev svg { transform: rotate(-90deg); }
.tdc-select-next svg { transform: rotate(90deg); }

/* ── Where a control sits in its field ───────────────────────────────
   A control with its label beside it (a stepper, a date, a switch, a ring;
   the script marks the field .field-beside) lines up with every other down
   the page (UV, 24 Oct): two equal columns, the control's right edge on the
   page's centre line, its label and hint to the right of the line, on the
   bottom line of the row. A control wider than half the row (a date on a
   narrow phone) takes the room it needs and the line moves for that row
   only, so the two dates of a pair still line up with each other. A
   select pill keeps its label and hint above and below, centred with it
   (.field-centred). */
.field.field-beside {
	display: grid;
	grid-template-columns: minmax(max-content, 1fr) 1fr;
	grid-template-rows: 1fr auto auto;
	column-gap: var(--space-4);
}
.field-beside > .tdc-stepper,
.field-beside > .tdc-date,
.field-beside > .tdc-switch,
.field-beside > .tdc-check {
	grid-column: 1;
	grid-row: 1 / -1;
	justify-self: end;
	align-self: center;
}

/* A field the page has just taken away, fading out as its space closes
   (tdc-controls.js). Nothing in it can be pressed. */
.tdc-gone { pointer-events: none; }
.field-beside > label { grid-column: 2; grid-row: 2; }
.field-beside > .hint { grid-column: 2; grid-row: 3; }

/* Two such fields side by side only where both fit with their labels: a
   PC, not a phone. */
.field-pair:has(> .field-beside) {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
	row-gap: 1.6rem;
}

.field > .tdc-select {
	display: flex;
	width: fit-content;
	margin-inline: auto;
}
.field.field-centred > label,
.field.field-centred > .hint { text-align: center; }

/* ── Stepper ──────────────────────────────────────────────────────────
   A number in a pill, a chevron above and below (UV, 24 Oct). A chevron
   at its limit is hidden by the script and the pill shrinks with it.
   --sw, --sn and --chevron let a control built from steppers (the date)
   size them without new rules. A number too long for the pill widens it:
   the script sets --chars to the longest the number can be (its max, or
   what is in it), at about 0.62 of the number's size per digit. */
.tdc-stepper {
	display: inline-grid;
	justify-items: center;
	row-gap: var(--space-1);
	width: max(var(--sw, var(--stepper-width)),
		calc(var(--chars, 1) * var(--sn, var(--stepper-number)) * 0.62 + var(--space-4)));
	padding: var(--space-3) 0;
}
.tdc-stepper > .tdc-chevron {
	width: 100%;
	padding: var(--space-1) 0;
}

/* The window the number rolls through: a changing number slides in from
   above or below and pushes the old one (the ghost) out the other side. */
.tdc-stepper-window {
	position: relative;
	display: block;
	width: 100%;
	overflow: hidden;
}
/* The number's rules carry three classes' weight, so a page stylesheet's
   own number-field rule (match.css: .set-row input[type="number"], loaded
   after this file) cannot reach inside the pill. */
.tdc-stepper .tdc-stepper-window > input[type="number"],
.tdc-stepper-ghost {
	color: var(--color-primary);
	font-family: inherit;
	font-size: var(--sn, var(--stepper-number));
	font-weight: 700;
	line-height: 1.2;
	text-align: center;
}
.tdc-stepper-ghost {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/* The number: no line of its own, no native spinners. */
.tdc-stepper .tdc-stepper-window > input[type="number"] {
	display: block;
	width: 100%;
	padding: 0;
	border: none;
	border-radius: var(--radius-sm);
	background: transparent;
	appearance: textfield;
	-moz-appearance: textfield;
}
.tdc-stepper input::-webkit-inner-spin-button,
.tdc-stepper input::-webkit-outer-spin-button {
	-webkit-appearance: none;
	margin: 0;
}
/* A placeholder is a word ("No limit", "Never"), not a number: small
   enough to fit the pill. */
.tdc-stepper input::placeholder {
	color: var(--text-muted);
	font-size: 0.7rem;
	font-weight: 400;
}
.tdc-stepper input:focus { outline: none; }
.tdc-stepper input::selection {
	background: var(--color-primary);
	color: var(--color-on-primary);
}

/* ── Stepper on its side (data-stepper="across") ─────────────────────
   Down on the left, up on the right, the number between (UV, 24 Oct). Small,
   for a row of them: a fixture's table numbers, which scroll sideways when a
   venue gives a match many tables. A hidden chevron keeps its place, so a
   row of these does not shuffle as one reaches its limit. */
.tdc-stepper.is-across {
	display: inline-flex;
	align-items: center;
	width: auto;
	padding: 0 var(--space-1);
	--sn: var(--stepper-across-number);
	--chevron: calc(var(--chevron-size) * 0.55);
}
.tdc-stepper.is-across > .tdc-chevron {
	width: auto;
	padding: var(--space-1);
}
.tdc-stepper.is-across > .tdc-chevron[hidden] { display: block; visibility: hidden; }
.tdc-stepper.is-across .tdc-stepper-window {
	width: calc(var(--chars, 1) * var(--sn) * 0.62 + var(--space-2));
}
.tdc-stepper.is-across > .tdc-stepper-down svg { transform: rotate(-90deg); }
.tdc-stepper.is-across > .tdc-stepper-up svg { transform: rotate(90deg); }
/* A row of them, scrolling sideways (with .scroll-x for the soft edges). */
.stepper-row {
	display: flex;
	gap: var(--space-2);
	overflow-x: auto;
	padding: var(--space-1) var(--space-1);
}
.stepper-row > .tdc-stepper { flex: 0 0 auto; }

/* ── Date ─────────────────────────────────────────────────────────────
   The calendar and clear buttons stacked on the left, then year, month and
   day as three small steppers. The real date input sits invisibly under
   the calendar button, so the browser's calendar opens beside it. */
.tdc-date {
	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
	max-width: 100%;
}
.tdc-date .tdc-stepper {
	--sw: var(--date-part-width);
	--sn: var(--date-number);
	--chevron: calc(var(--chevron-size) * 0.66);
	padding: var(--space-2) 0;
}
.tdc-date .tdc-stepper.is-year { --sw: var(--date-year-width); }

.tdc-date-tools {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	margin-right: var(--space-1);
}
.tdc-date-tools > button {
	display: block;
	width: 1.5rem;
	height: 1.5rem;
	margin: 0;
	padding: 0;
	border: none;
	border-radius: 0;
	background: none;
	color: var(--control-line);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}
.tdc-date-tools > button svg {
	display: block;
	width: 100%;
	height: 100%;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.tdc-date-tools > button:hover { color: var(--color-primary); }
.tdc-date-tools > .tdc-date-clear.is-empty { visibility: hidden; }

.tdc-date-tools > input[type="date"] {
	position: absolute;
	left: 0;
	top: 0;
	width: 1.5rem;
	height: 1px;
	padding: 0;
	border: none;
	opacity: 0;
	pointer-events: none;
}

/* ── Select ───────────────────────────────────────────────────────────
   The options side by side in a horizontal pill, the chosen one in a
   green pill that slides over and takes the next one's width (UV,
   24 Oct). Too many to fit and the options scroll sideways inside it. An
   arrow with nowhere to go is hidden but keeps its place, so the options
   never shift under a finger. The real select sits invisibly inside,
   keeping the keyboard. */
.tdc-select {
	display: inline-flex;
	align-items: center;
	max-width: 100%;
	padding: var(--space-1);
}
.tdc-select > .tdc-chevron {
	flex: 0 0 auto;
	width: auto;
	padding: var(--space-1) var(--space-2);
	--chevron: calc(var(--chevron-size) * 0.6);
}
.tdc-select > .tdc-chevron.is-end { visibility: hidden; }

.tdc-select-track {
	position: relative;
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	gap: 2px;
	overflow-x: auto;
	scrollbar-width: none;
}
.tdc-select-track::-webkit-scrollbar { display: none; }

/* The green pill. Placed by the script; it slides only while the track is
   marked animated, so the first drawing, a resize and the jump back to
   where a rebuilt select's pill was do not slide. transition-property must
   be none here, not left out: the script sets the duration inline, and the
   property's default (all) would animate those jumps too, which made the
   slide start from the wrong place (seen going left, 24 Oct). */
.tdc-select-thumb {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	border-radius: var(--radius-pill);
	background: var(--color-primary);
	pointer-events: none;
	transition-property: none;
}
.tdc-select-track.is-animated .tdc-select-thumb {
	transition-property: transform, width;
	transition-timing-function: cubic-bezier(0.2, 0.7, 0.3, 1);
}

.tdc-select .tdc-select-option {
	position: relative;
	z-index: 1;
	flex: 0 0 auto;
	width: auto;
	margin: 0;
	padding: var(--space-2) var(--space-3);
	border: none;
	border-radius: var(--radius-pill);
	background: none;
	color: var(--text-primary);
	font-family: inherit;
	font-size: var(--select-text);
	font-weight: 600;
	letter-spacing: normal;
	text-transform: none;
	white-space: nowrap;
	cursor: pointer;
	touch-action: manipulation;
	-webkit-tap-highlight-color: transparent;
	transition: background-color 0.15s ease, color var(--control-motion) ease;
}
.tdc-select .tdc-select-option:not(.is-selected):hover { background: var(--hover-wash); }
.tdc-select .tdc-select-option.is-selected { color: var(--color-on-primary); }
.tdc-select .tdc-select-option:disabled { opacity: 0.4; cursor: default; }

/* data-icon: a ring icon in the chosen option (28 Oct: the break event's
   cue ball), at its left, as tall as the green pill allows, ring and all,
   in the option's own colour. The words move over to make room. */
.tdc-select .tdc-select-option:has(> .tdc-select-icon) {
	--select-icon: calc(1.2em + 2 * var(--space-2) - 0.3em);
	padding-left: calc(var(--select-icon) + 0.15em + var(--space-2));
}
.tdc-select .tdc-select-icon.tdc-ring {
	position: absolute;
	left: 0.15em;
	top: 50%;
	width: var(--select-icon);
	height: var(--select-icon);
	transform: translateY(-50%);
	color: currentColor;
	--ring-accent: currentColor;
}
.tdc-select .tdc-select-icon .ring { stroke: currentColor; }

.tdc-select > select {
	position: absolute;
	left: 0;
	bottom: 0;
	width: 1px;
	height: 1px;
	padding: 0;
	border: none;
	opacity: 0;
	pointer-events: none;
}

/* data-tone="warning": the match page's break event, in the lag colour. */
.tdc-select[data-tone="warning"] { border-color: var(--color-warning); }
.tdc-select[data-tone="warning"] .tdc-select-thumb { background: var(--color-warning); }
.tdc-select[data-tone="warning"]:hover,
.tdc-select[data-tone="warning"]:focus-within {
	border-color: var(--color-warning);
	box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-warning) 55%, transparent),
		0 0 16px color-mix(in srgb, var(--color-warning) 30%, transparent);
}

/* ── Slide ────────────────────────────────────────────────────────────
   Slide to confirm (the match page's undo). A pill outlined like the
   other controls, a cream knob holding an undo arrow at the max end, and
   the words in the middle. The knob's place is --at, set by the script:
   1 at the max end (right), 0 at the min end (left). The words fade as it
   travels. The real range lies invisibly over the pill for the keyboard. */
.tdc-slide {
	--at: 1;
	position: relative;
	display: flex;
	align-items: center;
	box-sizing: border-box;
	width: 100%;
	height: var(--slide-height);
	padding: var(--space-1);
	border: var(--control-border) solid var(--control-line);
	border-radius: var(--radius-pill);
	container-type: inline-size;
	touch-action: pan-y;
	user-select: none;
	-webkit-user-select: none;
}
.tdc-slide:focus-within { border-color: var(--color-primary); box-shadow: var(--glow-primary); }
.tdc-slide.is-disabled { opacity: 0.4; pointer-events: none; }

.tdc-slide-label {
	flex: 1 1 auto;
	padding-inline: var(--slide-knob);
	text-align: center;
	font-size: var(--slide-text);
	font-weight: 600;
	color: var(--text-primary);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	opacity: var(--at);
}
/* Which way to slide, before the words. */
.tdc-slide-label::before { content: '‹‹ '; color: var(--text-muted); }

.tdc-slide-knob {
	position: absolute;
	left: var(--space-1);
	top: 50%;
	display: grid;
	place-items: center;
	width: var(--slide-knob);
	height: var(--slide-knob);
	border-radius: var(--radius-round);
	background: var(--control-line);
	color: var(--bg-base);
	cursor: grab;
	touch-action: none;
	transform: translate(calc(var(--at) * (100cqw - var(--slide-knob))), -50%);
	transition: transform var(--control-motion) cubic-bezier(0.2, 0.7, 0.3, 1);
}
.tdc-slide.is-dragging .tdc-slide-knob { transition: none; cursor: grabbing; }
/* data-tone="error": the match page's undo (UV, 28 Oct). The bar, a ring
   round the knob and the arrow in it all red; the knob's fill is the page,
   so the ring reads as one. The ring is a border, not a shadow: the dots
   take a plain element's colour from its border, else its fill, and the
   fill here is the page (they were drawn in the background colour). */
.tdc-slide[data-tone="error"] { border-color: var(--color-error); }
.tdc-slide[data-tone="error"]:focus-within {
	border-color: var(--color-error);
	box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-error) 55%, transparent),
		0 0 16px color-mix(in srgb, var(--color-error) 30%, transparent);
}
.tdc-slide[data-tone="error"] .tdc-slide-knob {
	box-sizing: border-box;
	border: var(--control-border) solid var(--color-error);
	background: var(--bg-base);
	color: var(--color-error);
}
.tdc-slide-knob svg { width: 75%; height: 75%; stroke-width: 9; }

.tdc-slide > input[type="range"] {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	margin: 0;
	opacity: 0;
	pointer-events: none;
}
