/* quiz.dobsinsky.xyz
 *
 * Design brief, from SPEC: this is filled in on a phone, often lying down, by
 * someone who feels awful. So: one question per screen, nothing below 56px
 * that has to be tapped, no animation that moves the thing you are aiming at.
 *
 * Palette anchor: endometriosis-awareness yellow - the condition's own ribbon
 * colour, chosen so a link shared in a DM reads as a cause rather than a
 * generic product. Because bright yellow cannot carry text on a near-white
 * ground, the identity is split: --accent is a text-safe deep gold, and
 * --accent-solid is the ribbon yellow used only as a fill under dark ink (see
 * the :root comment). The earlier "organic" cream+terracotta system was
 * dropped: that specific pairing has become the most recognisable "AI default"
 * skin, which is the wrong signal for original student research.
 *
 * A researcher may still override per survey via the editor's colour wheel;
 * js/palette.js derives the rest from that one hue, clamping lightness until
 * the contrast floors hold (tools/palette.test.js proves this over 1,448 seed
 * hues). The :root values below are the NULL-accent default - what a survey
 * that has picked no colour uses - expressed literally here rather than derived.
 *
 * Body face is still Figtree (full Czech coverage; Caprasimo was dropped for
 * missing diacritics - see the @font-face comment). A grotesque display face
 * with verified ě ů ž č ř ď ť ň coverage is a deliberate next step, not done
 * here, precisely so it does not repeat the broken-glyph regression.
 */

/* Caprasimo (the mock's display face) was tried and dropped: its latin-ext
   file is missing the glyphs for ě ů ž č ř ď ť ň - only š is actually drawn,
   despite Google's declared unicode-range claiming the whole block. Since
   headings render database-authored Czech prompt text (SPEC: full CZ/EN
   parity is a hard constraint), that is not a style call, it is broken text -
   a fallback font silently substituted per-glyph mid-word, which is worse
   than not trying at all. Figtree, which does have full Czech coverage,
   carries both roles now: body at 400, headings at 700. */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/fonts/figtree-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 300 800;
  font-display: swap;
  src: url("/fonts/figtree-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0300-036F, U+1E00-1EFF;
}

:root {
  --bg:        #fbfaf7;
  --bg-raised: #f3f1ea;
  --ink:       #1c1b19;
  --ink-soft:  #5c5852;
  /* Endometriosis-awareness yellow is the anchor - the disease's own ribbon
     colour, not a decorative accent. It cannot be a text colour on a near-white
     ground (bright ribbon yellow fails the AA floor palette.js enforces), so it
     lives in two roles: --accent is a text-safe deep gold used everywhere the
     accent is drawn as ink or a thin stroke (links, eyebrow, option borders,
     body-map regions), and --accent-solid is the literal ribbon yellow, used
     ONLY as a fill under dark --accent-ink (the primary button, the progress
     fill) where the yellow is large and contrast is trivial. */
  --accent:       #8a6a00;
  --accent-2:     #b8890a;
  --accent-solid: #e8b10a;
  --accent-ink:   #1c1b19;
  --accent-bg:    #fbf3d6;
  --line:      color-mix(in srgb, var(--ink) 14%, transparent);
  --focus:     var(--accent);

  --font-heading: "Figtree", system-ui, sans-serif;
  --font-body: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 28px;

  --shadow-sm: 0 1px 2px color-mix(in srgb, var(--ink) 12%, transparent);
  --shadow-md: 0 3px 12px color-mix(in srgb, var(--ink) 16%, transparent);
  --shadow-lg: 0 14px 34px color-mix(in srgb, var(--ink) 22%, transparent);

  /* A fixed crimson ramp, deliberately NOT derived from --accent: it encodes
     pain intensity on the body map, so it is data rather than decoration, and
     has to stay a different hue family from whatever accent a researcher
     picks or a selected region starts reading as "the accent", not "painful".
     Terracotta (~H24) and the old formula's orange-leaning pain-2 (~H16) sat
     only ~8° apart - this ramp sits at ~H350, a safe ~35°+ from any warm
     accent a colour wheel is likely to produce. */
  --pain-1:    #f4c3cb;
  --pain-2:    #d65c70;
  --pain-3:    #8e293a;
}

/* Explicit toggle, not prefers-color-scheme: the default is light regardless
   of OS setting, and dark is opt-in via the switch in the site bar. theme.js
   sets data-theme on <html> before first paint (same file that already
   replays the cached survey accent), reading a stored choice or "light" if
   none exists yet - so a first-time visitor never sees an unrequested dark
   flash even on a dark-mode OS. */
:root[data-theme="dark"] {
  --bg:        #17150f;
  --bg-raised: #23201a;
  --ink:       #f2eee6;
  --ink-soft:  #ada79b;
  /* On the dark ground the gold can run brighter and still read as text; the
     ribbon yellow fill and its dark ink stay fixed, because the button is the
     same yellow in both themes. */
  --accent:       #e8c24a;
  --accent-2:     #f2d06a;
  --accent-solid: #e8b10a;
  --accent-ink:   #1c1b19;
  --accent-bg:    #2e2814;
  --pain-1:    #793440;
  --pain-2:    #be374e;
  --pain-3:    #d65168;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 17px/1.6 var(--font-body);
  font-feature-settings: "kern", "liga";
  text-rendering: optimizeLegibility;
  min-height: 100dvh;
  overflow-wrap: break-word;
}

.skip {
  position: absolute; left: -9999px;
  background: var(--accent); color: var(--bg); padding: .8rem 1.2rem; border-radius: 0 0 var(--radius-sm) 0;
}
.skip:focus { left: 0; top: 0; z-index: 50; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 6px;
}
/* app.js moves keyboard focus to #screen (a tabindex="-1" <main>) after every
   screen change, so assistive tech and keyboard users land on the new content
   without tabbing through the whole page again - that focus move is the
   point. The ring the rule above draws around it is not: it boxes the entire
   question, appears the instant the screen loads, and vanishes the moment
   focus moves anywhere else, which reads as a rendering glitch rather than a
   focus indicator. A landmark, not a control, so it gets the move without
   the visible ring. */
#screen:focus-visible { outline: none; }

/* ---------------------------------------------------------------- site bar */
/* Brand and language. The palette picker that used to live here moved into the
   editor and became a property of the survey - respondents get the colours the
   researcher chose, not their own.

   Deliberately NOT sticky: #bar below it is,
   and two stacked sticky bars on a phone eat the vertical space the SPEC
   reserves for one question per screen. This one scrolls away; the progress
   bar is the part that has to stay. */

#sitebar {
  border-bottom: 1px solid var(--line);
  padding: max(.55rem, env(safe-area-inset-top)) 1rem .55rem;
}
.sitebar-row {
  max-width: 42rem; margin: 0 auto;
  display: flex; align-items: center; gap: .75rem;
}
.sitebar__brand {
  font-family: var(--font-heading); font-weight: 700; font-size: 1rem; letter-spacing: -.01em;
  color: var(--ink); text-decoration: none; margin-right: auto;
}
.sitebar__brand:hover { color: var(--accent); }

/* ------------------------------------------------------------------ footer */

/* Same trap as .consent on the portfolio: an author `display` outranks the UA
   [hidden] rule, so without this the footer appeared on question screens too -
   exactly where renderFooter() is meant to suppress it. */
.sitefoot[hidden] { display: none; }
.sitefoot {
  max-width: 42rem; margin: 3.5rem auto 0;
  padding: 1.25rem 0 max(1.25rem, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  font-size: .82rem; color: var(--ink-soft);
  display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: center;
}
.sitefoot a { color: var(--ink-soft); text-decoration: none; border-bottom: 1px solid var(--line); }
.sitefoot a:hover { color: var(--accent); border-bottom-color: var(--accent); }
.sitefoot__spacer { margin-left: auto; }

/* ------------------------------------------------------------------ header */

#bar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  padding: max(.6rem, env(safe-area-inset-top)) 1rem .6rem;
}

.bar-row { display: flex; align-items: center; gap: .75rem; max-width: 42rem; margin: 0 auto; }

.icon-btn {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 0; border-radius: 999px;
  background: transparent; color: var(--ink-soft);
  cursor: pointer;
}
.icon-btn:hover { background: var(--accent-bg); color: var(--accent); }
.icon-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.icon-btn[hidden] { display: none; }

/* Light/dark switch, in the site bar next to the language nav. The icon shows
   the mode a click switches TO, not the current one. */
#theme-toggle { margin-left: -.25rem; }
.theme-icon--sun { display: none; }
:root[data-theme="dark"] .theme-icon--sun { display: block; }
:root[data-theme="dark"] .theme-icon--moon { display: none; }

.progress {
  flex: 1 1 auto; height: 6px;
  background: var(--line); border-radius: 99px; overflow: hidden;
}
#progress-fill {
  height: 100%; width: 0%;
  background: var(--accent-solid);
  border-radius: 99px;
  transition: width .35s cubic-bezier(.4, 0, .2, 1);
}
.progress-text {
  flex: 0 0 auto;
  font-size: .8rem; font-variant-numeric: tabular-nums; color: var(--ink-soft);
}

.saved {
  max-width: 42rem; margin: 0 auto;
  height: 1.1rem; font-size: .78rem; color: var(--ink-soft);
  opacity: 0; transition: opacity .3s;
}
.saved.show { opacity: 1; }

/* -------------------------------------------------------------------- main */

main {
  max-width: 42rem;
  margin: 0 auto;
  padding: 1.75rem 1.15rem calc(2rem + env(safe-area-inset-bottom));
}

.step { animation: rise .32s cubic-bezier(.2, .7, .3, 1) both; }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

h1, h2 {
  font-family: var(--font-heading); font-weight: 700;
}
h1 { font-size: clamp(1.7rem, 5vw, 2.2rem); line-height: 1.2; letter-spacing: -.01em; margin: 0 0 1rem; }
h2 { font-size: clamp(1.35rem, 4.5vw, 1.65rem); line-height: 1.25; letter-spacing: -.01em; margin: 0 0 .5rem; }
p  { margin: 0 0 1rem; }
strong { font-weight: 650; }

.eyebrow {
  font-family: var(--font-heading); font-weight: 700;
  font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 .6rem;
}
.help { color: var(--ink-soft); font-size: .93rem; margin: -.1rem 0 1.4rem; }

.prose { color: var(--ink-soft); }
.prose strong { color: var(--ink); }
.prose ul { padding-left: 1.15rem; margin: 0 0 1rem; }
.prose li { margin-bottom: .5rem; }

/* ------------------------------------------------------------------ inputs */

.options { display: grid; gap: .6rem; margin: 0 0 1.5rem; list-style: none; padding: 0; }

.opt {
  display: flex; align-items: center; gap: .85rem;
  min-height: 60px; padding: .85rem 1.05rem;
  background: var(--bg-raised);
  border: 1.5px solid var(--line); border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .08s;
}
.opt:active { transform: scale(.988); }
.opt:hover { border-color: var(--accent); }
.opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.opt:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }

.opt .mark {
  flex: 0 0 auto; width: 24px; height: 24px;
  border: 1.5px solid var(--line); background: var(--bg);
  display: grid; place-items: center;
  transition: border-color .15s, background .15s;
}
.opt[data-kind="single"] .mark { border-radius: 50%; }
.opt[data-kind="multi"]  .mark { border-radius: var(--radius-sm); }
.opt .mark::after {
  content: ""; opacity: 0; transition: opacity .15s, transform .15s;
  transform: scale(.5);
}
.opt[data-kind="single"] .mark::after { width: 11px; height: 11px; border-radius: 50%; background: var(--bg); }
.opt[data-kind="multi"] .mark::after {
  width: 12px; height: 7px; margin-top: -3px;
  border-left: 2.5px solid var(--bg); border-bottom: 2.5px solid var(--bg);
  transform: rotate(-45deg) scale(.5);
}

.opt:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--bg-raised)); }
.opt:has(input:checked) .mark { border-color: var(--accent); background: var(--accent); }
.opt:has(input:checked) .mark::after { opacity: 1; transform: scale(1); }
.opt[data-kind="multi"]:has(input:checked) .mark::after { transform: rotate(-45deg) scale(1); }

textarea, input[type="text"], input[type="email"], input[type="number"], input[type="date"] {
  width: 100%; padding: .9rem 1.1rem;
  font: inherit; font-size: 16px;         /* < 16px makes iOS zoom on focus */
  color: var(--ink); background: var(--bg-raised);
  border: 1.5px solid var(--line);
  margin-bottom: .5rem;
}
input[type="text"], input[type="email"], input[type="number"], input[type="date"] { border-radius: 999px; }
textarea { border-radius: var(--radius-md); min-height: 8.5rem; resize: vertical; line-height: 1.6; }
.counter { font-size: .78rem; color: var(--ink-soft); text-align: right; margin-bottom: 1.2rem; }
.counter.over { color: var(--pain-3); }

/* Honeypot: off-screen and hidden from assistive tech. Bots fill it, and the
 * API rejects any submission that has it set. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ------------------------------------------------------------------- scale */

.scale-value {
  font-family: var(--font-heading); font-weight: 700;
  font-size: 3rem; line-height: 1;
  text-align: center; font-variant-numeric: tabular-nums;
  color: var(--accent); margin: .5rem 0 1rem;
}
.scale-value.unset { color: var(--ink-soft); opacity: .45; }

input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 44px; background: transparent; margin: 0;
  accent-color: var(--accent);
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 8px; border-radius: 99px; background: var(--line);
}
input[type="range"]::-moz-range-track {
  height: 8px; border-radius: 99px; background: var(--line);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 32px; height: 32px; margin-top: -12px;
  border-radius: 50%; background: var(--bg-raised);
  border: 3px solid var(--accent); box-shadow: var(--shadow-sm); cursor: grab;
}
input[type="range"]::-moz-range-thumb {
  width: 32px; height: 32px; border: none;
  border-radius: 50%; background: var(--bg-raised);
  outline: 3px solid var(--accent); outline-offset: -3px; box-shadow: var(--shadow-sm); cursor: grab;
}
.scale-ends { display: flex; justify-content: space-between; gap: 1rem; font-size: .82rem; color: var(--ink-soft); margin-bottom: 1.5rem; }
.scale-ends span:last-child { text-align: right; }

/* ---------------------------------------------------------------- body map */

.bodymap { margin-bottom: 1.25rem; }

.view-toggle {
  display: flex; gap: .25rem; padding: .25rem; margin: 0 auto 1rem;
  width: fit-content; background: var(--bg-raised); border-radius: 99px;
}
.view-toggle button {
  border: 0; border-radius: 99px; padding: .55rem 1.4rem; min-height: 44px;
  font: inherit; font-weight: 600; font-size: .9rem;
  background: transparent; color: var(--ink-soft); cursor: pointer;
}
.view-toggle button[aria-pressed="true"] { background: var(--bg); color: var(--accent); box-shadow: var(--shadow-sm); }

.bodymap svg { display: block; width: 100%; max-width: 340px; margin: 0 auto; height: auto; touch-action: manipulation; }
/* Same trap as .sitefoot[hidden] above: an author `display` always outranks
   the UA [hidden] rule regardless of specificity, so without this override
   the front/back toggle set the attribute correctly and nothing happened -
   both views stayed visible, stacked. Pre-existing in the original file;
   the new quiz body-map question is what first exercised this toggle. */
.bodymap svg[hidden] { display: none; }
.body-silhouette { fill: var(--bg-raised); stroke: var(--line); stroke-width: 2; }
.region {
  fill: var(--bg-raised); stroke: var(--line); stroke-width: 1.5;
  cursor: pointer; transition: fill .18s, stroke .18s;
}
/* An untouched tappable region used to be drawn exactly like the silhouette
   under it (same fill, same stroke), so nothing said where to tap. Scoped to
   role="button" so the print appendix and the admin heat map keep their look. */
.region[role="button"][data-level="0"] {
  fill: color-mix(in srgb, var(--accent) 16%, var(--bg-raised));
  stroke: var(--accent); stroke-dasharray: 4 3;
}
@media (prefers-reduced-motion: no-preference) {
  /* A slow pulse until the first region is marked, then the map goes still. */
  .bodymap:not(:has(.region:not([data-level="0"]))) .region[role="button"] {
    animation: region-hint 2.4s ease-in-out infinite;
  }
}
@keyframes region-hint { 50% { fill-opacity: .45; } }
.region:hover { stroke: var(--accent); stroke-width: 2.5; }
.region:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.region[data-level="1"] { fill: var(--pain-1); stroke: var(--pain-1); }
.region[data-level="2"] { fill: var(--pain-2); stroke: var(--pain-2); }
.region[data-level="3"] { fill: var(--pain-3); stroke: var(--pain-3); }

/* Graded "select the areas" question (spec levels:1 - see bodymap.js and
   007_quiz_pain_location.sql): a tap is right-or-wrong, not an intensity, so
   a selected region takes the accent rather than a point on the pain ramp. */
.bodymap--select .region[data-level="1"] {
  fill: var(--accent);
  stroke: color-mix(in srgb, var(--accent) 70%, black);
}

.bodymap-hint { text-align: center; font-size: .85rem; color: var(--ink-soft); margin: 0 0 .75rem; }

.legend { display: flex; flex-wrap: wrap; gap: .5rem .9rem; justify-content: center; font-size: .8rem; color: var(--ink-soft); margin-bottom: 1rem; }
.legend span { display: inline-flex; align-items: center; gap: .4rem; }
.swatch { width: 14px; height: 14px; border-radius: var(--radius-sm); border: 1.5px solid var(--line); }
.swatch.l1 { background: var(--pain-1); border-color: var(--pain-1); }
.swatch.l2 { background: var(--pain-2); border-color: var(--pain-2); }
.swatch.l3 { background: var(--pain-3); border-color: var(--pain-3); }

.picked { list-style: none; padding: 0; margin: 0 0 1.4rem; display: flex; flex-wrap: wrap; gap: .45rem; }
.picked li {
  font-size: .82rem; padding: .35rem .75rem; border-radius: 99px;
  background: var(--accent-bg); color: var(--accent); border: 1px solid var(--line);
}

/* ----------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  width: 100%; min-height: 58px; padding: 1rem 1.5rem;
  font-family: var(--font-heading); font-weight: 700; font-size: 1.05rem;
  border: 0; border-radius: 999px; cursor: pointer;
  background: var(--accent-solid); color: var(--accent-ink); box-shadow: var(--shadow-md);
  transition: transform .08s, filter .15s;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: scale(.985); }
.btn:disabled { opacity: .45; cursor: not-allowed; filter: none; }

.btn-quiet {
  background: transparent; color: var(--ink-soft); box-shadow: none;
  font-family: var(--font-body); font-weight: 600; min-height: 48px; font-size: .9rem;
}
.btn-quiet:hover { color: var(--accent); filter: none; }

.actions { display: grid; gap: .35rem; margin-top: 1.5rem; }

/* ----------------------------------------------------------------- consent */

.consent-box {
  background: var(--bg-raised); border: 1.5px solid var(--line);
  border-radius: var(--radius-lg); padding: 1.25rem; margin-bottom: 1.25rem;
  box-shadow: var(--shadow-md);
}
.check {
  display: flex; gap: .85rem; align-items: flex-start;
  padding: 1rem; min-height: 60px; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: var(--radius-md);
  background: var(--bg-raised); margin-bottom: .6rem;
}
.check:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--bg-raised)); }
.check:has(input:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check .mark { flex: 0 0 auto; width: 24px; height: 24px; margin-top: 2px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: var(--bg); display: grid; place-items: center; }
.check:has(input:checked) .mark { border-color: var(--accent); background: var(--accent); }
.check .mark::after { content: ""; width: 12px; height: 7px; margin-top: -3px; border-left: 2.5px solid var(--bg); border-bottom: 2.5px solid var(--bg); transform: rotate(-45deg); opacity: 0; }
.check:has(input:checked) .mark::after { opacity: 1; }
.check-text { font-size: .94rem; }
.check-text small { display: block; color: var(--ink-soft); font-size: .85rem; margin-top: .2rem; }

/* -------------------------------------------------------------- lang, misc */

.lang { display: flex; gap: .4rem; justify-content: center; margin-top: 2rem; }
.lang a {
  font-size: .85rem; padding: .5rem 1rem; min-height: 44px;
  display: inline-flex; align-items: center;
  border-radius: 999px; border: 1px solid var(--line);
  color: var(--ink-soft); text-decoration: none;
}
.lang a[aria-current="true"] { border-color: var(--accent); color: var(--accent); background: var(--accent-bg); }

/* Same switcher, compacted for the site bar. The 44px pill is right at the
   bottom of a screen where it is the only target; in the bar it would make the
   header twice as tall as it needs to be. The one at the bottom of the consent
   and thanks screens keeps the full size. */
.lang--bar { margin-top: 0; gap: .2rem; }
.lang--bar a { font-size: .76rem; padding: .3rem .55rem; min-height: 32px; }
.lang--bar:empty { display: none; }

.error {
  background: var(--accent-bg); border: 1.5px solid var(--accent);
  border-radius: var(--radius-md); padding: .9rem 1.1rem; margin-bottom: 1.2rem;
  font-size: .92rem; color: var(--accent);
}

/* Missing-required list on the review screen. One row per unanswered question,
   each one a jump target, numbered so it maps onto the progress counter. */
.missing-list { display: grid; gap: .4rem; margin: -.6rem 0 1.2rem; }

.missing-item {
  display: flex; align-items: center; gap: .7rem;
  text-align: left; justify-content: flex-start;
  background: var(--bg-raised); border: 1.5px solid var(--line);
  border-radius: var(--radius-md); padding: .75rem 1rem; min-height: 48px;
  color: var(--ink); font-size: .92rem;
}
.missing-item:hover { border-color: var(--accent); color: var(--accent); }

.missing-num {
  flex: none; display: grid; place-items: center;
  width: 1.6rem; height: 1.6rem; border-radius: 999px;
  background: var(--accent-bg); color: var(--accent);
  font-size: .78rem; font-weight: 700; font-variant-numeric: tabular-nums;
}

.center { text-align: center; }
.big-emoji { font-size: 3rem; line-height: 1; margin-bottom: .75rem; }
.footnote { font-size: .8rem; color: var(--ink-soft); margin-top: 2.5rem; text-align: center; }
.noscript { padding: 2rem 1.25rem; max-width: 42rem; margin: 0 auto; }

.spinner {
  width: 28px; height: 28px; margin: 3rem auto;
  border: 3px solid var(--line); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------- quiz mode */
/* Feedback shown after a graded answer is committed. Right and wrong are
 * distinguished by mark and wording as well as colour - never colour alone.
 * The mock uses one accent-coloured badge for both outcomes; this keeps a
 * second, deliberately different hue for "correct" as an extra channel on
 * top of the glyph and label, not instead of them. */

.verdict {
  border: 1.5px solid var(--line);
  border-left-width: 3px;
  border-radius: var(--radius-md);
  padding: 1rem 1.15rem;
  margin: 1.25rem 0 0;
  background: var(--bg-raised);
  animation: rise .28s cubic-bezier(.2, .7, .3, 1) both;
}
.verdict--ok { border-left-color: #2f8f5b; }
.verdict--no { border-left-color: var(--accent); }
.verdict--info { border-left-color: var(--ink-soft); }

.verdict-head {
  display: flex; align-items: center; gap: .55rem;
  font-weight: 650; margin: 0 0 .5rem;
}
.verdict--ok .verdict-head { color: #2f8f5b; }
.verdict--no .verdict-head { color: var(--accent); }
:root[data-theme="dark"] .verdict--ok .verdict-head { color: #6cc48d; }

.verdict-mark {
  flex: 0 0 auto;
  width: 22px; height: 22px; border-radius: var(--radius-sm);
  display: inline-grid; place-items: center;
  font-size: .78rem; color: var(--bg);
  background: currentColor;
}
.verdict-mark::first-letter { color: var(--bg); }
.verdict--ok .verdict-mark { background: #2f8f5b; color: var(--bg); }
.verdict--no .verdict-mark { background: var(--accent); color: var(--bg); }

.verdict-answer { font-size: .93rem; margin-bottom: .6rem; }
.verdict .prose { font-size: .93rem; }
.verdict .prose p:last-child { margin-bottom: 0; }
.verdict-peers {
  margin: .75rem 0 0; padding-top: .6rem;
  border-top: 1px solid var(--line);
  font-size: .85rem; color: var(--ink-soft);
}

/* score card */
.scorecard {
  background: var(--bg-raised);
  border: 1.5px solid var(--line); border-radius: var(--radius-lg);
  padding: 1.5rem 1.25rem; margin-bottom: 1.5rem;
  box-shadow: var(--shadow-md); text-align: center;
}
.score-big {
  font-family: var(--font-heading); font-weight: 700;
  font-size: 2.75rem; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink-soft);
  margin: .25rem 0 1rem;
}
.score-big strong { font-weight: 700; color: var(--accent); }
.score-track {
  height: 8px; background: var(--line); border-radius: 99px;
  overflow: hidden; margin-bottom: 1rem;
}
.score-fill {
  height: 100%; border-radius: 99px;
  background: var(--accent);
  transition: width .6s cubic-bezier(.4, 0, .2, 1);
}

/* recap - collapsed by default so the screen is not a wall of text */
.recap {
  border: 1.5px solid var(--line); border-left-width: 3px;
  border-radius: var(--radius-md); padding: .85rem 1rem; margin-bottom: .5rem;
  background: var(--bg-raised);
}
.recap--ok { border-left-color: #2f8f5b; }
.recap--no { border-left-color: var(--accent); }
.recap--info { border-left-color: var(--ink-soft); }
.recap summary {
  display: flex; align-items: flex-start; gap: .6rem;
  cursor: pointer; font-size: .94rem; list-style: none;
  min-height: 32px;
}
.recap summary::-webkit-details-marker { display: none; }
.recap[open] summary { margin-bottom: .6rem; font-weight: 600; }
.recap .prose { font-size: .9rem; }
.recap .prose p:last-child { margin-bottom: 0; }

/* sources - last on the results page, quieter than the recap above */
.sources {
  margin: 2rem 0 1.5rem; padding-top: 1.25rem;
  border-top: 1px solid var(--line); font-size: .9rem;
}
.sources h2 { font-size: 1.05rem; color: var(--ink-soft); }
.sources .prose { font-size: .85rem; }
.sources .prose li { margin-bottom: .45rem; }
.sources .prose a { color: var(--accent); overflow-wrap: anywhere; }

/* ------------------------------------------------------------- home screen */
/* The chooser at `/`. Cards are whole-area links, not a title link with text
   beside it - on a phone the tap target should be the card. */

.cards { display: grid; gap: .9rem; margin: 1.75rem 0; }

.card {
  display: block; text-decoration: none; color: inherit;
  background: var(--bg-raised); border: 1.5px solid var(--line);
  border-radius: var(--radius-lg); padding: 1.25rem 1.35rem;
  box-shadow: var(--shadow-md);
  transition: border-color .15s ease, transform .15s ease;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); }
.card:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }

.card-kind {
  display: inline-block; font-size: .7rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
  padding: .22rem .65rem; border-radius: 999px; margin-bottom: .7rem;
}
.card-kind--survey { background: var(--accent-bg); color: var(--accent); }
.card-kind--quiz {
  background: color-mix(in srgb, var(--accent-2) 18%, var(--bg-raised));
  color: var(--accent-2);
}

.card-title { font-family: var(--font-heading); font-weight: 700; font-size: 1.2rem; margin: 0 0 .45rem; line-height: 1.3; }
.card-blurb { color: var(--ink-soft); font-size: .92rem; margin: 0 0 .9rem; }
.card-go { color: var(--accent); font-weight: 650; font-size: .92rem; }

/* A closed survey is only ever listed to a trusted client, so this is an admin
   affordance rather than something a respondent runs into. */
.card--closed { opacity: .6; }
.card--closed .card-go { color: var(--ink-soft); }

/* ------------------------------------------------------------- admin panel */
/* Rendered only when the API reports a trusted client. Visually separate from
   the cards so it never reads as part of the respondent's path. */

.admin-panel {
  border: 1.5px dashed var(--line); border-radius: var(--radius-lg);
  padding: 1.25rem 1.35rem; margin-top: 2.5rem;
}
.admin-panel h2 { font-size: 1.05rem; margin: 0 0 .35rem; }
.admin-panel .help { margin-bottom: 1.1rem; }

.admin-rows { display: grid; gap: .75rem; }
.admin-row {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: .35rem .8rem; padding-top: .75rem; border-top: 1px solid var(--line);
}
.admin-row:first-child { padding-top: 0; border-top: 0; }
.admin-name { font-weight: 600; font-size: .95rem; flex: 1 1 100%; }
.admin-flag { color: var(--ink-soft); font-weight: 400; font-style: normal; }
.admin-links { display: flex; flex-wrap: wrap; gap: .5rem; }

.admin-link {
  font-size: .84rem; text-decoration: none; color: var(--ink-soft);
  border: 1px solid var(--line); border-radius: 999px;
  padding: .35rem .8rem; min-height: 32px; display: inline-flex; align-items: center;
}
.admin-link:hover { border-color: var(--accent); color: var(--accent); }

/* -------------------------------------------------------------- print view */
/* SPEC: the blank questionnaire is a required thesis appendix. Plain system
   fonts and a flat black-on-white palette regardless of the survey's accent -
   a display face and a warm cream ground are for the screen, not for a form
   someone photocopies. */

.print-q { break-inside: avoid; margin-bottom: 1.75rem; }
.print-q .num { color: var(--accent); font-weight: 650; }
.print-opts { list-style: none; padding: 0; margin: .5rem 0 0; }
.print-opts li { display: flex; gap: .6rem; align-items: center; padding: .18rem 0; }
.print-box { flex: 0 0 auto; width: 14px; height: 14px; border: 1.3px solid var(--ink); }
.print-box.round { border-radius: 50%; }
.print-rule { border-bottom: 1px solid var(--line); height: 1.7rem; }
.print-scale { display: flex; gap: .4rem; margin-top: .4rem; }
.print-scale span { flex: 1; text-align: center; border: 1px solid var(--ink); padding: .3rem 0; font-size: .8rem; }

@media print {
  :root {
    --bg: #fff; --bg-raised: #fff; --ink: #000; --ink-soft: #444;
    --line: #999; --accent: #000; --accent-bg: #fff;
    --shadow-sm: none; --shadow-md: none; --shadow-lg: none;
    --font-heading: system-ui, sans-serif; --font-body: system-ui, sans-serif;
  }
  #bar, #sitebar, .sitefoot, .lang, .actions, .skip, .btn { display: none !important; }
  body { font-size: 11pt; }
  main { max-width: none; padding: 0; }
  h1 { font-size: 18pt; font-weight: 700; }
  h2 { font-size: 12pt; font-weight: 700; }
  .bodymap svg { max-width: 300px; }
  .region { fill: #fff !important; stroke: #000 !important; stroke-width: 1 !important; }
  .print-q { page-break-inside: avoid; }
  a[href]::after { content: ""; }
}
