/*
 * JeuRange styles.
 *
 * Layout: one centred column (30rem at most) of chunky "pixel panels" set on
 * a daytime sky. The game keeps this single look on every device and theme.
 */

:root {
	/* Colours. */
	--sky: #a5dcf7;
	--cloud: #d6f0fc;
	--ink: #1a1c2c;
	--paper: #fff6e3;
	--paper-shade: #ecdcb8;
	--sun: #ffcd75;
	--sun-deep: #ef9d3a;
	--leaf: #5fd07f;
	--leaf-deep: #2f9a58;
	--berry: #f0707e;
	--berry-deep: #c8404f;
	--ocean: #3b5dc9;
	--muted: #4b5a73;
	--white: #ffffff;
	--shadow: rgba(26, 28, 44, 0.28);
	--overlay: rgba(59, 93, 201, 0.84);

	/* Type: a blocky display face for titles, a narrow and very legible pixel face for text. */
	--font-display: "Press Start 2P", "Courier New", monospace;
	--font-body: "Jersey 20", "Trebuchet MS", Verdana, sans-serif;

	/* Size of one "interface pixel": borders and shadows are multiples of it. */
	--px: 4px;

	/* Border drawn with four shadows, which leaves the corners notched like pixel art. */
	--pixel-border:
		0 calc(-1 * var(--px)) 0 0 var(--ink),
		0 var(--px) 0 0 var(--ink),
		calc(-1 * var(--px)) 0 0 0 var(--ink),
		var(--px) 0 0 0 var(--ink);

	color-scheme: light;
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	background: var(--sky);
}

body {
	margin: 0;
	min-height: 100%;
	/* Sky with a few pixel clouds, drawn as a small repeating picture. */
	background-color: var(--sky);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='200' shape-rendering='crispEdges'%3E%3Cg fill='%23d6f0fc'%3E%3Crect x='24' y='32' width='56' height='8'/%3E%3Crect x='32' y='24' width='32' height='8'/%3E%3Crect x='144' y='120' width='64' height='8'/%3E%3Crect x='160' y='112' width='32' height='8'/%3E%3Crect x='152' y='128' width='40' height='8'/%3E%3C/g%3E%3C/svg%3E");
	color: var(--ink);
	font-family: var(--font-body);
	font-size: 1.375rem;
	line-height: 1.2;
	/* The pixel face has one weight: a faked bold would blur its pixels. */
	font-synthesis: none;
	padding-block: 1rem 2.5rem;
	padding-left: max(16px, env(safe-area-inset-left, 0px));
	padding-right: max(16px, env(safe-area-inset-right, 0px));
	-webkit-tap-highlight-color: transparent;
}

/* On phones with a notch, keep the strip above the page in the sky colour while scrolling. */
body::before {
	content: "";
	position: fixed;
	inset: 0 0 auto;
	height: env(safe-area-inset-top, 0px);
	z-index: 10;
	background: var(--sky);
}

h1,
h2,
p,
ul {
	margin: 0;
}

/* The `hidden` attribute always wins over the display rules below. */
[hidden] {
	display: none !important;
}

ul {
	padding: 0;
	list-style: none;
}

#app {
	max-width: 30rem;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
}

.noscript {
	max-width: 30rem;
	margin-inline: auto;
	text-align: center;
}

/* ---------- Shared pieces ---------- */

/* A panel is a box of paper with a pixel border and a hard shadow below it. */
.panel {
	background: var(--paper);
	margin: var(--px);
	padding: 0.875rem;
	box-shadow: var(--pixel-border), 0 calc(2 * var(--px)) 0 0 var(--shadow);
}

.btn {
	appearance: none;
	border: 0;
	border-radius: 0;
	margin: var(--px);
	padding: 0.5rem 0.875rem;
	min-height: 2.75rem;
	background: var(--sun);
	color: var(--ink);
	font: inherit;
	line-height: 1.2;
	cursor: pointer;
	touch-action: manipulation;
	/* The inner shadow is the darker lower edge that makes the button look raised. */
	box-shadow: var(--pixel-border), inset 0 calc(-1 * var(--px)) 0 0 var(--sun-deep);
}

.btn:active {
	transform: translateY(2px);
	box-shadow: var(--pixel-border), inset 0 0 0 0 var(--sun-deep);
}

.btn:disabled {
	opacity: 0.45;
	cursor: default;
}

.btn:focus-visible,
.swatch:focus-visible,
.save__play:focus-visible,
.field__input:focus-visible {
	outline: 3px solid var(--ocean);
	outline-offset: 6px;
}

.btn--primary {
	background: var(--leaf);
	box-shadow: var(--pixel-border), inset 0 calc(-1 * var(--px)) 0 0 var(--leaf-deep);
}

.btn--danger {
	background: var(--berry);
	box-shadow: var(--pixel-border), inset 0 calc(-1 * var(--px)) 0 0 var(--berry-deep);
}

.btn--ghost {
	background: var(--paper);
	box-shadow: var(--pixel-border), inset 0 calc(-1 * var(--px)) 0 0 var(--paper-shade);
}

.btn--small {
	padding: 0.375rem 0.625rem;
	font-size: 1.25rem;
}

.btn--icon {
	min-width: 2.75rem;
	padding-inline: 0.5rem;
}

.btn--big {
	padding-block: 0.875rem;
	font-size: 1.75rem;
}

.section-title {
	font-family: var(--font-display);
	font-size: 0.875rem;
	line-height: 1.5;
	text-wrap: balance;
}

.screen-title {
	font-family: var(--font-display);
	font-size: 1rem;
	line-height: 1.5;
	text-wrap: balance;
}

.hint {
	color: var(--muted);
	font-size: 1.25rem;
}

/* Every sprite and scene is a tiny canvas scaled up: keep the pixels sharp. */
canvas {
	image-rendering: pixelated;
	display: block;
}

/* ---------- Title screen ---------- */

.title {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	padding-top: 1rem;
	text-align: center;
}

.title__logo {
	margin: var(--px);
	padding: 0.875rem 1.125rem;
	background: var(--ink);
	color: var(--sun);
	font-family: var(--font-display);
	font-size: clamp(1.375rem, 7.5vw, 2.25rem);
	line-height: 1.2;
	text-shadow: var(--px) var(--px) 0 var(--berry-deep);
	box-shadow: var(--pixel-border), 0 calc(2 * var(--px)) 0 0 var(--shadow);
}

.title__tagline {
	max-width: 22rem;
	font-size: 1.625rem;
	text-wrap: balance;
}

.saves {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

.samples {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	text-align: center;
}

.samples__row {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem;
}

.samples__avatar {
	width: 72px;
	height: 88px;
}

.samples__text {
	max-width: 22rem;
	text-wrap: balance;
}

.save {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.5rem;
}

.save__play {
	appearance: none;
	flex: 1;
	min-width: 0;
	display: flex;
	align-items: center;
	gap: 0.75rem;
	border: 0;
	padding: 0.25rem;
	background: none;
	color: inherit;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.save__avatar {
	flex: none;
	width: 54px;
	height: 66px;
}

.save__text {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}

.save__name {
	font-size: 1.75rem;
	overflow-wrap: anywhere;
}

.save__level {
	color: var(--muted);
	font-size: 1.25rem;
}

.save__go {
	flex: none;
	color: var(--leaf-deep);
	font-size: 1.25rem;
}

/* ---------- Hero editor ---------- */

.editor {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

.editor__header {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

/* The preview follows the scroll, so the hero stays in sight while choosing. */
.editor__preview {
	position: sticky;
	top: calc(env(safe-area-inset-top, 0px) + 0.5rem);
	z-index: 5;
	display: flex;
	align-items: center;
	justify-content: space-around;
	gap: 1rem;
	background: var(--cloud);
}

.editor__canvas {
	width: 108px;
	height: 132px;
}

.field {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.field__label {
}

.field__input {
	margin: var(--px);
	width: calc(100% - 2 * var(--px));
	border: 0;
	border-radius: 0;
	padding: 0.5rem 0.75rem;
	background: var(--white);
	color: var(--ink);
	font: inherit;
	font-size: 1.625rem;
	box-shadow: var(--pixel-border);
}

.field__input::placeholder {
	color: var(--muted);
	opacity: 0.7;
}

.field__error {
	color: var(--berry-deep);
}

.field__error:empty {
	display: none;
}

.options {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

.option {
	display: flex;
	flex-direction: column;
	gap: 0.625rem;
}

.option__title {
	font-family: var(--font-display);
	font-size: 0.75rem;
	line-height: 1.5;
}

.cycle {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

.cycle__label {
	flex: 1;
	min-width: 0;
	text-align: center;
	font-size: 1.625rem;
}

.swatches {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	padding: var(--px);
}

.swatch {
	appearance: none;
	width: 2.25rem;
	height: 2.25rem;
	border: 0;
	border-radius: 0;
	padding: 0;
	cursor: pointer;
	touch-action: manipulation;
	box-shadow: var(--pixel-border);
}

/* The chosen colour gets a second, wider frame. */
.swatch[aria-pressed="true"] {
	box-shadow: var(--pixel-border), 0 0 0 6px var(--white), 0 0 0 10px var(--ink);
}

/* ---------- Game screen ---------- */

.hud {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

.hud__name {
	flex: 1;
	min-width: 0;
	text-align: center;
	font-family: var(--font-display);
	font-size: 1rem;
	line-height: 1.5;
	overflow-wrap: anywhere;
}

.scene {
	padding: 0;
}

/* The picture itself; the XP labels float above it. */
.scene__view {
	position: relative;
	overflow: hidden;
}

.scene__canvas {
	width: 100%;
	height: auto;
}

/* On tall screens the scene follows the scroll, so the mission animations are never missed. */
@media (min-height: 600px) {
	.scene {
		position: sticky;
		top: calc(env(safe-area-inset-top, 0px) + 0.5rem);
		z-index: 5;
	}
}

.scene__floats {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

/* Bar under the picture: what the hero is doing, and the button to skip an animation. */
.scene__bar {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	min-height: 3.75rem;
	padding: 0.125rem 0.5rem;
	background: var(--ink);
	color: var(--paper);
}

.scene__caption {
	flex: 1;
	min-width: 0;
	text-align: center;
	overflow-wrap: anywhere;
}

.scene__skip {
	flex: none;
}

/* "+20 XP" label rising above the hero's head. */
.scene__float {
	position: absolute;
	left: 42%;
	top: 30%;
	transform: translateX(-50%);
	padding: 0.125rem 0.5rem;
	background: var(--ink);
	color: var(--sun);
	white-space: nowrap;
	animation: float-up 1.2s steps(12) forwards;
}

@keyframes float-up {
	from {
		transform: translate(-50%, 0);
		opacity: 1;
	}
	70% {
		opacity: 1;
	}
	to {
		transform: translate(-50%, -2.5rem);
		opacity: 0;
	}
}

.xp {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.xp__header {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.25rem 0.75rem;
}

.xp__level {
	font-family: var(--font-display);
	font-size: 1rem;
}

.xp__title {
}

.xp__bar {
	height: 1.25rem;
	margin: var(--px);
	background: var(--ink);
	box-shadow: var(--pixel-border);
	padding: 3px;
}

.xp__fill {
	height: 100%;
	min-width: 0;
	background: var(--leaf);
	box-shadow: inset 0 -4px 0 0 var(--leaf-deep);
	transition: width 0.5s steps(10);
}

.xp__numbers {
	text-align: right;
	font-variant-numeric: tabular-nums;
}

.missions {
	display: flex;
	flex-direction: column;
	gap: 0.625rem;
}

.missions__header {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
	padding-inline: var(--px);
}

.missions__count {
	font-family: var(--font-display);
	font-size: 0.875rem;
	font-variant-numeric: tabular-nums;
}

.missions .hint {
	padding-inline: var(--px);
}

.missions__list {
	display: flex;
	flex-direction: column;
	gap: 0.875rem;
	margin-top: 0.25rem;
}

.mission {
	display: flex;
	align-items: center;
	gap: 0.625rem;
	padding: 0.5rem 0.625rem;
}

.mission--done {
	background: var(--paper-shade);
}

.mission__icon {
	flex: none;
	width: 2rem;
	font-size: 1.5rem;
	text-align: center;
}

.mission__text {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.mission__label {
	overflow-wrap: anywhere;
}

.mission__xp {
	color: var(--muted);
	font-size: 1.25rem;
	font-variant-numeric: tabular-nums;
}

.mission .btn {
	flex: none;
}

/* ---------- Dialog, notification, confetti ---------- */

.modal {
	position: fixed;
	inset: 0;
	z-index: 20;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1.5rem max(16px, env(safe-area-inset-right, 0px)) 1.5rem max(16px, env(safe-area-inset-left, 0px));
	background: var(--overlay);
	overflow: hidden;
}

.modal__box {
	position: relative;
	width: min(100%, 24rem);
	display: flex;
	flex-direction: column;
	gap: 1rem;
	padding: 1.25rem;
	text-align: center;
}

.modal__title {
	font-family: var(--font-display);
	font-size: 1rem;
	line-height: 1.6;
	text-wrap: balance;
}

.modal__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75rem;
}

.confetti {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.confetti__piece {
	position: absolute;
	top: -1rem;
	width: 0.625rem;
	height: 0.625rem;
	animation: confetti-fall 2.4s steps(24) infinite;
}

@keyframes confetti-fall {
	from {
		transform: translateY(0);
	}
	to {
		transform: translateY(110vh);
	}
}

.toast-region {
	position: fixed;
	left: 0;
	right: 0;
	bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
	z-index: 30;
	display: flex;
	justify-content: center;
	padding-left: max(16px, env(safe-area-inset-left, 0px));
	padding-right: max(16px, env(safe-area-inset-right, 0px));
	pointer-events: none;
}

.toast {
	max-width: 26rem;
	margin: var(--px);
	padding: 0.625rem 0.875rem;
	background: var(--ink);
	color: var(--paper);
	text-align: center;
	box-shadow: 0 calc(2 * var(--px)) 0 0 var(--shadow);
	animation: toast-in 0.25s steps(4);
}

@keyframes toast-in {
	from {
		transform: translateY(1rem);
		opacity: 0;
	}
	to {
		transform: translateY(0);
		opacity: 1;
	}
}

/* People who asked for less motion get a still interface. */
@media (prefers-reduced-motion: reduce) {
	.scene__float,
	.toast {
		animation: none;
	}

	.confetti {
		display: none;
	}

	.xp__fill {
		transition: none;
	}

	.btn:active {
		transform: none;
	}
}
