:root {
  --bg: #f2f6fb;
  --card: #ffffff;
  --ink: #1c2533;
  --muted: #6b7688;
  --accent: #2f6df0;
  --accent-ink: #ffffff;
  --success: #15803d;
  --success-ink: #ffffff;
  --error: #c0392b;
  --border: #d7dee8;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
}

.survey-shell { max-width: 720px; margin: 0 auto; padding: 32px 20px 64px; }

.survey-header {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 16px;
  font-size: 14px;
}
.survey-header-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.brand { font-weight: 600; }

/* ---- Header progress widget (two levels: scenario dots + named task stepper) ----
   Rendered into the shared header from `build_progress`, so it appears on every page.
   The macro row (label + scenario dots) always shows; the task stepper only inside a
   scenario block. */
.survey-progress-macro {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  white-space: nowrap;
}
.survey-progress-label { font-weight: 600; }
.survey-progress-dots { display: inline-flex; gap: 6px; }
.progress-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--border);
}
.progress-dot.is-done { background: var(--accent); opacity: 0.45; }
.progress-dot.is-current { background: var(--accent); box-shadow: 0 0 0 3px rgba(47, 109, 240, 0.18); }

/* Named task stepper: five equal segments with connector lines; the line leading into
   a reached (done/current) node is accented, so the "filled path" tracks progress. */
.survey-progress-tasks { width: 100%; }
.survey-progress-tasks ol {
  list-style: none;
  display: flex;
  margin: 0 auto;
  padding: 0;
  max-width: 620px;
}
.progress-task {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
}
.progress-task::before {
  content: "";
  position: absolute;
  top: 9px;
  right: 50%;
  width: 100%;
  height: 2px;
  background: var(--border);
  z-index: 0;
}
.progress-task:first-child::before { display: none; }
.progress-task.is-done::before,
.progress-task.is-current::before { background: var(--accent); }
.progress-task-marker {
  position: relative;
  z-index: 1;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 2px solid var(--border);
  background: var(--card);
  display: grid;
  place-items: center;
}
.progress-task.is-done { color: var(--ink); }
.progress-task.is-done .progress-task-marker {
  background: var(--accent);
  border-color: var(--accent);
}
.progress-task.is-done .progress-task-marker::after {
  content: "";
  width: 6px;
  height: 10px;
  margin-top: -2px;
  border: solid var(--accent-ink);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.progress-task.is-current { color: var(--accent); font-weight: 700; }
.progress-task.is-current .progress-task-marker {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(47, 109, 240, 0.18);
}
.progress-task.is-current .progress-task-marker::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}
.progress-task-name { line-height: 1.2; }

@media (max-width: 540px) {
  .survey-header-top { flex-direction: column; align-items: flex-start; gap: 6px; }
  .progress-task { font-size: 11px; }
  .progress-task-name { overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
}

.survey-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 28px 32px;
  box-shadow: 0 1px 3px rgba(20, 30, 50, 0.06);
}

h1 { margin-top: 0; font-size: 22px; }

.instructions { color: var(--ink); }
.instructions p { margin: 0 0 12px; }
.muted { color: var(--muted); font-size: 14px; }
.optional { color: var(--muted); font-weight: 400; font-size: 13px; }
.help { color: var(--muted); font-size: 13px; margin: 0 0 8px; }

.survey-form { margin-top: 8px; }

/* Intro line under a questionnaire title: reads as a subtitle and keeps clear space
   above the first field so the prompt doesn't collide with the first question's divider. */
.form-lead {
  margin: -2px 0 22px;
  color: var(--muted);
  font-size: 15px;
  max-width: 60ch;
}

/* Final "all done" screen: a quiet, reassuring confirmation chip under the closing line. */
.done-saved {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 0;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #f7f9fc;
  font-weight: 600;
}
.done-saved::before { content: "\2713"; color: var(--accent); font-weight: 700; }

/* On the form screens, let the title/lead whitespace do the separating instead of a rule
   pinned right under it. (Scoped so the shared _questions partial in T4/T5 is untouched.) */
body.questionnaire-page .survey-form fieldset.question:first-of-type {
  border-top: none;
  padding-top: 4px;
}

fieldset.question {
  border: none;
  border-top: 1px solid var(--border);
  padding: 18px 0 4px;
  margin: 0;
}
fieldset.question legend { font-weight: 600; padding: 0; }
fieldset.has-error legend { color: var(--error); }

input[type="number"], input[type="email"], textarea, select.dropdown, .other-input {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  margin-top: 8px;
}
textarea { resize: vertical; }
.other-input { margin-top: 6px; }

/* Short inputs read better capped than stretched the full card width; textareas stay full. */
fieldset.question input[type="number"],
fieldset.question select.dropdown,
fieldset.question .other-input {
  max-width: 440px;
}

.radio-row { display: flex; gap: 20px; margin-top: 8px; }

.scale { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.scale-point { display: flex; flex-direction: column; align-items: center; font-size: 13px; }
.scale-end { color: var(--muted); font-size: 13px; max-width: 110px; }

.slider-row { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.slider-row input[type="range"] { flex: 1; }
.slider-row output { min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; }

.consent-check { display: flex; gap: 10px; align-items: flex-start; margin: 18px 0; }
.consent-check input { margin-top: 3px; }
.consent-optional { margin-top: 4px; color: var(--ink); }
.consent-optional .optional { display: block; margin-top: 2px; }

/* Consent page: full information text in a scroll-gated container. */
body.consent-page .survey-shell { max-width: 1040px; }
.consent-subtitle { margin: -6px 0 20px; font-weight: 600; color: var(--ink); }
.consent-meta {
  margin: 0 0 22px;
  padding: 16px 20px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #f7f9fc;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px 28px;
  font-size: 14px;
}
.consent-meta div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.consent-meta dt {
  margin: 0;
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.consent-meta dd { margin: 0; word-break: break-word; }
.consent-scroll-hint {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
}
.consent-scroll-hint.is-done { color: #0b6a4f; }
.consent-scroll-hint.is-done::before { content: "\2713  "; }
.consent-doc {
  max-height: 460px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 20px 28px;
  background: #fcfdff;
}
/* Keep the reading measure comfortable even though the card is wide. */
.consent-doc > * { max-width: 760px; }
.consent-doc h2 { font-size: 16px; margin: 22px 0 6px; }
.consent-doc h2:first-of-type { margin-top: 8px; }
.consent-doc p { margin: 0 0 12px; }
.consent-doc ul { margin: 0 0 12px; padding-left: 22px; }
.consent-doc li { margin: 4px 0; }
.consent-doc-end {
  margin: 18px 0 0;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}
.btn-primary:disabled {
  background: var(--border);
  color: var(--muted);
  cursor: not-allowed;
  filter: none;
}

.field-error { color: var(--error); font-size: 13px; margin: 8px 0 0; }

/* Enrollment (/join) e-mail field: labeled block with a comfortably sized input. */
.enroll-field { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.enroll-field > span { font-weight: 600; }
.enroll-field input[type="email"] {
  max-width: 420px;
  padding: 12px 14px;
  font-size: 16px;
  margin-top: 0;
}

/* A rejected /join submission (direct mode only: email mode has one neutral response and no
   errors to show). Same red as .field-error, but page-level rather than beside one input. */
.enroll-error {
  color: var(--error);
  font-weight: 600;
  border-left: 3px solid var(--error);
  padding-left: 12px;
  margin: 0 0 16px;
}

/* The personal study link, shown once and only here (direct mode). RED on the supervisor's
   request: the participant has to notice it is theirs to keep, since nothing else delivers it. */
.enroll-link-callout {
  display: flex;
  /* Column, not a wrapping row: the link is one unbreakable word wider than most cards, so a row
     layout wraps it mid-token and strands a character or two on the second line. */
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin: 18px 0;
  padding: 16px;
  border: 1px solid var(--error);
  border-radius: 8px;
  background: #fff;
}
.enroll-link {
  color: var(--error);
  font-weight: 700;
  /* 16px, not 17: at 17 the real link (https://isler-survey.ivia.ch/survey/<22-char token>) is a
     few pixels wider than the card and break-all strands its last character on a line of its own,
     which reads as a rendering fault. A narrow window still wraps it, correctly. */
  font-size: 16px;
  /* The token makes this one unbreakable word; without break-all it overflows the card on a
     narrow window instead of wrapping. */
  word-break: break-all;
  user-select: all;
}

.actions { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border: none;
  border-radius: 8px;
  padding: 11px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-primary:hover { filter: brightness(1.05); }
/* Four buttons are actually <a> (the two retry links, "Start now", "Request a new link"), and
   an anchor keeps the browser's underline -- which the copy conventions reserve for links, not
   for the primary action. Anchors only: a <button> has no underline to remove. */
a.btn-primary, a.btn-secondary { text-decoration: none; }
.btn-secondary {
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 11px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-secondary:hover { background: #f4f6fb; }

/* Affirmative "this is already correct" action, e.g. accepting the AI's T4 output.
   Green so it reads as the approve path rather than a lesser alternative. */
.btn-success {
  background: var(--success);
  color: var(--success-ink);
  border: none;
  border-radius: 8px;
  padding: 11px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-success:hover { filter: brightness(1.08); }

/* The "stop, this isn't working" exit, e.g. giving up on T5 refinement. */
.btn-danger {
  background: var(--error);
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 11px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-danger:hover { filter: brightness(1.08); }

/* Tinted-red "discard and restart" action, e.g. T5's start over from the base model. Red because
   it discards work (the red = stop convention), but TINTED rather than solid so it does not
   compete with the solid-red give-up exit further down the same page. It replaced .btn-secondary
   there, which was white-on-white and easy to miss. */
.btn-caution {
  background: #fdf0ee;
  color: #a5342a;
  border: 1px solid #e8b4ac;
  border-radius: 8px;
  padding: 11px 22px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn-caution:hover { background: #fbe3df; border-color: #dc9a90; }

/* Playground page footers: navigation differs per view. Sketch = one forward button, bottom
   right. Model = back-link bottom left + the one-way exit bottom right. */
.pg-footer { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.pg-footer-end { justify-content: flex-end; }
.pg-footer-split { justify-content: space-between; }
.pg-end-form { margin: 0; text-align: right; }
.pg-end-note { margin: 6px 0 0; }

/* Pill nav buttons for moving between the two practice pages: no underline, arrow set off in the
   accent colour, subtle lift on hover. */
.pg-nav {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 10px 20px;
  font-weight: 600;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.pg-nav:hover { background: #f4f6fb; border-color: var(--accent); }
.pg-nav-arrow { font-size: 18px; line-height: 1; color: var(--accent); }

code { background: #eef2f8; padding: 1px 6px; border-radius: 5px; font-size: 13px; }

/* Scenario boundary screen: a between-scenario "chapter divider" signpost. The
   "Scenario X of N" label + dots now live in the shared header progress widget. */
.scenario-tasks-lead { font-weight: 600; margin: 18px 0 0; }

.scenario-task-list {
  list-style: none;
  counter-reset: scenario-task;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.scenario-task-list li {
  counter-increment: scenario-task;
  position: relative;
  padding: 14px 16px 14px 60px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fcfdff;
}
.scenario-task-list li::before {
  content: counter(scenario-task);
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 15px;
  font-weight: 700;
}
.scenario-task-list li strong { font-weight: 700; }

/* Task hand-off pages: a small "Task N of 5" eyebrow above the title. */
.task-eyebrow {
  display: inline-block;
  margin-bottom: 8px;
  padding: 5px 14px;
  border-radius: 999px;
  background: #eaf1fe;
  color: var(--accent);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* The key action on a task page, emphasised inline. Bold only: an underline
   (especially a coloured one) reads as a hyperlink. */
.instruction-key {
  font-weight: 700;
}

/* Motivating statement: a labelled callout so the participant knows what this sentence is. */
.motivation-callout {
  margin: 4px 0 20px;
  padding: 14px 18px;
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 10px;
  background: #f7f9fc;
}
.motivation-label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 6px;
}
.motivation-statement { margin: 0; font-size: 17px; font-weight: 600; color: var(--ink); }

/* Column/legend caption. Shared by T2's brief band and the T1/T5 sketch-menu legend: it always
   sits OUTSIDE the frame it labels, so a caption and its box never share a border. */
.t2-brief-label,
.sketch-options-label {
  display: block;
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

/* Sketch-menu options (T1 + T5): what each Sketch ▸ choice does, in the quiet single-framed
   style established for T2's toolbar legend — small type, no per-row boxes — so the task pages
   read as the same page shape and the 780px viewer stays close to the fold. The name column is
   wider than T2's (86px) because "New 3-View Sketch" is a longer label than any tool name. */
.sketch-options,
.views-legend {
  list-style: none;
  margin: 0 0 4px;
  padding: 4px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fcfdff;
  font-size: 13px;
  line-height: 1.4;
}
.sketch-options li,
.views-legend li {
  display: grid;
  gap: 10px;
  align-items: baseline;
  padding: 6px 0;
  border-top: 1px solid var(--border);
}
/* Name columns are sized to their own longest label: "New 3-View Sketch" vs "Section cut". */
.sketch-options li { grid-template-columns: 150px minmax(0, 1fr); }
.views-legend li { grid-template-columns: 96px minmax(0, 1fr); }
.sketch-options li:first-child,
.views-legend li:first-child { border-top: 0; }
.sketch-option-name {
  font-weight: 700;
  color: var(--accent);
}
.sketch-option-desc { color: var(--muted); }
/* The "view-only, never the model" reassurance closing the Views legend. A full-width footer row
   rather than a name/description pair: it is a caveat, not another control. */
.views-legend li.legend-note {
  grid-template-columns: 1fr;
  font-size: 12px;
  font-style: italic;
  color: var(--muted);
}
@media (max-width: 640px) {
  .sketch-options li,
  .views-legend li { grid-template-columns: 1fr; gap: 2px; }
}

/* The two-legend band on T1/T5: sketch menu beside the Views pad, so explaining a second control
   does not push the viewer back below the fold. Same shape as T2's .t2-brief. */
.legend-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 20px;
  /* stretch (not start): the two legends have different row counts, and letting the shorter box
     end high leaves a ragged notch above the viewer. Equal boxes read as one band. */
  align-items: stretch;
  /* Generous top margin: the band follows the instruction sentence, and at the paragraph's own
     12px it read as one crowded block rather than prose followed by reference material. */
  margin: 26px 0 14px;
}
@media (max-width: 900px) {
  .legend-band { grid-template-columns: 1fr; }
}
/* Column wrappers are flex so their framed list can stretch: the legends have different row
   counts, and boxes of unequal height leave a ragged gap above the viewer. */
.views-legend-wrap,
.sketch-options-wrap {
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.views-legend-wrap .views-legend,
.sketch-options-wrap .sketch-options { flex: 1; }

/* T1 sketch hand-off: same shape as T2 — a compact reference band, then the viewer at FULL
   shell width, then the saved-sketch confirmation. Shell matches T2/T3 (was 1180px, which
   made T1 the odd one out among the viewer pages). Unlike T2, the sketch thumbnail stays
   BELOW the viewer: here it confirms what you just drew rather than serving as reference
   while you work, and the reading order after saving runs on down to the prompt + submit. */
body.t1-page .survey-shell { max-width: 1320px; }
.t1-viewer-wrap { margin: 18px 0 8px; }
.t1-viewer-frame {
  width: 100%;
  height: 780px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
}
.t1-sketch-error { margin: 0 0 12px; }
.t1-saved-note {
  margin: 16px 0 0;
  padding: 10px 14px;
  border-radius: 8px;
  background: #e6f4ec;
  color: #0b6a4f;
  font-weight: 600;
}
.t1-sketch-preview { margin: 16px 0 0; }
.t1-sketch-preview-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
.t1-sketch-thumb {
  display: block;
  width: 280px;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}

/* T2 build-in-3D hand-off: widen the shell. A "brief" band on top carries the T1 sketch
   (the main reference, so it gets the larger share) beside a compact toolbar legend; the
   editable viewer then spans the FULL shell width below it, since a half-width 3D editor
   was too cramped to model in. The viewer must stay wide (>=1080px) or AIslerAPP's mobile
   media query wraps/clips the header — full width satisfies that by construction. */
body.t2-page .survey-shell { max-width: 1320px; }
.t2-structure-error { margin: 0 0 12px; }
/* The sketch column is `auto` (shrink-to-fit the height-capped image) rather than a fraction,
   so the legends sit directly beside the sketch instead of across a gap of dead space. The second
   column holds a .legend-band (Toolbar + Views panel) and so takes the remaining width: two
   legends at a fixed 420px would be unreadably narrow, and letting the brief grow a third top-level
   column would leave dead space on the pages where no sketch is rendered. */
.t2-brief {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  justify-content: start;
  gap: 20px;
  align-items: start;
  margin: 18px 0 0;
}
/* The band's own margin spaces it from T1/T5 prose; inside the brief the brief's margin already
   does that, and any extra would break the shared top baseline with the sketch caption. */
.t2-brief .legend-band { margin: 0; }
@media (max-width: 900px) {
  .t2-brief { grid-template-columns: 1fr; }
}
.t2-sketch-ref { margin: 0; }
/* .t2-brief-label ("Your sketch" / "Toolbar") is defined with .sketch-options-label above.
   Each sits OUTSIDE its column's frame, so the two headers share a baseline and the two
   framed boxes below them start at the same y. */
/* Height-capped to roughly the legend card's height, so the two read as one band and the
   full-width viewer below stays close to the fold. */
.t2-sketch-ref-img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 320px;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}

/* Toolbar legend: deliberately quiet next to the sketch — small type, no per-row boxes
   (contrast the roomier .sketch-options used on T1/T5). The frame is on the list, not on
   .t2-toolbar-guide, so the "Toolbar" header stays outside it — mirroring the sketch column,
   where the caption sits above the image's frame. */
.t2-toolbar-guide { min-width: 0; }
.t2-tool-list {
  list-style: none;
  margin: 0;
  padding: 4px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fcfdff;
  font-size: 13px;
  line-height: 1.4;
}
/* The name column is wide enough that NO tool name wraps ("Measure Distance", the longest, needs
   143px). That is what makes the legend read evenly: with baseline alignment a one-line name sits
   on the description's first line, so every keyword lands at the same height in its row. Let a name
   wrap and it becomes a two-line block that visually centres itself against the description, which
   is what made the list look ragged. So: adding a tool name longer than this column re-introduces
   the raggedness — widen the column with it. */
.t2-tool-list li {
  display: grid;
  grid-template-columns: 148px minmax(0, 1fr);
  gap: 10px;
  align-items: baseline;
  padding: 6px 0;
  border-top: 1px solid var(--border);
}
.t2-tool-list li:first-child { border-top: 0; }
/* Group boundaries mirror the vertical .t2-sep rules in the viewer toolbar (index.html
   #toolbar-survey-edit), so the legend reads in the same blocks the buttons are arranged in.
   Extra space does the grouping, not a heavier rule: .t2-sep is itself only var(--border), and
   the legend is meant to stay quiet next to the sketch. */
.t2-tool-list li.is-group-start {
  margin-top: 6px;
  padding-top: 12px;
}
.t2-tool-name { font-weight: 700; color: var(--accent); }
/* Delete is red here and in the viewer toolbar (.t2-danger in styles.css) — red = destructive,
   matching the survey's fixed button-colour meanings. */
.t2-tool-name.is-danger { color: var(--error); }
.t2-tool-desc { color: var(--muted); }
/* Undo/Redo are shown as the same glyphs the viewer toolbar uses (index.html #t2-undo /
   #t2-redo), so the legend and the button are recognisably the same thing. Keyed on an explicit
   class, NOT on :first-child: the glyph row stopped being first when the "Selecting" row landed
   above it (2026-08-18), and a positional selector silently blew the word "Selecting" up to 17px
   with letter-spacing meant for two arrows. */
.t2-tool-list li.is-glyph-row .t2-tool-name { font-size: 17px; letter-spacing: 0.12em; }
.t2-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
@media (max-width: 640px) {
  .t2-tool-list li { grid-template-columns: 1fr; gap: 2px; }
}

/* The gap above the viewer lives HERE, not on the block above it, because two different pages sit
   above it: T2's .t2-brief (sketch + legend) and the playground's .instructions (legend only).
   Owning it on the viewer keeps both pages at the same distance instead of only whichever one got
   the bottom margin — the playground legend used to sit flush against the iframe. */
.t2-viewer-wrap { min-width: 0; margin: 24px 0 8px; }
.t2-viewer-frame {
  width: 100%;
  height: 780px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
}

/* T3 describe-your-modification: the participant's own record (modified-3D view + T1 sketch
   + prompt) beside a required description textarea. The sketch and the 3D model are roughly
   equally relevant references, so the two columns share the width evenly — unlike T2 the
   viewer can go narrow because mode=view leaves the header empty (Sketch menu hidden) and the
   survey-inspect guards still pin it, so the <=1080px reflow can't clip anything. */
body.t3-page .survey-shell { max-width: 1320px; }
.t3-description-error { margin: 0 0 12px; }
/* The 3D model is what the description is written ABOUT; the sketch is a secondary reminder
   of the intent. So the viewer takes roughly two thirds and the sketch column is capped -
   an even split made the sketch read as the primary subject. */
.t3-workspace {
  display: grid;
  grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  margin: 18px 0 8px;
}
@media (max-width: 1180px) {
  .t3-workspace { grid-template-columns: 1fr; }
}
.t3-reference {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.t3-ref-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
.t3-sketch-ref { margin: 0; }
.t3-sketch-ref-img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}
.t3-prompt-ref { margin: 0; }
.t3-prompt-text {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  white-space: pre-wrap;
  word-break: break-word;
}
.t3-describe-prompt {
  margin: 0;
  color: var(--ink);
  line-height: 1.5;
}
.t3-viewer-wrap { min-width: 0; }
/* Height floor: mode=view carries the section-cut + story panels, so the Views pad needs a
   404px shell (+24px offsets) = a >=492px frame or its bottom control is clipped away.
   600px clears that and keeps the model readable next to the sketch. */
.t3-viewer-frame {
  width: 100%;
  height: 600px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
}

/* T4 rate-the-AI: one screen combining the T1 sketch/prompt reference, two read-only viewers
   (the VLM's modification as the larger primary view + the participant's own T2 model for
   comparison), and the rating questionnaire. Both viewers use mode=view, which leaves the header
   empty and pins it via the survey-inspect guards, so the side-by-side pair can go narrow safely. */
body.t4-page .survey-shell { max-width: 1400px; }
.t4-stub-banner {
  margin: 0 0 14px;
  padding: 10px 12px;
  border: 1px solid #e0b400;
  border-radius: 8px;
  background: #fff8e1;
  color: #7a5d00;
  font-size: 14px;
}
/* Section dividers on the rating page so the three blocks (what you gave the AI / the two
   models / your rating) read as distinct steps rather than one long stack. */
.t4-section-label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin: 24px 0 10px;
}
.t4-reference {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: start;
  margin: 0 0 4px;
}
.t4-sketch-ref { margin: 0; flex: 0 1 320px; min-width: 0; }
.t4-prompt-ref { margin: 0; flex: 1 1 320px; min-width: 0; }
.t4-ref-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
/* Which viewer is whose is the whole point of T4, and the two labels differ only in wording. The
   label is already 600/muted, so the emphasised words need BOTH a heavier weight and full ink to
   read as distinct at a glance. */
.t4-ref-label strong {
  font-weight: 800;
  color: var(--ink);
}
.t4-sketch-ref-img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}
.t4-prompt-text {
  margin: 0;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  white-space: pre-wrap;
  word-break: break-word;
}
.t4-viewers {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 16px;
  align-items: start;
  margin: 0 0 4px;
}
/* The AI's result is the thing being rated — give its frame a faint accent ring so the eye
   lands there first, with the participant's own model as the quieter comparison. */
.t4-viewer-primary .t4-viewer-frame {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
@media (max-width: 1180px) {
  .t4-viewers { grid-template-columns: 1fr; }
}
.t4-viewer-wrap { min-width: 0; }
.t4-viewer-frame {
  width: 100%;
  height: 540px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
}

/* T4 live-run waiting + error states */
.t4-generating {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  margin: 32px auto;
  max-width: 520px;
}
.t4-generating-title { margin: 0; font-size: 20px; font-weight: 600; }
.t4-generating-sub { margin: 0; color: var(--muted); font-size: 15px; }
.t4-generating .t4-sketch-ref { margin-top: 8px; flex: 0 1 320px; }
/* On the waiting screen the sketch + prompt stack in one left-aligned column,
   full-width within the centered 520px waiting card. */
.t4-reference-generating {
  flex-direction: column;
  flex-wrap: nowrap;
  align-self: stretch;
  text-align: left;
}
.t4-reference-generating .t4-sketch-ref,
.t4-reference-generating .t4-prompt-ref { flex: 1 1 auto; width: 100%; }
.t4-spinner {
  width: 42px;
  height: 42px;
  border: 4px solid var(--border);
  border-top-color: var(--accent, #2d6cdf);
  border-radius: 50%;
  animation: t4-spin 0.9s linear infinite;
}
@keyframes t4-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .t4-spinner { animation: none; }
}
.t4-error {
  margin: 32px auto;
  max-width: 520px;
  text-align: center;
  padding: 18px 16px;
  border: 1px solid #d98c8c;
  border-radius: 10px;
  background: #fdeded;
}
.t4-error-title { margin: 0 0 6px; font-size: 18px; font-weight: 600; color: #8a2a2a; }
.t4-error-sub { margin: 0 0 10px; color: #7a3b3b; font-size: 15px; }
.t4-error-detail {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: #7a3b3b;
  word-break: break-word;
}
/* What to do if the retry fails too. Sits BELOW the button: the first thing to try is the
   button, and this is only for the second failure. */
.t4-error-help { margin: 14px 0 0; color: #7a3b3b; font-size: 13px; }
.t4-error-help a { color: #7a3b3b; }
/* The raw exception, collapsed. Kept only so a participant's screenshot is diagnosable; it is
   also in vlm_status.json and the pod log, which is where it is actually read from. */
.t4-error-more { margin: 12px 0 0; text-align: left; }
.t4-error-more > summary {
  cursor: pointer;
  color: #7a3b3b;
  font-size: 12px;
  text-align: center;
}

/* T5 iterative refinement: the sketchable working viewer stays full-width (mode=inspect needs
   the width or AIslerAPP's mobile media query clips the header), with the base model shown as a
   shorter full-width read-only reference panel above it. */
body.t5-page .survey-shell { max-width: 1180px; }
/* Header row: the "Task 5 of 5 · Refine" eyebrow (left) and the round counter (right) on one
   line, matching T1's eyebrow vocabulary. */
.t5-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.t5-round-pill {
  display: inline-block;
  padding: 5px 14px;
  border-radius: 999px;
  background: #eef2f8;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.t5-ref-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
/* Scenario goal + compact base reference in one horizontal band. A small read-only base-model
   reminder sits on the left; the motivating statement (the actual end goal) sits on the right in
   the same labelled callout used on T1. mode=view gives the iframe an empty header, so it may go
   narrow (same exception T3 relies on). */
.t5-viewer-wrap { margin: 14px 0 8px; }
/* Review phase only: the instructions sit directly above the viewer label with no intervening
   controls, so the default 14px reads as cramped. The sketch-phase wrap keeps its tighter gap. */
.t5-viewer-review { margin-top: 26px; }
/* Sketch-phase viewer header: the label and the "start over from base" escape hatch on one
   row, so the escape hatch is visible *above* the viewer (before the participant sketches),
   not buried below it. */
.t5-viewer-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.t5-viewer-head .t5-ref-label { margin-bottom: 0; }
.t5-startover-form { margin: 0; }
.t5-startover-btn { padding: 7px 14px; font-size: 14px; }
.t5-startover-note { color: var(--muted); font-size: 13px; font-weight: 600; }
.t5-viewer-frame {
  width: 100%;
  height: 780px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
}
.t5-sketch-error { margin: 0 0 12px; }
.t5-cap-note { margin: 0; color: var(--muted); font-size: 14px; }

/* Commit point: the two correction channels side by side. The sketch slot is ALWAYS rendered
   (empty as a dashed placeholder, filled with the thumbnail once saved) so the sketch option is
   visible where the participant actually commits, the Sketch menu being far above in the viewer's
   top bar. Fixed-width column, muted, no colour of its own: it must read as an equal option next
   to the textarea, never as a nag or as the primary action (modality is a dependent variable). */
.t5-correction-grid {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  margin-top: 10px;
}
.t5-sketch-slot { margin: 0; }
/* Both slot states carry an explicit `display`, which would otherwise beat the UA's
   `[hidden] { display: none }` and leave the placeholder (and the empty img's alt text) on screen. */
.t5-sketch-slot [hidden] { display: none; }
.t5-sketch-slot-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
.t5-sketch-slot.is-filled .t5-sketch-slot-label { color: var(--success); }
/* Height-matched to the 6-row textarea beside it so the two channels form one band. */
.t5-sketch-slot-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 148px;
  padding: 12px 16px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  background: #fbfcfe;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}
.t5-sketch-thumb {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
}
.t5-correction-text-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}
.t5-correction-text textarea { margin-top: 0; }
/* Narrow viewports: stack, sketch slot first (it mirrors the reading order above). */
@media (max-width: 720px) {
  .t5-correction-grid { grid-template-columns: minmax(0, 1fr); }
  .t5-sketch-slot { max-width: 320px; }
}

/* ===================================================================== *
 * PUBLIC ENTRY PAGES (/join and the link page) -- institutional skin.
 *
 * Scoped to ``body.enroll-page`` ONLY. The task pages (T1-T5, consent,
 * questionnaire) keep the existing survey look on purpose: this is the
 * front door a stranger arrives at from a forwarded link, and it has to
 * match ``backend/landing.html``, which is a separate hardcoded file. If
 * you change a colour or a logo size here, change it there too.
 *
 * Deliberately light-only, like the landing page: neither the BRG mark (a
 * JPEG with a baked white background) nor the IVIA mark has a negative
 * variant, so a dark ground would need hand-keyed logo files.
 * ===================================================================== */
body.enroll-page {
  --bg: #ffffff;
  --card: #ffffff;
  --ink: #101010;
  --muted: #525252;
  --accent: #215caf;          /* ETH blue, replacing the survey's #2f6df0 */
  --border: #d9d9d9;
  font-family: "Helvetica Neue", Helvetica, Arial, "Segoe UI", system-ui, sans-serif;
}

/* The logo bar carries the identity here, so the "AIsler - User Study" brand line
   would be a second, weaker masthead directly beneath it. */
body.enroll-page .survey-header { display: none; }

/* --- Institutional masthead (partial: _institutional_bar.html) --------- */
.inst-bar { border-bottom: 1px solid #d9d9d9; }
.inst-bar-inner {
  max-width: 1040px;
  margin: 0 auto;
  padding: 18px 20px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px 26px;
}
/* Sized by optical cap height, not by box height: the ETH file includes its
   protection zone, BRG is a bare wordmark and so reads larger than its box, and
   IVIA's letters sit inside a drawn frame and so read smaller. */
.inst-logo-eth { height: 64px; width: auto; display: block; margin-left: -21px; }
.inst-logo-sep { width: 1px; align-self: stretch; margin: 6px 0; background: #d9d9d9; }
.inst-logo-labs { display: flex; align-items: center; gap: 26px; }
.inst-logo-ivia { height: 36px; width: auto; display: block; }
.inst-logo-brg { height: 20px; width: auto; display: block; }
/* design++ is the odd mark out and cannot follow the optical-cap-height rule the
   other three do: it is STACKED (two text lines, so one line reads at a third of the
   box) and FULL-BLEED (no protection zone in the file). Matched to the two wordmarks
   it collapses into an illegible smudge, so it is pinned to the ETH BOX instead, at
   both breakpoints. That is the largest it can be for free: the bar's height is set
   by the 64px ETH box, so 64px costs no bar height and 68px costs 4. */
.inst-logo-designpp { height: 64px; width: auto; display: block; }

/* --- Flatten the card into a page ------------------------------------- */
body.enroll-page .survey-shell { max-width: 1040px; padding: 40px 20px 48px; }
body.enroll-page .survey-card {
  border: none;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
body.enroll-page h1 {
  font-size: 34px;
  line-height: 1.1;
  letter-spacing: -0.022em;
  font-weight: 700;
  margin-bottom: 10px;
}
/* The blue rule under the title is the one device carried over from the landing
   page's masthead; it is what makes the two pages read as one site. */
body.enroll-page h1::after {
  content: "";
  display: block;
  height: 3px;
  background: var(--accent);
  margin-top: 14px;
}
body.enroll-page .survey-card > p { max-width: 680px; }

/* --- Square every rounded corner in the funnel ------------------------- */
body.enroll-page .btn-primary,
body.enroll-page .btn-secondary,
body.enroll-page .enroll-field input[type="email"],
body.enroll-page .enroll-link-callout,
body.enroll-page .done-saved {
  border-radius: 0;
}
body.enroll-page .btn-primary {
  border: 1px solid var(--accent);
  font-weight: 700;
  padding: 13px 26px;
}
body.enroll-page .btn-primary:hover { filter: none; background: #1a4a8f; border-color: #1a4a8f; }
body.enroll-page .enroll-field input[type="email"] { border: 1px solid #b6b6b6; }
body.enroll-page .enroll-field input[type="email"]:focus {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}

/* --- Responsibility footer (partial: _institutional_footer.html) -------- */
.inst-footer {
  max-width: 1040px;
  margin: 0 auto;
  padding: 0 20px 56px;
  font-size: 14px;
  color: #525252;
  font-family: "Helvetica Neue", Helvetica, Arial, "Segoe UI", system-ui, sans-serif;
}
/* The rule sits on the grid, not on .inst-footer: on the padding box it overhung the
   text column by the 20px gutter at each end. */
.inst-contacts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  border-top: 3px solid #101010;
  padding-top: 26px;
}
.inst-contacts h3 {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #6e6e6e;
  font-weight: 700;
  margin: 0 0 8px;
}
.inst-contacts p { margin: 0; line-height: 1.5; }
/* The Supervision cell holds two people; every other cell holds one. */
.inst-contacts p + p { margin-top: 14px; }
.inst-contacts .inst-name { color: #101010; font-weight: 600; }
.inst-contacts a { color: #215caf; text-decoration: none; word-break: break-word; }
.inst-contacts a:hover { text-decoration: underline; }
/* Affiliations are VERIFICATION links, not contact routes, and there are nine of them
   against four addresses -- inheriting the ETH blue above would make every supervisor's
   affiliation line louder than their own name. Blue stays reserved for "reach me"; a
   quiet rule underneath says "who we are, click to check". */
.inst-contacts a.inst-affil {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: #b8b8b8;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.inst-contacts a.inst-affil:hover { text-decoration-color: currentColor; }

@media (max-width: 620px) {
  .inst-logo-eth { height: 54px; margin-left: -18px; }
  .inst-logo-sep { display: none; }
  .inst-logo-ivia { height: 31px; }
  .inst-logo-brg { height: 17px; }
  .inst-logo-designpp { height: 54px; }
  body.enroll-page h1 { font-size: 28px; }
  .inst-contacts { grid-template-columns: 1fr; gap: 20px; }
}
