/* Lanternfall - playlanternfall.com
   Palette sampled from the shipped Steam key art so the site and the store
   page read as one product. Cyan (--aether) is reserved for live board data
   and nothing else. */

@font-face {
	font-family: "Oswald";
	src: url("../fonts/oswald-latin-var.woff2") format("woff2");
	font-weight: 200 700;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+2122, U+2212;
}

@font-face {
	font-family: "Inter";
	src: url("../fonts/inter-latin-var.woff2") format("woff2");
	font-weight: 100 900;
	font-display: swap;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+2122, U+2212;
}

:root {
	/* Near black with a violet cast, so the art carries the colour and the
	   page stays out of its way. */
	--night: #07050f;
	--night-2: #100c20;
	--night-3: #16112c;
	--violet: #5b3fb8;
	--ember: #ff7a18;
	--aether: #4fd6e8;
	--bone: #f4ead6;
	--ash: rgb(244 234 214 / 58%);
	--hairline: rgb(91 63 184 / 32%);

	--glow-ember: 0 0 28px rgb(255 122 24 / 45%);
	--glow-aether: 0 0 24px rgb(79 214 232 / 40%);

	--display: "Oswald", "Haettenschweiler", "Arial Narrow", sans-serif;
	--body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

	--gutter: clamp(1.25rem, 4vw, 3.5rem);
	--measure: 68rem;
	--rhythm: clamp(4.5rem, 10vw, 9rem);
	--nav-height: 4rem;
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	scroll-behavior: smooth;
	/* The sticky nav must not cover anchor targets. */
	scroll-padding-top: var(--nav-height);
}

body {
	margin: 0;
	background: var(--night);
	color: var(--bone);
	font-family: var(--body);
	font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
	line-height: 1.65;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

img {
	max-width: 100%;
	height: auto;
	display: block;
}

a {
	color: var(--bone);
}

:focus-visible {
	outline: 3px solid var(--aether);
	outline-offset: 3px;
	border-radius: 2px;
}

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--ember);
	color: #1a0d02;
	padding: 0.75rem 1.25rem;
	font-weight: 600;
}

.skip-link:focus {
	left: 0;
}

/* ---------- layout primitives ---------- */

.container {
	width: min(100% - (var(--gutter) * 2), var(--measure));
	margin-inline: auto;
}

.section {
	padding-block: var(--rhythm);
}

.eyebrow {
	font-family: var(--display);
	font-weight: 500;
	font-size: 0.8125rem;
	letter-spacing: 0.34em;
	text-transform: uppercase;
	color: var(--ember);
	margin: 0 0 1rem;
}

.section-title {
	font-family: var(--display);
	font-weight: 600;
	font-size: clamp(2rem, 1.4rem + 2.8vw, 3.25rem);
	line-height: 1.05;
	letter-spacing: 0.01em;
	text-transform: uppercase;
	margin: 0 0 1rem;
}

.lede {
	font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem);
	color: var(--ash);
	max-width: 46ch;
	margin: 0 0 3rem;
}

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

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.6em;
	font-family: var(--display);
	font-weight: 600;
	font-size: 1rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	text-decoration: none;
	padding: 0.9rem 1.9rem;
	border: 1px solid transparent;
	border-radius: 2px;
	cursor: pointer;
	transition: transform 160ms ease, box-shadow 160ms ease,
		background-color 160ms ease, border-color 160ms ease;
}

.btn--primary {
	background: var(--ember);
	color: #1a0d02;
	box-shadow: var(--glow-ember);
}

.btn--primary:hover {
	transform: translateY(-2px);
	box-shadow: 0 0 40px rgb(255 122 24 / 65%);
}

.btn--ghost {
	background: transparent;
	color: var(--bone);
	border-color: var(--hairline);
}

.btn--ghost:hover {
	border-color: var(--bone);
	transform: translateY(-2px);
}

/* ---------- nav ---------- */

.nav {
	position: fixed;
	inset: 0 0 auto;
	z-index: 50;
	height: var(--nav-height);
	display: flex;
	align-items: center;
	gap: 2rem;
	padding-inline: var(--gutter);
	background: rgb(7 5 15 / 78%);
	backdrop-filter: blur(14px);
	border-bottom: 1px solid transparent;
	transition: border-color 240ms ease, background-color 240ms ease;
}

.nav[data-scrolled="true"] {
	border-bottom-color: var(--hairline);
	background: rgb(7 5 15 / 94%);
}

.nav__home {
	display: flex;
	align-items: center;
	flex: 0 0 auto;
}

.nav__wordmark {
	height: 1.4rem;
	width: auto;
}

.nav__links {
	display: flex;
	gap: 1.75rem;
	margin-inline-start: auto;
	list-style: none;
	padding: 0;
	margin-block: 0;
}

.nav__links a {
	font-family: var(--display);
	font-weight: 500;
	font-size: 0.8125rem;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	text-decoration: none;
	color: var(--ash);
	transition: color 160ms ease;
}

.nav__links a:hover {
	color: var(--bone);
}

.nav .btn {
	padding: 0.55rem 1.15rem;
	font-size: 0.8125rem;
	flex: 0 0 auto;
}

@media (max-width: 60rem) {
	.nav__links {
		display: none;
	}

	.nav__cta {
		margin-inline-start: auto;
	}
}

/* ---------- hero ---------- */

.hero {
	position: relative;
	/* Shorter on phones so the very wide plate is not cropped to nothing. */
	min-height: min(78svh, 44rem);
	display: grid;
	place-items: end center;
	padding-block: calc(var(--nav-height) + 3rem) clamp(3rem, 8vh, 6rem);
	padding-inline: var(--gutter);
	text-align: center;
	overflow: hidden;
	isolation: isolate;
}

.hero__art {
	position: absolute;
	inset: 0;
	z-index: -2;
}

.hero__art img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* The plate is 3.1:1, so a portrait viewport crops hard. Favour the upper
	   middle, where the moon and the bridge fight are. */
	object-position: center 42%;
}

/* Dissolve the art into the page rather than letting it sit in a box. */
.hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(
			to bottom,
			rgb(7 5 15 / 45%) 0%,
			rgb(7 5 15 / 8%) 28%,
			rgb(7 5 15 / 78%) 70%,
			var(--night) 100%
		);
}

.hero__inner {
	max-width: 54rem;
}

.hero__wordmark {
	width: min(46rem, 88vw);
	margin-inline: auto;
	filter: drop-shadow(0 6px 40px rgb(0 0 0 / 70%));
}

.hero__tagline {
	font-family: var(--display);
	font-weight: 600;
	font-size: clamp(1.0625rem, 0.85rem + 1.1vw, 1.75rem);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	line-height: 1.35;
	margin: 1.5rem 0 0;
	text-shadow: 0 2px 24px rgb(0 0 0 / 80%);
}

.hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	justify-content: center;
	margin-top: 2.25rem;
}

.hero__dates {
	font-size: 0.9375rem;
	color: var(--ash);
	margin: 1.75rem 0 0;
	letter-spacing: 0.02em;
}

.hero__dates strong {
	color: var(--bone);
	font-weight: 600;
}

@media (min-width: 48rem) {
	.hero {
		min-height: min(100svh, 60rem);
	}
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
	}
}

/* ---------- utility ---------- */

.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Content is visible by default and only JS may hide it, so a failed script
   or a blocked module can never leave the page blank. */
[data-reveal][data-revealed="false"] {
	opacity: 0;
	transform: translateY(18px);
}

[data-reveal][data-revealed] {
	transition: opacity 620ms ease, transform 620ms ease;
}

[data-reveal][data-revealed="true"] {
	opacity: 1;
	transform: none;
}

/* ---------- systems ---------- */

.systems {
	display: grid;
	gap: clamp(1.5rem, 3vw, 2.5rem);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
}

.system {
	position: relative;
	padding: 2rem 1.75rem 1.75rem;
	background: linear-gradient(165deg, var(--night-3), var(--night-2) 60%);
	border: 1px solid var(--hairline);
	border-radius: 3px;
}

/* A struck match along the top edge - the only ornament in the section. */
.system::before {
	content: "";
	position: absolute;
	inset: -1px auto auto -1px;
	width: 4rem;
	height: 2px;
	background: var(--ember);
	box-shadow: var(--glow-ember);
}

.system__title {
	font-family: var(--display);
	font-weight: 600;
	font-size: 1.375rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	line-height: 1.15;
	margin: 0 0 0.85rem;
}

.system p {
	margin: 0;
	color: var(--ash);
	font-size: 1rem;
}

/* ---------- filmstrip ---------- */

.filmstrip {
	display: flex;
	gap: 1.25rem;
	list-style: none;
	margin: 2.5rem 0 0;
	padding: 0 var(--gutter) 1.5rem;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-color: var(--violet) transparent;
}

.filmstrip > li {
	flex: 0 0 min(86vw, 52rem);
	scroll-snap-align: center;
}

.shot {
	display: block;
	width: 100%;
	padding: 0;
	border: 1px solid var(--hairline);
	border-radius: 3px;
	background: none;
	cursor: zoom-in;
	overflow: hidden;
	transition: border-color 200ms ease, transform 200ms ease;
}

.shot:hover {
	border-color: var(--ember);
	transform: translateY(-3px);
}

.shot img {
	width: 100%;
}

/* ---------- lightbox ---------- */

.lightbox {
	width: min(92vw, 80rem);
	padding: 0;
	border: 1px solid var(--hairline);
	border-radius: 3px;
	background: var(--night);
}

.lightbox::backdrop {
	background: rgb(3 2 7 / 92%);
}

.lightbox img {
	width: 100%;
}

.lightbox__close {
	position: absolute;
	top: 0.5rem;
	right: 0.75rem;
	z-index: 1;
	background: rgb(7 5 15 / 85%);
	color: var(--bone);
	border: 1px solid var(--hairline);
	border-radius: 2px;
	font-size: 1.5rem;
	line-height: 1;
	width: 2.25rem;
	height: 2.25rem;
	cursor: pointer;
}

/* ---------- the board ---------- */

.board {
	background:
		radial-gradient(120% 80% at 50% 0%, rgb(79 214 232 / 6%), transparent 62%),
		var(--night);
	border-block: 1px solid var(--hairline);
}

.board__frame {
	border: 1px solid var(--hairline);
	border-radius: 3px;
	background: rgb(4 3 9 / 72%);
	padding: clamp(1rem, 3vw, 2rem);
}

.board__status {
	font-size: 0.875rem;
	letter-spacing: 0.02em;
	color: var(--ash);
	margin: 0 0 1.25rem;
	display: flex;
	align-items: center;
	gap: 0.6rem;
}

.board__status::before {
	content: "";
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--aether);
	box-shadow: var(--glow-aether);
	flex: 0 0 auto;
}

.board__frame[data-offline="true"] .board__status::before {
	background: var(--ash);
	box-shadow: none;
	animation: pulse 1.6s ease-in-out infinite;
}

@keyframes pulse {
	50% { opacity: 0.25; }
}

.board__table {
	width: 100%;
	border-collapse: collapse;
	font-variant-numeric: tabular-nums;
}

.board__table th,
.board__table td {
	text-align: left;
	padding: 0.7rem 0.75rem;
	border-bottom: 1px solid rgb(91 63 184 / 22%);
}

.board__table thead th {
	font-family: var(--display);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	color: var(--ash);
	border-bottom-color: var(--hairline);
}

.col-rank { width: 4.5rem; }
.col-score,
.col-level,
.col-wave { text-align: right; }
.col-score { color: var(--aether); font-weight: 600; }

.board__table td.col-score,
.board__table th.col-score,
.board__table td.col-level,
.board__table th.col-level,
.board__table td.col-wave,
.board__table th.col-wave {
	text-align: right;
}

.board__row--crowned .col-rank,
.board__row--crowned .col-name {
	color: var(--ember);
	font-weight: 600;
}

.board__row--changed {
	animation: landed 1.8s ease-out;
}

@keyframes landed {
	0% { background: rgb(79 214 232 / 22%); }
	100% { background: transparent; }
}

/* Empty state: rank one is a lantern nobody has lit. */

.board__empty {
	text-align: center;
	padding: clamp(2rem, 6vw, 4rem) 1rem 1rem;
}

.lantern {
	width: 5.5rem;
	height: auto;
	margin-inline: auto;
	fill: none;
	stroke: var(--violet);
	stroke-width: 3;
	stroke-linejoin: round;
	stroke-linecap: round;
}

.lantern__bars {
	stroke-width: 1.5;
	opacity: 0.72;
}

.lantern__flame {
	fill: rgb(91 63 184 / 16%);
	stroke: none;
}

.board__frame[data-state="open-empty"] .lantern {
	stroke: var(--ember);
	filter: drop-shadow(0 0 18px rgb(255 122 24 / 60%));
}

.board__frame[data-state="open-empty"] .lantern__flame {
	fill: var(--ember);
	animation: flicker 2.4s ease-in-out infinite;
}

@keyframes flicker {
	0%, 100% { opacity: 1; }
	42% { opacity: 0.72; }
	61% { opacity: 0.95; }
}

.board__empty-title {
	font-family: var(--display);
	font-weight: 600;
	font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.25rem);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	margin: 1.25rem 0 0.5rem;
}

.board__empty-copy {
	color: var(--ash);
	margin: 0 auto 1.75rem;
	max-width: 34ch;
	font-variant-numeric: tabular-nums;
}

/* ---------- realms ---------- */

.realms {
	list-style: none;
	margin: 0 0 2.5rem;
	padding: 0;
	display: grid;
	gap: 1px;
	background: var(--hairline);
	border: 1px solid var(--hairline);
	border-radius: 3px;
	overflow: hidden;
}

.realm {
	background: var(--night);
	padding: 1.5rem clamp(1rem, 3vw, 2rem);
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.5rem 1.5rem;
	transition: background-color 220ms ease;
}

.realm:hover {
	background: var(--night-2);
}

.realm__ordinal {
	font-family: var(--display);
	font-weight: 500;
	font-size: 0.75rem;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--ember);
	flex: 0 0 7rem;
}

.realm__name {
	font-family: var(--display);
	font-weight: 600;
	font-size: clamp(1.25rem, 1rem + 1vw, 1.75rem);
	letter-spacing: 0.03em;
	text-transform: uppercase;
	margin: 0;
}

.demo__close {
	color: var(--ash);
	max-width: 46ch;
	margin: 0 0 2rem;
}

/* ---------- footer ---------- */

.footer {
	border-top: 1px solid var(--hairline);
	padding-block: 3.5rem;
	background: #050309;
}

.footer__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.5rem 2.5rem;
}

.footer__wordmark {
	height: 1.5rem;
	width: auto;
	opacity: 0.75;
}

.footer__links {
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem;
	margin-inline-start: auto;
}

.footer__links a {
	color: var(--ash);
	text-decoration: none;
	font-size: 0.9375rem;
	border-bottom: 1px solid transparent;
}

.footer__links a:hover {
	color: var(--bone);
	border-bottom-color: var(--ember);
}

.footer__legal {
	flex: 1 0 100%;
	margin: 0;
	font-size: 0.8125rem;
	color: rgb(244 234 214 / 40%);
}

/* ---------- ambient sprites ----------
   Real enemy cut-outs from the game drifting through the dark. Injected by
   motion.js only when motion is allowed, so there is nothing to clean up for
   reduced-motion visitors. */

.drift {
	position: absolute;
	pointer-events: none;
	user-select: none;
	opacity: 0;
	will-change: transform, opacity;
	z-index: 0;
}

.drift img {
	width: 100%;
	height: auto;
	filter: drop-shadow(0 0 18px rgb(0 0 0 / 80%));
}

@keyframes drift-across {
	0%   { opacity: 0; transform: translate3d(0, 0, 0) rotate(0deg); }
	12%  { opacity: var(--drift-opacity, 0.5); }
	88%  { opacity: var(--drift-opacity, 0.5); }
	100% { opacity: 0; transform: translate3d(var(--drift-x, 60px), var(--drift-y, -80px), 0) rotate(var(--drift-spin, 12deg)); }
}

@keyframes bob {
	0%, 100% { transform: translateY(0) rotate(-4deg); }
	50%      { transform: translateY(-14px) rotate(4deg); }
}

@keyframes spin-slow {
	from { transform: rotate(0deg); }
	to   { transform: rotate(360deg); }
}

.drift--drifting { animation: drift-across var(--drift-duration, 26s) linear infinite; }
.drift--bobbing  { opacity: var(--drift-opacity, 0.45); animation: bob var(--drift-duration, 9s) ease-in-out infinite; }
.drift--spinning { opacity: var(--drift-opacity, 0.4); animation: spin-slow var(--drift-duration, 34s) linear infinite; }

.section,
.board,
.keeper {
	position: relative;
	overflow: hidden;
}

.section > .container,
.keeper__inner {
	position: relative;
	z-index: 1;
}

/* ---------- portraits behind the system cards ---------- */

.system {
	overflow: hidden;
	isolation: isolate;
}

/* No mix-blend-mode here. Chrome drops the element entirely when a mask is
   applied anywhere in the ancestor chain of a blended image - masking creates
   a group and the blend then has nothing to composite against. The radial mask
   alone feathers the portrait's dark backdrop into the page, which is all the
   effect was for. */
.system > picture {
	position: absolute;
	right: -14%;
	bottom: -12%;
	width: 62%;
	z-index: -1;
	transition: opacity 300ms ease, transform 400ms ease;
	opacity: 0.72;
}

.system__art {
	width: 100%;
}

.system:hover > picture {
	opacity: 0.95;
	transform: scale(1.04);
}

.system__title,
.system p {
	position: relative;
}

/* ---------- the Lantern Keeper ---------- */

.keeper {
	background: var(--night);
	border-block: 1px solid var(--hairline);
	padding-block: var(--rhythm);
}

.keeper__inner {
	width: min(100% - (var(--gutter) * 2), var(--measure));
	margin-inline: auto;
	display: grid;
	gap: clamp(2rem, 5vw, 4rem);
	align-items: center;
}

@media (min-width: 56rem) {
	.keeper__inner {
		grid-template-columns: 1fr 1fr;
	}
}

.keeper__portrait {
	position: relative;
	justify-self: center;
	max-width: 34rem;
	width: 100%;
}

.keeper__portrait picture {
	display: block;
}

.keeper__portrait img {
	width: 100%;
}

/* Warm light welling up behind him. */
.keeper__portrait::before {
	content: "";
	position: absolute;
	inset: 12% 8% 18%;
	z-index: -1;
	background:
		radial-gradient(closest-side, rgb(255 122 24 / 30%), transparent 74%),
		radial-gradient(closest-side at 50% 40%, rgb(79 214 232 / 16%), transparent 70%);
	filter: blur(26px);
	animation: keeper-glow 6s ease-in-out infinite;
}

@keyframes keeper-glow {
	0%, 100% { opacity: 0.85; }
	45%      { opacity: 1; }
	70%      { opacity: 0.72; }
}

.keeper__stat {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem 2rem;
	margin: 0 0 2rem;
	padding: 0;
	list-style: none;
}

.keeper__stat div {
	min-width: 7rem;
}

.keeper__stat dt {
	font-family: var(--display);
	font-weight: 500;
	font-size: 0.6875rem;
	letter-spacing: 0.26em;
	text-transform: uppercase;
	color: var(--ash);
	margin: 0 0 0.2rem;
}

.keeper__stat dd {
	font-family: var(--display);
	font-weight: 600;
	font-size: 1.125rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ember);
	margin: 0;
}

/* ---------- towers beside the realms ---------- */

.towers {
	display: flex;
	gap: 1.5rem;
	align-items: flex-end;
	justify-content: center;
	margin: 0 0 2.5rem;
}

.towers img {
	width: clamp(6rem, 16vw, 10rem);
	filter: drop-shadow(0 12px 30px rgb(0 0 0 / 70%));
}
