/* ========================================
   The pupils' login and home (pupil/index.html, app.js)
   The tokens and the shared parts (buttons, panels, the scene, bubbles, the sky world) come from
   shared/css/classlings-pupil.css; this is the two screens' own layout. Side by side on a
   Chromebook, one thing under another on a phone.
   ======================================== */

body { margin: 0; background: #ffffff; }
.pupil-shell { display: flex; flex-direction: column; }
/* Where the clouds float on each screen, in the sky world. */
.pupil-shell[data-screen="login"], .pupil-shell[data-screen="reconnect"] { --cloud-a: left 120px top 34px; --cloud-b: left 1110px top 58px; }
.pupil-shell[data-screen="home"] { --cloud-a: left 1060px top 92px; --cloud-b: left 900px top 26px; }

/* ---------------------------------------------------------------- the bar along the top */

.topbar { display: flex; align-items: center; gap: var(--s-4); padding: var(--s-2) var(--gutter) 0; }
.topbar .end { margin-left: auto; display: flex; align-items: center; gap: var(--s-4); }
.pupil-shell[data-screen="login"] .topbar { justify-content: center; }
.pupil-shell[data-screen="login"] .topbar .end { display: none; }

.pupil-screen { display: none; flex: 1; }
.pupil-screen.active { display: block; }

/* ---------------------------------------------------------------- signing in */

.login.active { display: grid; align-content: center; }
.login .steps {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-6);
    padding: 0 var(--gutter) var(--ground);
}
.step { position: relative; display: grid; align-content: start; gap: var(--s-4); padding: var(--s-6); border-radius: var(--r-xl); }
.step.one { gap: var(--s-5); }
/* Step 2 waits, faded, until the code works. Then it's the step they're on, in the mock-up's
   highlight: a light blue fill and a blue edge, on white and in the sky. */
.step.two { transition: opacity 0.2s ease-out, background-color 0.2s ease-out, box-shadow 0.2s ease-out; }
.step.two:not(.active) { opacity: 0.5; }
.step.two:not(.active) :is(.answers, .who) { visibility: hidden; }
.pupil-shell .step.two.active { background: var(--sky-tint); box-shadow: inset 0 0 0 var(--edge) var(--sky-deep); }
.head { display: flex; align-items: center; gap: var(--s-3); }
.head h1, .head h2 { font: 700 var(--t-l) / 1.05 var(--display); }
.n { flex: none; display: grid; place-items: center; width: 48px; height: 48px; font: 700 var(--t-s) / 1 var(--display); background: var(--page); border-radius: 50%; box-shadow: inset 0 0 0 var(--edge) var(--ink); }
.code-form { display: grid; gap: var(--s-4); }
.code-form label { font: 600 var(--t-ui) / 1.2 var(--display); }

/* The code: a box for each character, drawn over the real text box, so typing works as it always has. */
.code { position: relative; display: block; cursor: text; }
.code input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; border: 0; font-size: 40px; cursor: text; }
.boxes { display: flex; align-items: center; justify-content: center; gap: var(--s-2); }
.box {
    display: grid;
    place-items: center;
    width: 52px;
    height: 72px;
    margin: var(--px) var(--px) calc(var(--px) * 2);
    font: 700 44px / 1 var(--body);
    letter-spacing: 0;
    color: var(--ink);
    background: var(--page);
    box-shadow: inset 0 calc(var(--px) * -1) 0 var(--wash-2), var(--ring), 0 calc(var(--px) * 2) 0 var(--line-soft);
}
.code:focus-within .box.is-next { box-shadow: inset 0 calc(var(--px) * -2) 0 var(--sky), var(--ring), 0 calc(var(--px) * 2) 0 var(--line-soft); }
.dash { flex: none; width: 16px; height: var(--px); margin: 0 var(--s-1); background: var(--ink); }
.code:focus-within { outline: 4px solid var(--sky); outline-offset: 6px; border-radius: var(--r-s); }
.code.shake { animation: code-shake 0.4s; }
@keyframes code-shake {
    20%, 60% { transform: translateX(-4px); }
    40%, 80% { transform: translateX(4px); }
}
.done { display: inline-flex; align-items: center; gap: var(--s-2); font: 600 var(--t-ui) / 1.2 var(--display); }
/* "Checking..." stands where "That code works." will: the line is the same height, so nothing moves when the answer comes. */
.done.is-checking { color: var(--ink-2); }
.pupil-shell[data-world="sky"] .done.is-checking { color: var(--ink); }
.done .cla-ic { width: 24px; height: 24px; padding: 4px; color: var(--ink); background: var(--lime); border-radius: 50%; box-sizing: content-box; }
.hint { font-size: var(--t-body); line-height: 1.5; color: var(--ink-2); }
/* "Try again" under a code check that got no answer: kept clear of the foot of a short window. */
.retry-code { justify-self: start; scroll-margin-bottom: var(--s-4); }
.step .notice { scroll-margin-bottom: var(--s-4); }
.pupil-shell[data-world="sky"] .hint { color: var(--ink); }
/* The privacy notice, small and quiet under "No card? Ask your teacher." (its "For pupils" box is written for them). */
.privacy-link { margin-top: calc(var(--s-3) * -1); font: 600 var(--t-small) / 1.3 var(--display); }
.privacy-link a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; }
.pupil-shell[data-world="sky"] .privacy-link a { color: var(--ink); }

.you { display: grid; grid-template-columns: 216px 1fr; align-items: center; gap: var(--s-5); }
.you .stage { --scene-ground: 40px; --scene-cloud: left 14px top 18px; --scene-puff: right -24px top 64px; height: 216px; border-radius: var(--r-l); }
.you .stage canvas { height: 150px; }
/* Today's champion ball, for a class without Classlings: no scene, just the ball.
   Classlings are always on: remove with the always-on change */
.you .stage.is-ball { background: var(--page); }
.you .stage.is-ball::after { display: none; }
.you .stage.is-ball canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.you .who b { display: block; font: 700 var(--t-m) / 1.1 var(--display); overflow-wrap: anywhere; }
.you .who span { font: 600 var(--t-ui) / 1.3 var(--display); }
/* The two answers share a row while they fit; a narrower panel puts one under the other, each the panel's full width. Their
   words stay on one line (the page never scrolls sideways). */
.answers { display: flex; flex-wrap: wrap; gap: var(--s-4); padding-top: var(--s-2); }
.answers > .btn { flex: 1 1 auto; }

/* The playful layer: Kit peeks over the first step, their Classling says hello, a twinkle for a
   code that works, and two trees on the grass. */
.step.one .peeker { right: 172px; }
.you .stage .bubble { left: 34px; top: 10px; --tail-at: 40px; }
.login .t1 { left: 64px; }
.login .t2 { right: 88px; }

/* ---------------------------------------------------------------- the saved sign-in can't reach the server */

.reconnect.active { display: grid; place-content: center; padding: var(--s-6) var(--gutter) var(--ground); }
.reconnect .step { width: min(100%, 560px); }
.reconnect h1 { font: 700 var(--t-l) / 1.05 var(--display); }

/* ---------------------------------------------------------------- home */

.home.active {
    display: grid;
    grid-template-columns: 480px minmax(0, 1fr);
    grid-template-rows: auto auto auto 1fr;
    grid-template-areas: "hello hello" "scene progress" "scene notices" "scene apps";
    column-gap: var(--s-6);
    padding: 0 var(--gutter) var(--ground);
}
/* On a laptop or a board (1024 px and wider) the home is laid out further down, in "home on a laptop and on a board". */
/* In the sky the ground already ends the page, so the home needs little room of its own below it. */
@media (min-width: 601px) {
    .pupil-shell[data-world="sky"] .home.active { padding-bottom: var(--h-sky-pad, var(--s-4)); }
}
/* Without Classlings, the home is the places to go.
   Classlings are always on: remove with the always-on change */
.home.active:not(.has-classling) { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto; grid-template-areas: "hello" "notices" "apps"; align-content: start; }
.home.active:not(.has-classling) .apps { align-self: start; }

.hello { grid-area: hello; display: flex; align-items: center; gap: var(--s-5); padding: var(--s-2) 0 var(--s-4); min-width: 0; }
.hello h1 { --title-scale: 5; }

/* Their Classling, standing on the grass. */
.home .stage { --scene-ground: 72px; --scene-cloud: left 30px top 36px; --scene-puff: right 36px top 112px; grid-area: scene; min-height: 360px; border-radius: var(--r-xl); }
.home .stage canvas { height: 300px; }
.home .stage .bubble { left: calc(50% - 4px); bottom: calc(var(--scene-ground) + 196px); }
/* Their Classling says its line now and then (app.js homeSays), then the bubble goes (the teacher, 10 October). */
#homeBubble { opacity: 0; visibility: hidden; transition: opacity 0.2s ease-out, visibility 0s linear 0.2s; }
#homeBubble.is-saying { opacity: 1; visibility: visible; transition: opacity 0.15s ease-out; }
.home .stage .s1 { left: 112px; bottom: calc(var(--scene-ground) + 110px); }
.home .stage .s2 { left: calc(50% + 116px); bottom: calc(var(--scene-ground) + 118px); }
.home .stage .s3 { left: calc(50% + 144px); bottom: calc(var(--scene-ground) + 20px); }

/* Their progress. */
.progress { grid-area: progress; position: relative; display: grid; gap: var(--s-5); padding: var(--s-5) var(--s-5) var(--s-6); }
.lvl { display: grid; grid-template-columns: 104px minmax(0, 1fr) 84px; align-items: center; gap: var(--s-4); }
.lvl p { font: 600 var(--t-s) / 1.15 var(--display); padding-bottom: var(--s-2); text-wrap: balance; }
/* Three steps to the box, as a game's bar. */
.meter { position: relative; height: 22px; background: var(--page); box-shadow: var(--ring); overflow: hidden; }
.meter i { display: block; width: calc(var(--filled, 0) * 100%); height: 100%; background: var(--sky); }
.meter::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        linear-gradient(var(--ink), var(--ink)) calc(100% / 3) 0 / var(--px) 100% no-repeat,
        linear-gradient(var(--ink), var(--ink)) calc(200% / 3) 0 / var(--px) 100% no-repeat;
}
.lvl .boxart { width: 84px; height: 72px; }
/* Ten steps to a rare box (once every Classling is found): one bar, no thirds. */
.meter.is-rare::after { display: none; }
/* A box waiting: what it is, and a big gold button to open it where the box was. */
.lvl.has-box { grid-template-columns: 104px minmax(0, 1fr) auto; }
.lvl .open-box { margin-bottom: var(--lift); }
.stats { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-5); padding-top: var(--s-5); border-top: var(--edge) solid var(--sky); }
/* How many they've found, with the next box's promise across from it, then the row of them. */
.stat { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "count note" "found found"; align-items: baseline; gap: var(--s-3) var(--s-4); }
.stat .count { grid-area: count; display: flex; align-items: baseline; gap: var(--s-2); font: 600 var(--t-ui) / 1.2 var(--display); }
.stat .count b { font: 700 var(--t-l) / 1 var(--display); }
.stat .found { grid-area: found; }
.stat .small { grid-area: note; justify-self: end; text-align: right; text-wrap: balance; font-size: var(--t-small); color: var(--ink-2); }
/* The Classlings found fill a row as wide as the panel: theirs, then faint shapes of ones still to
   find, and "+12" in the last place when there are more than fit (app.js renderFound sets --per). */
.found { display: grid; grid-template-columns: repeat(var(--per, 9), minmax(0, 1fr)); gap: var(--s-2); }
.found canvas { width: 100%; height: auto; aspect-ratio: 1; }
.found .more { display: grid; place-items: center; aspect-ratio: 1; font: 700 var(--t-ui) / 1 var(--display); color: var(--ink-2); background: var(--page); border-radius: var(--r-s); box-shadow: inset 0 0 0 2px var(--wash-2); }
.progress .peeker { right: var(--h-peek-right, 44px); }

/* Something to read: a maths reward. */
.notices { grid-area: notices; display: grid; gap: var(--s-3); padding-top: var(--s-4); }
.notices:empty { display: none; }
.notice.is-reward { justify-content: space-between; gap: var(--s-3); background: var(--gold-tint); border-color: var(--gold-deep); }
.notice.is-reward span { flex: 1; }
.notice.is-reward .btn { margin: 0; }

/* Where to go: three tiles, each with its Classling peeking over. */
.apps { grid-area: apps; align-self: end; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-4); padding-top: 52px; }
.apps .slot { position: relative; display: grid; }
.apps .peeker { right: var(--s-4); }
.tile { display: flex; flex-direction: column; gap: var(--s-1); min-height: 128px; padding: var(--s-3) var(--s-4) var(--s-2); border-radius: var(--r-l); }
.tile h2 { font: 700 var(--t-label) / 1.1 var(--display); }
.tile p { font-size: var(--t-small); line-height: 1.35; }
.tile .do { margin-top: auto; display: flex; align-items: center; justify-content: space-between; min-height: 44px; padding-top: var(--s-1); font: 600 var(--t-ui) / 1 var(--display); border-top: var(--edge) solid var(--app-deep); }
.tile .do .cla-ic { width: 26px; height: 26px; }
/* Reading is coming soon: dashed and flat, as on the teacher's Home, and it doesn't press. */
.tile.is-soon, .home .tile.is-soon { background: var(--app-tint); border-style: dashed; box-shadow: none; cursor: default; }
.cla-pupil .tile.is-soon:active { transform: none; }

/* Four places, for a class trying Try new things (app.js sets data-count). On a laptop or a board the four share
   the row three have, so their words come down a step and they stand a little closer (on a laptop narrower than
   the school's 1366, their names another step). Narrower still, they go two by two, with room between the rows for
   the Classlings peeking over; on a phone they're one under another, as ever. */
@media (min-width: 1200px) {
    .apps[data-count="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: var(--s-3); }
    .apps[data-count="4"] .tile { padding-left: var(--s-3); padding-right: var(--s-3); }
    .apps[data-count="4"] .tile h2 { font-size: var(--t-ui); }
    .apps[data-count="4"] .tile p { font-size: calc(var(--t-small) - 1px); line-height: 1.25; }
    .apps[data-count="4"] .tile .do { font-size: var(--t-ui-s); }
    .apps[data-count="4"] .peeker { right: var(--s-3); }
}
@media (min-width: 1200px) and (max-width: 1365px) {
    .apps[data-count="4"] .tile h2 { font-size: var(--t-ui-s); }
}
@media (min-width: 601px) and (max-width: 1199px) {
    .apps[data-count="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--h-room, 56px); }
}
/* Beside the scene (a small laptop), the scene comes down beside their first row and the badges tile stands
   beside the second, so there's no gap under the scene. */
@media (min-width: 1024px) and (max-width: 1199px) {
    .home.active.has-badges:has(> .apps[data-count="4"]) {
        grid-template-rows: auto minmax(0, 1fr) auto auto auto;
        grid-template-areas: "hello hello" "scene progress" "scene notices" "scene apps" "badges apps";
    }
}

/* ---------------------------------------------------------------- the badges tile
   Once they have a badge, their home gets a tile of its own: their newest few pictures and how many, with the
   newest peeking over its top as a Classling peeks over each place's. It wears teal. On a Chromebook it stands
   under the scene (and the scene is a little shorter to make room), across from the three places. Everywhere
   else it comes after the progress panel and before My Classling, with the other tiles. With no badge it isn't there. */

.bslot { --room: 52px; grid-area: badges; position: relative; display: grid; align-self: end; padding-top: var(--room); }
.bslot .badge-peek { top: calc(var(--room) - 44px); right: var(--s-5); width: 60px; height: 60px; }
/* A button wearing a tile's look: .bslot .btile outranks the shared .cla-pupil .tile, which is a grid. */
.bslot .btile { display: flex; flex-direction: row; align-items: center; appearance: none; margin: 0 0 8px; font: inherit; text-align: left; gap: var(--s-4); padding: var(--s-3) var(--s-5); }
.btile .t-words { display: grid; gap: var(--s-2); min-width: 0; }
.btile .t-name { font: 700 var(--t-label) / 1.1 var(--display); }
.btile .row { display: flex; gap: var(--s-3); }
.btile .do { margin: 0 0 0 auto; padding: 0; border: 0; gap: var(--s-3); }
.btile .cnt { display: flex; align-items: center; gap: var(--s-2); }
.tile .do .pi { width: 24px; height: 24px; }

/* The pictures are SVG, drawn a whole number of screen pixels to a pixel of art: 2 is 40 px, 3 is 60 and 4 is 80. */
.bdg { display: block; flex: none; width: calc(var(--bs, 4) * 20px); height: calc(var(--bs, 4) * 20px); }
.bs2 { --bs: 2; }
.bs3 { --bs: 3; }
.bs4 { --bs: 4; }

/* "New" on what was given in the last week. */
.badge-new { padding: 1px 8px 2px; font: 700 var(--t-small) / 1.2 var(--display); color: var(--ink); white-space: nowrap; background: var(--grape); border: 2px solid var(--grape-deep); border-radius: var(--r-s); }

/* ---------------------------------------------------------------- the badges sheet
   Tapping the tile opens their badges this year, newest first, over the page: each with its picture, name and day. */

html.sheet-open { overflow: hidden; }
.sheet {
    width: min(760px, calc(100% - 2 * var(--gutter)));
    max-width: none;
    max-height: calc(100vh - 2 * var(--gutter));
    max-height: calc(100dvh - 2 * var(--gutter));
    margin: auto;
    padding: 0;
    overflow: hidden;
    color: var(--ink);
    background: var(--page);
    border: var(--edge) solid var(--app-deep);
    border-radius: var(--r-xl);
}
.sheet[open] { display: flex; flex-direction: column; }
.sheet::backdrop { background: rgba(30, 27, 58, 0.42); }
.sheet-top { flex: none; display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-4); padding: var(--s-5) var(--s-5) var(--s-4); background: var(--app-tint); border-bottom: var(--edge) solid var(--app-deep); }
.sheet-head { flex: 1 1 0; min-width: 0; display: grid; gap: var(--s-3); }
.sheet-lead { font: 600 var(--t-ui) / 1.2 var(--display); }
/* .sheet .badge-list outranks the shared reset of lists' padding. */
.sheet .badge-list { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-content: start; gap: var(--s-4); margin: 0; padding: var(--s-5); overflow-y: auto; overscroll-behavior: contain; }
.badge-row { display: flex; align-items: center; gap: var(--s-4); min-width: 0; padding: var(--s-3) var(--s-4); background: var(--page); border: var(--edge) solid var(--wash-2); border-radius: var(--r-l); }
.badge-words { display: grid; gap: var(--s-1); min-width: 0; }
.badge-name { font: 700 var(--t-label) / 1.15 var(--display); overflow-wrap: anywhere; }
.badge-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); font: 600 var(--t-body) / 1.2 var(--display); color: var(--ink-2); }
@media (prefers-reduced-motion: no-preference) {
    .sheet[open] { animation: sheet-in 160ms ease-out; }
    @keyframes sheet-in { from { opacity: 0; transform: translateY(8px); } }
}

/* ---------------------------------------------------------------- loading */

.loading { position: fixed; inset: 0; z-index: 20; display: grid; place-items: center; background: rgba(255, 255, 255, 0.7); }
.pupil-shell[data-world="sky"] .loading { background: rgba(124, 198, 242, 0.6); }

/* ---------------------------------------------------------------- home on a laptop and on a board (1024 px and wider)
   One screen, no scrolling: the teacher's school laptop is 1366 x 768, and in a browser the page gets about
   1366 x 540 to 600 of it. So as the window gets shorter the home gives up room in this order, and nothing goes:
   spacing, the window's height (the scene is as tall as the level panel beside it), the "Hi" lettering a step,
   the level panel's padding, the places' height, the Classlings found a step smaller.
   Whatever height is left over goes to the scene and the level panel, which stay level with each other.
   A big board (1920 x 1080) gets the laptop layout drawn bigger, with every piece of pixel art a whole number
   of screen pixels to an art pixel. The sizes below are --h-* values on the shell; each tier changes some.
   Each tier is no taller, with nothing handed out, than the shortest window it covers: about 530 px for the
   tightest (540 and up), 590 (596), 670 (676) and 758 (760); tests/smoke checks 540, 600 and 768. */
@media (min-width: 1024px) {
    .pupil-shell[data-screen="home"] .topbar { padding-top: var(--h-top, var(--s-2)); }
    .pupil-shell[data-screen="home"] .topbar .btn {
        min-height: var(--h-btn, var(--tap));
        padding: 0 var(--h-btn-pad, var(--s-5));
        font-size: var(--h-btn-font, var(--t-ui));
        border-radius: var(--h-btn-r, var(--r-m));
        --lift: var(--h-lift, 6px);
    }

    .home.active {
        grid-template-columns: var(--h-col, clamp(480px, 30vw, 640px)) minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr) auto auto;
        column-gap: var(--h-gap, var(--s-6));
    }
    /* With a badge, the badges tile stands under the scene, across from the three places. */
    .home.active.has-badges { grid-template-areas: "hello hello" "scene progress" "scene notices" "badges apps"; }
    .hello { padding: var(--h-hello, var(--s-2) 0 var(--s-4)); }

    /* The scene is as tall as the level panel (and any notice) beside it; the Classling stands on the grass at
       a whole number of screen pixels per art pixel (--h-s of them, drawn by app.js), and the speech bubble and
       sparkles keep their places round the Classling whatever the scene's height. */
    .home .stage {
        --scene-ground: var(--h-ground, 72px);
        --scene-cloud: var(--h-cloud, left 30px top 36px);
        --scene-puff: var(--h-puff, right 36px top 112px);
        min-height: 0;
    }
    .home.active:not(.has-badges) { --h-s: var(--h-s-alone, 11); }
    .home .stage canvas { height: calc(var(--h-s, 9) * 27px); }
    .home .stage .bubble { bottom: calc(var(--scene-ground) + var(--h-s, 9) * 17px + 23px); }
    .home .stage .s1 { left: calc(var(--h-s, 9) * 10.7px); bottom: calc(var(--scene-ground) + var(--h-s, 9) * 17.5px); }
    .home .stage .s2 { left: calc(50% + var(--h-s, 9) * 13.3px); bottom: calc(var(--scene-ground) + var(--h-s, 9) * 13.5px); }
    .home .stage .s3 { left: calc(50% + var(--h-s, 9) * 17.8px); bottom: calc(var(--scene-ground) + var(--h-s, 9) * 7.3px); }

    .progress { align-content: space-evenly; gap: var(--h-pg-gap, var(--s-5)); padding: var(--h-pg-pad, var(--s-5) var(--s-5) var(--s-6)); }
    .lvl { grid-template-columns: var(--h-cookie, 104px) minmax(0, 1fr) var(--h-boxw, 84px); }
    .lvl.has-box { grid-template-columns: var(--h-cookie, 104px) minmax(0, 1fr) auto; }
    .lvl .cookie { width: var(--h-cookie, 104px); height: var(--h-cookie, 104px); }
    .lvl .cookie b { font-size: var(--h-cookie-n, var(--t-l)); }
    .meter { height: var(--h-meter, 22px); }
    .lvl .boxart { width: var(--h-boxw, 84px); height: var(--h-boxh, 72px); }
    .stats { gap: var(--h-pg-gap, var(--s-5)); padding-top: var(--h-pg-gap, var(--s-5)); }
    .stat .count b { font-size: var(--h-count, var(--t-l)); }
    .found { gap: var(--found-gap, var(--s-2)); }

    /* The places: each Classling peeks over its tile; --h-room is the room for that above them. */
    .apps { padding-top: var(--h-room, 52px); }
    .bslot { --room: var(--h-room, 52px); }
    .apps .peeker, .progress .peeker { top: calc(4px - var(--h-room, 52px)); width: var(--h-peek, 56px); height: var(--h-peek, 56px); }
    .tile { min-height: var(--h-tile, 128px); gap: var(--h-tile-gap, var(--s-1)); padding: var(--h-tile-pad, var(--s-3) var(--s-4) var(--s-2)); }
    .tile .do { min-height: var(--h-do, 44px); }
    .bslot .btile { padding: var(--h-btile-pad, var(--s-3) var(--s-5)); }
}

/* A window under the height of a full-screen laptop (760): spacing first. */
@media (min-width: 1024px) and (max-height: 759px) {
    .pupil-shell[data-screen="home"] {
        --ground: 32px;
        --soil-h: 12px;
        --h-top: 4px;
        --h-hello: 4px 0 12px;
        --h-sky-pad: 8px;
        --h-ground: 56px;
        --h-s: 8;
        --h-s-alone: 11;
        --h-cloud: left 28px top 24px;
        --h-puff: right 32px top 72px;
        --h-pg-pad: 20px 24px 24px;
        --h-pg-gap: 20px;
        --h-cookie: 96px;
        --h-cookie-n: 40px;
        --h-boxw: 80px;
        --h-boxh: 56px;
        --h-count: 40px;
        --h-room: 48px;
        --h-tile: 116px;
        --h-tile-pad: 8px 16px 6px;
        --h-do: 40px;
        --h-btile-pad: 8px 24px;
    }
}
@media (min-width: 1024px) and (max-height: 675px) {
    .pupil-shell[data-screen="home"] {
        --ground: 24px;
        --soil-h: 8px;
        --h-top: 4px;
        --h-btn: 48px;
        --h-btn-font: 18px;
        --h-btn-pad: 20px;
        --h-btn-r: 14px;
        --h-lift: 4px;
        --h-hello: 2px 0 8px;
        --h-ground: 44px;
        --h-s: 7;
        --h-s-alone: 10;
        --h-pg-pad: 14px 20px 16px;
        --h-pg-gap: 12px;
        --h-cookie: 84px;
        --h-cookie-n: 34px;
        --h-boxw: 72px;
        --h-boxh: 50px;
        --h-meter: 20px;
        --h-count: 34px;
        --found-gap: 6px;
        --h-room: 44px;
        --h-tile: 100px;
        --h-tile-gap: 2px;
        --h-tile-pad: 6px 16px 4px;
        --h-do: 32px;
        --h-btile-pad: 6px 20px;
    }
}

/* Signing in on a short laptop window (the school laptop gives about 540 to 600 of page): a little less room in the
   panels and a shorter strip of ground, so both steps fit with nothing to scroll from 540 up (the teacher's test page,
   10 October, scrolled by two pixels). Step 2 keeps the room for its answers, so nothing moves when they appear. */
@media (min-width: 1024px) and (max-height: 595px) {
    .pupil-shell[data-screen="login"] { --ground: 24px; }
    .login .step { padding: var(--s-5) var(--s-6); gap: var(--s-3); }
    .login .step.one { gap: var(--s-4); }
}

@media (min-width: 1024px) and (max-height: 595px) {
    .pupil-shell[data-screen="home"] {
        --ground: 20px;
        --soil-h: 8px;
        --h-top: 2px;
        --h-btn: 48px;
        --h-btn-font: 18px;
        --h-btn-pad: 20px;
        --h-btn-r: 14px;
        --h-lift: 4px;
        --h-title-cap: 4;
        --h-hello: 2px 0 6px;
        --h-sky-pad: 4px;
        --h-ground: 40px;
        --h-s: 6;
        --h-s-alone: 9;
        --h-cloud: left 28px top 16px;
        --h-puff: right 32px top 56px;
        --h-pg-pad: 12px 20px 12px;
        --h-pg-gap: 10px;
        --h-cookie: 76px;
        --h-cookie-n: 30px;
        --h-boxw: 68px;
        --h-boxh: 48px;
        --h-meter: 18px;
        --h-count: 30px;
        --h-found-big: 48px;
        --h-found-small: 40px;
        --found-gap: 6px;
        --h-room: 44px;
        --h-tile: 96px;
        --h-tile-gap: 2px;
        --h-tile-pad: 4px 16px 4px;
        --h-do: 32px;
        --h-btile-pad: 4px 20px;
    }
}

/* A taller window on a wide screen (a big board's browser, 1920 x 950 or so): the laptop layout drawn 1.2 times as big. */
@media (min-width: 1500px) and (min-height: 912px) and (max-height: 1061px) {
    .pupil-shell[data-screen="home"] {
        --gutter: 38px;
        --ground: 56px;
        --soil-h: 20px;
        --px: 5px;
        --ring: 0 calc(var(--px) * -1) 0 var(--ink), 0 var(--px) 0 var(--ink),
            calc(var(--px) * -1) 0 0 var(--ink), var(--px) 0 0 var(--ink);
        --cloud-a: left 1280px top 108px;
        --cloud-b: left 1080px top 30px;
        --h-top: 10px;
        --h-btn: 66px;
        --h-btn-pad: 29px;
        --h-btn-font: 24px;
        --h-btn-r: 24px;
        --h-lift: 7px;
        --h-col: clamp(576px, 30vw, 640px);
        --h-gap: 38px;
        --h-hello: 10px 0 17px;
        --h-title-cap: 6;
        --h-s: 11;
        --h-s-alone: 13;
        --h-ground: 88px;
        --h-cloud: left 36px top 43px;
        --h-puff: right 43px top 134px;
        --h-cookie: 125px;
        --h-meter: 26px;
        --h-found-big: 72px;
        --h-found-small: 60px;
        --found-gap: 10px;
        --h-room: 56px;
        --h-peek-right: 53px;
        --h-tile: 154px;
        --h-do: 53px;
    }
    .home.active {
        --s-1: 5px; --s-2: 10px; --s-3: 14px; --s-4: 19px; --s-5: 29px; --s-6: 38px; --s-7: 58px; --s-8: 77px;
        --t-l: 58px; --t-m: 43px; --t-s: 34px; --t-label: 29px; --t-ui: 24px; --t-body: 22px; --t-ui-s: 22px; --t-small: 19px; --t-tag: 17px;
        --r-s: 17px; --r-m: 24px; --r-l: 34px; --r-xl: 53px;
        --edge: 4px;
    }
    .home .tile { margin-bottom: 10px; box-shadow: 0 10px 0 var(--app-deep); --ring-lift: 10px; }
    .home .tile:active { transform: translateY(10px); }
    .bslot .btile { margin-bottom: 10px; }
    .tile .do .cla-ic { width: 31px; height: 31px; }
}

/* A big board (1920 x 1080): the laptop layout drawn about 1.4 times as big. The spacing, type and shapes are the
   page's tokens at that size, and every piece of pixel art keeps a whole number of screen pixels to an art pixel
   (the lettering 7, the logo 3, the Classling in the scene 13 or 15, the ones found 4, the box 4, the places 4). */
@media (min-width: 1700px) and (min-height: 1062px) {
    .pupil-shell[data-screen="home"] {
        --gutter: 44px;
        --logo-s: 3px;
        --ground: 64px;
        --soil-h: 24px;
        --px: 6px;
        --ring: 0 calc(var(--px) * -1) 0 var(--ink), 0 var(--px) 0 var(--ink),
            calc(var(--px) * -1) 0 0 var(--ink), var(--px) 0 0 var(--ink);
        --cloud-a: left 1480px top 128px;
        --cloud-b: left 1250px top 36px;
        --h-top: 12px;
        --h-btn: 78px;
        --h-btn-pad: 34px;
        --h-btn-font: 28px;
        --h-btn-r: 28px;
        --h-lift: 8px;
        --h-col: clamp(640px, 35vw, 760px);
        --h-gap: 45px;
        --h-hello: 11px 0 18px;
        --h-title-cap: 7;
        --h-s: 13;
        --h-s-alone: 15;
        --h-ground: 100px;
        --h-cloud: left 42px top 50px;
        --h-puff: right 50px top 156px;
        --h-cookie: 146px;
        --h-boxw: 100px;
        --h-boxh: 84px;
        --h-meter: 31px;
        --h-found-big: 84px;
        --h-found-small: 68px;
        --found-gap: 11px;
        --h-room: 68px;
        --h-peek: 72px;
        --h-peek-right: 62px;
        --h-tile: 176px;
        --h-do: 62px;
    }
    .home.active {
        --s-1: 6px; --s-2: 11px; --s-3: 17px; --s-4: 22px; --s-5: 34px; --s-6: 45px; --s-7: 67px; --s-8: 90px;
        --t-l: 67px; --t-m: 50px; --t-s: 39px; --t-label: 34px; --t-ui: 28px; --t-body: 25px; --t-ui-s: 25px; --t-small: 22px; --t-tag: 20px;
        --r-s: 20px; --r-m: 28px; --r-l: 39px; --r-xl: 62px;
        --edge: 4px;
    }
    .home .tile { margin-bottom: 11px; box-shadow: 0 11px 0 var(--app-deep); --ring-lift: 11px; }
    .home .tile:active { transform: translateY(11px); }
    .bslot .btile { margin-bottom: 11px; }
    .tile .do .cla-ic { width: 36px; height: 36px; }
    .tile .do .pi { width: 32px; height: 32px; }
    .bslot .badge-peek { top: calc(var(--room) - 62px); width: 84px; height: 84px; }
    .bslot .badge-peek .bdg { --bs: 4; }
    .btile .row .bdg { --bs: 3; }
}

/* ---------------------------------------------------------------- narrower screens */

@media (max-width: 1199px) {
    .box { width: 40px; height: 60px; font-size: 34px; }
    .you { grid-template-columns: 170px 1fr; }
    .you .stage { height: 170px; }
    .you .stage canvas { height: 120px; }
    .step.one .peeker { right: 100px; }
    .home.active { grid-template-columns: 400px minmax(0, 1fr); }
    .apps { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
    .tile h2 { font-size: 22px; }
}

@media (max-width: 1023px) {
    .login .steps { grid-template-columns: minmax(0, 1fr); max-width: 680px; margin: 0 auto; width: 100%; }
    .login.active { align-content: start; }
    .step.two:not(.active) { display: none; }
    .box { width: 52px; height: 72px; font-size: 44px; }
    .home.active { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto auto 1fr; grid-template-areas: "hello" "scene" "progress" "notices" "apps"; }
    .home .stage { min-height: 0; height: 300px; }
    .home .stage canvas { height: 230px; }
    .home .stage .bubble { bottom: calc(var(--scene-ground) + 160px); }
    .home .stage .s1 { bottom: calc(var(--scene-ground) + 90px); }
    .home .stage .s2 { bottom: calc(var(--scene-ground) + 100px); }
    .progress { margin-top: var(--s-5); }
    .apps { align-self: start; padding-top: 56px; }
    /* With a badge: the tile comes after the progress panel, before My Classling, with the other tiles. */
    .home.active.has-badges { grid-template-rows: auto auto auto auto auto 1fr; grid-template-areas: "hello" "scene" "progress" "notices" "badges" "apps"; }
    .bslot { --room: 56px; align-self: start; }
}

@media (max-width: 600px) {
    /* In the sky, the mock-up's two puffs either side of the logo, rather than a cloud under it, and
       on the home a cloud in the gap under the progress panel. */
    .pupil-shell[data-screen="login"], .pupil-shell[data-screen="reconnect"] { --cloud-a: left -400px top 0; --cloud-b: left 14px top 34px; --cloud-c: left 300px top 22px; }
    .pupil-shell[data-screen="home"] { --cloud-a: left 40px top 702px; }
    .topbar { padding: var(--s-2) var(--gutter) 0; }
    .topbar .btn { min-height: 48px; padding: 0 var(--s-4); font-size: var(--t-ui-s); --lift: 4px; border-radius: var(--r-s); }
    .login .steps { gap: var(--s-4); padding: var(--s-3) var(--gutter) var(--s-6); }
    .step { padding: var(--s-5) var(--s-4); gap: var(--s-3); }
    .head { flex-wrap: wrap; row-gap: var(--s-2); }
    .head h1, .head h2 { font-size: var(--t-m); }
    .n { width: 40px; height: 40px; font-size: var(--t-label); }
    .boxes { gap: 3px; }
    .box { width: 30px; height: 48px; margin: var(--px) 2px calc(var(--px) * 2); font-size: 28px; }
    .dash { width: 8px; margin: 0 2px; }
    .you { grid-template-columns: 120px 1fr; gap: var(--s-4); }
    .you .stage { --scene-ground: 28px; --scene-cloud: left -60px top 10px; --scene-puff: right -40px top 30px; height: 120px; border-radius: var(--r-m); }
    .you .stage canvas { height: 84px; }
    .you .who b { font-size: var(--t-s); }
    .answers { gap: var(--s-2); }
    .answers .btn.is-huge { min-height: 76px; font-size: var(--t-s); }
    .you .stage .bubble { display: none; }
    .step.one .peeker { right: 32px; }
    .reconnect.active { padding: var(--s-4) var(--gutter) var(--s-6); }

    .home.active { padding: 0 var(--gutter) var(--s-6); }
    .hello { padding: var(--s-1) 0 var(--s-3); gap: var(--s-3); }
    .hello h1 { --title-scale: 3; }
    .home .stage { --scene-ground: 44px; --scene-cloud: left 16px top 20px; --scene-puff: right 20px top 64px; height: 220px; }
    .home .stage canvas { height: 168px; }
    .home .stage .bubble { left: auto; right: var(--s-4); bottom: auto; top: 12px; }
    .home .stage .s1 { left: 92px; bottom: calc(var(--scene-ground) + 60px); }
    .home .stage .s2 { left: calc(50% + 70px); bottom: calc(var(--scene-ground) + 68px); }
    .home .stage .s3 { left: calc(50% + 100px); bottom: calc(var(--scene-ground) + 16px); }
    .progress { margin-top: var(--s-4); padding: var(--s-4); gap: var(--s-3); }
    .lvl, .lvl.has-box { grid-template-columns: 84px minmax(0, 1fr); gap: var(--s-3); }
    .lvl p { font-size: 20px; }
    .lvl .boxart { display: none; }
    /* The button to open a box waiting takes the panel's width, under the level. */
    .lvl .open-box { grid-column: 1 / -1; width: 100%; min-height: var(--tap-l); font-size: var(--t-s); }
    .stats { gap: var(--s-4); padding-top: var(--s-3); }
    .stat { grid-template-columns: minmax(0, 1fr); grid-template-areas: "count" "found" "note"; }
    .stat .small { justify-self: start; text-align: left; }
    .found { gap: var(--s-1); }
    .found .more { font-size: var(--t-ui-s); }
    .progress .peeker { display: none; }
    .apps { grid-template-columns: minmax(0, 1fr); gap: var(--s-7); padding-top: var(--s-8); }
    .tile { min-height: 0; }
    .bslot { --room: var(--s-8); }
    .home.has-badges .apps { padding-top: var(--s-7); }
    .sheet { width: 100%; margin: auto 0 0; max-height: calc(100vh - var(--s-5)); max-height: calc(100dvh - var(--s-5)); border-bottom: 0; border-radius: var(--r-xl) var(--r-xl) 0 0; }
    .sheet-top { padding: var(--s-4); }
    .sheet .badge-list { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); padding: var(--s-4); }
}

/* The badges tile when it is narrow (a phone, or the column beside the scene on a small Chromebook): its words
   and pictures, then the count and arrow along the foot, as the other tiles have their "Open". */
@media (max-width: 600px), (min-width: 1024px) and (max-width: 1199px) {
    .btile { flex-wrap: wrap; row-gap: var(--s-2); min-height: 0; }
    .btile .do { flex-basis: 100%; justify-content: space-between; margin: 0; padding-top: var(--s-1); border-top: var(--edge) solid var(--app-deep); }
}
