/*
 * `hidden` means hidden, whatever else a class says.
 *
 * The attribute is implemented as a browser default of `display: none`, which is the
 * weakest rule in the cascade — so any component that sets a display value silently defeats
 * it. That happened to the write-up prompt, which set `hidden` on five of six questions and
 * rendered on all six because its class said `display: flex`.
 *
 * One line, and the whole class of bug goes with it.
 */
[hidden] { display: none !important; }

/*
 * Trial Day — the candidate's side.
 *
 * Daylit office, not a dashboard. Four earlier drafts were rejected for looking like
 * analytics software, and the lesson stuck: the numbers are *furniture* here. The person
 * talking to you is the interface.
 *
 * Palette and faces live in tokens.css, shared with the recruiter console so the two
 * surfaces stay one product. This file is only what the game does with them.
 */

@import url("/tokens.css");

/*
 * The frame never moves.
 *
 * This was a scrolling page, and scrolling is what made it feel like a document rather
 * than a place. The viewport is now fixed: the office stays put, and only the inside of a
 * panel scrolls, the way a list inside a game screen does.
 */
html, body { height: 100%; overflow: hidden; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 15px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
}

#root { flex: 1; min-height: 0; }

/* Anything that might overflow scrolls inside itself, never the page. */
.scrolls { overflow-y: auto; min-height: 0; scrollbar-width: thin; }
.scrolls::-webkit-scrollbar { width: 9px; }
.scrolls::-webkit-scrollbar-thumb { background: var(--room-2); border-radius: 5px; }
.scrolls::-webkit-scrollbar-track { background: transparent; }

button { font: inherit; cursor: pointer; }
button:focus-visible, [tabindex]:focus-visible {
  outline: 2.5px solid var(--accent); outline-offset: 2px;
}

/* ── status bar ──────────────────────────────────────────────────────── */

/*
 * `display: flex` beats the `hidden` attribute, so the bar was showing on the title
 * screen with four empty metrics under it. Needs to be explicit.
 */
.bar[hidden] { display: none; }

.bar {
  flex-shrink: 0; z-index: 40;
  display: flex; align-items: center; gap: 22px;
  padding: 9px 20px;
  background: rgba(242,239,233,.94);
  border-bottom: 1px solid var(--rule);
}
.bar .logo {
  font: 600 13px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--accent);
}
.bar .when { font: 600 14px/1 var(--sans); }
.bar .when small { color: var(--ink-3); font-weight: 400; margin-left: 7px; }

/*
 * The countdown, on invited runs only.
 *
 * Monospaced and tabular so the digits don't jitter every second — a clock that shifts
 * the layout under someone's cursor while they're deciding is its own small cruelty. It
 * stays quiet until five minutes remain, then earns attention.
 */
.bar .clock {
  font: 600 14px/1 var(--mono); font-variant-numeric: tabular-nums;
  padding: 5px 9px; border-radius: 5px;
  background: var(--room); color: var(--ink-2);
}
.bar .clock[hidden] { display: none; }
.bar .clock.low { background: var(--warn-bg); color: var(--warn); }
.bar .clock.out {
  background: var(--bad-bg); color: var(--bad);
  animation: tick 1s steps(2) infinite;
}
@keyframes tick { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .bar .clock.out { animation: none; } }
.bar .spacer { flex: 1; }

.metric { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
.metric b {
  font: 600 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.metric span { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 14px; }
.metric.low span { color: var(--bad); }
.metric.ok span { color: var(--good); }

/* ── the room ────────────────────────────────────────────────────────── */

/*
 * Dialogue and work are different modes, and the mistake was making them share a fixed
 * split. At 36% the room wasted space; at 27% it clipped the speech. Any percentage is
 * wrong, because the right height depends on how much the person has to say.
 *
 * So somebody walking up to your desk is now a *moment* that owns the screen, and then
 * you get the whole screen to work in. `auto` rows, never fractions — the room takes
 * exactly what the text needs and the work takes the rest.
 */
.week {
  height: 100%;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
}

/* The full-screen dialogue beat. */
.moment {
  height: 100%;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  background:
    linear-gradient(180deg, var(--room) 0%, var(--room) 66%, var(--desk) 66%, var(--desk-2) 100%);
  position: relative; overflow: hidden;
}
.moment .stage { padding: 24px 24px 0; max-width: 1000px; }
.moment .bubble { max-width: 52ch; font-size: clamp(15px, 1.7vh + .4vw, 20px); }
.moment .who svg { max-height: min(46vh, 340px); }
.moment .after {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: center; gap: 14px;
  padding: 16px 24px 26px;
}
.moment .qline {
  font: 600 clamp(15px, 1.6vh, 19px)/1.3 var(--serif);
  max-width: 46ch; text-align: right; color: var(--ink);
}

/* The slim reminder of who's waiting, once you're working. */
.askbar {
  flex-shrink: 0;
  display: flex; align-items: center; gap: 12px;
  max-width: 1180px; width: 100%; margin: 0 auto; padding: 9px 20px 0;
}
.askbar .mini { flex-shrink: 0; width: 40px; height: 42px; overflow: hidden; border-radius: 50%; }
.askbar .mini svg { width: 40px; height: 42px; }
.askbar .txt { min-width: 0; flex: 1; }
.askbar .q {
  font: 600 15px/1.3 var(--serif); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.askbar .nm {
  font: 500 10.5px/1.4 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}
.askbar .again {
  flex-shrink: 0; border: 1px solid var(--rule); background: var(--card);
  border-radius: 7px; padding: 6px 11px; font-size: 12.5px; color: var(--ink-2);
}
.askbar .again:hover { border-color: var(--accent); color: var(--accent); }

.scene {
  position: relative; overflow: hidden;
  min-height: 0;
  background:
    linear-gradient(180deg, var(--room) 0%, var(--room) 62%, var(--desk) 62%, var(--desk-2) 100%);
}
/* Used where the room sizes to its content rather than filling a fixed row. */
.scene.auto { min-height: 190px; }
.scene .window {
  position: absolute; top: 26px; left: 6%;
  width: 190px; height: 150px; border-radius: 3px;
  background: linear-gradient(160deg, #f6fbfd 0%, #dcecf3 55%, #cfe3ee 100%);
  border: 7px solid var(--room);
  box-shadow: 0 0 0 1px var(--rule), 0 30px 70px -20px rgba(180,200,215,.75);
}
.scene .window::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 48%, var(--room) 48%, var(--room) 52%, transparent 52%);
}
.scene .plant {
  position: absolute; bottom: 38%; right: 7%; width: 74px; height: 96px;
}
.scene .frame {
  position: absolute; top: 54px; right: 22%;
  width: 74px; height: 56px; border-radius: 2px;
  background: var(--card); border: 5px solid var(--room-2);
  box-shadow: var(--shadow);
}
.scene .lamp {
  position: absolute; bottom: 38%; left: 14%; width: 54px; height: 70px;
}

.stage {
  position: relative; z-index: 2; height: 100%;
  display: flex; align-items: flex-end; justify-content: center; gap: 20px;
  max-width: 1080px; margin: 0 auto; padding: 10px 24px 0;
}

.who { flex-shrink: 0; text-align: center; align-self: flex-end; }
/* The figure scales to the room rather than forcing the room to be tall enough. */
.who svg { display: block; height: auto; max-height: 100%; width: auto;
  filter: drop-shadow(0 10px 18px rgba(60,45,30,.16)); }
/*
 * The caption under the figure, set for the wall it is painted on.
 *
 * ── Why it was unreadable ────────────────────────────────────────────────
 *
 * Both lines inherited inks chosen for --paper, and they are not on --paper: they sit on the
 * office backdrop, which is --bronze (#96693a) behind every world. Measured against it, the
 * role was --ink-2 at **1.6:1** and the name --ink at **3.4:1**, where readable body text
 * wants 4.5:1. The role was effectively invisible, which is what got reported — and it was
 * invisible for every candidate on every question, because the backdrop never varies.
 *
 * ── Why the role is not simply dimmer than the name ──────────────────────
 *
 * The instinct is to set the name white and the role a faded white, the way a caption usually
 * goes. That is backwards here: the role is 10px and small text needs *more* contrast, not
 * less. So both are near-white — 5.1:1 and 4.7:1 — and the hierarchy is carried by weight,
 * size and letter-spacing instead, which costs nothing legible.
 *
 * The shadow is for the figure rather than the wall. A head or a shoulder can sit directly
 * behind the first characters, and that is the one place the flat bronze measurement does
 * not hold.
 */
.who .name {
  margin-top: 2px; font: 600 13px/1.25 var(--sans);
  color: #fff; text-shadow: 0 1px 3px rgba(35, 22, 8, .55);
}
.who .role {
  font: 500 10px/1.25 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  color: rgba(255, 255, 255, .93); text-shadow: 0 1px 3px rgba(35, 22, 8, .55);
}

/* speech bubble */
/*
 * The bubble never scrolls. A scrollbar inside dialogue is the single most game-breaking
 * thing on this screen — you cannot have someone talking to you inside a scroll pane.
 * It sizes to its text instead, and the text shrinks to fit the room when it's long.
 */
.bubble {
  position: relative;
  align-self: center;
  max-width: 42ch; margin-bottom: 3%;
  background: var(--card); border: 1px solid var(--rule); border-radius: 14px;
  padding: 12px 16px;
  box-shadow: var(--shadow);
  font: 400 clamp(13px, 1.3vh + 0.32vw, 15.5px)/1.45 var(--serif);
  overflow: visible;
}
.bubble::after {
  content: ""; position: absolute; right: -11px; bottom: 26px;
  width: 20px; height: 20px; background: var(--card);
  border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  transform: rotate(-45deg);
}
.bubble .cursor {
  display: inline-block; width: 2px; height: 1.05em; margin-left: 2px;
  background: var(--accent); vertical-align: -.15em;
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.pretext {
  margin: 0 0 10px; padding-left: 11px; border-left: 3px solid var(--accent-bg);
  font: 500 13.5px/1.5 var(--sans); color: var(--ink-2);
}

/* ── work area ───────────────────────────────────────────────────────── */

.work {
  min-height: 0;
  max-width: 1180px; width: 100%; margin: 0 auto; padding: 14px 20px 16px;
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 16px;
}
@media (max-width: 860px) { .work { grid-template-columns: 1fr; } }

/* Each column scrolls on its own, so a long brief never moves the office. */
.col {
  min-height: 0; overflow-y: auto; scrollbar-width: thin;
  display: flex; flex-direction: column; gap: 14px;
  padding-right: 4px;
}
.col::-webkit-scrollbar { width: 9px; }
.col::-webkit-scrollbar-thumb { background: var(--room-2); border-radius: 5px; }
.col::-webkit-scrollbar-track { background: transparent; }

.panel {
  background: var(--card); border: 1px solid var(--rule); border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 15px 17px;
  display: flex; flex-direction: column; gap: 11px;
  flex-shrink: 0;
}

h2.title {
  margin: 0;
  font: 600 11px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  color: var(--ink-3);
}
.ask-q { margin: 0; font: 600 21px/1.3 var(--serif); letter-spacing: -.01em; }

.brief { display: flex; flex-direction: column; gap: 12px; }
.brief p { margin: 0; }
.brief .lbl {
  font: 600 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); display: block; margin-bottom: 4px;
}
.brief .method { color: var(--ink-2); }
.brief .watch {
  background: var(--warn-bg); border-radius: 6px; padding: 11px 13px;
  font-size: 14.5px; color: var(--warn);
}

/* term chips */
.terms { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  border: 1px dashed var(--teal); background: var(--teal-bg); color: var(--teal);
  border-radius: 20px; padding: 3px 11px;
  font: 600 12.5px/1.5 var(--sans);
}
.chip:hover { background: var(--teal-bg); }
.chip[aria-expanded="true"] { border-style: solid; background: var(--teal); color: #fff; }

.termcard {
  background: var(--teal-bg); border: 1px solid var(--teal); border-radius: 8px;
  padding: 14px 16px; display: flex; flex-direction: column; gap: 8px;
}
.termcard h4 { margin: 0; font: 600 15px/1.3 var(--sans); }
.termcard h4 small { color: var(--ink-2); font-weight: 500; }
.termcard p { margin: 0; font-size: 14.5px; }
.termcard .why { color: var(--ink-2); }
.termcard .live {
  font: 600 13.5px/1.5 var(--mono);
  background: #fff; border-radius: 5px; padding: 8px 10px; color: var(--teal);
}
.termcard .src {
  font: 500 11px/1 var(--mono); letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
}

/* ── the decision ────────────────────────────────────────────────────── */

.opts { display: flex; flex-direction: column; gap: 5px; }
.opt {
  display: flex; gap: 9px; align-items: center; text-align: left;
  border: 1.5px solid var(--rule); background: #fff; border-radius: 7px;
  padding: 7px 11px; width: 100%;
  font-size: 14px;
}
.opt:hover { border-color: var(--accent); background: var(--accent-bg); }
.opt[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-bg); }
.opt .dot {
  flex-shrink: 0; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--ink-3);
}
.opt[aria-pressed="true"] .dot {
  border-color: var(--accent); background: var(--accent); box-shadow: inset 0 0 0 2.5px #fff;
}
.opt .label { font-weight: 600; }
/* Only rendered when options genuinely differ — see paneAsk. */
.opt .imp { display: block; color: var(--ink-3); font-size: 12.5px; font-weight: 400; }

.row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; }
.field { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 190px; }
.field label {
  font: 600 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
select, input[type="range"] { font: inherit; }
select {
  border: 1.5px solid var(--rule); border-radius: 7px; padding: 9px 10px;
  background: #fff; color: var(--ink);
}
.conf-val { font: 600 13px/1 var(--mono); color: var(--ink-2); }

.commit {
  border: 0; border-radius: 8px; padding: 13px 22px;
  background: var(--accent); color: #fff; font-weight: 600; font-size: 15.5px;
}
.commit:hover { background: var(--accent-2); }
.commit:disabled { background: var(--rule-2); cursor: not-allowed; }

.ghost {
  border: 1.5px solid var(--rule); background: #fff; color: var(--ink-2);
  border-radius: 8px; padding: 12px 18px; font-weight: 600;
}
.ghost:hover { border-color: var(--ink-3); }

.note { font-size: 13.5px; color: var(--ink-3); margin: 0; }
.err {
  background: var(--bad-bg); color: var(--bad); border-radius: 7px;
  padding: 10px 13px; font-size: 14px; font-weight: 500;
}

.finding {
  border-left: 3px solid var(--teal); padding-left: 12px;
  font-size: 14px; color: var(--ink-2);
}
.finding b { display: block; color: var(--ink); font-size: 13px; }

/* ── month playout ───────────────────────────────────────────────────── */

.playout {
  height: 100%; overflow-y: auto; scrollbar-width: thin;
  max-width: 780px; margin: 0 auto; padding: 30px 24px 40px;
  display: flex; flex-direction: column; gap: 16px;
}
.daystrip { height: 8px; background: var(--rule); border-radius: 4px; overflow: hidden; }
.daystrip i { display: block; height: 100%; width: 0; background: var(--accent); }
.beats { display: flex; flex-direction: column; gap: 10px; min-height: 240px; }
.beat {
  display: flex; gap: 14px; align-items: baseline;
  background: var(--card); border: 1px solid var(--rule); border-radius: 8px;
  padding: 12px 16px; box-shadow: var(--shadow);
  opacity: 0; transform: translateY(6px);
  animation: rise .45s ease forwards;
}
.beat .d {
  font: 600 11px/1.6 var(--mono); color: var(--ink-3); white-space: nowrap;
  letter-spacing: .06em;
}
@keyframes rise { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .beat { animation: none; opacity: 1; transform: none; }
  .bubble .cursor { animation: none; }
}

/* ── scorecard / debrief ─────────────────────────────────────────────── */

.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.stat {
  background: var(--card); border: 1px solid var(--rule); border-radius: 9px;
  padding: 13px 15px;
}
.stat b {
  display: block; font: 600 10px/1 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px;
}
.stat span { font: 600 20px/1 var(--sans); font-variant-numeric: tabular-nums; }

.calls { display: flex; flex-direction: column; gap: 8px; }
.call {
  display: flex; gap: 12px; align-items: baseline;
  border-radius: 7px; padding: 10px 13px; font-size: 14px;
  background: var(--bad-bg);
}
.call.right { background: var(--teal-bg); }
.call .mark { font-weight: 700; color: var(--bad); }
.call.right .mark { color: var(--teal); }
.call .q { flex: 1; }
.call .a { color: var(--ink-2); font-size: 13.5px; }

/* ── the writing box, and what the reader sees of it later ───────────── */

/*
 * `display: flex` beat the `hidden` attribute, and the write-up prompt showed on every
 * question.
 *
 * The class sets a display value, and any display value overrides `[hidden]` — which is a
 * browser default of `display: none` and therefore the weakest rule in the cascade. So the
 * client correctly set `why.hidden = true` on the first five decisions, the element
 * correctly reported itself as hidden to anything that asked, and it rendered anyway:
 * "Write this up for the team — last one" sat under question one of six.
 *
 * The general fix is at the top of this file rather than here, so no future component can
 * reintroduce it by naming a display value.
 */
.why {
  display: flex; flex-direction: column; gap: 6px;
  border-left: 3px solid var(--accent); padding: 2px 0 2px 13px; margin: 4px 0;
}
.why label {
  font: 600 11px/1 var(--sans); letter-spacing: .07em;
  text-transform: uppercase; color: var(--ink-3);
}
.why textarea {
  font: 400 14.5px/1.6 var(--serif); color: var(--ink);
  border: 1px solid var(--rule); border-radius: 6px; padding: 9px 11px;
  background: #fff; resize: vertical; min-height: 96px;
}
.why textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.wcount {
  font: 500 12px/1 var(--sans); color: var(--ink-3);
  font-variant-numeric: tabular-nums; align-self: flex-end;
}

.writes { display: flex; flex-direction: column; gap: 10px; }
.write {
  border-radius: 7px; padding: 11px 14px;
  background: var(--sunken); border: 1px solid var(--rule);
}
/* Fabricated figures take the alarm colour — the most serious thing this page can show. */
.write.bad { background: var(--bad-bg); border-color: var(--bad); }
.write .q {
  display: block; font: 600 12px/1.3 var(--sans);
  letter-spacing: .04em; color: var(--ink-3); margin-bottom: 6px;
}
.write p { font: 400 15px/1.62 var(--serif); margin: 0 0 7px; }
.write .a { display: block; color: var(--ink-2); font-size: 13px; }
.write .tn { color: var(--warn); }

/* Traceable to work they did · quoted from nowhere. */
b.ok { background: var(--teal-bg); color: var(--teal); border-radius: 3px; padding: 0 3px; }
b.qm { background: var(--warn-bg); color: var(--warn); border-radius: 3px; padding: 0 3px;
       text-decoration: underline wavy currentColor 1px; text-underline-offset: 3px; }

/* ── the ask pane: a document beside an instrument ───────────────────────
 *
 * Every element in here used to be the same white rounded card on the same beige — the
 * brief, the glossary, the options, the evidence picker, the confidence control. With no
 * variation in treatment the eye had nothing to prioritise, and the decision panel, which
 * is the only thing on the screen that *does* anything, looked exactly like the reading
 * material next to it.
 *
 * So the two halves are now built differently on purpose. The left is a document: no box,
 * the question set large in the book face, the brief on hairline rules. The right is an
 * instrument: bordered, raised, carrying the accent, and holding every control.
 *
 * That contrast is the whole idea. One side you read, one side you operate.
 */
.pane.ask-pane {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(360px, .85fr);
  gap: 30px; align-items: start;
}
@media (max-width: 1000px) { .pane.ask-pane { grid-template-columns: 1fr; gap: 18px; } }

.brief-doc { min-width: 0; padding: 4px 6px 0 0; }
.brief-doc .ask-q {
  margin: 0 0 20px; font: 600 clamp(21px, 1.5vw + .5vh, 28px)/1.22 var(--serif);
  letter-spacing: -.02em; text-wrap: balance; color: var(--ink);
}

/*
 * Labels above their paragraph, not beside it.
 *
 * A two-column list with a 148px label rail narrowed the measure and made a briefing note
 * read like a spec sheet — and the longest label wrapped onto two lines in that rail,
 * pulling the eye sideways before it had finished the sentence next to it. Small quiet
 * eyebrows over full-width text read as prose, which is what this is.
 */
.brief-body { display: flex; flex-direction: column; gap: 17px; }
.brief-body section { display: flex; flex-direction: column; gap: 5px; }
.brief-body p {
  margin: 0; font: 400 15.5px/1.62 var(--sans); color: var(--ink); max-width: 70ch;
}
/* Scaffolding that fades with seniority reads as an aside, not as fact. */
.brief-body .hint p {
  color: var(--ink-2); font-style: italic;
  border-left: 2px solid var(--rule); padding-left: 13px;
}

.watch {
  margin: 16px 0 0; padding: 11px 14px; border-radius: 7px;
  background: var(--warn-bg); font: 400 14px/1.55 var(--sans); color: var(--ink);
}
.watch b {
  display: block; font: 600 10px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--warn); margin-bottom: 5px;
}

.terms-block { margin-top: 22px; }
.eyebrow {
  display: block; font: 600 10.5px/1 var(--mono); letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 9px;
}

/* The instrument. Raised, edged, and the only thing here that acts. */
.decision {
  background: var(--card); border: 1px solid var(--rule); border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 17px 19px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 12px; min-width: 0;
  position: sticky; top: 8px;
}
@media (max-width: 1000px) { .decision { position: static; } }

/* ── the query console ───────────────────────────────────────────────────
 *
 * Three columns: the catalogue, the work, what was kept.
 *
 * This is the one screen in the product that is allowed to look like software, and the
 * exception is deliberate. Everywhere else the numbers are furniture and the person talking
 * to you is the interface; here the candidate *is* doing the job, and the job looks like a
 * SQL client. Making it look like a conversation would be a costume.
 *
 * What holds it to the rest of the product: the same paper, the same ink, the same rules
 * and the same one accent. Nothing here is dark-on-dark, nothing glows, and the monospace
 * appears only where characters have to line up.
 */
.pane.sql-pane {
  display: grid;
  grid-template-columns: minmax(200px, 250px) minmax(0, 1fr) minmax(210px, 270px);
  gap: 20px; align-items: start; min-height: 0;
}
.pane.sql-pane.one { display: block; }
@media (max-width: 1180px) {
  .pane.sql-pane { grid-template-columns: minmax(190px, 230px) minmax(0, 1fr); }
  .pane.sql-pane .kept { grid-column: 1 / -1; }
}
@media (max-width: 820px) {
  .pane.sql-pane { grid-template-columns: 1fr; gap: 16px; }
}

/* ── starting up ─────────────────────────────────────────────────────── */

.sql-loading, .sql-fail {
  border: 1px dashed var(--rule-2); border-radius: 10px; padding: 26px 28px;
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
  max-width: 56ch; margin: 24px auto;
}
.sql-loading b, .sql-fail b { font: 600 16px/1.3 var(--sans); }
.sql-loading p, .sql-fail p {
  margin: 0; font: 400 14.5px/1.6 var(--sans); color: var(--ink-3);
}
.sql-fail { border-color: var(--bad); }
.sql-fail button { margin-top: 6px; }

/* ── left: the catalogue ─────────────────────────────────────────────── */

.schema {
  min-width: 0; max-height: calc(100vh - 210px); overflow-y: auto;
  scrollbar-width: thin; padding-right: 4px;
}
.schema .eyebrow { display: block; margin-bottom: 9px; }
/* The company date. Boxed, because being missed is the one thing it must not be. */
.asof {
  margin: 0 0 14px; padding: 9px 11px; border-radius: 7px;
  background: var(--warn-bg); color: var(--ink-2);
  font: 400 12.5px/1.55 var(--sans);
}
.asof b { font-variant-numeric: tabular-nums; color: var(--ink); }
.asof span { display: block; margin-top: 3px; color: var(--ink-3); font-size: 11.5px; }
.schema-note {
  margin: 14px 0 0; font: 400 12px/1.55 var(--sans); color: var(--ink-3);
}

.tbl { border-top: 1px solid var(--rule); }
.tbl:first-of-type { border-top: 0; }
.tbl-head {
  display: flex; align-items: baseline; gap: 8px; width: 100%;
  padding: 8px 2px; background: none; border: 0; text-align: left; cursor: pointer;
}
.tbl-head .n { font: 500 14px/1.3 var(--mono); color: var(--ink); }
.tbl-head .c {
  margin-left: auto; font: 400 11.5px/1 var(--mono); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.tbl-head:hover .n { color: var(--accent); }
.tbl.open .tbl-head .n { color: var(--accent); font-weight: 600; }

.tbl-note {
  margin: 0 0 8px; font: 400 12.5px/1.55 var(--sans); color: var(--ink-2);
}
.cols { list-style: none; margin: 0 0 12px; padding: 0; }
.cols li {
  display: grid; grid-template-columns: auto 1fr; column-gap: 7px;
  padding: 3px 0; align-items: baseline;
}
/* A column name is a button because clicking it types it into the editor. */
.col {
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
  font: 400 12.5px/1.4 var(--mono); color: var(--ink); border-bottom: 1px dotted var(--rule-2);
}
.col:hover { color: var(--accent); border-bottom-color: var(--accent); }
/*
 * A column name that is only a name.
 *
 * In the SQL console a column is a button — pressing it types the name into the editor, so
 * nobody is retyping `stage_changed_on` against a clock. The pivot has no editor to type
 * into; columns are chosen from dropdowns. A control that looks pressable and does nothing
 * is worse than plain text, so here it is plain text.
 */
.col.plain { cursor: default; border-bottom: 1px dotted var(--rule-2); }
.col.plain:hover { color: var(--ink); border-bottom-color: var(--rule-2); }
.cols .ty { font: 400 10.5px/1.4 var(--mono); color: var(--ink-3); text-transform: lowercase; }
.cols .cn {
  grid-column: 1 / -1; font: 400 11.5px/1.5 var(--sans); color: var(--ink-3);
  margin: 1px 0 3px;
}

/* ── middle: the editor and its result ───────────────────────────────── */

.query { min-width: 0; display: flex; flex-direction: column; gap: 14px; }

/*
 * Says what the box is for.
 *
 * Nothing did. It was an unlabelled rectangle with a grey placeholder, and the placeholder
 * is empty at the two levels that do not get a starter query — so a senior candidate met a
 * blank box and had to infer from the table list that they were expected to write SQL.
 */
.editor-head { display: flex; flex-direction: column; gap: 3px; }
.editor-head p {
  margin: 0; max-width: 68ch;
  font: 400 12.5px/1.55 var(--sans); color: var(--ink-3);
}

.editor {
  border: 1px solid var(--rule-2); border-radius: 9px; background: var(--card);
  box-shadow: var(--shadow); overflow: hidden;
}
.editor:focus-within { border-color: var(--accent); }
#sql {
  display: block; width: 100%; box-sizing: border-box; resize: vertical;
  /*
   * Eleven lines, which is where the height was set from rather than guessed at: the
   * queries this data actually needs are a CTE plus a join plus a GROUP BY, and at the
   * old 132px a five-line query was already scrolling. Somebody against a clock should be
   * able to see the whole of what they are writing.
   */
  min-height: 230px; padding: 13px 15px; border: 0; outline: 0; background: var(--card);
  font: 400 13.5px/1.65 var(--mono); color: var(--ink); tab-size: 2;
}
#sql::placeholder { color: var(--ink-3); opacity: .7; }
.editor-bar {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 12px; border-top: 1px solid var(--rule); background: var(--sunken);
}
.editor-bar .grow { flex: 1; }
.hint-k { font: 400 11.5px/1 var(--mono); color: var(--ink-3); }
.editor-bar .stat {
  font: 400 11.5px/1 var(--mono); color: var(--ink-3); font-variant-numeric: tabular-nums;
}

.sql-err {
  background: var(--bad-bg); color: var(--bad); border-radius: 7px;
  padding: 11px 14px; font: 400 13.5px/1.6 var(--mono); white-space: pre-wrap;
}

.result-empty {
  border: 1px dashed var(--rule); border-radius: 9px; padding: 20px 22px;
}
.result-empty p {
  margin: 0; font: 400 14px/1.65 var(--sans); color: var(--ink-3); max-width: 62ch;
}

.result {
  border: 1px solid var(--rule); border-radius: 9px; background: var(--card);
  overflow: hidden;
}
.result-bar {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 8px 10px; border-bottom: 1px solid var(--rule); background: var(--sunken);
}
.result-bar .grow { flex: 1; }
.vtab {
  background: none; border: 1px solid transparent; border-radius: 6px; cursor: pointer;
  padding: 5px 10px; font: 500 12.5px/1 var(--sans); color: var(--ink-2);
}
.vtab:hover:not(:disabled) { background: var(--room); }
.vtab.on { background: var(--card); border-color: var(--rule-2); color: var(--ink); }
.vtab:disabled { opacity: .38; cursor: not-allowed; }
.axis {
  display: inline-flex; align-items: center; gap: 5px;
  font: 400 11.5px/1 var(--sans); color: var(--ink-3);
}
.axis select {
  font: 400 12px/1 var(--mono); color: var(--ink); padding: 4px 6px;
  border: 1px solid var(--rule-2); border-radius: 5px; background: var(--card);
  max-width: 130px;
}

/*
 * The grid and the chart are the same size, so flipping between them moves nothing.
 *
 * The grid scrolls inside itself in both directions and the page does not. The floor is
 * the part worth explaining: without it a six-row table is about 220px and a chart of the
 * same six rows is 300px, so switching view resized the panel and everything below it
 * shifted. Sharing a floor and a ceiling means the panel is the same height in every view
 * for any result up to the cap, and forty pixels different beyond it.
 *
 * The cost is white space under a very short result. That is a fair trade for a panel that
 * holds still while somebody is reading it.
 */
.grid-wrap {
  min-height: 300px; max-height: 340px;
  overflow: auto; scrollbar-width: thin;
}
.grid { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
.grid th, .grid td {
  padding: 6px 11px; text-align: left; white-space: nowrap;
  border-bottom: 1px solid var(--rule); font: 400 12.5px/1.5 var(--mono);
}
.grid th {
  position: sticky; top: 0; z-index: 1; background: var(--card);
  font-weight: 600; color: var(--ink-2); border-bottom-color: var(--rule-2);
}
.grid td.num { text-align: right; }
.grid td.nul { color: var(--ink-3); font-style: italic; }
.grid tbody tr:hover td { background: var(--sunken); }
.more {
  margin: 0; padding: 8px 12px; border-top: 1px solid var(--rule);
  font: 400 11.5px/1 var(--sans); color: var(--ink-3);
}

/* ── the pivot table ─────────────────────────────────────────────────────
 *
 * The spreadsheet seat's whole interface, and the replacement for two hundred lines of
 * grid: cells, row numbers, column letters, a live cell editor, selection highlighting and
 * spill shading. None of that exists any more, because none of it was doing any work — the
 * grid was an imitation of Excel that a candidate spent their clock discovering the edges
 * of, and the one instruction printed above it could not run at any size.
 *
 * The builder above, the answer below. Sized to sit in the space the SQL editor and its
 * result occupy together, for the same reason those two are matched: moving between
 * questions asked in different languages must not resize the panel and shove everything
 * under it around.
 *
 * The look is deliberately not a pastiche of Excel. Same rules, same ink and the same
 * monospace as the SQL grid beside it, because this is one console with three editors
 * rather than three products — and an imitation that gets the green tint right and the
 * behaviour wrong reads far worse than a tool that is plainly its own thing.
 * --------------------------------------------------------------------- */

.pivot { display: flex; flex-direction: column; min-width: 0; }

/* -- the builder ------------------------------------------------------- */

/*
 * A field list and four wells, which is the arrangement anybody who has used a pivot table
 * already knows.
 *
 * What stood here was a five-row form read top to bottom as a sentence. The argument for it
 * was that Excel's own four panels are opaque for the first ten minutes. The argument was
 * wrong twice: those ten minutes are not spent by somebody who has used Excel, and this seat
 * exists for people who have — so the form threw away the familiarity the whole seat is built
 * on — and it had rows and no columns, which is not a pivot table at all.
 */
.pv-top {
  display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap;
  padding: 8px 12px; background: var(--card);
  border: 1px solid var(--rule); border-bottom: 0; border-radius: 9px 9px 0 0;
}
/*
 * The row count wraps onto its own line rather than being squeezed into whatever is left.
 *
 * It matters most exactly when there is least room for it: once two tables are combined this
 * is where "grown to 30,171 rows" appears, and that number is the warning that a join has
 * fanned out. Set three characters wide down the right-hand edge, it was unreadable.
 */
.pv-top-n {
  font: 400 11.5px/1.4 var(--sans); color: var(--ink-3);
  margin-left: auto; white-space: nowrap;
}
.pv-top select { max-width: 250px; }
@media (max-width: 1150px) {
  .pv-top-n { margin-left: 0; width: 100%; }
}

.pv-build {
  display: grid; grid-template-columns: 148px 1fr; gap: 1px;
  background: var(--rule); border: 1px solid var(--rule); border-top: 0;
  overflow: hidden;
}
.pv-lab {
  flex: none;
  font: 600 10.5px/1.6 var(--sans); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}

/* -- the field list ---------------------------------------------------- */

.pv-fields-list {
  background: var(--card); padding: 9px 10px;
  display: flex; flex-direction: column; gap: 7px; min-width: 0;
}
/* Scrolls on its own: twelve tables here and the widest has nineteen columns. */
.pv-flist {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 240px; overflow-y: auto; min-width: 0;
}
.pv-field {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 4px 6px; border-radius: 5px; cursor: grab; text-align: left;
  background: transparent; border: 1px solid transparent; font: inherit; color: var(--ink);
}
.pv-field:hover { background: var(--sunken); border-color: var(--rule-2); }
.pv-field.dragging { opacity: .4; }
/* Already in a well. Marked, not hidden — a column can go in more than one place. */
.pv-field.in .pv-f-n { color: var(--accent); font-weight: 600; }
.pv-f-t {
  flex: none; width: 15px; text-align: center;
  font: 600 10.5px/1 var(--mono); color: var(--ink-3);
}
.pv-f-n {
  font: 500 12px/1.35 var(--mono); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* -- the four wells ---------------------------------------------------- */

.pv-wells {
  background: var(--card); padding: 9px 11px;
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
}
.pv-well {
  display: grid; grid-template-columns: 68px 1fr; gap: 9px; align-items: start;
  padding: 5px 7px; border-radius: 7px;
  border: 1px dashed transparent;
}
/* Lit while a field is over it, because a drop target that gives no sign is not one. */
.pv-well.over { border-color: var(--accent); background: var(--accent-bg); }
.pv-well[data-empty] { border-color: var(--rule-2); }
.pv-well-h {
  font: 600 10.5px/1.7 var(--sans); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-2);
}
.pv-well-h i {
  display: block; font: 400 10.5px/1.3 var(--sans); letter-spacing: 0;
  text-transform: none; color: var(--ink-3);
}
.pv-well-in {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0;
}
.pv-put { color: var(--ink-3) !important; }

/* The calculation, folded away. See the note in pivotui.js for why it is not a fifth well. */
.pv-calc-fold { margin-top: 2px; }
.pv-calc-fold > summary {
  cursor: pointer; padding: 4px 7px; border-radius: 6px;
  font: 500 12px/1.4 var(--sans); color: var(--ink-3);
}
.pv-calc-fold > summary:hover { background: var(--sunken); color: var(--ink-2); }
.pv-calc-fold .pv-well-in { padding: 7px 7px 2px; }

@media (max-width: 1180px) {
  /* The list goes above the wells rather than shrinking both into uselessness. */
  .pv-build { grid-template-columns: 1fr; }
  .pv-flist { max-height: 132px; flex-direction: row; flex-wrap: wrap; }
  .pv-field { width: auto; }
}

/*
 * The remove button is pinned to the corner rather than sitting in the flow.
 *
 * A well is about three hundred and eighty pixels wide inside the console, so a measure chip
 * of two dropdowns, a name and a "shown as" wraps to two lines — and the ✕, being last,
 * wrapped onto a third line of its own. One control alone on a row, three times over, was
 * most of what made the builder look like a form that had come apart.
 */
.pv-chip {
  position: relative;
  display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap;
  background: var(--sunken); border: 1px solid var(--rule);
  border-radius: 7px; padding: 4px 22px 4px 7px;
}
.pv-chip > .pv-x { position: absolute; top: 3px; right: 2px; }
.pv-as { font: 400 11.5px/1 var(--sans); color: var(--ink-3); }

.pivot select {
  font: 500 12.5px/1 var(--sans); color: var(--ink);
  background: var(--card); border: 1px solid var(--rule-2); border-radius: 5px;
  padding: 5px 6px; max-width: 230px;
}
.pivot select:focus { outline: 0; border-color: var(--accent); }

.pv-name, .pv-val, .pv-formula {
  font: 500 12.5px/1 var(--mono); color: var(--ink);
  background: var(--card); border: 1px solid var(--rule-2); border-radius: 5px;
  padding: 5px 7px;
}
/*
 * Narrow, because it is the least important control in the chip.
 *
 * It was 110px, which on the width a well actually gets pushed the name onto its own line
 * and made every measure two rows tall. What a measure is *called* matters only to a formula
 * that refers to it, and most pivots have none — so it shrinks first and the summarise and
 * column dropdowns keep their room.
 */
.pv-name { width: 78px; flex: 0 1 78px; min-width: 52px; }
.pv-val { width: 120px; }
.pv-formula { width: 230px; }
.pv-name:focus, .pv-val:focus, .pv-formula:focus { outline: 0; border-color: var(--accent); }

.pv-x {
  cursor: pointer; border: 0; background: transparent; color: var(--ink-3);
  font: 400 12px/1 var(--sans); padding: 4px 5px; border-radius: 4px;
}
.pv-x:hover { color: var(--bad); background: var(--card); }

.pv-add {
  cursor: pointer; font: 600 12px/1 var(--sans); color: var(--accent);
  background: transparent; border: 1px dashed var(--rule-2); border-radius: 6px;
  padding: 6px 9px;
}
.pv-add:hover { border-color: var(--accent); background: var(--card); }

/* What is true when a row is empty, said rather than left blank. */
.pv-none { font: 400 12px/1.5 var(--sans); color: var(--ink-3); }

/* -- the answer -------------------------------------------------------- */

.pv-out {
  border: 1px solid var(--rule); border-top: 0; border-radius: 0 0 9px 9px;
  background: var(--card); overflow: hidden;
}

.pv-head {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-bottom: 1px solid var(--rule); background: var(--sunken);
}
.pv-head .grow { flex: 1; }
.pv-note { font: 400 11.5px/1.4 var(--sans); color: var(--ink-3); }
.pivot .small { font-size: 12px; padding: 6px 10px; }

/*
 * An error stands where the answer would have been, and it is a sentence.
 *
 * The interface this replaced answered #SPILL! to the instruction printed on its own screen,
 * for every candidate, for as long as it shipped. A code tells somebody there is a problem
 * and nothing they can do about it.
 */
.pv-err {
  padding: 20px 18px; color: var(--bad);
  font: 400 13.5px/1.6 var(--sans);
}
.pv-err b { font-weight: 600; }

.pv-scroll { overflow: auto; max-height: 340px; scrollbar-width: thin; }
.pv-table { border-collapse: collapse; width: 100%; }
.pv-table th, .pv-table td {
  border-bottom: 1px solid var(--rule); padding: 7px 11px;
  font: 400 12.5px/1.5 var(--mono); white-space: nowrap;
}
.pv-table th {
  position: sticky; top: 0; z-index: 1; cursor: pointer;
  background: var(--sunken); text-align: left;
  font: 600 11px/1.4 var(--sans); letter-spacing: .04em;
  color: var(--ink-2); border-bottom: 1px solid var(--rule-2);
}
.pv-table th:hover { color: var(--ink); }

/*
 * Grouping columns left and aligned left; measures right and aligned right, with the digits
 * lining up. A column of numbers that does not line up is a column somebody misreads.
 */
.pv-table td.pv-m { text-align: right; font-variant-numeric: tabular-nums; }
.pv-table th.pv-m { text-align: right; }
.pv-table td.pv-g { color: var(--ink); }

/* A calculated column is the candidate's own work, and it is marked as theirs. */
.pv-table th.pv-c { color: var(--accent); }

.pv-table tbody tr:hover td { background: var(--sunken); }
.pv-more {
  margin: 0; padding: 8px 12px; border-top: 1px solid var(--rule);
  font: 400 11.5px/1 var(--sans); color: var(--ink-3);
}

.pv-chartbox { padding: 8px 10px 4px; overflow: auto; }

@media (max-width: 1100px) {
  .pv-scroll { max-height: 300px; }
  .pv-lab { width: 60px; }
  .pv-formula { width: 170px; }
}

/*
 * Close to the height of a full table, on purpose.
 *
 * The grid caps at 340px, so a long result and a chart of it used to be very different
 * heights — and flipping between them resized the whole panel, which shifts everything
 * below it. Matching them approximately means the page barely moves. It is not exact
 * (a three-row table is genuinely short, and padding it out to 340 would be worse), so
 * a small shift remains on the longest results; what it no longer does is jump.
 */
.chart-wrap {
  padding: 8px 10px 4px; overflow: auto;
  min-height: 300px; max-height: 340px; display: flex;
}
.plot { align-self: center; }
.plot { display: block; width: 100%; height: auto; min-width: 460px; }
.plot .br { fill: var(--accent); }
.plot .ln { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; }
.plot .pt { fill: var(--accent); }
.plot .ax { stroke: var(--rule-2); stroke-width: 1; }
.plot .xl { font: 400 10.5px var(--sans); fill: var(--ink-3); text-anchor: middle; }
.plot .yl { font: 500 11px var(--sans); fill: var(--ink-2); }
.plot .ymax {
  font: 400 11px var(--mono); fill: var(--ink-3); text-anchor: end;
}

.keep {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 10px 12px; border-top: 1px solid var(--rule); background: var(--sunken);
}
#keep-title {
  flex: 1; min-width: 200px; padding: 8px 11px;
  border: 1px solid var(--rule-2); border-radius: 6px; background: var(--card);
  font: 400 13.5px/1.4 var(--sans); color: var(--ink);
}
#keep-title:focus { outline: 0; border-color: var(--accent); }

/* ── right: what was kept ────────────────────────────────────────────── */

.kept {
  min-width: 0; display: flex; flex-direction: column; gap: 10px;
  max-height: calc(100vh - 210px); overflow-y: auto; scrollbar-width: thin;
}
.kept-item {
  border-left: 3px solid var(--teal); background: var(--teal-bg);
  border-radius: 0 7px 7px 0; padding: 9px 11px;
}
.kept-item h4 {
  margin: 0 0 3px; display: flex; align-items: flex-start; gap: 6px;
  font: 600 13.5px/1.4 var(--sans);
}
.kept-item .drop {
  margin-left: auto; flex: none; background: none; border: 0; cursor: pointer;
  font: 400 16px/1 var(--sans); color: var(--ink-3); padding: 0 2px;
}
.kept-item .drop:hover { color: var(--bad); }
.kept-meta {
  margin: 0; font: 400 11.5px/1.5 var(--mono); color: var(--ink-2);
  overflow-wrap: anywhere;
}
.reopen {
  margin-top: 6px; background: none; border: 0; padding: 0; cursor: pointer;
  font: 500 11.5px/1 var(--sans); color: var(--teal); text-decoration: underline;
  text-underline-offset: 2px;
}
.kept-empty, .kept-note {
  margin: 0; font: 400 12.5px/1.6 var(--sans); color: var(--ink-3);
}
.kept-note { border-top: 1px solid var(--rule); padding-top: 9px; }

/* ── the decision panel, decompressed ────────────────────────────────────
 *
 * Evidence and confidence shared one row, so a dropdown and a slider with a live readout
 * were fighting over the same 360 pixels. They are two separate decisions and each now
 * gets a block, with room to breathe between them.
 */
.fields-stack { display: flex; flex-direction: column; gap: 15px; }
.fields-stack .field { min-width: 0; }
.fields-stack select { width: 100%; }

/*
 * Confidence carries its meaning in colour.
 *
 * A grey bar at 30% and a grey bar at 90% look identical while making opposite claims —
 * one says "don't act on this yet", the other moves budget. The fill and the readout run
 * from neutral through amber to the accent as the assertion gets stronger, so the weight
 * of what is being claimed registers before the number is read.
 */
/*
 * The readout now carries a phrase as well as a number — "70% — more likely right than not"
 * — because the score is a Brier score and a bare percentage gets read as a mood. That makes
 * it long enough to wrap a label, so it drops to its own line rather than fighting the
 * question for width.
 */
.field label .conf-val {
  display: block; margin-top: 4px;
  font: 600 14px/1.3 var(--sans); font-variant-numeric: tabular-nums;
  letter-spacing: 0; text-transform: none; color: var(--ink-3);
}
.field label:has(.conf-val) { display: block; }
#cfhint { margin-top: 7px; max-width: 54ch; }
.conf-val[data-band="low"]  { color: var(--ink-2); }
.conf-val[data-band="mid"]  { color: var(--warn); }
.conf-val[data-band="high"] { color: var(--accent); }

input[type="range"]#cf {
  --fill: 0%;
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 7px; border-radius: 4px; cursor: pointer;
  background: linear-gradient(90deg, var(--band, var(--ink-3)) var(--fill), var(--room) var(--fill));
}
#cf[data-band="low"]  { --band: var(--ink-3); }
#cf[data-band="mid"]  { --band: var(--warn); }
#cf[data-band="high"] { --band: var(--accent); }
#cf.unset { background: var(--room); }
#cf::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 19px; height: 19px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--band, var(--ink-3));
  box-shadow: 0 1px 4px rgba(40,32,20,.28);
}
#cf::-moz-range-thumb {
  width: 19px; height: 19px; border-radius: 50%; border: 2px solid var(--band, var(--ink-3));
  background: var(--card); box-shadow: 0 1px 4px rgba(40,32,20,.28);
}
#cf:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* ── required fields ─────────────────────────────────────────────────────
 *
 * Standard practice, and it was missing: the commit button simply stayed disabled with no
 * indication of what was still owed. An asterisk with a legend costs nothing and removes
 * the guesswork — particularly on a clock, where a candidate stuck on a dead button is
 * losing time to the interface rather than to the problem.
 */
.req { color: var(--accent); font-weight: 700; text-decoration: none; cursor: help; }
.req-note { font-size: 12.5px; color: var(--ink-3); margin: 0 0 8px; }
.opt-tag {
  font: 500 10px/1 var(--mono); letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); background: var(--room); padding: 3px 6px; border-radius: 3px;
  margin-left: 5px;
}

/* ── the induction's "one week" panel ────────────────────────────────────
 *
 * Ten bare pips under the heading "one week" read as ten chances, not ten hours. Time and
 * questions are two different quantities and the panel was showing neither clearly, so
 * each now gets a labelled row of its own.
 */

/* ── the week's closing bar ──────────────────────────────────────────────
 *
 * What is left of the old between-weeks page: one line saying the hours you still hold
 * buy analyses for next week, and the way forward. A whole screen was not paying for
 * itself when nothing resolves between weeks.
 */
/* ── the first-question walkthrough ──────────────────────────────────────
 *
 * A hole cut in a dimmed page rather than an arrow drawn beside it: the point is that the
 * thing being described stays legible and in place while it is described. The ring is an
 * enormous outward shadow, which is what dims everything *except* the target without
 * needing an SVG mask or four separate overlay rectangles.
 */
/*
 * The overlay must not swallow the wheel.
 *
 * #tour is a fixed full-screen layer, so it ate every scroll event and the page froze the
 * moment a step opened — which is what made the last step, pointing at a control below the
 * fold, look completely stuck. Only the card itself needs to be interactive.
 */
#tour { position: fixed; inset: 0; z-index: 200; pointer-events: none; }
.tour-veil { position: absolute; inset: 0; pointer-events: none; }
.tour-card { pointer-events: auto; }
.tour-ring {
  position: absolute; border-radius: 9px; pointer-events: none;
  box-shadow: 0 0 0 9999px rgba(24, 20, 14, .58), 0 0 0 2px var(--accent);
  transition: all .22s cubic-bezier(.4, 0, .2, 1);
}
.tour-card {
  position: absolute; width: 366px; max-width: calc(100vw - 28px);
  background: var(--card); border-radius: 10px; padding: 15px 17px;
  box-shadow: 0 12px 40px rgba(24, 20, 14, .3);
  display: flex; flex-direction: column; gap: 7px;
}
.tour-card.above { transform: translateY(-100%); }
.tour-card .n {
  font: 600 10px/1 var(--mono); letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-3);
}
.tour-card b { font: 600 16px/1.3 var(--sans); }
.tour-card p { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-2); }
.tour-card .row { display: flex; gap: 8px; margin-top: 4px; }
.tour-card .commit { padding: 9px 16px; font-size: 13.5px; }

@media (prefers-reduced-motion: reduce) { .tour-ring { transition: none; } }

/* ── centred single-column scenes (title, board, result) ─────────────── */

.mid {
  height: 100%; overflow-y: auto; scrollbar-width: thin;
  max-width: 780px; margin: 0 auto; padding: 38px 24px 44px;
  display: flex; flex-direction: column; gap: 18px;
}
.mid h1 {
  margin: 0; font: 600 clamp(28px, 4.4vh + 0.9vw, 48px)/1.05 var(--serif);
  letter-spacing: -.025em; text-wrap: balance;
}

/*
 * The title screen fits, always. Sized against viewport *height* rather than width,
 * because it was a short landscape window that pushed it into a scroll.
 */
.mid.title { justify-content: center; padding: 24px 24px 28px; gap: 14px; }
.mid.title .sub { font-size: clamp(14px, 1.5vh + .35vw, 17.5px); }
.mid.title .picker { flex-direction: row; gap: 10px; }
.mid.title .pick { flex: 1; }
.mid.title .pick .d { font-size: clamp(11.5px, 1.15vh, 13.5px); }
@media (max-width: 720px) { .mid.title .picker { flex-direction: column; } }
.mid .sub { font-size: 18px; color: var(--ink-2); max-width: 60ch; }
.mid .kicker {
  font: 600 11.5px/1 var(--mono); letter-spacing: .17em; text-transform: uppercase;
  color: var(--accent);
}

.picker { display: flex; flex-direction: column; gap: 9px; }
.pick {
  display: flex; flex-direction: column; gap: 3px; text-align: left;
  border: 1.5px solid var(--rule); background: var(--card); border-radius: 9px;
  padding: 15px 17px;
}
.pick:hover { border-color: var(--accent); }
.pick[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-bg); }
.pick .t { font-weight: 600; }
.pick .d { color: var(--ink-3); font-size: 13.5px; }

.speaker {
  display: flex; gap: 14px; align-items: flex-start;
  background: var(--card); border: 1px solid var(--rule); border-radius: 10px;
  padding: 14px 16px; box-shadow: var(--shadow);
}
.speaker svg { flex-shrink: 0; }
.speaker .said { font: 400 16px/1.55 var(--serif); }
.speaker .nm {
  font: 600 11px/1.6 var(--mono); letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}

.scoreline {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--rule);
}
.scoreline .l { flex: 1; font-weight: 600; }
.scoreline .n { font: 600 15px/1 var(--mono); font-variant-numeric: tabular-nums; }
.scoreline .track { width: 110px; height: 7px; background: var(--rule); border-radius: 4px; }
.scoreline .track i { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.scoreline small { display: block; color: var(--ink-3); font-weight: 400; font-size: 13px; }
.scoreline.mod .n { color: var(--bad); }
.scoreline.mod.plus .n { color: var(--good); }

.grade {
  font: 600 76px/1 var(--serif); color: var(--accent); letter-spacing: -.03em;
}

/* ── tabs ────────────────────────────────────────────────────────────────
 *
 * The week was one cramped two-column screen with the analyses squeezed into a sidebar.
 * They're the actual work, so they get a room of their own.
 */

.tabs {
  flex-shrink: 0;
  display: flex; gap: 3px; align-items: flex-end;
  max-width: 1180px; width: 100%; margin: 0 auto; padding: 8px 20px 0;
}
.tab {
  border: 1px solid var(--rule); border-bottom: none;
  background: var(--room); color: var(--ink-2);
  border-radius: 8px 8px 0 0; padding: 8px 16px;
  font-weight: 600; font-size: 14px;
  display: flex; align-items: center; gap: 8px;
}
.tab:hover { background: var(--paper); }
.tab[aria-selected="true"] {
  background: var(--card); color: var(--ink);
  box-shadow: 0 -2px 0 var(--accent) inset;
}

/*
 * The data guide, at the far end of the tab row.
 *
 * Pushed away from the tabs and styled unlike them, because it is not one: it opens another
 * tab in the browser rather than another pane of this page, and a control that leaves should
 * not look like a control that switches. The arrow says so a second time.
 */
.tabspace { flex: 1; }
.tab-out {
  align-self: center; text-decoration: none;
  font: 500 12.5px/1 var(--sans); color: var(--ink-3);
  padding: 6px 10px; border: 1px solid var(--rule); border-radius: 6px;
  background: rgba(255,255,255,.5); margin-bottom: 4px;
}
.tab-out:hover { color: var(--ink); border-color: var(--accent); background: #fff; }
.tab .count {
  font: 600 10.5px/1 var(--mono);
  background: var(--accent); color: #fff;
  border-radius: 9px; padding: 3px 6px;
}
.tab[aria-selected="true"] .count { background: var(--accent); }
.tab .count.quiet { background: var(--rule-2); }

.tabwrap { min-height: 0; display: flex; flex-direction: column; }
.tabbody {
  min-height: 0; flex: 1;
  border-top: 1px solid var(--rule);
  background: var(--card);
}
.pane {
  height: 100%; overflow-y: auto; scrollbar-width: thin;
  max-width: 1180px; margin: 0 auto; padding: 16px 20px 22px;
  display: flex; flex-direction: column; gap: 14px;
}
.pane.two {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 18px; align-items: start;
}
@media (max-width: 900px) { .pane.two { display: flex; } }

/* ── charts ──────────────────────────────────────────────────────────── */

.chart { display: flex; flex-direction: column; gap: 9px; }
.chart .ct {
  font: 600 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}
.chart .row { display: grid; grid-template-columns: 150px 1fr auto; gap: 10px; align-items: center; }
.chart .cl { font-size: 13.5px; text-align: right; color: var(--ink-2); }
.chart .cb { height: 20px; background: var(--room); border-radius: 4px; overflow: hidden; }
.chart .cb i {
  display: block; height: 100%; border-radius: 4px;
  background: linear-gradient(90deg, var(--bronze), var(--accent));
}
.chart .cb i.bad { background: linear-gradient(90deg, var(--bad), var(--bad)); }
.chart .cv {
  font: 600 13px/1 var(--mono); font-variant-numeric: tabular-nums;
  min-width: 74px; text-align: right;
}
.chart .cn { font: 500 11px/1 var(--mono); color: var(--ink-3); }

.finding-card {
  border: 1px solid var(--rule); border-radius: 9px; padding: 14px 16px;
  display: flex; flex-direction: column; gap: 11px; background: var(--sunken);
}
.finding-card > header { display: flex; align-items: baseline; gap: 10px; }
.finding-card h3 { margin: 0; font: 600 15.5px/1.3 var(--sans); flex: 1; }
.finding-card .cost { font: 600 11px/1 var(--mono); color: var(--teal); }
.finding-card p { margin: 0; font-size: 14px; color: var(--ink-2); }

.empty {
  border: 1px dashed var(--rule); border-radius: 9px; padding: 26px 20px;
  text-align: center; color: var(--ink-3); font-size: 14px;
}

/* ── orientation ─────────────────────────────────────────────────────── */

/* ── the briefing: two columns, not two rows ─────────────────────────────
 *
 * The induction and the welcome screen used to stack a scene band above a content panel.
 * Every complaint about this page came from that one decision: a beat with a chart under
 * it had to scroll, a beat with nothing under it left a white void, and the reading column
 * was capped and centred so it used about sixty per cent of the width with bare plaster
 * either side. Stretching the panel to fill only turned the void into a big empty box.
 *
 * Rows were the wrong axis. A briefing is a person on one side and their evidence on the
 * other, and as two columns each side sizes to its own content — neither has to stretch to
 * cover for the other. The page fits the viewport at any beat, and only the evidence
 * scrolls, only when it genuinely overflows.
 *
 * It also rehearses the layout of the workspace they are about to use, where the question
 * sits left and the analyses sit right. By the time the clock starts, the shape is
 * familiar.
 */
.brief {
  height: 100%; display: grid; min-height: 0;
  grid-template-columns: minmax(330px, 37%) minmax(0, 1fr);
}

/* Left: the room. Warm, person-led, the voice. */
.brief-voice {
  position: relative; overflow: hidden; min-height: 0;
  display: flex; flex-direction: column;
  padding: 26px 30px 22px;
  background: linear-gradient(170deg, var(--room) 0%, var(--room-2) 100%);
  border-right: 1px solid var(--rule);
}
.brief-voice .kicker { margin-bottom: 18px; }

/*
 * The line is typeset, not put in a speech bubble.
 *
 * A cartoon bubble was fighting the register of everything around it. Set large in the
 * book face it reads as someone talking to you, and it lets the words be the biggest thing
 * on the left — which they should be, because they carry the meaning while the panel
 * opposite carries the numbers.
 */
.brief-voice .line {
  flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: thin;
  font: 400 clamp(17px, 1.15vw + 0.9vh, 23px)/1.5 var(--serif);
  color: var(--ink); letter-spacing: -.005em; text-wrap: pretty;
}
.brief-voice .speaker { display: flex; align-items: flex-end; gap: 14px; margin-top: 16px; }
.brief-voice .speaker .fig { flex: none; width: 92px; }
.brief-voice .speaker .fig svg { display: block; width: 100%; height: auto; }
.brief-voice .speaker .id { padding-bottom: 8px; }
.brief-voice .speaker .name { font: 600 15px/1.25 var(--sans); }
.brief-voice .speaker .role {
  font: 500 10.5px/1.3 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-top: 2px;
}

/* Right: the evidence. Paper, cooler, holds the numbers. */
.brief-evidence {
  min-height: 0; overflow-y: auto; scrollbar-width: thin;
  padding: 30px 34px; display: flex; flex-direction: column; justify-content: center;
  background: var(--paper);
}
.brief-evidence > * { width: 100%; max-width: 780px; margin: 0 auto; }

/* Progress and navigation, pinned under the voice. */
.brief-nav { margin-top: 18px; display: flex; flex-direction: column; gap: 12px; }
.steps { display: flex; gap: 4px; }
.steps i { flex: 1; height: 3px; border-radius: 2px; background: rgba(30,34,41,.13); }
.steps i.on { background: var(--accent); }
.steps i.here { background: var(--accent-2); }
.brief-nav .row { display: flex; gap: 9px; align-items: center; }
.brief-nav .row .spacer { flex: 1; }
.brief-nav .back {
  cursor: pointer; border: 1px solid var(--rule); background: rgba(255,255,255,.6);
  border-radius: 7px; width: 40px; height: 40px; flex: none;
  font: 600 16px/1 var(--sans); color: var(--ink-2);
}
.brief-nav .back:hover:not(:disabled) { background: #fff; color: var(--ink); }
.brief-nav .back:disabled { opacity: .32; cursor: default; }

/* ── asking a colleague, and walking away ────────────────────────────────
 *
 * Both sit under the commit button, and both are deliberately quieter than it. They are
 * offers, not steps: a candidate who uses neither has skipped nothing, and the moment either
 * reads as the expected path the assessment has started guiding rather than measuring.
 * --------------------------------------------------------------------- */

.colleague {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--rule);
  display: flex; flex-direction: column; gap: 8px; align-items: flex-start;
}
.colleague.used { border-top-color: var(--warn); }

/* What was said, kept on screen — nobody should have to remember a hint they paid for. */
.said {
  background: var(--warn-bg); border-left: 3px solid var(--warn);
  border-radius: 0 6px 6px 0; padding: 8px 11px; width: 100%; box-sizing: border-box;
}
.said b { display: block; font: 600 12.5px/1.4 var(--sans); color: var(--ink); }
.said p { margin: 3px 0 0; font: 400 13px/1.55 var(--sans); color: var(--ink-2); }

/* ── what a colleague said ───────────────────────────────────────────────
 *
 * A panel over the page, because inline failed in a real sitting: below the fold on the tab
 * it appeared on, and absent from the tab where it was needed. See web/game.js.
 * --------------------------------------------------------------------- */

/* The one line beside the commit button saying the notes exist and how to get back to them. */
.colleague-recall {
  margin-top: 12px; width: 100%; box-sizing: border-box;
  display: flex; align-items: center; gap: 10px; text-align: left; cursor: pointer;
  padding: 9px 12px; border-radius: 8px; font: inherit;
  border: 1px solid var(--warn); background: var(--warn-bg);
}
.colleague-recall:hover { box-shadow: var(--shadow); }
.cr-n {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--warn); color: #fff; font: 700 11px/1 var(--sans);
}
.cr-t { font: 400 12.5px/1.4 var(--sans); color: var(--ink-2); }
.cr-t b { display: block; font: 600 12.5px/1.4 var(--sans); color: var(--warn); }

/*
 * Above the onboarding tour, which is at 200.
 *
 * The tour is a stack of cards pointing at parts of the console, and it was drawing straight
 * over the panel — so a candidate on their first question, which is exactly when both are on
 * screen, read a hint through a tour card. Whichever the candidate opened last is the one
 * they are looking at, and only one of these is something they paid for.
 */
.cm { position: fixed; inset: 0; z-index: 240; display: grid; place-items: center; }
.cm-back { position: absolute; inset: 0; background: rgba(15, 23, 42, .55); }
.cm-card {
  position: relative; z-index: 1;
  width: min(620px, calc(100vw - 32px)); max-height: calc(100vh - 48px);
  display: flex; flex-direction: column;
  background: var(--card); border-radius: 14px; box-shadow: 0 24px 60px rgba(15, 23, 42, .3);
}
/*
 * Headed with a person, because the premise is that this is one.
 *
 * Initials on their own accent colour, the way the cast appears everywhere else in the
 * product, so the panel reads as a colleague answering rather than as the product handing
 * over a card from a deck.
 */
.cm-top {
  display: flex; align-items: center; gap: 12px;
  padding: 15px 18px; border-bottom: 1px solid var(--rule-2);
}
.cm-face {
  flex: none; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--who); color: #fff; font: 700 13px/1 var(--sans); letter-spacing: .02em;
}
.cm-top > div { flex: 1; min-width: 0; }
.cm-top h2 { margin: 0; font: 600 17px/1.25 var(--sans); color: var(--ink); }
.cm-role { font: 400 12.5px/1.35 var(--sans); color: var(--ink-3); }

/*
 * The charge, at the top, before anything else is read.
 *
 * It was under the offer and below two notes, so somebody scrolling to the button met it
 * after they had already decided. A charge is only stated before it is paid if it is the
 * first thing on the screen.
 */
.cm-warn {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 18px; background: var(--warn-bg);
  border-bottom: 1px solid var(--warn);
}
.cm-warn-m {
  flex: none; width: 19px; height: 19px; border-radius: 50%; margin-top: 1px;
  display: grid; place-items: center;
  background: var(--warn); color: #fff; font: 800 12px/1 var(--sans);
}
.cm-warn p { margin: 0; font: 400 13px/1.55 var(--sans); color: var(--ink-2); max-width: 62ch; }
.cm-warn b { color: var(--ink); }

/* What she actually said, set apart from the label above it as speech. */
.cm-speech {
  margin-top: 6px; padding-left: 11px; border-left: 2px solid var(--teal);
}
.cm-speech p {
  margin: 0 0 8px; font: 400 14px/1.6 var(--sans); color: var(--ink); max-width: 60ch;
}
.cm-speech p:last-child { margin-bottom: 0; }
.cm-open { color: var(--ink-2); }
.cm-close-l { color: var(--ink-2); font-style: italic; }
.cm-how b { color: var(--teal); }
.cm-x {
  flex: none; border: 0; background: transparent; cursor: pointer;
  font-size: 15px; color: var(--ink-3); padding: 4px 6px; border-radius: 6px;
}
.cm-x:hover { background: var(--rule-2); color: var(--ink); }
/* The panel scrolls inside itself: three notes and an offer outgrow a laptop. */
.cm-body { overflow-y: auto; padding: 16px 18px 18px; }

.cm-notes { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
.cm-note { display: flex; gap: 11px; align-items: flex-start; }
.cm-note-n {
  flex: none; width: 21px; height: 21px; border-radius: 50%; margin-top: 1px;
  display: grid; place-items: center;
  background: var(--warn); color: #fff; font: 700 11px/1 var(--sans);
}
.cm-note-b { min-width: 0; }
/* The label is what they asked; the speech below it is the answer. Different weights. */
.cm-note-b > b {
  display: block; font: 600 11px/1.35 var(--mono); letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
}

/*
 * Where to look, set as a list of names rather than folded into the sentence.
 *
 * The point of the first rung is orientation, and a candidate extracting eight dotted column
 * names out of a paragraph is doing the same work the question already made them do.
 */
.cm-where {
  margin-top: 9px; padding: 10px 12px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--rule-2);
}
.cm-where-h {
  display: block; font: 600 10px/1 var(--mono); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 5px;
}
.cm-where p { margin: 0 0 9px; display: flex; flex-wrap: wrap; gap: 5px; }
.cm-where p:last-child { margin-bottom: 0; }
.cm-where code {
  font: 500 12px/1.5 var(--mono); padding: 1px 6px; border-radius: 4px;
  background: var(--card); border: 1px solid var(--rule-2); color: var(--ink);
}
/*
 * Tables lead, columns follow.
 *
 * The tables are the two or three things they have to open, so those are in the accent
 * colour and carry weight. The columns are a longer list to be scanned and copied from, and
 * setting those with the same emphasis turns eight equally-loud chips into a wall.
 */
.cm-tables code { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.cm-cols code { color: var(--ink-2); }
.cm-join { font: 400 13px/1.55 var(--sans); color: var(--ink-2); max-width: 58ch; }

.cm-offer {
  border-top: 1px solid var(--rule-2); padding-top: 15px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
}
.cm-notes + .cm-offer { margin-top: 2px; }
.cm-more {
  font: 600 10px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 6px;
}
.cm-q { font: 600 16px/1.3 var(--sans); color: var(--ink); }
.cm-sub { font: 400 13.5px/1.5 var(--sans); color: var(--ink-2); }

/*
 * The price, and it is deliberately the loudest thing in the panel.
 *
 * Two bars rather than a sentence: somebody deciding whether they are stuck enough to ask is
 * comparing two numbers, and a comparison is a picture.
 */
/*
 * What it costs, as two bars.
 *
 * The sentence at the top of the panel says there is a charge. This says how big it is, and
 * it is quieter than it was: with the warning moved above the fold, a second amber panel
 * down here was the same alarm sounded twice.
 */
.cm-cost {
  margin: 12px 0; width: 100%; box-sizing: border-box;
  padding: 11px 13px; border-radius: 9px;
  background: var(--bg); border: 1px solid var(--rule-2);
}
.cm-bars { display: flex; flex-direction: column; gap: 6px; }
.cm-bar {
  position: relative; display: grid;
  grid-template-columns: 1fr 92px 42px; align-items: center; gap: 9px;
  height: 20px;
}
.cm-bar i {
  display: block; height: 9px; border-radius: 5px; background: var(--rule);
  grid-column: 1; justify-self: start; min-width: 3px;
}
.cm-bar em {
  grid-column: 2; font: 400 11.5px/1 var(--sans); color: var(--ink-3); font-style: normal;
}
.cm-bar b {
  grid-column: 3; text-align: right;
  font: 700 13px/1 var(--mono); color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.cm-bar.now i { background: var(--teal); }
.cm-bar.now b { color: var(--teal); }
.cm-bar.after i { background: var(--warn); }
.cm-bar.after b { color: var(--warn); }
.cm-act { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; }
/* Two limits, stacked, with the one about this question first and in the darker ink. */
.cm-left { display: flex; flex-direction: column; gap: 1px; }
.cm-left b { font: 600 12.5px/1.4 var(--sans); color: var(--ink-2); font-weight: 600; }
.cm-left i { font: 400 11.5px/1.4 var(--sans); color: var(--ink-3); font-style: normal; }
.cm-none {
  margin: 10px 0 0; font: 400 13.5px/1.6 var(--sans); color: var(--ink-2); max-width: 60ch;
}

@media (max-width: 620px) {
  .cm-bar { grid-template-columns: 1fr 46px; }
  .cm-bar em { display: none; }
  .cm-bar b { grid-column: 2; }
}

.walkaway {
  margin-top: 10px; display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
}

/*
 * The quietest control on the screen, and still a real button.
 *
 * Underlined text rather than a bordered box, because it is the one thing here that cannot be
 * undone and should not be a thing anybody presses by accident on the way to something else.
 */
.quiet {
  cursor: pointer; background: none; border: 0; padding: 0;
  font: 500 13px/1.4 var(--sans); color: var(--ink-3);
  text-decoration: underline; text-underline-offset: 3px;
}
.quiet:hover { color: var(--ink-2); }
.quiet:disabled { opacity: .4; cursor: default; }

/*
 * "For this question" — the tables the ask is answered from, above the full list.
 *
 * The strongest thing in the rail, on purpose. It is read once at the start of a question and
 * then ignored, and the whole reason it exists is that a candidate was spending ten of forty
 * minutes finding out what it says.
 *
 * The tables it names are also flagged in the list below it, because the two have to be
 * recognisable as the same three things — a block naming `budget` and a list where `budget`
 * looks like everything else makes the reader match them by eye.
 */
.needed-block {
  border: 1px solid var(--accent); border-radius: 8px;
  background: rgba(255,255,255,.7);
  padding: 10px 12px; margin-bottom: 14px;
}
.needed-tables { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0 8px; }
.needed-t {
  cursor: pointer; font: 600 12.5px/1 var(--mono);
  color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule); border-radius: 5px; padding: 5px 8px;
}
.needed-t:hover { border-color: var(--accent); background: #fff; }
.needed-join {
  margin: 0 0 7px; font-size: 12.5px; line-height: 1.6; color: var(--ink-2);
}
.needed-join code { font: 500 12px/1.4 var(--mono); }
.needed-note { margin: 0; font-size: 12px; line-height: 1.5; color: var(--ink-3); }

/* And the same tables, marked where they sit in the full list. */
.tbl.needed > .tbl-head .n { color: var(--accent); }

/*
 * The two optional doors: a practice run and the data guide.
 *
 * Deliberately quieter than Start — they are offers, not steps. A candidate who ignores both
 * has not skipped anything, and the moment these read as prerequisites the welcome screen
 * grows from one decision into three.
 *
 * Side by side on a laptop, stacked below it, because at that width two cards this size put
 * three words on each line.
 */
/*
 * Advised, and above the button rather than under it.
 *
 * These were two quiet cards below Start and read as ignorable, so the candidate who most
 * needed them skipped them. Numbered, boxed and introduced by a line saying they cost no
 * time — which is the fact that decides it, because the objection to doing them is always
 * that the clock is running, and it is not.
 */
.brief-first {
  border: 1px solid var(--accent); border-radius: 10px;
  background: var(--accent-bg);
  padding: 13px 14px; margin-bottom: 4px;
}
.brief-first-h {
  margin: 0 0 9px;
  font: 600 13px/1.35 var(--sans); color: var(--accent-2);
}
.brief-extras {
  display: grid; gap: 9px;
  grid-template-columns: 1fr 1fr;
}
.extra {
  position: relative;
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 13px 11px 34px; text-decoration: none;
  border: 1px solid var(--rule-2); border-radius: 8px;
  background: var(--card);
}
.extra:hover { border-color: var(--accent); box-shadow: var(--shadow); }
.extra-n {
  position: absolute; left: 11px; top: 11px;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent); color: #fff;
  font: 600 10.5px/1 var(--sans);
}
.extra-h { font: 600 13.5px/1.3 var(--sans); color: var(--ink); }
.extra-p { font: 400 12.5px/1.45 var(--sans); color: var(--ink-2); }

@media (max-width: 720px) {
  .brief-extras { grid-template-columns: 1fr; }
}

/*
 * Proving the link reached the right person.
 *
 * The sign-in step stands exactly where the Start button stands, at the same size and in the
 * same colour, because it *is* the next action rather than a warning about one — a candidate
 * who has to hunt for it after reading the briefing has been given a puzzle on the wrong day.
 *
 * The card around it is deliberately plainer than .brief-first: that block is an invitation
 * and this one is a requirement, and dressing a requirement up in the same accent panel as an
 * optional extra makes both of them read as neither.
 */
.idbox {
  border: 1px solid var(--rule); border-radius: 10px;
  background: var(--card); padding: 14px 15px;
}
.idbox-h { margin: 0 0 6px; font: 600 14.5px/1.35 var(--sans); color: var(--ink); }
.idbox-p {
  margin: 0 0 13px; max-width: 56ch;
  font: 400 13.5px/1.55 var(--sans); color: var(--ink-2);
}
.idbox-p b { color: var(--ink); font-family: var(--mono); font-size: 13px; }
/*
 * One button per provider, wrapping rather than shrinking.
 *
 * The first is the primary and the rest are quiet, because on nearly every invitation one of
 * them is obviously the right one and a row of equal-weight choices makes somebody stop and
 * decide about something that does not matter.
 */
.idways { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; }

/*
  The code route, under the provider buttons.

  ── Why it is quieter than the buttons above it ────────────────────────

  For most candidates a provider is one click and cannot land in spam, so leading with an
  equal-weight third option would make somebody stop and choose about something that does
  not matter to them. For a candidate on their employer's own mail server it is the only
  route there is, which is why it is on the page rather than behind "having trouble?".
*/
.idcode { margin-top: 12px; }

/*
  A button that reads as a link.

  It has to be a <button>: it does not navigate, and an <a href="#"> that runs JavaScript is
  the standard way to build a control a keyboard user cannot understand and a screen reader
  announces wrongly.
*/
.linkish {
  background: none; border: 0; padding: 0;
  font: inherit; font-size: 13.5px;
  color: var(--accent); text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}
.linkish:hover { color: var(--accent-2); }
.linkish:disabled { color: var(--ink-3); cursor: default; text-decoration: none; }

.idcode-sent { margin: 0 0 10px; font-size: 13.5px; color: var(--ink-2); }
.idcode-sent b { color: var(--ink); font-family: var(--mono); font-size: 13px; }

.idcode-row { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; }

/*
  Wide-tracked monospace, because the whole job of this field is transcription.

  Six digits copied off a phone are misread in predictable ways, and letter-spacing plus a
  fixed-width face is what makes a doubled digit visible before the button is pressed rather
  than after.
*/
.idcode-in {
  width: 8.5rem; padding: 9px 12px;
  font: 600 17px/1 var(--mono); letter-spacing: .22em;
  color: var(--ink); background: var(--card);
  border: 1px solid var(--rule-2); border-radius: 8px;
}
.idcode-in:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.idcode-err {
  margin: 9px 0 0; font-size: 13.5px; color: var(--bad);
}

/*
 * What happened on the way back from the provider.
 *
 * Three tones and no icons. A mismatch is the one people meet, it is nearly always the wrong
 * Google account rather than the wrong person, and a red panel with a warning triangle on it
 * accuses somebody of cheating on the morning of their assessment.
 */
.idnote {
  display: flex; flex-direction: column; gap: 3px;
  border-radius: 8px; padding: 11px 13px; margin-bottom: 4px;
  border: 1px solid var(--rule-2); background: var(--card);
}
.idnote b { font: 600 13.5px/1.35 var(--sans); color: var(--ink); }
.idnote span { font: 400 13px/1.5 var(--sans); color: var(--ink-2); }
.idnote.yes { border-color: var(--teal); background: var(--teal-bg); }
.idnote.no { border-color: var(--warn); background: var(--warn-bg); }

/*
 * Where a beat has no chart, the panel lists what the briefing covers and marks where you
 * are. It replaces an empty column with something worth reading, and it gives the Back
 * button a visible purpose — you can see the point you would be returning to.
 */
.contents { display: flex; flex-direction: column; gap: 2px; }
.contents h4 {
  margin: 0 0 10px; font: 600 11px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3);
}
.contents li {
  list-style: none; display: flex; align-items: center; gap: 11px;
  padding: 7px 10px; border-radius: 6px;
  font: 400 14.5px/1.4 var(--sans); color: var(--ink-3);
}
.contents li .tick { width: 15px; flex: none; text-align: center; font-size: 12px; }
.contents li.done { color: var(--ink-2); }
.contents li.done .tick { color: var(--teal); }
.contents li.here {
  background: var(--accent-bg); color: var(--accent-2); font-weight: 600;
}

/* The welcome page borrows the same frame, with the headline doing the talking. */
.welcome-h {
  display: block; margin-bottom: 14px;
  font: 600 clamp(26px, 2.2vw + 1.3vh, 40px)/1.12 var(--serif);
  letter-spacing: -.025em; text-wrap: balance; color: var(--ink);
}
.brief-voice .line p { margin: 0; font-size: clamp(15px, .7vw + .7vh, 18px); color: var(--ink-2); }

/*
 * Four steps, numbered because this genuinely is a sequence — it is the loop the candidate
 * repeats twelve times. Numbering anything that is not a sequence is decoration.
 */
.how { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 14px; }
.how li { display: flex; gap: 15px; align-items: flex-start; }
.how .n {
  flex: none; width: 27px; height: 27px; border-radius: 50%;
  background: var(--accent); color: #fff;
  font: 600 13px/27px var(--sans); text-align: center;
}
.how .t { display: flex; flex-direction: column; gap: 3px; font: 400 14px/1.5 var(--sans); color: var(--ink-2); }
.how .t b { font: 600 16px/1.3 var(--sans); color: var(--ink); }

.facts-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1px;
  margin-top: 22px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: 9px; overflow: hidden;
}
.facts-strip > div {
  background: var(--card); padding: 13px 15px;
  display: flex; flex-direction: column; gap: 2px;
  font: 600 16px/1.25 var(--sans); color: var(--ink);
}
.facts-strip b {
  font: 600 10px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 3px;
}
.facts-strip span { font: 400 12.5px/1.35 var(--sans); color: var(--ink-3); }

@media (max-width: 860px) {
  .brief { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .brief-voice { border-right: 0; border-bottom: 1px solid var(--rule); padding: 16px 18px; }
  .brief-voice .line { font-size: 16.5px; }
  .brief-voice .speaker .fig { width: 62px; }
  .brief-evidence { padding: 18px; }
}

/* ── end of a week ───────────────────────────────────────────────────────
 *
 * This was one sentence and a button inside a panel stretched across the full width, which
 * read as an empty box with something small in the corner. The week you just spent is the
 * obvious thing to put there: hours used, what you ran, what you decided. It fills the
 * space with the only content that belongs, and it doubles as the moment to notice you
 * committed to something without running anything.
 */
.wrapup { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; }
.wrapup .card {
  background: var(--card); border: 1px solid var(--rule); border-radius: 9px;
  padding: 14px 16px; display: flex; flex-direction: column; gap: 9px;
}
.wrapup .card > h4 {
  margin: 0; font: 600 10.5px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3);
}
.wrapup .big { font: 600 30px/1 var(--sans); font-variant-numeric: tabular-nums; }
.wrapup .big small { font: 500 13px/1 var(--sans); color: var(--ink-3); margin-left: 4px; }
.wrapup .item {
  font: 400 13.5px/1.45 var(--sans); color: var(--ink-2);
  padding-left: 15px; position: relative;
}
.wrapup .item::before {
  content: "·"; position: absolute; left: 3px; color: var(--accent); font-weight: 700;
}
.wrapup .none { font: 400 13.5px/1.45 var(--sans); color: var(--ink-3); font-style: italic; }
.steps { display: flex; gap: 5px; }
.steps i { flex: 1; height: 4px; border-radius: 2px; background: var(--rule); }
.steps i.on { background: var(--accent); }
.orient .foot { display: flex; gap: 10px; align-items: center; }
.orient .foot .spacer { flex: 1; }

.demo {
  background: var(--card); border: 1px solid var(--rule); border-radius: 10px;
  padding: 16px 18px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 12px;
}
.demo h4 { margin: 0; font: 600 11px/1 var(--mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); }

/*
 * Supporting text inside a panel.
 *
 * Set larger and looser than the old `.note` it replaces. These lines carry the parts of
 * the briefing that Ruth deliberately does not say out loud, so they are being read
 * properly rather than skimmed — and often by someone reading English as a second
 * language. 15px with generous leading is the difference between reading it once and
 * reading it twice.
 */
.demo .lead {
  margin: 0; font: 400 15px/1.62 var(--sans); color: var(--ink-2); max-width: 76ch;
}
.demo .lead b { color: var(--ink); font-weight: 600; }
.stat span.sm { font-size: 15px; }

/* Numbered procedure — used where order genuinely matters, not for decoration. */
.steps-list {
  margin: 0; padding-left: 0; list-style: none;
  counter-reset: s; display: flex; flex-direction: column; gap: 7px;
}
.steps-list li {
  counter-increment: s; position: relative; padding-left: 30px;
  font: 400 14.5px/1.5 var(--sans); color: var(--ink-2);
}
.steps-list li::before {
  content: counter(s); position: absolute; left: 0; top: 1px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent-bg); color: var(--accent-2);
  font: 600 11px/20px var(--sans); text-align: center;
}

.bignum { font: 600 40px/1 var(--sans); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.bignum small { font: 500 15px/1 var(--sans); color: var(--ink-3); letter-spacing: 0; }

.cal { display: flex; gap: 6px; flex-wrap: wrap; }
.cal .mo {
  flex: 1 1 60px; border: 1px solid var(--rule); border-radius: 6px; padding: 7px 5px;
  text-align: center; font: 600 11px/1.3 var(--mono); color: var(--ink-3);
}
.cal .mo.q { border-color: var(--indigo, var(--accent)); background: var(--accent-bg); color: var(--accent); }
.cal .wk { display: flex; gap: 2px; justify-content: center; margin-top: 5px; }
.cal .wk i { width: 6px; height: 6px; border-radius: 1px; background: var(--rule); }
.cal .mo.q .wk i { background: var(--accent); }

.lineup { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.lineup figure { margin: 0; text-align: center; width: 82px; }
.lineup figcaption { font: 600 10.5px/1.3 var(--sans); }
.lineup span { display: block; font: 500 9.5px/1.25 var(--mono); color: var(--ink-3); }

.scale { display: flex; height: 30px; border-radius: 6px; overflow: hidden; font: 600 11px/30px var(--mono); text-align: center; color: #fff; }
.scale i { display: block; }

/*
 * A query, shown in the briefing.
 *
 * Set the way the editor sets it, so the first thing a candidate sees of SQL in this
 * product looks like the thing they are about to type into.
 */
.sql-demo {
  margin: 0 0 14px; padding: 12px 14px; overflow-x: auto;
  background: var(--sunken); border: 1px solid var(--rule); border-radius: 7px;
  font: 400 13px/1.6 var(--mono); color: var(--ink); white-space: pre;
}

/* The four technique checks, shared with the recruiter's report. */
.checks { display: flex; flex-direction: column; gap: 11px; margin-top: 4px; }
.check { display: flex; gap: 10px; align-items: flex-start; }
.check .mark {
  flex: none; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center; font: 600 12px/1 var(--sans);
  background: var(--bad-bg); color: var(--bad);
}
.check.on .mark { background: var(--teal-bg); color: var(--teal); }
.check .t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.check .t b { font: 600 14.5px/1.35 var(--sans); }
.check .t .a { font: 400 13px/1.55 var(--sans); color: var(--ink-3); }

/* ── the five-minute demo ────────────────────────────────────────────────
 *
 * Two screens, both borrowing the centred column the title and result scenes already use.
 * Only what is genuinely new gets rules: the seat picker on the way in, and the reveal's
 * one paragraph on the way out.
 */
.demo-welcome .note { max-width: 64ch; }
/*
 * What the demo has switched off, admitted before it is noticed.
 *
 * Set into the page rather than announced, because it is a caveat and a caveat styled like
 * a feature reads as one nobody believes. The button beside it is the actual answer: the
 * real overlay, played once, armed at nothing.
 */
.demo-integrity {
  margin-top: 22px; padding: 16px 18px;
  max-width: 64ch;
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--rule-2);
  border-radius: 0 10px 10px 0;
}
.demo-integrity p { margin: 0 0 12px; font-size: 14px; line-height: 1.6; color: var(--ink-2); }
.demo-integrity p:last-child { margin-bottom: 0; }
.demo-integrity b { color: var(--ink); font-weight: 600; }

.demo-pick { margin-top: 30px; }
.demo-pick .eyebrow { display: block; margin-bottom: 10px; }
.demo-pick .picks { display: flex; gap: 10px; flex-wrap: wrap; }
/*
 * `.mid.title .pick { flex: 1 }` already exists for the length picker on the welcome
 * screen and would squeeze these to nothing on a narrow window, so the basis is stated
 * here and this rule has to be at least as specific to win.
 */
.demo-pick .picks .pick {
  flex: 1 1 190px; min-width: 0;
  display: flex; flex-direction: column; gap: 3px;
  border: 1px solid var(--rule); border-radius: 8px; padding: 11px 13px;
  background: var(--card); color: var(--ink);
}
/* An anchor inherits the global link underline; the card is the affordance, not the text. */
.demo-pick .picks .pick,
.demo-pick .picks .pick b,
.demo-pick .picks .pick span { text-decoration: none; color: inherit; }
.demo-pick .picks .pick:hover { border-color: var(--accent); }
.demo-pick .picks .pick.on { border-color: var(--accent); background: var(--accent-bg); }
.demo-pick .picks .pick b { font: 600 14px/1.3 var(--sans); color: var(--ink); }
.demo-pick .picks .pick span { font: 400 12.5px/1.45 var(--sans); color: var(--ink-3); }

.demo-reveal { gap: 20px; }
.demo-reveal .reveal { display: flex; flex-direction: column; gap: 18px; }
/* The sentence the whole demo exists to deliver. Set larger than body copy on purpose. */
.reveal-body {
  margin: 0 0 10px; max-width: 64ch;
  font: 400 16.5px/1.65 var(--serif); color: var(--ink);
}
.demo-end { background: var(--accent-bg); border-color: var(--accent); }
.demo-end .note { max-width: 66ch; }
/* Anchors styled as buttons need the padding a <button> gets from .commit / .ghost. */
a.commit, a.ghost { display: inline-flex; align-items: center; text-decoration: none; }

/* ── Python ──────────────────────────────────────────────────────────────
 *
 * The console is the same three columns whichever language it is in — same schema panel,
 * same result grid, same charts, same save. What Python needs on top is an honest account
 * of a twenty-one megabyte download, somewhere for print() to land, and a way out of a
 * cell that has stopped coming back.
 */

/* Which language this question is in, said once, under the heading. */
.lang-note {
  margin: 4px 0 0; padding: 6px 9px; border-radius: 6px;
  background: var(--accent-bg); color: var(--accent-2);
  font: 400 12px/1.5 var(--sans); max-width: 68ch;
}
.lang-note b { font-weight: 600; }

/*
 * The boot.
 *
 * It occupies the editor's place so the column does not jump when Python arrives, and it
 * says what it is doing at each stage — because four seconds of an unexplained pause is
 * indistinguishable from a broken page, and a candidate who reloads has lost far more
 * than four seconds.
 */
.py-boot {
  border: 1px solid var(--rule-2); border-radius: 9px; background: var(--card);
  padding: 18px 20px; display: flex; flex-direction: column; gap: 9px;
  min-height: 200px; justify-content: center;
}
.py-boot b { font: 600 15px/1.3 var(--sans); }
.py-track {
  height: 6px; border-radius: 3px; background: var(--room); overflow: hidden;
}
.py-track i {
  display: block; height: 100%; width: 0; border-radius: 3px;
  background: var(--accent); transition: width .25s ease-out;
}
.py-stage { font: 400 12px/1 var(--mono); color: var(--ink-3); }
.py-boot p {
  margin: 2px 0 0; font: 400 12.5px/1.6 var(--sans); color: var(--ink-3); max-width: 60ch;
}

/* Anything printed, above the result. Never scored — it is somebody thinking aloud. */
.stdout {
  margin: 0; padding: 10px 13px; max-height: 140px; overflow: auto;
  background: var(--sunken); border: 1px solid var(--rule); border-radius: 7px;
  font: 400 12.5px/1.6 var(--mono); color: var(--ink-2);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* "Still running…", which appears beside the Stop button and only after five seconds. */
.editor-bar .stat.warn { color: var(--warn); font-weight: 600; }

/* ── the spreadsheet's field list and summary builder ────────────────────
 *
 * The sidebar is the same furniture as the SQL schema panel, because it is the same thing
 * seen differently: there, a catalogue to read before writing a query; here, a set of
 * fields to put into cells. Reusing the styling keeps it one console rather than two.
 * --------------------------------------------------------------------- */

.fields-note {
  margin: 0 0 12px; font: 400 12px/1.5 var(--sans); color: var(--ink-3);
}
.fields-note code {
  font: 400 11.5px/1 var(--mono); background: var(--sunken);
  padding: 1px 4px; border-radius: 3px;
}
.fields .peek {
  display: block; width: 100%; margin: 0 0 8px; padding: 6px 9px;
  border: 1px solid var(--rule-2); border-radius: 6px; background: var(--card);
  font: 500 11.5px/1.3 var(--sans); color: var(--ink-2); text-align: left; cursor: pointer;
}
.fields .peek:hover { border-color: var(--accent); color: var(--accent); }
.fields .col { cursor: pointer; }
.fields .col:hover { color: var(--accent); text-decoration: underline; }

/*
 * One row, above the grid, in the place the editor's toolbar occupies for SQL. It wraps
 * on a narrow window rather than scrolling sideways, because a control the reader has to
 * hunt for is a control they will not find.
 */
.summarise {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 11px; margin-bottom: 10px;
  border: 1px solid var(--rule-2); border-radius: 7px; background: var(--sunken);
}
.summarise .eyebrow { margin: 0 2px 0 0; }
.summarise .w { font: 400 12.5px/1 var(--sans); color: var(--ink-3); }
.summarise select {
  padding: 5px 7px; border: 1px solid var(--rule-2); border-radius: 5px;
  background: var(--card); color: var(--ink); font: 400 12.5px/1.2 var(--sans);
  max-width: 150px;
}
.summarise button { padding: 6px 11px; font-size: 12.5px; }
.summarise .hint-k { margin-left: auto; }

/* ── the transcript, on the candidate's own result screen ─────────────── */

/*
 * "Every query you ran" is rendered by game.js with the same markup as the recruiter's
 * report, and the styling for it lived only in report.css — which index.html does not load.
 * So the panel came out as a default browser <ol>: numbered, indented, monospace nowhere,
 * and no colour separating a kept result from one that errored.
 *
 * The half that was actively wrong rather than merely plain: a kept query is
 * `<li class="q kept">`, and `.kept` on this page is the evidence pane in the working
 * console — a scrolling flex column with `max-height: calc(100vh - 210px)`. Every kept row
 * in the transcript was being laid out as a full-height scroll container. The rules below
 * are two classes deep specifically so they win against that bare `.kept`, and they reset
 * the three properties it sets rather than only overriding the colour.
 *
 * Duplicated from report.css rather than shared, and that is the intended trade. The
 * candidate's screen and the console are deliberately different design languages — the only
 * file both load is tokens.css, which holds palette and type and would be the wrong home for
 * a component. Two small copies is a better cost than a shared component stylesheet that
 * exists to serve one list.
 */
.queries {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.queries .q {
  display: block; max-height: none; overflow: visible;
  border-left: 3px solid var(--rule-2); padding: 2px 0 2px 11px;
}
.queries .q.kept { border-left-color: var(--teal); background: none; }
.queries .q.failed { border-left-color: var(--rule); opacity: .62; }
.queries pre {
  margin: 0; overflow-x: auto; white-space: pre-wrap; overflow-wrap: anywhere;
  font: 400 12.5px/1.6 var(--mono); color: var(--ink);
}
.queries .a {
  display: block; margin-top: 2px;
  font: 400 11.5px/1.5 var(--mono); color: var(--ink-3);
}
.queries .q.failed .a { color: var(--bad); }

/* Used once, under the evidence picker, where .note is still a shade too loud. */
.note.tiny { font-size: 12.5px; line-height: 1.5; }

/*
 * The colleague button before it can be pressed.
 *
 * Visible from the first second and plainly not yet available, rather than absent. A control
 * that appears out of nowhere three minutes in is a control nobody was waiting for; one that
 * is greyed out with a reason underneath is an offer somebody can plan around.
 */
.colleague .ghost:disabled {
  opacity: .55; cursor: default; border-style: dashed;
}
.colleague .ghost:disabled:hover { background: transparent; border-color: var(--rule-2); }

/* ── the demo's header ───────────────────────────────────────────────────
 *
 * The demo had none: no mark, no name, and no route anywhere. Somebody arriving from the
 * landing page could only press the browser's back button, and somebody sent the link
 * directly had no way to find out what this product is — which is the worse case, since that
 * is exactly the person the demo exists to convince.
 *
 * Only on the welcome screen. Once it starts, the demo is the assessment, and a link out of a
 * running assessment is a link somebody presses by accident.
 * --------------------------------------------------------------------- */

.demo-top {
  display: flex; align-items: center; gap: 12px;
  max-width: 1180px; width: 100%; margin: 0 auto;
  padding: 16px 24px 0;
}
.demo-top .brand {
  display: flex; align-items: center; gap: 9px; text-decoration: none; color: var(--ink);
}
.demo-top .mark {
  width: 26px; height: 26px; border-radius: 6px; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: #fff;
}
.demo-top .wordmark { font: 600 16px/1 var(--serif); }
.demo-back {
  margin-left: auto;
  font: 500 13px/1 var(--sans); color: var(--ink-3); text-decoration: none;
}
.demo-back:hover { color: var(--accent); }

/* ── the two ways out, in the status bar ─────────────────────────────────
 *
 * "Ask a colleague" and "Move on" were buttons at the foot of the question panel. That put
 * them below the fold on a laptop, and it removed them entirely the moment somebody switched
 * to the Analysis tab — which is where a person goes when they are stuck, and therefore
 * exactly when they need to see that a way out exists.
 *
 * Here they are on screen whatever is showing. Styled as quiet controls rather than as
 * calls to action: this is an offer, and a button that looks eager reads as the product
 * expecting somebody to fail.
 * --------------------------------------------------------------------- */

.ways { display: flex; gap: 8px; align-items: stretch; margin-left: 14px; }
.way {
  display: flex; flex-direction: column; gap: 1px; text-align: left;
  padding: 5px 11px; border-radius: 7px; cursor: pointer;
  background: transparent; border: 1px solid var(--rule-2); color: var(--ink-2);
  font: inherit;
}
.way:hover:not([disabled]) { border-color: var(--accent); color: var(--accent); }
.way[disabled] { opacity: .45; cursor: default; }
/*
 * Marked once a colleague has answered something on this question.
 *
 * The button is the only way back to a note that was paid for, so it has to look like it
 * holds something rather than like an offer that has already been used up.
 */
.way.has { border-color: var(--warn); background: var(--warn-bg); color: var(--warn); }
.way.has .way-n { color: var(--warn); }

/*
 * Marked when somebody has been on one question for half the time it is worth.
 *
 * Being on screen from the first second was the fix for the previous failure, where the offer
 * appeared only after a hidden timer and nobody ever found it. It was not sufficient: a small
 * control in a status bar, read for the first time under a clock, is furniture.
 *
 * So it says something — once, late, and quietly. Three short pulses and then a permanent but
 * unobtrusive accent, because a control that pulses forever is a control people learn to
 * ignore and then resent.
 */
.way.nudge { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); }
.way.nudge .way-n { color: var(--accent); }
@media (prefers-reduced-motion: no-preference) {
  .way.nudge { animation: nudge 1.1s ease-out 3; }
  @keyframes nudge {
    0%, 100% { box-shadow: 0 0 0 0 rgba(43, 91, 168, 0); }
    35% { box-shadow: 0 0 0 5px rgba(43, 91, 168, .22); }
  }
}

/*
 * And the line of text, for somebody who has run nothing at all.
 *
 * Bottom right rather than over the work: this is an offer, and an offer that blocks the
 * screen has stopped being one. It never appears twice on the same question, and it is not
 * shown at all to somebody who has already saved a result — they are working, not stuck, and
 * telling them otherwise mid-analysis is the product implying they are failing.
 */
.stuck {
  position: fixed; right: 18px; bottom: 18px; z-index: 70;
  width: min(330px, calc(100vw - 36px));
  padding: 14px 15px; border-radius: 11px;
  background: var(--card); border: 1px solid var(--accent);
  box-shadow: 0 14px 40px rgba(15, 23, 42, .18);
}
.stuck b { display: block; font: 600 14.5px/1.3 var(--sans); color: var(--ink); }
.stuck p {
  margin: 5px 0 11px; font: 400 13px/1.55 var(--sans); color: var(--ink-2);
}
.stuck-do { display: flex; align-items: center; gap: 10px; }
.stuck .commit { padding: 8px 13px; font-size: 13.5px; }
.stuck-x {
  border: 0; background: transparent; cursor: pointer; padding: 6px 2px;
  font: 500 13px/1 var(--sans); color: var(--ink-3);
}
.stuck-x:hover { color: var(--ink); text-decoration: underline; }
@media (prefers-reduced-motion: no-preference) {
  .stuck { animation: stuck-in .22s ease-out; }
  @keyframes stuck-in {
    from { transform: translateY(8px); opacity: 0; }
    to { transform: none; opacity: 1; }
  }
}
.way-h { font: 600 12px/1.2 var(--sans); }
.way-n {
  font: 400 10.5px/1.2 var(--sans); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.way:hover:not([disabled]) .way-n { color: var(--accent); }

@media (max-width: 900px) {
  /* The count is the part that must survive; the second line is the first thing to go. */
  .way-n { display: none; }
}

/* ── away from the page ──────────────────────────────────────────────────
 *
 * ── What blanking the screen actually buys ─────────────────────────────
 *
 * This is the only screenshot mitigation a web page can honestly offer, and it is worth
 * being exact about its limits rather than letting anyone assume more.
 *
 * It does **not** stop a screenshot of the focused tab. The print-screen key is handled by
 * the operating system and never reaches JavaScript, and the usual gestures at it — blocking
 * right-click, disabling selection — are bypassed by anyone who wants to and are a daily
 * irritation to everyone who does not. It does not stop a phone pointed at the monitor, and
 * nothing ever will.
 *
 * What it does stop is the common case: alt-tabbing away and capturing the window from
 * outside it, and a screen recorder running over this tab while the candidate works in
 * another. Both of those now see a blank page.
 * --------------------------------------------------------------------- */

html.away body > *:not(#awaybox) {
  /* Blur rather than hide, so the page does not reflow and lose scroll position. */
  filter: blur(18px);
  opacity: .35;
  pointer-events: none;
  user-select: none;
}
html.away::after {
  content: "Paused — this page is not being shown while you are elsewhere";
  position: fixed; inset: 0; z-index: 40;
  display: grid; place-items: center;
  background: var(--paper);
  font: 500 15px/1.5 var(--sans); color: var(--ink-3); text-align: center;
  padding: 40px;
}

/*
 * The warning on return.
 *
 * ── Why this takes the whole screen ────────────────────────────────────
 *
 * It was a small bordered box in the middle of the page with an "I understand" button. Sat
 * as a candidate, an eighty-six second absence produced something that read as a receipt for
 * an event already over. It never conveyed that anything was still happening, because under
 * the old rule nothing was.
 *
 * Something is now. There is a live deadline on this and coming back is what satisfies it, so
 * the screen belongs to it until it is answered — a warning that can be worked around is one
 * that has to be read to be obeyed, and this one has to be obeyed to be dismissed.
 *
 * Red, and with a mark on it, because the two things it has to communicate in the first
 * second are *this is serious* and *this is about you right now*. Everywhere else in this
 * product uses amber for circumstance and red for a real failure. This is a real failure.
 * --------------------------------------------------------------------- */

/*
 * The three rungs of the rule, on the induction screen.
 *
 * Numbered because it genuinely is a sequence and the order carries the meaning: what the
 * second one is depends on the first having happened. The last rung is red, because that is
 * the one that ends somebody's assessment and it should not be discovered later.
 */
.rule-steps { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 14px; }
.rs { display: flex; gap: 10px; align-items: flex-start; }
.rs-n {
  flex: none; width: 19px; height: 19px; border-radius: 50%; margin-top: 2px;
  display: grid; place-items: center;
  background: var(--warn); color: #fff; font: 700 10.5px/1 var(--sans);
}
.rs.last .rs-n { background: var(--bad); }
.rs-t { font: 400 14px/1.55 var(--sans); color: var(--ink-2); }
.rs-t b { color: var(--ink); }
.rs.last .rs-t b { color: var(--bad); }

/*
 * The screen a disqualified candidate ends on.
 *
 * Deliberately calm rather than punishing. The mark is red because the fact is serious and
 * everything else is the ordinary end-of-assessment voice — somebody meeting this has just
 * lost something they were trying at, and a page that shouts at them on the way out is
 * cruelty with no purpose. What it owes them is the reason, the reassurance that their work
 * was kept, and a way to say something went wrong.
 */
.dq-page { max-width: 60ch; }
.dq-mark {
  width: 40px; height: 40px; border-radius: 50%; margin: 0 auto 18px;
  display: grid; place-items: center;
  background: var(--bad); color: #fff; font: 800 23px/1 var(--sans);
}
.dq-page .note { max-width: 58ch; }
.dq-last { margin-top: 20px; color: var(--ink-3); }

#awaybox.awayback {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center; padding: 24px;
  background: rgba(76, 12, 12, .55);
  backdrop-filter: blur(3px);
}
.ab-card {
  position: relative;
  width: min(520px, 100%); max-height: calc(100vh - 48px); overflow-y: auto;
  background: var(--card); border-radius: 14px;
  border-top: 5px solid var(--bad);
  padding: 26px 26px 22px; box-shadow: 0 26px 70px rgba(15, 23, 42, .45);
  text-align: left;
}
.ab-mark {
  width: 38px; height: 38px; border-radius: 50%; margin-bottom: 13px;
  display: grid; place-items: center;
  background: var(--bad); color: #fff; font: 800 22px/1 var(--sans);
}
.ab-eyebrow {
  display: block; font: 700 10.5px/1 var(--mono); letter-spacing: .13em;
  text-transform: uppercase; color: var(--bad); margin-bottom: 7px;
}
.ab-card h2 { margin: 0 0 11px; font: 700 22px/1.2 var(--sans); color: var(--ink); }
.ab-p { margin: 0 0 11px; font: 400 14.5px/1.6 var(--sans); color: var(--ink-2); max-width: 54ch; }
.ab-p b { color: var(--ink); }

/* The sentence that says the next one ends it. It gets its own weight for that reason. */
.ab-final {
  margin: 0 0 13px; padding: 11px 13px; border-radius: 8px;
  background: var(--bad-bg); border: 1px solid var(--bad);
  font: 400 14px/1.55 var(--sans); color: var(--ink); max-width: 54ch;
}
.ab-final b { color: var(--bad); }

/*
 * The countdown, which is the whole difference between this and the notice it replaced.
 *
 * Large and monospaced so a glance reads it, and it turns red under twenty seconds — by then
 * a candidate who is reading rather than clicking needs to stop reading.
 */
.ab-clock {
  display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap;
  margin: 4px 0 17px; padding: 12px 14px; border-radius: 9px;
  background: var(--bg); border: 1px solid var(--rule-2);
}
.ab-clock-h { font: 600 12px/1 var(--sans); color: var(--ink-2); }
.ab-clock-n {
  font: 700 30px/1 var(--mono); color: var(--ink); font-variant-numeric: tabular-nums;
}
.ab-clock-n.out { color: var(--bad); }
.ab-clock-s { font: 400 12.5px/1.4 var(--sans); color: var(--ink-3); }

.ab-go { margin: 0; }
#awaybox .ab-note {
  margin: 12px 0 0; font: 400 12.5px/1.55 var(--sans); color: var(--ink-3); max-width: 54ch;
}

/* Ended: no clock, nothing to do, and the button only goes to their own result. */
#awaybox.ended .ab-card { border-top-color: var(--bad); }

@media (prefers-reduced-motion: no-preference) {
  .ab-card { animation: ab-in .18s ease-out; }
  @keyframes ab-in {
    from { transform: translateY(10px); opacity: 0; }
    to { transform: none; opacity: 1; }
  }
}

/*
 * What the calculation box accepts.
 *
 * It was an empty field labelled "work something out", with sixty Excel functions behind it
 * and no way for a candidate to know that any of them were there. Set quiet and small: it is
 * reference, read once, and it sits inside a fold that most questions never open.
 */
.pv-calc-help {
  margin-top: 9px; padding: 10px 12px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--rule-2);
}
.pv-calc-help p {
  margin: 0 0 7px; font: 400 12px/1.6 var(--sans); color: var(--ink-2); max-width: 66ch;
}
.pv-calc-help p:last-child { margin-bottom: 0; }
.pv-calc-help b { color: var(--ink); font-weight: 600; }
.pv-calc-help code {
  font: 500 11.5px/1.5 var(--mono); padding: 1px 5px; border-radius: 4px;
  background: var(--card); border: 1px solid var(--rule-2); color: var(--ink);
}

/* The "with" label on the combine control, quieter than the table label beside it. */
.pv-with { color: var(--ink-3); }

/*
 * Calculated fields, in the open rather than behind a disclosure.
 *
 * It was a <details>, on the reasoning that most questions never need one. That is about how
 * often it is used, not about whether anybody can find it — and reported from a sitting, a
 * closed fold labelled "work something out" beside four wells reads as an advanced option
 * rather than as a field you can build. The reference behind it stays folded, because that
 * genuinely is reference.
 */
.pv-calcs {
  grid-column: 1 / -1;
  margin-top: 2px; padding: 10px 11px 11px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--rule-2);
}
.pv-calc-list { display: flex; flex-direction: column; gap: 9px; margin-top: 6px; }
.pv-calc-row {
  display: flex; flex-direction: column; gap: 5px;
  padding: 8px 9px; border-radius: 7px;
  background: var(--card); border: 1px solid var(--rule-2);
}
.pv-calc-def { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.pv-calc-def .pv-formula { flex: 1 1 190px; min-width: 130px; }
.pv-calc-put { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.pv-calc-hint { font: 400 11.5px/1.4 var(--sans); color: var(--ink-3); }

/* Where to put it. Buttons rather than a dropdown: three choices, all worth seeing at once. */
.pv-chipbtn {
  cursor: pointer; font: 600 11.5px/1 var(--sans); color: var(--accent);
  background: var(--accent-bg); border: 1px solid var(--accent);
  border-radius: 6px; padding: 5px 9px;
}
.pv-chipbtn:hover { background: var(--accent); color: #fff; }

.pv-ref { margin-top: 9px; }
.pv-ref > summary {
  cursor: pointer; font: 500 12px/1.4 var(--sans); color: var(--ink-3);
  padding: 3px 2px; border-radius: 5px;
}
.pv-ref > summary:hover { color: var(--ink-2); }

/* A chip in a well is a drag handle, so it should say so before anybody tries. */
.pv-chip[draggable="true"] { cursor: grab; }
.pv-chip[draggable="true"]:active { cursor: grabbing; }
