/* ═══════════════════════════════════════════════════════════════════════════
   TRU-Think — COMP 1110
   ---------------------------------------------------------------------------
   A classic-platformer skin: chunky outlines, hard pixel shadows, coin meters
   and level tiles. Every ornament here is CSS — no sprite files — so the pixel
   look stays crisp at any zoom and survives both colour themes.

   Two rules keep it a *game skin* rather than a costume:
     · the arcade font is chrome only (brand, badges, HUD numbers). Anything a
       student has to actually read — task prose, tutor feedback, their own
       code — stays in a normal, readable face.
     · every interactive block is outline + hard offset shadow, and pressing it
       moves it into its own shadow. One physical language across the app.
   ═══════════════════════════════════════════════════════════════════════════ */

* { box-sizing: border-box; }

:root {
  /* ---- Overworld (light) -------------------------------------------- */
  --sky-1: #6fb7ff;
  --sky-2: #bfe3ff;
  --bg: #cfe7fb;
  --card: #fffdf5;
  --ink: #221a33;
  --muted: #6c6484;
  --outline: #221a33;          /* the black key line around every block */
  --outline-soft: rgba(34, 26, 51, .16);
  --accent: #1668c9;
  --accent-dark: #0f4e9b;
  --accent-soft: #e3f0ff;
  --accent-soft-border: #a8ccf4;
  --green: #2f8f3f;
  --pipe: #43b047;             /* pipe green — fills, never text */
  --red: #cc2b26;
  --brick: #c3541f;
  --amber: #8f5f00;            /* legible gold, for text */
  --coin: #fbd000;             /* bright gold, for fills */
  --border: #d9c9b4;           /* quiet dividers inside a block */
  --input-bg: #fffefa;
  --code-bg: #f4eddf;
  --ok-bg: #e8f8e6;   --ok-border: #8fce8a;
  --err-bg: #fdeceb;  --err-border: #eda9a5;
  --info-bg: #e6f1ff; --info-border: #a8ccf4;
  --warn-bg: #fff6d9; --warn-border: #e8c65c;
  --ai-bg: #f4efff;   --ai-border: #c5b4f0;
  --locked-bg: #efe7da;
  --passed-bg: #ecf9e9;
  --success-border: #57b14f;
  --bonus-bg: #fff2d4;
  --shadow: #221a33;           /* solid: hard pixel shadows, never blurred */
  --run: #2f9e4f;
  --pane-head: #f0e6d4;
  --nav-bg: #fffaee;
  --paper: #f7f0e0;        /* the lesson page's reading surface */
  --topbar-h: 3.6rem;
  --sky-deco: #ffffff;         /* clouds by day, stars by night */

  --font-body: "Baloo 2", "Trebuchet MS", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-arcade: "Press Start 2P", "Courier New", ui-monospace, monospace;
  --font-code: "SF Mono", "Fira Code", Consolas, ui-monospace, monospace;
}

/* ---- Castle (dark) --------------------------------------------------- */
[data-theme="dark"] {
  --sky-1: #1b1440;
  --sky-2: #2a1e57;
  --bg: #15102c;
  --card: #241d47;
  --ink: #f3eeff;
  --muted: #a79fd0;
  --outline: #0a0718;
  --outline-soft: rgba(0, 0, 0, .5);
  --accent: #57adff;
  --accent-dark: #9ad2ff;
  --accent-soft: #2f2765;
  --accent-soft-border: #4d419b;
  --green: #4fd97e;
  --pipe: #35b45f;
  --red: #ff6055;
  --brick: #e0733c;
  --amber: #ffd166;
  --coin: #ffc400;
  --border: #453b85;
  --input-bg: #1b1540;
  --code-bg: #191238;
  --ok-bg: #16321f;   --ok-border: #3b7a4a;
  --err-bg: #3a1620;  --err-border: #8a3644;
  --info-bg: #1b2550; --info-border: #3d55a0;
  --warn-bg: #3a2c14; --warn-border: #8a6c2a;
  --ai-bg: #2b2160;   --ai-border: #55429e;
  --locked-bg: #1d1740;
  --passed-bg: #1a3324;
  --success-border: #3b7a4a;
  --bonus-bg: #3a2c14;
  --shadow: #0a0718;
  --run: #35b45f;
  --pane-head: #2c2456;
  --nav-bg: #1d1740;
  --paper: #1b1539;
  --sky-deco: #ffe27a;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --sky-1: #1b1440;
    --sky-2: #2a1e57;
    --bg: #15102c;
    --card: #241d47;
    --ink: #f3eeff;
    --muted: #a79fd0;
    --outline: #0a0718;
    --outline-soft: rgba(0, 0, 0, .5);
    --accent: #57adff;
    --accent-dark: #9ad2ff;
    --accent-soft: #2f2765;
    --accent-soft-border: #4d419b;
    --green: #4fd97e;
    --pipe: #35b45f;
    --red: #ff6055;
    --brick: #e0733c;
    --amber: #ffd166;
    --coin: #ffc400;
    --border: #453b85;
    --input-bg: #1b1540;
    --code-bg: #191238;
    --ok-bg: #16321f;   --ok-border: #3b7a4a;
    --err-bg: #3a1620;  --err-border: #8a3644;
    --info-bg: #1b2550; --info-border: #3d55a0;
    --warn-bg: #3a2c14; --warn-border: #8a6c2a;
    --ai-bg: #2b2160;   --ai-border: #55429e;
    --locked-bg: #1d1740;
    --passed-bg: #1a3324;
    --success-border: #3b7a4a;
    --bonus-bg: #3a2c14;
    --shadow: #0a0718;
    --run: #35b45f;
    --pane-head: #2c2456;
    --nav-bg: #1d1740;
    --paper: #1b1539;
    --sky-deco: #ffe27a;
  }
}

/* ═══════════════════════════════════════════════════ page ═══════════ */

body {
  margin: 0;
  color: var(--ink);
  font: 400 17px/1.6 var(--font-body);
  background: var(--bg);
  /* The sky sits behind everything and stops before the fold, so long pages
     don't stretch one gradient over five screens of reading. */
  background-image: linear-gradient(180deg, var(--sky-1) 0, var(--sky-2) 220px, var(--bg) 420px);
  background-repeat: no-repeat;
  background-attachment: fixed;
}
main { max-width: 1200px; margin: 1.5rem auto 3rem; padding: 0 1rem; }

/* The credits roll. Arcade type is fine here because it is three short lines
   nobody has to read twice. */
footer {
  text-align: center; color: var(--muted); padding: 1.6rem 1rem 2.4rem;
  font-family: var(--font-arcade); font-size: .55rem; line-height: 2.2;
}
footer .footer-star { color: var(--coin); }

h1, h2, h3 { font-weight: 800; letter-spacing: -.01em; }
h1 { font-size: 1.7rem; margin: .2rem 0 .6rem; }
h2 { font-size: 1.2rem; margin: .4rem 0 .5rem; }
a { color: var(--accent); text-underline-offset: 2px; }
a:hover { color: var(--accent-dark); }

code, pre { font-family: var(--font-code); font-size: .92em; }
pre {
  background: var(--code-bg); border: 2px solid var(--outline); border-radius: 0;
  padding: .8rem; overflow-x: auto; box-shadow: 3px 3px 0 var(--outline-soft);
}

/* One focus ring everywhere: a gold coin outline that reads on any surface. */
:where(a, button, input, textarea, select, summary, .peer, .task-row, .ws-row):focus-visible {
  outline: 3px solid var(--coin);
  outline-offset: 2px;
}

/* ═══════════════════════════════════════════════ the HUD bar ═════════ */

.topbar {
  display: flex; justify-content: space-between; align-items: center; gap: .6rem;
  padding: .5rem 1.1rem; position: sticky; top: 0; z-index: 5; flex-wrap: wrap;
  background: var(--card);
  border-bottom: 4px solid var(--outline);
  /* A course of bricks along the bottom edge — the ground the HUD stands on.
     Wide enough to read as bricks; any thinner and it is just a dotted line. */
  background-image:
    linear-gradient(var(--outline), var(--outline)),
    repeating-linear-gradient(90deg, var(--outline) 0 3px, var(--brick) 3px 34px);
  background-position: 0 calc(100% - 12px), bottom;
  background-size: 100% 2px, 100% 12px;
  background-repeat: repeat-x, repeat-x;
  padding-bottom: calc(.5rem + 14px);
}

.brand {
  display: inline-flex; align-items: center; gap: .55rem;
  text-decoration: none; color: var(--ink);
}
/* The ? block. It hops when you point at it, the way it should. */
.brand-block {
  width: 1.9rem; height: 1.9rem; flex: none;
  display: grid; place-items: center;
  background: var(--coin); color: var(--outline);
  border: 3px solid var(--outline);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .45), 3px 3px 0 var(--shadow);
  font-family: var(--font-arcade); font-size: .8rem; line-height: 1;
  transition: transform .12s steps(2);
}
.brand:hover .brand-block { transform: translateY(-3px); }
.brand-name { font-family: var(--font-arcade); font-size: .84rem; line-height: 1.4; }
.brand-name .tru { color: var(--red); }
.brand-name .think { color: var(--accent); }

.topbar nav { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; }
.topbar nav a {
  text-decoration: none; font-weight: 600; font-size: .95rem;
  padding: .1rem .1rem; border-bottom: 2px solid transparent;
}
.topbar nav a:hover { border-bottom-color: var(--accent); }
/* The profile tab. It is where the character lives now, so it wears their face. */
.whoami {
  display: inline-flex; align-items: center; gap: .45rem;
  color: var(--ink) !important; font-family: var(--font-arcade); font-size: .62rem;
  background: var(--accent-soft); border: 2px solid var(--outline);
  padding: .3rem .55rem !important; box-shadow: 2px 2px 0 var(--shadow);
}
.whoami-face {
  width: 1.6rem; height: 1.6rem; object-fit: cover; display: block;
  border: 2px solid var(--outline); margin: -.1rem 0 -.1rem -.25rem;
}
.whoami:hover { border-bottom-color: var(--outline) !important; filter: brightness(1.04); }
.theme-toggle {
  border: 3px solid var(--outline); background: var(--card); border-radius: 0;
  padding: .2rem .5rem; cursor: pointer; font-size: 1rem; line-height: 1.3;
  box-shadow: 2px 2px 0 var(--shadow);
}
.logout-btn { padding: .3rem .7rem; font-size: .8rem; }

/* ═════════════════════════════════════════════════ blocks ═══════════ */

.card {
  background: var(--card);
  border: 3px solid var(--outline); border-radius: 0;
  padding: 1.1rem 1.3rem; margin-bottom: 1.1rem;
  box-shadow: 5px 5px 0 var(--shadow);
}
.card.narrow { max-width: 480px; margin: 3rem auto; }

/* The title screen on /login: name first, everything else after. */
.titlecard { text-align: center; }
.titlecard .stack, .titlecard p:not(.title-super):not(.press-start) { text-align: left; }
.title-super {
  font-family: var(--font-arcade); font-size: .5rem; color: var(--muted);
  letter-spacing: .08em; margin: .2rem 0 1rem;
}
.title-logo {
  font-family: var(--font-arcade); font-size: 1.5rem; line-height: 1.5; margin: 0;
  text-shadow: 4px 4px 0 var(--outline-soft);
}
.title-logo .tru { color: var(--red); }
.title-logo .think { color: var(--accent); }
.press-start {
  font-family: var(--font-arcade); font-size: .58rem; color: var(--coin);
  text-shadow: 2px 2px 0 var(--outline); margin: .9rem 0 1.4rem;
  animation: blink 1.4s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .press-start { animation: none; } }

/* The sky panel at the top of the dashboard: a cloud by day, a star at
   night, and a strip of ground holding the greeting up. */
.hero {
  position: relative; overflow: hidden; padding-bottom: 2rem;
  background: linear-gradient(180deg, var(--sky-1), var(--sky-2));
  color: var(--ink);
}
.hero h1 { font-size: 1.55rem; margin-top: 0; }
[data-theme="dark"] .hero, :root:not([data-theme="light"]) .hero { color: var(--ink); }
/* The shadows reach 50px to the right of the box, so it is anchored well clear
   of the card edge or the cloud loses its tail. */
.hero::before {                       /* pixel cloud, drawn in box-shadows */
  content: ""; position: absolute; top: 2.6rem; right: 4.6rem;
  width: 10px; height: 10px; background: var(--sky-deco); opacity: .9;
  box-shadow:
    10px 0 var(--sky-deco), 20px 0 var(--sky-deco), 30px 0 var(--sky-deco),
    40px 0 var(--sky-deco), 50px 0 var(--sky-deco), -10px 0 var(--sky-deco),
    0 -10px var(--sky-deco), 10px -10px var(--sky-deco), 30px -10px var(--sky-deco),
    40px -10px var(--sky-deco), 20px -20px var(--sky-deco), 30px -20px var(--sky-deco);
}
.hero::after {                        /* the ground it all stands on */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: .85rem;
  background: var(--pipe);
  border-top: 3px solid var(--outline);
  background-image: repeating-linear-gradient(90deg,
    rgba(0, 0, 0, .18) 0 3px, transparent 3px 14px);
}
.hero > * { position: relative; z-index: 1; }
.funfact { color: var(--ink); opacity: .82; margin-bottom: .3rem; }
/* Keep a lane clear on the right so a long greeting never runs into the cloud.
   Below 640px the cloud is hidden and the text takes the whole card. */
@media (min-width: 641px) { .hero h1, .hero .funfact { max-width: calc(100% - 9rem); } }

/* Score line under the hero — coins collected, worlds cleared, who's playing. */
.scoreboard {
  display: flex; flex-wrap: wrap; gap: .7rem; margin: -.3rem 0 1.4rem;
}
.score {
  flex: 1 1 10rem; background: var(--card);
  border: 3px solid var(--outline); box-shadow: 4px 4px 0 var(--shadow);
  padding: .5rem .8rem; display: flex; flex-direction: column; gap: .2rem;
}
.score-label {
  font-family: var(--font-arcade); font-size: .52rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em;
}
.score-val { font-family: var(--font-arcade); font-size: .82rem; line-height: 1.4; }
.score-val small { font-size: .62rem; color: var(--muted); }

.section-title { margin-top: 1.8rem; font-family: var(--font-arcade); font-size: .8rem; }
.muted { color: var(--muted); }
.crumb {
  display: inline-block; margin-bottom: .6rem; text-decoration: none;
  font-weight: 700; font-size: .92rem;
}
.crumb:hover { text-decoration: underline; }
.hidden { display: none !important; }
.inline { display: inline; }

/* ═══════════════════════════════════════════════ form fields ════════ */

.stack { display: flex; flex-direction: column; gap: .95rem; }
.stack label { display: flex; flex-direction: column; gap: .3rem; font-weight: 700; font-size: .95rem; }
input, textarea, select {
  font: inherit; padding: .55rem .7rem; border: 3px solid var(--outline);
  border-radius: 0; width: 100%; background: var(--input-bg); color: var(--ink);
  box-shadow: inset 2px 2px 0 var(--outline-soft);
}
input:focus, textarea:focus, select:focus { background: var(--card); }
textarea { min-height: 70px; resize: vertical; font-family: var(--font-code); font-size: .92rem; }

/* ═══════════════════════════════════════════════════ buttons ════════ */

/* Every button is a block you can push: outline, hard shadow, and on :active
   it slides into its own shadow. That press is the whole physical metaphor. */
button, .btn {
  font-family: var(--font-body); font-size: .98rem; font-weight: 800;
  border: 3px solid var(--outline); border-radius: 0;
  padding: .45rem 1rem; cursor: pointer; background: var(--card); color: var(--ink);
  text-decoration: none; display: inline-block; line-height: 1.4;
  box-shadow: 3px 3px 0 var(--shadow);
  transition: transform .08s steps(1), box-shadow .08s steps(1), filter .12s;
}
button:hover:not(:disabled), .btn:hover { filter: brightness(1.06); }
button:active:not(:disabled), .btn:active {
  transform: translate(3px, 3px); box-shadow: 0 0 0 var(--shadow);
}
button.primary {
  background: var(--red); border-color: var(--outline); color: #fff8f0;
  text-shadow: 1px 1px 0 rgba(0, 0, 0, .45);
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .22), 3px 3px 0 var(--shadow);
}
button.primary:active:not(:disabled) {
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .22), 0 0 0 var(--shadow);
}
button.secondary, .btn.secondary {
  background: var(--accent-soft); border-color: var(--outline); color: var(--accent-dark);
}
button.linklike {
  border: 2px dashed var(--outline-soft); background: none; color: var(--accent);
  padding: .3rem .6rem; box-shadow: none; font-size: .9rem;
}
button.linklike:hover:not(:disabled) { border-style: solid; background: var(--accent-soft); }
button.linklike:active:not(:disabled) { transform: none; }
button:disabled { opacity: .55; cursor: wait; box-shadow: 2px 2px 0 var(--outline-soft); }
.btn-row { display: flex; gap: .6rem; margin-top: .8rem; flex-wrap: wrap; align-items: center; }
.nav-row { justify-content: space-between; }

/* Mood buttons on the dashboard read as a row of pickable faces. */
.mood-row { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .6rem; }
.mood { font-size: .95rem; }
.mood.selected {
  background: var(--coin); color: var(--outline);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .5), 3px 3px 0 var(--shadow);
}

/* ═══════════════════════════════════════════════════ alerts ═════════ */

.alert {
  border: 3px solid var(--outline); border-radius: 0; padding: .7rem 1rem; margin: .7rem 0;
  font-weight: 600; box-shadow: 4px 4px 0 var(--shadow);
}
.alert.error { background: var(--err-bg); color: var(--red); }
.alert.success { background: var(--ok-bg); color: var(--green); }
.alert.info { background: var(--info-bg); color: var(--accent-dark); }
.alert.warn { background: var(--warn-bg); color: var(--amber); }

/* ══════════════════════════════════════════ worksheets = worlds ═════ */

.ws-row {
  display: flex; justify-content: space-between; gap: 1rem; align-items: center;
  text-decoration: none; color: inherit; position: relative;
  transition: transform .1s steps(1), box-shadow .1s steps(1);
}
.ws-row:hover {
  transform: translate(-2px, -2px); box-shadow: 7px 7px 0 var(--shadow);
  border-color: var(--outline);
}
.ws-row:active { transform: translate(2px, 2px); box-shadow: 2px 2px 0 var(--shadow); }
.ws-row h3 { margin: 0 0 .2rem; font-size: 1.15rem; }
/* The level tag. Gold in both themes — a dark-on-dark plate disappears at
   night, and this is the one label that says which world you are looking at. */
.world-tag {
  display: inline-block; font-family: var(--font-arcade); font-size: .55rem;
  background: var(--coin); color: #221a33; border: 2px solid var(--outline);
  padding: .3rem .5rem; margin-bottom: .5rem; letter-spacing: .04em;
  box-shadow: 2px 2px 0 var(--shadow);
}
.due { color: var(--amber); font-size: .9rem; margin: .3rem 0 0; font-weight: 700; }
.ws-progress { text-align: right; min-width: 150px; font-size: .8rem; color: var(--muted); }
.ws-progress.wide { text-align: left; }
.ws-progress span { font-family: var(--font-arcade); font-size: .58rem; }

/* The coin meter. Notched like a power bar, and the fill carries moving
   stripes so a part-done worksheet looks like it is still in play. */
.bar {
  background: var(--code-bg); border: 3px solid var(--outline); border-radius: 0;
  height: 15px; overflow: hidden; margin-bottom: .35rem;
  box-shadow: inset 2px 2px 0 var(--outline-soft);
}
.fill {
  background: var(--coin); height: 100%;
  background-image: repeating-linear-gradient(115deg,
    rgba(255, 255, 255, .45) 0 6px, transparent 6px 14px);
  animation: meter 1.1s linear infinite;
}
@keyframes meter { to { background-position: 30px 0; } }
@media (prefers-reduced-motion: reduce) { .fill { animation: none; } }

/* Not yet released: boarded up, and it says so without shouting. */
.card.locked {
  background: var(--locked-bg); color: var(--muted); box-shadow: 4px 4px 0 var(--outline-soft);
  border-style: dashed;
}
/* A signpost: standing instructions, not a locked door — so it keeps the solid
   outline and takes the warm board colour. */
.card.sign { background: var(--warn-bg); }

/* ════════════════════════════════════════════ tasks = level select ══ */

.task-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.task-row {
  display: flex; gap: .7rem; align-items: baseline; padding: .6rem .9rem;
  background: var(--card); border: 3px solid var(--outline); border-radius: 0;
  margin-bottom: .55rem; text-decoration: none; color: inherit;
  box-shadow: 4px 4px 0 var(--shadow);
  transition: transform .1s steps(1), box-shadow .1s steps(1);
}
.task-row:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--shadow); }
.task-row:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--shadow); }
.task-row .tcode {
  font-family: var(--font-arcade); font-size: .68rem; min-width: 3.1rem; color: var(--accent);
}
.task-row .ttitle { font-weight: 600; }
.task-row.passed { background: var(--passed-bg); border-color: var(--success-border); }
.task-row.passed .ttitle { color: var(--muted); }

/* ═══════════════════════════════════════════ the tutor speaking ═════ */

.ai-reply {
  background: var(--ai-bg); border: 3px solid var(--outline); border-radius: 0;
  padding: .75rem 1rem; margin-top: .7rem; box-shadow: 3px 3px 0 var(--outline-soft);
}
.ai-reply p:first-child { margin-top: 0; }
.ai-reply p:last-child { margin-bottom: 0; }

.ai-card.success { background: var(--ok-bg); border-color: var(--success-border); }
.ai-card.success h2 { color: var(--green); }
.ai-card.success .ai-reply { background: var(--passed-bg); border-color: var(--outline); }

/* Human review of an AI verdict — deliberately quieter than the tutor card:
   it is an escape hatch, not the main path through a task. */
.appeal-card { margin-top: 1rem; box-shadow: 4px 4px 0 var(--outline-soft); }
.appeal-card h2 { font-size: 1.05rem; }
.appeal-card h3 { font-size: .95rem; margin-bottom: .3rem; }
.appeal-card label { display: block; font-size: .9rem; margin-top: .6rem; font-weight: 700; }
.appeal-note {
  margin: .6rem 0; padding: .55rem .9rem;
  border-left: 5px solid var(--accent); background: var(--ai-bg);
}
.appeal-note p:first-child { margin-top: 0; }
.appeal-note p:last-child { margin-bottom: 0; }

/* ═══════════════════════════════════════ hints = the ? block ════════ */

/* Hints stack oldest-first, each labelled with which format it is and how far
   down the ladder, and each folded to its badge except the newest — so the one
   just asked for is on screen and the earlier, gentler ones are one click away.
   Worked examples are tinted differently: the code in them solves a *different*
   problem, and that has to be obvious at a glance. */
.hint-card {
  margin-top: 1.2rem; background: var(--card);
  border-top: 8px solid var(--coin);
}
.hint-card h2 { font-size: 1.05rem; margin-bottom: .2rem; }
.hint-note { font-size: .88rem; margin: 0; }
/* Out of hints, or waiting on an edit — not busy: the cursor should say so. */
.hint-btn:disabled { cursor: not-allowed; }
.hint-step { margin-top: .8rem; }
.hint-step > summary { list-style: none; cursor: pointer; }
.hint-step > summary::-webkit-details-marker { display: none; }
.hint-step > summary::after { content: " ▾"; color: var(--muted); font-size: .75rem; }
.hint-step[open] > summary::after { content: " ▴"; }
.hint-badge {
  display: inline-block; background: var(--coin); border: 3px solid var(--outline);
  color: var(--outline); border-radius: 0; padding: .28rem .6rem;
  font-family: var(--font-arcade); font-size: .58rem; line-height: 1.4;
  box-shadow: 2px 2px 0 var(--shadow);
}
.hint-step.example .hint-badge { background: var(--accent-soft); color: var(--accent-dark); }
.hint-step > summary:hover .hint-badge { filter: brightness(.96); }
.hint-step .ai-reply { margin-top: .5rem; }
.hint-step .ai-reply pre { margin: .5rem 0; }

/* ══════════════════════════════════════════════ lesson shell ════════ */

/* Course contents on the left, the lesson split into prose | workpane. The sky
   belongs on the pages you browse; a task is half an hour of reading and
   typing, so it gets a flat paper surface and nothing behind the words. */
body.lesson { background-image: none; }
main.lesson-page {
  max-width: 1580px; margin: 0 auto; padding: 0;
  display: grid; grid-template-columns: 262px minmax(0, 1fr); align-items: start;
  background: var(--paper); min-height: calc(100vh - var(--topbar-h));
}

.lesson-nav {
  position: sticky; top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h)); overflow-y: auto;
  background: var(--nav-bg); border-right: 4px solid var(--outline);
  padding: 1rem .6rem 3rem; font-size: .9rem;
}
/* Hiding the contents gives the lesson the full width. */
:root[data-nav="hidden"] .lesson-nav { display: none; }
:root[data-nav="hidden"] main.lesson-page { grid-template-columns: minmax(0, 1fr); }
.nav-toggle { padding: .1rem .5rem; line-height: 1.5; color: var(--muted); font-size: .9rem; }
.nav-toggle:hover { color: var(--accent); }
.prose-top { display: flex; align-items: center; gap: .6rem; margin-bottom: .5rem; }
.prose-top .crumb { margin-bottom: 0; }

.nav-top { display: flex; align-items: center; gap: .4rem; }
.nav-hide {
  border: none; background: none; color: var(--muted); font-size: 1.05rem;
  line-height: 1; padding: .1rem .4rem; margin-left: auto; box-shadow: none;
}
.nav-hide:hover { color: var(--accent); }
.nav-hide:active { transform: none; }
.nav-home { flex: 1; display: block; padding: .2rem .5rem .5rem; text-decoration: none; font-size: .85rem; font-weight: 700; }
.nav-ws-head { display: block; padding: 0 .5rem; text-decoration: none; color: var(--ink); }
.nav-ws-head:hover .nav-ws-title { color: var(--accent); }
.nav-ws-num {
  display: inline-block; font-family: var(--font-arcade); font-size: .55rem;
  background: var(--coin); color: #221a33; border: 2px solid var(--outline);
  padding: .26rem .42rem; margin-bottom: .35rem;
}
.nav-ws-title { display: block; font-weight: 800; font-size: 1rem; line-height: 1.3; }
.nav-progress {
  padding: .55rem .5rem .8rem; font-size: .78rem; color: var(--muted);
  border-bottom: 3px solid var(--outline); margin-bottom: .6rem;
}
.nav-progress span { font-family: var(--font-arcade); font-size: .55rem; }
.nav-tasks { list-style: none; margin: 0; padding: 0; }
.nav-task {
  display: flex; gap: .45rem; align-items: baseline; text-decoration: none; color: var(--ink);
  padding: .34rem .5rem; border-radius: 0; line-height: 1.35;
  border: 2px solid transparent;
}
.nav-task:hover { background: var(--accent-soft); border-color: var(--accent-soft-border); }
/* The level you are standing on. */
.nav-task.current {
  background: var(--coin); color: var(--outline); font-weight: 800;
  border-color: var(--outline); box-shadow: 2px 2px 0 var(--shadow);
}
.nav-task.current .nav-code { color: var(--outline); }
.nav-task.passed .nav-title { color: var(--muted); }
.nav-task.passed.current .nav-title { color: var(--outline); }
.nav-status { font-size: .82rem; }
.nav-code { color: var(--muted); font-size: .62rem; min-width: 2.1rem; font-family: var(--font-arcade); }
.nav-title { flex: 1; font-size: .9rem; }

.task-layout { padding: 1.4rem 1.6rem 3rem; }
.lesson-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: 1.7rem; }

.lesson-prose { font-size: 1.04rem; line-height: 1.75; min-width: 0; }
.lesson-prose h1 { font-size: 1.6rem; line-height: 1.25; }
.lesson-prose .crumb { color: var(--muted); font-size: .85rem; }
.lesson-prose .description > :first-child { margin-top: .2rem; }
.lesson-prose .description h2, .lesson-prose .description h3 { margin-top: 1.6rem; }
.lesson-prose .checks { margin-top: 1.2rem; }
.stuck-note {
  margin-top: 1.2rem; padding: .7rem .9rem;
  background: var(--warn-bg); border: 3px solid var(--outline);
  box-shadow: 3px 3px 0 var(--outline-soft); font-size: .92rem;
}

.task-header { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.pill {
  background: var(--accent-soft); color: var(--accent-dark);
  border: 2px solid var(--outline); border-radius: 0; padding: .25rem .55rem;
  font-family: var(--font-arcade); font-size: .54rem; line-height: 1.5;
}
.pill.bonus { background: var(--bonus-bg); color: var(--amber); }

/* ═══════════════════════════════════════════ the workpane ═══════════ */

/* The workpane rides along as the lesson text scrolls, like the Trinket embed. */
.lesson-work {
  position: sticky; top: calc(var(--topbar-h) + 1.4rem); align-self: start;
  max-height: calc(100vh - var(--topbar-h) - 2.8rem); overflow-y: auto; min-width: 0;
  padding-right: 4px;   /* room for the hard shadow inside the scroll box */
}
.workpane {
  background: var(--card); border: 3px solid var(--outline); border-radius: 0;
  overflow: hidden; box-shadow: 5px 5px 0 var(--shadow);
}
.pane-head {
  display: flex; justify-content: space-between; align-items: center; gap: .6rem;
  padding: .4rem .5rem .4rem .8rem; background: var(--pane-head);
  border-bottom: 3px solid var(--outline);
}
.pane-label { font-family: var(--font-arcade); font-size: .58rem; color: var(--muted); }
/* Tabs: the editor, plus the data files the task hands the student. */
.pane-tabs { display: flex; gap: .2rem; flex-wrap: wrap; margin: -.4rem 0 -.4rem -.8rem; }
.pane-tab {
  background: none; border: none; border-bottom: 4px solid transparent;
  border-radius: 0; padding: .55rem .8rem; font-size: .82rem; color: var(--muted);
  font-family: var(--font-code); font-weight: 600; cursor: pointer; box-shadow: none;
}
.pane-tab:hover { color: var(--ink); background: var(--accent-soft); }
.pane-tab:active { transform: none; }
.pane-tab.current {
  color: var(--ink); font-weight: 700; border-bottom-color: var(--red); background: var(--card);
}
.data-note {
  margin: 0; padding: .55rem .8rem; font-size: .85rem; color: var(--muted);
  border-bottom: 2px solid var(--border);
}
.datafile {
  margin: 0; padding: .8rem; max-height: 26rem; overflow: auto; font-size: .9rem;
  white-space: pre-wrap; word-break: break-word; background: var(--code-bg);
  border: none; box-shadow: none;
}

.pane-actions { display: flex; gap: .45rem; }
.pane-actions button { padding: .3rem .75rem; font-size: .88rem; }
button.run {
  background: var(--run); border-color: var(--outline); color: #f4fff6;
  text-shadow: 1px 1px 0 rgba(0, 0, 0, .4);
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .22), 3px 3px 0 var(--shadow);
}
button.run:active:not(:disabled) {
  box-shadow: inset 0 -4px 0 rgba(0, 0, 0, .22), 0 0 0 var(--shadow);
}
.pane-section { padding: .85rem .9rem 0; }
.pane-section h2 { margin-top: 0; font-size: 1.02rem; }
.pane-foot {
  display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
  padding: .55rem .8rem; border-top: 3px solid var(--outline); font-size: .86rem;
  background: var(--pane-head);
}
.workpane .CodeMirror { border: none; border-radius: 0; min-height: 260px; }
/* Before CodeMirror takes over (and if its CDN is unreachable). */
.workpane #editor {
  border: none; border-radius: 0; min-height: 260px; background: var(--card);
  font-family: var(--font-code); font-size: .95rem; box-shadow: none;
}
.workpane .snippet { margin: 0; border: none; border-radius: 0; box-shadow: none; }
.workpane .output {
  margin: 0; border-radius: 0; border: none; border-top: 3px solid var(--outline);
  max-height: 17rem; overflow: auto; box-shadow: none;
}
.workpane .btn-row { padding-bottom: .85rem; }
.lesson-work .ai-card { margin-top: 1rem; }
.lesson-work #result-banner:not(.hidden) { margin-top: 1rem; }

/* The console. Always the dark CRT, in either theme. */
.output {
  margin-top: .8rem; background: #100c22; color: #d8e7f5; border: 3px solid var(--outline);
  box-shadow: none;
}
/* The caret shown at an input() prompt, inline at the end of the transcript. */
.output .term-input {
  font: inherit; color: #9be9a8; background: transparent; padding: 0;
  border: none; border-bottom: 2px solid #4b5a70; caret-color: #9be9a8; min-width: 10rem;
  box-shadow: none;
}
.output .term-input:focus { outline: none; border-bottom-color: #9be9a8; background: transparent; }
.output .term-input:disabled { color: #9be9a8; opacity: .8; }
.output .term-hint { margin-top: .7rem; color: #8ba0ba; font-size: .8rem; white-space: normal; }

.checks summary { cursor: pointer; font-weight: 800; }
.snippet { background: var(--code-bg); }
.CodeMirror {
  border: 3px solid var(--outline); border-radius: 0; height: auto; min-height: 140px;
  font-size: .95rem;
}
[data-theme="dark"] .CodeMirror { filter: invert(.92) hue-rotate(180deg); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .CodeMirror { filter: invert(.92) hue-rotate(180deg); }
}

.description img { max-width: 100%; }
.description table { border-collapse: collapse; display: block; overflow-x: auto; }
.description td, .description th { border: 2px solid var(--outline); padding: .35rem .6rem; }

/* ═══════════════════════════════════════════ prev / next warp ═══════ */

.lesson-foot {
  display: flex; justify-content: space-between; gap: 1rem; margin-top: 1.8rem;
  padding-top: 1.2rem; border-top: 4px solid var(--outline);
}
.foot-link {
  display: flex; flex-direction: column; gap: .1rem; text-decoration: none;
  border: 3px solid var(--outline); border-radius: 0; padding: .6rem 1.1rem;
  background: var(--card); color: var(--ink); min-width: 12rem;
  box-shadow: 4px 4px 0 var(--shadow);
  transition: transform .1s steps(1), box-shadow .1s steps(1);
}
.foot-link:hover { transform: translate(-2px, -2px); box-shadow: 6px 6px 0 var(--shadow); }
.foot-link:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--shadow); }
.foot-link span { color: var(--accent); font-family: var(--font-arcade); font-size: .54rem; }
.foot-link strong { font-family: var(--font-arcade); font-size: .72rem; line-height: 1.5; }
.foot-link.next { text-align: right; align-items: flex-end; }

/* ═══════════════════════════════════════════════ admin tables ═══════ */

.table-scroll { overflow-x: auto; }
table.admin { width: 100%; border-collapse: collapse; background: var(--card); }
table.admin th, table.admin td {
  border: 2px solid var(--outline); padding: .45rem .7rem; text-align: left; font-size: .92rem;
}
table.admin th {
  background: var(--pane-head); font-family: var(--font-arcade); font-size: .54rem;
  line-height: 1.7; font-weight: 400;
}

/* Paste-behaviour signals in the admin views. */
.signal {
  border-radius: 0; padding: .12rem .5rem; font-size: .78rem; white-space: nowrap;
  font-weight: 700; border: 2px solid var(--outline);
}
.signal.watch { background: var(--warn-bg); color: var(--amber); }
.signal.high { background: var(--err-bg); color: var(--red); }

/* ══════════════════════════════════════ who else is on this level ═══ */

/* Full-width card on the worksheet page; `.compact` rides in the lesson
   sidebar. Both carry the same controls, so the CSS differs only in size. */
.presence {
  background: var(--card); border: 3px solid var(--outline); border-radius: 0;
  padding: .8rem 1rem; margin-bottom: 1.1rem; box-shadow: 5px 5px 0 var(--shadow);
}
.presence.offline { display: none; }
.presence-head { display: flex; align-items: center; gap: .5rem; font-size: .95rem; }
.presence-head strong { font-weight: 800; }
.live-dot {
  width: .6rem; height: .6rem; border-radius: 0; background: var(--green);
  box-shadow: 0 0 0 0 var(--green); animation: pulse 2.4s steps(6) infinite;
}
.presence.empty .live-dot, .presence.is-hidden-me .live-dot { background: var(--muted); animation: none; }
@keyframes pulse {
  70% { box-shadow: 0 0 0 .5rem rgba(47, 143, 63, 0); }
  100% { box-shadow: 0 0 0 0 rgba(47, 143, 63, 0); }
}
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

.presence-peers { display: flex; flex-wrap: wrap; gap: .45rem; margin: .65rem 0 0; }
.peer {
  display: inline-flex; align-items: center; gap: .4rem; padding: .18rem .55rem .18rem .22rem;
  border-radius: 0; border: 2px solid var(--outline); background: var(--bg);
  font-size: .85rem; font-weight: 600; cursor: pointer; box-shadow: 2px 2px 0 var(--shadow);
}
.peer:hover { background: var(--accent-soft); }
.peer-dot {
  width: 1.5rem; height: 1.5rem; border-radius: 0; background: var(--coin);
  border: 2px solid var(--outline);
  font-size: .9rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.presence-privacy { margin: .5rem 0 0; font-size: .74rem; color: var(--muted); }
.peer-task { color: var(--muted); font-size: .7rem; font-family: var(--font-code); }
.peer.more { color: var(--muted); border-style: dashed; cursor: default; padding: .2rem .6rem; box-shadow: none; }

.presence-foot { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: .7rem; font-size: .8rem; }
.vibe-open {
  padding: .3rem .7rem; font-size: .85rem; background: var(--accent-soft);
  border-color: var(--outline); color: var(--accent-dark);
}

.vibe-picker {
  margin-top: .65rem; padding: .6rem;
  background: var(--accent-soft); border: 3px solid var(--outline);
  box-shadow: inset 2px 2px 0 var(--outline-soft);
}
.vibe-picker-head {
  display: flex; justify-content: space-between; align-items: center;
  font-size: .85rem; font-weight: 800; margin-bottom: .5rem;
}
.vibe-picker-head button { padding: 0 .3rem; }
.vibe-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.4rem, 1fr)); gap: .4rem; }
.vibe {
  display: flex; flex-direction: column; align-items: center; gap: .1rem;
  padding: .45rem .3rem; font-size: .72rem; line-height: 1.2; text-align: center;
  background: var(--card); border-width: 2px; box-shadow: 2px 2px 0 var(--shadow);
}
.vibe:hover:not(:disabled) { background: var(--coin); color: var(--outline); }
.vibe-emoji { font-size: 1.3rem; }
.vibe-label { color: var(--muted); font-weight: 600; }
.vibe:hover:not(:disabled) .vibe-label { color: var(--outline); }

.presence-note { margin: .55rem 0 0; font-size: .85rem; font-weight: 700; }
.presence-note.good { color: var(--green); }
.presence-note.bad { color: var(--red); }
.presence-hide {
  display: flex; align-items: center; gap: .4rem; margin-top: .65rem;
  font-size: .78rem; color: var(--muted); cursor: pointer;
}
.presence-hide input { width: auto; box-shadow: none; border-width: 2px; accent-color: var(--red); }

/* The sidebar version: same bar, tucked under the worksheet contents. */
.presence.compact {
  margin: .9rem .2rem 0; padding: .6rem .65rem;
  background: var(--bg); box-shadow: 3px 3px 0 var(--shadow); border-width: 2px;
}
.presence.compact .presence-head { font-size: .82rem; line-height: 1.3; }
.presence.compact .peer { font-size: .78rem; }
.presence.compact .vibe-grid { grid-template-columns: repeat(auto-fill, minmax(4.4rem, 1fr)); }
.presence.compact .vibe { font-size: .62rem; padding: .35rem .2rem; }
.presence.compact .vibe-emoji { font-size: 1.05rem; }

/* Vibes land as a stack of cards in the corner, wherever the student is. */
.vibe-toasts {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 50;
  display: flex; flex-direction: column; gap: .55rem; max-width: min(22rem, 92vw);
}
.vibe-toast {
  display: flex; gap: .6rem; align-items: flex-start; cursor: pointer;
  background: var(--card); border: 3px solid var(--outline); border-left-width: 8px;
  border-left-color: var(--success-border);
  border-radius: 0; padding: .65rem .8rem; font-size: .88rem; line-height: 1.45;
  box-shadow: 5px 5px 0 var(--shadow); animation: vibe-in .3s steps(4);
}
.vibe-toast.leaving { opacity: 0; transition: opacity .6s ease-in; }
/* One from the instructor stands out — staff are never in the room, so this is
   the only place the class hears from them here. */
.vibe-toast.staff { border-left-color: var(--coin); background: var(--warn-bg); }
.toast-emoji { font-size: 1.6rem; line-height: 1.1; }
@keyframes vibe-in { from { opacity: 0; transform: translateY(.9rem); } }
@media (prefers-reduced-motion: reduce) { .vibe-toast { animation: none; } }

/* ═══════════════════════════════════════════════ narrow screens ═════ */

/* The workpane drops below the lesson text, then the course contents become a
   short scrollable strip at the top. */
@media (max-width: 1180px) {
  .lesson-split { grid-template-columns: minmax(0, 1fr); gap: 1.2rem; }
  .lesson-work { position: static; max-height: none; overflow: visible; }
}
@media (max-width: 900px) {
  main.lesson-page { grid-template-columns: minmax(0, 1fr); }
  .lesson-nav {
    position: static; height: auto; max-height: 13rem;
    border-right: none; border-bottom: 4px solid var(--outline);
    display: flex; flex-direction: column;
  }
  /* The contents become a short scrollable strip, which would bury the room at
     the bottom of it — so on a phone the room comes first instead. The strip
     scrolls, so nothing in it may be squeezed to fit. */
  .lesson-nav > * { flex: none; }
  .lesson-nav .presence.compact { order: -1; margin: 0 0 .6rem; }
  .task-layout { padding: 1rem 1rem 2.5rem; }
}

@media (max-width: 640px) {
  body { font-size: 16px; }
  .lesson-prose { font-size: 1rem; }
  .lesson-prose h1 { font-size: 1.3rem; }
  .lesson-foot { flex-direction: column; }
  .foot-link { min-width: 0; }
  .foot-link.next { text-align: left; align-items: flex-start; }
  main { margin-top: 1rem; padding: 0 .7rem; }
  /* On a phone the HUD wraps to three rows; sticking it to the top would eat a
     third of the screen, and every sticky element below it is static at this
     width anyway. */
  .topbar { position: static; padding: .5rem .7rem calc(.5rem + 14px); }
  .brand-name { font-size: .7rem; }
  .card { padding: .9rem 1rem; }
  .card.narrow { margin: 1.2rem auto; }
  h1 { font-size: 1.3rem; }
  .hero::before { display: none; }
  .ws-row { flex-direction: column; align-items: stretch; gap: .5rem; }
  .ws-progress { text-align: left; }
  .btn-row button, .btn-row .btn { flex: 1 1 auto; text-align: center; }
  .btn-row .muted { flex-basis: 100%; }
  .scoreboard { gap: .5rem; }
  .score { flex: 1 1 100%; }
}

/* ═══════════════════════════════════ character, badges & cards ══════════ */

/* ---- the HUD player tile, now with a face in it ------------------------ */
/* The player tile is the one that runs across rather than down: face, then
   name and stage beside it. */
.score-player { flex-direction: row; align-items: center; gap: .65rem; }
.score-lines { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.score-sub { font-family: var(--font-arcade); font-size: .5rem; color: var(--accent); line-height: 1.6; }
.hud-avatar {
  width: 3rem; height: 3rem; flex: none; display: grid; place-items: center; overflow: hidden;
  border: 3px solid var(--outline); background: var(--accent-soft);
  box-shadow: 2px 2px 0 var(--shadow);
}
.hud-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hud-avatar-empty { font-size: 1.4rem; }
a.score { text-decoration: none; color: inherit; }
a.score:hover { filter: brightness(1.04); }
a.score:hover .score-val { color: var(--accent-dark); }
.ws-badge {
  display: block; margin-top: .35rem; font-size: .72rem; color: var(--amber);
  font-weight: 700; max-width: 14rem;
}

/* ---- the creator ------------------------------------------------------- */
.creator { display: grid; grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); gap: 1.2rem;
  align-items: start; }
.char-panel {
  background: var(--card); border: 3px solid var(--outline); box-shadow: 5px 5px 0 var(--shadow);
  padding: 1rem; display: flex; flex-direction: column; gap: .7rem; align-items: center;
  text-align: center;
}
/* The portrait window: always square, so a page of them lines up whatever the
   model hands back. */
.char-frame {
  width: 100%; aspect-ratio: 1; border: 3px solid var(--outline);
  background: var(--accent-soft); display: grid; place-items: center; overflow: hidden;
  box-shadow: inset 3px 3px 0 var(--outline-soft);
}
.char-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.char-drawing { padding: 1rem; color: var(--muted); font-size: .9rem; }
.char-drawing p { margin: .3rem 0; }
.char-drawing > span { font-size: 2.4rem; display: block; }
.char-spinner { animation: bob 1.1s steps(4) infinite; }
@keyframes bob { 50% { transform: translateY(-.4rem) rotate(180deg); } }
@media (prefers-reduced-motion: reduce) { .char-spinner { animation: none; } }

.stage-plate {
  display: flex; flex-direction: column; gap: .15rem; align-items: center;
  background: var(--coin); color: #221a33; border: 3px solid var(--outline);
  box-shadow: 3px 3px 0 var(--shadow); padding: .4rem .9rem; width: 100%;
}
.stage-num { font-family: var(--font-arcade); font-size: .5rem; }
.stage-plate strong { font-family: var(--font-arcade); font-size: .78rem; line-height: 1.5; }
.stage-next { margin: 0; font-size: .88rem; }
.tiny { font-size: .78rem; }

.char-choices { display: flex; flex-direction: column; gap: .9rem; }
.choice-set {
  border: 3px solid var(--outline); background: var(--card); padding: .7rem .9rem 1rem;
  box-shadow: 4px 4px 0 var(--shadow); margin: 0;
}
.choice-set legend {
  font-family: var(--font-arcade); font-size: .58rem; background: var(--outline);
  color: var(--card); padding: .3rem .5rem;
}
.choice-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: .45rem; }
/* Real radios, hidden; the block beside them is what gets styled. Keyboard and
   screen readers get the standard control, everyone else gets the block. */
.opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.opt span {
  display: block; padding: .45rem .55rem; font-size: .88rem; font-weight: 600;
  border: 2px solid var(--outline); background: var(--bg); cursor: pointer;
  box-shadow: 2px 2px 0 var(--outline-soft);
}
.opt span:hover { background: var(--accent-soft); }
.opt input:checked + span {
  background: var(--coin); color: #221a33; box-shadow: 2px 2px 0 var(--shadow);
}
.opt input:focus-visible + span { outline: 3px solid var(--accent); outline-offset: 2px; }

/* ---- the growth line --------------------------------------------------- */
.growth { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.growth-step { display: flex; flex-direction: column; align-items: center; gap: .25rem; min-width: 5.5rem; }
.growth-art {
  width: 5rem; height: 5rem; border: 3px solid var(--outline); background: var(--accent-soft);
  display: grid; place-items: center; overflow: hidden; box-shadow: 3px 3px 0 var(--shadow);
}
.growth-art img { width: 100%; height: 100%; object-fit: cover; }
.growth-step.todo .growth-art { background: var(--locked-bg); border-style: dashed; box-shadow: none; }
.growth-step.current .growth-art { border-color: var(--coin); box-shadow: 0 0 0 3px var(--coin); }
.growth-lock { font-family: var(--font-arcade); font-size: 1.2rem; color: var(--muted); }
.growth-name { font-family: var(--font-arcade); font-size: .5rem; }
.growth-need { font-size: .72rem; color: var(--muted); }
.growth-arrow { color: var(--muted); font-size: 1.2rem; }

/* ---- the binder -------------------------------------------------------- */
.binder-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem;
  flex-wrap: wrap; }
.binder-head p { max-width: 52ch; }
.binder-count {
  background: var(--card); border: 3px solid var(--outline); box-shadow: 4px 4px 0 var(--shadow);
  padding: .5rem .9rem; display: flex; flex-direction: column; gap: .2rem;
}
.binder { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 1.1rem; margin: 1.2rem 0 2rem; }

/* A card. The gold rim, the type chip and the flavour line are the collectable
   language; the art window is the only part the model draws, and every word on
   the card is real text sitting on top of it. */
.tcard {
  background: var(--card); border: 3px solid var(--outline);
  box-shadow: 5px 5px 0 var(--shadow); padding: .5rem;
  display: flex; flex-direction: column; gap: .45rem;
  /* Just a wash of the card's type in the bottom corner — the chip and the
     art window carry the colour; the flavour text still has to be read. */
  background-image: linear-gradient(155deg, var(--card) 76%, var(--type-tint, var(--accent-soft)));
}
.tcard-head { display: flex; justify-content: space-between; align-items: baseline; gap: .4rem; }
.tcard-head h3 { margin: 0; font-size: 1rem; line-height: 1.2; }
.tcard-type {
  font-family: var(--font-arcade); font-size: .48rem; white-space: nowrap;
  background: var(--type-color, var(--accent)); color: #fffdf5;
  border: 2px solid var(--outline); padding: .25rem .4rem;
}
.tcard-art {
  aspect-ratio: 3 / 4; border: 3px solid var(--outline); overflow: hidden;
  background: var(--code-bg); display: grid; place-items: center;
  box-shadow: inset 0 0 0 3px var(--type-color, var(--accent));
}
.tcard-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tcard-developing { text-align: center; color: var(--muted); font-size: .85rem; padding: 1rem; }
.tcard-developing > span { font-size: 2rem; display: block; }
.tcard.developing .tcard-developing > span { animation: bob 1.1s steps(4) infinite; }
.tcard-stats {
  display: flex; justify-content: space-between; gap: .3rem;
  font-size: .7rem; color: var(--muted); border-top: 2px solid var(--border);
  border-bottom: 2px solid var(--border); padding: .3rem 0;
}
.tcard-stats b { font-family: var(--font-arcade); font-size: .6rem; color: var(--ink); }
.tcard-flavour { margin: 0; font-size: .82rem; font-style: italic; line-height: 1.45; }
.tcard-foot {
  display: flex; justify-content: space-between; gap: .4rem; margin-top: auto;
  font-family: var(--font-arcade); font-size: .42rem; color: var(--muted); line-height: 1.8;
}
/* An empty slot in the binder — the gap is the point. */
.tcard.locked { background: var(--locked-bg); border-style: dashed; box-shadow: none; }
.tcard-slot { text-align: center; padding: 1.4rem .8rem; color: var(--muted);
  height: 100%; display: flex; flex-direction: column; justify-content: center; }
.tcard-slot p { margin: .3rem 0; font-size: .85rem; }
.tcard-slot-num { font-family: var(--font-arcade); font-size: .52rem; }
.tcard-slot-mark {
  display: block; font-family: var(--font-arcade); font-size: 2.4rem; margin: .8rem 0;
  color: var(--muted); opacity: .45;
}

/* Card types. Each is a rim colour and a corner tint — the same topic is the
   same colour in every student's binder. */
.t-logic    { --type-color: #7a3fd0; --type-tint: #ece2fb; }
.t-loop     { --type-color: #1668c9; --type-tint: #dceafc; }
.t-string   { --type-color: #c2185b; --type-tint: #fbe0ec; }
.t-data     { --type-color: #0f7b6c; --type-tint: #d9f2ee; }
.t-rune     { --type-color: #a1611b; --type-tint: #f8ebd6; }
.t-warden   { --type-color: #c0392b; --type-tint: #fbe2de; }
.t-signal   { --type-color: #0b7285; --type-tint: #d8f0f5; }
.t-explorer { --type-color: #4a5568; --type-tint: #e6e9ef; }
[data-theme="dark"] .tcard { --type-tint: #2b2456; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tcard { --type-tint: #2b2456; }
}

/* ---- "world cleared" ---------------------------------------------------- */
.award-pop {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
  z-index: 60; display: flex; align-items: flex-start; gap: .8rem;
  max-width: min(34rem, 94vw); padding: .9rem 1rem;
  background: var(--card); border: 3px solid var(--outline); border-bottom-width: 8px;
  border-bottom-color: var(--coin);
  box-shadow: 6px 6px 0 var(--shadow); animation: award-in .4s steps(5);
}
.award-pop p { margin: 0 0 .4rem; font-size: .92rem; }
.award-star { font-size: 2rem; line-height: 1; }
.award-close { position: absolute; top: .2rem; right: .3rem; border: none; box-shadow: none; }
.award-pop.leaving { opacity: 0; transition: opacity 1s ease-in; }
@keyframes award-in { from { opacity: 0; transform: translate(-50%, 1.5rem); } }
@media (prefers-reduced-motion: reduce) { .award-pop { animation: none; } }

/* The first-run form: the same questions as the profile page, but with nothing
   to show beside them yet, so it runs down the middle. */
.onboarding { max-width: 46rem; margin: 0 auto; }
.onboarding > p { max-width: 60ch; }
.onboarding-step { margin: 1.4rem 0 .2rem; font-weight: 700; }

@media (max-width: 820px) {
  .creator { grid-template-columns: minmax(0, 1fr); }
  .char-panel { max-width: 22rem; margin: 0 auto; }
}

/* Staff view of a student's character and cards — small, factual, no frame. */
.admin-char { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap; }
.admin-char p { margin: 0; font-size: .85rem; }
.admin-badges { display: flex; flex-wrap: wrap; gap: .8rem; margin-top: .9rem; }
.admin-badge { display: flex; flex-direction: column; align-items: center; gap: .2rem;
  width: 6rem; text-align: center; }
.admin-badge .growth-need { font-size: .68rem; line-height: 1.25; }

/* ══════════════════════════════════════════════ the guest account ═════ */

/* The strip under the HUD on every page of a guest session. It is a warning,
   not decoration: the work on screen really is going to be thrown away, and
   someone who has just spent an hour on Worksheet 1 must never learn that at
   the end. Warm amber rather than red — nothing has gone wrong. */
.guest-strip {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .5rem 1.1rem; font-size: .88rem; line-height: 1.4;
  background: var(--warn-bg); color: var(--ink);
  border-bottom: 3px solid var(--outline);
}
.guest-tag {
  font-family: var(--font-arcade); font-size: .6rem; letter-spacing: .04em;
  padding: .35rem .45rem; background: var(--coin); color: var(--outline);
  border: 2px solid var(--outline); box-shadow: 2px 2px 0 var(--shadow);
}

/* The way in, under the login form. A second door, plainly the smaller one:
   the TRU ID form keeps the primary button. */
.guest-door { margin-top: 1.2rem; }
.guest-door .tiny { max-width: 46ch; margin-inline: auto; }
.guest-btn { width: 100%; }
.or-rule {
  display: flex; align-items: center; gap: .7rem; margin: 1rem 0 .8rem;
  color: var(--muted); font-size: .8rem; text-transform: uppercase;
  letter-spacing: .08em;
}
.or-rule::before, .or-rule::after {
  content: ""; flex: 1; height: 2px; background: var(--border);
}

/* What sits where the "who else is here" room would be. */
.guest-room p { margin: .3rem 0 0; }
