:root {
	--purple-deep: #2f1b60;
	--purple: #5b34ad;
	--purple-light: #a385ea;
	--ui-font: "Trebuchet MS", "Avenir Next", "Segoe UI", system-ui, sans-serif;
	--safe-top: env(safe-area-inset-top, 0px);
	--safe-bottom: env(safe-area-inset-bottom, 0px);
	--safe-left: env(safe-area-inset-left, 0px);
	--safe-right: env(safe-area-inset-right, 0px);
}

* {
	box-sizing: border-box;
}

html,
body {
	height: 100%;
	margin: 0;
	overflow: hidden;
	overscroll-behavior: none;
	background-color: #2e2c33;
	color: #f0f0f0;
	font-family: var(--ui-font);
	-webkit-text-size-adjust: 100%;
}

body {
	-webkit-tap-highlight-color: transparent;
	-webkit-touch-callout: none;
	user-select: none;
}

#scene,
#confetti,
#flash,
#finale {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}

#scene {
	display: block;
	touch-action: none;
	cursor: grab;
	z-index: 0;
}

#scene:active {
	cursor: grabbing;
}

#confetti,
#flash,
#finale {
	pointer-events: none;
}

#confetti {
	z-index: 20;
}

/* ------------------------------------------------------------------ header */

#info {
	position: fixed;
	top: calc(var(--safe-top) + 1rem);
	left: 50%;
	transform: translateX(-50%);
	width: min(92vw, 40rem);
	/* Keeps the title clear of the round sound button in the corner. */
	padding: 0 3.75rem;
	text-align: center;
	z-index: 10;
	pointer-events: none;
	transition: opacity 0.5s ease, transform 0.5s ease;
}

#info.is-hidden {
	opacity: 0;
	transform: translate(-50%, -1.5rem);
}

#info h1 {
	margin: 0;
	font-size: clamp(1.75rem, 8vmin, 4rem);
	font-weight: 900;
	line-height: 1.05;
	text-shadow:
		2px 0 0 #333, -2px 0 0 #333, 0 2px 0 #333, 0 -2px 0 #333,
		1px 1px #333, -1px -1px 0 #333, 1px -1px 0 #333, -1px 1px 0 #333;
}

/* ------------------------------------------------------------------- nudge */

/* Sits on the lower-right quarter of the cube: a slow press-and-hold ripple,
   which invites a long press without spelling the rules out. */
#nudge {
	position: fixed;
	top: 50%;
	left: 50%;
	width: 5.5vmin;
	height: 5.5vmin;
	margin: -2.75vmin 0 0 -2.75vmin;
	translate: 10vmin 11vmin;
	z-index: 10;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.35s ease;
}

#nudge.is-visible {
	opacity: 1;
	transition-delay: 0.9s;
}

#nudge span {
	position: absolute;
	inset: 0;
	border-radius: 50%;
}

/* Everything carries a dark halo as well as a light core, so the marker stays
   readable whether it lands on the dark page or on the white photo. */
.nudge__dot {
	background: #fff;
	box-shadow:
		0 0 0 0.35vmin rgba(31, 18, 64, 0.55),
		0 0.4vmin 1.2vmin rgba(0, 0, 0, 0.45);
	animation: nudge-press 2.8s ease-in-out infinite;
}

.nudge__ring {
	border: 0.5vmin solid rgba(255, 255, 255, 0.95);
	box-shadow:
		0 0 0 0.16vmin rgba(31, 18, 64, 0.45),
		inset 0 0 0 0.16vmin rgba(31, 18, 64, 0.45);
	opacity: 0;
	animation: nudge-ripple 2.8s ease-out infinite;
}

.nudge__ring:nth-of-type(2) {
	animation-delay: 0.45s;
}

@keyframes nudge-press {
	0%,
	100% {
		scale: 1;
	}
	10%,
	72% {
		scale: 0.68;
	}
	86% {
		scale: 1;
	}
}

@keyframes nudge-ripple {
	0% {
		scale: 0.6;
		opacity: 0;
	}
	12% {
		opacity: 0.85;
	}
	72% {
		scale: 4;
		opacity: 0;
	}
	100% {
		scale: 4;
		opacity: 0;
	}
}

/* ----------------------------------------------------------------- caption */

/* main.js projects the screen slot of the wordmark the intro animates and
   writes the position, size and opacity of this block every frame. Everything
   inside is sized in em so the whole lockup scales with one font-size. */
#finale {
	z-index: 15;
}

#caption {
	position: absolute;
	top: 0;
	left: 0;
	opacity: 0;
	text-align: center;
	line-height: 1;
	white-space: nowrap;
	will-change: transform, opacity, font-size;
}

#caption p {
	margin: 0;
}

.caption__line {
	font-size: 0.25em;
	font-weight: 700;
	letter-spacing: 0.14em;
	/* The tracking pushes the line off-centre by half a space; pull it back. */
	text-indent: 0.14em;
	text-transform: uppercase;
	color: #d9cdff;
	padding-bottom: 0.5em;
	text-shadow: 0 0 1.2em rgba(136, 106, 226, 0.7);
}

.caption__name {
	font-weight: 900;
	letter-spacing: -0.02em;
	background: linear-gradient(175deg, #ffffff 0%, #cdbcff 45%, #8163d8 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	filter: drop-shadow(0 0.04em 0.14em rgba(90, 58, 180, 0.7));
}

.caption__exp {
	font-size: 0.5em;
	vertical-align: super;
	line-height: 0;
}

/* ------------------------------------------------------------------- flash */

#flash {
	z-index: 30;
	background: #fff;
	opacity: 0;
}

#flash.is-firing {
	animation: flash 0.55s ease-out forwards;
}

@keyframes flash {
	0% {
		opacity: 0;
	}
	8% {
		opacity: 0.95;
	}
	100% {
		opacity: 0;
	}
}

/* ------------------------------------------------------------------ notice */

#notice {
	position: fixed;
	left: 50%;
	bottom: calc(var(--safe-bottom) + 1rem);
	transform: translateX(-50%);
	z-index: 50;
	display: none;
	width: min(92vw, 34rem);
	margin: 0;
	padding: 0.9rem 1.1rem;
	border-radius: 0.75rem;
	background: rgba(20, 12, 44, 0.92);
	border: 1px solid rgba(163, 133, 234, 0.4);
	color: #e6dcff;
	font-size: clamp(0.78rem, 3vmin, 0.95rem);
	line-height: 1.45;
	text-align: center;
}

#notice.is-visible {
	display: block;
}

#notice code {
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	font-size: 0.95em;
	color: #fff;
	background: rgba(255, 255, 255, 0.1);
	padding: 0.1em 0.35em;
	border-radius: 0.25em;
}

/* ----------------------------------------------------------------- buttons */

#replay,
#sound {
	position: fixed;
	z-index: 40;
	border: 0;
	font-family: inherit;
	font-weight: 700;
	color: #fff;
	background: var(--purple);
	cursor: pointer;
	transition: opacity 0.35s ease, transform 0.2s ease, background-color 0.2s ease;
	touch-action: manipulation;
}

#replay:hover,
#sound:hover {
	background: var(--purple-deep);
}

#replay:active,
#sound:active {
	transform: scale(0.94);
}

/* Bottom left, not centred: the caption lands low in the frame and the two
   would sit on top of each other on wide screens. */
#replay {
	left: calc(var(--safe-left) + 1rem);
	bottom: calc(var(--safe-bottom) + 1rem);
	padding: 0.7rem 1.6rem;
	border-radius: 999px;
	font-size: clamp(0.9rem, 3.4vmin, 1.1rem);
	box-shadow: 0 6px 18px rgba(47, 27, 96, 0.3);
	opacity: 0;
	pointer-events: none;
}

#replay.is-visible {
	opacity: 1;
	pointer-events: auto;
}

#sound {
	top: calc(var(--safe-top) + 0.75rem);
	right: calc(var(--safe-right) + 0.75rem);
	width: 2.75rem;
	height: 2.75rem;
	display: grid;
	place-items: center;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.14);
	backdrop-filter: blur(6px);
}

#sound:hover {
	background: rgba(255, 255, 255, 0.26);
}

#sound svg {
	width: 1.35rem;
	height: 1.35rem;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.9;
	stroke-linecap: round;
	stroke-linejoin: round;
}

#sound .sound__speaker {
	fill: currentColor;
	stroke-linejoin: round;
}

#sound .sound__cross {
	opacity: 0;
}

#sound.is-muted .sound__waves {
	opacity: 0;
}

#sound.is-muted .sound__cross {
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	#flash.is-firing {
		animation-duration: 0.01ms;
	}

	.nudge__dot {
		animation: none;
	}

	.nudge__ring {
		animation: none;
		opacity: 0.5;
		scale: 2;
	}
}
