/* Dark is the base palette. Light is defined once, below, and applied either
   by an explicit choice (data-theme) or by the computer's own setting. */
:root {
  --bg: #12151c;
  --bg-panel: #1a1e27;
  --bg-head: #212734;
  --line: #2c3341;
  --text: #dde3ee;
  --muted: #8a94a8;
  --accent: #4f8cff;
  --accent-hover: #3d78e8;
  --on-accent: #08182f;
  --green: #3ecf8e;
  --green-hover: #35b87d;
  --on-green: #0d2b1e;
  --red: #ff6b6b;
  --on-red: #3a0d0d;
  --purple: #b79cff;

  --hover-bg: #232936;
  --hover-line: #40495b;
  --sprite-hover: #1e2534;
  --banner-bg: #1d2740;
  --banner-line: #2b3a5e;
  --banner-text: #c3d3f2;
  --chip-game-bg: #221d38;
  --chip-game-line: #3d3560;
  --check-a: #171b23;
  --check-b: #1c212b;
  --shadow: rgba(0, 0, 0, .45);

  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --bar-h: 56px;
  --code-size: 14px;   /* editor + output only; the chrome never scales */

  color-scheme: dark;
}

/* Light. Accent and status colours are darkened so they stay legible on a
   classroom projector, which washes contrast out badly. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #ffffff;
    --bg-panel: #f6f8fb;
    --bg-head: #edf1f7;
    --line: #ccd4e0;
    --text: #161c28;
    --muted: #55607a;
    --accent: #1d4ed8;
    --accent-hover: #1e40af;
    --on-accent: #ffffff;
    --green: #15803d;
    --green-hover: #126c34;
    --on-green: #ffffff;
    --red: #b91c1c;
    --on-red: #ffffff;
    --purple: #6b21a8;

    --hover-bg: #e3e9f2;
    --hover-line: #9fadc4;
    --sprite-hover: #eaf0fa;
    --banner-bg: #e8eefb;
    --banner-line: #b9c9ea;
    --banner-text: #24365e;
    --chip-game-bg: #f0e9fb;
    --chip-game-line: #cdb6ea;
    --check-a: #e9edf4;
    --check-b: #dfe5ef;
    --shadow: rgba(24, 34, 54, .18);

    color-scheme: light;
  }
}

:root[data-theme="light"] {
  --bg: #ffffff;
  --bg-panel: #f6f8fb;
  --bg-head: #edf1f7;
  --line: #ccd4e0;
  --text: #161c28;
  --muted: #55607a;
  --accent: #1d4ed8;
  --accent-hover: #1e40af;
  --on-accent: #ffffff;
  --green: #15803d;
  --green-hover: #126c34;
  --on-green: #ffffff;
  --red: #b91c1c;
  --on-red: #ffffff;
  --purple: #6b21a8;

  --hover-bg: #e3e9f2;
  --hover-line: #9fadc4;
  --sprite-hover: #eaf0fa;
  --banner-bg: #e8eefb;
  --banner-line: #b9c9ea;
  --banner-text: #24365e;
  --chip-game-bg: #f0e9fb;
  --chip-game-line: #cdb6ea;
  --check-a: #e9edf4;
  --check-b: #dfe5ef;
  --shadow: rgba(24, 34, 54, .18);

  color-scheme: light;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  overflow: hidden;
}

/* ------------------------------------------------------------------- bar */
.bar {
  height: var(--bar-h);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  background: var(--bg-head);
  border-bottom: 1px solid var(--line);
}

.brand {
  font-weight: 650;
  font-size: 15px;
  letter-spacing: .2px;
  white-space: nowrap;
}
.logo { margin-right: 4px; }

.meta {
  display: flex;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.field {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  padding: 7px 10px;
  font: inherit;
  font-size: 13px;
  min-width: 0;
}
.field:focus { outline: none; border-color: var(--accent); }
.field::placeholder { color: var(--muted); }
.field[readonly] { opacity: .7; }
.field-bad {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(255, 107, 107, .18);
}
.field-bad:focus { border-color: var(--red); }
.field-title { flex: 1 1 260px; max-width: 340px; }
.field-author { flex: 0 1 160px; }

.actions { display: flex; gap: 8px; }

/* "Hide code" — turns Share into a demo link. Deliberately understated: it
   sits next to Share rather than announcing itself, and reads as a modifier
   to the button beside it rather than as an action of its own. */
.hidecode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 4px 0 2px;
  color: var(--muted);
  font-size: 12.5px;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}
.hidecode input { accent-color: var(--accent); cursor: pointer; margin: 0; }
.hidecode:hover { color: var(--text); }
.hidecode[hidden] { display: none; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  padding: 8px 14px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { border-color: var(--hover-line); background: var(--hover-bg); }
.btn:disabled { opacity: .5; cursor: default; }
/* .btn sets display, which would otherwise beat the browser's [hidden] rule */
.btn[hidden] { display: none; }

.btn-run {
  background: var(--green);
  border-color: var(--green);
  color: var(--on-green);
  font-weight: 650;
  min-width: 104px;
  justify-content: center;
}
.btn-run:hover:not(:disabled) { background: var(--green-hover); border-color: var(--green-hover); }
.btn-icon { font-size: 11px; }

.btn-icon-only {
  padding: 8px 11px;
  font-size: 15px;
  line-height: 1;
}

/* Code text size. Deliberately separate from browser zoom, which blows the
   toolbar up along with the code. */
.stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--bg);
}

.step {
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  line-height: 1;
  padding: 0 10px;
  cursor: pointer;
}
.step:hover:not(:disabled) { background: var(--hover-bg); }
.step:disabled { opacity: .35; cursor: default; }

.step-value {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.btn-stop {
  background: var(--red);
  border-color: var(--red);
  color: var(--on-red);
  font-weight: 650;
}
.btn-stop:hover:not(:disabled) { filter: brightness(1.08); }
.btn-stop[hidden] { display: none; }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}
.btn-primary:hover:not(:disabled) {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

/* ---------------------------------------------------------------- banner */
.banner {
  background: var(--banner-bg);
  border-bottom: 1px solid var(--banner-line);
  color: var(--banner-text);
  font-size: 13px;
  padding: 9px 16px;
}
.banner strong { color: var(--text); }

/* ----------------------------------------------------------------- panes */
.split {
  display: flex;
  height: calc(100% - var(--bar-h));
  min-height: 0;
}
.banner ~ .split { height: calc(100% - var(--bar-h) - 37px); }

.pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.pane-editor { flex: 1 1 58%; border-right: 1px solid var(--line); }
.pane-right { flex: 1 1 42%; background: var(--bg-panel); }

.pane-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--bg-head);
  border-bottom: 1px solid var(--line);
}
.hint { text-transform: none; font-weight: 400; letter-spacing: 0; }

/* ------------------------------------------------------------ file tabs */
.pane-head-tabs { padding: 0 12px 0 0; gap: 8px; }

.tabs {
  display: flex;
  align-items: stretch;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: thin;
  min-width: 0;
}

.tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  padding: 9px 12px;
  cursor: pointer;
  white-space: nowrap;
}
.tab:hover { color: var(--text); background: var(--hover-bg); }
.tab-on {
  color: var(--text);
  border-bottom-color: var(--accent);
  background: var(--bg-panel);
}

.tab-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 3px;
  font-size: 14px;
  line-height: 1;
  color: var(--muted);
}
.tab-x:hover { background: var(--red); color: var(--on-red); }

.linkbtn {
  background: none;
  border: 0;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  cursor: pointer;
  padding: 0;
}
.linkbtn:hover { color: var(--text); }

/* ---------------------------------------------------------------- editor */
.editor-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}
.editor-wrap .CodeMirror {
  position: absolute;
  inset: 0;
  height: 100%;
  font-family: var(--mono);
  font-size: var(--code-size);
  line-height: 1.6;
}
.CodeMirror-gutters { border-right: 1px solid var(--line); }

/* CodeMirror's built-in light theme, retuned for a projector. Its own comment
   colour (#a50) only reaches 5.2:1 on white; #7a3e00 reaches 8.3:1, and the
   operator purple is darkened for the same reason. */
.cm-s-default { background: var(--bg); color: var(--text); }
.cm-s-default .CodeMirror-gutters { background: var(--bg); }
.cm-s-default .CodeMirror-linenumber { color: var(--muted); }
.cm-s-default .CodeMirror-cursor { border-left-color: var(--text); }
.cm-s-default .CodeMirror-selected { background: #cfe0fb; }
.cm-s-default.CodeMirror-focused .CodeMirror-selected { background: #b9d3f8; }
.cm-s-default .CodeMirror-activeline-background { background: #eef3fb; }
.cm-s-default .cm-comment { color: #7a3e00; }
.cm-s-default .cm-operator { color: #6b21a8; }

/* material-darker renders comments and line numbers at #545454, only 2.1:1
   against its own background — close to invisible, and lesson code is full of
   explanatory comments. Lifted to 5.7:1. */
.cm-s-material-darker .cm-comment { color: #909d90; }
.cm-s-material-darker .CodeMirror-linenumber { color: #8b9499; }

/* ---------------------------------------------------------------- output */
.output {
  flex: 1;
  margin: 0;
  padding: 14px;
  overflow: auto;
  font-family: var(--mono);
  font-size: var(--code-size);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text);
}
.output .err { color: var(--red); }
.output .dim { color: var(--muted); }

/* ------------------------------------------------- typing into the output */
/* input() reads here rather than in a browser dialog, so the question, the
   answer and everything printed around them share one transcript.

   The field has to be invisible as a control and identical as text: same
   font, same size, same colour, sitting on the prompt line with no box around
   it. Anything else and the line the student types looks unlike the line that
   appears a moment later when it becomes output. */
.askline { display: inline; }

input.ask {
  font: inherit;
  font-family: var(--mono);
  font-size: var(--code-size);
  line-height: inherit;
  color: var(--text);
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin: 0;
  outline: none;
  /* wide enough for a sentence, but it is an inline element on a wrapping
     line, so it gives way rather than forcing a horizontal scrollbar */
  width: 22ch;
  max-width: 100%;
  caret-color: var(--green);
}
input.ask::selection { background: var(--accent); color: #fff; }

/* A hairline under the field. Without a border it is genuinely invisible when
   unfocused, and a student who clicked into the editor and came back would
   have nothing showing them where the program is waiting. */
input.ask { box-shadow: inset 0 -1px 0 var(--line); }
input.ask:focus { box-shadow: inset 0 -1px 0 var(--accent); }

/* Committed input: the same text, now ordinary output. No underline, nothing
   to click, indistinguishable from a line the program printed itself. */
.output .typed { color: var(--text); }

/* ------------------------------------------------------------ mode chip */
.mode {
  align-self: center;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--bg);
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  padding: 5px 11px;
  cursor: pointer;
  white-space: nowrap;
}
.mode:hover { color: var(--text); border-color: var(--hover-line); }
.mode-console { color: var(--muted); }
.mode-game { color: var(--purple); border-color: var(--chip-game-line); background: var(--chip-game-bg); }
.mode-pinned::after { content: " •"; }

/* --------------------------------------------------------------- stage */
.stage {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  border-bottom: 1px solid var(--line);
}
.stage[hidden] { display: none; }

.stage-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  background:
    repeating-conic-gradient(var(--check-a) 0% 25%, var(--check-b) 0% 50%) 50% / 18px 18px;
}
#canvas {
  max-width: 100%;
  height: auto;
  background: #000;
  border-radius: 4px;
  box-shadow: 0 4px 18px var(--shadow);
  image-rendering: pixelated;
}
#canvas:focus { outline: 2px solid var(--accent); outline-offset: 3px; }

/* In game mode the output pane becomes a log strip under the picture. */
body.is-game .pane-right .output { flex: 1 1 auto; min-height: 90px; }

/* ------------------------------------------------------------- demo page */
/* What a "hide my code" link opens. There is no editor pane to place beside
   the output, because there is no editor on that page at all — not hidden,
   not read-only, absent — so the output takes the full width. */
.demo-main {
  display: flex;
  height: calc(100% - var(--bar-h));
  min-height: 0;
}
.demo-main .pane-right { flex: 1 1 100%; }

/* ----------------------------------------------------- completion popup */
/* show-hint.css hardcodes a white box with black text, which would be a
   glaring rectangle in dark mode. Repaint it from the tokens. */
.CodeMirror-hints {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 7px;
  box-shadow: 0 6px 20px var(--shadow);
  font-family: var(--mono);
  font-size: calc(var(--code-size) * 0.92);
  padding: 4px;
  z-index: 40;
}
.CodeMirror-hint {
  color: var(--text);
  border-radius: 4px;
  padding: 3px 9px;
}
li.CodeMirror-hint-active {
  background: var(--accent);
  color: var(--on-accent);
}

/* ---------------------------------------------------------------- notes */
/* The right pane holds two views: program output, and rendered notes. Only
   one is ever visible, and .subpane sets display, so [hidden] needs help. */
.subpane {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.subpane[hidden] { display: none; }

.notes-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 20px 24px 32px;
  min-height: 0;
}

/* Assignment notes can't be selected, so the code in them can't be copied
   into the editor. Typing it out is most of the exercise.

   Done by preventing selection rather than by policing paste: a paste filter
   would have to guess where text came from, and would block a student who
   typed the starter code correctly and then copied their own line. This has no
   such failure — it removes the shortcut without ever getting in the way of
   someone doing the work.

   It is a speed bump, not a lock. Developer tools will still show the text.
   That is the same bargain as a demo link, and it stops the ordinary path.

   Not while authoring: at `/` the notes are yours, and you may well want to
   copy a line out of them. Every view a student sees — a share, a fork — is
   covered. */
body:not(.is-authoring) .notes-body {
  user-select: none;
  -webkit-user-select: none;
}

/* Links stay usable: clicking one still works, and its text is the one thing
   worth being able to lift out of the notes. */
body:not(.is-authoring) .notes-body a {
  user-select: text;
  -webkit-user-select: text;
}

/* Class notes are prose, so they get prose treatment rather than the
   monospaced console look of the output pane. */
.prose {
  color: var(--text);
  font-size: 15px;
  line-height: 1.65;
  max-width: 68ch;
}
.prose > :first-child { margin-top: 0; }
.prose h1, .prose h2, .prose h3, .prose h4 {
  line-height: 1.25;
  margin: 1.6em 0 .5em;
  text-wrap: balance;
}
.prose h1 { font-size: 1.7em; }
.prose h2 { font-size: 1.35em; }
.prose h3 { font-size: 1.15em; }
.prose h4 { font-size: 1em; letter-spacing: .01em; }
.prose h1, .prose h2 {
  padding-bottom: .25em;
  border-bottom: 1px solid var(--line);
}
.prose p, .prose ul, .prose ol, .prose blockquote { margin: 0 0 1em; }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li { margin: .25em 0; }
.prose li > ul, .prose li > ol { margin: .25em 0; }

.prose a { color: var(--accent); text-decoration: underline; }
.prose a:hover { color: var(--accent-hover); }

.prose code {
  font-family: var(--mono);
  font-size: .88em;
  background: var(--hover-bg);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: .1em .35em;
}
.prose pre {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 12px 14px;
  overflow-x: auto;
  margin: 0 0 1em;
}
.prose pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: .92em;
}

.prose blockquote {
  border-left: 3px solid var(--accent);
  padding: .1em 0 .1em 1em;
  color: var(--muted);
}
.prose hr { border: 0; border-top: 1px solid var(--line); margin: 1.8em 0; }

.prose img {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  display: block;
  margin: .4em 0;
}

.prose table {
  border-collapse: collapse;
  width: 100%;
  margin: 0 0 1em;
  font-size: .95em;
}
.prose th, .prose td {
  border: 1px solid var(--line);
  padding: 6px 10px;
  text-align: left;
}
.prose th { background: var(--bg-head); font-weight: 600; }

.prose kbd {
  font-family: var(--mono);
  font-size: .85em;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: .05em .4em;
  background: var(--bg-head);
}

/* -------------------------------------------------------- sprite panel */
.pane-sprites {
  flex: 0 0 268px;
  background: var(--bg-panel);
  border-left: 1px solid var(--line);
}
.pane-sprites[hidden] { display: none; }

.sprite-tools { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.sprite-tools .field { width: 100%; }

.sprite-scroll { flex: 1 1 auto; overflow-y: auto; padding: 12px; min-height: 0; }

.sprite-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

.sprite {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 8px 4px 6px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 7px;
  cursor: pointer;
  font: inherit;
}
.sprite:hover { border-color: var(--accent); background: var(--sprite-hover); }
.sprite:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sprite[hidden] { display: none; }

.sprite-img {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 44px;
}
.sprite-img img {
  max-width: 100%;
  max-height: 44px;
  image-rendering: pixelated;
}
/* One frame of an animation strip, shown through a window the size of that
   frame. The whole strip is inside, shifted to the left edge, so the cell
   shows a standing character rather than nine tiny ones in a row.
   `loading="lazy"` is why this is an <img> in a box and not a background
   image: the dungeon pack is 142 pictures and most are off-screen. */
.sprite-frame { display: block; overflow: hidden; }
.sprite-frame img {
  display: block;
  max-width: none;
  max-height: none;
  image-rendering: pixelated;
}

/* A corner mark on anything that animates. */
.sprite-anim {
  position: absolute;
  top: 3px;
  right: 4px;
  font-size: 9px;
  line-height: 1;
  color: var(--accent);
}
.sprite { position: relative; }

/* The atlas is one big picture, not a grid cell — showing it at 44px would
   make it a smudge. It gets the full width of the panel. */
.atlas-card {
  display: block;
  width: 100%;
  padding: 8px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 7px;
  cursor: pointer;
  font: inherit;
  text-align: left;
}
.atlas-card:hover { border-color: var(--accent); background: var(--sprite-hover); }
.atlas-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.atlas-card[hidden] { display: none; }
.atlas-card img {
  display: block;
  width: 100%;
  border-radius: 4px;
  image-rendering: pixelated;
}
.atlas-card .sprite-name { display: block; margin-top: 6px; }
.atlas-note {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.45;
}

.sprite-section[hidden] { display: none; }
.sprite-section:first-child .sprite-subhead { margin-top: 0; }

.sprite-name {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--muted);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sprite:hover .sprite-name { color: var(--text); }

.sprite-empty { padding: 18px 4px; font-size: 13px; }

.sprite-subhead {
  margin: 20px 0 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
  color: var(--muted);
}
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  padding: 4px 10px;
  cursor: pointer;
}
.chip:hover { border-color: var(--accent); color: var(--text); }

.sprite-foot {
  margin: 0;
  padding: 9px 12px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 11.5px;
  line-height: 1.45;
}

/* ----------------------------------------------------------------- modal */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 12, .72);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 50;
}
.modal[hidden] { display: none; }

.modal-card {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 26px;
  width: 100%;
  max-width: 480px;
}
.modal-card h2 { margin: 0 0 4px; font-size: 19px; }
.modal-sub { margin: 0 0 18px; color: var(--muted); font-size: 13.5px; }
.modal-note { margin: 14px 0 20px; color: var(--muted); font-size: 12.5px; line-height: 1.5; }

.linkrow { display: flex; gap: 8px; }
.linkrow input {
  flex: 1;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--text);
  padding: 9px 11px;
  font-family: var(--mono);
  font-size: 13px;
  min-width: 0;
}
.linkrow input:focus { outline: none; border-color: var(--accent); }

/* ---------------------------------------------------------------- mobile */
@media (max-width: 860px) {
  html, body { overflow: auto; }
  .bar { height: auto; flex-wrap: wrap; padding: 10px 12px; gap: 10px; }
  .meta { order: 3; width: 100%; }
  .field-title, .field-author { flex: 1 1 auto; max-width: none; }
  .split, .banner ~ .split { flex-direction: column; height: auto; }
  .pane-editor { border-right: 0; border-bottom: 1px solid var(--line); }
  .editor-wrap { height: 55vh; flex: 0 0 auto; }
  .output { height: 35vh; }
  .pane-sprites { flex: 0 0 auto; border-left: 0; border-top: 1px solid var(--line); }
  .sprite-scroll { max-height: 46vh; }
  .sprite-grid { grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); }
}

/* ------------------------------------------------- signing in and saving */

/* Whether the work is safe. Quiet when it is, because it almost always is —
   the only state worth noticing is the one that says it isn't. */
.savestate {
  align-self: center;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
  padding: 0 4px;
  min-width: 68px;
  text-align: right;
}
.savestate.busy { opacity: .7; }
.savestate.bad { color: var(--red); font-weight: 600; }

.account { position: relative; }
.btn-account { max-width: 150px; overflow: hidden; text-overflow: ellipsis; }

.menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 170px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px var(--shadow);
  padding: 5px;
  z-index: 60;
}
.menu[hidden] { display: none; }
.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 5px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 8px 10px;
  cursor: pointer;
  text-decoration: none;
}
.menu-item:hover { background: var(--bg); }

.banner-hint { background: var(--bg-panel); }

.projects { max-height: 340px; overflow-y: auto; margin: 4px 0 18px; }
.project-row {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: 7px;
  margin-bottom: 6px;
}
.project-row:hover { border-color: var(--accent); }
.project-open {
  flex: 1;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 10px 12px;
  text-decoration: none;
  color: var(--text);
  min-width: 0;
}
.project-name { font-weight: 500; }
.project-when { color: var(--muted); font-size: 12px; white-space: nowrap; }

/* Quiet until you go looking for it, so nobody deletes a project on the way
   to opening one. */
.project-x {
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 19px;
  line-height: 1;
  padding: 6px 12px 8px;
  cursor: pointer;
  opacity: .35;
  border-radius: 6px;
}
.project-row:hover .project-x { opacity: 1; }
.project-x:hover { color: var(--red); background: var(--bg); }

.rowactions { white-space: nowrap; }
.rowactions .linkbtn { margin-left: 12px; }
.linkbtn.danger { color: var(--red); }

/* ------------------------------------------------------ teacher's pages */
.sheet {
  max-width: 860px;
  margin: 0 auto;
  padding: 28px 24px 60px;
  overflow-y: auto;
  height: calc(100% - var(--bar-h));
}
.sheet h2 {
  font-size: 15px;
  letter-spacing: .3px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 30px 0 12px;
}
.sheet .count {
  color: var(--text);
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 9px;
  font-size: 12px;
  margin-left: 4px;
}
.pagetitle { font-weight: 600; }
.whoami { align-self: center; color: var(--muted); font-size: 12.5px; }
.brandlink { color: inherit; text-decoration: none; }

.listing { width: 100%; border-collapse: collapse; font-size: 14px; }
.listing th {
  text-align: left;
  font-size: 11.5px;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  padding: 0 10px 8px;
  border-bottom: 1px solid var(--line);
}
.listing td { padding: 12px 10px; border-bottom: 1px solid var(--line); }
.listing tr:hover td { background: var(--bg-panel); }
.listing a { color: var(--accent); text-decoration: none; }
.listing a:hover { text-decoration: underline; }
.listing .right { text-align: right; }
.small { font-size: 12px; }

.handout { border: 1px solid var(--line); border-radius: 9px; padding: 16px 18px; }
.handout h2 { margin-top: 0; }
.names { columns: 2; margin: 0; padding-left: 20px; color: var(--muted); font-size: 14px; }
.empty { text-align: center; padding: 60px 20px; color: var(--muted); }
.empty h2 { text-transform: none; font-size: 20px; color: var(--text); }

/* -------------------------------------------------------------- 404 page */
.center {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 24px;
}
.center h1 { margin: 0; font-size: 22px; }
.center p { margin: 0; color: var(--muted); max-width: 40ch; line-height: 1.6; }

/* ------------------------------------------------- the engine PyIDE serves */
/* Ordinarily a footnote — which version is vendored, and whether PyPI has a
   newer one. It only raises its voice when there is something to do. */
.engine {
  margin-top: 36px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.5;
}
.engine p { margin: 0 0 4px; }
.engine p:last-child { margin-bottom: 0; }
.engine code {
  font-family: var(--mono);
  font-size: 12px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 1px 6px;
}
.engine-new {
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 12px 14px;
  color: var(--text);
  font-size: 13.5px;
}

/* Quiet buttons: present and reachable, and not competing with Run.
   + Game and Support are both this — things wanted occasionally that should
   never be hit by accident on the way to somewhere else. */
.btn-quiet {
  color: var(--muted);
  border-color: transparent;
  background: none;
}
.btn-quiet:hover {
  color: var(--text);
  background: var(--hover-bg);
  border-color: var(--hover-line);
}
