/* Light and achromatic. Achromatic is not a style choice: participants name the
   colours of objects, and a coloured interface would shift those judgements
   through simultaneous contrast. The mid-grey behind each stimulus is there for
   the same reason -- a white surround would change how the objects read. */
:root {
  --bg: #f5f6f8;
  --surface: #ffffff;
  --surface-2: #eef0f3;
  --border: #dcdfe4;
  /* Borders that have to answer the cursor: one step darker, never near-black,
     so hovering does not read as selecting. */
  --border-strong: #b7bcc4;
  --text: #1b1d21;
  --text-dim: #616773;
  /* One ink carries every "this one is chosen" state: the primary button, a
     selected answer, a picked room. Selected always means dark ground with
     --on-accent text, which is the pairing that was missing and left selected options
     unreadable. */
  --accent: #2f3640;
  --accent-strong: #191d23;
  --on-accent: #ffffff;
  --ok: #1c7a45;
  --bad: #a33529;
  --stimulus-surround: #6f7378;
  --radius: 8px;
  /* One sans-serif for the whole interface. Emphasis is weight or italics, never
     a second face, never capitals: small caps read as shouting and are harder to
     scan, which is the opposite of what an instruction needs to do. */
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 17px/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
}

#app {
  /* Wide enough for the Unity canvas (960px) plus the card's padding. Prose is
     kept to a readable measure inside the card instead, so widening the page does
     not turn the instructions into long lines. */
  max-width: 1060px;
  margin: 0 auto;
  padding: 32px 20px 72px;
}

/* A page carries one heading. Sub-headings and badges were doing the work of
   punctuation and made simple pages look complicated. */
h1 { font-size: 1.45rem; font-weight: 650; margin: 0 0 .8em; }
h2 { font-size: 1.1rem; font-weight: 600; margin: 1.4em 0 .5em; }
p { margin: 0 0 1em; }
/* Prose fills the card. It used to be capped at 68ch, which on a 1060px page left
   a third of every line empty and made the text look misplaced rather than
   readable. The card's own padding is the measure now. */
ul { margin: 0 0 1em; padding-left: 1.3em; }
li { margin-bottom: .35em; }

.muted { color: var(--text-dim); }
.small { font-size: .9rem; }
.error { color: var(--bad); }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px 34px;
}

/* Wider than the card when a stimulus needs the room. */

.progress-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
  color: var(--text-dim);
  font-size: .85rem;
}

.progress-track {
  flex: 1;
  height: 3px;
  background: var(--surface-2);
  border-radius: 2px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: var(--accent);
  transition: width .3s ease;
}

button, .button {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 11px 20px;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}

button:hover:not(:disabled), .button:hover { background: var(--surface-2); border-color: var(--border-strong); }
button:disabled { opacity: .4; cursor: not-allowed; }

button.primary, .button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}
/* An anchor is inline and underlined by default; a button is neither. */
.button { display: inline-block; text-decoration: none; }
button.primary:hover:not(:disabled), .button.primary:hover {
  background: var(--accent-strong); border-color: var(--accent-strong); }

.actions { display: flex; gap: 12px; align-items: center; margin-top: 22px; }

/* --- stimuli ------------------------------------------------------------ */

.stimulus {
  background: var(--stimulus-surround);
  border-radius: var(--radius);
  padding: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  /* Shrink to the picture rather than to the card. Filling the card's full width
     left a wide grey margin either side of a 760px image but only the padding
     above and below it, so the surround read as lopsided; fit-content makes the
     gap the same 16px on all four sides, and auto margins keep it centred. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 20px;
}

.stimulus img, .stimulus video {
  display: block;
  max-width: 100%;
  border-radius: 6px;
}

/* Overrides the element's width attribute: the stimuli are 1280x720, and the card
   is now wide enough to show them at a useful size. A definite width rather than a
   percentage, because the surround shrinks to fit its content and a percentage
   contributes nothing to that calculation -- it would size to the 1280px intrinsic
   width and leave the grey margin this is meant to remove. max-width still keeps
   it inside a narrow window. */
.stimulus video, .stimulus > img { width: 760px; max-width: 100%; height: auto; }

.stimulus.diagram { background: transparent; padding: 0; }
.stimulus.diagram svg { width: 460px; max-width: 100%; }

.stage { display: flex; gap: 22px; align-items: flex-start; }
.stage-main { flex: 1 1 auto; min-width: 0; }

.sidebar {
  flex: 0 0 190px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.sidebar .thumb {
  background: var(--stimulus-surround);
  border-radius: 8px;
  padding: 7px;
}
.sidebar .thumb img, .sidebar .thumb svg { display: block; width: 100%; border-radius: 4px; }
.sidebar .thumb-label {
  font-size: .75rem;
  color: var(--text-dim);
  margin-bottom: 5px;
}

.video-controls { display: flex; gap: 12px; align-items: center; margin-bottom: 18px; }

/* --- questions ---------------------------------------------------------- */

.question { margin-bottom: 24px; }
.question-prompt { font-weight: 600; margin-bottom: 10px; }

.options { display: flex; flex-wrap: wrap; gap: 10px; }

.option {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 8px;
  padding: 10px 18px;
  cursor: pointer;
  user-select: none;
  transition: background .12s ease, border-color .12s ease;
}
.option:hover:not(.selected) {
  background: var(--surface-2);
  border-color: var(--border-strong);
}
/* Dark ground, light text. It was a dark ground with the body's dark text, so a
   chosen answer was the one thing on the page you could not read. */
.option.selected {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

.image-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px;
}

.image-option {
  background: var(--stimulus-surround);
  border: 3px solid transparent;
  border-radius: 10px;
  padding: 7px;
  cursor: pointer;
}
.image-option img { display: block; width: 100%; border-radius: 5px; }
.image-option.selected { border-color: var(--accent); }
.image-option .tag {
  text-align: center;
  font-size: .8rem;
  color: var(--on-accent);
  font-weight: 700;
  padding-top: 5px;
}

/* --- route builder ------------------------------------------------------ */

.route-pad {
  display: grid;
  grid-template-columns: repeat(3, 62px);
  grid-template-rows: repeat(3, 52px);
  gap: 8px;
  justify-content: center;
  margin: 6px 0 16px;
}
.route-pad button { padding: 0; font-weight: 700; }
.route-pad .n { grid-area: 1 / 2; }
.route-pad .w { grid-area: 2 / 1; }
.route-pad .e { grid-area: 2 / 3; }
.route-pad .s { grid-area: 3 / 2; }

.route-display {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  min-height: 52px;
  font-size: 1.05rem;
}

/* --- clickable diagram -------------------------------------------------- */

.room-picker svg { max-width: 460px; width: 100%; }
.room-picker [data-room] { cursor: pointer; }
.room-picker [data-room].chosen .cm-room,
.room-picker [data-room].chosen .cm-room-start,
.room-picker [data-room].chosen .cm-room-target,
.room-picker [data-room].chosen .cm-room-query {
  stroke: var(--accent-strong);
  stroke-width: 5;
}

/* --- misc --------------------------------------------------------------- */

.checklist label {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  margin-bottom: 12px;
  cursor: pointer;
}
.checklist input { margin-top: 5px; flex: 0 0 auto; }

.code-box {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 18px;
  text-align: center;
  font-size: 1.35rem;
  font-weight: 700;
  margin: 18px 0;
}

.badge {
  display: inline-block;
  font-size: .75rem;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 11px;
  margin-bottom: 12px;
}

/* A practice question is visually unmistakable: a banner above the card, in the
   one place the eye lands first. */
.practice-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  padding: 10px 14px;
  /* Neutral, not amber. The old tint sat next to yellow, which is one of the four
     landmark colours a participant has to name, and it was the only coloured
     panel in an otherwise achromatic interface. The left rule marks it instead. */
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  background: var(--surface-2);
  border-radius: var(--radius);
  color: var(--text);
  font-size: .9rem;
}

.practice-tag {
  font-weight: 700;
  font-size: .72rem;
  flex: 0 0 auto;
}

@media (max-width: 1060px) {
  .stage { flex-direction: column; }
  .sidebar { flex-direction: row; width: 100%; }
  .sidebar > * { flex: 1; }
}

/* --- familiarisation pages ---------------------------------------------- */

/* --- instruction steps -------------------------------------------------- */

.step-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.step-count { color: var(--text-dim); font-size: .85rem; }
.step-dots { display: flex; gap: 6px; }
.step-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--border);
}
/* Where you are, and how much is behind you. A participant who can see the end
   of the instructions reads them rather than hunting for the skip. */
.step-dot.done { background: var(--border-strong); }
.step-dot.here { background: var(--accent); transform: scale(1.3); }

.figure { margin: 18px 0 22px; }
.figure img {
  display: block;
  width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}
/* A label for the picture, not a second paragraph: a caption long enough to read
   as prose competes with the instruction text for the same attention. */
.figure figcaption {
  margin-top: 8px;
  color: var(--text-dim);
  font-size: .85rem;
}

/* Text one side, picture the other. The aerial view is nearly square, so at full
   width it fills the screen and pushes the instruction out of sight. */
.step-aside {
  display: flex;
  gap: 28px;
  align-items: flex-start;
  flex-wrap: wrap;
}
.step-aside-text { flex: 1 1 300px; min-width: 0; }
.step-aside-figure { flex: 0 1 300px; }
.step-aside-figure .figure { margin: 0; }

/* Two pictures compared, so they share a row and stay the same size. */
.figure-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
  margin: 18px 0 22px;
}
.figure-pair .figure { margin: 0; }
.figure-pair figcaption { font-weight: 600; color: var(--text); }

.map-figure { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }
.map-figure .stimulus { flex: 1 1 320px; }

/* A tile is a button because it is one: it is clicked, it takes focus, and it
   answers the keyboard. Styled back down to not look like the primary action. */
.reveal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px;
  margin: 18px 0 22px;
}
.reveal-tile {
  font: inherit;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease;
}
.reveal-tile:hover { border-color: var(--border-strong); background: var(--surface-2); }
.reveal-tile img { display: block; width: 100%; border-radius: 6px; }
.reveal-tile .swatch { margin-bottom: 0; }
.reveal-label {
  margin-top: 8px;
  font-size: .9rem;
  color: var(--text-dim);
}
.reveal-tile.revealed { border-color: var(--accent); }
.reveal-tile.revealed .reveal-label {
  color: var(--text);
  font-weight: 600;
  font-size: 1rem;
}

.check { margin: 6px 0 4px; }
.check-prompt { font-weight: 600; margin-bottom: 4px; }
.check-option.correct { border-color: var(--ok); box-shadow: 0 0 0 2px var(--ok); }
.check-option.wrong { border-color: var(--bad); opacity: .55; }
.check-feedback { min-height: 1.4em; font-size: .95rem; }
.check-feedback.ok { color: var(--ok); font-weight: 600; }
.check-feedback.bad { color: var(--bad); }

.train-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px;
  margin: 18px 0 22px;
}

.train-item { text-align: center; }

.train-thumb {
  background: var(--stimulus-surround);
  border-radius: 8px;
  padding: 6px;
  margin-bottom: 8px;
}
.train-thumb img { display: block; width: 100%; border-radius: 5px; }

.train-label {
  font-weight: 600;
}

/* The colour fills the tile: a border or a light ground beside it would shift how
   the colour reads, which is the one thing this page must not do. */
.swatch {
  height: 96px;
  border-radius: 6px;
  margin-bottom: 8px;
}

/* One SVG, centred by its own geometry. It was three rows of text whose middle
   row was a flex layout, which pushed the centre dot off the axis the arrows
   were supposed to share. */
.compass { flex: 0 0 auto; display: flex; justify-content: center; }
.compass svg { display: block; }
/* SVG text does not inherit the page font on its own, and the default is a
   serif, which would be the one place in the interface with a second typeface. */
.compass svg text, .control-icon svg text { font-family: var(--font); }

/* One control, drawn, centred, with its caption under it. */
.control-figure { text-align: center; margin: 18px 0 22px; }
.control-icon svg { display: block; margin: 0 auto; }
.control-figure figcaption {
  margin-top: 4px;
  font-size: .95rem;
  color: var(--text);
  font-weight: 600;
}

/* --- orientation cue on the first frame --------------------------------- */

.video-frame {
  position: relative;
  display: inline-block;
  line-height: 0;
}

/* Sits over the held first frame; never intercepts clicks. */
.orient-cue {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease;
  /* Light scrim only: the point is to read the first frame *with* the cue over it,
     so the arrow and pill carry their own contrast instead of dimming the frame. */
  background: radial-gradient(ellipse at center, rgba(10, 11, 13, .22), rgba(10, 11, 13, .04) 70%);
  border-radius: 6px;
}

.orient-cue.showing { opacity: 1; }

.orient-arrow {
  font-size: 3.4rem;
  line-height: 1;
  color: #ffffff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .8);
}

.orient-text {
  font: 700 .95rem/1 var(--font);
  color: #ffffff;
  background: rgba(18, 20, 24, .88);
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: 999px;
  padding: 8px 16px;
}

/* --- live navigation ----------------------------------------------------- */

.nav-holder {
  background: #000;
  border-radius: var(--radius);
  /* Never scrolls. The frame is exactly the canvas size and the game page inside
     it is told not to scroll either, so a scrollbar here could only ever be a
     stray pixel of Unity's own chrome. */
  overflow: hidden;
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Exactly the Unity canvas's own size. The build's page positions a fixed
   960x600 container absolutely, so an iframe any smaller makes that page overflow
   and the browser puts scrollbars on both axes -- inside the frame, where no CSS
   of ours can reach. Matching the canvas removes the cause rather than hiding it. */
.nav-frame {
  display: block;
  width: 960px;
  height: 600px;
  max-width: 100%;
  border: 0;
  /* Belt and braces with the game page's own overflow:hidden: on a cross-origin
     frame (the dev setup, where the game is on another port) CSS cannot reach
     inside, and this attribute-backed rule is all that is left. */
  overflow: hidden;
}

.nav-status {
  margin-bottom: 10px;
  transition: color .15s ease;
}

/* A move into a wall is refused by the game; say so rather than leaving the
   participant wondering whether the key registered. */
.nav-status.nav-blocked {
  color: var(--bad);
  font-weight: 600;
}

.nav-log-label {
  font-weight: 600;
  margin-bottom: 5px;
}

/* Practice feedback. Marked plainly so a participant can never mistake a worked
   example for a scored question. */
.feedback { margin: 0 0 22px; }

.feedback-item {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface-2);
  padding: 14px 16px;
  margin-bottom: 12px;
}
.feedback-item.right { border-left-color: var(--ok); }
.feedback-item.wrong { border-left-color: var(--bad); }

.feedback-prompt { font-weight: 600; margin-bottom: .5em; }

.feedback-line {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: .3em;
}
.feedback-mark { flex: 0 0 1em; color: var(--text-dim); }
.feedback-item.right .feedback-mark { color: var(--ok); }

.feedback-why {
  margin-top: .7em;
  padding-top: .7em;
  border-top: 1px solid var(--border);
  color: var(--text-dim);
  font-size: .925rem;
}

/* The route a participant actually walked, shown in practice feedback. */
.feedback-nav {
  margin: .6em 0 0;
  padding: .5em .7em;
  border-radius: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: .925rem;
}
