/* ── Lessons ─────────────────────────────────────────────────────────────────
   The course pages and the level screen. Tokens only — a lesson is the same
   paper and the same ink as everything else; the only thing it adds is a way to
   sit a sentence directly under a board.

   The level screen is a column: what you are asked · the board · what you may do
   about it. The board is a REAL game screen mounted whole, so the first job here
   is to strip the parts of it the lesson owns instead — its own back button, its
   own footer, its own undo stack. A drill goes further and hides every control,
   because the only thing a drill accepts is a tap on a cell.                    */

/* ── the course front page ─────────────────────────────────────────────────── */

.lsn-intro {
  padding: var(--space-5) var(--space-5) var(--space-4);
}

.lsn-lede {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-xl);
  line-height: 1.45;
  color: var(--text);
}

.lsn-count {
  margin: var(--space-4) 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--mute);
}

/* The chapter's argument, stated before its levels. */
.lsn-teach {
  margin: 0 0 var(--space-4);
  padding: 0 var(--space-2);
  font-size: var(--text-lg);
  line-height: 1.5;
  color: var(--dim);
}

/* A level card says which puzzle the argument is shown in — the course's whole
   claim is that the move travels between games, so the game belongs on the card
   rather than as a surprise inside the level. */
.lsn-lv-b {
  display: grid;
  place-items: center;
  gap: var(--space-2);
}

.lsn-lv-ic {
  display: block;
  width: 34px;
  height: 34px;
}

.lsn-lv-ic svg { width: 100%; height: 100%; }

.lsn-lv-kind {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--mute);
}

.lsn-lv.solved .lsn-lv-kind { color: var(--accent); }

/* ── a level ───────────────────────────────────────────────────────────────── */

.lsn-play {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.lsn-top {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: calc(var(--sat) + var(--space-3)) var(--space-4) var(--space-3);
}

.lsn-where {
  font-size: var(--text-lg);
  color: var(--dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lsn-where b {
  font-family: var(--font-mono);
  color: var(--accent);
  margin-right: var(--space-2);
}

.lsn-src {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--mute);
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius-sm);
  padding: 2px var(--space-3);
}

/* What the player is asked, directly above the board it is asked about. */
.lsn-ask {
  margin: 0;
  padding: 0 var(--space-5) var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-xl);
  line-height: 1.4;
  color: var(--text);
}

/* The board's box. A game's play screen is a `.screen` — absolutely positioned,
   filling its offset parent — and it MEASURES that box to size its own grid. So
   the stage is a positioned box of a definite size and the game fills it, rather
   than the stage shrink-wrapping the game: shrink-wrapping is circular, and the
   board settles at its 26px floor. */
.lsn-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.lsn-foot {
  flex: 0 0 auto;
  padding: var(--space-4) var(--space-5) calc(var(--sab) + var(--space-5));
}

/* ── the mounted game ────────────────────────────────────────────────────────
   A real play screen, hosted. It arrives with a full screen's worth of chrome
   that the lesson has already drawn for itself, so that chrome goes; on a drill
   every control goes, because a drill accepts one gesture and it is a tap on a
   cell. It keeps its own `.screen` positioning — see .lsn-stage — because the
   game measures that box to lay its grid out. */
.lsn-host {
  position: absolute;
  inset: 0;
}

.lsn-host .q-chrome,
.lsn-host .nav,
.lsn-host .pz-statstrip { display: none; }

.is-drill .lsn-host .q-foot,
.is-drill .lsn-host .q-ur,
.is-drill .lsn-host .q-sub,
.is-drill .lsn-host .po-bar { display: none; }

/* A frozen board should look composed, not disabled: no press states, no
   pointer cursor, nothing that invites a gesture the drill will swallow. */
.is-drill .lsn-host .q-cell,
.is-drill .lsn-host .kk-cell,
.is-drill .lsn-host .sg-cell { cursor: default; }

/* ── drill feedback ────────────────────────────────────────────────────────── */

.lsn-hint {
  margin: 0;
  font-size: var(--text-lg);
  line-height: 1.5;
  color: var(--dim);
  min-height: 2.6em;
}

.lsn-yes { color: var(--accent); }
.lsn-no { color: var(--dim); }

.lsn-tally {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--mute);
}

/* A wrong tap is answered with a shake and a sentence, never with a penalty —
   the drill is where being wrong is supposed to happen. */
.lsn-wrong { animation: lsn-shake var(--duration-2) var(--ease); }

@keyframes lsn-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  75% { transform: translateX(3px); }
}

@media (prefers-reduced-motion: reduce) {
  .lsn-wrong { animation: none; outline: 2px solid var(--mute); outline-offset: -2px; }
}

.lsn-got { position: relative; z-index: 1; }

/* ── the explanation ───────────────────────────────────────────────────────── */

.lsn-why {
  border-top: var(--hairline) solid var(--line);
  padding-top: var(--space-4);
}

.lsn-why-t {
  margin: 0 0 var(--space-4);
  font-size: var(--text-xl);
  line-height: 1.5;
  color: var(--text);
  min-height: 3em;
}

.lsn-why-nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.lsn-why-nav .dd-dots { flex: 1 1 auto; }

.lsn-done {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.lsn-done-t {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--accent);
}

/* An inline ICON.* is a bare <svg> with no intrinsic size — left alone in a flex
   row it grows to fill the box. Every other tick in the app is pinned the same
   way (see .note.done svg). */
.lsn-done-t svg {
  width: 12px;
  height: 12px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
