/* © 2026 William C. Chesher. All Rights Reserved.
   spawn - the studio's skin (studio/index.html); the admin also leans on the
   shared rules at the bottom. The colours, type and motion are tokens.css, the one source.

   SPAWN'S OWN BRAND, BUILT THE GLITCH WAY (operator, 2026-10-09: "i want spawn to have its own
   branding" / "use glitch as a source of truth for the way we do this"). Every colour is a token
   and no rule below hardcodes one; self-hosted faces (fonts.css); a lowercase wordmark; one accent
   leads; the house motion and a real reduced-motion path.

   TWO PLAYERS ON A DARK SCREEN. Lime is player one, the student: it leads, and every screen has
   one lime action. Sky is player two, Claude: it appears only where player two is, with the
   robot (the player-two icon). THE BRACKETS are the spawn point: the station you are at, the game you picked,
   the screen. THE ONE MOTION: a new thing spawns in, four hard steps over 160ms, then stays put.

   THE BENCH (the 2026-10-10 handoff, "implement this now"). Three columns: the room (scrolls on
   its own, ends in a sticky bar with the one lime action), the screen (the game at 600 x 600, as
   large as the window allows, sized by studio.js::fitScreen), and player two (a 340px rail, or a
   56px strip when folded; an overlay under 1100px). Four stations along the top; four rooms open
   from make. Everything survives 924px wide and a 1366 x 768 Chromebook. */

@import url("/tokens.css");

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }       /* the attribute wins over any display a class sets */
html, body { margin: 0; color: var(--ink); -webkit-text-size-adjust: 100%; }
html { background: var(--surface); }   /* the body stays clear so the void's light (tokens.css, body::before) shows through */
body { font: var(--type-body)/1.5 var(--body); min-height: 100dvh; }
a { color: var(--accent); text-underline-offset: 3px; }
a:hover { color: var(--accent-hover); }
h1, h2, h3, h4, h5 { letter-spacing: -.01em; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
code, kbd { font-family: var(--mono); font-size: .92em; }
/* pinned to its containing block's corner: left at its static place, an .sr inside a scroll box that is not
   positioned (the watch list) lands below the fold of the page itself, grows the document past the window,
   and the next scrollIntoView scrolls the whole bench up and off the top bar (2026-11-03 review, P0) */
.sr { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.grow { flex: 1 1 auto; }
.mono { font-family: var(--mono); }
.muted { color: var(--muted); }
.hair { height: 1px; background: var(--line); border: 0; margin: 0; }
input[type=range], input[type=checkbox] { accent-color: var(--accent); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 10px; border: 3px solid var(--surface); }

/* the bracket corners, one recipe: --b is the stroke colour, --bl the arm, --bw the weight */
.brackets::before, .station[aria-current="step"]::before, .game-card.here::before, .model[aria-pressed="true"]::before,
.screen::before, .dryrun::before {
  content: ""; position: absolute; pointer-events: none; inset: var(--bi, 0);
  --c: linear-gradient(var(--b, var(--accent)), var(--b, var(--accent)));
  background: var(--c) top left / var(--bl, 14px) var(--bw, 2.5px), var(--c) top left / var(--bw, 2.5px) var(--bl, 14px),
    var(--c) top right / var(--bl, 14px) var(--bw, 2.5px), var(--c) top right / var(--bw, 2.5px) var(--bl, 14px),
    var(--c) bottom left / var(--bl, 14px) var(--bw, 2.5px), var(--c) bottom left / var(--bw, 2.5px) var(--bl, 14px),
    var(--c) bottom right / var(--bl, 14px) var(--bw, 2.5px), var(--c) bottom right / var(--bw, 2.5px) var(--bl, 14px);
  background-repeat: no-repeat; animation: spawn-in var(--step) both; }

/* ---- the lockup ---- */
.lockup { display: flex; align-items: center; gap: 10px; min-width: 0; text-decoration: none; color: var(--ink); flex: none; }
.lockup:hover { color: var(--ink); }
.lockmark { flex: none; width: 32px; height: 32px; display: block; }
.lockmark .frame { fill: none; stroke: var(--muted); stroke-width: 3; stroke-linecap: square; }
.lockmark .p1 { fill: var(--accent); }
.lockmark .p2 { fill: var(--p2); }
.lockmark .in { animation: spawn-in var(--step) 120ms both; }
.brand { margin: 0; font: 800 26px/.9 var(--display); letter-spacing: -.055em; color: var(--ink); display: flex; align-items: baseline; }
.brand .pt { display: inline-block; flex: none; width: .17em; height: .17em; margin-left: .05em; background: var(--accent); }
/* the admin keeps the big lockup */
.admin .lockmark, .top .lockmark { width: clamp(56px, 10vw, 68px); height: auto; margin-top: -6px; }
.admin .brand, .top .brand { font-size: clamp(44px, 8vw, 58px); }
.admin .lockup, .top .lockup { align-items: flex-start; gap: clamp(14px, 2.4vw, 22px); }

/* ---- pixel labels: step numbers and eyebrows, never a sentence ---- */
.eyebrow, .px { font: 400 var(--type-small)/1.4 var(--pixel); color: var(--muted); margin: 0; letter-spacing: .02em; display: flex; align-items: center; gap: 8px; }
.eyebrow .n, .px .n { color: var(--accent); }
.eyebrow.lime { color: var(--accent); }
.sectional { font: 400 var(--type-small)/1.4 var(--pixel); color: var(--muted); margin: 0 0 14px; display: flex; align-items: center; gap: 10px; }
.sectional .n { color: var(--accent); }

/* ---- the studio: the bar on top, the bench filling the window ---- */
.studio { height: 100dvh; display: grid; grid-template-rows: auto minmax(0, 1fr); }
.bar { position: relative; display: flex; align-items: center; gap: 28px; padding: 12px 24px; border-bottom: 1px solid var(--line); min-width: 0; }
.bar::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; background: var(--genesis); opacity: .45; pointer-events: none; }   /* the seam: player one into player two */
.line { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; min-width: 0; justify-content: center; overflow-x: auto; scrollbar-width: none; }
.line::-webkit-scrollbar { display: none; }
.station { position: relative; display: flex; align-items: baseline; gap: 8px; padding: 8px 14px; text-decoration: none; flex: none; --bl: 10px; --bw: 2px; }
.station .n { font: 400 var(--type-label) var(--pixel); color: var(--muted); }
.station .w { font: 600 var(--type-body) var(--body); color: var(--muted); letter-spacing: -.01em; }
.station:hover .w { color: var(--ink); }
/* each station keeps its step on the genesis walk (tokens.css), the same four the landing shows: pick is
   lime, design aqua, make periwinkle, and ship is the whole walk, player one into player two */
.station { --c: var(--accent); }
.station[data-place="design"] { --c: var(--genesis-2); }
.station[data-place="make"] { --c: var(--genesis-3); }
.station.done .n, .station[aria-current="step"] .n { color: var(--c); }
.station[data-place="ship"].done .n, .station[data-place="ship"][aria-current="step"] .n { background: var(--genesis); -webkit-background-clip: text; background-clip: text; color: transparent; }
.station.done .w, .station[aria-current="step"] .w { color: var(--ink); }
.link-bar { width: 18px; height: 2px; background: var(--line-2); flex: none; }
.link-bar.done { background: var(--accent); }
/* In a room the stations step back by COLOUR, not opacity: .6 opacity took the words to 3.3 : 1 and
   the numbers to 1.47. The bars may fade; every word keeps at least 4.5 : 1. */
.in-room .link-bar { opacity: .6; }
.in-room .station .w { color: var(--muted); }
.in-room .station.done .w, .in-room .station[aria-current="step"] .w { color: var(--muted); }
.in-room .station:hover .w { color: var(--ink); }
.bar-actions { position: relative; flex: none; display: flex; align-items: center; gap: 8px; }
.bar-discard { min-height: 40px; padding: 0 10px; background: transparent; border: 1px solid transparent; border-radius: var(--radius-sm);
  font: 600 var(--type-body) var(--body); color: var(--muted); white-space: nowrap; transition: color var(--fast) var(--ease); }
.bar-discard:hover { color: var(--bad); }
.bar-commit { min-height: 40px; padding: 0 14px; background: transparent; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: 600 var(--type-body) var(--body); color: var(--muted); white-space: nowrap; transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease); }
.bar-commit.dirty { border-color: var(--line-2); color: var(--ink); }
.bar-commit:hover { border-color: var(--muted); }
.menu-wrap { position: relative; }
.game-button { display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 14px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-sm); max-width: 260px; color: var(--ink); transition: border-color var(--fast) var(--ease); }
.game-button:hover { border-color: var(--muted); }
.game-button svg { flex: none; color: var(--muted); }
.game-art { width: 20px; height: 20px; flex: none; display: grid; place-items: center; }
.game-art img { width: 20px; height: 20px; image-rendering: pixelated; object-fit: contain; }
.game-art .box { width: 14px; height: 14px; border: 1.5px dashed var(--muted); }
.game-name { font: 600 var(--type-body) var(--body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.game-tag { font: 400 var(--type-small) var(--mono); color: var(--muted); white-space: nowrap; }
.game-tag:empty { display: none; }
.menu { position: absolute; right: 0; top: calc(100% + 8px); width: 260px; max-height: calc(100dvh - 80px); overflow-y: auto; background: var(--panel); border: 1px solid var(--line-2);
  border-radius: var(--radius); padding: 6px; z-index: 30; box-shadow: var(--shadow); animation: spawn-in var(--step) both; }
.menu-item { display: flex; justify-content: flex-start; gap: 10px; align-items: center; width: 100%; padding: 10px 12px; background: none; border: 0;
  border-radius: 8px; text-align: left; font-size: var(--type-body); color: var(--ink); text-decoration: none; }
.menu-item:hover { background: var(--panel-2); color: var(--ink); }
.menu-item.quiet { color: var(--muted); }
.menu-item.quiet:hover { color: var(--ink); }
.menu-item .count { margin-left: auto; padding-left: 12px; white-space: nowrap; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.menu-group { margin: 0; padding: 8px 12px 2px; }
.menu .menu-copyright { padding: 10px 12px 4px; margin-top: 6px; border-top: 1px solid var(--line); text-align: left; }
.menu-rule { height: 1px; background: var(--line); margin: 6px 4px; }
.menu-who { margin: 0; padding: 8px 12px 6px; font-size: var(--type-small); color: var(--muted); }
.menu-who strong { color: var(--ink); }
label.menu-item { cursor: pointer; }
.menu-item.danger { color: var(--caution); }
.menu-item.danger:hover { color: var(--caution); background: color-mix(in srgb, var(--caution) 12%, transparent); }
.menu-item.danger .icon { color: inherit; filter: none; }
.menu-name { display: grid; gap: 6px; padding: 8px 12px 4px; }
.menu .menu-name input[type=text] { padding: 8px 10px; font-weight: 600; }
.menu-name-note { margin: 0; padding: 0 12px 4px; font: 400 var(--type-small) var(--body); color: var(--muted); }
.menu-note { margin: 0; padding: 8px 12px 10px; border-bottom: 1px solid var(--line); margin-bottom: 6px; font: 400 var(--type-small) var(--body); color: var(--muted); }

/* the three columns. --screen is the game's drawn size (studio.js::fitScreen); the column is the
   game plus its brackets (24) plus its padding (40). --p2w is the rail: 340 open, 56 folded. */
.bench { --screen: 600px; --p2w: 340px; display: grid; min-height: 0; position: relative;
  grid-template-columns: minmax(0, 1fr) calc(var(--screen) + 64px) var(--p2w); }
.bench.p2-folded { --p2w: 56px; }
/* the edge between the room and the game: the student sets the split */
.split { position: absolute; top: 0; bottom: 0; z-index: 5; width: 10px; right: calc(var(--p2w) + var(--screen) + 64px - 5px);
  cursor: col-resize; touch-action: none; }
.split::after { content: ""; position: absolute; left: 4px; top: 0; bottom: 0; width: 2px; background: transparent; transition: background var(--fast) var(--ease); }
.split:hover::after, .split:focus-visible::after, .split.on::after { background: var(--accent); }
.split:focus-visible { outline: none; }
/* the divider's focus is its line lit, thickened so a keyboard student sees it (2026-11-03 review) */
.split:focus-visible::after { left: 3px; width: 4px; }
.playtesting .split { display: none; }
@media (max-width: 760px) { .split { display: none; } }

/* the room */
/* position: relative makes the room the anchor for the hidden words inside it (.sr, a button's words kept for screen
   readers): anchored to the bench instead, they sat at their place in the room's full scroll length, and the page itself
   scrolled down into an empty band below the studio (usability pass, 2026-10-22: 541px on make at 1366 x 768). */
.room { position: relative; min-height: 0; min-width: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; container-type: inline-size; }
/* a narrow room keeps the note on its own line over the actions (2026-11-03 second review: every station column is
   ~362px and most rooms ~460px, so hiding it there hid "to go: a name, 5 lines" from nearly every screen) */
@container (max-width: 520px) {
  .next { padding: 6px 16px 8px; gap: 4px 8px; justify-content: flex-end; flex-wrap: wrap; padding-left: max(48px, 16px); }
  .next .next-note { flex: 1 0 100%; order: -1; line-height: 1.3; }
}
/* except the map room: every pixel of the bar is a pixel of map (at 1366 x 768 the explorer's map sat under a taller
   bar), and the verdict pinned over the grid already says what the note would */
@container (max-width: 520px) { body[data-place="map"] .next .next-note { display: none; } body[data-place="map"] .next { padding: 10px 16px; } }
.room-body { flex: 1 0 auto; padding: 22px clamp(18px, 2.4vw, 36px); width: 100%; max-width: 920px; }
.place { min-width: 0; animation: spawn-in var(--step) both; }
/* ONE LINE A STATION HEAD (the pretty pass, wchesher 2026-10-25): the rail says where you are, so no eyebrow; a section
   title, not a display one; at 768 tall the head took ~200px of the room, now ~90 */
.place h1 { margin: 0 0 6px; font: 700 clamp(22px, 2vw, 30px)/1.1 var(--display); letter-spacing: -.03em; text-wrap: pretty; }
.lede { margin: 0 0 18px; color: var(--muted); font-size: var(--type-body); max-width: 60ch; }
.strip-head { display: flex; align-items: baseline; gap: 12px; margin: 0 0 12px; }
.games-space { margin-left: auto; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.games-space.full { color: var(--caution); }
.strip-label { margin: 24px 0 10px; }
/* the cheat code box under the starters (alpha starters a code unlocks) */
.cheat { margin: 14px 0 0; font-size: var(--type-small); color: var(--muted); }
.cheat[hidden] { display: none; }
.cheat summary { cursor: pointer; width: max-content; }
.cheat-form { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 0; }
.cheat-code { min-height: 36px; padding: 0 10px; flex: 0 1 220px; min-width: 0; font: inherit; font-family: var(--mono); text-transform: uppercase;
  background: var(--well, transparent); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-sm, 6px); }
.cheat-note:empty { display: none; }
.next { position: sticky; bottom: 0; display: flex; align-items: center; gap: 16px; padding: 10px clamp(20px, 3vw, 44px);
  border-top: 1px solid var(--line); background: var(--surface); z-index: 5;
  /* the Feedback button stays put at the bottom left (suite-feedback.js, 8px in, 28px wide): the bar's words start
     clear of it (usability pass, 2026-10-22: it sat on "art · 1 of 5 have art") */
  padding-left: max(48px, clamp(20px, 3vw, 44px)); }
/* two lines before it is cut, not one (2026-11-03 review: Ship's note clipped mid-sentence, "gold · before it can go in the...") */
.next-note { flex: 1; min-width: 0; font: 400 var(--type-small)/1.35 var(--mono); color: var(--muted); overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; }
.next .btn svg { flex: none; }
.room-head { display: flex; align-items: center; gap: 16px; margin: -12px 0 28px; flex-wrap: wrap; }
.back-pill { display: inline-flex; align-items: center; gap: 8px; min-height: 36px; padding: 0 12px 0 8px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); font: 600 var(--type-small) var(--body); color: var(--ink); text-decoration: none; transition: border-color var(--fast) var(--ease); }
.back-pill:hover { border-color: var(--muted); color: var(--ink); }
.room-title { margin: 0; font: 700 clamp(24px, 2.2vw, 30px)/1 var(--display); letter-spacing: -.03em; }
#place-playtest .room-title { font-size: 30px; margin: 10px 0 8px; }
#place-playtest { max-width: 32ch; }
/* ONE HEAD IN EVERY ROOM (2026-11-03 review): the room's name, then its one-line note under it, the same in art, the
   map and sound at every width; beside-or-under used to follow whatever room the title left, so it moved room to room */
.room-note { flex: 1 0 100%; margin-top: -8px; font-size: var(--type-body); color: var(--muted); min-width: 0; }

/* the screen */
.screen-col { container: screen / inline-size; min-height: 0; display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 18px 20px 14px;
  border-left: 1px solid var(--line); overflow-y: auto; overflow-x: hidden;
  background: radial-gradient(80% 380px at 50% 330px, var(--p2-soft), transparent 75%) no-repeat, var(--side); }   /* the screen sits in light */
/* the game stays in view while the tools under it scroll (on a short screen they can run longer than the column) */
.screen { position: sticky; top: 0; z-index: 3; background: var(--side); padding: 12px; box-shadow: 0 30px 90px -30px color-mix(in srgb, var(--p2) 40%, transparent); width: calc(var(--screen) + 24px); flex: none; --b: var(--muted); --bl: 28px; --bw: 3px; }
.screen-inner { position: relative; width: var(--screen); height: var(--screen); overflow: hidden; background: #000; }
.screen iframe { position: absolute; left: 0; top: 0; width: 600px; height: 600px; border: 0; transform-origin: 0 0; background: #000; }
/* the game says when it has the keys: the studio's lime ring, inside the screen so the frame's own brackets stay
   where they are (2026-11-03 review: it reported outline none and showed nothing). :focus, not :focus-visible,
   which Chromium never matches on an iframe reached by Tab (measured); a click into the game lights it too,
   which is true: the keys go to the game */
.screen.has-keys .screen-inner::after { content: ""; position: absolute; inset: 0; border: 2px solid var(--accent); border-radius: 2px; pointer-events: none; z-index: 2; }
/* under the screen: the verdict and the two run buttons on one line, then the four switches for how
   the game shows as one segmented bar the screen's width, so nothing is left wrapped on a line alone */
.screen-row { display: flex; flex-direction: column; gap: 8px; width: var(--screen); flex: none; }
/* the controls under the game stay with it: the row sticks right under the screen, so the tools and the
   console scroll under both and the screen's edge never cuts through Code, Restart or the switches (class
   report, 2026-10-19). It takes up the column gap above it so the two read as one block, and paints the
   side strips beside it so nothing scrolling shows there. A column too short to hold both lets it go. */
.screen-row { position: sticky; top: calc(var(--screen) + 24px); z-index: 3; margin-top: -10px; padding: 10px 0 8px; background: var(--side);
  box-shadow: 12px 0 0 var(--side), -12px 0 0 var(--side); }
@media (max-height: 560px) { .screen-row, .story-strip { position: static; margin-top: 0; padding: 0; box-shadow: none; } }
.screen-status { display: flex; align-items: center; gap: 8px; min-width: 0; }
.screen-status .verdict-text { margin-right: auto; }
/* the four switches are icon squares packed in one joined bar, never stretched across the row: on a
   screen too narrow for one line they sit on their own line at its right end, under the run controls,
   where they sit at the end of the one line on a wide screen (Maestro, 2026-10-19: "why are the icons
   spread out like this?") */
.view-bar { display: grid; grid-auto-flow: column; grid-auto-columns: auto; align-self: flex-end; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--panel); padding: 3px; gap: 3px; }
.view { min-height: 30px; padding: 0 6px; border: 1px solid transparent; border-radius: 7px; background: transparent; color: var(--muted);
  font: 600 var(--type-small) var(--body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease); }
.view:hover { color: var(--ink); background: var(--panel-2); }
/* a full-size screen has the width for both on one line. The switches are icons now, each a square, so the
   row's two halves fit whole from a 520 column (the screen plus 40 of padding); with words they needed 590 */
/* ten controls fit one line from a 400 column now that the verdict rides Code and Sprite debug is only in Tools (the pretty
   pass): the code room's docked game and a short screen with Tools open keep one line under the game */
@container screen (min-width: 400px) { .screen-row { flex-direction: row; align-items: center; } .screen-status { flex: 1 1 auto; }
  .view-bar { flex: none; grid-auto-columns: auto; } .view { padding: 0 10px; } .view.icon-only { width: 36px; padding: 0; } }
/* the smallest screen: the four switches stay in one bar, in the label size */
@container screen (max-width: 299px) { .view { padding: 0 2px; font-size: var(--type-label); } }
/* a narrow screen (the code room): the chip says the verdict, the buttons stay on one line */
@container screen (max-width: 440px) { .verdict-text { display: none; } .screen-status { justify-content: flex-start; } .screen-status .chip { margin-right: auto; }
  .screen-status .btn.tiny { padding: 0 10px; } }
.verdict-text { flex: 1 1 0; min-width: 0; font-size: var(--type-small); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-decoration: none; }
.verdict-text:hover { color: var(--ink); }
/* the Code button and the game speed under the game (class feedback, 2026-10-14): one line with Restart */
.code-open[aria-current="page"] { border-color: var(--accent); color: var(--accent); }
/* THE VERDICT IS A DOT ON CODE (the pretty pass, M8): green solid, amber works, red breaks; the word stays inside for a
   screen reader, and Code's tip says what to fix. The flare and its burst still fire when a game turns solid. */
.code-open { position: relative; overflow: visible; }
/* inside the button's corner, never past its edge: the row's check reads a button that spills as one cut short */
.screen-status .code-open .verdict-dot { position: absolute; top: 3px; right: 3px; width: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%;
  background: currentColor; box-shadow: 0 0 0 2px var(--side); overflow: visible; font-size: 0; line-height: 0; color: var(--muted); }
.screen-status .code-open .verdict-dot.solid { color: var(--good); } .screen-status .code-open .verdict-dot.works { color: var(--caution); }
.screen-status .code-open .verdict-dot.gold { color: var(--good); }
.screen-status .code-open .verdict-dot.prototype, .screen-status .code-open .verdict-dot.alpha, .screen-status .code-open .verdict-dot.beta { color: var(--caution); }
.screen-status .code-open .verdict-dot.breaks { color: var(--bad); }
.speed-pick { min-height: 32px; padding: 0 2px; flex: none; background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--radius-sm); font: 600 var(--type-small) var(--body); cursor: pointer; }
.speed-pick:hover { border-color: var(--muted); }
/* a full-size screen holds the verdict, Code, the two run buttons, the speed and the four switches on one
   line: everything a little tighter there, the verdict's words give way first, then the switches' */
@container screen (min-width: 400px) { .screen-status { gap: 4px; } .screen-status .btn.tiny { padding: 0 8px; }
  .screen-status .verdict-text { width: 0; } .speed-pick { font-size: var(--type-label); }
  .screen-row .view-bar { min-width: 0; flex: 0 1 auto; grid-auto-columns: minmax(0, auto); } .screen-row .view { padding: 0 5px; } .screen-row .view.icon-only { width: 36px; padding: 0; } }
@container screen (max-width: 440px) { .screen-status { gap: 6px; } .screen-status .btn.tiny { padding: 0 8px; } .speed-pick { font-size: var(--type-label); } }
.scale-note { font: 400 var(--type-label) var(--mono); color: var(--muted); white-space: nowrap; }
/* the strip under the game: a tab per level, card and cutscene, in the order the player meets them (class
   feedback, 2026-10-22). Levels are solid like the map room's level buttons, cards outlined, cutscenes dashed;
   the picked one is lime. One line that scrolls sideways, never two. */
.story-strip { display: flex; flex-direction: column; gap: 6px; width: var(--screen); min-width: 0; flex: none;
  position: sticky; top: calc(var(--screen) + 24px); z-index: 3; margin-top: -10px; padding: 10px 0 0; background: var(--side);
  box-shadow: 12px 0 0 var(--side), -12px 0 0 var(--side); }
.story-strip:not([hidden]) + .screen-row { top: calc(var(--screen) + 24px + var(--strip, 44px)); }
.story-tabs { display: flex; gap: 6px; align-items: center; overflow-x: auto; scrollbar-width: thin; padding-bottom: 2px; }
.part { flex: none; max-width: 150px; height: 32px; padding: 0 12px; border-radius: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: var(--panel-2); border: 1px solid var(--line); font: 500 var(--type-small) var(--body); color: var(--muted); }
.part:hover { border-color: var(--muted); color: var(--ink); }
.part-card { background: transparent; border-color: var(--line-2); }
.part-cutscene { background: transparent; border-style: dashed; border-color: var(--line-2); }
.part.now { color: var(--ink); border-color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); }   /* the level the whole game is on now */
.part[aria-pressed="true"] { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); border-style: solid; }
.part-add { flex: none; }
.story-edit { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; min-width: 0; }
.story-edit .eyebrow { font-size: var(--type-label); color: var(--muted); }
.story-edit input { height: 32px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--line); background: var(--well); color: var(--ink); font: 400 var(--type-small) var(--body); min-width: 0; }
.story-edit .story-title { flex: 0 1 140px; }
.story-edit .story-words { flex: 1 1 160px; }
.shot-chips { display: flex; gap: 4px; align-items: center; }
.shot-chips .eyebrow { font-size: var(--type-label); color: var(--muted); margin-right: 2px; }
.story-shot { flex: 0 0 100%; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; min-width: 0; padding-left: 10px; border-left: 2px dashed var(--line-2); }
.story-shot .shot-secs { display: flex; align-items: center; gap: 4px; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.story-shot .story-words { flex: 1 1 100%; }
.story-shot .shot-seconds { width: 64px; }
.story-shot .shot-pick { height: 32px; padding: 0 8px; border-radius: 8px; border: 1px solid var(--line); background: var(--well); color: var(--ink); font: 400 var(--type-small) var(--body); max-width: 150px; }
.story-note { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.playtest-level { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0; width: var(--screen); font: 400 var(--type-small) var(--mono); color: var(--accent); }
/* looking inside the game: one row of tools, the console under it */
.debug { width: var(--screen); flex: none; display: flex; flex-direction: column; gap: 8px; }
/* docked (studio.js placeTools): a drawer at the foot of the room, on the bar with the one main action, the full room wide */
.debug-dock { position: sticky; bottom: var(--next-h, 0px); z-index: 4; flex: none; padding: 10px clamp(18px, 2.4vw, 36px) 12px;
  background: var(--side); border-top: 1px solid var(--line); box-shadow: 0 -18px 40px -24px rgba(0, 0, 0, .7); }
.debug-dock[hidden] { display: none; }
.debug-dock .debug { width: 100%; }
.tools-toggle { position: relative; }
.tools-toggle[aria-expanded="true"] { color: var(--ink); background: var(--panel-2); border-color: var(--line-2); }
.tools-dot { position: absolute; top: -3px; right: -3px; width: 9px; height: 9px; border-radius: 50%; background: var(--bad); box-shadow: 0 0 0 2px var(--side); }
/* the tools: three joined groups (time, what shows, keeping it), each wraps as a whole */
.debug-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tool-group { display: inline-flex; flex: none; }
.tool { position: relative; min-height: 28px; padding: 0 8px; border-radius: 0; border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  font: 600 var(--type-label) var(--body); white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; }
.tool-group > .tool + .tool, .tool-group > .sr + .tool { margin-left: -1px; }
.tool-group > .tool:first-child { border-radius: 7px 0 0 7px; }
.tool-group > .tool:last-child { border-radius: 0 7px 7px 0; }
.tool:hover:not(:disabled) { color: var(--ink); border-color: var(--muted); z-index: 1; }
.tool:disabled { color: var(--faint); cursor: default; }
.tool[aria-pressed="true"] { z-index: 2; }
select.tool { padding-right: 2px; }
.debug-bar .coords, .debug-bar .scale-note { margin-left: auto; }
.debug-bar .coords + .scale-note { margin-left: 0; }
/* the console's fold, with the readouts at its right */
.debug-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 0 12px; min-height: 28px; padding: 0 2px; border-bottom: 1px solid var(--line); }
.console-toggle { display: inline-flex; white-space: nowrap; align-items: center; gap: 8px; min-height: 28px; padding: 0 2px; background: none; border: 0; color: var(--ink-2); font: 400 var(--type-small) var(--mono); }
.console-toggle:hover { color: var(--ink); }
.console-toggle .caret { width: 0; height: 0; border: 4px solid transparent; border-left-color: currentColor; border-right: 0; transition: transform var(--fast) var(--ease); }
.console-toggle[aria-expanded="true"] .caret { transform: rotate(90deg); }
.console-toggle .badge { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--bad); color: var(--surface); font: 700 var(--type-label)/18px var(--mono); text-align: center; }
.coords { font: 400 var(--type-label) var(--mono); color: var(--muted); white-space: pre; min-width: 80px; }
/* the console and watch: two panes side by side, one above the other on a narrow screen */
.debug-body { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 8px; height: 214px; }
/* a short screen keeps the game (the pretty pass, M1; studio.js::debugHeight counts the same 142) */
@media (max-height: 899px) { .debug-body { height: 142px; } }
.debug-body[hidden] { display: none; }
/* the console and watch stack only in the narrowest column: from a 300 column (the column less its padding) they stay side by side at their fixed height,
   so a short screen's Tools fit under the game instead of running on under it (the pretty pass, M1) */
@container screen (max-width: 300px) { .debug-body { grid-template-columns: minmax(0, 1fr); height: auto; } .console { height: 180px; } .watch { max-height: 240px; } }
/* LINE BY LINE (studio.js renderTrace): at a breakpoint, above the watched values */
.trace { flex: 0 1 auto; min-height: 0; max-height: 70%; overflow: auto; margin: 6px 6px 0; padding: 8px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel-2); }
/* the step bar under the screen (index.html trace-bar): the line it stands on, on one line, never wrapped or run
   off (the whole of it in its tip), the four moves under it, each 32px tall, sharing the column's width */
.trace-bar { display: grid; gap: 6px; margin: 0; padding: 8px; border: 1px solid var(--caution); border-radius: 8px; background: var(--panel-2); }
.trace-bar[hidden] { display: none; }
.trace-where { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font: 600 var(--type-small)/1.4 var(--mono); color: var(--ink); }
.trace-steps { display: flex; gap: 6px; }
.trace-step { flex: 1 1 auto; min-height: 32px; padding: 0 8px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel);
  color: var(--ink); font: 600 var(--type-small) var(--body); white-space: nowrap; cursor: pointer; }
.trace-step:hover { background: var(--panel-2); }
.trace-vars { margin-top: 6px; }
.trace-note { margin: 6px 0 0; font: var(--type-small) var(--body); color: var(--muted); }
.pane-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; min-height: 30px; padding: 0 10px; border-bottom: 1px solid var(--line); }
.pane-head .eyebrow { font-size: var(--type-label); }
.pane-note { font: 400 var(--type-label) var(--mono); color: var(--accent); }
.pane-action { background: none; border: 0; padding: 4px 0; color: var(--muted); font: 600 var(--type-label) var(--body); }
.pane-action:hover { color: var(--ink); }
.console { min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); overflow: hidden; }
.console-out { flex: 1; overflow: auto; padding: 6px 10px; font: var(--type-small)/1.5 var(--mono); }
.console-out .line { display: flex; gap: 8px; align-items: baseline; white-space: pre-wrap; word-break: break-word; }
.console-out .said { flex: 1; min-width: 0; }
.console-out .error { color: var(--bad); }
.console-out .warn { color: var(--caution); }
.console-out .input { color: var(--muted); }
.console-out .result { color: var(--ink-2); }   /* the running game answering, not player two */
.console-out .break { color: var(--accent); }
.console-out .run { color: var(--muted); justify-content: center; }
.console-out .at { flex: none; background: none; border: 0; padding: 0; color: inherit; font: inherit; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; opacity: .8; }
.console-row { display: flex; align-items: center; gap: 8px; min-height: 34px; padding: 0 10px; border-top: 1px solid var(--line); background: var(--well); }
.console-row .console-prompt { font: var(--type-small) var(--mono); color: var(--accent); }
.console-row input[type=text] { flex: 1; min-width: 0; width: auto; background: transparent; border: 0; border-radius: 0; color: var(--ink); font: var(--type-small) var(--mono); padding: 6px 0; }
.console-row input[type=text]::placeholder { color: var(--faint); }
.console-row:focus-within { box-shadow: inset 0 1px 0 var(--accent); }
.console-row input[type=text]:focus { outline: none; }
.watch { min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); overflow: hidden; }
.watch-scroll { position: relative; flex: 1; min-height: 0; overflow: auto; padding: 4px 0 8px; }
.watch-list { font: var(--type-small)/1.5 var(--mono); }
.watch-empty { margin: 0; padding: 4px 10px 2px; font: var(--type-small)/1.5 var(--body); color: var(--faint); }
.watched { position: relative; display: grid; grid-template-columns: minmax(0, auto) minmax(0, 1fr); gap: 12px; align-items: baseline; padding: 3px 10px; }
.watched + .watched { border-top: 1px solid var(--line); }
.watched .name { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watched .value { color: var(--ink); text-align: right; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watched .drop { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px; padding: 1px 6px; color: var(--muted); font: 600 var(--type-label) var(--body); opacity: 0; transition: opacity var(--fast) var(--ease); }
.watched:hover .drop, .watched .drop:focus-visible { opacity: 1; }
.watched .drop:hover { color: var(--bad); }
@media (hover: none) { .watched .drop { opacity: 1; } }
.watch-suggest { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 5px 10px; align-items: baseline; padding: 8px 10px 0; }
.watch-suggest:not(:empty) { margin-top: 6px; border-top: 1px dashed var(--line); }
.offer-line { display: contents; }
.offer-line .owner { font: 400 var(--type-label) var(--mono); color: var(--faint); text-align: right; }
.offer-line .offers { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.watch-suggest .offer { background: var(--panel); border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; color: var(--muted); font: 400 var(--type-label)/1.6 var(--mono); }
.watch-suggest .offer:hover { color: var(--ink); border-color: var(--muted); background: var(--panel-2); }
/* the grid and the stop note sit over the game and never take its clicks */
.grid-overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.grid-overlay[hidden] { display: none; }
/* white and clear by default (#309: at 16 and 38 percent it was not found); .dark for a light game */
.grid-overlay line { stroke: rgba(255, 255, 255, .4); stroke-width: 1; vector-effect: non-scaling-stroke; }
.grid-overlay line.bold { stroke: rgba(255, 255, 255, .85); }
.grid-overlay line.cross { stroke: var(--accent); stroke-dasharray: 4 4; }
.grid-overlay text { fill: #fff; font: 600 var(--type-label) var(--mono); paint-order: stroke; stroke: rgba(0, 0, 0, .7); stroke-width: 3px; }
.grid-overlay.dark line { stroke: rgba(0, 0, 0, .35); }
.grid-overlay.dark line.bold { stroke: rgba(0, 0, 0, .8); }
.grid-overlay.dark text { fill: #000; stroke: rgba(255, 255, 255, .75); }
.paused-note { position: absolute; left: 8px; top: 8px; padding: 2px 8px; border-radius: 6px; background: var(--accent); color: var(--surface); font: 600 var(--type-label) var(--mono); pointer-events: none; }
.paused-note[hidden] { display: none; }
/* STOPPED (Stop beside Restart, Maestro 2026-10-19): the game dims a little, its corners turn amber and the tag in
   its corner says so, so a frozen screen reads from across the room. The tag is the paused-note, in amber. */
.screen.stopped .paused-note { background: var(--caution); color: var(--accent-ink); z-index: 2; }
.screen.stopped .screen-inner::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: rgba(7, 11, 24, .38);
  backdrop-filter: saturate(.4); animation: spawn-in var(--fast) both; }
.screen.screen.stopped { --b: var(--caution); }
.stopped-play { position: absolute; inset: 0; z-index: 1; display: grid; place-items: center; padding: 0; border: 0; background: transparent; cursor: pointer; }
.stopped-play[hidden] { display: none; }
.stopped-play .disc { display: grid; place-items: center; width: 88px; height: 88px; border-radius: 50%; background: var(--accent); color: var(--accent-ink);
  box-shadow: 0 0 0 6px rgba(198, 244, 50, .18), 0 10px 30px rgba(0, 0, 0, .5); transition: transform var(--fast); animation: spawn-in var(--step) both; }
.stopped-play .disc .icon { width: 40px; height: 40px; margin-left: 4px; color: var(--accent-ink); filter: none; }
.stopped-play:hover .disc, .stopped-play:focus-visible .disc { transform: scale(1.08); }
/* LINE BY LINE, THE FRAME STAYS IN SIGHT: at a breakpoint the student is told the screen shows where the frame
   ended, so Play is a chip in the corner rather than a disc over the middle (Go on in the step bar does the same) */
.screen.tracing .stopped-play { inset: auto 10px 10px auto; }
.screen.tracing .stopped-play .disc { width: 40px; height: 40px; box-shadow: 0 0 0 3px rgba(198, 244, 50, .18), 0 4px 12px rgba(0, 0, 0, .5); }
.screen.tracing .stopped-play .disc .icon { width: 20px; height: 20px; margin-left: 2px; }
/* the buttons under the game that are icons (Maestro, 2026-10-19: "Icons only"): a square the height of the row,
   the glyph in the button's own colour, the word in its aria-label and title */
/* THE ICONS in the studio (the shared rule is in tokens.css): royal in player two's rail, the saved mark
   in its own colour, and a switch that is on fills lime with its icon dark on it */
.save-mark .icon, .del .icon, .mine-delete .icon, .mine-offer .icon, #take-down .icon, #anim-delete .icon { color: inherit; filter: none; }
.p2-open .icon, .p2-strip .icon { color: var(--p2); }
.p2-open :hover > .icon, .p2-strip:hover .icon { filter: drop-shadow(0 0 5px rgba(91, 127, 255, .6)); }
.view[aria-pressed="true"], .tool[aria-pressed="true"], .run-pair #pause[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.view[aria-pressed="true"] .icon, .tool[aria-pressed="true"] .icon, .run-pair #pause[aria-pressed="true"] .icon { color: var(--accent-ink); filter: none; }
.btn.tiny.icon-only, .screen-status .btn.tiny.icon-only { width: 34px; padding: 0; }
.btn.two.icon-only { width: var(--btn-h); padding: 0; }
.btn.two.icon-only::before { content: none; }
/* a fix it asks player two for: bug, arrow, robot, and the words in its aria-label and title (Maestro, 2026-10-19:
   "No literally bug icon --> robot", "I want to minimize text on buttons", "Alt tag is our friend") */
.btn.two.icon-only.fix { width: auto; padding: 0 12px; gap: 6px; }
.view.icon-only { padding: 0; }
.tool.icon-only { width: 32px; padding: 0; }
.pane-action.icon-only { width: 26px; height: 26px; padding: 0; border-radius: 6px; }
.pane-action.icon-only:hover { background: var(--panel-2); }
.save-mark, .tabs button, .bar-help { display: inline-flex; align-items: center; gap: 7px; }
.room-card .what b { display: flex; align-items: center; gap: 8px; }
.room-card b .icon { width: 18px; height: 18px; }
.game-card .del > .icon { width: 15px; height: 15px; }
/* Stop and Restart are one pair */
.run-pair { display: inline-flex; flex: none; }
.run-pair .btn { border-radius: 0; }
.run-pair .btn:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.run-pair .btn:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
.playtesting .debug { display: none; }
.screen-inner:fullscreen { display: flex; align-items: center; justify-content: center; background: #000; width: 100vw; height: 100vh; }
.screen-inner:fullscreen iframe { position: relative; flex: none; transform-origin: center; }
.chip { font: 600 var(--type-small) var(--mono); border-radius: 999px; padding: 3px 11px; flex: none; border: 1.5px solid currentColor; white-space: nowrap; }
.chip-text.solid { color: var(--good); } .chip-text.works { color: var(--caution); } .chip-text.breaks { color: var(--bad); }
.chip.solid { color: var(--good); } .chip.works { color: var(--caution); } .chip.breaks { color: var(--bad); } .chip.quiet { color: var(--muted); }
/* the stages (studio-lint.js, STAGE_WORDS): gold is the goal colour, a running game still climbing is caution */
.chip-text.gold, .chip.gold { color: var(--good); }
.chip-text.prototype, .chip-text.alpha, .chip-text.beta, .chip.prototype, .chip.alpha, .chip.beta { color: var(--caution); }

/* playtest: the room steps aside, the screen grows */
.playtesting .room-body > .place:not(#place-playtest), .playtesting .room-head { display: none !important; }

/* ---- player two: the rail ---- */
.p2-rail { min-height: 0; display: flex; flex-direction: column; border-left: 1px solid var(--line); background: var(--side); overflow: hidden; }
/* while player two's changes wait to be added, the open rail widens over the bench as the student reads
   them, so whole code lines fit ("squished", "doesnt fit in the box" on a Chromebook). The grid keeps its
   column, so the game never resizes; moving onto the game gives it back, and Add or Drop ends it. Wide
   only while the pointer or the keyboard is in the rail, so a change left waiting never hides the game.
   A phone's rail is already full width. */
@media (min-width: 761px) {
  .bench.p2-wide:not(.p2-folded) .p2-rail:is(:hover, :has(:focus-visible)) { position: absolute; right: 0; top: 0; bottom: 0; z-index: 20;
    width: min(680px, calc(100% - 24px)); box-shadow: var(--shadow); }
}
.p2-strip { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 16px 0; background: none; border: 0; color: var(--muted);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease); }
.p2-strip:hover { background: var(--panel); color: var(--ink); }
.p2-vertical { writing-mode: vertical-rl; font: 400 var(--type-small) var(--pixel); color: var(--p2); }
.p2-unread { min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; background: var(--p2); color: var(--accent-ink);
  font: 600 var(--type-small) var(--mono); display: grid; place-items: center; }
.p2-open { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.p2-head { flex: none; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 20px; container-type: inline-size; }
.p2-name { display: flex; align-items: center; gap: 8px; font: 400 var(--type-small) var(--pixel); color: var(--muted); white-space: nowrap; min-width: 0; overflow: hidden; }
.p2-name .two { color: var(--p2); }
/* FIVE TOOLS FIT THE HEAD (the seams pass): with the beacon, past asks, a new conversation and the fold, the tools ran
   off the rail's edge at 1280 and 1440; they keep their size, and on a narrow rail with all five the name drops "claude" */
.p2-tools { flex: none; display: flex; align-items: center; gap: 6px; }
@container (max-width: 400px) { .p2-head:has(#chat-new:not([hidden])) .p2-who { display: none; } }
.p2-fold { background: none; border: 1px solid var(--line); border-radius: 8px; width: 28px; height: 28px; padding: 0; display: grid; place-items: center; color: var(--muted); }
.p2-fold:hover { border-color: var(--muted); color: var(--ink); }
/* PAST ASKS: the student's own asks from every game, over the conversation while open (studio.js::openPastAsks) */
.p2-fold[aria-pressed=true] { border-color: var(--p2); color: var(--p2); }
.past-asks { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 8px; padding: 4px 20px 12px; }
.past-asks[hidden], .p2-open.past-open > .thread, .p2-open.past-open > .design-start { display: none; }
.past-head { margin: 0; font: 400 var(--type-small) var(--pixel); color: var(--p2); }
.past-asks input[type=search] { width: 100%; font-size: var(--type-body); color: var(--ink); background: var(--well);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 8px 12px; }
.past-asks input[type=search]:focus { border-color: var(--p2); outline: none; }
.past-games { display: flex; flex-wrap: wrap; gap: 6px; }
.past-games:empty { display: none; }
.past-games .prompt[aria-pressed=true] { border-color: var(--p2); color: var(--ink); }
.past-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.past-ask { width: 100%; text-align: left; display: flex; flex-direction: column; gap: 4px; padding: 9px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--panel-2); color: var(--ink); transition: border-color var(--fast) var(--ease); }
.past-ask:hover, .past-ask:focus-visible { border-color: var(--p2); outline: none; }
.past-ask .words { font-size: var(--type-body); line-height: 1.4; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 3;
  -webkit-box-orient: vertical; overflow: hidden; }
.past-ask .where { font: 400 var(--type-label) var(--mono); color: var(--muted); }
.past-none { margin: 0; font-size: var(--type-body); color: var(--muted); line-height: 1.5; }
.thread { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 4px 20px 12px; display: flex; flex-direction: column; gap: 10px; }
.thread-empty { margin: 0; font-size: var(--type-body); color: var(--ink); line-height: 1.5; }
/* THE EMPTY RAIL IS NOT EMPTY SPACE (the pretty pass, M6): before the first message the thread is only as tall as its
   words, the design session's offer sits under them, and the composer keeps the bottom */
.thread:has(> .thread-empty:only-child) { flex: 0 0 auto; }
.p2-open > .design-start { margin: 0 20px 12px; }
.p2-open > .composer { margin-top: auto; }
.msg { max-width: 92%; padding: 10px 13px; border-radius: var(--radius-sm); font-size: var(--type-body); line-height: 1.45; min-width: 0; animation: spawn-in var(--step) both; overflow-wrap: anywhere; }
.msg .who { display: block; font: 400 var(--type-label) var(--pixel); color: var(--muted); margin: 0 0 4px; }
.msg.me { align-self: flex-end; background: var(--panel-2); border: 1px solid var(--line); white-space: pre-wrap; }
.msg.p2 { align-self: flex-start; background: var(--p2-wash); border: 1px solid transparent; }
.msg.p2 .who { color: var(--p2); }
.msg.change { width: 100%; max-width: 100%; }
.msg.sys { align-self: center; max-width: 100%; background: transparent; color: var(--muted); font: 400 var(--type-small) var(--mono); padding: 2px 0; text-align: center; }
.msg.sys.bad { color: var(--bad); }
/* PLAYER TWO PLAYS ON THE SCREEN (Maestro, 2026-10-28: "C. Play it live on the screen"; studio.js playLive): royal
   corners while it plays, a chip with what it is doing, the keys it uses lit while down, what it watches in a corner */
#screen.p2-playing { --b: var(--p2); }
.p2-run { position: absolute; inset: 0; z-index: 5; pointer-events: auto; cursor: progress; }
/* the chip rides the screen's top edge, on the frame, so the game's own score line stays readable under it */
.p2-run-chip { position: absolute; top: 0; left: 50%; z-index: 6; transform: translate(-50%, -40%); display: flex; gap: 8px; align-items: center;
  max-width: calc(100% - 28px); padding: 4px 12px; border-radius: 999px; background: var(--p2); color: #fff; white-space: nowrap;
  font: 600 var(--type-label) var(--mono); box-shadow: 0 2px 12px rgba(0, 0, 0, .45); }
.p2-run-who::after { content: "\00b7"; margin-left: 8px; opacity: .7; }
.p2-run-doing { overflow: hidden; text-overflow: ellipsis; }
.p2-run-keys { position: absolute; left: 14px; bottom: 14px; display: flex; gap: 4px; }
.p2-run-keys kbd { padding: 3px 8px; border: 1px solid var(--p2); border-radius: 6px; background: var(--surface); color: var(--ink);
  font: 600 var(--type-label) var(--mono); transition: background var(--step), color var(--step); }
.p2-run-keys kbd.down { background: var(--p2); color: #fff; }
.p2-run-watch { position: absolute; right: 14px; bottom: 14px; display: grid; gap: 2px; max-width: 55%; padding: 6px 10px;
  border: 1px solid var(--p2); border-radius: 8px; background: color-mix(in srgb, var(--surface) 88%, transparent); font-size: var(--type-label); }
.p2-run-row { display: flex; justify-content: space-between; gap: 12px; min-width: 0; }
.p2-run-row span { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p2-run-row b { font-weight: 600; color: var(--ink); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .p2-run-keys kbd { transition: none; } }
/* PLAYER TWO PLAYED YOUR GAME (the seams pass): what player two did and saw reads as player two's, in its color, one
   line each, beside its answer -- not a centered log line */
.msg.sys.run { align-self: flex-start; text-align: left; white-space: pre-line; color: var(--ink-2); padding: 8px 12px;
  border-left: 2px solid var(--p2); background: color-mix(in srgb, var(--p2) 7%, transparent); border-radius: 0 8px 8px 0; }
.msg.sys.thinking { display: flex; align-items: center; gap: 10px; font: 400 var(--type-body) var(--body); color: var(--ink); text-align: left; align-self: flex-start; }
.msg.sys.thinking::before { content: ""; width: 9px; height: 9px; background: var(--p2); flex: none; animation: spawn-in var(--step) both; }
/* the wait's clock and step (studio.js askClock): quiet beside the line it rides on */
.msg.sys.thinking .p2-live { color: var(--muted); font: 400 var(--type-small) var(--mono); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* the dry run is the studio's own check, not player two thinking: its marker is quiet (2026-11-03 review: royal is player two only) */
#dry-run-result .msg.sys.thinking::before { background: var(--muted); }
.msg.failed { opacity: .6; }
.msg .row { margin-top: 10px; }
.hunks { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.hunk { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: var(--surface); }
.hunk.dropped { opacity: .5; }
.hunk-head { display: flex; align-items: center; gap: 10px; padding: 7px 10px; background: var(--panel-2); }
.hunk-head span { flex: 1; min-width: 0; font: 600 var(--type-small) var(--body); color: var(--ink); }
.hunk-head label { display: flex; align-items: center; gap: 6px; font: 600 var(--type-small) var(--body); color: var(--ink); cursor: pointer; }
.hunk-head input { width: 16px; height: 16px; margin: 0; }
.hunk-lines { padding: 5px 0; font: var(--type-small)/1.6 var(--mono); overflow-x: auto; }
.hunk-lines div { white-space: pre; padding: 0 10px; }
.hunk-lines .same { color: var(--muted); }
.hunk-as-blocks { padding: 6px 10px 8px; }
.hunk-blocks-note { margin: 0 0 4px; font: 600 var(--type-small) var(--body); color: var(--muted); }
.p2-blocks { overflow: auto; max-height: 360px; padding: 4px; border-radius: 6px; background: var(--panel); }
/* Blockly's own rules place its svg absolutely; a drawing stays in its card, and takes no pointer: it is a picture */
.p2-blocks { position: relative; }
.p2-blocks svg { display: block; max-width: none; position: static !important; pointer-events: none; }
.p2-blocks.out { opacity: .6; }
.hunk-as-blocks .hunk-lines { padding: 2px 0 0; }
.hunk-as-blocks .hunk-lines div { padding: 0; }
.hunk-as-blocks .p2-blocks + .hunk-blocks-note { margin-top: 8px; }
.hunk-lines .mark { user-select: none; -webkit-user-select: none; }
.hunk-lines .add { background: var(--accent-soft); color: var(--ink); }
.hunk-lines .del { background: rgba(255, 92, 122, .1); color: var(--ink); }
.hunk.dropped .add { text-decoration: line-through; }
.change-lead { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.change-lead .btn, .change-actions .try-changes { white-space: normal; text-align: center; }
.change-how { margin: 0; font-size: var(--type-small); color: var(--muted); }
.gate-note { margin: 0; font-size: var(--type-small); color: var(--caution); }
.change-actions { display: flex; gap: 8px; align-items: center; }
.change-result { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.change-result.kept { color: var(--accent); }
.fgo-grew { margin: 4px 0 0; padding: 6px 10px; border-left: 3px solid var(--accent); background: var(--accent-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0; font: 600 var(--type-small)/1.4 var(--body); color: var(--ink); }
.composer { flex: none; padding: 12px 20px 16px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.prompts { display: flex; flex-wrap: wrap; gap: 6px; }
.prompts:empty { display: none; }
.prompt { min-height: 30px; padding: 0 11px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--ink);
  font-size: var(--type-small); text-align: left; transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease); }
.prompt:hover { border-color: var(--p2); color: var(--p2-hover); }
.say-row { display: flex; gap: 8px; }
/* a fluency growth opportunity: what the studio noticed in an ask, before player two reads it (studio.js::showFgo) */
.fgo-card { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; border: 1px solid var(--p2); border-radius: 10px; }
.fgo-card[hidden] { display: none; }
.fgo-frame { margin: 0; font: 400 var(--type-small)/1.45 var(--body); color: var(--p2-hover); }
.fgo-frame[hidden] { display: none; }
.fgo-model { padding: 8px 10px; border-radius: var(--radius-sm); background: var(--p2-wash); border-left: 3px solid var(--p2); }
.fgo-model[hidden] { display: none; }
.fgo-model b { display: block; font: 700 var(--type-small) var(--body); color: var(--ink); }
.fgo-model span { display: block; font: 400 var(--type-small)/1.45 var(--body); color: var(--ink-2); }
.fgo-model q { display: block; margin: 4px 0 0; font: 500 var(--type-small)/1.45 var(--body); color: var(--ink); }
.fgo-model summary { cursor: pointer; font: 400 var(--type-small) var(--body); color: var(--p2-hover); }
.fgo-model-h { margin: 0 0 2px; font: 400 var(--type-label) var(--pixel); text-transform: lowercase; color: var(--p2-hover); }
.fgo-said { margin: 0; font-size: var(--type-body); color: var(--ink); }
.fgo-tip { margin: 0; font-size: var(--type-small); color: var(--muted); }
.fgo-items { max-height: 180px; overflow-y: auto; }
.fgo-items .prompt[aria-pressed=true] { border-color: var(--p2); box-shadow: inset 0 0 0 1px var(--p2); color: var(--ink); font-weight: 600; }
.fgo-row { display: flex; flex-wrap: wrap; gap: 8px; }
.fgo-line { flex: 1 1 100%; display: grid; gap: 4px; margin: 0 0 8px; font: 400 var(--type-small) var(--body); color: var(--ink-2); }
.fgo-field { min-height: 36px; padding: 0 10px; border: 1px solid var(--line-2); border-radius: var(--radius-sm); background: var(--well);
  color: var(--ink); font: 400 var(--type-body) var(--body); }
.fgo-field:focus { outline: 2px solid var(--p2); outline-offset: 1px; border-color: var(--p2); }
.fgo-field::placeholder { color: var(--faint); }
.fgo-again { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 8px 0 0; padding: 8px 10px;
  border-left: 3px solid var(--caution); background: rgba(255, 181, 71, .08); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
/* plain mode: today's goal, one quiet line under player two's head; the Try buttons sit under the newest answer */
.p2-goal { margin: 0; padding: 6px 12px; font: 500 var(--type-small)/1.4 var(--body); color: var(--muted); border-bottom: 1px solid var(--line); }
.p2-try { margin: 10px 0 0; }
.p2-next { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 10px 0 0; padding: 10px 12px;
  border-radius: var(--radius-sm); background: var(--accent-soft); border: 1px solid rgba(198, 244, 50, .3); }
.p2-next p { margin: 0; flex: 1 1 240px; font: 500 var(--type-small)/1.5 var(--body); color: var(--ink); }
.p2-next b { display: block; font: 400 var(--type-label) var(--pixel); letter-spacing: .06em; text-transform: lowercase; color: var(--accent); margin: 0 0 2px; }
.fgo-again p { margin: 0; flex: 1 1 220px; font: 600 var(--type-small)/1.4 var(--body); color: var(--ink); }
/* THE BEACON (beacon.py): caution amber, the one place it is spent in player two's rail; lit, it breathes */
.beacon-btn .icon, .p2-open .beacon-btn .icon { color: var(--muted); }
.beacon-btn.stuck .icon, .beacon-btn.lit .icon { color: var(--caution); }
.beacon-btn.lit { border-color: var(--caution); animation: beacon-breathe 2.4s var(--ease) infinite; }
@keyframes beacon-breathe { 50% { box-shadow: 0 0 14px 2px rgba(255, 181, 71, .45); } }
@media (prefers-reduced-motion: reduce) { .beacon-btn.lit { animation: none; box-shadow: 0 0 10px 1px rgba(255, 181, 71, .4); } }
.beacon-card { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border: 1px solid var(--caution); border-radius: 10px; background: rgba(255, 181, 71, .06); }
.beacon-card[hidden], .beacon-card [hidden] { display: none; }
.beacon-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.beacon-head { margin: 0; font-size: var(--type-body); font-weight: 600; color: var(--caution); }
.beacon-tip { margin: 0; font-size: var(--type-small); color: var(--ink-2); }
.beacon-tip:empty { display: none; }
.beacon-tried ol { margin: 2px 0 0; padding-left: 20px; font-size: var(--type-small); color: var(--ink-2); }
.beacon-form { display: flex; flex-direction: column; gap: 4px; }
.beacon-form label { font-size: var(--type-small); color: var(--ink-2); }
.beacon-form textarea { resize: vertical; min-height: 40px; padding: 6px 8px; background: var(--well); color: var(--ink); border: 1px solid var(--line); border-radius: 8px; font: inherit; font-size: var(--type-small); }
.beacon-row { display: flex; flex-wrap: wrap; gap: 8px; }
.beacon-card .btn.beacon-go { background: var(--caution); border-color: var(--caution); color: var(--accent-ink); }
.beacon-card .btn.beacon-go:hover { background: #ffc773; border-color: #ffc773; }
.beacon-card .btn.beacon-go .icon { color: var(--accent-ink); }
.ask-mode { display: flex; gap: 6px; }
/* UNDER THE ASK BOX (the pretty pass): how player two helps, where the ask is sent from */
.ask-tools { display: flex; align-items: center; gap: 6px; min-width: 0; }
.ask-mode .part { height: 28px; max-width: none; padding: 0 10px; }
/* agency mode: the student's own rules for player two, one game at a time (studio.js::loadRules) */
.my-rules { margin: -2px 0 4px; font-size: var(--type-small); }
.my-rules summary { cursor: pointer; color: var(--muted); }
.my-rules[open] summary { color: var(--ink); }
.my-rules p { margin: 6px 0; color: var(--muted); }
.my-rules textarea { width: 100%; box-sizing: border-box; resize: vertical; min-height: 64px; font: var(--type-small)/1.45 var(--body); }
.my-rules textarea:focus-visible { border-color: var(--p2); }
.my-rules .rules-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.class-row { display: flex; flex-direction: column; gap: 8px; }
.join-say { margin: 0; font-size: var(--type-body); color: var(--ink); }
.say-row { align-items: flex-end; }
/* the ask box grows with what is typed, up to six lines, then scrolls (studio.js::fitIdea) */
.say-row textarea { flex: 1; min-width: 0; resize: none; overflow-y: auto; max-height: 160px; font: var(--type-body)/1.45 var(--body); }
.say-row textarea:focus-visible { border-color: var(--p2); }
.ask-notice { margin: 0; font-size: var(--type-small); color: var(--muted); }
/* the notice and "What is kept" share one line; opened, the whole story takes the rail's width under them */
.p2-fine { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.p2-fine .ask-notice:empty { display: none; }
.p2-fine .privacy[open] { flex-basis: 100%; }
.pic-row .pic-note { display: none; }
.pic-row:has(.pic-preview:not([hidden])) .pic-note { display: inline; }
/* a picture for player two: the add link, the rule, and the one picture going with the next question */
.pic-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; font-size: var(--type-small); color: var(--muted); }
.pic-row[hidden] { display: none; }
.pic-preview { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 6px; }
.pic-preview[hidden] { display: none; }
.pic-preview img, .msg .pic { display: block; max-width: 72px; max-height: 72px; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.msg .pic { max-width: 120px; max-height: 120px; }
/* several pictures (report #268): a strip of thumbnails, each with its remove in its corner */
.pic-one { position: relative; display: block; }
.pic-x { position: absolute; top: -6px; right: -6px; display: grid; place-items: center; width: 22px; height: 22px; padding: 0;
  border-radius: 50%; border: 1px solid var(--line-2); background: var(--panel-2); color: var(--ink); cursor: pointer; }
.pic-x:hover, .pic-x:focus-visible { border-color: var(--p2); color: var(--p2-hover); }
.pic-x .icon { width: 12px; height: 12px; }
.msg .pics { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 0; }
.privacy { font-size: var(--type-small); color: var(--muted); }
.privacy summary { cursor: pointer; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.privacy p { margin: 6px 0 0; line-height: 1.5; max-width: 64ch; }
.live-note button { padding: 0; border: 0; background: none; color: var(--ink); font: inherit; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.live-note button:hover { color: var(--ink); }
/* LIVE SHARING READS (2026-11-03 review): the rail line in reading ink, not the fine print's, and its state as a chip
   beside the icon-only switch. Spring green, a state and not an action: lime is player one, royal is player two only */
.live-note { color: var(--ink-2); }
.live-chip { display: inline-flex; align-items: center; gap: 5px; padding: 0 7px; border: 1px solid var(--line-2); border-radius: 999px;
  font: 400 var(--type-label)/1.7 var(--mono); text-transform: lowercase; color: var(--muted); vertical-align: 1px; }
.live-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.live-chip[data-state="on"] { color: var(--genesis-2); border-color: rgba(62, 230, 160, .45); }
.live-chip[data-state="on"]::before { background: var(--genesis-2); box-shadow: 0 0 6px var(--genesis-2); }
/* the chip and its two buttons on one row, the words the column's full width under them */
.live-told { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 4px 8px; margin: 0 0 12px;
  padding: 10px 10px 12px 14px; background: var(--panel-2); color: var(--ink); border: 1px solid rgba(62, 230, 160, .45); border-radius: var(--radius-sm); }
.live-told[hidden] { display: none; }
.live-told .live-chip { grid-column: 1; justify-self: start; }
.live-told #live-told-stop { grid-column: 3; }
.live-told #live-told-close { grid-column: 4; }
.live-told p { grid-column: 1 / -1; grid-row: 2; margin: 0; font-size: var(--type-small); line-height: 1.4; }
#chat-off { margin: 0; padding: 10px 14px; border: 1px dashed var(--line-2); border-radius: var(--radius-sm); }

/* ---- buttons: 10px corners; lime is the one main action; heights from tokens.css ---- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 10px; min-height: var(--btn-h); padding: 0 var(--btn-pad);
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: 600 var(--type-body) var(--body); text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease), color var(--fast) var(--ease), transform var(--fast) var(--ease); }
.btn:hover { border-color: var(--muted); color: var(--ink); }
.btn:active { transform: scale(.985); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }
.btn.two { background: transparent; border: 1.5px solid var(--p2); color: var(--p2); }
.btn.two::before { content: ""; width: 9px; height: 9px; background: currentColor; flex: none; }
.btn.two:has(> .icon)::before { content: none; }   /* the robot is player two's mark where an icon is drawn */
.btn.two:hover { color: var(--p2-hover); border-color: var(--p2-hover); background: var(--p2-soft); }
.btn.small { min-height: var(--btn-h-small); padding: 0 var(--btn-pad-small); font-size: var(--type-small); }
.btn.tiny { min-height: var(--btn-h-small); padding: 0 var(--btn-pad-small); font-size: var(--type-small); flex: none; }
.btn.tiny[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.btn.quiet { background: transparent; border-color: transparent; color: var(--muted); }
.btn.quiet:hover { color: var(--ink); border-color: transparent; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .35; cursor: default; transform: none; }
/* Undo is the one button a student hunts for in a hurry, so it is the one amber control on the bench. */
.btn.undo-button { border-color: var(--caution); color: var(--caution); font-weight: 700; }
.btn.undo-button:hover:not(:disabled) { background: rgba(255, 181, 71, .12); border-color: var(--caution); color: var(--caution); }
/* Redo sits joined to Undo under the game; Undo's amber edge stays on top of the seam. */
.undo-pair .undo-button { position: relative; z-index: 1; }
/* THE HISTORY (Maestro, 2026-10-19, option B): Undo, Redo and the step count at the far end of the row under
   the game, away from Restart; the count opens every step in words above it */
.history-wrap { position: relative; flex: none; display: flex; }
.history-open { min-width: 34px; padding: 0 8px; font: 600 var(--type-small) var(--mono); color: var(--caution); }
.history-open[aria-expanded="true"] { background: rgba(255, 181, 71, .12); border-color: var(--caution); }
.history { position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 20; width: min(380px, calc(100vw - 32px));
  max-height: min(440px, 62vh); display: flex; flex-direction: column; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: 0 18px 50px -12px rgba(0, 0, 0, .7); }
.history[hidden] { display: none; }
.history-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.history-head .eyebrow { color: var(--caution); }
.history-head #history-said { margin-left: auto; font-size: var(--type-label); }
.history-steps { overflow-y: auto; padding: 4px 0; }
.history-step { display: grid; grid-template-columns: 18px minmax(0, 1fr) auto auto; align-items: center; gap: 8px; padding: 5px 10px;
  font-size: var(--type-small); }
.history-step:hover { background: var(--panel-2); }
.history-step > .icon { width: 16px; height: 16px; color: var(--muted); }
.history-step .who { color: var(--accent); font-weight: 600; }
.history-step.p2 .who, .history-step.p2 > .icon { color: var(--p2); }
.history-step.ahead { opacity: .55; }
.history-ask { display: block; color: var(--muted); font-size: var(--type-label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.history-when { color: var(--muted); font: 400 var(--type-label) var(--mono); white-space: nowrap; }
.history-step .history-go { min-height: 26px; width: 30px; padding: 0; }
.history-here { margin: 2px 10px; padding-top: 2px; border-top: 1px solid var(--caution); color: var(--caution); text-align: center;
  font: 600 var(--type-label) var(--mono); }
.history-foot { margin: 0; padding: 6px 10px; border-top: 1px solid var(--line); color: var(--muted); font-size: var(--type-label); }
.map-history { margin-bottom: 6px; }
.round-here { font-size: var(--type-label); }
/* a narrow screen: the run controls on the first line, the switches and the history on the second */
/* left-aligned, and two lines, not a staircase (2026-11-03 second review: in the code room the run controls sat alone
   on the left, the switches on a right-aligned line and the history on a third): the count shows its number, its
   word in the tip, as at the thumbnail, so the switches and the history share the second line */
@container screen (max-width: 399px) { .screen-row { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; gap: 6px 8px; }
  .screen-status { flex: 1 1 100%; }
  .screen-row .history-open .unit { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } }
.row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.link { background: none; border: 0; padding: 0; font: 400 var(--type-small) var(--mono); color: var(--accent); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.quiet-link { background: none; border: 0; padding: 4px; color: var(--muted); font: 400 var(--type-small) var(--body); text-decoration: underline;
  text-underline-offset: 3px; white-space: nowrap; cursor: pointer; }
.quiet-link:hover { color: var(--ink); }
.mono-link { background: none; border: 0; padding: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; white-space: nowrap; }
.mono-link:hover { color: var(--ink); }
.mono-note { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.plain-link { font: 600 var(--type-small) var(--body); color: var(--ink); text-decoration: none; white-space: nowrap; }
.plain-link:hover { color: var(--ink); }

/* ---- inputs ---- */
input[type=text], input[type=password], textarea {
  width: 100%; font-size: var(--type-body); color: var(--ink); background: var(--well);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 10px 12px; transition: border-color var(--fast) var(--ease); }
input[type=text]:focus, input[type=password]:focus, textarea:focus { border-color: var(--accent); outline: none; }
textarea { font: var(--type-small)/1.6 var(--mono); resize: vertical; tab-size: 2; }
.code-input { font: 600 var(--type-body) var(--mono) !important; color: var(--accent) !important; }
.note { font-size: var(--type-small); color: var(--muted); margin: 8px 0 0; }
.note-text { margin: 0 0 14px; font-size: var(--type-body); color: var(--muted); max-width: 60ch; }
.warn-note { color: var(--caution); }

/* ---- 01 pick ---- */
.games { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); margin: 0 0 4px; }
.game-card { position: relative; display: flex; align-items: center; gap: 14px; padding: 14px 16px; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: var(--radius); text-align: left; color: var(--ink); --bi: -5px; transition: border-color var(--fast) var(--ease); }
.game-card:hover { border-color: var(--muted); }
.tile { flex: none; width: 48px; height: 48px; border-radius: 8px; display: grid; place-items: center; overflow: hidden; }
.tile img { width: 28px; height: 28px; image-rendering: pixelated; object-fit: contain; }
.tile .box { width: 18px; height: 18px; border: 1.5px dashed rgba(255, 255, 255, .5); }
.game-card .what { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.game-card b { font: 600 var(--type-lead) var(--body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game-card .when, .game-card .times { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.game-card.here .when { color: var(--accent); }
.game-card .del { position: absolute; right: 8px; top: 6px; opacity: 0; transition: opacity var(--fast) var(--ease); }
.game-card:hover .del, .game-card .del:focus-visible { opacity: 1; }
/* the sign-in panel and the save marker: where a student's games are kept (saves.py) */
/* the gate: signed out, the sign-in is the whole page (studio.js::renderGate) */
.gate { position: fixed; inset: 0; z-index: 50; display: grid; place-items: center; padding: 16px; background: var(--surface); }
.gate[hidden] { display: none; }
/* signed in: the sign-in dissolves off the studio (studio.js dissolveGate) */
.gate.dissolving { opacity: 0; pointer-events: none; transition: opacity 280ms var(--ease, ease); }
.gate-card { position: relative; z-index: 1; width: min(100%, 560px); }
.gate-ripple { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* the mini hero: the word and the mark, large, on the spawn point's light */
.gate-hero { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 20px; margin-bottom: 36px; }
.gate-hero::before { content: ""; position: absolute; inset: -80px -60px; z-index: -1; pointer-events: none;
  background: radial-gradient(closest-side circle at 84% 50%, var(--bloom-1), transparent 45%),
    radial-gradient(closest-side circle at 84% 50%, var(--bloom-2), transparent); }
.gate-word { min-width: 0; }
.gate-hero .brand { font-size: clamp(64px, 17vw, 112px); }
.gate-tag { margin: 10px 0 0; font: 400 var(--type-small)/1.4 var(--pixel); letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.gate-mark { width: clamp(84px, 22vw, 136px); height: auto; }
.gate-mark .frame { stroke-width: 2.4; }
.gate-form { display: grid; gap: 8px; }
.gate-form label { font: 400 var(--type-label)/1.4 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.gate-form input + label { margin-top: 10px; }
.gate-form input { min-height: 52px; font-size: var(--type-lead); }
.gate-form .lede { margin: 6px 0 4px; font-size: var(--type-small); color: var(--muted); }
.gate-form .account-error { margin: 0; }
/* the gate's one lime action keeps its words (studio.js wordless: "Help, Sign in, Add changes"), full width */
#gate .gate-form .btn.primary { width: 100%; height: 52px; min-height: 52px; margin-top: 4px; justify-content: center; font-size: var(--type-lead); }
.gate-card .note { margin: 18px 0 0; text-align: center; font-size: var(--type-small); color: var(--muted); }
/* the studio could not start (studio.js showBroken): the hero stays, the words and Reload take the form's place */
.gate-broke { display: grid; gap: 10px; }
.gate-broke-say { margin: 0; font-size: var(--type-lead); color: var(--ink); }
.gate-broke-why { margin: 0 0 6px; font-size: var(--type-small); color: var(--muted); overflow-wrap: anywhere; }
.gate-broke-why:empty { display: none; }
.gate-broke .btn.primary { width: 100%; min-height: 52px; }
.gate-card .note a { color: var(--accent); }
.account { margin: 0; }
.account-shelf { margin: 0 0 18px !important; padding: 12px 14px; background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius); }
/* Sign out sits at the note's right edge, never left dangling on the sentence's last line (usability pass, 2026-10-22) */
.account-note { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 10px; font-size: var(--type-body); color: var(--ink-2); }
.account-note > span { flex: 1; min-width: 0; }
.account-note #signout { flex: none; }
.account-note strong { color: var(--ink); }
#account-out .account-note strong { color: var(--caution); }
.account-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.account-form input[type=text], .account-form input[type=password] { flex: 1 1 160px; min-width: 0; }
.account-first { flex-basis: 100%; display: flex; gap: 8px; align-items: center; font-size: var(--type-small); color: var(--muted); }
.account-say { flex-basis: 100%; font-size: var(--type-small); color: var(--caution); }
.account-error { margin: 8px 0 0; font-size: var(--type-small); color: var(--bad); }
.account-shelf { margin: 12px 0 0; font-size: var(--type-small); }
.account-shelf ul { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 6px; }
.account-shelf li { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; }
.account-shelf li b { color: var(--ink); }
.account-shelf li .when { color: var(--muted); }
.game-card .where { color: var(--caution); }
.save-mark { min-height: 32px; padding: 0 10px; background: transparent; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: 400 var(--type-small) var(--mono); color: var(--muted); cursor: pointer; white-space: nowrap; }
.save-mark:hover { border-color: var(--muted); color: var(--ink); }
.save-mark[data-state="saved"] { color: var(--accent); border-color: transparent; }
.save-mark[data-state="behind"] { color: var(--caution); border-color: var(--caution); }
@media (max-width: 760px) { .save-mark { max-width: 9em; overflow: hidden; text-overflow: ellipsis; } }
/* a phone's bar keeps the icons and tucks the words away (still read out, and the sentence is the title) */
@media (max-width: 560px) { .bar-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .save-mark, .bar-help { width: 34px; padding: 0; justify-content: center; } }
/* THE STARTERS ARE TILES (the pretty pass, M7): 23 cards in one column put the first at the fold and the last 2,000px
   down at 1366 x 768; two or three across, art and name and one line, and the full line in the card's tip */
.models { display: grid; gap: 8px; grid-template-columns: repeat(auto-fill, minmax(156px, 1fr)); }
.model { position: relative; display: flex; gap: 10px; align-items: center; padding: 8px 10px; min-height: 60px; background: var(--panel-2); border: 0;
  border-radius: var(--radius); text-align: left; color: var(--ink); --bi: -5px; transition: background var(--fast) var(--ease); }
.model:hover { background: var(--line); }
.model .tile { width: 40px; height: 40px; }
.model .tile img { width: 26px; height: 26px; }
.model > span:last-child, .model .what { min-width: 0; }
.model b { display: block; font: 600 var(--type-body)/1.2 var(--body); }
/* TWO LINES OF WHAT IT IS (wchesher, 2026-10-25, "do all of it": the starters cut their own line at one, "Start here. A
   tiny ...", "Slide along the b...", so a student picking could not read what each one was). Two lines say it for
   every starter at 1366; a longer one keeps its whole line in the card's tip.) Measured 2026-11-03: two lines still cut
   8 starters at 1366 and 5 at 1024 mid-sentence ("Start here. A tiny game whose..."), so the line is shown whole. */
.model small { display: block; margin-top: 2px; font-size: var(--type-label); line-height: 1.35; color: var(--muted); }
.model.suggested small { white-space: normal; }

/* ---- 01 pick: a design session. The card offers it; the starters player two suggests wear its royal outline,
   with a mono line saying why, and the name box and Start sit under the one picked. ---- */
.design-start { margin: 28px 0 0; padding: 14px 16px 16px; background: var(--panel-2); border: 1px solid var(--p2); border-radius: var(--radius); }
.design-start[hidden] { display: none; }
.design-start h2 { margin: 0 0 6px; font: 600 var(--type-lead)/1.25 var(--body); color: var(--ink); }
.design-start p { margin: 0 0 14px; font-size: var(--type-small); line-height: 1.45; color: var(--ink-2); }
.model.suggested { outline: 2px solid var(--p2); outline-offset: 2px; }
.model.suggested[aria-pressed="true"] { background: var(--p2-wash); }
.model .credit { display: block; margin-top: 6px; font: 400 var(--type-label)/1.4 var(--mono); color: var(--muted); }
.design-credit { margin: -18px 0 22px; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.model .suggests { display: block; margin-top: 6px; font: 400 var(--type-label)/1.4 var(--mono); color: var(--p2); }
.design-name { grid-column: 1 / -1; display: flex; gap: 8px; }
.design-name input { flex: 1; min-width: 0; }
.msg.hello .chips { margin-top: 10px; }

/* ---- 02 design ---- */
.design-line { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; padding: 16px 0; border-top: 1px solid var(--line); }
.design-line > span { font: 400 var(--type-small) var(--pixel); color: var(--accent); }
.design-line textarea { display: block; width: 100%; padding: 11px 14px; font: 400 var(--type-lead)/1.4 var(--body); background: var(--surface); resize: none; overflow: hidden; field-sizing: content; min-height: 0; }
.design-filled { margin: 18px 0 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.design-ask { margin-top: 18px; }

/* ---- 03 make: the knob panel and the room cards ---- */
.knob-panel { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 18px 28px; padding: 18px 20px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius); }
.knob-panel:empty { display: none; }
.knob { display: grid; grid-template-columns: 1fr auto auto; gap: 8px 10px; align-items: baseline; font-size: var(--type-body); }
/* the for-players switch: quiet until it is on, then lime */
.knob-players { align-self: center; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0;
  border: 1px solid transparent; border-radius: 8px; background: none; color: var(--faint); cursor: pointer; }
.knob-players:hover, .knob-players:focus-visible { border-color: var(--line-2); color: var(--ink); }
.knob-players[aria-pressed="true"] { color: var(--accent); border-color: var(--accent-soft); }
/* the for-players switch shows on the knob a pointer or the keyboard is on, or when it is on (the pretty pass) */
@media (hover: hover) { .knob .knob-players[aria-pressed="false"] { opacity: 0; transition: opacity var(--fast) var(--ease); }
  .knob:is(:hover, :focus-within) .knob-players { opacity: 1; } }
.knob-players .icon { width: 15px; height: 15px; }
.knob label { color: var(--ink); }
.knob output { font: 600 var(--type-small) var(--mono); color: var(--accent); }
/* the lime value is a box you can type in (studio.js buildNumber): it reads as the value until it is clicked */
.knob .knob-num { width: 7ch; font: 600 var(--type-small) var(--mono); color: var(--accent); background: transparent; border: 1px solid transparent;
  border-radius: var(--radius-sm); padding: 1px 4px; text-align: right; -moz-appearance: textfield; }
.knob .knob-num::-webkit-inner-spin-button, .knob .knob-num::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.knob .knob-num:hover { border-color: var(--line); }
.knob .knob-num:focus { border-color: var(--accent); background: var(--panel-2); outline: none; }
.knob input[type=text] { grid-column: 1 / -1; }
.knob .scale { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 8px; font: 400 var(--type-label) var(--mono); color: var(--muted); }
.knob .scale code { font-size: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* THE BLOCK METER (a class idea, 2026-10-22; Maestro: "the blocks are a feature"). The track is a row of blocks
   that light lime up to the value, like a health bar, and a slim ink block rides on it, cut out by a ring of the
   ground. The gaps are clear, so it sits on any ground. The blocks stay Spawn's; the meter makes them the design. */
.knob input[type=range], .sound-knob input[type=range] { grid-column: 1 / -1; width: 100%; height: 22px; margin: 0; background: transparent;
  -webkit-appearance: none; appearance: none; cursor: pointer; }
.knob input[type=range]::-webkit-slider-runnable-track, .sound-knob input[type=range]::-webkit-slider-runnable-track { height: 8px;
  background: var(--meter-lit) 0 0 / var(--fill, 50%) 100% no-repeat, var(--meter-dark); }
.knob input[type=range]::-moz-range-track, .sound-knob input[type=range]::-moz-range-track { height: 8px;
  background: var(--meter-dark); }
.knob input[type=range]::-moz-range-progress, .sound-knob input[type=range]::-moz-range-progress { height: 8px;
  background: var(--meter-lit); }
.knob input[type=range]::-webkit-slider-thumb, .sound-knob input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 20px;
  margin-top: -6px; background: var(--ink); border: 0; border-radius: 0; box-shadow: 0 0 0 3px var(--surface); }
.knob input[type=range]::-moz-range-thumb, .sound-knob input[type=range]::-moz-range-thumb { width: 12px; height: 20px; background: var(--ink); border: 0;
  border-radius: 0; box-shadow: 0 0 0 3px var(--surface); }
.knob input[type=range]:is(:hover, :focus-visible)::-webkit-slider-thumb, .sound-knob input[type=range]:is(:hover, :focus-visible)::-webkit-slider-thumb { background: var(--accent-hover); }
.knob input[type=range]:is(:hover, :focus-visible)::-moz-range-thumb, .sound-knob input[type=range]:is(:hover, :focus-visible)::-moz-range-thumb { background: var(--accent-hover); }
.knob-grid { display: grid; gap: 16px 32px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
/* sliders in groups: each group a section that folds, across the whole panel */
.knob-group { grid-column: 1 / -1; border-top: 1px solid var(--line); padding-top: 14px; }
.knob-group summary { display: flex; align-items: baseline; gap: 10px; cursor: pointer; list-style: none; }
.knob-group summary::-webkit-details-marker { display: none; }
.knob-group summary::before { content: ""; width: 0; height: 0; border-left: 5px solid var(--muted); border-top: 4px solid transparent; border-bottom: 4px solid transparent; transition: transform var(--fast) var(--ease); }
.knob-group[open] summary::before { transform: rotate(90deg); }
.knob-group summary .eyebrow { margin: 0; }
.knob-group summary .count { font: 400 var(--type-label) var(--mono); color: var(--faint); }
.knob-group summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.knob-group .knob-grid { margin-top: 14px; }
/* add a slider: one quiet button, opening a small form under it */
.add-slider { grid-column: 1 / -1; display: grid; gap: 12px; justify-items: start; }
.add-slider-form { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px 14px; align-items: center; width: 100%; max-width: 520px; }
.add-slider-form label { color: var(--ink-2); font-size: var(--type-small); }
.add-slider-form select, .add-slider-form input { min-width: 0; min-height: 34px; padding: 0 10px; background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-sm); font: 400 var(--type-small) var(--body); }
.add-slider-range { display: flex; gap: 8px; align-items: center; color: var(--muted); font-size: var(--type-small); }
.add-slider-range input { width: 7em; }
.add-slider-go { display: flex; gap: 8px; }
.add-slider-form .note-text { grid-column: 1 / -1; margin: 0; }
.colours { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 10px; }
.colour-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.swatch-pick { width: 34px; height: 34px; border-radius: 8px; border: 2px solid transparent; padding: 0; cursor: pointer; }
.swatch-pick[aria-pressed="true"] { border-color: var(--ink); }
.swatch-pick.neon, .pop-dot { box-shadow: 0 0 8px currentColor; }
.pop-strip { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 6px 8px; border: 1px solid var(--line); border-radius: 10px; width: max-content; max-width: 100%; }
.pop-dot { width: 22px; height: 22px; border-radius: 6px; border: 1px solid rgba(255, 255, 255, .25); padding: 0; cursor: pointer; }   /* one swatch shape (the pretty pass) */
.flash-switch { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; padding: 0; border-radius: 8px;
  border: 1px solid var(--line); background: none; color: var(--ink); cursor: pointer; }
.flash-switch[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.flash-switch[aria-pressed="true"] .icon { color: var(--accent-ink); filter: none; }
.flash-second { width: 24px; height: 24px; border: 0; padding: 0; background: none; cursor: pointer; }
.flash-second[hidden] { display: none; }
.colour-knob.picked { outline: 2px solid var(--accent); outline-offset: 1px; }
.colour-knob .flash-to { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
.colour-any { width: 34px; height: 34px; border: 0; padding: 0; background: none; cursor: pointer; }
.colour-knob { display: inline-flex; align-items: center; gap: 8px; padding: 4px 10px 4px 4px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--panel-2); font-size: var(--type-small); }
.colour-knob input { width: 26px; height: 26px; border: 0; padding: 0; background: none; cursor: pointer; }
/* the doors come first on make, so they are compact: the name on top, what is left under it, the
   sentence in the title. One shape for all four: same height, title and status on the same lines. */
.room-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.room-follow { margin: 10px 0 0; font-size: var(--type-small); }
.room-follow .quiet-link { padding: 0; }
.room-card { display: flex; flex-direction: column; justify-content: flex-start; gap: 6px; min-width: 0; padding: 12px 14px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  text-align: left; color: var(--ink); text-decoration: none; transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease); }
.room-card:hover { border-color: var(--muted); background: var(--panel-2); color: var(--ink); }
.room-card .what { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.room-card b { display: block; font: 600 var(--type-lead) var(--body); letter-spacing: -.01em; white-space: nowrap; }
.room-card small { display: none; }
/* a status wraps rather than widening the card: on a phone the longest one ("drag pictures onto your game") pushed make
   past the screen's edge (the seams pass) */
.room-card .status { display: flex; align-items: flex-start; gap: 8px; font: 400 var(--type-small) var(--mono); color: var(--caution); min-width: 0; }
.room-card .status::before { content: ""; width: 7px; height: 7px; margin-top: .5em; background: currentColor; flex: none; }
.room-card .status.pieces { white-space: normal; align-items: flex-start; }
.room-card .status.pieces::before { margin-top: .45em; }
.room-card .status.done { color: var(--accent); }

/* ---- the rooms: slots on the left, the maker on the right ---- */
.maker-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 24px; align-items: start; }
.slot-col { display: flex; flex-direction: column; gap: 8px; max-width: 320px; }
.slot-note { margin: 8px 2px 0; font-size: var(--type-small); color: var(--muted); line-height: 1.45; }
.slots { display: flex; flex-direction: column; gap: 8px; }
.slot { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--panel-2);
  text-decoration: none; color: inherit; text-align: left; width: 100%; min-width: 0; transition: border-color var(--fast) var(--ease); }
.slot:hover { border-color: var(--muted); color: inherit; }
.slot.empty { border-style: dashed; }
.slot.now { border-color: var(--accent); border-style: solid; }
.slot .ic { width: 40px; height: 40px; border-radius: 6px; flex: none; display: grid; place-items: center; overflow: hidden;
  background: repeating-conic-gradient(var(--panel-2) 0 25%, var(--panel) 0 50%) 0 0 / 10px 10px; border: 1px solid var(--line); }
.slot .ic canvas, .slot .ic img { width: 30px; height: 30px; image-rendering: pixelated; object-fit: contain; }
.slot .ic .empty-box { width: 22px; height: 22px; border: 1.5px dashed var(--line-2); }
.slot .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); flex: none; }
.slot .dot.off { background: transparent; border: 1.5px dashed var(--line-2); }
/* the row's on / off switch (studio.js slotSwitch): beside the row, the same pressed look as the game's tool buttons */
.slot-wrap { display: flex; align-items: stretch; gap: 6px; }
.slot-wrap > .slot { flex: 1; min-width: 0; }
.slot-switch { flex: none; width: 40px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--panel-2); color: var(--muted); display: grid; place-items: center; cursor: pointer; }
.slot-switch .icon { width: 18px; height: 18px; fill: currentColor; }
.slot-switch[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }
.slot-switch[aria-pressed="false"] { border-style: dashed; opacity: .75; }
.slot-switch:hover { border-color: var(--muted); }
.music-volume { display: flex; align-items: center; gap: 10px; padding: 2px 4px 6px; color: var(--muted); font-size: var(--type-small); }
.music-volume input { flex: 1; min-width: 0; accent-color: var(--accent); }
.music-volume output { width: 4ch; text-align: right; font-variant-numeric: tabular-nums; }
.slot .what { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.slot .what b { font: 600 var(--type-small) var(--mono); }
.slot.now .what b { color: var(--accent); }
.slot .what small { color: var(--muted); font-size: var(--type-small); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.maker { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px 20px; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.maker-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.maker-head h2 { margin: 0; font: 600 var(--type-lead) var(--body); }
.maker-head h2 code { font: 600 var(--type-lead) var(--mono); color: var(--accent); }
.maker-head h2 .moment { color: var(--accent); }
.maker-head h2 select { font: 600 var(--type-lead) var(--mono); color: var(--accent); background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--radius-sm); padding: 2px 6px; }
.art-undo { display: inline-flex; gap: 6px; }
.tabs { display: inline-flex; gap: 4px; padding: 4px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.tabs button { white-space: nowrap; padding: 6px 14px; border: 0; border-radius: 7px; background: transparent; color: var(--muted); font: 600 var(--type-small) var(--body); }
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { background: var(--panel-2); color: var(--ink); }
/* tighter tabs in a narrow room (the pretty pass). The icons stay: Make a song and Make a beat are told apart by them
   (wchesher, 2026-10-23: "give make a song and make a beat different icons") */
@container (max-width: 560px) { .tabs button { padding: 6px 10px; gap: 6px; } }
.maker-foot { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; padding-top: 14px; border-top: 1px solid var(--line); }
.saved-as { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }

/* the art room */
.library-facets { display: flex; flex-direction: column; gap: 8px; }
.facet { display: flex; flex-wrap: wrap; gap: 6px; }
.facet button { height: 30px; padding: 0 12px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--ink);
  font: 600 var(--type-small) var(--body); cursor: pointer; transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease); }
.facet button:hover { border-color: var(--line-2); color: var(--ink); }
.facet button[aria-pressed="true"] { border-color: var(--accent); color: var(--ink); background: var(--accent-soft); }
.facet .count { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.library { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; max-height: 360px; overflow: auto; }
.library.backdrops { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); max-height: 440px; }
.backdrop-slot { margin-bottom: 8px; }
/* the sound room's pinned music row: the whole game's, above the moments, as the background row is in art */
.music-row { margin-bottom: 8px; }
.sound-row .what, .music-row .what { flex-direction: row; align-items: baseline; gap: 10px; }
.sound-row .what b, .music-row .what b { flex: none; }
.music-row .ic { background: var(--panel-2); }
.music-row .ic .icon { width: 20px; height: 20px; color: var(--accent); }
.music-row.empty .ic .icon { color: var(--faint); }
.library.backdrops .backdrop-group { grid-column: 1 / -1; margin: 6px 2px 0; font: 400 var(--type-label) var(--mono); color: var(--muted); text-transform: lowercase; }
.library.backdrops .backdrop-card { position: relative; display: flex; }
.library.backdrops .backdrop-card > button[data-backdrop] { width: 100%; }
.library.backdrops .backdrop-card.long { grid-column: span 2; }
/* Edit, on every scene: a small lime chip over the picture's corner, the badge's size */
.library.backdrops button.backdrop-edit { position: absolute; top: 9px; left: 7px; flex-direction: row; gap: 4px; padding: 2px 7px; height: 22px;
  font-size: var(--type-label); font-weight: 600; line-height: 1; color: var(--accent); background: rgba(13, 18, 20, .86); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.library.backdrops button.backdrop-edit:hover { border-color: var(--accent); box-shadow: 0 0 10px var(--accent-soft); }
.library.backdrops button.backdrop-edit .icon { width: 13px; height: 13px; }
.library.backdrops button.long .frame { aspect-ratio: 2; background-repeat: repeat-x; animation: backdrop-pan var(--pan-time, 28s) linear infinite; }
@keyframes backdrop-pan { from { background-position: 0 0; } to { background-position: var(--pan-end, 0%) 0; } }
@media (prefers-reduced-motion: reduce) { .library.backdrops button.long .frame { animation: none; } }
.library button { position: relative; border-radius: 8px; border: 1px solid var(--line); display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 6px 4px 5px; background: transparent; color: var(--ink); cursor: pointer; transition: border-color var(--fast) var(--ease); }
.library button:hover { border-color: var(--muted); }
.library button[aria-pressed="true"] { border-color: var(--accent); }
.library .frame { width: 100%; aspect-ratio: 1; border-radius: 6px; image-rendering: pixelated; background-repeat: no-repeat; background-position: 0 0;
  background-color: var(--panel-2); }
.library .frame.smooth { image-rendering: auto; }
.library .badge { position: absolute; top: 9px; right: 7px; font: 400 var(--type-label) var(--pixel); color: var(--ink); background: rgba(13, 18, 20, .8);
  padding: 1px 4px; border-radius: 4px; }
/* A SPRITE'S CARD SAYS WHAT IT IS IN WORDS (same ask): the sprite's code name ("robot_cyan_idle") was cut to "robot_cya..."
   on every card in a family, and "moves" sat over the sprite's head. The card says the family on one line and the pose
   under it, "moves" beside the pose; the code name, the one used in code, is the card's tip and what it stores. */
.library .art-card .badge { position: static; padding: 0; background: none; font: 400 var(--type-label) var(--mono); color: var(--accent); }
.library .name.two { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; white-space: normal; text-align: center; line-height: 1.25; }
.library .pose { font: 400 var(--type-label)/1.25 var(--mono); color: var(--muted); max-width: 100%; text-align: center; overflow-wrap: anywhere; }
.library .mine-card { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.library .mine-card > button:first-child { width: 100%; }
.library .mine-actions { display: flex; gap: 10px; align-items: center; }
.library button.mine-delete, .library button.mine-offer { border: 0; padding: 0; display: inline; font-size: var(--type-label); }
.library button.mine-offer.waiting { color: var(--caution, #ffb347); }
.library button.mine-offer.accepted { color: var(--good, #3bd6a6); opacity: 1; cursor: default; }
.library .name { font: 400 var(--type-label) var(--mono); color: var(--muted); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.library-picked { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--panel-2); border: 1px solid var(--line); font-size: var(--type-small); color: var(--ink); }
.library-picked .mono { font: 600 var(--type-small) var(--mono); color: var(--ink); }
.library-picked .grow { flex: 1; }
.library-credit { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.sets { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 14px; }
.sets .eyebrow { flex-basis: 100%; }
.sets .set { display: grid; grid-template-columns: repeat(3, 28px); gap: 4px 6px; padding: 10px 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); cursor: pointer; text-align: left; color: var(--ink); transition: border-color var(--fast) var(--ease); }
.sets .set:hover { border-color: var(--accent); }
.sets .set:active { transform: scale(.985); }
.sets .set .pic { width: 28px; height: 28px; background-size: auto 100%; background-repeat: no-repeat; image-rendering: pixelated; }
/* A set card is painted in its own sky, which can be any colour, so its words sit on a band of the
   ground: 6 : 1 or better even on a white sky (muted straight on a mid-blue sky was 2.63). */
.sets .set b, .sets .set small { grid-column: 1 / -1; justify-self: start; padding: 1px 5px; border-radius: 4px;
  background: color-mix(in srgb, var(--surface) 78%, transparent); }
.sets .set b { font: 600 var(--type-body) var(--body); }
.sets .set small { font: 400 var(--type-label) var(--mono); color: var(--ink); }
/* every animation: the ones no slot names, a new one, and how each plays */
.own-anims { display: flex; flex-direction: column; gap: 8px; }
.more-anims { margin: 10px 2px 0; font-size: var(--type-label); }
.slot.new-anim { border-style: dashed; background: transparent; color: var(--muted); font: inherit; text-align: left; cursor: pointer; }
.slot.new-anim:hover { color: var(--ink); border-color: var(--accent); }
.slot .ic.plus { font: 600 20px var(--mono); color: var(--accent); background: none; }
.slot.free .what small { font-family: var(--mono); font-size: var(--type-label); }
/* a sprite's moves (studio.js buildMoves): still, walk, jump, hurt, one row under the sprite's head */
.art-moves { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.art-moves .move { display: grid; grid-template-columns: auto auto; grid-template-rows: auto auto; column-gap: 8px; align-items: center; padding: 5px 10px 5px 6px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--panel-2); color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.art-moves .move:hover { border-color: var(--muted); }
.art-moves .move.empty { border-style: dashed; background: transparent; }
.art-moves .move.now { border-color: var(--accent); border-style: solid; }
.art-moves .move .ic { grid-row: 1 / 3; width: 30px; height: 30px; border-radius: 5px; display: grid; place-items: center; overflow: hidden; background: var(--screen); }
.art-moves .move .ic img { width: 24px; height: 24px; image-rendering: pixelated; object-fit: contain; }
.art-moves .move .ic .empty-box { width: 16px; height: 16px; border: 1.5px dashed var(--line-2); }
.art-moves .move b { font: 600 var(--type-small) var(--body); line-height: 1.1; }
.art-moves .move small { font: 400 var(--type-label) var(--mono); color: var(--muted); line-height: 1.1; }
.anim-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.anim-name { display: inline-flex; align-items: center; gap: 8px; }
.anim-name input { width: 180px; background: var(--surface); border: 1px solid var(--line-2); border-radius: var(--radius-sm); color: var(--ink); padding: 6px 10px; font: 400 var(--type-small) var(--mono); }
.playback { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: var(--type-small); }
.playback input[type=range] { flex: 1 1 140px; max-width: 240px; accent-color: var(--accent); }
.playback .loop { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); }
.playback .loop input { accent-color: var(--accent); }
/* Draw is Piskel, in the room: the size line over it, the editor filling the column, the game under it */
.maker-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.draw-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* one line over the sheet on a laptop: the size words give way first (they never push a button onto a second line) */
#painter-room > .draw-head:not(.backdrop-draw-head) > .size-now { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.size-now { font: 400 var(--type-small) var(--mono); color: var(--ink); }
.new-size { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.new-size .muted { font: 400 var(--type-small) var(--mono); }
.backdrop-draw { display: flex; flex-direction: column; gap: 6px; }
.backdrop-sizes { display: flex; gap: 8px; }
.backdrop-size { flex: 1; display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: var(--radius-sm); border: 1px solid var(--line);
  background: var(--panel); color: var(--ink); text-align: left; cursor: pointer; transition: border-color var(--fast) var(--ease); }
.backdrop-size:hover { border-color: var(--muted); }
.backdrop-size[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.backdrop-size i { display: block; height: 14px; flex: none; border: 1px solid var(--line-2); border-radius: 3px; background: var(--panel-2); }
.backdrop-size b { display: block; font-size: var(--type-small); font-weight: 600; }
.backdrop-size small { color: var(--muted); font: 400 var(--type-label) var(--mono); }
.backdrop-draw-head .size-now { font-family: inherit; color: var(--ink-2); }
.piskel-host { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--panel-2); }
.piskel-host[hidden] { display: none; }
.piskel { display: block; width: 100%; height: 520px; border: 0; }
/* Full screen: the host covers the window, a thin bar over Piskel; the frame is restyled, never moved */
.piskel-bar { display: none; }
body.piskel-full #place-art { animation: none; }   /* its entrance animation makes a stacking context the cover could not leave */
body.piskel-full .piskel-host { position: fixed; inset: 0; z-index: 40; border: 0; border-radius: 0; overflow-y: auto; background: var(--surface); }
body.piskel-full .piskel-bar { display: flex; align-items: center; gap: 10px; padding: 8px 16px; border-bottom: 1px solid var(--line); background: var(--surface); position: sticky; top: 0; z-index: 1; }
body.piskel-full .piskel-bar code { font: 600 var(--type-body) var(--mono); color: var(--accent); }
/* NOTHING BEHIND THE DRAWING PAINTS (Maestro, 2026-10-16: "The screen is flickering when pixels are edited",
   on Windows, in Full screen only). Each stroke redraws the slot row, the sprite in the game and the running
   game under the cover, and the drawing sheet darkened for a moment with each one. Behind the cover none of
   it can be seen, so none of it is painted: the page is hidden while the cover is up and shows again,
   current, on the way out. Piskel gets a layer of its own, so a change around it never repaints it. */
body.piskel-full { visibility: hidden; }
body.piskel-full .piskel-host, body.piskel-full .toast { visibility: visible; }
body.piskel-full .piskel { will-change: transform; }
/* drawing: the slots become one row of chips and the maker tightens, so Piskel gets the height. The
   art (draw) interface dominates the room (operator, 2026-10-12: "this is an enacceptable use of the
   space"): the room drops its reading width so Piskel takes the whole column, and the sets, a
   Library thing, wait off screen until Library or Upload is open again. */
body.art-drawing .room-body { max-width: none; }
#place-art.drawing .sets, #place-art.art-thing .sets { display: none; }
#place-art.drawing .backdrop-slot, #place-art.art-thing .backdrop-slot { margin-bottom: 0; }
#place-art.drawing .slots .slots, #place-art.drawing .own-anims, #place-art.art-thing .slots .slots, #place-art.art-thing .own-anims { display: contents; }   /* every chip in one wrapping row */
#place-art.drawing .more-anims, #place-art.art-thing .more-anims { margin: 0 2px 0 8px; }
#place-art.drawing .maker-grid, #place-art.art-thing .maker-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
#place-art.drawing .slot-col, #place-art.art-thing .slot-col { max-width: none; }
#place-art.drawing .slots, #place-art.art-thing .slots { flex-direction: row; flex-wrap: wrap; gap: 6px; }
#place-art.drawing .slot, #place-art.art-thing .slot { width: auto; padding: 4px 10px 4px 5px; gap: 8px; }
.art-drawing .room-note { display: none; }
.art-drawing:not(.playtesting) .room-head { display: none; }   /* its pill rides the drawing's head line (studio.js drawBack) */
.maker-head .draw-back { align-self: center; }
.back-pill.draw-back { display: none; }
.art-drawing .back-pill.draw-back { display: inline-flex; }
#place-art.drawing .playback { font-size: var(--type-small); }
#place-art.drawing .slot .ic, #place-art.art-thing .slot .ic { width: 28px; height: 28px; }
#place-art.drawing .slot .ic img, #place-art.art-thing .slot .ic img { width: 22px; height: 22px; }
#place-art.drawing .slot .what small, #place-art.drawing .slot-note, #place-art.art-thing .slot .what small, #place-art.art-thing .slot-note { display: none; }
#place-art.drawing .maker { padding: 12px 16px; gap: 10px; }
.drop { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 40px 20px; border: 1.5px dashed var(--line-2); border-radius: var(--radius-sm);
  text-align: center; color: var(--muted); font-size: var(--type-body); cursor: pointer; transition: border-color var(--fast) var(--ease); }
.drop:hover { border-color: var(--accent); }
.drop b { font: 600 var(--type-lead) var(--body); color: var(--ink); }
.drop input[type=file] { margin-top: 8px; color: var(--ink); font-size: var(--type-small); }
/* PIXEL ART FROM A PHOTO (#153, pixelate.js): Upload's choices, above the drop. */
.pixel-art { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.pixel-art .pixel-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.pixel-art .pixel-row .eyebrow { margin-left: 6px; }
.pixel-art .btn[aria-pressed=true] { border-color: var(--accent); color: var(--ink); box-shadow: inset 0 0 0 1px var(--accent); }
.pixel-art .pixel-note { color: var(--muted); font-size: var(--type-small); }
/* Ask player two (inbox #227): the student's words in their box, player two's reading and drawing in its royal */
.p2-draw { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }
.p2-draw-words { display: flex; flex-direction: column; gap: 4px; }
.p2-draw-words textarea { width: 100%; resize: vertical; min-height: 64px; font: 400 var(--type-body) var(--body); color: var(--ink);
  background: var(--panel-2); border: 1px solid var(--line-2); border-radius: var(--radius-sm); padding: 8px 10px; }
.p2-draw-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.p2-draw-row .pixel-note { color: var(--muted); font-size: var(--type-small); }
.p2-draw .p2-draw-go { border-color: var(--p2); color: var(--p2); }
.p2-draw .p2-draw-go .icon { color: var(--p2); }
.p2-draw-error { color: var(--muted); font-size: var(--type-small); margin: 0; }
.p2-draw-said { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; padding: 12px; border: 1px solid var(--p2);
  border-radius: var(--radius-sm); background: var(--p2-soft); }
.p2-draw-art { width: 192px; height: 192px; image-rendering: pixelated; background: var(--panel-2); border-radius: var(--radius-sm); flex: none; }
.p2-draw-read { flex: 1; min-width: 200px; display: flex; flex-direction: column; gap: 8px; }
.p2-draw-read .eyebrow { color: var(--p2); }
.p2-draw-read p { margin: 0; }
/* THE ART ROOM, THING FIRST (option A, 2026-10-22). #art: a card for every thing, big enough to read, then
   the art packs in one line. #art/<name>: that thing's page has the room, and the cards shrink to one row of
   chips above it, so every other thing stays in view (class report, 2026-10-22: "the other sprites should not
   disappear, keep it in one frame"). Draw it keeps the whole room for the editor. */
#place-art.art-home .maker-col { display: none; }
#place-art.art-thing.drawing .slot-col { display: none; }   /* while drawing, the editor keeps the whole room, as it had */
#place-art.art-home .maker-grid, #place-art.art-thing .maker-grid { grid-template-columns: minmax(0, 1fr); }
#place-art.art-home .slot-col { max-width: none; gap: 18px; }
#place-art.art-home #art-slots { display: flex; flex-direction: column; gap: 18px; }
#place-art.art-home #art-slots > .slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 10px; }
#place-art.art-home .own-anims { display: contents; }
#place-art.art-home .more-anims { grid-column: 1 / -1; margin: 6px 2px 0; }
#place-art.art-home .slot { flex-direction: column; justify-content: center; gap: 8px; padding: 14px 10px 12px; text-align: center; min-height: 132px; margin: 0; }
#place-art.art-home .slot:hover { border-color: var(--accent); }
#art-slots .slot.drop-here { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }   /* a dragged picture lands on this card */
#place-art.art-home .slot .ic { width: 76px; height: 76px; border-radius: 10px; }
#place-art.art-home .slot .ic img { width: 64px; height: 64px; }
#place-art.art-home .slot .ic .empty-box { width: 48px; height: 48px; }
#place-art.art-home .slot .ic.plus { font-size: 40px; }
#place-art.art-home .slot .what { align-items: center; flex: none; max-width: 100%; }
#place-art.art-home .slot .what b { font: 600 var(--type-body) var(--body); }
#place-art.art-home .slot.new-anim { text-align: center; }
#place-art.art-home .sets { flex-wrap: nowrap; overflow-x: auto; margin: 0; padding-bottom: 6px; scrollbar-width: thin; }
#place-art.art-home .sets .eyebrow { flex: none; flex-basis: auto; margin-right: 4px; }
#place-art.art-home .sets .set, #place-art.art-home #art-sets-more { flex: none; white-space: nowrap; }
.art-ways { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(max-content, 1fr); width: 100%; gap: 6px; padding: 6px; }
/* FOUR WAYS FIT THE ROOM (2026-10-28, the seams pass): Ask player two made a fourth tab that ran past the room's edge at
   desktop widths. A wide room keeps one row; a room too narrow for four (the usual 1280 and 1440 layouts) lays them two
   by two, an even grid rather than three and a straggler. */
.art-ways button { min-width: 0; justify-content: center; padding: 12px 10px; white-space: nowrap; font: 600 var(--type-body) var(--body); }
@container (max-width: 460px) { .art-ways:has(> :nth-child(4)) { grid-auto-flow: row; grid-template-columns: 1fr 1fr; }
  .art-ways:has(> :nth-child(4)) button { padding: 9px 10px; } }
/* player two's way is player two's color, as everything player two does is */
.art-ways button[data-way=p2] { color: var(--p2); }
#place-art.drawing .art-ways button { padding: 8px 14px; }
.drop small { color: var(--muted); font-size: var(--type-small); text-align: center; max-width: 46ch; }
.drop input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; }
.drop { position: relative; }

.in-game-box { padding: 0 2px; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 16px; align-items: center; }
.in-game-box:empty { display: none; }
.in-game-box .eyebrow { font-size: var(--type-label); }
.in-game-box .note { margin: 0; font-size: var(--type-small); text-align: right; }
.in-game { grid-column: 1 / -1; position: relative; aspect-ratio: 3 / 1; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.in-game .ground { position: absolute; left: 0; right: 0; bottom: 0; height: 14%; background: rgba(255, 255, 255, .06); }
.in-game .sprite { position: absolute; left: 50%; bottom: 14%; transform: translateX(-50%); image-rendering: pixelated; object-fit: contain; }
.in-game .sprite.box { border: 1.5px dashed var(--muted); }
.in-game .hud { position: absolute; left: 3%; top: 8%; font: 400 var(--type-label) var(--pixel); color: var(--ink); }
/* the animation by itself, in Draw: only the sprite, bigger than in the game, on the frames' see-through squares */
.anim-alone { grid-column: 1 / -1; display: grid; place-items: center; min-height: 120px; padding: 12px; border: 1px solid var(--line); border-radius: 8px;
  background: repeating-conic-gradient(var(--panel) 0 25%, var(--panel-2) 0 50%) 0 0 / 16px 16px; }
.anim-alone .sprite { max-width: 100%; object-fit: contain; image-rendering: pixelated; }
.in-game-box .art-size { grid-column: 1 / -1; display: grid; grid-template-columns: auto minmax(0, 1fr) 3.5em auto; gap: 4px 10px; align-items: center; }
.in-game-box .art-size input[type=range] { width: 100%; accent-color: var(--accent); }
.in-game-box .art-size .art-size-value { font: 400 var(--type-small) var(--mono); text-align: right; }
.in-game-box .art-size .note { grid-column: 1 / -1; text-align: left; color: var(--muted); }

/* the sound room */
.presets { display: flex; flex-wrap: wrap; gap: 6px; }
.preset { min-height: 32px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--ink); font-size: var(--type-small); }
.preset:hover { border-color: var(--muted); }
.preset[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.wave { display: flex; align-items: center; gap: 2px; height: 104px; padding: 0 14px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.wave i { flex: 1; display: block; background: var(--accent); border-radius: 1px; min-height: 2px; }
.sound-knobs { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px 20px; }
.sound-knob { display: flex; flex-direction: column; gap: 4px; font-size: var(--type-small); color: var(--ink); }
.sound-knob .top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
/* the page header's .top (its 36 px of padding, further down this sheet) is not a knob's label row: every slider in the
   sound room sat under an empty band of it (found in the UX pass, 2026-10-23) */
.sound-knob .top { padding: 0; flex-wrap: nowrap; }
.sound-knob output { font: 600 var(--type-small) var(--mono); color: var(--accent); }
.shapes { display: flex; flex-wrap: wrap; gap: 4px; }
/* the shapes are words now (Square, Triangle ...), so they wrap rather than clip (2026-11-03 review) */
.shapes button { flex: 1 1 auto; padding: 0 8px; min-height: 30px; border-radius: 6px; border: 1px solid var(--line); background: var(--surface); color: var(--muted); font: 400 var(--type-label) var(--pixel); }
.shapes button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.the-line { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 14px; align-items: center; padding: 10px 14px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface); font: var(--type-small)/1.5 var(--mono); color: var(--ink); }
.the-line .eyebrow { font-size: var(--type-label); }
.the-line .on { color: var(--accent); }
.the-line > span { min-width: 0; overflow-wrap: anywhere; }
/* every sound in the room is drawn: the slot's own, the library's while it plays, a take while it is trimmed */
.slot-wave { width: 48px; height: 14px; flex: none; opacity: .85; }
.sound-now { display: flex; flex-direction: column; gap: 8px; padding: 10px 14px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.sound-now.empty { border-style: dashed; }
.sound-now.empty .note { margin: 0; }
.sound-now-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.sound-now-head .eyebrow { font-size: var(--type-label); }
.sound-now-what { font: 400 var(--type-small) var(--mono); color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.sound-now-wave, .sound-take-wave { display: block; width: 100%; height: 48px; }
.sound-library { display: flex; flex-direction: column; gap: 10px; }
.sound-cats { display: flex; gap: 6px; flex-wrap: wrap; }
.sound-cat { padding: 4px 10px; border-radius: 999px; border: 1px solid var(--line); background: transparent; color: var(--muted); font: 400 var(--type-small) var(--mono); white-space: nowrap; }
.sound-cat:hover { color: var(--ink); }
.sound-cat[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
/* the beat maker (beat-maker.js): starters and play over a sixteen-step grid, drums then melody */
.beat-maker { display: flex; flex-direction: column; gap: 14px; }
.beat-head { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* sixteen steps fit the sound column (about 330 px) with no sideways scroll; a scroll is the fallback below that */
.beat-scroll { overflow-x: auto; }
.beat-grid { display: grid; grid-template-columns: 72px repeat(16, minmax(24px, 30px)); gap: 2px; min-width: 260px; }
.beat-title { grid-column: 1 / -1; font-size: var(--type-label); margin-top: 4px; }
.beat-label { font: 400 var(--type-small) var(--mono); color: var(--muted); align-self: center; white-space: nowrap; }
.beat-cell { aspect-ratio: 1; min-height: 24px; padding: 0; border-radius: 3px; border: 1px solid var(--line); background: var(--panel-2); cursor: pointer; }
.beat-cell.beat-one { background: var(--line); }
.beat-cell:hover { border-color: var(--muted); }
.beat-cell.on { background: var(--accent); border-color: var(--accent); }
.beat-cell.melody.on { background: var(--p2-hover); border-color: var(--p2-hover); }
.beat-cell.bass.on { background: var(--caution); border-color: var(--caution); }
.beat-cell.now { border-color: var(--ink); }
.beat-cell.now.on { filter: brightness(1.2); }
/* Mixdesk's desk, carried in (2026-10-27): the pattern letters and song order, track ends, the lanes, the mixer strips */
.beat-patterns { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.beat-patterns .eyebrow { font-size: var(--type-label); }
.beat-letters { display: flex; flex-wrap: wrap; gap: 3px; }
.beat-letter { min-width: 24px; height: 24px; padding: 0 4px; border-radius: 4px; border: 1px solid var(--line); background: transparent; color: var(--faint); font: 400 var(--type-small) var(--mono); }
.beat-letter.has { color: var(--ink); border-color: var(--line-2); }
.beat-letter[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.beat-order { display: flex; align-items: center; gap: 8px; font-size: var(--type-small); color: var(--ink); }
.beat-order input { width: 9em; background: var(--surface); border: 1px solid var(--line-2); color: var(--ink); border-radius: 6px; padding: 4px 8px; font: 400 var(--type-small) var(--mono); letter-spacing: .08em; }
button.beat-label { background: none; border: 0; padding: 0; text-align: left; cursor: pointer; }
button.beat-label:hover { color: var(--ink); }
.beat-label[aria-pressed="true"] { color: var(--accent); }
.beat-label.silent, .beat-strip.silent .beat-strip-name { opacity: .45; }
.beat-cell.past { opacity: .3; }
.beat-cell.lane.on { background: var(--ink-2); border-color: var(--ink-2); }
.beat-mixer { display: grid; grid-template-columns: 64px minmax(0, 1fr) 3ch auto auto; gap: 4px 8px; align-items: center; }
.beat-mixer .eyebrow { grid-column: 1 / -1; font-size: var(--type-label); }
.beat-strip { display: contents; }
.beat-strip-name { font: 400 var(--type-small) var(--mono); color: var(--muted); white-space: nowrap; }
.beat-strip output { font: 600 var(--type-small) var(--mono); color: var(--accent); text-align: right; }
.beat-toggle { width: 26px; height: 24px; border-radius: 4px; border: 1px solid var(--line); background: transparent; color: var(--muted); font: 400 var(--type-label) var(--pixel); }
.beat-toggle.mute[aria-pressed="true"] { border-color: var(--bad); color: var(--bad); }
.beat-toggle.solo[aria-pressed="true"] { border-color: var(--caution); color: var(--caution); }
.beat-credit { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }
/* the tunes studio's Song room (studio.js songPane): the song's settings, the arrangement, the pattern, the parts */
.song-maker { display: flex; flex-direction: column; gap: 14px; }
/* THE SONG ROOM TAKES THE MIDDLE (the UX pass, wchesher 2026-10-23: "Full width"): while a song is made the game steps
   aside and the room has the width the grids need; Back to the game (#song-back) folds it into the sound column again */
body.song-full .bench { grid-template-columns: minmax(0, 1fr) var(--p2w); }
body.song-full #side, body.song-full .split { display: none; }
/* ONE LIME IN THE SONG ROOM (2026-11-03 review: Play and Next were lime side by side): Play is the room's action, so the
   bench's Next steps back to an ordinary button while the song maker has the whole width */
body.song-full #next-go.btn.primary { background: var(--panel-2); border-color: var(--line); color: var(--ink); }
body.song-full #next-go.btn.primary:hover { border-color: var(--muted); }
/* MORE: key, scale, time and a MIDI file, folded beside the speed */
.song-more { align-self: center; }
.song-more > summary { cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 6px; min-height: 34px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); font: 600 var(--type-small) var(--body); color: var(--ink-2); }
.song-more > summary::-webkit-details-marker { display: none; }
.song-more > summary::before { content: "+"; font: 400 var(--type-body) var(--mono); color: var(--muted); }
.song-more[open] > summary::before { content: "\2212"; }
.song-more[open] > summary { border-color: var(--muted); color: var(--ink); }
.song-more-body { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px; margin-top: 10px; }
body.song-full .room-body { max-width: none; }
body.song-full #place-sound .maker-grid { grid-template-columns: minmax(200px, 240px) minmax(0, 1fr); }
@media (max-width: 760px) { body.song-full #place-sound .maker-grid { grid-template-columns: minmax(0, 1fr); } }
.song-transport { display: flex; flex-wrap: wrap; align-items: end; gap: 10px 18px; position: sticky; top: 0; z-index: 3;
  background: var(--panel); padding: 6px 0 12px; border-bottom: 1px solid var(--line); }
.song-transport .sound-knob { min-width: 140px; flex: 0 1 180px; }
.song-back { align-self: flex-start; }
.song-transport .song-choice { min-width: 0; flex: 0 0 auto; }
.song-start { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.song-start .eyebrow { margin: 0; }
.song-start .presets { margin: 0; }
.song-tabs { flex-wrap: wrap; margin-top: 4px; }
.song-panel { min-height: 120px; }
.song-folded { gap: 10px; }
.song-code { display: flex; flex-direction: column; gap: 8px; }
.song-text { display: flex; flex-direction: column; gap: 8px; }
.song-code-text { width: 100%; font: 400 var(--type-small)/1.5 var(--mono); background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: 10px 12px; resize: vertical; overflow: auto; tab-size: 2; }
.song-code-errors { margin: 0; padding-left: 18px; color: var(--bad); font-size: var(--type-small); }
.song-code-errors:empty { display: none; }
.song-code-row { display: grid; grid-template-columns: minmax(12em, max-content) minmax(0, 1fr) auto; gap: 4px 14px; align-items: center; }
.song-code-row code { font: 400 var(--type-small) var(--mono); color: var(--accent); }
@media (max-width: 760px) { .song-code-row { grid-template-columns: minmax(0, 1fr) auto; } .song-code-row .note { grid-column: 1 / -1; } }
.song-maker select, .song-maker input[type=text], .song-number { font: 400 var(--type-small) var(--mono); background: var(--panel-2); color: var(--ink); border: 1px solid var(--line); border-radius: 4px; padding: 3px 6px; }
.song-number { width: 4.5em; }
.song-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
#song-add-how { margin: 0; flex: 1 1 240px; }   /* how drums and bells get into a song (student feedback, 2026-10-23) */
.song-grid { display: grid; gap: 2px; align-items: stretch; min-width: 260px; }
.song-corner { display: block; }
.song-bar-number { font: 400 var(--type-small) var(--mono); color: var(--muted); text-align: center; border-bottom: 2px solid transparent; }
.song-bar-number.loop { border-bottom-color: var(--accent); color: var(--ink); }
.song-bar-number.now { color: var(--accent); }
.song-track { display: flex; gap: 6px; align-items: center; padding-right: 8px; white-space: nowrap; }
.song-track-name { font: 600 var(--type-small) var(--mono); min-width: 5.5em; }
.song-track input[type=range] { width: 64px; }
.song-toggle { font: 700 var(--type-small) var(--mono); min-width: 24px; padding: 2px 4px; border-radius: 3px; border: 1px solid var(--line); background: var(--panel-2); color: var(--muted); cursor: pointer; }
.song-toggle.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.song-cell { min-height: 22px; padding: 0; border-radius: 3px; border: 1px solid var(--line); background: var(--panel-2); color: var(--accent-ink); font: 700 var(--type-small) var(--mono); cursor: pointer; }
.song-cell:hover { border-color: var(--muted); }
.song-cell:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }
.song-cell.beat-one { background: var(--line); }
.song-cell.bar-start { border-left-color: var(--muted); }
.song-cell.on { background: var(--accent); border-color: var(--accent); }
.song-cell.melody.on { background: var(--p2-hover); border-color: var(--p2-hover); }
.song-cell.held { background: color-mix(in srgb, var(--accent) 45%, var(--panel-2)); border-color: transparent; }
.song-cell.melody.held { background: color-mix(in srgb, var(--p2-hover) 45%, var(--panel-2)); }
.song-cell.picked { box-shadow: inset 0 0 0 2px var(--ink); }
.song-cell.now { border-color: var(--ink); }
.song-roll .song-cell { aspect-ratio: 1; min-height: 12px; }
.beat-label.root { color: var(--ink); }
.song-check { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.song-sections { display: flex; flex-direction: column; gap: 6px; }
.song-call { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.song-mixer { display: flex; flex-direction: column; gap: 8px; }
.song-library, .song-tunes { display: flex; flex-direction: column; gap: 6px; }
.song-files, .song-ask { display: flex; flex-direction: column; gap: 6px; }
.song-ask .song-row input[type=text] { flex: 1; min-width: 0; }
.song-p2:not(:empty) { display: flex; flex-direction: column; gap: 4px; padding-left: 10px; border-left: 2px solid var(--p2-hover); }
.song-p2 p { margin: 0; }
.song-tune.picked input { border-color: var(--accent); }
.song-version { padding-left: 16px; }
.song-strip { align-items: end; }
.song-strip .song-track-name { align-self: center; }
/* sound packs: ONE LINE, shut until opened (studio.js soundPackRow), then the pills, each fills every slot from one mood shelf */
.sound-packs { margin: 0 0 10px; }
.sound-packs > summary { display: inline-flex; align-items: baseline; gap: 10px; cursor: pointer; list-style: none; padding: 4px 0; }
.sound-packs > summary::-webkit-details-marker { display: none; }
.sound-packs > summary::before { content: "+"; font: 600 var(--type-small) var(--mono); color: var(--muted); width: 1ch; }
.sound-packs[open] > summary::before { content: "\2212"; }
.sound-packs > summary .eyebrow { margin: 0; }
.sound-packs-say { font-size: var(--type-small); color: var(--muted); }
.sound-packs > summary:hover .sound-packs-say { color: var(--ink); }
.sound-pack-list { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; padding: 6px 0 2px; }
/* ONE ROW OF CHIPS, NOT A COLUMN OF CARDS (2026-11-03 review): a slot is always open in the sound room, so the slots ride
   as the art room's compact chips (#place-art.art-thing) and the maker under them starts in view; the dot still says
   sound or silence, the switch stays beside its chip. The song room's sidebar keeps its list. */
body:not(.song-full) #place-sound .slot-col { max-width: none; gap: 6px; }
body:not(.song-full) #place-sound .slot-col > .slots, body:not(.song-full) #place-sound .slot-col .slots .slots { flex-direction: row; flex-wrap: wrap; gap: 6px; }
body:not(.song-full) #place-sound .slot-col > .slots { display: flex; }
body:not(.song-full) #place-sound .slot-col .slots .slots { display: contents; }
body:not(.song-full) #place-sound .slot-wrap { gap: 2px; }
body:not(.song-full) #place-sound .slot { width: auto; padding: 4px 10px 4px 6px; gap: 8px; margin: 0; }
/* still ONE LINE A MOMENT (usability pass, 2026-10-22): its words, what plays there, its shape -- each cut to a chip's size */
body:not(.song-full) #place-sound .slot .what { gap: 6px; }
body:not(.song-full) #place-sound .slot .what small { max-width: 14ch; }
body:not(.song-full) #place-sound .slot .slot-wave { width: 40px; height: 14px; flex: none; }
body:not(.song-full) #place-sound .slot .ic { width: 26px; height: 26px; }
body:not(.song-full) #place-sound .music-row .ic .icon { width: 16px; height: 16px; }
body:not(.song-full) #place-sound .slot-switch { width: 30px; }
body:not(.song-full) #place-sound .music-volume, body:not(.song-full) #place-sound .sound-packs { flex-basis: 100%; }
body:not(.song-full) #place-sound .sound-packs { margin: 0 0 2px; }
body:not(.song-full) #place-sound .maker-grid { grid-template-columns: minmax(0, 1fr); gap: 12px; }
.sound-pack b { font-weight: 600; color: var(--ink); }
.sound-pack:hover { border-color: var(--accent); }
.sound-pack:disabled { opacity: .6; cursor: progress; }
.sound-count { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.sound-rows { display: flex; flex-direction: column; gap: 4px; max-height: 360px; overflow: auto; padding-right: 2px; }
.sound-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 6px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--panel-2); }
.sound-item.playing { border-color: var(--accent); }
.sound-play { min-width: 52px; min-height: 30px; border-radius: 6px; border: 1px solid var(--line-2); background: var(--surface); color: var(--ink); font: 600 var(--type-small) var(--mono); }
.sound-item.playing .sound-play { color: var(--accent); border-color: var(--accent); }
.sound-item-name { display: flex; flex-direction: column; min-width: 0; }
.sound-item-name b { font: 600 var(--type-small) var(--body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sound-item-name small { font: 400 var(--type-label) var(--mono); color: var(--muted); white-space: nowrap; }
/* drawn under the name while it plays, so a row is only as tall as it needs to be */
.sound-item-wave { display: none; width: 100%; height: 18px; margin-top: 4px; }
.sound-item-wave[data-drawn] { display: block; }
#sound-maker .tabs { flex-wrap: wrap; max-width: 100%; }
#sound-maker .tabs button { padding: 6px 12px; }
.sound-record { display: flex; flex-direction: column; gap: 12px; }
.sound-meter { height: 14px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); overflow: hidden; }
.sound-meter i { display: block; height: 100%; width: 0; background: var(--accent); transition: width 60ms linear; }
.sound-left { font: 600 var(--type-small) var(--mono); color: var(--accent); }
.sound-trim { display: block; width: 100%; height: 96px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); touch-action: none; cursor: ew-resize; }
.sound-trims { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px 20px; }
.sound-trims label { display: flex; flex-direction: column; gap: 4px; font-size: var(--type-small); color: var(--ink); }
.sound-kept { margin: 0; font: 400 var(--type-small) var(--mono); color: var(--muted); }

/* the map room */
.map-room { max-width: 760px; }
.map-tools { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin: 0 0 14px; }
.levels { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.levels .eyebrow { font-size: var(--type-label); margin-right: 4px; }
.lvl { min-width: 34px; height: 32px; border-radius: 8px; background: var(--panel-2); border: 1px solid var(--line); font: 400 var(--type-label) var(--pixel); color: var(--muted); }
.lvl:hover { border-color: var(--muted); color: var(--ink); }
.lvl[aria-pressed="true"] { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.tiles { display: flex; flex-wrap: wrap; gap: 6px; }
.tile-chip { display: flex; align-items: center; gap: 8px; padding: 3px 12px 3px 3px; border-radius: 8px; background: var(--panel-2); border: 1px solid var(--line); font-size: var(--type-small); color: var(--ink); }
.tile-chip i { width: 24px; height: 24px; border-radius: 4px; display: block; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18); }
.tile-chip .ch { font: 600 var(--type-label) var(--mono); color: var(--muted); }
.tile-chip[aria-pressed="true"] { border-color: var(--accent); }
.map-grid { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; touch-action: none; user-select: none; width: 100%; }
.map-grid div { aspect-ratio: 1 / 1; display: grid; place-items: center; font: 600 var(--type-label) var(--mono); color: #fff; cursor: crosshair; }
.map-grid div:hover { outline: 2px solid var(--ink); outline-offset: -2px; }
.map-grid div, .tiles i { image-rendering: pixelated; }   /* a tile that wears art shows its pixels sharp */
.map-grid div.out-of-reach { outline: 2px solid var(--bad); outline-offset: -2px; }
/* where the player can get to, lit when something is out of reach: a light wash, neither lime (the main action) nor
   sky (player two), so the dead end reads as the edge of the lit part; the square's own colour stays under it */
.map-grid div.reached { box-shadow: inset 0 0 0 999px rgba(255, 255, 255, .22); }
.map-grid div.reached.out-of-reach { box-shadow: none; }
/* the square in hand from the keyboard (studio.js mapCursor): the house's lime focus ring, drawn inside the square */
.map-grid div:focus-visible { outline: 3px solid var(--accent, #c6f432); outline-offset: -3px; position: relative; z-index: 1; }
/* the world map (explorer): one square per screen, gray where a screen can go */
.world-pane { --world-cell: 34px; }
.world-head { display: flex; align-items: flex-start; gap: 14px; margin: 0 0 12px; }
.world-where { display: grid; gap: 6px; min-width: 0; }
.world-where .eyebrow { font-size: var(--type-label); color: var(--muted); }
.world-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 20px; }
.world-map { display: grid; grid-auto-rows: var(--world-cell); gap: 4px; overflow-x: auto; padding: 2px; max-width: 100%; }
.world-cell { width: var(--world-cell); height: var(--world-cell); border-radius: 6px; padding: 0; position: relative; background-position: left center; }
.world-cell.off { background: #3d4560; border: 2px solid #4f5876; }
.world-cell.off:hover, .world-cell.off:focus-visible { background: #4f5876; border-color: var(--muted); }
.world-cell.on { background-color: #000; border: 2px solid var(--line-2); image-rendering: pixelated; }
.world-cell.on[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.world-cell.start::after { content: ""; position: absolute; left: 4px; bottom: 4px; width: 7px; height: 7px; border-radius: 2px; background: var(--good); box-shadow: 0 0 0 1px var(--surface); }
.world-scenes { display: flex; flex-wrap: wrap; gap: 6px; width: 100%; max-height: 140px; overflow-y: auto; padding: 2px; }
.world-scene { width: 52px; height: 52px; border-radius: 6px; border: 2px solid var(--line); background-color: #000; background-position: left center; image-rendering: pixelated; padding: 0; }
.world-scene[aria-pressed="true"] { border-color: var(--accent); }
.world-scene.black { background: #000; }
.world-grid { background-position: left center; image-rendering: pixelated; }
.world-grid div { box-shadow: inset 0 0 0 .5px rgba(255, 255, 255, .14); }
.map-scroll { overflow-x: auto; padding: 0 0 6px; scrollbar-color: var(--line) transparent; }
.map-note { margin: 10px 0 0; }
.level-check { display: flex; align-items: flex-start; gap: 12px; margin: 12px 0 10px; padding: 10px 14px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--surface); }
.level-check .eyebrow { flex: none; padding-top: 3px; font-size: var(--type-label); color: var(--muted); }
.level-check .check-text { flex: 1; font-size: var(--type-body); color: var(--ink); }
.level-check.warn-note { border-color: var(--caution); }
.level-check.warn-note .eyebrow, .level-check.warn-note .check-text { color: var(--caution); }
.play-level.on { border-color: var(--accent); color: var(--accent); }
.shape-knobs { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
/* Build your world: the map room's panel for a 3D game, whose world is built in the game itself (Build mode) */
.build-panel { display: grid; gap: 12px; max-width: 62ch; }
.build-panel p { margin: 0; }
.marks-panel { display: grid; gap: 10px; margin-top: 8px; padding-top: 16px; border-top: 1px solid var(--line); }
.mark-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.mark-picker .chip { background: transparent; color: var(--muted); cursor: pointer; }
.mark-picker .chip.on { color: var(--accent); }
.built-map { width: 100%; max-width: 360px; aspect-ratio: 1 / 1; image-rendering: pixelated; border: 1px solid var(--line); border-radius: 8px; cursor: crosshair; }
.shape-knobs .eyebrow { font-size: var(--type-label); margin: 0 0 14px; }

/* the code room */
.code-room { display: flex; flex-direction: column; gap: 10px; }
/* the code room takes the whole room: the workspace is the work, and the checker is a strip over it
   (the gutter already marks each problem on its line, so the strip says the verdict and lists findings
   only when there are some) */
body[data-place="code"] .room-body { max-width: none; }
.code-room .checker { order: -1; max-width: none; display: flex; align-items: baseline; gap: 6px 16px; flex-wrap: wrap; padding: 9px 14px; }
/* ONE BAR (2026-10-13): in the code room the head carries back, the name, and the checker as a slim strip;
   the room's note and the bottom bar step away, so the workspace starts high and runs to the floor */
body[data-place="code"] .room-body { padding-top: 14px; padding-bottom: 14px; }
body[data-place="code"] .room-head { margin: 0 0 12px; flex-wrap: nowrap; gap: 14px; }
body[data-place="code"] .room-note { display: none; }
body[data-place="code"] .room-title { font-size: 22px; flex: none; }
body[data-place="code"] .next { display: none; }
.room-head .checker { flex: 1 1 auto; min-width: 0; max-width: none; display: flex; align-items: center; gap: 6px 16px; padding: 6px 14px; border-radius: 20px; flex-wrap: wrap; }
.room-head .checker-head { margin: 0; flex: none; gap: 10px; }
.room-head #code-lines { display: none; }
/* in the one bar the ladder stays and its line steps away: the next move is the first finding, and Code's tip says it */
.room-head .code-stage { flex: none; }
/* THE LADDER KEEPS ITS WIDTH (class feedback #284, 2026-11-03: "the recommendations at the top overlap with other words").
   It was allowed to shrink (flex: 0 1 auto, and .code-stage's min-width: 0) while its rungs cannot, so a finding that
   wanted the room narrowed the ladder's box and BETA and GOLD painted over the finding's words. The findings give way
   instead: they wrap and scroll in their own box, on a row of their own when the bar is narrow (the all-clear line
   too, which a narrow bar had squeezed to no width at all). The bar's corners are 20px, not 999px: one row still reads
   as the pill, and a taller bar is a rounded box whose ends no longer cut off a finding's first and last lines. */
.room-head .code-stage .stage-line { display: none; }   /* a line count says nothing to a student; the room has no space to spend on it */
.room-head #findings { flex: 1 1 260px; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px; }   /* under 260px beside the ladder, a row of its own */
/* the checker's sentence wraps rather than ending in "This ru..." (usability pass, 2026-10-22: clipped text is a bug) */
.room-head #findings .all-clear { margin: 0; line-height: 1.3; }
.room-head .finding { margin: 4px 0; }
/* ONE LINE, THE LIST UNDER IT (2026-11-03 review: a missing brace grew the bar to 130px and cut its sentence in half).
   The bar holds the first problem's name, its line and "why"; the whole list opens under the bar, over the workspace,
   so opening it never moves the editor. Outside the code room's head the list is the card, as before. */
.findings-line { display: none; }
.room-head .findings-line { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; min-width: 0; position: relative; padding-left: 16px; }
.room-head .findings-line::before { content: ""; position: absolute; left: 0; top: calc(50% - 3px); width: 7px; height: 7px; background: var(--line-2); }
.room-head .findings-line.error::before { background: var(--bad); } .room-head .findings-line.warn::before { background: var(--caution); }
.room-head .findings-line .fix { margin: 0; }
.findings-name { font: 600 var(--type-body)/1.3 var(--body); }
.findings-line button { background: none; border: 0; padding: 0; color: var(--accent); font: 400 var(--type-small) var(--mono); cursor: pointer; }
.findings-line .findings-toggle { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; }
.findings-line .findings-toggle[aria-expanded="true"] { color: var(--ink); text-decoration-style: double; }
.findings-line .where.whole, .finding .where.whole { color: var(--muted); font: 400 var(--type-small) var(--mono); }   /* no line to find (#293) */
.room-head .checker { position: relative; }
.room-head #findings .findings-list { display: none; }
.room-head #findings.open .findings-list { display: block; position: absolute; z-index: 30; top: calc(100% + 6px); left: 0; right: 0;
  max-height: min(50vh, 420px); overflow: auto; padding: 12px 16px; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 12px 32px rgba(0, 0, 0, .45); }
.room-head #findings .fix { flex: none; }
/* too narrow for the whole line (player two's rail open beside the code): "or before" goes to the line's tip and the
   open list, never a second row */
.room-head #findings { container-type: inline-size; }
@container (max-width: 470px) { .findings-line .or-before { display: none; } }
/* on a laptop the eyebrow gives its width to the problem: the ladder's own word says the stage, and the card keeps its
   name for a screen reader (aria-label "The checker") */
@media (max-width: 1399px) { .room-head .checker-head { display: none; } }
/* code that will not start says so once: the problem's own line names it in red beside the dot, so the ladder's
   "won't start" rung, a second name for the same thing, steps away from the bar (the stage stays on Code's dot
   under the game, the lobby and Spawn Point) */
.room-head .code-stage:has(.rung.stop) { display: none; }
.code-room .checker-head { margin: 0; flex: none; gap: 10px; }
.code-room #findings { flex: 1 1 320px; min-width: 0; max-height: 140px; overflow: auto; }
.code-room #findings .all-clear { margin: 0; }
.code-room .finding { margin: 6px 0 8px; }
.code-room .finding:first-child { margin-top: 0; }
.editor { min-width: 0; }
.code-lab { display: block; width: 100%; height: 520px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.editor-row { margin-top: 8px; }
.checker { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; max-width: 320px; }
.checker-head { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 14px; }
/* THE STAGE LADDER (2026-10-27): four rungs in the pixel face, the one the game is at in lime, the ones behind it
   tinted, and the one move that climbs it beside them */
.code-stage { display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap; flex: none; min-width: 0; }
.code-stage .ladder { display: inline-flex; gap: 3px; }
.code-stage .rung { font: 400 var(--type-label)/1 var(--pixel); padding: 5px 6px; border-radius: 5px; border: 1px solid var(--line-2); color: var(--faint); }
.code-stage .rung.done { border-color: transparent; background: var(--accent-soft); color: var(--accent); }
.code-stage .rung.here { border-color: var(--accent); background: var(--accent); color: var(--accent-ink); }
.code-stage .rung.stop { border-color: var(--bad); color: var(--bad); }
/* ON A PHONE THE RUNGS WRAP (2026-11-03 review: at 390 wide the code room scrolled sideways to 427, the four rungs
   kept their width in one row past the edge). They still never shrink under each other's words (#284); they take
   a second row instead, and the checker's bar takes the room's width */
@media (max-width: 760px) {
  .room-head .checker { flex: 1 1 100%; }
  .room-head .code-stage, .code-stage { flex: 0 1 auto; max-width: 100%; }
  .code-stage .ladder { flex-wrap: wrap; }
}
.code-stage .stage-line { margin: 0; font-size: var(--type-small); color: var(--ink-2); }
.checker-head .muted { font: 400 var(--type-label) var(--mono); }
.finding { position: relative; padding-left: 16px; margin: 0 0 14px; }
.finding::before { content: ""; position: absolute; left: 0; top: 8px; width: 7px; height: 7px; background: var(--line-2); }
.finding.error::before { background: var(--bad); } .finding.warn::before { background: var(--caution); } .finding.info::before { background: var(--muted); }
.finding h5 { margin: 0; font: 600 var(--type-body) var(--body); }
.finding h5 small { font: 400 var(--type-label) var(--mono); color: var(--muted); margin-left: 6px; }
.finding p { margin: 3px 0 0; font-size: var(--type-small); color: var(--muted); }
.finding button { background: none; border: 0; padding: 0; color: var(--accent); font: 400 var(--type-small) var(--mono); }
.all-clear { margin: 0; font-size: var(--type-body); color: var(--accent); }

/* ---- 04 ship ---- */
/* THE ROW IS THE BUTTON (the pretty pass, D2 option A): the card's icon button stretches over its card, so the card's words
   are what a student reads and presses; the icon stays the keyboard's stop */
.row-button { position: relative; cursor: pointer; transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease); }
.row-button > .btn::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.row-button:hover { background: var(--panel-2); }
.row-button > .dry-result { position: relative; z-index: 1; }
.dryrun { position: relative; display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; padding: 20px 22px;
  background: var(--surface); border-radius: var(--radius-sm); margin: 0 0 24px; --bl: 18px; }
.dryrun > div:first-child { flex: 1 1 260px; }
.dry-text { margin: 4px 0 0; font-size: var(--type-body); color: var(--ink); max-width: 56ch; }
.dry-result { flex-basis: 100%; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: var(--type-body); color: var(--ink); }
.dry-result:empty { display: none; }
.ship-check { display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; padding: 16px 22px; margin: -8px 0 24px;
  border: 1px dashed var(--line); border-radius: var(--radius-sm); }
.ship-check > div:first-child { flex: 1 1 260px; }
.ship-check .dry-text { color: var(--muted); }
.submit-panel { padding: 22px; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: 14px 24px; align-items: end; }
.submit-panel .full { grid-column: 1 / -1; }
.submit-what { margin: 6px 0 0; font-size: var(--type-body); color: var(--ink); max-width: 60ch; }
.submit-public { margin: 6px 0 0; padding-left: 12px; border-left: 2px solid var(--line); font-size: var(--type-small); line-height: 1.5; color: var(--muted); max-width: 64ch; }
.submit-public strong { font-weight: 500; color: var(--ink); }
.share-log { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0 0; font-size: var(--type-small); line-height: 1.5; color: var(--ink); max-width: 64ch; cursor: pointer; }
.share-log input { flex: none; width: 18px; height: 18px; margin: 1px 0 0; }
/* THE SHARE BAR (share_bar.py): each item the lobby asks for, met or not, and what to do about the ones that are not */
.share-bar { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 4px; max-width: 64ch; font-size: var(--type-small); line-height: 1.45; }
.share-bar:empty { display: none; }
.share-bar li { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 8px; color: var(--ink); }
.share-bar li::before { content: ""; width: 10px; height: 10px; margin: 5px 4px 0; border-radius: 50%; background: var(--accent); }
.share-bar li.miss::before { background: transparent; box-shadow: inset 0 0 0 2px var(--caution); }
.share-bar li .fix { display: block; color: var(--muted); }
/* HOW TO SHARE / HOW TO UPDATE (#176): the steps left, in order, at the top of the panel */
.ship-steps-box { margin: 10px 0 14px; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-sm, 8px); max-width: 64ch; }
.ship-steps-head { margin: 0 0 6px; font-weight: 600; color: var(--ink); }
/* ONE LIST (2026-11-03 review): the share bar and the yes live in this box; the one step under them names the button.
   Once the link is up to date the list has nothing to ask, so only the step shows. */
.ship-steps { margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 4px; font-size: var(--type-small); line-height: 1.45; color: var(--ink); }
.ship-steps li.met { color: var(--muted); }
.ship-steps li.miss { color: var(--ink-2); }
.ship-steps-box.done .share-bar, .ship-steps-box.done .share-proud { display: none; }
.ship-steps-box.done .ship-steps { margin-top: 0; }
/* WHAT IS SHARED: one line in sight, every fact a press away */
.ship-shared { margin: 6px 0 0; max-width: 64ch; }
.ship-shared > summary { cursor: pointer; font-size: var(--type-small); color: var(--muted); }
.ship-shared > summary:hover, .ship-shared[open] > summary { color: var(--ink); }
.ship-shared .submit-as { margin: 8px 0 0; }
.share-proud { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0 0; font-size: var(--type-small); line-height: 1.5;
  font-weight: 500; color: var(--ink); max-width: 64ch; cursor: pointer; }
.share-proud input { flex: none; width: 18px; height: 18px; margin: 1px 0 0; }
.share-proud.miss { color: var(--caution); }
.share-proud.miss input { outline: 2px solid var(--caution); outline-offset: 2px; }
.next-note.to-go { color: var(--caution); cursor: pointer; }
.field { display: flex; flex-direction: column; gap: 6px; font-size: var(--type-small); color: var(--muted); }
.field[hidden] { display: none; }
.submit-panel .note:empty { display: none; }
.submit-panel .note { margin: 0; }
.submitted { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface);
  border: 1px solid var(--accent); animation: spawn-in var(--step) both; }
.submitted .eyebrow { font-size: var(--type-label); }
.submitted code { flex: 1; min-width: 0; font: 400 var(--type-small) var(--mono); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the play card (ship-qr.js): the picture and what to do with it, side by side, stacked on a narrow screen */
.ship-qr { display: flex; align-items: center; gap: 18px; flex-basis: 100%; padding-top: 12px; border-top: 1px solid var(--line); }
.ship-qr[hidden] { display: none; }
.ship-qr canvas { flex: none; width: 180px; height: auto; border-radius: 10px; }
.ship-qr-side { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.ship-qr-side .eyebrow { margin: 0; }
.ship-qr-what { margin: 0; font-size: var(--type-small); line-height: 1.5; color: var(--muted); max-width: 46ch; }
.ship-qr-buttons { display: flex; gap: 8px; flex-wrap: wrap; }
.btn.ghost { background: transparent; }
@media (max-width: 560px) { .ship-qr { flex-direction: column; align-items: flex-start; } }
.open-shelf { font: 600 var(--type-small) var(--body); color: var(--accent); text-decoration: none; white-space: nowrap; }
.featured-box { margin-top: 16px; }
.featured-links { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 20px; }

/* ---- dialogs ---- */
dialog { background: var(--panel); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px;
  width: min(680px, calc(100vw - 32px)); max-height: calc(100dvh - 64px); overflow: auto; box-shadow: var(--shadow); }
dialog[open] { animation: spawn-in var(--step) both; }
dialog::backdrop { background: rgba(6, 9, 10, .72); }
dialog h2 { margin: 0 0 6px; font: 800 24px var(--display); letter-spacing: -.03em; }
.dialog-foot { margin-top: 16px; }
/* the confirm (studio.js confirmFirst): a small panel in the middle of a dimmed, softened screen */
.confirm-dialog { width: min(440px, calc(100vw - 32px)); padding: 26px 28px 22px; border-color: var(--line-2);
  background: linear-gradient(180deg, var(--panel-2), var(--panel)); box-shadow: var(--shadow), 0 0 0 1px rgba(91, 127, 255, .08); }
.confirm-dialog::backdrop { background: rgba(4, 6, 16, .62); backdrop-filter: blur(6px) saturate(.8); -webkit-backdrop-filter: blur(6px) saturate(.8); }
.confirm-dialog[open] { animation: confirm-in 220ms var(--enter) both; }
.confirm-eyebrow { margin: 0 0 10px; font: 400 var(--type-label) var(--pixel); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }   /* the studio asking, not player two */
.confirm-text { margin: 0; font: 400 var(--type-lead)/1.5 var(--body); color: var(--ink); text-wrap: pretty; }
.confirm-foot { display: flex; justify-content: flex-end; gap: 10px; margin-top: 24px; }
.confirm-dialog.danger .confirm-eyebrow { color: var(--bad); }
.confirm-dialog.danger #confirm-yes { background: var(--bad); border-color: var(--bad); color: var(--accent-ink); }
.confirm-dialog.danger #confirm-yes:hover { filter: brightness(1.08); }
@keyframes confirm-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .confirm-dialog[open] { animation: none; } }
.version { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px; align-items: center; padding: 12px 0; border-top: 1px solid var(--line); }
.version .tag { font: 400 var(--type-label) var(--pixel); color: var(--muted); white-space: nowrap; }
.version.submit .tag { color: var(--accent); }
.version .name-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.version .name { background: none; border: 0; padding: 0; font: 600 var(--type-body) var(--body); color: var(--ink); cursor: text; text-align: left; }
.version .name:hover { text-decoration: underline; text-decoration-color: var(--muted); }
.version .rename { padding: 4px 8px; border-color: var(--accent); font: 600 var(--type-body) var(--body); min-width: 220px; width: auto; }
.version .pill { font: 400 var(--type-label) var(--pixel); color: var(--accent); border: 1px solid var(--accent); border-radius: 999px; padding: 2px 8px; }
.version .now { font: 400 var(--type-label) var(--pixel); color: var(--muted); }
.version .meta { display: block; font: 400 var(--type-small) var(--mono); color: var(--muted); }
.version .acts { display: flex; gap: 6px; }
.log-list { margin: 12px 0; }
.log-entry { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px 14px; margin: 0 0 10px; }
.log-entry h3 { margin: 0 0 6px; font: 400 var(--type-label) var(--pixel); color: var(--accent); }
.log-entry p { margin: 0 0 4px; font-size: var(--type-body); }
.log-entry input { margin: 6px 0 0; font-size: var(--type-body); }

/* UNDER THE HEADER, OVER NOTHING TO PRESS (2026-11-03 review): at the bottom it sat on the row of controls under the
   game, Restart and Undo among them, for the two seconds after every save and sign-in */
.toast { position: fixed; left: 50%; top: 72px; transform: translateX(-50%); background: var(--ink); color: var(--surface);
  font-weight: 600; font-size: var(--type-body); padding: 10px 18px; border-radius: var(--radius-sm); opacity: 0; pointer-events: none; z-index: 50;
  transition: opacity 160ms steps(4, end); max-width: calc(100vw - 32px); text-align: center; }
.toast.on { opacity: 1; }
.unsaved { position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 60; display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 8px 16px; padding: 12px 16px; background: var(--panel); color: var(--ink); border: 2px solid var(--bad);
  border-radius: var(--radius-sm); box-shadow: var(--shadow); font-size: var(--type-body); }
.unsaved[hidden] { display: none; }
.unsaved strong { color: var(--bad); }

/* ---- shared with the admin ---- */
.top { display: flex; align-items: flex-end; justify-content: space-between; gap: 18px 24px; flex-wrap: wrap; padding: 36px 0 4px; }
.back { font: 400 var(--type-small) var(--mono); color: var(--ink); text-decoration: none; border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 10px 14px; white-space: nowrap; transition: border-color var(--fast) var(--ease); }
.back:hover { border-color: var(--muted); color: var(--ink); }
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; min-width: 0; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 16px; }
.foot { margin: 48px 0 0; padding: 22px 0 48px; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap;
  gap: 14px 32px; justify-content: space-between; align-items: flex-start; color: var(--muted); font-size: var(--type-body); }
.foot p { margin: 0; max-width: 64ch; }
.foot .links { display: flex; gap: 18px; flex-wrap: wrap; font: 400 var(--type-small) var(--mono); }
.foot .links a { color: var(--muted); text-decoration: none; }
.foot .links a:hover { color: var(--ink); }
.screen.static { width: 100%; }
.screen.static .screen-inner { width: 100%; height: auto; aspect-ratio: 1 / 1; }

/* ---- the admin (app.py::_page) ---- */
.admin { max-width: 760px; margin: 0 auto; padding: 0 16px 60px; }
.admin .lede { margin: 30px 0 26px; font-size: var(--type-lead); color: var(--ink); max-width: 62ch; }
.admin .panel { margin: 0 0 14px; }
.admin .panel h2 { margin: 0 0 6px; font: 600 var(--type-lead) var(--body); }
.admin form.row { margin: 12px 0 0; }
.admin .row input[type=text], .admin .row input[type=password] { flex: 1 1 220px; width: auto; }
.admin .btn.stop { color: var(--bad); border-color: rgba(255, 92, 122, .45); background: transparent; }
.admin .btn.stop:hover { border-color: var(--bad); }
.admin label.note { display: flex; gap: 8px; align-items: center; margin: 0; }
.admin label.note input { accent-color: var(--accent); width: 18px; height: 18px; }
.flash { border-radius: var(--radius-sm); padding: 11px 14px; margin: 0 0 16px; font-size: var(--type-body); }
.flash.good { background: var(--accent-soft); border: 1px solid var(--accent); }
.flash.bad { background: rgba(255, 92, 122, .1); border: 1px solid var(--bad); }
.panel.warn { border-color: rgba(255, 181, 71, .5); }
.panel.warn h2 { color: var(--caution); }
.state-on { color: var(--accent); } .state-off { color: var(--muted); }
strong.code { font-family: var(--mono); color: var(--accent); }

/* ---- a drop zone, and a game's name in a section label ---- */
.drop p { margin: 0 0 12px; }
.drop .row { margin: 0 0 12px; }
.drop.over { border-color: var(--accent); background: var(--accent-soft); }
.sectional .game-name { font: 600 var(--type-body) var(--body); color: var(--ink); text-transform: none; letter-spacing: 0; }
.sectional .game-name::before { content: "\00b7"; color: var(--muted); margin-right: 8px; }


/* ---- narrow ---- */
/* under 1100px the station numerals go, and an OPEN player two lies over the screen instead of
   taking a column: the grid keeps the 56px strip, so opening it never shrinks the game */
@media (max-width: 1100px) {
  .bar { gap: 16px; padding: 10px 16px; }
  .station { padding: 8px; }
  .station .n { display: none; }
  .link-bar { width: 10px; }
  .bench { --p2w: 56px; }
  .bench:not(.p2-folded) .p2-rail { position: absolute; right: 0; top: 0; bottom: 0; width: min(340px, calc(100vw - 380px)); z-index: 20; box-shadow: var(--shadow); }
}
/* a phone: one column, the page scrolls, the game first */
@media (max-width: 760px) {
  .studio { height: auto; min-height: 100dvh; }
  .bar { flex-wrap: wrap; }
  .line { order: 3; flex-basis: 100%; justify-content: flex-start; }
  .game-button { max-width: 180px; }
  .bench { display: flex; flex-direction: column; }
  .screen-col { order: -1; border-left: 0; border-bottom: 1px solid var(--line); overflow: visible; }
  .screen { position: relative; }
  .screen-row, .story-strip { position: static; margin-top: 0; padding: 0; box-shadow: none; }
  .room { overflow: visible; }
  .bench:not(.p2-folded) .p2-rail { position: fixed; inset: auto 0 0 0; width: 100%; height: 70dvh; }
  .p2-rail { border-left: 0; border-top: 1px solid var(--line); }
  .bench.p2-folded .p2-rail { display: none; }
  .dryrun, .featured-box { grid-template-columns: minmax(0, 1fr); }
  .checker { max-width: none; }
}

/* ---- moments (studio.js, "moments"): the instance, solid, the save point, shipping, player two asleep ---- */
.screen.spawning { --b: var(--accent); }
.screen.spawning::before { animation: bracket-flare 700ms steps(4, end) both; }
@keyframes bracket-flare { 0% { filter: drop-shadow(0 0 14px rgba(198, 244, 50, .95)); } 100% { filter: drop-shadow(0 0 0 rgba(198, 244, 50, 0)); } }
.render-sweep { position: absolute; left: 0; right: 0; top: 0; height: 100%; z-index: 2; pointer-events: none; opacity: 0;
  background: linear-gradient(180deg, transparent 0 calc(100% - 3px), rgba(198, 244, 50, .9) calc(100% - 3px)), linear-gradient(180deg, rgba(91, 127, 255, .14), rgba(62, 230, 160, .1));
  transform-origin: top; }
.render-sweep.spawning { animation: render-sweep 520ms steps(10, end) both; }
@keyframes render-sweep { 0% { opacity: 1; transform: scaleY(0); } 92% { opacity: 1; transform: scaleY(1); } 100% { opacity: 0; transform: scaleY(1); } }
.instance-tag { position: absolute; left: 10px; bottom: 8px; z-index: 2; pointer-events: none; opacity: 0;
  font: 400 var(--type-label) var(--pixel); color: var(--accent); text-shadow: 0 0 8px rgba(0, 0, 0, .9); }
.instance-tag.spawning { animation: instance-tag 2400ms steps(8, end) both; }
@keyframes instance-tag { 0% { opacity: 0; } 8% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; } }
.chip { position: relative; }
.chip.flare { animation: chip-flare 600ms steps(4, end); }
@keyframes chip-flare { 0% { transform: scale(1.25); box-shadow: 0 0 0 0 rgba(198, 244, 50, .8); } 100% { transform: none; box-shadow: 0 0 0 12px rgba(198, 244, 50, 0); } }
.chip .burst { position: absolute; left: 50%; top: 50%; width: 5px; height: 5px; margin: -2px 0 0 -2px; background: var(--accent); pointer-events: none;
  animation: burst 700ms steps(6, end) both; }
@keyframes burst { from { transform: translate(0, 0); opacity: 1; } to { transform: translate(var(--dx), var(--dy)); opacity: 0; } }
.stamp { position: fixed; left: 50%; top: 22%; z-index: 70; display: flex; flex-direction: column; align-items: center; gap: 6px; pointer-events: none; opacity: 0;
  transform: translateX(-50%); padding: 18px 34px 20px; border: 2px solid var(--accent); border-radius: 6px;
  background: color-mix(in srgb, var(--surface) 82%, transparent); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 12%, transparent), 0 30px 80px -20px rgba(0, 0, 0, .9), 0 0 60px -10px rgba(198, 244, 50, .45); }
.stamp.on { animation: stamp 1700ms steps(1, end) both; }
.stamp.big.on { animation-duration: 2600ms; }
@keyframes stamp { 0% { opacity: 0; transform: translateX(-50%) scale(1.3); } 6% { opacity: 1; transform: translateX(-50%) scale(1.08); } 12% { transform: translateX(-50%) scale(1); }
  88% { opacity: 1; } 100% { opacity: 0; transform: translateX(-50%); } }
.stamp-k { font: 400 var(--type-small) var(--pixel); color: var(--accent); letter-spacing: .06em; }
.stamp-v { font: 800 44px/1 var(--display); letter-spacing: -.04em; background: var(--genesis); -webkit-background-clip: text; background-clip: text; color: transparent; padding-bottom: .06em; }
.stamp.big .stamp-v { font-size: 72px; }
.confetti { position: fixed; inset: 0; z-index: 69; pointer-events: none; }
.confetti i { position: absolute; width: var(--s, 8px); height: var(--s, 8px); animation: confetti 1900ms cubic-bezier(.2, .6, .4, 1) both; }
@keyframes confetti { 0% { transform: translate(0, 0) rotate(0); opacity: 1; } 55% { transform: translate(calc(var(--dx) * .8), var(--dy)) rotate(calc(var(--r) * .6)); opacity: 1; }
  100% { transform: translate(var(--dx), calc(var(--dy) * -.4 + 280px)) rotate(var(--r)); opacity: 0; } }
/* player two, asleep: when it is not switched on, the rail holds a sleeping robot, not an empty box */
.p2-asleep { position: relative; flex: 1; display: grid; place-items: center; min-height: 220px; }
.p2-asleep .sleeper { width: 96px; height: 96px; background: url("/code/library/originals/robot_teal_idle.png") 0 0 / 384px 96px no-repeat; image-rendering: pixelated;
  filter: saturate(.5) brightness(.7) drop-shadow(0 0 18px rgba(91, 127, 255, .35)); animation: sleeper 3.2s steps(4) infinite; }
@keyframes sleeper { from { background-position: 0 0; } to { background-position: -384px 0; } }
.p2-asleep .bed { position: absolute; left: 50%; top: calc(50% + 46px); width: 120px; height: 14px; transform: translateX(-50%); border-radius: 50%;
  background: radial-gradient(closest-side, rgba(91, 127, 255, .35), transparent); }
.p2-asleep .zz { position: absolute; left: calc(50% + 34px); top: calc(50% - 52px); font: 400 var(--type-small) var(--pixel); color: var(--p2); opacity: 0;
  animation: zz 3s steps(6, end) infinite; }
.p2-asleep .zz.two { animation-delay: 1s; font-size: var(--type-body); }
.p2-asleep .zz.three { animation-delay: 2s; font-size: var(--type-lead); }
@keyframes zz { 0% { opacity: 0; transform: translate(0, 0); } 20% { opacity: 1; } 100% { opacity: 0; transform: translate(18px, -34px); } }

/* the ship page's two plain warnings: signed out before a submit, and a link whose title is behind the game's */
.submit-account, .link-stale { margin: 0; padding: 10px 12px; border: 1px solid var(--caution); border-radius: var(--radius-sm);
  color: var(--ink-2); font-size: var(--type-small); }
.submit-account a { color: var(--caution); font-weight: 700; }
.submit-account[hidden], .link-stale[hidden] { display: none; }
.submit-as { margin: 0; color: var(--ink-2); font-size: var(--type-small); }
.submit-as[hidden] { display: none; }
.submitted .link-stale { flex-basis: 100%; }
/* a link behind the work: what it plays is not the game on the bench until the student submits again */
.submitted.behind code, .submitted.behind .ship-qr canvas { opacity: .45; }

/* the art room's "copy art from" row: another sprite's art onto this one */
.art-from { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.art-from select { min-height: 34px; padding: 0 10px; background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--radius-sm); font: 500 var(--type-small) var(--body); }

/* the art room's frame strip: every frame of the animation, in order, under the art */
.in-game-box .frames-box { grid-column: 1 / -1; min-width: 0; margin-bottom: 8px; }
.frames-said { font-size: var(--type-small); color: var(--muted); }
.frames-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-bottom: 8px; }
.frame-strip { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.frame-cell { flex: none; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px; min-width: 76px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted); cursor: pointer;
  font-size: var(--type-label); }
.frame-cell:hover { border-color: var(--muted); color: var(--ink); }
/* in Upload, the frame the next picture goes into (class report #322) */
.frame-cell.picked { border-color: var(--accent); color: var(--ink); box-shadow: 0 0 0 1px var(--accent) inset; }
.upload-into { margin: 10px 0 0; font-size: var(--type-small); color: var(--muted); }
.frame-cell img { width: 56px; height: 56px; object-fit: contain; image-rendering: pixelated;
  background: repeating-conic-gradient(var(--panel) 0 25%, var(--panel-2) 0 50%) 0 0 / 8px 8px; }
.drop.backdrop-drop { padding: 18px 20px; margin-bottom: 14px; text-align: center; }
/* the background is ONE of three, said in words (wchesher, 2026-10-26: "unambiguous and easy to do") */
.backdrop-kinds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.backdrop-kind { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 12px 14px; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); cursor: pointer; }
.backdrop-kind b { font: 600 var(--type-body) var(--body); }
.backdrop-kind small { font-size: var(--type-small); color: var(--muted); }
.backdrop-kind:hover { border-color: var(--accent); }
.backdrop-kind[aria-checked="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); background: var(--panel-2); }
.backdrop-now { margin: 0; }
.backdrop-own { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.backdrop-own .eyebrow { flex-basis: 100%; }
.backdrop-own .slot .ic img { width: 48px; height: 48px; image-rendering: pixelated; }
@container (max-width: 560px) { .backdrop-kinds { grid-template-columns: 1fr; } }

/* ---- the companion's door: the Help card in the bar (companion-link.js); the companion itself is
   /companion/, on the student's phone ---- */
.bar-help { min-height: 32px; padding: 0 12px; background: transparent; border: 1px solid var(--line); border-radius: var(--radius-sm);
  font: 400 var(--type-small) var(--mono); color: var(--ink-2); white-space: nowrap; }
.bar-help:hover, .bar-help[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }
.bar-p2 { display: none; }
@media (max-width: 760px) { .bar-p2 { display: inline-flex; } }
.bar-p2 .icon { color: var(--p2); }
.bar-p2 .p2-unread { height: 18px; min-width: 18px; padding: 0 5px; }
.help-pop { width: min(300px, calc(100vw - 32px)); padding: 14px; display: grid; gap: 10px; justify-items: start; }
.help-pop-say { margin: 0; font-size: var(--type-small); color: var(--ink-2); line-height: 1.5; }
/* the spawn point brackets around the code (qr-face.js draws the code, the mark in its middle): lime with player two's
   royal at the foot, all OUTSIDE the white tile, as on Spawn Point's card (gamecenter.css .qr-brackets) */
.help-qr { --arm: 20px; --bar: 4px; justify-self: center; width: 196px; height: 196px; padding: 9px; box-sizing: border-box;
  background:
    linear-gradient(var(--accent) 0 0) top left / var(--arm) var(--bar) no-repeat, linear-gradient(var(--accent) 0 0) top left / var(--bar) var(--arm) no-repeat,
    linear-gradient(var(--accent) 0 0) top right / var(--arm) var(--bar) no-repeat, linear-gradient(var(--accent) 0 0) top right / var(--bar) var(--arm) no-repeat,
    linear-gradient(var(--accent) 0 0) bottom right / var(--arm) var(--bar) no-repeat, linear-gradient(var(--accent) 0 0) bottom right / var(--bar) var(--arm) no-repeat,
    linear-gradient(var(--p2) 0 0) bottom left / var(--arm) var(--bar) no-repeat, linear-gradient(var(--p2) 0 0) bottom left / var(--bar) var(--arm) no-repeat; }
.help-qr svg { display: block; width: 100%; height: 100%; border-radius: 6px; box-shadow: 0 0 26px rgba(91, 127, 255, .35); }
.help-link { justify-self: center; font: 400 var(--type-small) var(--mono); color: var(--accent); }
.help-pop-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }

/* TIGHT UNDER THE GAME (Maestro, 2026-10-19: "the buttons need to be tight vertically"). Every control in
   the row under the game and in Tools stands 30 tall, the switch bar included (its own padding counted), so
   the row reads as one clean line and costs the game less height. */
.screen-status .btn.tiny, .screen-status .speed-pick, .tool, .debug-row select.tool { height: 30px; min-height: 30px; }
.screen-row .view-bar { padding: 2px; gap: 2px; }
.screen-row .view { height: 24px; min-height: 24px; }
.screen-row .view.icon-only { width: 32px; }
@container screen (min-width: 520px) { .screen-row .view-bar { align-self: center; } }
.screen-status .chip { padding: 2px 10px; }
#next-back { min-height: 34px; height: 34px; padding: 0 10px; }

/* NO WORDS ON BUTTONS (Maestro, 2026-10-19: "DO AWAY WITH TEXT ON BUTTONS EXCEPT FOR EXCEPTIONS WHICH ARE ABSOLUTELY
   NECESSARY"): a button the studio made wordless (studio.js wordless) is a square of its own height, the icon centred */
button.icon-only:not(.fix), a.icon-only { padding-left: 0; padding-right: 0; justify-content: center; gap: 0; aspect-ratio: 1 / 1; }
button.icon-only:not(.fix)::before, a.icon-only::before { content: none; }
.btn.icon-only:not(.fix) { min-width: var(--btn-h); }
.btn.small.icon-only:not(.fix) { min-width: var(--btn-h-small); }
/* THE TIP ("We can make a custom in context alt tag that provides the info"): the words of a wordless button, in the
   studio's look, above it (below when there is no room), shown on hover and on keyboard focus */
.tip { position: fixed; z-index: 1000; pointer-events: none; max-width: 260px; padding: 6px 10px; border-radius: 8px;
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line); box-shadow: 0 6px 20px rgba(0, 0, 0, .45);
  font: 500 var(--type-small)/1.3 var(--body); opacity: 0; transform: translateY(2px); transition: opacity 90ms, transform 90ms; }
.tip.on { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .tip { transition: none; } }
/* the history's controls stand 30 tall like the rest of the row under the game; its step buttons are smaller still */
.history-wrap .btn.tiny, .history-head .btn.tiny { height: 30px; min-height: 30px; }
.history-wrap .btn.tiny.icon-only, .history-head .btn.tiny.icon-only { width: 34px; min-width: 34px; }
.btn.history-open { min-width: 34px; padding: 0 9px; color: var(--caution); font: 600 var(--type-small) var(--mono); white-space: nowrap; }
.btn.history-open .unit { font-weight: 400; }
.history-step .btn.history-go { height: 26px; min-height: 26px; width: 28px; min-width: 28px; }
.map-history .btn.tiny.icon-only { width: 34px; min-width: 34px; height: 30px; min-height: 30px; }

/* PLACE: a box over each sprite that starts at two plain numbers; drag one to move where it starts. */
.place-layer { position: absolute; inset: 0; z-index: 3; }
.place-layer[hidden] { display: none; }
.place-box { position: absolute; min-width: 14px; min-height: 14px; padding: 0; border: 2px dashed var(--accent); border-radius: 3px;
  background: color-mix(in srgb, var(--accent) 14%, transparent); cursor: grab; touch-action: none; }
.place-box:hover, .place-box:focus-visible, .place-box.dragging { border-style: solid; background: color-mix(in srgb, var(--accent) 24%, transparent); outline: none; }
.place-box.dragging { cursor: grabbing; z-index: 1; }
.place-tag { position: absolute; left: 50%; bottom: calc(100% + 4px); transform: translateX(-50%); padding: 1px 6px; border-radius: 5px; white-space: nowrap;
  background: var(--surface); color: var(--accent); border: 1px solid var(--accent); font-size: var(--type-label); pointer-events: none; }
.place-box:not(:hover):not(:focus-visible):not(.dragging) .place-tag { opacity: .75; }
/* A TAG STAYS ON THE GAME (the seams pass): a box near a side anchors its tag to that side instead of its middle, and a
   box at the top puts it underneath (studio.js placeTagSide) */
.place-box.tag-left .place-tag { left: 0; transform: none; }
.place-box.tag-right .place-tag { left: auto; right: 0; transform: none; }
.place-box.tag-below .place-tag { bottom: auto; top: calc(100% + 4px); }

/* DECORATE: the room's library to drag from and its list of what is on the game; the game under it is the drop
   target (studio.js renderDecorateRoom, wireDecorDrop). */
.place-layer.decorating { cursor: copy; }
/* scenery is a solid box, a sprite a dashed one, so the two read apart on one game */
.place-box.decor-box { border-style: solid; border-width: 1.5px; }
/* the x on a picture's corner (studio.js renderDecorBoxes): shown while the pointer is on the picture or it is picked */
.decor-off { position: absolute; transform: translate(-50%, -50%); width: 22px; height: 22px; padding: 0; border-radius: 50%;
  border: 1px solid var(--bad); background: var(--panel); color: var(--bad); font: 700 var(--type-body)/1 var(--body); cursor: pointer;
  opacity: 0; pointer-events: none; transition: opacity var(--fast) var(--ease); z-index: 3; }
.decor-box:hover + .decor-off, .decor-box:focus-visible + .decor-off, .decor-box:focus + .decor-off, .decor-off:hover, .decor-off:focus-visible {
  opacity: 1; pointer-events: auto; }
@media (hover: none) { .decor-off { opacity: 1; pointer-events: auto; } }
.place-layer.drop-here { outline: 2px dashed var(--accent); outline-offset: -2px; background: color-mix(in srgb, var(--accent) 8%, transparent); }
.decorate-room { display: flex; flex-direction: column; gap: 12px; }
.decorate-room .art-card[draggable="true"] { cursor: grab; }
.decor-list { display: flex; flex-direction: column; gap: 2px; padding-top: 12px; border-top: 1px solid var(--line); }
.decor-row { display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; grid-template-areas: "pic name off" "pic at size"; align-items: center; column-gap: 10px; padding: 6px 0; }
.decor-row.elsewhere { opacity: .6; }
.decor-pic { grid-area: pic; width: 30px; height: 30px; background: center / contain no-repeat; image-rendering: pixelated; }
.decor-name { grid-area: name; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.decor-at { grid-area: at; color: var(--muted); font-size: var(--type-label); }
.decor-size { grid-area: size; width: 110px; }
.decor-row .btn { grid-area: off; justify-self: end; }

/* ---- the one search (Maestro, 2026-10-22: "one search to rule them all", then "C. A is ugly"): one button in the
   bar opens Find, a pop-up over the studio with the field on top and the results under it. Each result says what it
   is in words under its name; the kind row is the art room's own facet row. studio.js, the one search. */
.bar-find { width: 34px; padding: 0; justify-content: center; }
.find-dialog { width: min(860px, calc(100vw - 32px)); height: min(760px, calc(100dvh - 64px)); padding: 0; overflow: hidden; }
.find-dialog[open] { display: flex; flex-direction: column; }
.find { flex: none; position: relative; display: flex; align-items: center; gap: 8px; padding: 16px 16px 12px; border-bottom: 1px solid var(--line); }
.find > .icon { position: absolute; left: 30px; width: 18px; height: 18px; color: var(--muted); pointer-events: none; }
.find input { flex: 1; min-width: 0; height: 46px; padding: 0 14px 0 44px; border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--well);
  color: var(--ink); font: 400 var(--type-body) var(--mono); }
.find input::placeholder { color: var(--faint); }
.find input:focus-visible { outline: 0; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.find input::-webkit-search-cancel-button { filter: grayscale(1); }
.find-close { flex: none; min-width: 40px; min-height: 40px; display: inline-grid; place-items: center; }
.find-esc { flex: none; font: 400 var(--type-label)/1.3 var(--mono); color: var(--muted); white-space: nowrap; }
@media (max-width: 760px) { .find-esc { display: none; } }
.find-sheet { flex: 1; min-height: 0; overflow: auto; padding: 0 16px 18px; display: grid; gap: 14px; align-content: start; }
.find-start { display: grid; gap: 12px; padding-top: 16px; }
.find-start .note { margin: 0; max-width: 60ch; }
.find-head { display: flex; align-items: flex-start; gap: 10px; position: sticky; top: 0; margin: 0 -16px; padding: 12px 16px 10px; background: var(--panel); z-index: 1; }
.find-head .facet { flex: 1; }
.find-kinds button { height: 26px; padding: 0 10px; font-size: var(--type-label); }
.find-kind.none { opacity: .5; }
.find-body { display: grid; gap: 18px; }
.find-group { display: grid; gap: 8px; }
.find-group-head { display: flex; align-items: baseline; gap: 8px; }
.find-group-head .eyebrow { margin: 0; }
.find-group-head .count { font: 400 var(--type-small) var(--mono); color: var(--faint); }
.find-all { margin-left: auto; }
.find-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 6px; }
.find-card { display: flex; flex-direction: column; align-items: stretch; gap: 3px; padding: 6px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); text-align: left; cursor: pointer; min-width: 0; transition: border-color var(--fast) var(--ease); }
.find-card:hover, .find-card:focus-visible { border-color: var(--muted); }
.find-card[aria-expanded="true"] { border-color: var(--accent); }
.find-card .frame { width: 56px; height: 56px; align-self: center; border-radius: 6px; image-rendering: pixelated; background-repeat: no-repeat; background-position: 0 0;
  background-color: var(--panel-2); }
.find-card .frame.smooth { image-rendering: auto; }
.find-background, .find-artpack { grid-column: span 2; }
.find-background .frame { width: 100%; height: auto; aspect-ratio: 2; background-size: cover !important; }
.find-set { height: 56px; border-radius: 6px; display: flex; align-items: center; justify-content: center; gap: 4px; }
.find-set .pic { width: 30px; height: 30px; background-size: auto 100%; background-repeat: no-repeat; image-rendering: pixelated; }
.find-card .name { font: 400 var(--type-label) var(--mono); line-height: 1.3; color: var(--ink-2); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.find-card .what, .find-row-say small { font: 400 var(--type-label) var(--pixel); letter-spacing: .04em; color: var(--muted); text-transform: lowercase; }
.find-use { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; padding: 10px 12px; border: 1px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--accent-soft); }
.find-use .frame { width: 44px; height: 44px; flex: none; border-radius: 6px; image-rendering: pixelated; background-repeat: no-repeat; background-color: var(--panel-2); }
.find-use-say { display: grid; gap: 1px; min-width: 0; }
.find-use-say b { font: 600 var(--type-body) var(--body); }
.find-use-say small { font: 400 var(--type-small) var(--mono); color: var(--muted); }
.find-use-slots { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.find-rows { display: grid; gap: 6px; }
.find-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 6px 8px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface); }
.find-row.find-soundpack, .find-row.find-game { grid-template-columns: minmax(0, 1fr) auto; }
.find-row-say { display: grid; gap: 2px; min-width: 0; }
.find-row-say b { font: 600 var(--type-small) var(--body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.find-row-say small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-transform: none; font-family: var(--mono); }
.find-play { min-width: 34px; min-height: 34px; padding: 0; display: inline-grid; place-items: center; }
.find-play[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }
.find-moments { grid-column: 1 / -1; padding-top: 4px; }
.find-use-open[aria-expanded="true"] { border-color: var(--accent); color: var(--accent); }
.find-more { justify-self: start; }
.find-none { margin: 0; }
@media (max-width: 760px) { .find-dialog { width: calc(100vw - 16px); height: calc(100dvh - 32px); } .find { padding: 12px 12px 10px; } .find > .icon { left: 24px; } .find-sheet { padding: 0 12px 14px; } .find-head { margin: 0 -12px; padding: 10px 12px 8px; } }
/* the ways in carry their words (the UX pass), so the row wraps in a narrow column rather than running off it */
.maker-head .tabs { flex-wrap: wrap; }
.maker-head .tabs button .icon { margin-right: 6px; }

/* THE THUMBNAIL WHILE DRAWING (2026-11-03 review): when Piskel takes the width the game is a 160-pixel thumbnail,
   and its controls stacked three lines deep, one group a line. Below 240 pixels the groups flow together, undo
   beside the run controls and the four switches under them, at 26 pixels (over the 24-pixel target floor), so
   it is two lines and every control is still there; the count shows its number, its words in its tip, as the
   Spawn Point link shows its icon alone on a phone (wchesher, 2026-11-03: "Only the count and Spawn Point"). */
@container screen (max-width: 240px) {
  #screen-row { gap: 4px; justify-content: flex-start; align-items: center; }
  #screen-row .screen-status { flex: none; gap: 2px; }
  #screen-row .history-wrap { order: 1; } #screen-row .view-bar { order: 2; }
  #screen-row .btn.tiny, #screen-row .view.icon-only { width: 26px; min-width: 26px; height: 26px; min-height: 26px; padding: 0; }
  #screen-row .btn.history-open { width: auto; min-width: 22px; padding: 0 5px; aspect-ratio: auto; }
  #screen-row .history-open .unit { display: none; } }

/* ONE UNDO ON SCREEN (2026-11-03 second review: the art room showed three Undo/Redo pairs and the map two). The art
   room's pair (where you draw: class report, 2026-10-22, "The undo broked should be in the spirte drawing") and the
   map's (class feedback, 2026-10-19) do exactly what the pair under the game does there (studio.js undoKey,
   artUndo), so while a room shows its own pair, the one under the game steps aside; the count and its history stay.
   A room view with no pair of its own (the art index, a backdrop) keeps the one under the game. */
body[data-place="art"]:has(#painter-room #art-undo) #screen-row :is(#undo, #redo),
body[data-place="map"]:has(#map-room .map-history .undo-button) #screen-row :is(#undo, #redo) { display: none; }
/* the decorate room (studio.js renderDecorateRoom): its steps with its own Undo and Redo, so the pair under the game steps aside */
body[data-place="decorate"]:has(#decorate-room .decor-history .undo-button) #screen-row :is(#undo, #redo) { display: none; }
.decor-start { display: flex; align-items: flex-start; gap: 12px; margin: 0 0 10px; }
.decor-steps { flex: 1 1 auto; margin: 0; padding: 0 0 0 1.4em; display: grid; gap: 4px; font-size: var(--type-body); line-height: 1.4; color: var(--ink-2); }
.decor-steps b { color: var(--ink); font-weight: 600; }
.decor-start .decor-history { flex: none; }
.decor-empty { margin: 4px 0 0; }
.decor-shelf { margin: 14px 0 6px; }
