/*
 * 0-60 Calculator -- the stage, the dial and the motion.
 *
 * CAREFUL WITH `stroke`. It is an inherited SVG presentation property, and
 * document classes share a namespace with artwork classes. On the sister tool
 * a rule written against the page's body class put a white stroke on every SVG
 * element on the page; it surfaced as chart labels rendering bold and white
 * whatever fill they had been given. Every selector below is scoped to an art
 * class (.z60-gauge*, .z60-shell*, .z60-streak*) and none of them can match an
 * ancestor of an unrelated SVG.
 *
 * No url() in this file either. See the note at the top of z60.css.
 */

/* ----------------------------------------------------------------- stage */

.z60-stage {
	position: relative;
	display: grid;
	grid-template-columns: calc(360px * var(--z60-ui-scale)) 1fr;
	gap: var(--z60-pad);
	align-items: center;
	background:
		radial-gradient(120% 90% at 50% 0%, rgba(225, 29, 42, .10), transparent 62%),
		var(--z60-surface);
	border: 1px solid var(--z60-line);
	border-radius: var(--z60-radius);
	padding: var(--z60-pad);
	overflow: hidden;
	/* CLS reservation: measured. Do not scale, do not hand-tune. */
	min-height: 392px;
}

@media (max-width: 860px) {
	.z60-stage { grid-template-columns: 1fr; min-height: 640px; }
}

/* ------------------------------------------------------------------ dial */

.z60-dial { position: relative; }
.z60-gauge { display: block; width: 100%; height: auto; }
.z60-gauge-num {
	font-family: var(--z60-font-ui);
	font-size: 13px;
	font-variant-numeric: tabular-nums;
}
.z60-gauge-fill { transition: stroke-dashoffset .06s linear; }

/* The needle is rotated by JS. transform-origin is set inline on the group,
   because a percentage origin resolves against the element's own box in SVG
   and that box is the needle, not the dial. */
[data-z60-needle] { transition: transform .06s linear; }

/*
 * The readout sits in the gap the 240-degree sweep leaves at the bottom of the
 * dial, which is where a real instrument puts its odometer. Positioned from the
 * top as a percentage of the dial rather than from the bottom in pixels: the
 * dial is a square that scales with the column, so a fixed offset from the
 * bottom drifted into the tick labels at some widths and left a hole at others.
 */
.z60-readout {
	position: absolute;
	left: 50%;
	top: 60%;
	transform: translateX(-50%);
	text-align: center;
	pointer-events: none;
}
.z60-readout-speed {
	font-family: var(--z60-font-display);
	font-weight: 700;
	font-size: calc(46px * var(--z60-ui-scale));
	line-height: 1;
	font-variant-numeric: tabular-nums;
}
.z60-readout-unit {
	font-family: var(--z60-font-ui);
	font-size: calc(10.5px * var(--z60-ui-scale));
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--z60-faint);
}
.z60-readout-clock {
	margin-top: calc(6px * var(--z60-ui-scale));
	font-family: var(--z60-font-display);
	font-size: calc(21px * var(--z60-ui-scale));
	color: var(--z60-amber);
	font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- the track */

.z60-track {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: calc(18px * var(--z60-ui-scale));
	min-width: 0;
}

.z60-road {
	position: relative;
	height: calc(132px * var(--z60-ui-scale));
}

.z60-road::after {
	content: "";
	position: absolute;
	left: 0; right: 0;
	bottom: calc(14px * var(--z60-ui-scale));
	height: 2px;
	background: linear-gradient(90deg, var(--z60-line-strong), transparent);
}

.z60-car {
	position: absolute;
	left: 0;
	bottom: 0;
	width: calc(210px * var(--z60-ui-scale));
	/* transform only -- the whole run is GPU work */
	will-change: transform;
}
.z60-shell { display: block; width: 100%; height: auto; }
.z60-shell-wheel { transform-origin: center; }

/*
 * Streaks. Opacity and length are driven from --z60-speed, which z60-run.js
 * writes every frame from the live velocity. They are the speed being drawn
 * rather than a loop that runs whether or not anything is happening -- which is
 * also why nothing here animates on its own.
 */
.z60-streaks {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}
.z60-streak {
	opacity: calc(var(--z60-speed, 0) * .55);
	transform: scaleX(calc(.4 + var(--z60-speed, 0) * 1.6));
	transform-origin: right center;
	transition: opacity .1s linear;
}

/* --------------------------------------------------------------- splits */

.z60-splits {
	display: flex;
	gap: calc(8px * var(--z60-ui-scale));
	flex-wrap: wrap;
}
.z60-split {
	flex: 1 1 0;
	min-width: calc(64px * var(--z60-ui-scale));
	background: var(--z60-surface-2);
	border: 1px solid var(--z60-line);
	border-radius: var(--z60-radius);
	padding: calc(8px * var(--z60-ui-scale)) calc(10px * var(--z60-ui-scale));
	font-family: var(--z60-font-ui);
	font-size: calc(11px * var(--z60-ui-scale));
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--z60-faint);
	transition: color .2s var(--z60-ease), border-color .2s var(--z60-ease),
		background .2s var(--z60-ease);
}
.z60-split.is-hit {
	color: var(--z60-text);
	border-color: var(--z60-red);
	background: var(--z60-surface-3);
}

.z60-launch-row {
	display: flex;
	align-items: center;
	gap: calc(14px * var(--z60-ui-scale));
	flex-wrap: wrap;
}
.z60-launch-hint {
	font-family: var(--z60-font-ui);
	font-size: calc(12.5px * var(--z60-ui-scale));
	color: var(--z60-muted);
	margin: 0;
}

/* While a run is playing the primary control reads as busy rather than
   inviting another press. */
.z60-app[data-z60-running] .z60-btn--primary { opacity: .55; }
