/* Palette: cobalt glass (what chemists look through at a flame test)
   with flame-test colours: copper, strontium, sodium, potassium and barium for the
   interface, and seven more so each of the twelve domains has its own. */
:root {
  --bg: #1b1f5e;
  --bg-deep: #12154a;
  --panel: #252a78;
  --line: #3d4399;
  --ink: #f2f3ff;
  --dim: #a9aee6;
  --cu: #2fe0b5;
  --sr: #ff5d73;
  --na: #ffc83d;
  --k: #c39bff;
  --ba: #b6f36a;
  --ca: #ff9a4d;
  --cs: #62c4ff;
  --in: #8a97ff;
  --li: #ff8fd8;
  --fe: #f0b890;
  --b: #e8eaff;
  --tl: #74dd8c;
  --tone: var(--cu);
  --display: "Bricolage Grotesque", "Avenir Next", system-ui, sans-serif;
  --body: "Atkinson Hyperlegible Next", "Atkinson Hyperlegible", system-ui, sans-serif;
  --ease: cubic-bezier(.2, .8, .2, 1);
  --spring: cubic-bezier(.3, 1.6, .5, 1);
  /* Room to leave at each edge of the screen: what the device reserves for a notch, a
     status bar or the home indicator (the page is laid out under them: viewport-fit=cover). */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
}
/* An iPad's home-screen app: the system bar's fade reaches about this far below the safe
   area it reports (measured from a screenshot on iPadOS; see main.js). */
:root.ipad-app { --safe-t: calc(env(safe-area-inset-top, 0px) + 44px); }
/* On a touch screen the bottom edge also belongs to the system's swipes, so nothing to tap
   sits right against it even where the device reserves no room. */
@media (pointer: coarse) {
  :root { --safe-b: max(env(safe-area-inset-bottom, 0px), 10px); }
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
/* Nothing inside the map scrolls, and a touch on a tile or the card must never move the
   page. (None of this stops Safari zooming on a double tap: main.js does that.) */
.map, .map * { touch-action: none; }
body {
  background: var(--bg);
  color: var(--ink);
  font: 400 17px/1.5 var(--body);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
button { font: inherit; color: inherit; cursor: pointer; }
button:focus-visible, input:focus-visible {
  outline: 3px solid var(--na);
  outline-offset: 3px;
}
#app { height: 100dvh; }

/* ───────────── Map ───────────── */
.map {
  position: relative;
  height: 100%;
  overflow: hidden;
  touch-action: none;
  /* A drag moves the map; it must not also select tile names or raise the callout. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  contain: layout paint;
  cursor: grab;
  background:
    radial-gradient(circle at 1px 1px, rgb(255 255 255 / .09) 1.2px, transparent 1.6px) 0 0 / 28px 28px,
    radial-gradient(120% 90% at 20% 40%, #262b85 0%, var(--bg) 55%, var(--bg-deep) 100%);
}
.map.dragging { cursor: grabbing; }
.world { position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform; }
.world.glide { transition: transform .6s var(--ease); }
.bonds { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
.bond { stroke: var(--line); stroke-width: 5; stroke-linecap: round; transition: stroke .5s; }
.bond[data-state="open"] { stroke: var(--dim); stroke-dasharray: 2 12; animation: flow 1.2s linear infinite; }
.bond[data-state="done"] { stroke: var(--ink); }
.bond[data-state="ghost"] { stroke-width: 4; stroke-dasharray: 1 10; opacity: .7; }
/* From a waiting topic to each topic it still needs. */
.need { stroke: var(--tone); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 9 8; opacity: .9; }
/* Every frame of the flowing dashes repaints the map, so they rest while the map is being moved. */
.map.moving .bond { animation-play-state: paused; }
@keyframes flow { to { stroke-dashoffset: -14; } }

.tile {
  --size: 92px;
  position: absolute;
  width: var(--size);
  height: var(--size);
  margin: calc(var(--size) / -2) 0 0 calc(var(--size) / -2);
  padding: 0;
  display: grid;
  place-items: center;
  border: 2.5px solid var(--tone);
  border-radius: 16px;
  background: var(--bg-deep);
  opacity: var(--fade, 1);
  transition: transform .25s var(--spring), background .4s, box-shadow .3s, opacity .3s;
}
.tile:hover, .tile.picked, .tile:focus-visible { transform: scale(1.08); opacity: 1; }
.tile .sym { font: 800 38px/1 var(--display); letter-spacing: -.02em; }
.tile .mark { position: absolute; top: 6px; right: 8px; font-size: 13px; line-height: 1; color: var(--tone); }
.tile .name {
  position: absolute;
  top: calc(100% + 9px);
  left: 50%;
  width: 150px;
  translate: -50% 0;
  font: 600 14.5px/1.2 var(--body);
  color: var(--ink);
  text-wrap: balance;
  pointer-events: none;
}
.tile[data-state="done"] { background: var(--tone); color: var(--bg-deep); }
.tile[data-state="done"] .mark { color: var(--bg-deep); }
/* The pulsing ring is a layer of its own for the browser to composite, so only tiles on
   screen (.live) have one. It is ::after so that it is painted last: anything painted over
   a layer needs a layer too, and ::before put the name and the mark over it. (Rings as
   separate elements in one group after the tiles measured slower in Chrome.) */
.tile.live[data-state="open"]::after {
  content: "";
  position: absolute;
  inset: -9px;
  border-radius: 22px;
  border: 2px solid var(--tone);
  animation: ring 2.2s var(--ease) infinite;
}
@keyframes ring {
  from { opacity: .9; transform: scale(.94); }
  to { opacity: 0; transform: scale(1.16); }
}
.tile[data-state="open"] { background: color-mix(in srgb, var(--tone) 18%, var(--bg-deep)); box-shadow: 0 0 26px color-mix(in srgb, var(--tone) 45%, transparent); }
.tile[data-state="locked"] { border-color: var(--line); color: color-mix(in srgb, var(--dim) 55%, var(--bg)); background: color-mix(in srgb, var(--bg-deep) 60%, var(--bg)); }
.tile[data-state="locked"] .name { opacity: .7; }
.tile[data-state="waiting"] { border-style: dashed; background: color-mix(in srgb, var(--tone) 8%, var(--bg-deep)); }
.tile.wanted { box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 40%, transparent); }
.tile[data-state="locked"] .name, .tile[data-state="ghost"] .name { color: var(--dim); }
.tile[data-state="locked"] .mark { color: var(--dim); }
.tile[data-state="ghost"] {
  --faint: color-mix(in srgb, var(--tone) 50%, var(--line));
  border: 2.5px dashed var(--faint);
  color: var(--faint);
  background: var(--bg);
}
.map.far .tile .name { opacity: 0; }
.tile .name { transition: opacity .3s; }
.tile.picked { box-shadow: 0 0 0 5px color-mix(in srgb, var(--tone) 30%, transparent); }

.masthead {
  position: absolute;
  left: calc(12px + var(--safe-l));
  top: calc(10px + var(--safe-t));
  max-width: 354px;
  padding: 10px 14px 14px 12px;
  border-radius: 18px;
  /* No backdrop blur: Safari would blur the map again on every frame of a drag. */
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  cursor: default;
}
.masthead h1 { margin: 0; font: 800 46px/.95 var(--display); letter-spacing: -.035em; }
.brand { display: flex; align-items: center; gap: 10px; }
.home {
  flex: none; display: grid; place-items: center; width: 42px; height: 42px;
  color: var(--ink); background: color-mix(in srgb, var(--bg-deep) 85%, transparent);
  border: 1.5px solid var(--line); border-radius: 12px;
  transition: border-color .2s var(--ease), transform .2s var(--spring);
}
.home:hover { border-color: var(--cu); }
.home:active { transform: scale(.92); }
.home:focus-visible { outline: 3px solid var(--na); outline-offset: 3px; }
.masthead p { margin: 10px 0 0; color: var(--dim); }
.tally {
  margin-top: 14px;
  display: inline-flex;
  gap: 10px;
  align-items: center;
  font-weight: 600;
}
.tally-bar { width: 120px; height: 8px; border-radius: 8px; background: var(--line); overflow: hidden; }
.tally-bar i { display: block; height: 100%; background: var(--cu); border-radius: 8px; transition: width .8s var(--ease); }

.zoomer { position: absolute; right: calc(18px + var(--safe-r)); top: calc(18px + var(--safe-t)); display: flex; gap: 6px; }
.zoomer button, .legend {
  background: color-mix(in srgb, var(--bg-deep) 85%, transparent);
  border: 1.5px solid var(--line);
  border-radius: 12px;
}
.zoomer button { width: 42px; height: 42px; font: 700 20px/1 var(--display); }
.zoomer button svg { display: block; margin: auto; }
.zoomer button.wide { width: auto; padding: 0 14px; font-size: 15px; }
.legend {
  position: absolute;
  left: calc(24px + var(--safe-l));
  bottom: calc(20px + var(--safe-b));
  display: flex;
  flex-wrap: wrap;
  gap: 0 4px;
  padding: 5px 6px;
  font-size: 14px;
  color: var(--dim);
  max-width: min(660px, calc(100% - 48px));
}
.legend button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 30px;
  padding: 0 8px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: inherit;
}
.legend button:hover { color: var(--ink); background: var(--panel); }
.legend i { width: 11px; height: 11px; border-radius: 4px; background: var(--tone); }

.confetti { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.card {
  position: absolute;
  right: calc(18px + var(--safe-r));
  bottom: calc(18px + var(--safe-b));
  width: min(380px, calc(100% - 36px - var(--safe-l) - var(--safe-r)));
  padding: 20px;
  background: var(--panel);
  border: 1.5px solid var(--line);
  border-radius: 22px;
  box-shadow: 0 18px 50px rgb(8 10 50 / .55);
  cursor: default;
  -webkit-user-select: text;
  user-select: text;
  animation: rise .35s var(--spring);
}
@keyframes rise { from { opacity: 0; transform: translateY(18px) scale(.97); } }
.card h2 { margin: 0 0 6px; font: 700 26px/1.1 var(--display); letter-spacing: -.02em; }
.card p { margin: 0 0 14px; color: var(--dim); }
.card .where { color: var(--tone); font-weight: 600; font-size: 15px; margin-bottom: 4px; }
.card .note { color: var(--dim); font-size: 15px; margin: 0; }

.go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 0 24px;
  border: 0;
  border-radius: 14px;
  background: var(--tone);
  color: var(--bg-deep);
  font: 700 18px/1 var(--display);
  transition: transform .2s var(--spring), opacity .3s, filter .2s;
}
.go:hover:not(:disabled) { transform: translateY(-2px) scale(1.02); filter: brightness(1.08); }
.go:active:not(:disabled) { transform: scale(.97); }
.go:disabled { opacity: .35; cursor: not-allowed; }
.quiet {
  min-height: 50px;
  padding: 0 16px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: transparent;
  color: var(--dim);
  font-weight: 600;
}
.quiet:hover { color: var(--ink); border-color: var(--dim); }

/* ───────────── Lesson ───────────── */
.lesson {
  height: 100%;
  display: grid;
  grid-template: "bar bar" auto "stage talk" minmax(0, 1fr) / minmax(0, 1.55fr) minmax(330px, 1fr);
  /* The top and bottom room is left inside the bar, the tray and the footer, so that the
     line between the model and the text runs to the bottom of the screen. */
  padding: 0 var(--safe-r) 0 var(--safe-l);
  background: var(--bg-deep);
}
.lbar {
  grid-area: bar;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: calc(10px + var(--safe-t)) 16px 10px;
  border-bottom: 1.5px solid var(--line);
}
.lbar .back { min-height: 40px; padding: 0 14px; }
.lsym {
  width: 40px;
  height: 40px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--tone);
  color: var(--bg-deep);
  font: 800 19px/1 var(--display);
  view-transition-name: tile;
}
.lbar h1 { margin: 0; font: 700 20px/1.1 var(--display); letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lprog { flex: 1; min-width: 60px; height: 8px; border-radius: 8px; background: var(--line); overflow: hidden; }
.lprog i { display: block; height: 100%; width: 0; background: var(--tone); border-radius: 8px; transition: width .6s var(--ease); }

.stage {
  grid-area: stage;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg);
  border-right: 1.5px solid var(--line);
}
.stage-view { position: relative; flex: 1; min-height: 0; overflow: hidden; }
.stage-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 14px;
  padding: 12px 16px calc(12px + var(--safe-b));
  border-top: 1.5px solid var(--line);
  background: var(--bg-deep);
  min-height: 68px;
}
.stage-controls:empty { display: none; }
.kit-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

.talk { grid-area: talk; display: flex; flex-direction: column; min-height: 0; }
.talk-body {
  flex: 1;
  position: relative;
  overflow-y: auto;
  padding: 30px 28px 34px;
  /* --fit is lowered by the lesson runner when the text would overflow the pane. */
  font-size: calc(1em * var(--fit, 1));
  /* Fades the last lines when the text overflows, as a cue that the pane scrolls. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 30px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 30px), transparent);
}
.stage.resting .stage-view { pointer-events: none; }
.stage-finish { position: absolute; inset: 0; display: grid; place-content: center; justify-items: center; gap: 4px; text-align: center; }
.stage-finish p { margin: 0; font: 700 22px/1.2 var(--display); max-width: 16ch; text-wrap: balance; }
.stage-finish .big-tile {
  width: clamp(96px, 22vmin, 168px);
  height: clamp(96px, 22vmin, 168px);
  font-size: clamp(42px, 10vmin, 76px);
  border-radius: 24px;
  margin-bottom: 18px;
}
.talk-body > * { animation: beat-in .5s var(--ease) backwards; }
.talk-body > :nth-child(2) { animation-delay: .06s; }
.talk-body > :nth-child(3) { animation-delay: .12s; }
.talk-body > :nth-child(4) { animation-delay: .18s; }
@keyframes beat-in { from { opacity: 0; transform: translateY(14px); } }
.talk .count { color: var(--tone); font-weight: 600; font-size: 15px; margin: 0 0 8px; }
.talk h2 { margin: 0 0 14px; font: 700 calc(32px * var(--fit, 1))/1.05 var(--display); letter-spacing: -.025em; text-wrap: balance; }
.talk p { margin: 0 0 14px; max-width: 46ch; }
.talk strong { color: var(--tone); font-weight: 700; }
.goal {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px 14px;
  border: 1.5px dashed var(--tone);
  border-radius: 14px;
  font-weight: 600;
  transition: background .4s, border-color .4s;
}
.goal .tick {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid var(--tone);
  display: grid;
  place-items: center;
  font-size: 14px;
  color: transparent;
  transition: background .3s, color .3s, transform .4s var(--spring);
}
.goal.met { background: color-mix(in srgb, var(--tone) 16%, transparent); border-style: solid; }
.goal.met .tick { background: var(--tone); color: var(--bg-deep); transform: scale(1.15); }
.talk-foot { display: grid; gap: 12px; padding: 12px 28px calc(22px + var(--safe-b)); }
.foot-row { display: flex; gap: 10px; align-items: center; }
.foot-row .go { flex: 1; }
.goal-slot:empty { display: none; }
.stage.resting .stage-controls { display: none; }
.talk-foot .skip { border: 0; background: none; color: var(--dim); text-decoration: underline; font-size: 15px; padding: 8px; }

.options { display: grid; gap: 10px; margin-top: 18px; }
.option {
  text-align: left;
  padding: 14px 16px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  font-weight: 600;
  transition: transform .2s var(--spring), border-color .2s, background .3s;
}
.option:hover:not(:disabled) { border-color: var(--tone); transform: translateX(4px); }
.option.right { background: var(--tone); border-color: var(--tone); color: var(--bg-deep); }
.option.wrong { border-color: var(--sr); animation: shake .35s; opacity: .6; }
.option.wrong { text-decoration: line-through; text-decoration-thickness: 2px; }
.option.right::before { content: "✓ "; }
@keyframes shake { 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.why { margin-top: 16px; color: var(--dim); }

.finish { text-align: left; }
.big-tile {
  width: 104px;
  height: 104px;
  display: grid;
  place-items: center;
  border-radius: 20px;
  background: var(--tone);
  color: var(--bg-deep);
  font: 800 46px/1 var(--display);
  margin-bottom: 20px;
  animation: pop .7s var(--spring) backwards;
  box-shadow: 0 0 0 0 var(--tone);
}
@keyframes pop {
  0% { transform: scale(.3) rotate(-18deg); opacity: 0; }
  60% { box-shadow: 0 0 0 22px color-mix(in srgb, var(--tone) 0%, transparent); }
}
.nexts { display: grid; gap: 10px; margin-top: 8px; }
.next {
  display: grid;
  grid-template-columns: 54px 1fr;
  gap: 14px;
  align-items: center;
  text-align: left;
  padding: 10px 14px 10px 10px;
  border: 1.5px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  transition: transform .2s var(--spring), border-color .2s;
}
.next:hover { transform: translateX(5px); border-color: var(--tone); }
.next .mini {
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  border: 2.5px solid var(--tone);
  font: 800 23px/1 var(--display);
}
.next b { display: block; font: 700 18px/1.15 var(--display); }
.next small { color: var(--dim); font-size: 14.5px; }

/* ───────────── Practice ───────────── */
/* On the map a practice node is round and carries ten pips, one per problem. */
.tile.practice { --size: 66px; border-radius: 50%; border-style: dotted; border-width: 3px; }
.tile.practice[data-state="open"], .tile.practice[data-state="done"] { border-style: solid; }
.tile.practice[data-state="open"]::after { border-radius: 50%; }
.tile.practice[data-state="done"] { background: color-mix(in srgb, var(--tone) 22%, var(--bg-deep)); color: var(--ink); }
.tile.practice .name { top: calc(100% + 7px); font-size: 13.5px; font-style: italic; }
.pips { display: grid; grid-template-columns: repeat(5, 7px); grid-auto-rows: 7px; gap: 5px 3px; }
.pips i { border-radius: 50%; border: 1.5px solid currentColor; opacity: .75; }
.pips i.on { background: var(--tone); border-color: var(--tone); opacity: 1; }
.tie { stroke: var(--tone); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 1 9; opacity: .9; animation: tie-in .4s var(--ease) backwards; }
.tie.met { stroke-dasharray: none; }
@keyframes tie-in { from { opacity: 0; } }
.tile.needed { opacity: 1; box-shadow: 0 0 0 4px color-mix(in srgb, var(--ink) 55%, transparent); }
.card .best, .finish .best { color: var(--tone); font-weight: 600; }
.tally-more { margin-top: 4px; font-size: 14.5px; color: var(--dim); font-weight: 600; }

/* A problem with no model takes the whole page as one column. */
.practice.solo { grid-template: "bar" auto "talk" minmax(0, 1fr) / minmax(0, 1fr); }
.practice.solo .stage { display: none; }
.practice.solo .talk { width: min(100%, 720px); margin: 0 auto; }
.practice.solo .talk-body { padding-top: clamp(18px, 7vh, 64px); }
.practice .lbar h1 { flex: 1; min-width: 0; }
.ppips { display: flex; gap: 7px; flex: none; }
.ppips i, .big-pips i { width: 14px; height: 14px; border-radius: 50%; border: 2px solid var(--line); transition: background .4s, border-color .4s, transform .4s var(--spring); }
.ppips i.now { border-color: var(--tone); transform: scale(1.2); }
.ppips i.first, .big-pips i.first { background: var(--tone); border-color: var(--tone); }
.ppips i.helped, .big-pips i.helped { border-color: var(--tone); background: color-mix(in srgb, var(--tone) 28%, transparent); }
.big-pips { display: grid; grid-template-columns: repeat(5, max-content); gap: 14px; margin-bottom: 26px; }
.big-pips i { width: 44px; height: 44px; border-width: 3px; animation: pop .6s var(--spring) backwards; }
.big-pips i:nth-child(2) { animation-delay: .08s; }
.big-pips i:nth-child(3) { animation-delay: .16s; }
.big-pips i:nth-child(4) { animation-delay: .24s; }
.big-pips i:nth-child(5) { animation-delay: .32s; }
.big-pips i:nth-child(6) { animation-delay: .4s; }
.big-pips i:nth-child(7) { animation-delay: .48s; }
.big-pips i:nth-child(8) { animation-delay: .56s; }
.big-pips i:nth-child(9) { animation-delay: .64s; }
.big-pips i:nth-child(10) { animation-delay: .72s; }

.prompt { font-size: 1.12em; line-height: 1.45; margin-bottom: 18px; max-width: 56ch; }
.prompt p { max-width: none; }
.prompt > :last-child { margin-bottom: 0; }
.prompt .eq { display: block; margin: 10px 0; font: 700 1.1em/1.3 var(--display); }
.prompt table { border-collapse: collapse; margin: 12px 0; font-size: .92em; font-variant-numeric: tabular-nums; }
.prompt th, .prompt td { padding: 5px 14px; border-bottom: 1.5px solid var(--line); text-align: left; }
.prompt th { color: var(--dim); font-weight: 600; }
.practice { --good: var(--ba); }
.practice .why { max-width: 56ch; min-height: 1.5em; margin-top: 16px; }
.practice .why:empty { min-height: 0; margin: 0; }
.practice .options { margin-top: 0; }
.practice .option.right { background: var(--good); border-color: var(--good); }

.blanks { display: flex; flex-wrap: wrap; gap: 12px 22px; align-items: flex-end; }
.blank { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px; font-weight: 600; }
.blank .lab { flex-basis: 100%; color: var(--dim); font-size: .9em; }
.blank .unit { color: var(--dim); }
.blank input {
  min-height: 52px;
  max-width: 100%;
  padding: 0 14px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  color: var(--ink);
  font: 700 22px/1 var(--display);
  font-variant-numeric: tabular-nums;
  transition: border-color .2s, background .3s;
}
.blank input:focus { border-color: var(--tone); outline: none; }
.blank input.bad { border-color: var(--sr); animation: shake .35s; }
.blank input.good { border-color: var(--good); background: color-mix(in srgb, var(--good) 18%, var(--panel)); }

.equation { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 10px; font: 700 26px/1 var(--display); }
.equation .op { color: var(--dim); }
.term { display: inline-flex; align-items: center; gap: 8px; }
.term sub, .term sup { font-size: .62em; }
.stepper { display: grid; justify-items: center; border: 1.5px solid var(--line); border-radius: 12px; background: var(--panel); overflow: hidden; }
.stepper button { width: 44px; height: 36px; border: 0; background: none; color: var(--dim); font: 700 20px/1 var(--display); }
.stepper button:hover { color: var(--bg-deep); background: var(--tone); }
.stepper b { font-size: 24px; line-height: 1.2; color: var(--ink); font-variant-numeric: tabular-nums; }
.balance.locked .stepper button { visibility: hidden; height: 6px; }
.atom-tally { display: inline-grid; grid-template-columns: repeat(3, auto); gap: 4px 22px; margin-top: 18px; font-weight: 600; font-variant-numeric: tabular-nums; }
.atom-tally[hidden] { display: none; }
.atom-tally .head { color: var(--dim); font-size: .88em; }
.atom-tally span { color: var(--sr); }
.atom-tally span:nth-child(3n + 1), .atom-tally .head { color: var(--dim); }
.atom-tally .level { color: var(--good); }

.order-wrap { max-width: 460px; }
.order-wrap .end { color: var(--dim); font-size: .88em; font-weight: 600; margin: 4px 2px; }
.order { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.order li {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 8px;
  min-height: 50px;
  padding: 4px 6px 4px 12px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  font-weight: 600;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.order li.lifted { border-color: var(--tone); box-shadow: 0 10px 30px rgb(8 10 50 / .6); position: relative; z-index: 1; cursor: grabbing; }
.order .grip { color: var(--dim); letter-spacing: -3px; }
.order button { width: 40px; height: 40px; border: 0; border-radius: 10px; background: none; color: var(--dim); font-size: 18px; }
.order button:hover { background: var(--tone); color: var(--bg-deep); }
.order.locked li { cursor: default; border-color: var(--good); }
.order.locked button, .order.locked .grip { visibility: hidden; }

.sort { display: grid; gap: 8px; max-width: 560px; }
.sort-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 12px;
  padding: 6px 6px 6px 14px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--panel);
  font-weight: 600;
}
.sort-row.bad { border-color: var(--sr); }
.sort-row.good { border-color: var(--good); }
.sort-row .bins { display: inline-flex; gap: 4px; margin-left: auto; }
.sort-row .bins button { min-height: 38px; padding: 0 12px; border: 1.5px solid var(--line); border-radius: 10px; background: transparent; color: var(--dim); font-weight: 700; font-size: .92em; }
.sort-row .bins button[aria-pressed="true"] { background: var(--tone); border-color: var(--tone); color: var(--bg-deep); }
.next.practice .mini { border-radius: 50%; }

/* ───────────── Kit controls (used inside lessons) ───────────── */
.kit-slider { display: grid; gap: 4px; min-width: 190px; flex: 1 1 190px; max-width: 360px; font-size: 15px; }
.kit-slider .row { display: flex; justify-content: space-between; gap: 10px; color: var(--dim); font-weight: 600; }
.kit-slider output { color: var(--ink); font-variant-numeric: tabular-nums; }
.kit-slider input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 26px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.kit-slider input::-webkit-slider-runnable-track { height: 8px; border-radius: 8px; background: var(--line); }
.kit-slider input::-moz-range-track { height: 8px; border-radius: 8px; background: var(--line); }
.kit-slider input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px;
  height: 26px;
  margin-top: -9px;
  border-radius: 50%;
  border: 0;
  background: var(--tone);
  box-shadow: 0 2px 10px rgb(0 0 0 / .4);
  transition: transform .15s var(--spring);
}
.kit-slider input::-moz-range-thumb { width: 26px; height: 26px; border-radius: 50%; border: 0; background: var(--tone); }
.kit-slider input:active::-webkit-slider-thumb { transform: scale(1.2); }
.kit-btn {
  min-height: 44px;
  padding: 0 18px;
  border: 1.5px solid var(--tone);
  border-radius: 12px;
  background: transparent;
  color: var(--ink);
  font-weight: 700;
  transition: transform .2s var(--spring), background .2s, color .2s;
}
/* Hover only where there is a pointer that hovers: on a touch screen it would stick to the last tap. */
@media (hover: hover) {
  .kit-btn:hover:not(:disabled) { background: var(--tone); color: var(--bg-deep); transform: translateY(-1px); }
}
.kit-btn:active:not(:disabled) { transform: scale(.95); }
.kit-btn:disabled { opacity: .4; cursor: not-allowed; }
.kit-btn.solid { background: var(--tone); color: var(--bg-deep); }
/* A question on the stage: the prompt, then answer buttons that all look alike. */
.kit-quiz { flex: 1 1 100%; min-width: 0; }
.kit-ask { display: grid; justify-items: center; gap: 8px; animation: ask-in .4s var(--ease) backwards; }
.kit-ask.leaving { opacity: 0; transform: translateY(-6px); transition: opacity .2s, transform .2s; }
.kit-ask-q { margin: 0; text-align: center; font-weight: 700; line-height: 1.25; text-wrap: balance; max-width: 60ch; }
.kit-ask-step { display: block; color: var(--tone); font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.kit-ask-step:empty { display: none; }
.kit-ask-opts { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 10px; }
.kit-ask-opts .kit-btn { animation: ask-in .4s var(--ease) backwards; }
.kit-ask-opts .kit-btn:nth-child(2) { animation-delay: .05s; }
.kit-ask-opts .kit-btn:nth-child(3) { animation-delay: .1s; }
.kit-ask-opts .kit-btn:nth-child(n+4) { animation-delay: .15s; }
.kit-ask-opts .kit-btn { position: relative; }
.kit-ask-opts .kit-btn.right { background: var(--cu); border-color: var(--cu); color: var(--bg-deep); opacity: 1; }
.kit-ask-opts .kit-btn.wrong, .kit-ask-opts .kit-btn.out, .option.out {
  color: var(--dim); text-decoration: line-through; text-decoration-thickness: 2px; opacity: .5;
}
.kit-ask-opts .kit-btn.out { border-color: var(--line); }
/* The learner's own wrong pick stays told apart from the choices that were merely crossed out. */
.kit-ask-opts .kit-btn.wrong { border-color: var(--sr); opacity: .8; }
/* The tick and the cross are corner badges, so marking a choice never changes its width. */
.kit-ask-opts .kit-btn.right::after, .kit-ask-opts .kit-btn.wrong::after {
  content: "✓"; position: absolute; top: -8px; right: -8px; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font: 700 12px/1 var(--body); text-decoration: none;
  background: var(--ink); color: var(--bg-deep); box-shadow: 0 0 0 2px var(--bg-deep);
}
.kit-ask-opts .kit-btn.wrong::after { content: "✕"; background: var(--sr); }
.kit-ask-note { margin: 0; font-size: 14px; color: var(--na); font-weight: 600; text-align: center; }
.kit-ask-note { min-height: 1.35em; }
.kit-ask-note:empty:not(.kept) { display: none; }
.kit-ask-done { margin: 0; font-weight: 700; color: var(--cu); animation: ask-in .4s var(--ease) backwards; }
.kit-ask-done::before { content: "✓ "; }
@keyframes ask-in { from { opacity: 0; transform: translateY(8px); } }

/* An explanation. It rises over the tray, so the model above stays in view, and waits to be closed. */
.kit-pop {
  position: absolute; inset: 0; z-index: 3;
  display: grid; align-items: end; justify-items: center; padding: 12px;
  background: linear-gradient(to top, rgb(18 21 74 / .85) 30%, rgb(18 21 74 / 0) 75%);
  animation: pop-fade .2s backwards;
}
.kit-pop-card {
  --edge: var(--line);
  position: relative; width: min(100%, 460px); max-height: 100%; overflow: auto;
  display: grid; gap: 8px; padding: 14px 16px 14px;
  border: 1.5px solid var(--edge); border-radius: 16px; background: var(--panel);
  box-shadow: 0 14px 40px rgb(0 0 0 / .45);
  animation: pop-in .32s var(--spring) backwards;
}
.kit-pop.good .kit-pop-card { --edge: var(--cu); }
.kit-pop.bad .kit-pop-card { --edge: var(--sr); }
.kit-pop h3 { margin: 0 36px 0 0; display: flex; align-items: center; gap: 8px; font: 700 19px/1.15 var(--display); }
.kit-pop h3 i {
  flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--edge); color: var(--bg-deep); font: 700 14px/1 var(--body);
}
.kit-pop p { margin: 0; line-height: 1.4; }
.kit-pop .kit-btn { justify-self: end; margin-top: 2px; }
.kit-pop-x {
  position: absolute; top: 6px; right: 6px; width: 36px; height: 36px;
  border: 0; border-radius: 10px; background: none; color: var(--dim); font-size: 24px; line-height: 1;
}
.kit-pop-x:hover { color: var(--ink); background: rgb(255 255 255 / .08); }
.kit-pop.leaving { opacity: 0; transition: opacity .18s; pointer-events: none; }
.stage.resting .kit-pop { display: none; }
@keyframes pop-fade { from { opacity: 0; } }
@keyframes pop-in { from { opacity: 0; transform: translateY(24px) scale(.96); } }

.kit-chips { display: inline-flex; padding: 4px; gap: 4px; border-radius: 14px; background: var(--panel); flex-wrap: wrap; justify-content: center; }
.kit-chips button {
  min-height: 38px;
  padding: 0 14px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--dim);
  font-weight: 700;
  transition: background .25s, color .25s;
}
.kit-chips button[aria-pressed="true"] { background: var(--tone); color: var(--bg-deep); }
.kit-readout { display: grid; font-size: 14px; color: var(--dim); font-weight: 600; line-height: 1.2; text-align: center; min-width: 84px; }
.kit-readout b { font: 700 22px/1.1 var(--display); color: var(--ink); font-variant-numeric: tabular-nums; }

/* ───────────── Small screens ───────────── */
/* ───────────── Periodic table pop-up ───────────── */
.pt-open { min-height: 40px; padding: 0 14px; white-space: nowrap; flex: none; }
.pt-open .short { display: none; }
.zoomer .pt-open { min-height: 42px; color: var(--ink); }
.ptable {
  width: min(1120px, calc(100vw - 24px));
  max-height: calc(100dvh - 24px - var(--safe-t) - var(--safe-b));
  padding: 16px 18px 14px;
  border: 1.5px solid var(--line);
  border-radius: 22px;
  background: var(--bg-deep);
  color: var(--ink);
  box-shadow: 0 24px 70px rgb(8 10 50 / .7);
  overflow: auto;
}
.ptable[open] { animation: rise .3s var(--spring); }
.ptable::backdrop { background: rgb(8 10 50 / .6); backdrop-filter: blur(3px); }
.ptable header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.ptable h2 { margin: 0; font: 700 24px/1 var(--display); letter-spacing: -.02em; }
.ptable header .quiet { min-height: 40px; }
.pt-body { position: relative; }
.pt-grid {
  display: grid;
  grid-template-columns: repeat(18, minmax(0, 1fr));
  grid-template-rows: repeat(7, auto) 10px repeat(2, auto);
  gap: 3px;
}
[data-cat="a"] { --cat: var(--sr); }
[data-cat="e"] { --cat: var(--ca); }
[data-cat="t"] { --cat: var(--na); }
[data-cat="p"] { --cat: var(--tl); }
[data-cat="m"] { --cat: var(--cu); }
[data-cat="n"] { --cat: var(--cs); }
[data-cat="h"] { --cat: var(--k); }
[data-cat="g"] { --cat: var(--li); }
[data-cat="l"] { --cat: var(--fe); }
[data-cat="c"] { --cat: var(--in); }
[data-cat="u"] { --cat: var(--dim); }
.pt-cell {
  aspect-ratio: 1;
  min-width: 0;
  padding: 0;
  display: grid;
  place-items: center;
  position: relative;
  border: 1.5px solid color-mix(in srgb, var(--cat) 55%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--cat) 14%, var(--bg-deep));
  color: var(--ink);
  transition: transform .18s var(--spring), background .2s;
}
.pt-cell small { position: absolute; top: 2px; left: 4px; font: 600 10px/1.2 var(--body); color: var(--dim); }
.pt-cell b { font: 700 clamp(13px, 1.75vw, 21px)/1 var(--display); margin-top: 6px; }
.pt-cell:hover, .pt-cell[aria-current] { transform: scale(1.12); z-index: 1; }
.pt-cell[aria-current] { background: var(--cat); color: var(--bg-deep); }
.pt-cell[aria-current] small { color: var(--bg-deep); }
.pt-gap {
  display: grid;
  place-items: center;
  border: 1.5px dashed color-mix(in srgb, var(--cat) 55%, transparent);
  border-radius: 8px;
  font: 600 10px/1 var(--body);
  color: var(--dim);
}
/* The detail panel sits in the empty space above the transition metals. */
.pt-detail {
  position: absolute;
  left: calc(100% * 2 / 18 + 8px);
  top: 0;
  width: calc(100% * 10 / 18 - 16px);
  aspect-ratio: 10 / 3.05;
  display: flex;
  align-items: center;
  gap: 18px;
  pointer-events: none;
}
.pt-big {
  height: 82%;
  aspect-ratio: 1;
  flex: none;
  display: grid;
  place-items: center;
  position: relative;
  border-radius: 16px;
  background: var(--cat);
  color: var(--bg-deep);
}
.pt-big small { position: absolute; top: 7px; left: 10px; font: 700 15px/1 var(--body); }
.pt-big b { font: 800 clamp(30px, 4.6vw, 58px)/1 var(--display); letter-spacing: -.02em; margin-top: 8px; }
.pt-facts h3 { margin: 0 0 2px; font: 700 24px/1.1 var(--display); letter-spacing: -.01em; }
.pt-facts p { margin: 0; font-size: 15px; line-height: 1.35; color: var(--dim); }
.pt-facts .pt-cat { color: var(--cat); font-weight: 600; }
.pt-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 12px; font-size: 13.5px; color: var(--dim); }
.pt-legend span { display: inline-flex; align-items: center; gap: 6px; }
.pt-legend i { width: 11px; height: 11px; border-radius: 4px; background: var(--cat); }

@media (max-width: 820px) {
  .lesson { grid-template: "bar" auto "stage" minmax(0, 47fr) "talk" minmax(0, 53fr) / minmax(0, 1fr); }
  /* The questions and the finish screen need the room more than the resting model does. */
  .lesson:has(.stage.resting) { grid-template-rows: auto minmax(0, 34fr) minmax(0, 66fr); }
  .stage { border-right: 0; border-bottom: 1.5px solid var(--line); }
  .why { margin-top: 10px; }
  body { font-size: 16px; }
  .talk-body { padding: 14px 18px 30px; }
  .talk p { margin-bottom: 10px; }
  .next { padding: 7px 12px 7px 7px; }
  .next .mini { width: 46px; height: 46px; font-size: 20px; }
  .next small { display: none; }
  .talk h2 { font-size: calc(25px * var(--fit, 1)); margin-bottom: 8px; }
  .talk-foot { padding: 8px 18px calc(12px + var(--safe-b)); gap: 8px; }
  .go, .quiet { min-height: 46px; }
  .goal { padding: 8px 12px; font-size: 15.5px; }
  .talk .count { margin-bottom: 4px; }
  .tally { font-size: 14.5px; white-space: nowrap; }
  .tally-bar { width: 70px; }
  /* The tray sits above the text here, not at the bottom of the screen. */
  .stage-controls { padding: 8px 10px; min-height: 0; gap: 6px 10px; }
  .kit-ask { gap: 6px; }
  /* Room for two lines always, so the model does not jump when a longer question arrives. */
  .kit-ask-q { font-size: 15.5px; min-height: 2.5em; display: grid; align-content: center; }
  .kit-ask-step { font-size: 12px; }
  .kit-ask-opts .kit-btn { padding: 0 14px; }
  .kit-pop { padding: 8px; }
  .kit-pop-card { padding: 12px 14px; gap: 6px; }
  .kit-pop h3 { font-size: 17px; }
  .kit-pop p { font-size: 15.5px; }
  .masthead { left: calc(8px + var(--safe-l)); top: calc(8px + var(--safe-t)); max-width: 60%; padding: 8px 12px 10px; }
  .masthead h1 { font-size: 34px; }
  .brand { gap: 8px; }
  .home { width: 36px; height: 36px; border-radius: 10px; }
  .masthead p { display: none; }
  .legend { display: none; }
  /* Long titles wrap onto a second line; the progress bar becomes the header's bottom edge. */
  .lbar { position: relative; gap: 10px; }
  .lbar h1 { flex: 1; min-width: 0; font-size: 16px; white-space: normal; text-wrap: balance; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  .lprog { position: absolute; left: 0; right: 0; bottom: -1.5px; height: 3px; border-radius: 0; background: none; }
  .lprog i { border-radius: 0; }
  .tile { --size: 84px; }
  .tile.practice { --size: 60px; }
  .practice.solo .talk-body { padding-top: 16px; }
  .prompt { font-size: 1.05em; margin-bottom: 12px; }
  /* Ten pips in one row would crowd out the title: two rows of five. */
  .ppips { display: grid; grid-template-columns: repeat(5, 9px); gap: 4px; }
  .ppips i { width: 9px; height: 9px; border-width: 1.5px; }
  .equation { font-size: 21px; gap: 10px 6px; }
  .stepper button { width: 40px; height: 32px; }
  .blank input { font-size: 20px; min-height: 48px; }
  .big-pips { gap: 10px; }
  .big-pips i { width: 36px; height: 36px; }
  .pt-open { padding: 0 10px; }
  .pt-open .full { display: none; }
  .pt-open .short { display: inline; }
  .zoomer .pt-open { display: none; }
  .ptable { padding: 12px 12px 10px; }
  /* The table is wider than a phone: it scrolls sideways under a fixed detail panel. */
  .pt-detail { position: static; width: auto; aspect-ratio: auto; height: 96px; margin-bottom: 10px; gap: 12px; }
  .pt-big { height: 84px; }
  .pt-big b { font-size: 38px; }
  .pt-facts h3 { font-size: 20px; }
  .pt-facts p { font-size: 13.5px; }
  .pt-scroll { overflow-x: auto; margin: 0 -12px; padding: 6px 12px; }
  .pt-grid { width: 700px; }
  .pt-cell b { font-size: 15px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .35s; }
::view-transition-group(tile) { animation-duration: .5s; animation-timing-function: cubic-bezier(.2, .8, .2, 1); }
