* { box-sizing: border-box; margin: 0; padding: 0; }

/* Reserve the vertical scrollbar's gutter at all times. The doc pages
   scroll (so they'd otherwise lose width to the scrollbar) while the
   simulation page does not — without this the shared top nav would be
   slightly narrower on the doc pages, making the right-aligned nav links
   jump a few pixels when navigating between pages. */
html { scrollbar-gutter: stable; }


:root {
  --bg: #14141a;
  --panel: #1e1e26;
  --panel-2: #26262f;
  --border: #33333f;
  --text: #e6e6ec;
  --muted: #8b8b9a;
  --accent: #8b7cff;
  --user: #3a3a4a;
  --ok: #6ee7a8;
  --warn: #ffb86b;
  --err: #ff7b7b;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  scrollbar-gutter: stable;
  display: flex;
  flex-direction: column;
}

#app { display: flex; height: 100vh; height: 100dvh; }

/* On the simulation page the shared top nav sits above #app, so let #app
   take the remaining height instead of the full viewport. */
body:has(> .top-nav) #app {
  height: auto;
  flex: 1;
  min-height: 0;
}

/* ============================================================
   Setup screen
   Shown in the centre of the main area after the user clicks
   "Click here to begin". Replaces the old fixed sidebar.
   ============================================================ */

#setupScreen {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow-y: auto;
  padding: 28px 24px;
}

#setupScreen[hidden] { display: none; }

.setup-card {
  width: 100%;
  max-width: 420px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 26px 26px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.setup-title {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.2px;
  text-align: center;
}

.setup-sub {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.55;
  text-align: center;
  margin: -6px 0 4px;
}

/* Two labelled halves of the card: the fields the simulation needs in order to
   start, then the cosmetic extras. No divider between them — each half already
   opens with a centred rule, so a full-width line above it would double up. */
.setup-section {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.setup-section + .setup-section {
  margin-top: 2px;
  padding-top: 16px;
}

/* Section heading centred between two hairline rules. The pseudo-elements share
   an equal basis, so the label sits on the card's centre line rather than being
   pushed left by a single trailing rule. */
.setup-section-title {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.9px;
  text-align: center;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: -3px;
}

.setup-section-title::before,
.setup-section-title::after {
  content: "";
  flex: 1 1 0;
  height: 1px;
  background: var(--border);
}

.setup-field { display: block; }
/* The `hidden` attribute must win over the display rule above. */
.setup-field[hidden] { display: none !important; }

/* Compare-mode child picker. One pill per role; Golden Child and Scapegoat
   are checked by default. */
.compare-roles-label,
.field-label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--muted);
  margin-bottom: 5px;
  font-weight: 600;
}

.compare-role-options {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.compare-role-option,
.gender-option {
  display: flex;
  align-items: center;
  gap: 7px;
  flex: 1 1 120px;
  margin: 0;
  padding: 8px 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.compare-role-option:hover,
.gender-option:hover { border-color: var(--muted); }

.compare-role-option:has(input:checked),
.gender-option:has(input:checked) {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.14);
}

.compare-role-option input[type="checkbox"],
.gender-option input[type="radio"] {
  width: 15px;
  height: 15px;
  padding: 0;
  margin: 0;
  flex: none;
  accent-color: var(--accent);
  cursor: pointer;
}

/* Optional parent/child gender pins. Two compact groups side by side; neither
   has a default, so an empty group means "draw it 50/50" on the server. */
.gender-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}

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

.gender-option { flex: 1 1 70px; }

/* The shared hint under both groups; unlike .role-hint it does not reserve a
   fixed two-line block. The compound selector beats the later .role-hint rule. */
.role-hint.gender-hint {
  margin-top: -4px;
  min-height: 0;
}

.setup-actions {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-top: 4px;
}

label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--muted);
  margin-bottom: 5px;
  font-weight: 600;
}

input, select {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 9px 11px;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  outline: none;
  transition: border-color 0.15s, opacity 0.15s;
}
input:focus, select:focus { border-color: var(--accent); }

select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b8b9a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'/%3e%3c/svg%3e");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 14px;
  padding-right: 32px;
  cursor: pointer;
}

input:disabled, select:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

button {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 7px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s;
}
button:hover { opacity: 0.87; }
button:disabled { opacity: 0.4; cursor: not-allowed; }

button.secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  font-weight: 500;
}
button.secondary:hover { color: var(--text); border-color: var(--muted); }
button.secondary:disabled { color: var(--muted); }

.role-group { display: block; }
body.compare-mode .role-group { display: none !important; }

.role-hint {
  font-size: 11px;
  line-height: 1.55;
  color: var(--muted);
  margin-top: 6px;
  min-height: 34px;
}

/* The self-assessment link at the bottom of the "Your role" group, directly
 * above the "Life stage" field. Block-level so it takes its own line; the link
 * reuses .start-link for its colour and underline and only overrides the
 * hint-sized type. */
.role-quiz-link {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.55;
}

.dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--muted);
  margin-right: 6px;
  vertical-align: middle;
}
.dot.ok   { background: var(--ok); }
.dot.warn { background: var(--warn); }
.dot.err  { background: var(--err); }

/* ============================================================
   Main area
   ============================================================ */

main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

#messages {
  flex: 1;
  overflow-y: auto;
  padding: 28px 32px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
}
#messages::-webkit-scrollbar { width: 8px; }
#messages::-webkit-scrollbar-thumb {
  background: var(--border); border-radius: 4px;
}

.msg {
  display: flex;
  flex-direction: column;
  gap: 5px;
  max-width: 780px;
  min-width: 0;
  width: 100%;
}

/* Single-role mode: keep every message in the central band of the
   screen instead of pinning it to the far edge. Parent (assistant) and
   child (user) messages share the same size, but are nudged either side
   of centre so the two speakers read as distinct columns without
   overlapping. Scoped away from compare mode, which uses its own grid. */
body:not(.compare-layout) .msg {
  align-self: center;
  transform: translateX(-8%);
}

.msg .who {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
}

.msg .body {
  padding: 12px 16px;
  border-radius: 10px;
  line-height: 1.6;
  font-size: 14.5px;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  min-width: 0;
  width: 100%;
}

/* In-bubble status text. Errors used to be injected with innerHTML and an
 * inline colour; they are now built with textContent and styled here. */
.msg .body .body-error { color: var(--err); }
.msg .body .body-note  { color: var(--muted); font-style: italic; }

.msg.assistant .body {
  background: var(--panel);
  border: 1px solid var(--border);
}

.msg.user { align-self: flex-end; align-items: flex-end; }
.msg.user .body {
  background: var(--user);
}
body:not(.compare-layout) .msg.user {
  align-self: center;
  transform: translateX(8%);
}

/* Below this width the centre band is too tight to offset the two
   speakers, so fall back to the original left/right alignment. */
@media (max-width: 900px) {
  body:not(.compare-layout) .msg { align-self: stretch; transform: none; }
  body:not(.compare-layout) .msg.user { align-self: flex-end; transform: none; }
}

/* ============================================================
   Compare pair and threads
   ============================================================ */

.compare-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  width: 100%;
  min-width: 0;
}

.compare-side {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.compare-thread {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

.compare-thread .msg { max-width: none; min-width: 0; }

.compare-thread .msg .who {
  font-size: 10px;
  letter-spacing: 0.6px;
  margin-bottom: 2px;
}

.waiting-text {
  color: var(--muted);
  font-style: italic;
  font-size: 13px;
  opacity: 0.75;
}

.end-note {
  text-align: center;
  font-size: 11.5px;
  color: var(--muted);
  padding: 6px 0 2px;
  letter-spacing: 0.3px;
}
.end-note b { color: var(--text); font-weight: 600; }

.sim-end-banner {
  text-align: center;
  font-size: 12.5px;
  color: #f87171;
  padding: 14px 20px;
  border: 1px dashed rgba(248,113,113,0.45);
  border-radius: 10px;
  letter-spacing: 0.3px;
  line-height: 1.6;
  max-width: 640px;
  margin: 4px auto 0;
}
.sim-end-banner b { color: #fff; font-weight: 600; }
/* Inline, clickable links in the message area ("Click here to begin" /
   "Start simulation") that drive the setup flow. */
.start-link {
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.start-link:hover { color: #fff; }

.empty {
  color: var(--muted);
  font-size: 13.5px;
  text-align: center;
  margin: auto;
  max-width: 460px;
  line-height: 1.7;
}

/* ============================================================
   Input area
   ============================================================ */

#inputArea {
  border-top: 1px solid var(--border);
  padding: 12px 32px 16px;
  background: var(--bg);
  flex-shrink: 0;
}

/* Manual row (textarea) keeps a wide max-width; auto row is
   narrower because it only holds buttons and the meter. */
#manualRow {
  width: 100%;
  max-width: 1100px;
  margin-left: auto;
  margin-right: auto;
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: 12px;
}

#autoRow {
  width: 100%;
  max-width: 680px;
  margin-left: auto;
  margin-right: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

#input {
  flex: 1;
  min-width: 0;
  min-height: 46px;
  max-height: 180px;
  resize: none;
  font-size: 14px;
  padding: 12px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text);
  font-family: inherit;
  outline: none;
  line-height: 1.5;
  transition: opacity 0.15s;
}
#input:focus { border-color: var(--accent); }
#input:disabled { opacity: 0.45; cursor: not-allowed; }

#send {
  height: 46px;
  padding: 0 22px;
  flex-shrink: 0;
}

/* ============================================================
   Auto mode: hint + frustration + strategy buttons
   ============================================================ */

.auto-hint {
  font-size: 10.5px;
  color: var(--muted);
  letter-spacing: 0.2px;
  line-height: 1.4;
}

/* ---------- Frustration meter (compact, inline) ---------- */

.frustration-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 10.5px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--muted);
  min-width: 0;
}

.frustration-label-text {
  flex-shrink: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Fixed (not min-) width so the "Parental frustration" and "Personal
     frustration" labels occupy an identical box, which keeps both tracks the
     same size. This width fits "Parental frustration" in full so nothing is
     truncated. */
  width: 156px;
}

.frustration-track {
  flex: 1;
  height: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
  min-width: 50px;
}

.frustration-fill {
  height: 100%;
  width: 0%;
  background: #6ee7a8;
  border-radius: 999px;
  transition: width 0.5s cubic-bezier(.4,0,.2,1), background 0.4s;
}

.frustration-pct {
  flex-shrink: 0;
  /* Fixed (not min-) width so the percentage column occupies the same space
     regardless of whether it reads "0%" or "100%". This keeps the stage text
     that follows it starting at an identical left edge on both meters, so
     "Irritated" and "Overwhelmed" line up. */
  width: 38px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.frustration-stage {
  flex-shrink: 0;
  /* Fixed width so the two meters' stage labels share the same box and the
     row width stays constant as the label text changes. */
  width: 76px;
  text-align: left;
}

@keyframes pulseRed {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220,38,38,0.55); }
  50%      { box-shadow: 0 0 0 7px rgba(220,38,38,0); }
}

.frustration-wrap[data-stage="baseline"]   .frustration-fill { background: #6ee7a8; }
.frustration-wrap[data-stage="escalating"] .frustration-fill { background: #fbbf24; }
.frustration-wrap[data-stage="hostile"]    .frustration-fill { background: #dc2626; }
.frustration-wrap[data-stage="hostile"] .frustration-track {
  animation: pulseRed 1.2s ease-in-out infinite;
}

/* ---------- Strategy buttons (compact, left-aligned) ---------- */

.strategy-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.strategy-btn {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 8px 12px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: row;
  align-items: baseline;
  justify-content: flex-start;
  gap: 8px;
  transition: border-color 0.15s, background 0.15s, transform 0.08s;
  min-width: 0;
  overflow: hidden;
}

.strategy-btn:hover:not(:disabled) {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.08);
}
.strategy-btn:active:not(:disabled) { transform: scale(0.985); }
.strategy-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.strategy-btn .strategy-name {
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.2px;
  white-space: nowrap;
  flex-shrink: 0;
}

.strategy-btn .strategy-hint {
  font-size: 10.5px;
  color: var(--muted);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.strategy-btn .strategy-hint::before {
  content: "— ";
  opacity: 0.5;
}

.strategy-btn[data-strategy="fawning"]       .strategy-name { color: #6ee7a8; }
.strategy-btn[data-strategy="jade"]          .strategy-name { color: #fbbf24; }
.strategy-btn[data-strategy="grey_rock"]     .strategy-name { color: #94a3b8; }
.strategy-btn[data-strategy="boundary"]     .strategy-name { color: #f87171; }

.strategy-btn.is-generating {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.12);
}

.status {
  font-size: 11px;
  color: var(--muted);
  text-align: left;
  line-height: 1.5;
  margin-top: auto;
}
.status.err { color: #ff7b7b; }

/* Status indicator relocated into the top nav. It is absolutely
   positioned and centred relative to the whole bar (the nav is a
   positioned context via `position: sticky`), so it stays dead-centre
   regardless of the widths of the brand and the nav links. */
.doc-nav .nav-status {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  font-size: 12px;
  line-height: 1;
  white-space: nowrap;
  display: flex;
  align-items: center;
}

.cursor::after {
  content: "▍";
  color: var(--accent);
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* ============================================================
   Role-tinted assistant bubbles
   ============================================================ */

/* Colour follows the ROLE, never the column: in compare mode a column can hold
 * any child, so the bubble's `role-*` class is the single source of tinting. */
.msg.assistant .body.role-golden_child {
  background: #FEF3C7;
  color: #78350F;
  border-color: #F5D68A;
}

.msg.assistant .body.role-scapegoat {
  background: #FEE2E2;
  color: #991B1B;
  border-color: #F5B5B5;
}

.msg.assistant .body.role-invisible_child {
  background: #F1F5F9;
  color: #64748B;
  border-color: #D8DEE6;
}

.msg.assistant .body.role-golden_child::after { color: #78350F; }
.msg.assistant .body.role-scapegoat::after { color: #991B1B; }
.msg.assistant .body.role-invisible_child::after { color: #64748B; }

.compare-side.gc .waiting-text { color: #78350F; opacity: 0.45; }
.compare-side.sc .waiting-text { color: #991B1B; opacity: 0.45; }

/* ============================================================
   Scenario picker
   ============================================================ */

.scenario-picker {
  display: flex;
  flex-direction: column;
  gap: 22px;
  max-width: 900px;
  width: 100%;
  margin: 4px auto;
  padding: 4px;
  align-self: center;
}

.scenario-picker h2 {
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.2px;
}

.scenario-picker .sub {
  font-size: 13px;
  color: var(--muted);
  margin-top: -16px;
  line-height: 1.55;
}

.scenario-stage-filter {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: -10px;
}

.scenario-stage-filter-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--muted);
  font-weight: 700;
  margin-right: 4px;
}

.scenario-stage-button {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 5px 12px;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}

.scenario-stage-button:hover {
  border-color: var(--accent);
  color: var(--text);
}

.scenario-stage-button[aria-pressed="true"] {
  background: rgba(139, 124, 255, 0.16);
  border-color: var(--accent);
  color: var(--text);
}

.scenario-stage-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.scenario-category {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.scenario-category-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--muted);
  font-weight: 700;
}

.scenario-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 8px;
}

.scenario-card {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 12px 14px;
  cursor: pointer;
  font-family: inherit;
  color: var(--text);
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: border-color 0.15s, background 0.15s, transform 0.08s;
}

.scenario-card:hover:not(:disabled) {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.08);
}
.scenario-card:active:not(:disabled) { transform: scale(0.99); }
.scenario-card:disabled { opacity: 0.4; cursor: not-allowed; }

.scenario-card-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}

.scenario-card-desc {
  font-size: 11.5px;
  color: var(--muted);
  line-height: 1.5;
}

.scenario-context {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.6;
  padding: 14px 22px;
  background: rgba(139, 124, 255, 0.06);
  border: 1px solid rgba(139, 124, 255, 0.22);
  border-radius: 10px;
  max-width: 640px;
  align-self: center;
  text-align: center;
  margin-top: 6px;
}
.scenario-context b {
  display: block;
  color: var(--text);
  font-weight: 600;
  font-size: 13px;
  margin-bottom: 4px;
  letter-spacing: 0.2px;
}

/* ============================================================
   Role transformation banner
   ============================================================ */

.role-change-banner {
  align-self: center;
  text-align: center;
  padding: 14px 22px;
  border: 1px dashed rgba(248, 113, 113, 0.5);
  border-radius: 10px;
  background: rgba(248, 113, 113, 0.06);
  color: #f87171;
  font-size: 12.5px;
  letter-spacing: 0.3px;
  line-height: 1.6;
  max-width: 520px;
  margin: 8px auto;
}
.role-change-banner b {
  color: #fff;
  font-weight: 600;
  display: block;
  margin-bottom: 3px;
  letter-spacing: 0.4px;
}

/* ============================================================
   End-of-run debrief
   The run's response pattern, rendered into the transcript when
   a simulation ends: how often each move was used, then the
   two-sided cost of every move (what it costs the child, what a
   narcissistic parent reliably does in return).
   ============================================================ */

.run-debrief {
  width: 100%;
  max-width: 760px;
  margin: 8px auto 4px;
  padding: 18px 20px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  color: var(--text);
  font-size: 12.5px;
  line-height: 1.65;
  text-align: left;
}

.debrief-title {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--text);
}

.debrief-role {
  margin: 16px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--text);
}

/* The "how it ended" qualifier sits under the role name at body weight, so it
   reads as a note rather than part of the heading. */
.debrief-role span {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}

/* In single mode the card title is the only heading, so the first section needs
   no divider of its own. */
.debrief-section:first-of-type .debrief-role {
  margin-top: 10px;
  padding-top: 0;
  border-top: 0;
}

.debrief-lede {
  margin: 8px 0 12px;
  color: var(--muted);
  font-size: 12px;
}

.debrief-lede b { color: var(--text); font-weight: 600; }

.debrief-move {
  --move: var(--muted);
  margin-bottom: 8px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--panel-2);
  overflow: hidden;
}

/* Same palette as the strategy buttons, so a move looks the same in the
   debrief as it did in the input row. */
.debrief-move[data-strategy="fawning"]   { --move: #6ee7a8; }
.debrief-move[data-strategy="jade"]      { --move: #fbbf24; }
.debrief-move[data-strategy="grey_rock"] { --move: #94a3b8; }
.debrief-move[data-strategy="boundary"]  { --move: #f87171; }

.debrief-move > summary {
  display: grid;
  grid-template-columns: 12px minmax(72px, auto) minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  cursor: pointer;
  list-style: none;
  font-size: 12px;
}

.debrief-move > summary::-webkit-details-marker { display: none; }

/* Border-drawn caret: no extra element and no glyph to depend on. */
.debrief-move > summary::before {
  content: "";
  justify-self: center;
  width: 0;
  height: 0;
  border-left: 5px solid var(--muted);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform 0.15s ease;
}

.debrief-move[open] > summary::before { transform: rotate(90deg); }

.debrief-move > summary:hover .debrief-name { text-decoration: underline; }

.debrief-move > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.debrief-name {
  color: var(--move);
  font-weight: 600;
  letter-spacing: 0.2px;
}

.debrief-bar {
  height: 5px;
  min-width: 0;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
}

.debrief-bar i {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--move);
  opacity: 0.8;
}

.debrief-count {
  color: var(--text);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A move the run never used is the teaching moment, not an error: muted, but
   still expandable and still explained. */
.debrief-move.is-unused .debrief-name,
.debrief-move.is-unused .debrief-count { color: var(--muted); }
.debrief-move.is-unused .debrief-count { font-weight: 400; }

.debrief-cost {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 2px;
  padding: 10px 14px 12px;
  border-top: 1px dashed var(--border);
}

.debrief-cost h3,
.debrief-cost h4 {
  margin: 0 0 4px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--move);
}

.debrief-cost p {
  margin: 0;
  font-size: 12px;
  line-height: 1.62;
  color: var(--text);
}

.debrief-close {
  margin: 12px 0 0;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 11.5px;
  font-style: italic;
}

@media (prefers-reduced-motion: reduce) {
  .debrief-move > summary::before { transition: none; }
}

/* ============================================================
   Terminal breakdown style — each role's final message.
   All three share the ALL-CAPS, heavy treatment that marks the
   end of a session, but each carries its own palette so the
   breakdown reads as role-specific (not a single "mobbing").
   ============================================================ */

.msg.assistant.mobbed .body,
.compare-thread .msg.assistant.mobbed .body {
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: 600;
}

/* Scapegoat: TOTAL EXILE — MOBBING (black / red). */
.msg.assistant.mobbed .body.role-scapegoat,
.compare-thread .msg.assistant.mobbed .body.role-scapegoat {
  background: #000;
  color: #dc2626;
  border-color: #7f1d1d;
}
.msg.assistant.mobbed .body.role-scapegoat::after,
.compare-thread .msg.assistant.mobbed .body.role-scapegoat::after {
  color: #dc2626;
}

/* Golden child: BETRAYAL — CONDITIONAL LOVE REVOKED (dark amber / gold). */
.msg.assistant.mobbed .body.role-golden_child,
.compare-thread .msg.assistant.mobbed .body.role-golden_child {
  background: #1c1206;
  color: #f59e0b;
  border-color: #78350f;
}
.msg.assistant.mobbed .body.role-golden_child::after,
.compare-thread .msg.assistant.mobbed .body.role-golden_child::after {
  color: #f59e0b;
}

/* Invisible child: TOTAL ERASURE — ABANDONMENT (near-black / cold slate). */
.msg.assistant.mobbed .body.role-invisible_child,
.compare-thread .msg.assistant.mobbed .body.role-invisible_child {
  background: #0b0f14;
  color: #94a3b8;
  border-color: #334155;
}
.msg.assistant.mobbed .body.role-invisible_child::after,
.compare-thread .msg.assistant.mobbed .body.role-invisible_child::after {
  color: #94a3b8;
}

/* ============================================================
   Compare-mode grid layout
   ============================================================ */

body.compare-layout #messages {
  display: grid;
  /* createCompareExchange() updates --compare-cols to the number of selected
     children (2 or 3), so the grid always matches the checkboxes. */
  grid-template-columns: repeat(var(--compare-cols, 2), minmax(0, 1fr));
  column-gap: 14px;
  row-gap: 14px;
  align-content: start;
  grid-auto-flow: row dense;
}

body.compare-layout .compare-pair,
body.compare-layout .compare-side,
body.compare-layout .compare-thread {
  display: contents;
}

body.compare-layout #messages > * {
  min-width: 0;
  max-width: 100%;
}

/* The compare grid sizes its own columns; don't shrink-wrap there. */
body.compare-layout .msg { width: auto; }

/* Every thread item is pinned to its own column by --col, set per side in
   createCompareExchange(). This works for any 2–3 selected children and keeps
   alignment correct even when a column holds a role other than the default. */
body.compare-layout .compare-thread > * {
  grid-column: var(--col, auto);
}

/* A manually typed line is shared by every column, so let it span the whole
   grid. Without this it would occupy one column's cell and push that column a
   row out of step with the others. */
body.compare-layout #messages > .msg.user {
  grid-column: 1 / -1;
}

body.compare-layout #messages > .scenario-context,
body.compare-layout #messages > .role-change-banner,
body.compare-layout #messages > .sim-end-banner,
body.compare-layout #messages > .end-note,
body.compare-layout #messages > .run-debrief,
body.compare-layout #messages > .empty {
  grid-column: 1 / -1;
}

/* The compare grid defaults to align-content: start, which pins the
   "Ready" empty-state to the top. When only the empty-state is present
   (before a session begins), centre it vertically to match single mode. */
body.compare-layout #messages:has(> .empty) {
  align-content: center;
}

body.compare-layout #messages > .scenario-picker {
  grid-column: 1 / -1;
  justify-self: center;
  align-self: start;
  width: 100%;
  max-width: 900px;
  margin-left: auto;
  margin-right: auto;
}

/* ============================================================
 *  Thread-ended marker
 *  Shown in an ended compare column on subsequent exchanges,
 *  when the other column is still live.
 *  ============================================================ */

.thread-ended {
  font-size: 10.5px;
  letter-spacing: 0.5px;
  color: var(--muted);
  text-align: center;
  padding: 10px 12px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-style: italic;
  opacity: 0.7;
}

/* ============================================================
 *  Personal frustration meter
 *  A second, visually distinct bar that tracks the user's OWN
 *  accumulating stress (fawning / grey-rocking / JADEing all
 *  cost the child something). It uses a cool violet palette so
 *  it can never be confused with the parent-frustration bar.
 *  ============================================================ */

.frustration-wrap.personal {
  border-color: rgba(139, 124, 255, 0.4);
  background: rgba(139, 124, 255, 0.08);
}

.frustration-wrap.personal .frustration-label-text {
  color: #c7bfff;
}

/* Personal meter overrides the shared stage colours: it stays in the
   violet family, darkening as the user's own stress climbs. */
.frustration-wrap.personal .frustration-fill {
  background: #a5b4fc;
}
.frustration-wrap.personal[data-stage="escalating"] .frustration-fill {
  background: #7c3aed;
}
.frustration-wrap.personal[data-stage="hostile"] .frustration-fill {
  background: #4c1d95;
}
.frustration-wrap.personal[data-stage="hostile"] .frustration-track {
  animation: pulseRed 1.2s ease-in-out infinite;
}

/* The child's own breaking point banner. */
.role-change-banner.personal-break-banner {
  border-color: rgba(139, 124, 255, 0.55);
  background: rgba(139, 124, 255, 0.08);
  color: #c7bfff;
}
.role-change-banner.personal-break-banner b {
  color: #fff;
}

/* Mutual breakdown — BOTH sides hit their limit in the same turn. Uses a
   warm amber/red palette to signal that this is neither side alone but the
   whole relationship collapsing at once, distinct from both solo banners. */
.role-change-banner.mutual-breakdown-banner {
  border-style: solid;
  border-color: rgba(255, 184, 107, 0.6);
  background: rgba(255, 184, 107, 0.1);
  color: #ffb86b;
  max-width: 560px;
}
.role-change-banner.mutual-breakdown-banner b {
  color: #fff;
}

/* ============================================================
 *  Documentation / Educational pages
 *  Standalone, scrollable content pages that reuse the app's
 *  palette (--bg / --panel / --accent) so they feel native to
 *  the simulation. They share a common top navigation bar that
 *  links the three pages together.
 *  ============================================================ */

/* The base `body` rule pins the viewport height and makes body a flex
   column — which stops the document from scrolling and keeps `position:
   sticky` from binding to the viewport. For the standalone content pages
   we undo all of that so the page scrolls normally and the nav sticks to
   the top of the viewport. The scrollbar gutter stays stable on both page
   types (see the `html` rule at the top) so the shared nav keeps an
   identical width wherever you are. */
body.doc-page {
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: visible;
  display: block;
}

/* Style the page scrollbar consistently on every page (the doc pages
   scroll on the root element, the simulation page's body is the scroll
   container). Styling it globally — rather than only on the doc pages —
   means every scroll container reserves the SAME width for its gutter,
   so the shared top nav keeps an identical width wherever you are. */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-thumb {
  background: var(--border); border-radius: 4px;
}

/* ---- Top navigation ---- */
.doc-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 14px 28px;
  background: rgba(20, 20, 26, 0.92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.doc-nav .brand {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--text);
  margin-right: auto;
  text-decoration: none;
}
.doc-nav .brand span { color: var(--accent); }

.doc-nav a.nav-link {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.3px;
  color: var(--muted);
  text-decoration: none;
  padding: 7px 13px;
  border-radius: 7px;
  border: 1px solid transparent;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.doc-nav a.nav-link:hover {
  color: var(--text);
  border-color: var(--border);
  background: var(--panel-2);
}
.doc-nav a.nav-link.active {
  color: var(--text);
  border-color: rgba(139, 124, 255, 0.5);
  background: rgba(139, 124, 255, 0.12);
}

/* ---- Content column ---- */
.doc-content {
  max-width: 820px;
  margin: 0 auto;
  padding: 40px 28px 96px;
}

.doc-header { margin-bottom: 32px; text-align: center; }

.doc-header h1 {
  font-size: 27px;
  font-weight: 600;
  letter-spacing: 0.2px;
  line-height: 1.25;
}
.doc-header h1 span { color: var(--accent); }

.doc-header p.lead {
  font-size: 14.5px;
  color: var(--muted);
  line-height: 1.7;
  margin-top: 12px;
}

/* Crisis note. Styled as a callout (it previously had no rules at all), which
   also gives it a clear visual break from the first section below — the
   "Communities" heading used to run straight into the paragraph above it. */
.doc-disclaimer {
  margin: 0 0 30px;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--text);
}
.doc-disclaimer strong { color: #fff; font-weight: 600; }

.doc-content section {
  margin-bottom: 34px;
  scroll-margin-top: 84px;
}

.doc-content h2 {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--text);
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  text-align: center;
}

.doc-content h3 {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text);
  margin: 20px 0 8px;
  text-align: center;
}

.doc-content h4 {
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  margin: 16px 0 8px;
  text-align: center;
}

.doc-content p {
  font-size: 14px;
  line-height: 1.75;
  color: var(--text);
  margin-bottom: 12px;
}
.doc-content p.dim { color: var(--muted); }

.doc-content ul,
.doc-content ol {
  margin: 0 0 14px;
  padding-left: 22px;
}
.doc-content li {
  font-size: 14px;
  line-height: 1.7;
  margin-bottom: 7px;
  color: var(--text);
}
.doc-content li strong { color: #fff; font-weight: 600; }

.doc-content a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.doc-content a:hover { color: #fff; }

/* ---- Help / resources list ----
   Scoped to `.doc-content ul.help-list` (not a bare `.help-list`) so this
   beats the generic `.doc-content ul { padding-left: 22px }` rule. With the
   lower-specificity selector the whole grid was inset by 22px, which read as
   "the buttons are off-centre, nudged to the right" on phones. */
.doc-content ul.help-list {
  list-style: none;
  padding: 0;
  /* Same bottom margin the generic `ul` rule would have applied. Without it a
     heading that follows a list (e.g. "Content creators and educators" after
     the Communities list) butts straight up against the last button. */
  margin: 0 0 14px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 8px;
}
.help-list li {
  margin: 0;
}
.help-list a {
  display: block;
  padding: 11px 15px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  transition: border-color 0.15s, background 0.15s, color 0.15s, transform 0.08s;
}
.help-list a:hover {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.1);
  color: #fff;
}
.help-list a:active { transform: scale(0.99); }

/* Single-column variant: one item per row, stacked vertically. Declared with
   the same specificity as the base grid rule above, otherwise the base
   `auto-fill` template would win and stack the "vertical" lists into columns. */
.doc-content ul.help-list.help-list-vertical {
  grid-template-columns: 1fr;
}

.doc-content code {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  font-size: 12.5px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 6px;
  color: #c7bfff;
}

.doc-content pre {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 14px 16px;
  overflow-x: auto;
  margin-bottom: 16px;
}
.doc-content pre code {
  background: none;
  border: none;
  padding: 0;
  color: var(--text);
  font-size: 12.5px;
  line-height: 1.6;
}

/* ---- Callout / note boxes ---- */
.doc-note {
  background: rgba(139, 124, 255, 0.07);
  border: 1px solid rgba(139, 124, 255, 0.28);
  border-radius: 10px;
  padding: 14px 18px;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--text);
  margin-bottom: 16px;
}
.doc-note b { color: #fff; }

.doc-warn {
  background: rgba(248, 113, 113, 0.07);
  border: 1px solid rgba(248, 113, 113, 0.35);
  border-radius: 10px;
  padding: 14px 18px;
  font-size: 13.5px;
  line-height: 1.7;
  color: #f8b4b4;
  margin-bottom: 16px;
}
.doc-warn b { color: #fff; }

/* ---- Page parts ----
   Labelled banners for the two halves of the educational material: the clinical
   background on education.html, and the website's own model, which now leads
   the documentation page. Each banner sits above the sections it introduces so
   a reader always knows which half they are in. */
.doc-part {
  margin: 0 0 26px;
  padding: 18px 22px;
  background: rgba(139, 124, 255, 0.06);
  border: 1px solid rgba(139, 124, 255, 0.25);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  text-align: center;
  scroll-margin-top: 84px;
}

.doc-part-kicker {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 6px;
}

.doc-content .doc-part h2 {
  font-size: 19px;
  padding-bottom: 0;
  border-bottom: 0;
  margin-bottom: 8px;
}

.doc-part p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--muted);
}

/* ---- In-page contents ----
   Two cards, one per part, sitting under the page header so the split is
   visible before any scrolling. From the education page the second card points
   at documentation.html, where part two now lives. */
.doc-toc {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 0 0 30px;
}

.doc-toc a {
  display: block;
  padding: 14px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-decoration: none;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.4;
  transition: border-color 0.15s, background 0.15s;
}

.doc-toc a:hover {
  border-color: rgba(139, 124, 255, 0.5);
  background: rgba(139, 124, 255, 0.08);
}

.doc-toc a span {
  display: block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 5px;
}

.doc-toc a em {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  font-style: normal;
  font-weight: 400;
  color: var(--muted);
}

/* ---- Card grid ---- */
.doc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.doc-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px 18px;
  text-align: center;
}
.doc-card h3 {
  margin: 0 0 6px;
  font-size: 13.5px;
  text-align: center;
}
.doc-card .doc-card-sub {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  color: inherit;
  margin: 0 0 8px;
  text-align: center;
}
.doc-card p {
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.6;
  margin: 0;
}

/* Role-accented cards echo the simulation's role colours. */
.doc-card.gc { border-color: rgba(245, 214, 138, 0.4); }
.doc-card.gc h3,
.doc-card.gc .doc-card-sub { color: #fbbf24; }
.doc-card.sc { border-color: rgba(245, 181, 181, 0.4); }
.doc-card.sc h3,
.doc-card.sc .doc-card-sub { color: #f87171; }
.doc-card.ic { border-color: rgba(216, 222, 230, 0.35); }
.doc-card.ic h3,
.doc-card.ic .doc-card-sub { color: #94a3b8; }

/* Role-coloured section headings, matching the card accents above. */
.doc-content h3.role-heading.gc { color: #fbbf24; }
.doc-content h3.role-heading.sc { color: #f87171; }
.doc-content h3.role-heading.ic { color: #94a3b8; }

/* ---- Embedded video (responsive 16:9) ---- */
.doc-video {
  position: relative;
  width: 100%;
  max-width: 720px;
  aspect-ratio: 16 / 9;
  margin: 24px auto 0;
}

.doc-video iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 10px;
  display: block;
}

/* ---- Further watching ----
   External talks listed under a role heading. Plain links rather than embeds:
   two more 16:9 players per role would dwarf the paragraphs they belong to and
   add six more YouTube frames to a page that already loads one. */
.doc-watch {
  margin: 0 0 18px;
  padding: 2px 0 2px 14px;
  border-left: 2px solid var(--border);
}

.doc-watch-label {
  display: block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}

/* Scoped under `.doc-content` to outrank the generic list rules above, which
   would otherwise indent these links by 22px and give them bullets. */
.doc-content .doc-watch ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.doc-content .doc-watch li {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
}

.doc-content .doc-watch li + li { margin-top: 3px; }

/* ---- Quiz teaser (education page) ----
   The assessment itself lives on quiz.html. This card is the hand-off: it keeps
   the destination visible where the exercise used to sit and reuses the quiz
   panel's card styling so the two pages read as one sequence. */
.quiz-teaser-card {
  background: var(--panel);
  border: 1px solid rgba(139, 124, 255, 0.4);
  border-radius: 12px;
  padding: 24px 22px;
  text-align: center;
}
.doc-content .quiz-teaser-card h2 {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 8px;
  font-size: 17px;
}
.doc-content .quiz-teaser-card p {
  max-width: 560px;
  margin: 0 auto 16px;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.7;
}

/* Accent button for cards that send the reader to a dedicated page. Scoped to
   `.doc-content` so it outranks the generic `a` colour and underline rules. */
.doc-content a.primary-btn {
  display: inline-block;
  padding: 11px 20px;
  border: 1px solid var(--accent);
  border-radius: 9px;
  background: var(--accent);
  color: #14141a;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2px;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s;
}
.doc-content a.primary-btn:hover {
  border-color: #9c8fff;
  background: #9c8fff;
  color: #14141a;
}
.doc-content a.primary-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* ---- Role self-assessment (quiz page) ----
   The markup is generated by assessment.js; these rules only style it. The
   panel/field palette is reused from the setup card so the exercise reads as
   part of the page rather than a bolted-on widget. */
.quiz {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px;
  margin: 4px 0 16px;
  scroll-margin-top: 84px;
}

.quiz-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}

.quiz-progress-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.quiz-progress-label b { color: var(--text); }

.quiz-progress-track {
  flex: 1;
  height: 6px;
  background: var(--panel-2);
  border-radius: 99px;
  overflow: hidden;
}

.quiz-progress-fill {
  width: 0;
  height: 100%;
  border-radius: 99px;
  background: var(--accent);
  transition: width 0.2s ease;
}

/* ---- Questions ---- */
.quiz-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.quiz-item { margin: 0 0 16px; }
.quiz-item:last-child { margin-bottom: 0; }
/* One question at a time: the rest keep their selections but are taken out of
   the layout, and with it out of the tab order. */
.quiz-item[hidden] { display: none; }

.quiz-q {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.quiz-legend {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-bottom: 8px;
  padding: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.5;
  color: #fff;
  /* Set by assessment.js to the tallest question heading in the quiz, so a
     question whose heading wraps to fewer lines does not shrink the card. */
  min-height: var(--quiz-legend-h, 0px);
}
/* Stepping moves focus here on purpose (assessment.js), so the question being
   asked is announced first. The ring only shows for keyboard and script focus,
   not for the click that advanced the quiz. */
.quiz-legend:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 6px;
}

.quiz-num {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--panel-2);
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
}

.quiz-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 7px;
}

/* Each question is a checkbox group, so the instruction sits directly under the
   heading instead of relying on the progress hint below the answers. */
.quiz .quiz-multi {
  margin: 0 0 8px 29px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

/* The global `label` rule is written for the setup form (11px, uppercase,
   letter-spaced), so the option labels have to opt out of all of it. */
.quiz-option {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0;
  padding: 9px 11px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.55;
  /* Set by assessment.js to the tallest option in the quiz (all fifteen
     questions, at the current width), so stepping between questions never
     resizes the card. A minimum, not a fixed height, so text is never clipped. */
  min-height: var(--quiz-option-h, 0px);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}

/* Off-screen copy of the question list that assessment.js lays out to find the
   tallest answer option. Hidden questions have no layout of their own, so the
   probe reveals every one of them, measures, and is removed again. It must
   still be laid out (hence visibility, not display), but must never be seen or
   affect the page. */
.quiz-measure {
  position: absolute;
  top: 0;
  left: -10000px;
  visibility: hidden;
  pointer-events: none;
}

.quiz-option:hover { border-color: var(--muted); color: var(--text); }

.quiz-option:has(input:checked) {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.14);
  color: var(--text);
}

.quiz-option input[type="checkbox"] {
  flex: none;
  width: 14px;
  height: 14px;
  margin: 2px 0 0;
  padding: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.quiz-option:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ---- Controls ---- */
.quiz-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
}

.quiz-btn {
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--panel-2);
  color: var(--text);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, opacity 0.15s;
}
.quiz-btn:hover:not(:disabled) {
  border-color: var(--accent);
  background: rgba(139, 124, 255, 0.12);
}
.quiz-btn.primary {
  border-color: var(--accent);
  background: var(--accent);
  color: #14141a;
}
.quiz-btn.primary:hover:not(:disabled) {
  border-color: #9c8fff;
  background: #9c8fff;
}
.quiz-btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* `p` rules in `.doc-content` outrank a lone class selector, so every result
   paragraph is scoped under `.quiz-result` to keep these sizes. */
.quiz .quiz-hint {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
}

/* ---- Result ---- */
.quiz-result {
  margin-top: 18px;
  padding: 18px;
  border: 1px solid rgba(139, 124, 255, 0.35);
  border-radius: 12px;
  background: rgba(139, 124, 255, 0.07);
  scroll-margin-top: 84px;
}
.quiz-result[hidden] { display: none; }

.quiz .quiz-kicker {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: var(--muted);
}

/* Also has to undo the shared `.doc-content h4` heading style (centred,
   uppercase, muted), which is more specific than a single class. */
.quiz-result .quiz-result-role {
  margin: 4px 0 3px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0.2px;
  text-align: left;
  text-transform: none;
  color: var(--text);
  outline: none;
}
.quiz-result-role.gc { color: #fbbf24; }
.quiz-result-role.sg { color: #f87171; }
.quiz-result-role.lc { color: #94a3b8; }
.quiz-result-role.hp { color: var(--ok); }

.quiz-result .quiz-result-meta {
  font-size: 12px;
  color: var(--muted);
}

.quiz-result .quiz-result-body {
  margin: 12px 0 0;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--text);
}

.quiz-bars {
  display: grid;
  gap: 7px;
  margin-top: 16px;
}

/* Fixed-width label column keeps the four bars aligned; the name is truncated
   rather than allowed to push the track out of line on narrow screens. */
.quiz-bar-row {
  display: grid;
  grid-template-columns: 118px 1fr 38px;
  align-items: center;
  gap: 10px;
}

.quiz-bar-label {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.quiz-bar-track {
  height: 7px;
  background: var(--panel-2);
  border-radius: 99px;
  overflow: hidden;
}

.quiz-bar-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: 99px;
  transition: width 0.35s ease;
}
.quiz-bar-fill.gc { background: #fbbf24; }
.quiz-bar-fill.sg { background: #f87171; }
.quiz-bar-fill.lc { background: #94a3b8; }
.quiz-bar-fill.hp { background: var(--ok); }

.quiz-bar-pct {
  font-size: 11.5px;
  color: var(--muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.quiz-result .quiz-note {
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--text);
}
.quiz-note strong { color: #fff; }
.quiz-result .quiz-note.dim { color: var(--muted); }

.quiz-result .quiz-cta { margin: 14px 0 0; font-size: 13px; font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .quiz-progress-fill,
  .quiz-bar-fill { transition: none; }
}
/* ---- Table ---- */
.doc-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 16px;
  font-size: 13px;
}
.doc-table th,
.doc-table td {
  text-align: left;
  padding: 9px 12px;
  border: 1px solid var(--border);
  vertical-align: top;
  line-height: 1.55;
}
.doc-table th {
  background: var(--panel-2);
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  font-weight: 700;
}
.doc-table td { color: var(--text); }
.doc-table tr:nth-child(even) td { background: rgba(255, 255, 255, 0.015); }

/* Wide comparison tables (e.g. the quant table in AI Model QA) scroll
   horizontally on narrow screens instead of being squeezed until every
   column is unreadable. */
.doc-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-bottom: 16px;
}
.doc-table-wrap .doc-table { margin-bottom: 0; min-width: 620px; }

.doc-footer {
  border-top: 1px solid var(--border);
  margin-top: 40px;
  padding-top: 20px;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.7;
}

/* ---- Debug-only surfaces ----
   The technical reference — and the copy that points at it — is a developer
   surface, not reader-facing content. It stays hidden unless the backend
   reports prompt debugging on: documentation.js adds `.dev-docs-on` to <body>
   after `/api/status` answers `debugPrompts: true`, and this pair is the whole
   switch. Hidden is the default, so a production page never paints the panel
   and then removes it. `revert` restores each element's own user-agent display
   value (inline for the header span, block for the panel and the callout). */
.doc-dev-only { display: none; }
body.dev-docs-on .doc-dev-only { display: revert; }

/* ---- Folded technical reference ----
   The developer reference sits at the bottom of the documentation page, closed
   by default so the page opens on the reader-facing guide. A native <details>
   supplies the toggle, the keyboard support and the "collapsed by default"
   state with no script; documentation.js only expands it when a link targets
   something inside it, which would otherwise scroll to hidden content. */
.doc-collapse {
  margin-top: 52px;
  padding: 0 20px 20px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  scroll-margin-top: 84px;
}

.doc-collapse > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 0 -20px;
  padding: 16px 20px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--text);
  cursor: pointer;
  list-style: none;
  transition: color 0.15s;
}
.doc-collapse > summary::-webkit-details-marker { display: none; }
.doc-collapse > summary:hover { color: #fff; }
.doc-collapse > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -4px;
  border-radius: 12px;
}

/* Plus/minus affordance, so the closed panel reads as expandable rather than
   as a dead heading. */
.doc-collapse > summary::after {
  content: "+";
  font-size: 17px;
  line-height: 1;
  color: var(--accent);
}
.doc-collapse[open] > summary { border-bottom: 1px solid var(--border); }
.doc-collapse[open] > summary::after { content: "\2212"; }

/* The panel supplies its own gutters, so its children sit flush inside it and
   only the top spacing survives: the page-level 34px bottom margin on sections
   would leave a gap before the panel's own bottom padding. */
.doc-collapse > p,
.doc-collapse > section { margin: 22px 0 0; }

@media (max-width: 600px) {
  .doc-nav { padding: 12px 16px; }
  .doc-content { padding: 28px 18px 80px; }
  .doc-header h1 { font-size: 22px; }
  /* One part card per row: two columns squeeze the descriptions to a sliver. */
  .doc-toc { grid-template-columns: 1fr; }
  .doc-part { padding: 16px; }
  .doc-collapse { padding: 0 14px 16px; }
  .doc-collapse > summary { margin: 0 -14px; padding: 14px 16px; font-size: 14px; }
  /* Long commands inside a callout wrap instead of being cut off at the
     panel's edge — they are still scrollable, but wrapping reads better on a
     phone than a horizontally clipped one-liner. */
  .doc-note pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  /* The quiz card loses its generous padding and the bar labels tighten so the
     percentage column stays visible on a phone. */
  .quiz { padding: 14px; }
  .quiz-result { padding: 14px; }
  .quiz-teaser-card { padding: 18px 16px; }
  /* The shared track has a 280px minimum, which is wider than the quiz card
     on the narrowest phones and pushed the options past the page edge. One
     full-width column keeps every label inside the card. */
  .quiz-options { grid-template-columns: 1fr; }
  .quiz-bar-row { grid-template-columns: 100px 1fr 34px; gap: 8px; }
  /* Wrap rather than truncate: the 100px label column is too narrow for the
     longer names, and the ellipsis hid which role a bar belonged to. */
  .quiz-bar-label { font-size: 11px; white-space: normal; }
}

/* Four controls do not fit on one phone-width line; two columns keep the
   primary action next to Back/Next instead of stranding "Start over" alone on
   a second row. Above this width they still fit on a single line. */
@media (max-width: 420px) {
  .quiz-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .quiz-actions .quiz-btn { width: 100%; }
}


/* ---- Top nav on the simulation page ----
   Matches the doc pages' nav so navigation is consistent everywhere.
   It sits above #app in the flex column; #app then takes the rest of
   the viewport height. */
body:has(> .top-nav) {
  height: 100vh;
  height: 100dvh;
}

.doc-nav.top-nav {
  flex-shrink: 0;
  position: sticky;
  top: 0;
  z-index: 100;
}

/* ---- Narrow-screen (mobile/tablet) top nav ----
   Below 900px five nav links plus the brand no longer leave room for the
   centred status indicator, so the nav becomes four stacked rows: the brand on
   its own line, the five nav links across two centred rows, and the status
   indicator centred on a final line below. This block MUST come after the base
   `.doc-nav` rule (which sets `display: flex`) — equal specificity means source
   order wins, so placed earlier the `display: grid` here would be silently
   overridden and the brand would wrap across multiple lines. It uses a single
   grid layout on ALL pages (index and the doc pages) so the brand and the nav
   links occupy identical positions everywhere.

   The six-column track is what lets five links sit on two balanced rows: three
   links spanning two columns each on the first row, then the remaining two
   centred over the four middle columns on the second. `nth-of-type` counts the
   anchors in the nav, where the brand is always the first. */
@media (max-width: 900px) {
  .doc-nav {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    justify-content: stretch;
    justify-items: stretch;
    align-items: center;
    column-gap: 6px;
    row-gap: 8px;
  }
  /* Brand on its own full-width line, left-aligned and on ONE line. */
  .doc-nav .brand {
    grid-column: 1 / -1;
    grid-row: 1;
    width: auto;
    margin: 0;
    text-align: left;
    white-space: nowrap;
  }
  /* Five links on two rows, each label centred in its track. Smaller side
     padding keeps the longer labels from crowding on the narrowest phones. */
  .doc-nav a.nav-link {
    text-align: center;
    white-space: nowrap;
    padding: 7px 4px;
  }
  /* Row 2: Simulation, Education, Family Roles. */
  .doc-nav a.nav-link:nth-of-type(2) { grid-area: 2 / 1 / 3 / 3; }
  .doc-nav a.nav-link:nth-of-type(3) { grid-area: 2 / 3 / 3 / 5; }
  .doc-nav a.nav-link:nth-of-type(4) { grid-area: 2 / 5 / 3 / 7; }
  /* Row 3: Help and Documentation, centred under the first row. */
  .doc-nav a.nav-link:nth-of-type(5) { grid-area: 3 / 2 / 4 / 4; }
  .doc-nav a.nav-link:nth-of-type(6) { grid-area: 3 / 4 / 4 / 6; }
  /* The status indicator sits on its own final line, centred. It is a real
     grid item spanning every column (rather than an absolutely positioned
     overlay), so its line height is reserved naturally and it can never
     collide with the links above it. */
  .doc-nav .nav-status {
    grid-column: 1 / -1;
    grid-row: 4;
    position: static;
    left: auto;
    top: auto;
    bottom: auto;
    transform: none;
    justify-self: center;
    margin: 0;
  }
}

/* ---- Mid-width top nav ----
   Between 901px and 1400px the five links and the brand still fit on one line,
   but a long status message ("Assessing how the parent takes it…") would
   overlap them if it stayed absolutely centred — measured at 1201px, the
   indicator's box reached into the "Simulation" link. Keep the indicator in
   flow at the end of the bar instead; above 1400px the centred layout has room
   again. `margin-left: auto` also right-aligns it if it wraps onto a second
   line on the narrowest tablets. */
@media (min-width: 901px) and (max-width: 1400px) {
  .doc-nav.top-nav .nav-status {
    position: static;
    left: auto;
    top: auto;
    transform: none;
    justify-self: auto;
    margin: 0 0 0 auto;
  }
}

/* ---- Landscape phones / short-and-wide viewports ----
   A phone in landscape is short but wide, so the stacked rows above (brand /
   links / status) waste what little vertical space there is, and a long status
   message on its own row still reads as cramped. When the viewport is short AND
   wide, fall back to a TWO-row grid: the brand sits on the left of the first
   row with the status indicator beside it on the right, and the five nav links
   share the second row.

   The brand is placed in columns 1-4 and the status in column 5, so each
   occupies its own grid track and a long status (e.g. "Backend unreachable")
   can never overlap the nav links or the brand no matter how it grows.

   Keyed off `orientation: landscape` plus a height cap so it only applies to
   genuinely short viewports (real phones rotated), not narrow desktop
   windows. Placed after the portrait grid block so it wins on phones in
   landscape. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  .doc-nav {
    /* This block also applies below 900px, where the portrait grid above is
       active, so the grid itself must be re-declared here with the landscape
       rows and columns. */
    display: grid;
    /* Five equal columns: row 2 places one nav link per column, and row 1
       spans the brand across columns 1-4 with the status in column 5. */
    grid-template-columns: repeat(5, 1fr);
    justify-content: stretch;
    align-items: center;
    column-gap: 6px;
    /* Two rows: brand + status on top, the five links beneath. */
    grid-template-rows: auto auto;
    row-gap: 6px;
    padding-top: 8px;
    padding-bottom: 8px;
  }
  /* Reset the portrait block's per-link `grid-area` placements. `:nth-of-type(n)`
     matches every link at the SAME specificity as `:nth-of-type(2)` above, so
     source order lets this later rule win; a plain `.nav-link` selector would
     be out-specified and the old column spans would survive. */
  .doc-nav a.nav-link:nth-of-type(n) {
    grid-row: 2;
    grid-column: auto;
  }
  /* The five nav links share row 2, one per equal column. The tighter type
     keeps the longest label inside a 480px-wide track. */
  .doc-nav a.nav-link {
    justify-self: stretch;
    font-size: 10.5px;
    padding: 7px 2px;
    letter-spacing: 0;
  }
  /* Brand sits on the left of row 1, spanning the first four columns. */
  .doc-nav .brand {
    grid-column: 1 / 5;
    grid-row: 1;
    justify-self: start;
    margin: 0;
  }
  /* Status sits on the SAME first line as the brand, in the final column,
     right-aligned so it hugs the right edge. Crucially it is reset from the
     absolutely-positioned desktop rule (left: 50%) to a normal static grid
     item — otherwise it stays pinned to the centre of the bar and overlaps
     the "Documentation" link. */
  .doc-nav .nav-status {
    grid-column: 5 / -1;
    grid-row: 1;
    position: static;
    left: auto;
    right: auto;
    top: auto;
    bottom: auto;
    transform: none;
    justify-self: end;
    margin: 0;
  }
}

/* ============================================================
   Prompt debug drawer (development only)
   ============================================================
   Rendered only when the server runs with DEBUG_PROMPTS on: the node is
   created by app.js on the first `debug` stream event, so none of this
   applies to a normal session. Fixed to an edge (bottom-right by default) so it
   never reflows the conversation, and it sits BELOW the top nav (z-index 100) so
   it cannot cover the navigation when the viewport is short. Which edge is the
   user's choice: the "Dock left / Dock right" button in the drawer header swaps
   the two classes below, and app.js remembers the choice. */
.debug-panel {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  width: min(640px, 46vw);
  max-height: 62vh;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 12px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--text);
}

/* Docked to the LEFT instead of the right. Only the horizontal anchor moves:
   the width, the vertical geometry, the shadow direction and the mobile rules
   below stay identical, so switching sides cannot reflow anything. */
.debug-panel.align-left {
  right: auto;
  left: 12px;
}

.debug-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  /* Title, count and three buttons share one row, and the panel is only 46vw
     wide. Wrapping is the graceful outcome on a narrow desktop window just
     above the phone breakpoint; without it the buttons spill past the panel
     edge, where they cannot be clicked. */
  flex-wrap: wrap;
}

.debug-panel.collapsed .debug-head { border-bottom: 0; }

.debug-title {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.debug-count {
  margin-right: auto;
  font-size: 11px;
  color: var(--muted);
}

.debug-btn {
  padding: 3px 8px;
  font: inherit;
  font-size: 11px;
  color: var(--text);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
}

.debug-btn:hover,
.debug-btn:focus-visible { border-color: var(--accent); }

.debug-body {
  overflow: auto;
  padding: 0 10px 8px;
}

.debug-panel.collapsed .debug-body { display: none; }

.debug-entry {
  padding: 6px 0;
  border-top: 1px solid var(--border);
}

.debug-entry:first-child { border-top: 0; }

.debug-entry summary {
  cursor: pointer;
  font-size: 11.5px;
  color: var(--warn);
}

.debug-opts {
  margin: 4px 0 2px;
  font-size: 11px;
  color: var(--muted);
}

.debug-msg {
  margin: 6px 0;
  padding: 6px 8px;
  background: var(--panel-2);
  border-radius: 8px;
  font: inherit;
  font-size: 11.5px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}

.debug-role {
  display: block;
  margin-bottom: 3px;
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Phones: full width, and shorter so the composer stays reachable. */
@media (max-width: 600px) {
  .debug-panel {
    left: 12px;
    right: 12px;
    width: auto;
    max-height: 45vh;
  }
  /* Full width wins over the side choice on small screens. Without this the
     left-docked variant would keep `right: auto` from the rule above and shrink
     to the width of its content instead of spanning the viewport. */
  .debug-panel.align-left { right: 12px; }
  /* ...and with no second edge to dock to, the control would be a dead button. */
  .debug-panel [data-act="side"] { display: none; }
}

/* ============================================================
   Phone overrides
   ------------------------------------------------------------
   These MUST stay at the END of the file. They used to sit near
   the top, which meant the base rules further down (same
   specificity, later in source order) silently won: the strategy
   hints kept `white-space: nowrap` + `text-overflow: ellipsis`
   and were cut off on phones, compare mode never collapsed to one
   column, and the touch-target sizing never applied. Media queries
   add no specificity, so source order is the only tie-breaker.
   ============================================================ */
@media (max-width: 768px) {

  /* ---- Main content ---- */
  main { width: 100%; }

  #messages {
    padding: 60px 16px 16px;
    gap: 14px;
  }

  .msg { max-width: 100%; }

  /* ---- Input area ---- */
  #inputArea {
    padding: 10px 16px max(12px, env(safe-area-inset-bottom));
  }

  #manualRow,
  #autoRow { max-width: 100%; }

  /* Keep the 2-column strategy grid on mobile, but stack name/hint. */
  .strategy-grid { gap: 6px; }

  .strategy-btn {
    padding: 7px 10px;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
  }

  .strategy-btn .strategy-name { font-size: 11.5px; }

  /* The hint must be allowed to WRAP here: on a phone the button is
     roughly half the screen wide, so a single nowrap line of hint
     text is always truncated mid-word. */
  .strategy-btn .strategy-hint {
    font-size: 10px;
    white-space: normal;
    line-height: 1.15;
  }
  .strategy-btn .strategy-hint::before { content: none; }

  /* Frustration row stays compact but the stage text can go. */
  .frustration-stage { display: none; }

  /* Both frustration labels keep the base fixed width so the two bars still
     line up. Do NOT trim it here: 140px clipped "PERSONAL FRUSTRATION" to an
     ellipsis on every phone. */

  /* ---- Compare mode: single column ---- */
  body.compare-layout #messages {
    grid-template-columns: minmax(0, 1fr);
  }

  body.compare-layout .compare-thread > * {
    grid-column: 1;
  }

  /* ---- End-of-run debrief ---- */
  /* The share bar is decorative: at phone width the name and count are enough,
     and dropping it keeps the three columns from wrapping. */
  .run-debrief { padding: 14px 14px 10px; }
  .debrief-move > summary {
    grid-template-columns: 12px minmax(0, 1fr) auto;
    gap: 8px;
  }
  .debrief-bar { display: none; }
  .debrief-cost {
    grid-template-columns: 1fr;
    gap: 10px;
    padding: 10px 12px 12px;
  }

  /* ---- Scenario picker ---- */
  .scenario-picker {
    max-width: 100%;
    padding: 0;
    margin: 0 auto;
  }

  .scenario-cards { grid-template-columns: 1fr; }

  .scenario-context {
    padding: 12px 16px;
    max-width: 100%;
  }

  /* ---- Touch targets ---- */
  input, select, textarea {
    padding: 12px 14px;
    font-size: 16px;
  }

  button {
    padding: 10px 14px;
    font-size: 13px;
  }
}

/* ---- Very narrow phones ---- */
@media (max-width: 400px) {
  #messages {
    padding-left: 12px;
    padding-right: 12px;
  }

  #inputArea {
    padding-left: 12px;
    padding-right: 12px;
  }

  .strategy-btn .strategy-name { font-size: 11px; }
  .strategy-btn .strategy-hint { font-size: 9.5px; }
}

