/*=== Burger Joint =============================================================
The game's looks: the series' bones in daylight. One monospaced face, hard offset shadows that press flat under a
tap, rounded corners, eased motion, and six colors: cream, brown, grey, mustard, teal and ketchup (see
docs/prototype-plan.md, Look and feel). Nothing glows or blurs. Everything on the floor and in the kitchen is a shape: the shapes are the art
until there is art. Mobile first: a phone in portrait is the layout everything else grows from */

:root {
	color-scheme: light;
	/* The palette is palette.css's, written from palette.js: cream, brown, grey, mustard, teal and ketchup, their
	shades (cream-2, cream-3, brown-2, teal-2), the plates' china, the receipt's paper, a patty's doneness (done-raw to
	done-burnt, as the grill's patties have them) and the faces' tints */
	--font: "IBM Plex Mono", "Courier New", Courier, monospace;
	--radius: 8px;
	--shadow: 4px 4px 0 var(--grey);
	--shadow-small: 3px 3px 0 var(--grey);
	--press: 80ms ease-out;
	--pop: cubic-bezier(0.34, 1.56, 0.64, 1); /* A small overshoot, for things that appear */
	--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);
	/* The chassis's tokens (core/style/base.css), from the palette above */
	--bg: var(--cream);
	--plate: var(--cream-2);
	--field: var(--cream-3);
	--key: var(--cream-2);
	--border: var(--grey);
	--text: var(--brown);
	--muted: var(--brown-2);
	--accent: var(--mustard);
	--accent-text: var(--brown);
	--primary-border: var(--grey);
	--select: var(--teal);
	--select-wash: var(--teal-2);
	--select-text: var(--brown);
	--focus: var(--brown);
	--shadow-color: var(--grey);
	--snap: var(--press);
	--disabled: 0.4;
	--screen-in: screen_in 180ms ease-out both;
}

/* The numbers the renderers set every frame, registered so they can be transitioned: a re-base's small shift is
absorbed over a tenth of a second instead of showing as a jump */
@property --p {
	syntax: "<number>";
	inherits: true;
	initial-value: 1;
}

@property --cook {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@property --progress {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@property --cook2 {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}


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

/* The shift is all taps, holds and drags: no text to select, no callout on a long press, and no pull to refresh or
bounce under a drag */
#screen_shift {
	user-select: none;
	-webkit-user-select: none;
	-webkit-touch-callout: none;
}

body:has(#screen_shift:not(.hidden)) {
	overscroll-behavior: none;
}

#app {
	min-height: 100dvh;
	display: flex;
	flex-direction: column;
	max-width: 560px;
	margin: 0 auto;
	padding: calc(14px + var(--safe-top)) calc(14px + var(--safe-right)) calc(14px + var(--safe-bottom)) calc(14px + var(--safe-left));
}


/*=== Keys =====================================================================
A button is a key: a hard border, a hard shadow, rounded, and a press that sinks it flat with a touch of ease */


/* A second line under a key's name: what it means, in sentence case */
.button .sub {
	display: block;
	margin-top: 3px;
	font-size: 11px;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
	color: var(--brown-2);
}


.button.primary.selected {
	background: var(--teal);
	border-color: var(--teal);
	color: var(--cream-2);
}

.button.primary.selected .sub {
	color: var(--cream-2);
}


@media (hover: hover) {
	.button:hover:not(:disabled) {
		border-color: var(--brown-2);
	}
}


/*=== Home =====================================================================*/

.hero {
	text-align: center;
	padding: 28px 0 22px;
}

.title {
	margin: 0;
	font-size: 40px;
	font-weight: 700;
	line-height: 1.1;
	letter-spacing: -1px;
}

/* The second word on a mustard sign, like the one over the counter */
.title_accent {
	display: inline-block;
	padding: 0 10px;
	border-radius: var(--radius);
	background: var(--mustard);
	color: var(--brown); /* Not the chassis's accent, which is the label's own mustard */
	transform: rotate(-2deg);
}

.title_accent.small {
	padding: 0 7px;
}


.credits {
	margin: auto 0 0;
	padding-top: 18px;
	font-size: 11px;
	text-align: center;
	color: var(--brown-2);
}

.credits a {
	color: inherit;
}

.home_level {
	margin: 14px 0 0;
}


/*=== Lobby ====================================================================
The room: the code large enough to read across a table, a field for a friend's, the two seats, the level, the role keys */


.lobby_title {
	margin: 0 0 12px;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	color: var(--brown-2);
}


.code_input::placeholder {
	color: var(--grey);
}


.lobby_status.error {
	color: var(--brown);
	font-weight: 700;
}


/* "Ready", a small teal chip; empty otherwise, so the seat keeps its height */
.seat_ready {
	min-height: 1.6em;
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 1px;
	text-transform: uppercase;
	color: var(--cream-2);
}

.seat_ready:not(:empty) {
	align-self: flex-start;
	padding: 1px 8px;
	border-radius: 999px;
	background: var(--teal);
	animation: pop 180ms var(--pop) both;
}

/* The level: a label, a key either side of the number, and how far this room may go */
.level_row {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 14px;
	padding: 8px 12px;
	border: 2px solid var(--grey);
	border-radius: var(--radius);
	background: var(--cream-3);
}

.level_label {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	color: var(--brown-2);
}

.level_value {
	min-width: 2ch;
	text-align: center;
	font-size: 26px;
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}

.level_note {
	flex: 1;
	text-align: right;
	font-size: 12px;
	color: var(--brown-2);
}


/*=== The shift: the HUD =======================================================
The level and the clock, the door sign in the middle, the score; under it the customer row, and in practice the bar
with the Server/Cook toggle */

.hud {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 0 0 8px;
}

.hud_group {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 72px;
}

.hud_group.right {
	align-items: flex-end;
}

.hud_label {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	color: var(--brown-2);
}

.hud_clock,
.hud_score {
	display: inline-block;
	font-size: 20px;
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}

.hud_score.bump {
	animation: bump 320ms var(--pop);
}

/* The door sign: Closed, then the count, then Open, lit */
.sign {
	min-width: 100px;
	padding: 6px 14px;
	border: 2px solid var(--grey);
	border-radius: 999px;
	background: var(--cream-2);
	box-shadow: var(--shadow-small);
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	text-align: center;
}

.sign.lit {
	background: var(--mustard);
	border-color: var(--brown);
}

.sign.digit {
	font-size: 22px;
	padding: 2px 14px;
}

.sign.sign_pop {
	animation: pop 260ms var(--pop);
}

/* A circle per customer: hollow to come, mustard while here, teal fed, grey angry */
.customer_row {
	display: flex;
	flex-wrap: wrap;
	gap: 5px;
	list-style: none;
	margin: 0 0 10px;
	padding: 0;
	min-height: 10px;
}

.pip {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: 2px solid var(--grey);
	transition: background-color 200ms, border-color 200ms;
}

.pip.here {
	border-color: var(--mustard);
	background: var(--mustard);
	animation: pulse 0.9s ease-in-out infinite alternate;
}

.pip.fed {
	border-color: var(--teal);
	background: var(--teal);
}

.pip.angry {
	background: var(--grey);
}

.shift_bar {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0 0 10px;
}

.shift_notice {
	flex: 1;
	font-size: 12px;
	color: var(--brown-2);
}

.shift_notice.warning {
	color: var(--brown);
	font-weight: 700;
}

/* The authority has gone quiet: the screen dims until it is back */
.stale .pass,
.stale .floor,
.stale .kitchen {
	opacity: 0.5;
	filter: saturate(0.3);
	transition: opacity 300ms, filter 300ms;
}


/*=== The pass =================================================================
Six slots in a teal strip, on both screens. A dish is a stack: a mustard bun top, the patty, a cream bun bottom, and
its letter on a chip */

/* The top bar, the same for both players: the pass, and the sink at its right */
.topbar {
	display: flex;
	align-items: stretch;
	gap: 8px;
	margin: 0 0 10px;
}

/* The column at the right of the pass: the sink */
.bar_side {
	display: flex;
	flex-direction: column;
	gap: 6px;
	flex: 0 0 21%;
}

.bar_stations {
	display: flex;
	gap: 8px;
	flex: 1;
}

.bar_stations:empty {
	display: none;
}

.pass {
	flex: 1;
	min-width: 0;
	display: grid;
	grid-template-columns: repeat(5, 1fr);
	align-items: center; /* The slots keep their square shape when the bar is taller than they are */
	gap: 6px;
	margin: 0;
	padding: 8px;
	border: 2px solid var(--teal);
	border-radius: var(--radius);
	background: var(--teal-2);
	touch-action: none;
	user-select: none;
	-webkit-user-select: none;
}

/* A slot: the home of one plate. The plate sits in it while it is home, food on it or not; while it is out (at a
table, dirty, in the sink) the slot is simply empty, and no food can go up onto it */
.pass_slot {
	position: relative;
	aspect-ratio: 1;
	border-radius: 8px;
}

.pass_slot > .slot_plate {
	position: absolute;
	left: 7%;
	top: 7%;
	width: 86%;
	visibility: hidden;
}

.pass_slot.has_plate > .slot_plate {
	visibility: visible;
}

/* The food sits on the slot's plate, and goes where the plate goes */
.slot_plate > .slot_food {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
}

.slot_plate[data-drag] {
	cursor: grab;
}

.dish {
	position: relative;
	width: 76%;
	aspect-ratio: 1.2;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 2px;
	animation: pop 220ms var(--pop) both;
}

.dish[data-drag] {
	cursor: grab;
}

.dish > .bun_top {
	height: 36%;
	border-radius: 50% 50% 10% 10% / 100% 100% 10% 10%;
	background: var(--mustard);
	border: 2px solid var(--brown);
	border-bottom-width: 0;
}

.dish > .patty {
	height: 22%;
	border-radius: 4px;
	background: var(--brown);
	border: 2px solid var(--brown);
}

.dish > .bun_bottom {
	height: 30%;
	border-radius: 10% 10% 45% 45% / 10% 10% 100% 100%;
	background: var(--cream);
	border: 2px solid var(--brown);
	border-top-width: 0;
}

/* The patty by its doneness: brown over cream, more of it the longer it cooked */
/* The patty by its doneness, in steps far enough apart to tell at a glance: pink raw, pink-tan rare, golden brown
medium, brown well, near black burnt. Mixes of cream, mustard and brown; the grill's patties go through the same
colors as they cook (see stations/grill.js DONENESS_COLORS) */
.dish[data-variant="raw"] > .patty { background: var(--done-raw); }
.dish[data-variant="rare"] > .patty { background: var(--done-rare); }
.dish[data-variant="medium"] > .patty { background: var(--done-medium); }
.dish[data-variant="well"] > .patty { background: var(--done-well); }
.dish[data-variant="burnt"] > .patty { background: var(--done-burnt); border-color: var(--grey); }

/* Steam: two wisps that rise and fade */
.dish::before,
.dish::after {
	content: "";
	position: absolute;
	top: -9px;
	left: 32%;
	width: 3px;
	height: 9px;
	border-radius: 2px;
	background: var(--brown-2);
	opacity: 0;
	animation: steam 1.8s ease-in-out infinite;
}

.dish::after {
	left: 60%;
	animation-delay: 0.9s;
}


/*=== The floor ================================================================
The Server's screen. Furniture from the level's floor list, placed by percent; customers drawn above it, walking on a
transition. The customers' layer lets pointers through to the tables, but for the ones at the door, which can be
picked up */

/* The space the floor has, and in it the room: one fixed shape, as large as fits (floor.js fits its width to the
space), so the door, the tables and the customers keep their sizes to each other on every screen. Sizes inside are
in percent of the room's width, with an aspect ratio for the height; positions are in percent of the room */
.floor {
	flex: 1;
	min-height: 260px;
	display: flex;
	justify-content: center;
	align-items: flex-start;
	touch-action: none;
	user-select: none;
	-webkit-user-select: none;
}

.floor_room {
	position: relative;
	flex: 0 0 auto;
	width: 100%;
	aspect-ratio: 13 / 14;
	border: 2px solid var(--grey);
	border-radius: var(--radius);
	background: var(--cream-2); /* Not overflow hidden: a dirty plate carried to the sink leaves the room on its way */
}

.floor_layer,
.customers {
	position: absolute;
	inset: 0;
}

.customers {
	pointer-events: none;
}

.piece {
	position: absolute;
	transform: translate(-50%, -50%);
}

/* A word on a piece of furniture */
.trash_word,
.sink_word {
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	color: var(--brown-2);
	pointer-events: none;
}

/* The door: a thick highlight on the room's bottom edge, in the left corner, centred on the edge line; the next
customer stands just inside it. Grey when nobody is waiting, mustard when someone is */
.door {
	width: 24%;
	height: 8px;
	border-radius: 4px;
	background: var(--grey);
	transition: background-color 200ms;
}

.door.busy {
	background: var(--mustard);
}

/* More in the queue than are drawn: a tag at the door's right end, just inside the room */
.door_more {
	position: absolute;
	bottom: 8px;
	right: -6px;
	min-width: 22px;
	height: 22px;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--mustard);
	border: 2px solid var(--brown);
	font-size: 11px;
	font-weight: 700;
	line-height: 18px;
	text-align: center;
}

.door_more:empty {
	display: none;
}

.trash {
	width: 12%;
	aspect-ratio: 1;
	border: 2px dashed var(--grey);
	border-radius: 8px;
	display: grid;
	place-items: center;
}

/* The dirty plate left on the trash by food thrown away, waiting to be taken to the sink, and how many are */
.trash > .plate {
	position: absolute;
	left: 10%;
	top: 10%;
	width: 80%;
}

.trash > .plate:not(.shown) {
	visibility: hidden;
}

.trash_count {
	position: absolute;
	top: -10px;
	right: -10px;
	min-width: 22px;
	height: 22px;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--grey);
	border: 2px solid var(--brown);
	font-size: 11px;
	font-weight: 700;
	line-height: 18px;
	text-align: center;
	pointer-events: none;
}

.trash_count:empty {
	display: none;
}

/* A table: a rounded square with a plate, the order's chips in its middle once taken, until the food comes */
.table {
	width: 16%;
	aspect-ratio: 1;
	border: 2px solid var(--grey);
	border-radius: 12px;
	background: var(--cream-2);
	box-shadow: var(--shadow-small);
	display: grid;
	place-items: center;
	transition: border-color 200ms, background-color 200ms;
}

.table.ordering {
	cursor: pointer;
	border-color: var(--mustard);
	animation: pulse_border 1s ease-in-out infinite alternate;
}

/* A plate: styled by its own classes, not by the table it sits on, so its copy under a finger looks the same */
.plate {
	display: block;
	width: 58%;
	aspect-ratio: 1;
	border-radius: 50%;
	background: var(--china);
	border: 2px solid var(--grey);
	box-shadow: inset 0 0 0 4px var(--cream-2);
}

/* A table shows its plate only while something is on it: the food, or the dirty plate it left */
.table > .plate:not(.shown) {
	visibility: hidden;
}

/* A dirty plate: grey, with crumbs */
.plate.dirty {
	background-color: var(--grey);
	background-image:
		radial-gradient(circle at 32% 40%, var(--brown) 0 11%, transparent 12%),
		radial-gradient(circle at 66% 62%, var(--brown) 0 9%, transparent 10%),
		radial-gradient(circle at 52% 24%, var(--brown) 0 6%, transparent 7%);
	border-color: var(--brown-2);
	box-shadow: none;
}

.plate.dirty[data-drag] {
	cursor: grab;
}

/* A customer's alert, on their table: a mustard "!" when the order is there to take */
.table > .alert {
	position: absolute;
	top: -11px;
	right: -11px;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	background: var(--mustard);
	border: 2px solid var(--brown);
	font-size: 15px;
	font-weight: 700;
	line-height: 22px;
	text-align: center;
	transform: scale(0);
	transition: transform 200ms var(--pop);
	pointer-events: none;
}

.table.ordering > .alert {
	transform: scale(1);
	animation: pulse_hand 0.9s ease-in-out infinite alternate;
}

/* What has arrived, on the plate */
/* What has come, on the table's plate: the plate and its food are one thing, and land together */
.table > .plate {
	position: relative;
}

.plate > .served {
	position: absolute;
	inset: 12%;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 2px;
	pointer-events: none;
}

.plate > .served .dish {
	width: 100%;
	animation: none; /* Landed with its plate: no pop of its own */
}

.table > .chips {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	pointer-events: none;
}

.chip {
	min-width: 34px;
	height: 34px;
	padding: 0 8px;
	border-radius: 9px;
	background: var(--mustard);
	border: 2px solid var(--brown);
	color: var(--brown);
	font-size: 18px;
	font-weight: 700;
	line-height: 30px;
	text-align: center;
	box-shadow: var(--shadow-small);
	animation: pop 200ms var(--pop) both;
}

/* A table's chair, just above it, where its customer is drawn: never seen, but a drop on it is a drop on the table */
.chair {
	width: 11%;
	aspect-ratio: 1;
	border-radius: 50%;
}

/* A customer: a dark circle with their face, and a spark for their patience */
.customer {
	--p: 1;
	position: absolute;
	width: 11%;
	aspect-ratio: 1;
	transform: translate(-50%, -50%);
	z-index: 2;
	animation: pop 220ms var(--pop) both;
	transition: --p 120ms linear; /* Not left and top: a customer seated by a drag is at the table at once */
}

.customer.queued {
	pointer-events: auto;
	cursor: grab;
}

/* A dark circle, and the face in it: the customer's sprite used as a mask over their tint, clipped by the circle */
.customer > .body {
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: var(--brown);
	border: 2px solid var(--brown);
	box-shadow: 2px 2px 0 var(--grey);
	overflow: hidden;
}

.customer .face {
	position: absolute;
	inset: 5%;
	-webkit-mask: var(--face) center / contain no-repeat;
	mask: var(--face) center / contain no-repeat;
}

/* Patience, as a spark at the top right: nothing at all above a third of their patience, then fading in as it drains
from a third to none, a single spark now and then, and at 20% or less a heartbeat, two sparks close together and a rest. A ketchup star
with a hard brown edge, and a smaller one beside it a beat behind */
.customer > .spark {
	position: absolute;
	top: -22%;
	right: -24%;
	width: 50%;
	aspect-ratio: 1;
	opacity: clamp(0, calc((0.33 - var(--p)) / 0.33), 1);
	filter: drop-shadow(1px 1px 0 var(--brown));
	pointer-events: none;
}

.customer > .spark::before,
.customer > .spark::after {
	content: "";
	position: absolute;
	background: var(--ketchup);
	clip-path: polygon(50% 0%, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0% 50%, 39% 39%);
	scale: 0;
	animation: spark_once 1.8s ease-out infinite;
}

.customer > .spark::before {
	inset: 0;
}

.customer > .spark::after {
	left: -18%;
	top: 46%;
	width: 52%;
	aspect-ratio: 1;
	animation-delay: 0.12s;
}

.customer.critical > .spark::before,
.customer.critical > .spark::after {
	animation: spark_beat 0.9s ease-out infinite;
}

.customer.critical > .spark::after {
	animation-delay: 0.06s;
}

/* Fed or gone: patience no longer matters */
.customer.eating > .spark,
.customer.leaving > .spark {
	display: none;
}

@keyframes spark_once {
	0% { scale: 0; rotate: 0deg; }
	8% { scale: 1.1; rotate: 20deg; }
	20% { scale: 0; rotate: 45deg; }
	100% { scale: 0; rotate: 45deg; }
}

@keyframes spark_beat {
	0% { scale: 0; rotate: 0deg; }
	8% { scale: 1.15; rotate: 15deg; }
	16% { scale: 0.15; rotate: 25deg; }
	25% { scale: 1; rotate: 35deg; }
	36% { scale: 0; rotate: 45deg; }
	100% { scale: 0; rotate: 45deg; }
}

.customer.eating > .body {
	animation: nibble 0.7s ease-in-out infinite alternate;
}

/* Upset: at 20% patience or less, a quick angry shake on each beat of the spark's heartbeat */
.customer.critical > .body {
	animation: fume 0.9s ease-in-out infinite;
}

@keyframes fume {
	0%, 30%, 100% { rotate: 0deg; translate: 0 0; }
	5% { rotate: -9deg; translate: -1px 0; }
	10% { rotate: 8deg; translate: 1px 0; }
	15% { rotate: -6deg; translate: -1px 0; }
	20% { rotate: 5deg; translate: 1px 0; }
	25% { rotate: -2deg; translate: 0 0; }
}

.customer.leaving {
	pointer-events: none;
}

.customer.leaving.fed {
	animation: leave_fed 650ms ease-in forwards;
}

.customer.leaving.angry {
	animation: leave_angry 650ms ease-in forwards;
}


/*=== The sink =================================================================
A teal basin, the dirty plates stacked in it, the water rising as the top one comes clean. Large as the Cook's tab,
small in the Server's corner */

.basin {
	--progress: 0;
	position: relative;
	border: 2px solid var(--teal);
	border-radius: 12px;
	background: var(--cream-2);
	overflow: hidden;
	display: grid;
	place-items: center;
	cursor: pointer;
	touch-action: none;
	user-select: none;
	-webkit-user-select: none;
	-webkit-tap-highlight-color: transparent;
	transition: background-color 200ms, border-color 200ms;
}

.bar_stations > .basin {
	flex: 1;
	min-height: 64px;
	box-shadow: var(--shadow-small);
}

.basin.hands_in {
	border-color: var(--brown);
}

.basin > .water {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: calc(var(--progress) * 100%);
	background: color-mix(in srgb, var(--teal) 55%, var(--cream-2));
	transition: --progress 100ms linear;
}

.basin > .plates {
	position: absolute;
	left: 50%;
	bottom: 10%;
	transform: translateX(-50%);
	display: flex;
	flex-direction: column-reverse;
	gap: 3px;
}

/* A dirty plate in the sink, edge on. Bused by a drag: there at once */
.plate_edge {
	width: 38px;
	max-width: 70%;
	height: 5px;
	margin: 0 auto;
	border-radius: 3px;
	background: var(--grey);
	border: 1px solid var(--brown-2);
}

.basin > .plates {
	width: 100%;
	align-items: center;
}

/* The count, large and in the middle, over the plates and the water; the word small in the corner */
.basin > .sink_count {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 1;
	transform: translate(-50%, -50%);
	padding: 0 6px;
	border-radius: 999px;
	font-size: 22px;
	font-weight: 700;
	line-height: 1.2;
	color: var(--brown);
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}

.basin > .sink_word {
	position: absolute;
	top: 4px;
	left: 5px;
	font-size: 9px;
	line-height: 14px;
	letter-spacing: 1px;
}

/* Bubbles while anyone holds it */
.basin > .bubbles {
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity 200ms;
}

.basin.washing > .bubbles {
	opacity: 1;
}

.bubbles::before,
.bubbles::after {
	content: "";
	position: absolute;
	bottom: 8%;
	left: 30%;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	border: 2px solid var(--cream-2);
	animation: bubble 1.1s linear infinite;
}

.bubbles::after {
	left: 62%;
	width: 7px;
	height: 7px;
	animation-delay: 0.5s;
}

.basin.pop_once {
	animation: pop_once 260ms var(--pop);
}


/*=== The kitchen ==============================================================
The Cook's screen: a tab per station, the station under it. The grill is a dark panel with six round spots */

.kitchen {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 12px;
	touch-action: none;
	user-select: none;
	-webkit-user-select: none;
}

.tabs {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: 1fr;
	gap: 10px;
}

.tab {
	position: relative;
	padding: 10px 12px;
	border: 2px solid var(--grey);
	border-radius: var(--radius);
	background: var(--cream-2);
	font-weight: 700;
	letter-spacing: 1px;
	text-transform: uppercase;
	box-shadow: var(--shadow-small);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: border-color var(--press), background-color var(--press);
}

.tab.selected {
	border-color: var(--teal);
	background: var(--teal-2);
}

.tab_badge {
	position: absolute;
	top: -9px;
	right: -6px;
	min-width: 20px;
	height: 20px;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--brown);
	color: var(--cream-2);
	font-size: 11px;
	line-height: 20px;
	text-align: center;
	letter-spacing: 0;
}

.tab_badge:empty {
	display: none;
}

.tab.alert .tab_badge {
	background: var(--mustard);
	color: var(--brown);
	animation: pulse 0.8s ease-in-out infinite alternate;
}

.station_body {
	flex: 1;
}

.station_note {
	margin: 10px 0 0;
	font-size: 12px;
	color: var(--brown-2);
	text-align: center;
}

.grill {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 12px;
	padding: 14px;
	border: 2px solid var(--grey);
	border-radius: 12px;
	background: var(--brown);
	box-shadow: var(--shadow);
}

/* A spot: a pad to tap. Its ring sweeps through the bands as the patty cooks, with ticks where they begin */
.pad {
	--cook: 0;
	position: relative;
	aspect-ratio: 1;
	padding: 0;
	border-radius: 50%;
	border: 2px solid color-mix(in srgb, var(--grey) 50%, var(--brown));
	background: color-mix(in srgb, var(--brown) 84%, var(--grey));
	display: grid;
	place-items: center;
	cursor: pointer;
	touch-action: manipulation;
	-webkit-tap-highlight-color: transparent;
	transition: transform 80ms ease-out;
	perspective: 320px; /* For the patty turning over */
}

.pad:active {
	transform: scale(0.95);
}

/* The patty: two discs, the side up on top and the side down on the grill under it, just showing at the bottom
edge, each colored by its own time (see stations/grill.js) */
.pad > .patty {
	position: absolute;
	width: 58%;
	aspect-ratio: 1;
	transform: scale(0);
	transition: transform 200ms var(--pop);
}

.pad.on > .patty {
	transform: scale(1);
}

.pad > .patty > .underside,
.pad > .patty > .topside {
	position: absolute;
	inset: 0;
	border-radius: 50%;
}

.pad > .patty > .underside {
	translate: 0 7%;
	box-shadow: 0 2px 0 color-mix(in srgb, var(--brown) 45%, transparent);
}

.pad > .patty > .topside {
	box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--brown) 20%, transparent);
}

/* Grill marks on the seared side, once it is up */
.pad.flipped > .patty > .topside::after {
	content: "";
	position: absolute;
	inset: 16%;
	border-radius: 50%;
	background: repeating-linear-gradient(45deg, transparent 0 5px, color-mix(in srgb, var(--brown) 40%, transparent) 5px 7px);
}

/* The patty's shadow on the grill: hidden under it at rest, drawn out while the patty is up in the air */
.pad > .patty_shadow {
	position: absolute;
	width: 58%;
	aspect-ratio: 1;
	border-radius: 50%;
	background: color-mix(in srgb, var(--brown) 55%, transparent);
	translate: 0 9%;
	filter: blur(2px);
	opacity: 0;
	pointer-events: none;
}

.pad.on > .patty_shadow.flipping {
	animation: flip_shadow 400ms linear;
}

/* A flip: the turn over is the first 140ms (the sides swap at its middle, 70ms: see stations/grill.js), up off the
grill, nearer, and over towards the player, edge on at the top, darker as it faces away from the light; then it
lands, squashed, and bounces out the rest */
.pad > .patty.flipping {
	animation: flip 400ms;
}

@keyframes flip {
	0% { translate: 0 0; rotate: x 0deg; scale: 1; filter: brightness(1); animation-timing-function: ease-out; }
	17.4% { translate: 0 -26%; rotate: x 89deg; scale: 1.14; filter: brightness(0.7); animation-timing-function: steps(1, end); }
	17.6% { translate: 0 -26%; rotate: x -89deg; scale: 1.14; filter: brightness(0.7); animation-timing-function: ease-in; }
	35% { translate: 0 0; rotate: x 0deg; scale: 1.14 0.84; filter: brightness(1); animation-timing-function: ease-out; }
	54% { translate: 0 -9%; scale: 0.95 1.06; animation-timing-function: ease-in; }
	70% { translate: 0 0; scale: 1.05 0.95; animation-timing-function: ease-out; }
	84% { translate: 0 -2%; scale: 0.99 1.01; animation-timing-function: ease-in; }
	100% { translate: 0 0; rotate: x 0deg; scale: 1; filter: brightness(1); }
}

@keyframes flip_shadow {
	0% { opacity: 0; scale: 1; }
	17.5% { opacity: 0.9; scale: 0.72; }
	35% { opacity: 0.5; scale: 1.1 1; }
	54% { opacity: 0.7; scale: 0.9; }
	70% { opacity: 0.3; scale: 1.04 1; }
	100% { opacity: 0; scale: 1; }
}

/* Two rings a spot, one a side. The first, inside, sweeps until the flip, then stays where it stopped, in teal, as
the reference; the second, outside it, sweeps from the flip in mustard */
.pad > .cookring,
.pad > .ticks {
	position: absolute;
	inset: 10%;
	border-radius: 50%;
	-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
	mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
	pointer-events: none;
}

.pad > .cookring.second,
.pad > .ticks.second {
	inset: 2%;
}

.pad > .cookring {
	--ring-color: var(--mustard);
	background: conic-gradient(var(--ring-color) calc(var(--cook) * 1turn), transparent 0);
	opacity: 0;
	transition: opacity 200ms, --cook 100ms linear;
}

.pad > .cookring.second {
	background: conic-gradient(var(--ring-color) calc(var(--cook2) * 1turn), transparent 0);
	transition: opacity 200ms, --cook2 100ms linear;
}

.pad.flipped > .cookring.first {
	--ring-color: var(--teal);
}

.pad.on > .cookring.first,
.pad.flipped > .cookring.second {
	opacity: 1;
}

.pad > .ticks {
	opacity: 0;
	transition: opacity 200ms;
	background: conic-gradient(
		transparent 0 calc(4 / 13 * 1turn - 1.5deg), var(--cream) 0 calc(4 / 13 * 1turn + 1.5deg),
		transparent 0 calc(7 / 13 * 1turn - 1.5deg), var(--cream) 0 calc(7 / 13 * 1turn + 1.5deg),
		transparent 0 calc(10 / 13 * 1turn - 1.5deg), var(--cream) 0 calc(10 / 13 * 1turn + 1.5deg),
		transparent 0
	);
}

.pad.on > .ticks.first,
.pad.flipped > .ticks.second {
	opacity: 0.75;
}

/* The dial: R, M and W round the ring at the middle of each band's stretch, while a patty is on (see stations/grill.js).
Silver, engraved rather than printed, and drawn under the rings, so the sweep passes over them */
.pad > .dial {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 200ms;
	pointer-events: none;
}

.pad.on > .dial {
	opacity: 1;
}

.dial_letter {
	position: absolute;
	translate: -50% -50%;
	font-size: 10px;
	font-weight: 700;
	line-height: 1;
	color: color-mix(in srgb, var(--grey) 72%, var(--brown));
}

/* Sizzle: two cream dots that rise and fade while a patty is on */
.pad.on::before,
.pad.on::after {
	content: "";
	position: absolute;
	top: 30%;
	left: 36%;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var(--cream);
	opacity: 0;
	animation: sizzle 1.2s ease-out infinite;
	pointer-events: none;
}

.pad.on::after {
	left: 58%;
	top: 34%;
	animation-delay: 0.6s;
}


/*=== Drag and drop ============================================================
The thing being moved, held in the cursor (see drag.js): itself, not a copy, lifted above everything with the piece
of furniture it sits in, its own size, and only its hard shadow dropping away from it, so it reads as picked up off
the floor. And the targets that would take it, lit */

.carried {
	z-index: 100;
	cursor: grabbing;
	pointer-events: none;
	filter: drop-shadow(7px 11px 0 var(--lifted));
	transition: filter 140ms ease-out;
}

.piece.carrying {
	z-index: 100;
}

[data-drop].can {
	outline: 2px dashed var(--teal);
	outline-offset: 3px;
}

[data-drop].over {
	background-color: var(--teal-2);
	border-color: var(--teal);
}

/* A table's chair takes a customer like its table, but shows nothing: the table lights up for both */
.chair[data-drop].can,
.chair[data-drop].over {
	outline: none;
	background-color: transparent;
}


/*=== Effects ==================================================================*/

.shake {
	animation: shake 320ms ease-in-out;
}

/* A score, floating up from a table */
.tag {
	position: fixed;
	z-index: 90;
	padding: 2px 10px;
	border-radius: 999px;
	background: var(--mustard);
	border: 2px solid var(--brown);
	color: var(--brown);
	font-size: 14px;
	font-weight: 700;
	white-space: nowrap;
	pointer-events: none;
}

/* A dish on its way from the pass to a table */
.flying {
	position: fixed;
	z-index: 95;
	margin: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	pointer-events: none;
	animation: none;
}


/*=== Results: the receipt =====================================================
A cream slip that prints line by line, the total, the threshold bar to the mark, the stamp, then the keys */

.card.receipt {
	margin: auto 0;
	width: 100%;
	max-width: 440px;
	align-self: center;
	background: var(--receipt);
}

.receipt_title {
	margin: 0;
	font-size: 24px;
	text-align: center;
}

.receipt_sub {
	margin: 6px 0 14px;
	font-size: 13px;
	text-align: center;
	color: var(--brown-2);
}

.receipt_lines {
	list-style: none;
	margin: 0;
	padding: 10px 0;
	border-top: 2px dashed var(--grey);
	border-bottom: 2px dashed var(--grey);
}

.line {
	display: grid;
	grid-template-columns: 2ch 1fr auto 5ch;
	gap: 8px;
	padding: 3px 0;
	font-size: 13px;
	opacity: 0;
	transform: translateY(4px);
	transition: opacity 180ms ease-out, transform 180ms ease-out;
}

.line.shown {
	opacity: 1;
	transform: none;
}

.line_no,
.line_how {
	color: var(--brown-2);
}

.line.walked .line_what {
	color: var(--brown-2);
	text-decoration: line-through;
}

.line_points {
	text-align: right;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.receipt_total {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: 12px 0 10px;
	opacity: 0;
	transition: opacity 200ms;
}

.receipt_total.shown {
	opacity: 1;
}

.receipt_total_label {
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	color: var(--brown-2);
}

.receipt_score {
	font-size: 32px;
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
}

.threshold {
	position: relative;
	height: 14px;
	border: 2px solid var(--grey);
	border-radius: 999px;
	background: var(--cream-3);
	opacity: 0;
	transition: opacity 200ms;
}

.threshold.shown {
	opacity: 1;
}

.threshold_fill {
	height: 100%;
	width: 0;
	border-radius: 999px;
	background: var(--teal);
	transition: width 800ms cubic-bezier(0.2, 0.8, 0.3, 1);
}

.threshold.passed .threshold_fill {
	background: var(--mustard);
}

.threshold_mark {
	position: absolute;
	top: -6px;
	bottom: -6px;
	width: 3px;
	border-radius: 2px;
	background: var(--brown);
	transform: translateX(-50%);
}

.threshold_note {
	min-height: 1.5em;
	margin: 10px 0 0;
	font-size: 13px;
	text-align: center;
	color: var(--brown-2);
	opacity: 0;
	transition: opacity 200ms;
}

.threshold_note.shown {
	opacity: 1;
}

.stamp {
	width: fit-content;
	margin: 10px auto 0;
	padding: 6px 14px;
	border: 3px solid var(--brown);
	border-radius: 8px;
	background: var(--mustard);
	color: var(--brown);
	font-weight: 700;
	letter-spacing: 2px;
	text-transform: uppercase;
	transform: rotate(-4deg);
	visibility: hidden;
}

.stamp:empty {
	display: none;
}

.stamp.shown {
	visibility: visible;
}

.stamp.stamp_in {
	animation: stamp_in 320ms var(--pop) both;
}

.results_menu {
	margin-top: 18px;
	visibility: hidden;
}

.results_menu.ready {
	visibility: visible;
	animation: screen_in 200ms ease-out both;
}

/* Play again, in a room: two keys on one line, roles kept or swapped. Yours is held down once pressed */
.results_row {
	display: flex;
	gap: 10px;
}

.results_row .button {
	flex: 1;
}

.results_status {
	min-height: 1.5em;
	margin: -2px 0 0;
	font-size: 12px;
	color: var(--brown-2);
}


/*=== Motion ===================================================================
Short and eased, with a little overshoot where something appears. Never stepped: that was the typewriter */

@keyframes screen_in {
	from { opacity: 0; transform: translateY(6px); }
	to { opacity: 1; transform: none; }
}

@keyframes pop {
	from { scale: 0.6; opacity: 0; }
	to { scale: 1; opacity: 1; }
}

@keyframes pop_once {
	0% { scale: 1; }
	50% { scale: 1.08; }
	100% { scale: 1; }
}

@keyframes bump {
	0% { scale: 1; }
	40% { scale: 1.3; }
	100% { scale: 1; }
}

@keyframes pulse {
	from { opacity: 1; }
	to { opacity: 0.35; }
}

@keyframes pulse_hand {
	from { scale: 1; }
	to { scale: 1.25; }
}

@keyframes pulse_border {
	from { box-shadow: var(--shadow-small); }
	to { box-shadow: var(--shadow-small), 0 0 0 4px var(--teal-2); }
}

@keyframes nibble {
	from { translate: 0 0; }
	to { translate: 0 -2px; }
}

@keyframes leave_fed {
	to { translate: 0 -26px; opacity: 0; }
}

/* Gone unfed: a hard shake on the spot, then off, tilted, fading */
@keyframes leave_angry {
	0% { translate: 0 0; rotate: 0deg; opacity: 1; }
	8% { rotate: -12deg; }
	16% { rotate: 11deg; }
	24% { rotate: -9deg; }
	32% { rotate: 7deg; }
	40% { translate: 0 0; rotate: -3deg; opacity: 1; }
	100% { translate: -34px 10px; rotate: -14deg; opacity: 0; }
}

@keyframes shake {
	0%, 100% { translate: 0 0; }
	20%, 60% { translate: -4px 0; }
	40%, 80% { translate: 4px 0; }
}

@keyframes sizzle {
	0% { translate: 0 0; opacity: 0; }
	20% { opacity: 0.9; }
	100% { translate: 0 -14px; opacity: 0; }
}

@keyframes steam {
	0% { translate: 0 0; opacity: 0; }
	30% { opacity: 0.6; }
	100% { translate: 2px -10px; opacity: 0; }
}

@keyframes bubble {
	0% { translate: 0 0; opacity: 0; }
	20% { opacity: 1; }
	100% { translate: 3px -40px; opacity: 0; }
}

@keyframes stamp_in {
	from { scale: 1.8; opacity: 0; }
	to { scale: 1; opacity: 1; }
}



/* The code in the page's own ink, not the accent */
.code {
	color: var(--brown);
}
