/* ds/controls.css -- design system v2: the things you operate.
 *
 * Spec: intent/site-looks-flat-and-unclickable/spec.md section 5. Sibling of
 * ds/surfaces.css, which holds the things these sit on.
 *
 * EVERY CONTROL CARRIES ITS OWN 44px FLOOR, and that is not belt-and-braces.
 * shell.css states the floor as
 * `@media (pointer: coarse) { :where(button, a[href], ...) { min-height: 44px } }`,
 * and `:where()` contributes ZERO specificity, so a bare class rule beats it
 * regardless of source order. Forty-four rules across sixteen stylesheets were
 * beating it when that was audited, every one of them shipping looking correct.
 * A control that does not repeat the floor here does not have it.
 *
 * REAL PIXELS, NOT CSS PIXELS, for anything a finger has to hit. The desktop
 * renders the app at 1.204x, so `--ctl-h` is `44 * --rpx`: 44 real pixels on a
 * phone at 1x and on a desktop at 1.204x, which is about 36.5 CSS pixels there.
 * Never multiply the token; `getBoundingClientRect()` already reports real
 * pixels. Paddings and radii stay in CSS pixels on purpose, so the desktop is
 * a little roomier while the target stays the same size under a finger.
 *
 * FIELDS ARE THE ONE EXCEPTION: a literal 16px on coarse pointers, stepped down
 * only behind `(min-width: 768px) and (pointer: fine)`. Anything smaller and
 * iOS Safari zooms the page on focus, which on a bottom sheet scrolls the list
 * out from under the person mid-task. The width query alone is not enough: an
 * iPad matches 768px and still needs the floor.
 *
 * STATE IS NEVER COLOUR ALONE. Every selected, pressed and checked state here
 * moves the depth or the position as well as the colour, and every one is
 * driven by a real ARIA attribute or a native `:checked`, so the accessibility
 * tree and the picture cannot disagree.
 */

/* ── Key: the button. Presses 2px down, and looks like it would. ── */
.tcg-btn,
.tcg-key {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	min-height: var(--ctl-h);
	padding: 0 14px;
	border-radius: var(--r-control);
	background: linear-gradient(180deg, var(--float), var(--raised));
	border: 1px solid var(--line-2);
	box-shadow: var(--depth-raised);
	color: var(--text);
	font-family: var(--font-sans);
	font-size: var(--text-body);
	font-weight: 550;
	white-space: nowrap;
	cursor: pointer;
	/* --transition-fast ALREADY carries its easing (150ms ease); appending
	   another would make the whole declaration invalid and silently drop it. */
	transition:
		box-shadow var(--transition-fast),
		transform var(--transition-fast);
}
.tcg-btn:hover,
.tcg-key:hover {
	border-color: var(--line-control);
}
.tcg-btn:active,
.tcg-key:active {
	box-shadow: var(--depth-pressed);
	transform: translateY(2px);
}
.tcg-btn[disabled],
.tcg-key[disabled] {
	opacity: 0.55;
	cursor: not-allowed;
	box-shadow: var(--depth-pressed);
	transform: none;
}
.tcg-btn.primary {
	background: linear-gradient(180deg, var(--accent-top), var(--accent));
	border-color: var(--accent-edge);
	box-shadow: var(--depth-primary);
	color: var(--on-accent);
}
.tcg-btn.primary:active {
	box-shadow: var(--depth-primary-pressed);
}
.tcg-btn.danger {
	color: var(--danger-text);
	background: var(--danger-soft);
	border-color: var(--danger-border);
}
/* Ghost keeps a visible border at rest. A tertiary action with no border at all
   stops reading as a button, which is the thing this redesign exists to fix. */
.tcg-btn.ghost {
	background: none;
	box-shadow: none;
	border-color: var(--line-2);
}
.tcg-btn.ghost:hover {
	background: linear-gradient(180deg, var(--float), var(--raised));
	box-shadow: var(--depth-raised);
}
.tcg-btn.icon {
	padding: 0;
	width: var(--ctl-h);
	min-width: var(--ctl-h);
}
/* The compact key exists for dense desktop toolbars ONLY. A touch screen always
   gets the full 44, which is why this is gated on the pointer and not the width. */
@media (pointer: fine) {
	.tcg-btn.sm,
	.tcg-key.sm {
		min-height: var(--ctl-h-sm);
		padding: 0 10px;
		font-size: var(--text-small);
	}
	.tcg-btn.sm.icon {
		width: var(--ctl-h-sm);
		min-width: var(--ctl-h-sm);
	}
}

/* ── Switch: one setting, on or off. A real role="switch". ── */
.tcg-switch {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	min-height: var(--ctl-h);
	background: none;
	border: 0;
	padding: 0;
	color: var(--text);
	font-size: var(--text-body);
	cursor: pointer;
}
.tcg-switch > .tcg-switch-track {
	position: relative;
	flex: none;
	width: 46px;
	height: 27px;
	border-radius: var(--r-pill);
	background: var(--well);
	box-shadow: var(--depth-sunken);
	transition: background var(--transition-snap);
}
.tcg-switch > .tcg-switch-track::after {
	content: "";
	position: absolute;
	top: 3px;
	left: 3px;
	width: 21px;
	height: 21px;
	border-radius: 50%;
	background: linear-gradient(180deg, var(--float), var(--raised));
	box-shadow:
		var(--depth-raised),
		0 0 0 1px var(--knob-ring);
	transition:
		transform var(--transition-snap),
		background var(--transition-snap);
}
.tcg-switch[aria-checked="true"] > .tcg-switch-track {
	background: var(--accent);
}
.tcg-switch[aria-checked="true"] > .tcg-switch-track::after {
	/* Moves AND changes colour: the position is what reads without colour. */
	transform: translateX(19px);
	background: var(--on-accent);
}
.tcg-switch[disabled] {
	opacity: 0.55;
	cursor: not-allowed;
}

/* ── Segments and tabs: pick one. A sunken track, a raised choice. ── */
.tcg-seg,
.tcg-tabs {
	display: inline-flex;
	align-items: center;
	gap: 3px;
	background: var(--well);
	box-shadow: var(--depth-sunken);
	border-radius: var(--r-control);
	padding: 3px;
}
.tcg-seg > label,
.tcg-tabs > [role="tab"] {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	min-height: var(--ctl-h);
	padding: 0 12px;
	border: 1px solid transparent;
	border-radius: 9px;
	background: none;
	color: var(--text-2);
	font-size: var(--text-body);
	font-weight: 500;
	white-space: nowrap;
	cursor: pointer;
}
/* The native radio is the state; it is kept in the accessibility tree and only
   removed from the picture, so a screen reader and the eye agree. */
.tcg-seg input[type="radio"] {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	pointer-events: none;
}
.tcg-seg > label:has(input:checked),
.tcg-tabs > [role="tab"][aria-selected="true"] {
	background: linear-gradient(180deg, var(--float), var(--raised));
	border-color: var(--line-2);
	box-shadow: var(--depth-raised);
	color: var(--text);
	font-weight: 600;
}

/* ── Choice: pick a tile. Palette swatches, printings. ── */
.tcg-choice {
	display: inline-flex;
	flex-direction: column;
	gap: 6px;
	position: relative;
	min-height: var(--ctl-h);
	padding: 8px;
	background: linear-gradient(180deg, var(--raised-top), var(--raised));
	border: 1px solid var(--line-2);
	border-radius: var(--r-tile);
	box-shadow: var(--depth-tile);
	cursor: pointer;
	color: var(--text);
	font-size: var(--text-small);
}
.tcg-choice input[type="radio"],
.tcg-choice input[type="checkbox"] {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	pointer-events: none;
}
.tcg-choice:has(input:checked) {
	border-color: var(--accent);
	/* Three signals, not one: the border, a wash, and the check mark below. */
	box-shadow:
		var(--depth-tile),
		inset 0 0 0 3px var(--accent-soft);
}
.tcg-choice:has(input:checked)::after {
	content: "✓";
	position: absolute;
	top: 6px;
	right: 8px;
	color: var(--accent-ink);
	font-weight: 700;
}

/* ── Movers: the keyboard's answer to dragging. ── */
.tcg-movers {
	display: inline-flex;
	flex-direction: column;
	gap: 2px;
}
.tcg-movers > button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Each mover is a full target in BOTH directions: a 44-tall, 22-wide key is
	   not reachable with a thumb, and a stacked pair is the common case. */
	min-height: var(--ctl-h);
	min-width: var(--ctl-h);
	padding: 0;
	background: linear-gradient(180deg, var(--float), var(--raised));
	border: 1px solid var(--line-2);
	border-radius: 9px;
	box-shadow: var(--depth-raised);
	color: var(--text-2);
	cursor: pointer;
}
.tcg-movers > button:active {
	box-shadow: var(--depth-pressed);
	transform: translateY(2px);
}
.tcg-movers > button[disabled] {
	opacity: 0.4;
	cursor: not-allowed;
	box-shadow: var(--depth-pressed);
	transform: none;
}

/* ── Fields: sunken, and never small enough to make iOS zoom. ── */
.tcg-input,
.tcg-select,
.tcg-textarea {
	width: 100%;
	min-height: var(--ctl-h);
	padding: 9px 12px;
	background: var(--well);
	border: 1px solid var(--line-control);
	border-radius: var(--r-field);
	box-shadow: var(--depth-sunken);
	color: var(--text);
	font-family: var(--font-sans);
	/* 16px, literally, so iOS Safari does not zoom the page on focus. Stepped
	   down below only behind a FINE pointer; an iPad matches the width query and
	   still needs this. */
	font-size: 16px;
}
.tcg-textarea {
	min-height: calc(3 * var(--ctl-h));
	resize: vertical;
}
/* --bp-md + fine pointer: 16px above is the coarse-pointer focus-zoom floor. */
@media (min-width: 768px) and (pointer: fine) {
	.tcg-input,
	.tcg-select,
	.tcg-textarea {
		font-size: var(--text-body);
	}
}

@media (prefers-reduced-motion: reduce) {
	.tcg-btn,
	.tcg-key,
	.tcg-switch > .tcg-switch-track,
	.tcg-switch > .tcg-switch-track::after {
		transition: none;
	}
	.tcg-btn:active,
	.tcg-key:active,
	.tcg-movers > button:active {
		transform: none;
	}
}
