  :root {
    --paper: #EDEFEC;
    --ebony: #1F1C1A;
    --slate: #5B6266;
    --nickel: #9AA0A2;
    --winding: #6F7578;
    --gutter: clamp(1rem, 5vw, 4rem);
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --paper: #1A1816;
      --ebony: #E8E5E0;
      --slate: #A3A7A6;
      --nickel: #7D8385;
      --winding: #5A5F61;
    }
  }

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

  body {
    margin: 0;
    background: var(--paper);
    color: var(--ebony);
    font-family: "Spectral", Georgia, serif;
    font-weight: 300;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    cursor: default;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    user-select: none; -webkit-user-select: none;
    /* Golden section, as on the homepage: free space above and below split 1 : φ. */
    display: flex; flex-direction: column;
    min-height: 100vh; min-height: 100svh;
  }
  body::before { content: ""; flex: 1; }
  body::after { content: ""; flex: 1.618; }
  body > * { width: 100%; }

  /* order: 1 puts the footer after the lower spacer, at the bottom of the page. */
  .site-footer { order: 1; margin: 0; padding-block: 1.25rem; text-align: center; font-size: 0.8125rem; color: var(--slate); }

  .wrap { max-width: 68rem; margin-inline: auto; padding-inline: var(--gutter); }

  .site-header { display: flex; justify-content: center; padding-block: 1.25rem; }
  .site-name { margin: 0; font-weight: 300; font-size: 2.25rem; letter-spacing: 0.01em; transition: opacity 2.5s ease-in-out; }
  body.started .site-name { opacity: 0; }
  /* The heading leads back to the overview; once faded out, a tap there starts or pauses as anywhere else. */
  .site-name a { color: inherit; text-decoration: none; }
  body.started .site-name a { pointer-events: none; }

  .strings { position: relative; height: 17rem; }
  .strings svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

  /* The answer: fades in slowly, and out again before the next chord. */
  .interval {
    margin: 0; padding-block: 1.25rem; min-height: 1.65em;
    box-sizing: content-box;
    text-align: center; font-size: 1.25rem; font-style: italic; color: var(--slate);
    opacity: 0; transition: opacity 2.5s ease-in-out;
  }
  .interval.shown { opacity: 1; transition-duration: 4s; }

  /* Exercise mode (uebung/) and the result a student shares (#r=…). */
  .stage { display: grid; }
  .stage > * { grid-area: 1 / 1; }
  .detail, .mistakes {
    margin: 0; text-align: center; font-size: 0.9375rem; color: var(--slate); user-select: text; -webkit-user-select: text;
    opacity: 0; transition: opacity 2.5s ease-in-out;
  }
  .detail { min-height: 1.65em; }
  .interval.shown ~ * { opacity: 1; transition-duration: 4s; }
  .mistakes { list-style: none; padding: 0.75rem 0 0; }
  body.listen .detail, body:not(.result) .mistakes, body:not(.exercise) .answering { display: none; }
  body.exercise .strings { height: 11rem; }

  .choices {
    display: grid; grid-template-columns: repeat(var(--cols-2, 2), 1fr); grid-template-rows: repeat(var(--rows-2, 7), auto);
    grid-auto-flow: column; column-gap: 1.5rem;
    width: 100%; max-width: 28rem; margin-inline: auto; padding-block: 0.5rem;
    opacity: 0; visibility: hidden; transition: opacity 1.5s ease-in-out, visibility 0s 1.5s;
  }
  .choices.open { opacity: 1; visibility: visible; transition: opacity 2s ease-in-out; }
  /* Above the answer text in the same grid cell: while that text is invisible
     (opacity 0) browsers paint it on a higher layer, where it would catch taps.
     The wrapper holds the choices and the replay button, so both stay on top.
     The wrapper itself lets taps through, or it would cover the result buttons. */
  .answering { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; pointer-events: none; }
  .choices.open, .replay.open { pointer-events: auto; }
  .replay { font-size: 0.8125rem; color: var(--slate); opacity: 0; visibility: hidden; transition: opacity 1.5s ease-in-out, visibility 0s 1.5s; }
  .replay.open { opacity: 1; visibility: visible; transition: opacity 2s ease-in-out; }
  button {
    margin: 0; padding: 0.5rem 0; min-height: 2.75rem;
    border: 0; background: none; cursor: pointer;
    font: inherit; font-size: 1.0625rem; color: var(--slate);
  }
  button.picked { color: var(--ebony); }
  @media (hover: hover) { button:hover { color: var(--ebony); } }
  .detail button { display: block; margin-inline: auto; min-height: 2.75rem; padding: 0; font-size: inherit; color: var(--slate); }
  .detail button svg { display: block; margin-inline: auto; }
  /* Rhythm: bars drawn in currentColor, so they follow the button colour (slate,
     ebony when picked or hovered). Large as a choice, smaller beside a line of text. */
  .bar { display: block; height: 3.3rem; width: auto; margin-inline: auto; }
  .interval .bar, .detail .bar, .mistakes .bar { display: inline-block; vertical-align: middle; }
  .detail .bar, .mistakes .bar { height: 1.925rem; }
  body.rhythmus .interval { min-height: 3rem; line-height: 3rem; }
  body.rhythmus .detail { min-height: 1.75rem; line-height: 1.75rem; }
  body.rhythmus .choices button { padding-block: 0.25rem; }
  :focus-visible { outline: 1px solid var(--slate); outline-offset: 3px; border-radius: 2px; }

  @media (min-width: 40rem) {
    .site-header { padding-block: 1.75rem; }
    .strings { height: 21rem; }
    body.exercise .strings { height: 15rem; }
    /* Narrower with fewer columns: 4 → 46rem, 3 (rhythm) → 34.5rem, 2 (Dur and Moll) → 28rem. */
    .choices {
      grid-template-columns: repeat(var(--cols-4, 4), 1fr); grid-template-rows: repeat(var(--rows-4, 4), auto);
      max-width: max(28rem, calc(var(--cols-4, 4) * 11.5rem));
    }
  }
  /* Short screens, also phones held sideways (an iPhone SE shows about 550px):
     the exercise must not scroll, or taps on the choices turn into scrolls. */
  @media (max-height: 46rem) {
    body.exercise .site-header { padding-block: 0.5rem; }
    body.exercise .strings { height: 4rem; }
    body.exercise .site-footer { display: none; }
    body.exercise .interval { padding-block: 0.5rem; }
    body.exercise .choices { padding-block: 0; }
    body.rhythmus .choices button { padding-block: 0; }
    body.rhythmus .choices .bar { height: 2.75rem; }
  }
  /* Phones held sideways: the replay button needs a little more room. */
  @media (max-height: 25rem) {
    body.exercise .strings { height: 2.75rem; }
  }
