/*
	THE READING GAME SHELL — one screen, shared by every reading game.

	Sentence Builder was the first; Sight Words is the second; anything else we
	build sits in the same frame. Everything visual that is not specific to one
	game lives here, so a change to "how a reading game looks" is a change to
	one file and every game gets it.

	The screen is a phone held upright, and it only ever holds three things:

		card    the words being read (a sentence, or one word, or nothing)
		tray    the choices, along the bottom, under the thumbs
		prize   the picture that arrives when the round is won, plus Next

	Rules that came out of building the first game, all of them from Robert:
	no start button, no score, no home button, no speaker icon, no borders
	around the words, and nothing that pulses, blinks or breathes. The only
	thing that ever moves is the highlight walking the words as they are read.
*/

/* ---- the phone ------------------------------------------------------ */
body { overflow:hidden; }

.phone {
	position:fixed; left:50%; top:50%; transform:translate(-50%,-50%);
	/* the -28px keeps the bezel ring off the window edges on a desktop, where
	   the frame is meant to read as a phone sitting on the page */
	width:min(100vw, 430px); height:min(100vh - 28px, 880px);
	overflow:hidden; background:#eaf6ff;
	border-radius:38px; box-shadow:0 26px 70px rgba(0,40,90,.45), 0 0 0 10px #26364a;
	z-index:5;
	--scale:1;
}
/* on an actual phone it IS the screen — no bezel, no rounding, and dvh so the
   browser's own chrome doesn't crop the tray */
@media (max-width:520px), (max-height:560px) {
	.phone { width:100vw; height:100dvh; border-radius:0; box-shadow:none; }
}
.phone .screen { position:absolute; inset:0; padding:0; }

/* a calm sky while they work — the picture is a reward, not wallpaper */
.rs_bg {
	position:absolute; inset:0;
	background:linear-gradient(#dff1ff 0%, #eaf7ff 55%, #f4fbe9 100%);
}

.rs_stage {
	position:absolute; inset:0; display:flex; flex-direction:column;
	padding:16px 14px calc(16px + env(safe-area-inset-bottom));
	gap:12px;
}

/* ---- the words ------------------------------------------------------ */

.rs_card {
	background:#fff; border-radius:26px;
	box-shadow:0 8px 22px rgba(0,60,120,.13);
	padding:18px 16px 20px;
	display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
	gap:8px 10px;
	min-height:2.6em;
	font-size:calc(clamp(21px, 6.6vw, 29px) * var(--scale));
	font-weight:bold; color:#2a3646; line-height:1.3;
	cursor:pointer; -webkit-tap-highlight-color:transparent;
	transition:transform .2s;
}
.rs_card:active { transform:scale(.985); }
/* a game with nothing to show yet (Sight Words, while it is only listening)
   keeps the card's shape so the screen doesn't jump when the words arrive */
.rs_card.empty { background:rgba(255,255,255,.55); box-shadow:none; }

.rs_word { padding:2px 4px; border-radius:9px; transition:background .12s, color .12s; }
.rs_word.rs_on { background:#f7b500; color:#fff; }
/* the one word the round was about, sitting in its sentence */
.rs_word.rs_hit { color:#1a7f5a; box-shadow:inset 0 -5px 0 #a7e8cd; }

/* the speaker a listening game shows instead of words */
.rs_speaker {
	display:inline-flex; align-items:center; justify-content:center;
	padding:6px 10px; border-radius:14px; color:#5f9dc4;
	transition:background .12s, color .12s;
}
.rs_speaker svg { width:1.9em; height:1.9em; fill:currentColor; }
.rs_speaker.rs_on { background:#f7b500; color:#fff; }

/* the blank is a writing line, the way it is on paper — no box, no dashes */
.rs_slot {
	min-width:4.4em; min-height:1.35em;
	display:inline-flex; align-items:center; justify-content:center;
	border-bottom:5px solid #b9d4e6; border-radius:2px;
	color:transparent; padding:0 6px;
	transition:border-color .2s, color .2s, background .2s;
}
.rs_slot.over { border-color:#f7b500; background:#fffbe6; }
.rs_slot.filled { border-color:#12b981; color:#2a3646; }

/* ---- the choices ---------------------------------------------------- */
/* the words sit a little above the bottom edge rather than pinned to it:
   pinned, the screen reads as two things stuck at opposite ends with a hole
   between them, and a small child's reach isn't the bottom 10% anyway */
.rs_tray {
	margin-top:auto; margin-bottom:9%;
	display:flex; flex-wrap:wrap; gap:12px; justify-content:center;
	padding:4px 2px;
}
.rs_tile {
	background:#fff; border:none; border-radius:16px;
	padding:12px 20px;
	font-size:calc(clamp(19px, 5.8vw, 27px) * var(--scale));
	font-weight:bold; color:#2a3646;
	cursor:grab; touch-action:none; user-select:none;
	-webkit-tap-highlight-color:transparent;
	box-shadow:0 4px 10px rgba(0,60,120,.14);
}
.rs_tile:not(.dead):active { transform:translateY(3px); box-shadow:0 1px 4px rgba(0,60,120,.14); }
.rs_tile.dragging { opacity:.35; }
.rs_tile.wrong { animation:shake .45s; }

/*
	A CHOICE THAT IS OUT OF PLAY TAKES NO INPUT AT ALL. Not "the callback
	returns early" — pointer-events:none, so there is no press state, no drag
	to start, no ghost, nothing to pick up and wave around. A three-year-old
	hammering a word that has just been refused should get no response from it
	whatsoever, and a locked tray should feel like a picture, not a toy that
	has stopped working.
*/
.rs_tile.dead { opacity:.35; cursor:default; pointer-events:none; }
.rs_tray.locked { pointer-events:none; }
/* off screen between questions, while the picture is being looked at */
.rs_tray.gone { opacity:0; transform:translateY(14px); pointer-events:none;
	transition:opacity .3s ease, transform .3s ease; }

/* a column of words, read top to bottom, each one a full-width target */
.rs_tray.list {
	flex-direction:column; flex-wrap:nowrap; align-items:stretch;
	gap:min(2.2vh,14px); margin-bottom:6%;
}
.rs_tray.list .rs_tile { width:100%; text-align:center; padding:min(2vh,15px) 18px; }

/* a game that picks rather than carries: a tap, so no grab cursor and none of
   the touch-action juggling a drag needs */
.rs_tray.tap .rs_tile { cursor:pointer; touch-action:manipulation; }

/* ---- a picture toured close up -------------------------------------- */
/*
	The picture is the BACKGROUND, full bleed, zoomed into one part of itself.
	Each part is behind a VEIL of its own — a solid pale sheet — and getting the
	word right lifts that part's veil, for good. The picture is therefore
	uncovered a section at a time and stays uncovered: by the last question most
	of it is showing, and the pull-back at the end is the whole thing clear.

	Why per-part veils and not one opacity over everything: fading the whole
	picture up on a right answer reveals every part at once, and then the next
	part starts revealed and fades DOWN — which is the opposite of uncovering
	something.

	THE VEILS ARE BLURRED AND OVERSIZED. A hard-edged rectangle makes the
	uncovered parts look like tiles cut out of a sheet; a blurred edge makes
	what has been won melt into what hasn't. Each veil is drawn bigger than its
	own part so that its solid middle still covers that part completely — two
	unsolved neighbours have no pale seam between them — while the soft edge
	spills into whatever is next to it. The softness around an uncovered part
	comes from ITS NEIGHBOURS' overhang, which is why the effect needs both the
	blur and the oversize.

	THE WORLD KEEPS THE PICTURE'S OWN SHAPE. It is as wide as the screen and 3:2
	as tall, so `background-size:100% 100%` lands the image on a box that has its
	aspect ratio and nothing is stretched. Sizing the world to the screen instead
	squashes a 2:3 picture into a phone's narrower box, and everything in it goes
	thin.
*/
.rs_scene { position:absolute; inset:0; z-index:1; overflow:hidden; }

.rs_world {
	position:absolute; left:0; top:0;
	width:100%; aspect-ratio:2 / 3;
	transform-origin:0 0;
	transition:transform .7s cubic-bezier(.35,.9,.3,1);
}
.rs_pic {
	position:absolute; inset:0;
	background-size:100% 100%; background-position:center;
}

.rs_veil {
	position:absolute;
	background:#eaf6ff;
	opacity:1;
	filter:blur(18px);
	transition:opacity .55s ease;
}
.rs_veil.lifted { opacity:0; }

/* the stage rides above the picture once there is a picture to ride above */
.rs_stage.pieces { z-index:2; }

/* ---- the reward ----------------------------------------------------- */
/*
	The picture arrives only once the round is won, and when it does it takes
	the whole phone. Nothing is on screen with it except the words and Next.
*/
.rs_prize {
	position:absolute; inset:0; z-index:3;
	background-size:cover; background-position:center;
	opacity:0; transform:scale(1.06); pointer-events:none;
	transition:opacity .5s ease, transform 4s ease-out;
}
.solved .rs_prize { opacity:1; transform:scale(1); pointer-events:auto; }
.solved .rs_tray { opacity:0; transform:translateY(24px); pointer-events:none;
	transition:opacity .4s, transform .4s; }
/* the words ride above the picture, still readable, still tappable */
.solved .rs_card { position:relative; z-index:4; background:rgba(255,255,255,.94); }
/* a pieces game keeps its grid as the picture, so the card sits above it in
   the normal flow rather than floating over a background */
.rs_stage.pieces .rs_card { z-index:1; background:#fff; }
/* and its tray gets out of the way completely when the picture is finished —
   fading it but leaving the box would squeeze the grown grid off the screen */
.solved .rs_stage.pieces .rs_tray {
	flex:0 0 0; height:0; min-height:0; margin:0; padding:0; overflow:hidden;
}

/* the only button in any of these games, and only once the picture is up */
.rs_next {
	position:absolute; left:0; right:0; z-index:5;
	bottom:calc(22px + env(safe-area-inset-bottom));
	display:flex; justify-content:center;
	opacity:0; pointer-events:none; transition:opacity .35s;
}
.solved .rs_next { opacity:1; pointer-events:auto; }
.rs_next button {
	font:inherit; font-size:calc(clamp(20px, 6vw, 26px) * var(--scale));
	font-weight:bold; color:#fff; background:#12b981;
	border:none; border-radius:999px; padding:14px 40px;
	box-shadow:0 6px 0 #0d8f64, 0 10px 24px rgba(0,40,90,.3);
	cursor:pointer; -webkit-tap-highlight-color:transparent;
}
.rs_next button:active { transform:translateY(4px); box-shadow:0 2px 0 #0d8f64; }

.rs_empty {
	position:absolute; inset:0; margin:auto;
	display:flex; align-items:center; justify-content:center; text-align:center;
	font-size:16px; color:#4a6785; padding:0 10%;
}
