/*=== Arcade ===================================================================
The front door's looks: a lightbulb with a die in it, lit (icon.svg). The night it hangs in, chalk lines with rough
edges, and a light stippled through in cyan, blue and violet, from the hub's palette (palette.css, written from
hub/palette.js). SymbolSync's bones under it: one monospaced face, hard offset shadows that press flat under a tap.
Each game's card is the exception, dressed as its game in that game's own colors (cards.css) and faces: a little of
its front door, so the menu shows what's behind each one. Mobile first: a phone in portrait is the layout everything
else grows from */

:root {
	color-scheme: dark;
	--font: "IBM Plex Mono", "Courier New", Courier, monospace;
	--snap: 60ms;
	--safe-top: env(safe-area-inset-top, 0px);
	--safe-right: env(safe-area-inset-right, 0px);
	--safe-bottom: env(safe-area-inset-bottom, 0px);
	--safe-left: env(safe-area-inset-left, 0px);
}

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

html {
	background: var(--void);
	color: var(--chalk);
	font: 15px/1.5 var(--font);
	-webkit-text-size-adjust: 100%;
}

body {
	position: relative;
	margin: 0;
	min-height: 100dvh;
	overflow-x: hidden;
	background:
		radial-gradient(circle at 50% 150px, color-mix(in srgb, var(--glow) 70%, transparent), transparent 300px),
		var(--void);
}

/* The grain the bulb is drawn on: a sparse stipple of its light over the whole night, fixed while the page scrolls */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	background: var(--cyan);
	opacity: 0.4;
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -30 10.4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -30 10.4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

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


/*=== The page =================================================================*/

#app {
	position: relative;
	z-index: 1;
	min-height: 100dvh;
	display: flex;
	flex-direction: column;
	gap: 24px;
	max-width: 560px;
	margin: 0 auto;
	padding: calc(28px + var(--safe-top)) calc(16px + var(--safe-right)) calc(28px + var(--safe-bottom)) calc(16px + var(--safe-left));
}

.hero {
	text-align: center;
}

.title {
	margin: 4px 0 0;
	font-size: 44px;
	line-height: 1.1;
	letter-spacing: 0.02em;
	text-shadow: 0 0 22px color-mix(in srgb, var(--cyan) 45%, transparent);
}

.tagline {
	margin: 10px auto 0;
	max-width: 420px;
	color: var(--cyan-pale);
}


/*=== The bulb =================================================================
Drawn in index.html; its colors are here. The glass glows in the dark teal of the picture, stippled with light; the
die is cyan, speckled blue and violet; the lines are chalk. It flickers on once as the page opens, and its rays
breathe after */

.bulb {
	display: block;
	width: 136px;
	height: auto;
	margin: 0 auto;
	overflow: visible;
	animation: switch_on 900ms steps(1) both;
}

.bulb_glass {
	fill: var(--glow);
}

.bulb_glass_light {
	fill: var(--cyan);
	opacity: 0.6;
}

.die_face {
	fill: var(--cyan);
}

.die_blue {
	fill: var(--blue);
}

.die_violet {
	fill: var(--violet);
}

.bulb_chalk {
	fill: none;
	stroke: var(--chalk);
	stroke-linecap: round;
	stroke-linejoin: round;
}

.bulb_rays {
	stroke-width: 8;
	animation: breathe 3.2s ease-in-out 900ms infinite;
}

.bulb_line {
	stroke-width: 7;
}

.die_line {
	stroke-width: 3.2;
}

.bulb_base {
	fill: var(--chalk);
	stroke: none;
}


/*=== The cards ================================================================
A card each, the whole card the link. Its bones are the series' (a hard offset shadow that grows under the pointer
and presses flat under a tap); its dress is a handful of tokens, the hub's own here and each game's below */

.games {
	display: grid;
	gap: 20px;
}

.game {
	--card-surface: var(--plate);
	--card-text: var(--chalk);
	--card-muted: var(--cyan-pale);
	--card-accent: var(--cyan);
	--card-border: var(--rim);
	--card-border-width: 2px;
	--card-border-style: solid;
	--card-shadow: var(--rim);
	--card-radius: 0px;
	--card-name-font: var(--font);
	--card-name-weight: 700;
	--card-name-spacing: 0;
	--card-name-size: 22px;
	--card-ease: steps(2);

	position: relative;
	isolation: isolate;
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 16px 18px;
	background: var(--card-surface);
	color: var(--card-text);
	border: var(--card-border-width) var(--card-border-style) var(--card-border);
	border-radius: var(--card-radius);
	box-shadow: 4px 4px 0 var(--card-shadow);
	text-decoration: none;
	overflow: hidden;
	transition: transform var(--snap) var(--card-ease), box-shadow var(--snap) var(--card-ease);
}

.game:hover,
.game:focus-visible {
	transform: translate(-2px, -2px);
	box-shadow: 6px 6px 0 var(--card-shadow);
}

.game:focus-visible {
	outline: 3px solid var(--cyan);
	outline-offset: 4px;
}

.game:hover .game_name,
.game:focus-visible .game_name {
	text-decoration: underline;
	text-decoration-color: var(--card-accent);
	text-decoration-thickness: 2px;
	text-underline-offset: 5px;
}

/* A press sinks the card flat, by the shadow's offset */
.game:active {
	transform: translate(4px, 4px);
	box-shadow: 0 0 0 var(--card-shadow);
}

.game_head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 4px 12px;
}

.game_name {
	font-family: var(--card-name-font);
	font-size: var(--card-name-size);
	font-weight: var(--card-name-weight);
	letter-spacing: var(--card-name-spacing);
	line-height: 1.2;
}

.accent {
	color: var(--card-accent);
}

.game_meta,
.game_live,
.game_tag {
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--card-muted);
}

.game_pitch {
	color: var(--card-text);
}

.game_live {
	min-height: 18px; /* Holds its line before hub.js fills it, so nothing shifts */
}

.game_live.busy {
	color: var(--card-accent);
}

/* A game not ready to stand with the others: a dashed card and a tag saying why (none at present) */
.game_tag {
	color: var(--card-accent);
}

.game.early {
	--card-border-style: dashed;
}


/*=== SymbolSync: a well oiled typewriter ======================================
The series' own bones, as the game has them: ink, steel, sage, paper and tan, hard edges, a stepped press */

.game[data-palette="symbolsync"] {
	--card-surface: var(--game-ink-2);
	--card-text: var(--game-paper);
	--card-muted: var(--game-sage);
	--card-accent: var(--game-tan);
	--card-border: var(--game-steel);
	--card-shadow: var(--game-steel);
}

/* The keys of the shutter, faint behind the pitch: a row of square plates along the bottom edge */
.game[data-palette="symbolsync"]::after {
	content: "";
	position: absolute;
	right: 14px;
	bottom: 14px;
	z-index: -1;
	width: 76px;
	height: 22px;
	background: repeating-linear-gradient(90deg, var(--game-ink-4) 0 22px, transparent 22px 27px);
	box-shadow: 0 3px 0 var(--game-ink);
}


/*=== Burger Joint: the series in daylight =====================================
Cream and brown, rounded corners, an eased press, the second word on the mustard sign over the counter, and a
gingham awning of ketchup along the top */

.game[data-palette="burgerjoint"] {
	--card-surface: var(--game-cream);
	--card-text: var(--game-brown);
	--card-muted: var(--game-brown-2);
	--card-accent: var(--game-ketchup);
	--card-border: var(--game-grey);
	--card-shadow: var(--game-grey);
	--card-radius: 8px;
	--card-name-spacing: -0.5px;
	--card-ease: ease-out;
	padding-top: 28px;
}

.game[data-palette="burgerjoint"]::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: 12px;
	background:
		repeating-linear-gradient(90deg, color-mix(in srgb, var(--game-ketchup) 55%, transparent) 0 12px, transparent 12px 24px),
		repeating-linear-gradient(0deg, color-mix(in srgb, var(--game-ketchup) 55%, transparent) 0 6px, transparent 6px 12px),
		var(--game-cream-2);
	border-bottom: 2px solid var(--game-grey);
}

.game[data-palette="burgerjoint"] .accent {
	display: inline-block;
	padding: 0 8px;
	border-radius: 6px;
	background: var(--game-mustard);
	color: var(--game-brown);
}


/*=== Crypt Tryst: a candle in the crypt =======================================
The night, darkest at the edges, umber stone for the frame and its shadow, wax for the words, and a candle's glow
pooling from the corner where its flame burns after the name */

.game[data-palette="crypttryst"] {
	--card-surface:
		radial-gradient(circle at 92% 12%, color-mix(in srgb, var(--game-candle) 22%, transparent), transparent 55%),
		radial-gradient(ellipse at 50% 40%, var(--game-night-glow), var(--game-night-edge));
	--card-text: var(--game-wax);
	--card-muted: var(--game-moon-pale);
	--card-accent: var(--game-candle);
	--card-border: var(--game-umber);
	--card-shadow: var(--game-umber);
}

.game[data-palette="crypttryst"] .flame {
	position: relative;
	display: inline-block;
	width: 0.32em;
	height: 0.32em;
	margin-left: 0.2em;
	vertical-align: 0.45em;
	transform-origin: 50% 100%;
	animation: flicker 2.8s ease-in-out infinite;
}

.game[data-palette="crypttryst"] .flame::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50% 0 50% 50%;
	transform: rotate(-45deg);
	background: radial-gradient(circle at 60% 40%, var(--game-rose) 0 22%, var(--game-candle) 48%, var(--game-spark) 100%);
	box-shadow: 0 0 10px 2px color-mix(in srgb, var(--game-candle) 60%, transparent), 0 0 28px 8px color-mix(in srgb, var(--game-candle) 22%, transparent);
}


/*=== StarSignals Crossed: a workshop by starlight =============================
Pine night with a glow up top and a sky of stars, mint words, firefly green for the accent and the brass slash, a
shooting star, through the name; the fridge's serif for the pitch, and a springy press */

.game[data-palette="starsignalscrossed"] {
	--card-surface:
		radial-gradient(1.5px 1.5px at 12% 22%, var(--game-mint), transparent),
		radial-gradient(1px 1px at 34% 70%, var(--game-mint), transparent),
		radial-gradient(2px 2px at 58% 16%, var(--game-firefly), transparent),
		radial-gradient(1px 1px at 72% 82%, var(--game-mint), transparent),
		radial-gradient(1.5px 1.5px at 88% 40%, var(--game-mint), transparent),
		radial-gradient(1px 1px at 22% 92%, var(--game-firefly), transparent),
		radial-gradient(ellipse at 50% -20%, var(--game-glow), var(--game-night) 70%);
	--card-text: var(--game-mint);
	--card-muted: var(--game-pewter);
	--card-accent: var(--game-firefly);
	--card-border: var(--game-pine);
	--card-shadow: var(--game-shade);
	--card-radius: 6px;
	--card-name-spacing: -0.5px;
	--card-ease: cubic-bezier(0.34, 1.56, 0.64, 1);
	transition-duration: 140ms;
}

.game[data-palette="starsignalscrossed"] .slash {
	display: inline-block;
	margin: 0 2px;
	color: var(--game-brass);
	font-size: 1.2em;
	line-height: 0.8;
	transform: rotate(12deg) translateY(2px);
	text-shadow: 0 0 10px color-mix(in srgb, var(--game-brass) 60%, transparent);
}

.game[data-palette="starsignalscrossed"] .game_pitch {
	font-family: "IBM Plex Serif", Georgia, "Times New Roman", serif;
	font-style: italic;
	font-size: 15.5px;
}


/*=== Mortar Team: a WW1 field kit =============================================
Graph paper with its fine and firm rules, graphite lines and words, the name typed on a worn typewriter in brick,
square corners, and the live line pencilled in by the Spotter's quick hand */

.game[data-palette="mortarteam"] {
	--card-surface:
		linear-gradient(var(--game-graph) 1px, transparent 1px) 0 0 / 60px 60px,
		linear-gradient(90deg, var(--game-graph) 1px, transparent 1px) 0 0 / 60px 60px,
		linear-gradient(color-mix(in srgb, var(--game-slate) 5%, transparent) 1px, transparent 1px) 0 0 / 12px 12px,
		linear-gradient(90deg, color-mix(in srgb, var(--game-slate) 5%, transparent) 1px, transparent 1px) 0 0 / 12px 12px,
		var(--game-paper);
	--card-text: var(--game-slate);
	--card-muted: var(--game-slate-2);
	--card-accent: var(--game-brick);
	--card-border: var(--game-slate);
	--card-border-width: 1.5px;
	--card-shadow: color-mix(in srgb, var(--game-slate) 45%, transparent);
	--card-name-font: "Special Elite", "Courier New", Courier, monospace;
	--card-name-weight: 400;
	--card-name-spacing: 2px;
	--card-name-size: 24px;
}

.game[data-palette="mortarteam"] .game_live {
	font-family: "Caveat", "Comic Sans MS", cursive;
	font-size: 19px;
	line-height: 1;
	text-transform: none;
	letter-spacing: 0;
	color: var(--game-olive);
}

.game[data-palette="mortarteam"] .game_live.busy {
	color: var(--game-brick);
}

/* A target ringed in red pencil, in the corner of the map */
.game[data-palette="mortarteam"]::after {
	content: "";
	position: absolute;
	right: -14px;
	bottom: -14px;
	z-index: -1;
	width: 64px;
	height: 64px;
	border-radius: 50%;
	background:
		radial-gradient(circle, var(--game-brick) 0 3px, transparent 3.5px),
		radial-gradient(circle, transparent 0 16px, color-mix(in srgb, var(--game-brick) 55%, transparent) 16.5px 18px, transparent 18.5px);
	border: 1.5px dashed color-mix(in srgb, var(--game-brick) 45%, transparent);
}


/*=== Jelly Cleave: a candy factory ============================================
Mist tiles with a fine grout, storm for the words and the frame, round corners and the soft round face, berry for
the accent, and three jellies (berry, lemon, lime) wobbling in the corner, each with its gloss */

.game[data-palette="jellycleave"] {
	--card-surface:
		linear-gradient(var(--game-tile) 1.5px, transparent 1.5px) 0 0 / 44px 44px,
		linear-gradient(90deg, var(--game-tile) 1.5px, transparent 1.5px) 0 0 / 44px 44px,
		var(--game-floor);
	--card-text: var(--game-storm);
	--card-muted: var(--game-storm-2);
	--card-accent: var(--game-berry);
	--card-border: var(--game-storm);
	--card-shadow: color-mix(in srgb, var(--game-storm) 55%, transparent);
	--card-radius: 14px;
	--card-name-font: "Fredoka", "Trebuchet MS", system-ui, sans-serif;
	--card-name-spacing: 1px;
	--card-name-size: 25px;
	--card-ease: ease-out;
	padding-bottom: 20px;
}

.game[data-palette="jellycleave"] .jellies {
	position: absolute;
	right: 14px;
	bottom: 12px;
	display: flex;
	align-items: flex-end;
	gap: 4px;
	pointer-events: none;
}

.game[data-palette="jellycleave"] .jellies span {
	--jelly: var(--game-berry);
	--jelly-light: var(--game-berry-light);
	--jelly-dark: var(--game-berry-dark);
	width: 20px;
	height: 16px;
	border-radius: 10px 10px 5px 5px;
	background: radial-gradient(circle at 32% 30%, var(--jelly-light) 0 3px, transparent 3.5px), var(--jelly);
	box-shadow: inset 0 -3px 0 var(--jelly-dark);
	transform-origin: 50% 100%;
	animation: wobble 2.4s ease-in-out infinite;
}

.game[data-palette="jellycleave"] .jellies span:nth-child(2) {
	--jelly: var(--game-lemon);
	--jelly-light: var(--game-lemon-light);
	--jelly-dark: var(--game-lemon-dark);
	height: 20px;
	animation-delay: -0.8s;
}

.game[data-palette="jellycleave"] .jellies span:nth-child(3) {
	--jelly: var(--game-lime);
	--jelly-light: var(--game-lime-light);
	--jelly-dark: var(--game-lime-dark);
	animation-delay: -1.6s;
}


/*=== Phase Formation: an iridescent void ======================================
Aubergine sunk toward black, with a film of the void's colors drifting through it, wheat words, and the name out of
phase: a cerulean ghost one way, a persimmon one the other */

.game[data-palette="phaseformation"] {
	--card-surface:
		linear-gradient(115deg,
			transparent 10%,
			color-mix(in srgb, var(--game-indigo) 22%, transparent) 35%,
			color-mix(in srgb, var(--game-blue) 14%, transparent) 50%,
			color-mix(in srgb, var(--game-orchid) 14%, transparent) 65%,
			transparent 90%) 0 0 / 240% 100%,
		var(--game-void);
	--card-text: var(--game-wheat);
	--card-muted: var(--game-wheat-2);
	--card-accent: var(--game-orange);
	--card-border: var(--game-rim);
	--card-shadow: var(--game-void-3);
	--card-radius: 4px;
	animation: film 14s ease-in-out infinite alternate;
}

.game[data-palette="phaseformation"] .game_name {
	text-shadow: -2px 0 0 color-mix(in srgb, var(--game-blue) 70%, transparent), 2px 0 0 color-mix(in srgb, var(--game-orange) 55%, transparent);
}

.game[data-palette="phaseformation"] .accent {
	text-shadow: -2px 0 0 color-mix(in srgb, var(--game-blue) 70%, transparent);
}


/*=== Sort Order: a post office back room ======================================
Cream paper on a dim wall, ink words, the rubber stamp's slab for the name with its second word in red pen, hazard
stripes along the top as a machine's lip has them, and a strip of parcel tape across the corner */

.game[data-palette="sortorder"] {
	--card-surface: var(--game-paper-2);
	--card-text: var(--game-ink);
	--card-muted: var(--game-ink-2);
	--card-accent: var(--game-salmon-dark);
	--card-border: var(--game-ink);
	--card-shadow: var(--game-shade);
	--card-radius: 6px;
	--card-name-font: "Alfa Slab One", Georgia, serif;
	--card-name-weight: 400;
	--card-name-spacing: 0.5px;
	--card-ease: ease-out;
	padding-top: 26px;
}

.game[data-palette="sortorder"]::before {
	content: "";
	position: absolute;
	inset: 0 0 auto;
	height: 10px;
	background: repeating-linear-gradient(-45deg, var(--game-salmon) 0 10px, var(--game-ink) 10px 20px);
}

.game[data-palette="sortorder"]::after {
	content: "";
	position: absolute;
	right: -22px;
	bottom: 18px;
	z-index: -1;
	width: 96px;
	height: 22px;
	background: var(--game-tape);
	transform: rotate(-32deg);
}


/*=== How it works, and the foot ===============================================*/

.card {
	padding: 16px 18px;
	background: color-mix(in srgb, var(--plate) 88%, transparent);
	border: 2px solid var(--rim);
}

.how_title {
	margin: 0 0 8px;
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--cyan);
}

.how p {
	margin: 0 0 10px;
}

.how p:last-child {
	margin-bottom: 0;
}

.how strong {
	color: var(--cyan-pale);
}

.foot {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 8px 16px;
	margin-top: auto;
	padding-top: 8px;
	font-size: 12px;
	color: var(--cyan-pale);
}


/*=== Motion ===================================================================*/

/* The bulb comes on as a bulb does: a stutter, then lit */
@keyframes switch_on {
	0% { opacity: 0.15; }
	20% { opacity: 1; }
	30% { opacity: 0.3; }
	45% { opacity: 1; }
	55% { opacity: 0.6; }
	70%, 100% { opacity: 1; }
}

@keyframes breathe {
	50% { opacity: 0.55; }
}

@keyframes flicker {
	0%, 100% { transform: scale(1, 1) rotate(0deg); }
	30% { transform: scale(0.94, 1.08) rotate(-3deg); }
	60% { transform: scale(1.04, 0.95) rotate(2deg); }
}

@keyframes wobble {
	0%, 100% { transform: scale(1, 1); }
	25% { transform: scale(1.08, 0.92); }
	50% { transform: scale(0.95, 1.06); }
	75% { transform: scale(1.02, 0.98); }
}

@keyframes film {
	to { background-position: 100% 0, 0 0; }
}

@media (prefers-reduced-motion: reduce) {
	.bulb,
	.bulb_rays,
	.game[data-palette="crypttryst"] .flame,
	.game[data-palette="jellycleave"] .jellies span,
	.game[data-palette="phaseformation"] {
		animation: none;
	}

	.game {
		transition: none;
	}
}
