import { useId, useMemo } from 'react';

import {
  SPRECHTEMPI,
  sprechtempoAnsage,
  sprechtempoBereinigen,
  sprechtempoText,
} from '../../../../shared/sprechtempo';
import type { ThemeAuswahl } from '../../../../shared/theme';
import type { Einstellungssteuerung } from '../../hooks/useEinstellungen';
import type { KatalogIndex, KatalogZustand } from '../../hooks/useKatalog';
import type { LernplanZustand } from '../../hooks/useLernplan';
import type { OffenePruefung } from '../../hooks/useOffenePruefung';
import type { Lernstand } from '../../hooks/useLernstand';
import type { KuerzelEinstellung } from '../../hooks/useTastenkuerzel';
import { Anzeigegroessenwahl } from '../Anzeigegroessenwahl';
import { Profilverwaltung } from '../profil/Profilverwaltung';
import { Unterbrochen } from '../pruefung/Unterbrochen';
import { Schalter } from '../Schalter';
import { Sprungmenue, type Sprungziel } from '../Sprungmenue';
import { SystemStatus } from '../SystemStatus';
import { Textabstandswahl } from '../Textabstandswahl';
import { ThemaWahl } from '../ThemaWahl';
import { Hinweis } from './Hinweis';
import { Einstieg } from './Einstieg';
import { KuerzelHilfe } from './KuerzelHilfe';
import { Datensicherung } from './Datensicherung';
import type { HartnaeckigeFrage } from '../../../../shared/hartnaeckig';
import { Hartnaeckige } from './Hartnaeckige';
import { Druckkarte } from './Druckkarte';
import { KAPITEL_IV } from '../../pruefung/auftrag';
import { Neuanfang } from './Neuanfang';
import { Lernplanung } from './Lernplanung';
import { Lernstandsuebersicht } from './Lernstandsuebersicht';

export interface StartbildschirmProps {
  readonly einstiegRef: React.RefObject<HTMLHeadingElement | null>;
  readonly lernstand: Lernstand;
  readonly lernplan: LernplanZustand;
  readonly katalogZustand: KatalogZustand;
  /** Für die Fragenliste; sie hängt am Katalog, nicht am Lernstand. */
  readonly katalogIndex: KatalogIndex | null;
  readonly onKatalogNeuLaden: () => void;
  readonly kuerzel: KuerzelEinstellung;
  readonly einstellungen: Einstellungssteuerung;
  /** Es läuft ein Screenreader o. Ä. – die Sprachausgabe erklärt sich dann anders. */
  readonly hilfsmittelAktiv: boolean;
  readonly themaAuswahl: ThemeAuswahl;
  readonly onThema: (auswahl: ThemeAuswahl) => void;
  readonly onWeiterlernen: () => void;
  readonly onKapitelWahl: () => void;
  readonly onNurFehler: () => void;
  /** Übt genau die hartnäckigen Fragen. */
  readonly hartnaeckigeFragen: readonly HartnaeckigeFrage[];
  readonly onHartnaeckigeUeben: (frageIds: readonly string[]) => void;
  readonly onGemerkte: () => void;
  readonly onOffeneFragen: () => void;
  readonly offenePruefung: OffenePruefung;
  readonly onPruefungFortsetzen: () => void;
  readonly onPruefung: () => void;
  readonly onGlossar: () => void;
  readonly onSuche: () => void;
  readonly onUeber: () => void;
}

/**
 * Das Inhaltsverzeichnis des Startbildschirms.
 *
 * Die Kennungen sind dieselben, die die Karten über `aria-labelledby` ohnehin
 * tragen – eine zweite Pflege gäbe es nicht umsonst. Die Beschriftungen sind
 * kürzer als die Überschriften, nennen aber deren tragendes Wort („Ihr
 * Lernstand im Einzelnen“ → „Lernstand im Einzelnen“), damit die Leiste bei
 * 1265 Pixel Breite nicht über drei Zeilen läuft. Ein Test hält fest, dass
 * jede Karte unterhalb des Menüs auch einen Eintrag hat.
 */
const SPRUNGZIELE: readonly Sprungziel[] = [
  { id: 'pruefungsteil-titel', text: 'Prüfungssimulation' },
  { id: 'lernstand-titel', text: 'Lernstand im Einzelnen' },
  { id: 'lernplan-titel', text: 'Lernplan' },
  { id: 'suche-titel', text: 'Fragen durchsuchen' },
  { id: 'glossar-titel', text: 'Glossar' },
  { id: 'drucken-titel', text: 'Drucken' },
  { id: 'sicherung-titel', text: 'Sichern und übertragen' },
  { id: 'einstellungen-titel', text: 'Einstellungen' },
  { id: 'systemzustand-titel', text: 'Systemzustand' },
  { id: 'ueber-start-titel', text: 'Über diese Software' },
];

/**
 * Startbildschirm: Wo stehe ich – und wie geht es weiter?
 *
 * Die Prüfungsreife steht oben, die fünf Wege ins Lernen darunter. Fällt der
 * Lernstand aus, bleibt der Bildschirm bedienbar und erklärt in einem Satz,
 * was fehlt.
 *
 * **Warum darunter ein Sprungmenü steht.** Diese Ansicht ist bei 1265 Pixel
 * Breite **8530** Pixel hoch – gemessen am 30.08.2026 an
 * `docs/bildschirmfotos/01-startbildschirm-hell.png`, im hohen Kontrast 8602.
 * Die Zahl stand hier bis Fassung 0.25.0 bei 8078: dem Stand von 0.20.0, vor
 * dem die Seite 9032 maß. Sie ist seither um 452 Pixel gewachsen, ohne dass
 * jemand die Zahl nachgezogen hätte. Wer mit einem Bildschirmleser arbeitet, hat
 * die Überschriftenliste; wer sieht, hatte bisher nur das Rollen. Das Menü
 * steht bewusst **unter** der Einstieg-Karte und nicht darüber: Die Karte hat
 * ein gemessenes Höhenbudget, damit der Weg ins Lernen im ersten Bildschirm
 * bleibt (`e2e/blickfeld.spec.ts`). Eine Leiste davor kostete dieses Budget.
 *
 * **Warum nichts zugeklappt ist.** Naheliegend wäre, die selten gebrauchten
 * Karten in `<details>` zu stecken. Dagegen sprechen zwei Dinge: Der Inhalt
 * eines geschlossenen `<details>` steht weder in der Überschriftenliste noch
 * in der Suche des Fensters – genau die beiden Wege, die Bildschirmleser-
 * Nutzenden heute schon offenstehen, wären damit weg. Und in „Einstellungen“
 * steckt die Anzeigegröße: Wer die Anwendung nicht lesen kann, darf nicht
 * erst ein Aufklappelement finden müssen. Der Weg ist deshalb das Verzeichnis
 * und nicht das Verstecken.
 */
export function Startbildschirm({
  einstiegRef,
  lernstand,
  lernplan,
  katalogZustand,
  katalogIndex,
  onKatalogNeuLaden,
  kuerzel,
  einstellungen,
  hilfsmittelAktiv,
  themaAuswahl,
  onThema,
  onWeiterlernen,
  onKapitelWahl,
  onNurFehler,
  hartnaeckigeFragen,
  onHartnaeckigeUeben,
  onGemerkte,
  onOffeneFragen,
  offenePruefung,
  onPruefungFortsetzen,
  onPruefung,
  onGlossar,
  onSuche,
  onUeber,
}: StartbildschirmProps): React.JSX.Element {
  const katalogBereit = katalogZustand.art === 'fertig';

  /*
    Das eine dauerhaft abwählbare Kapitel. Kennung und Titel kommen aus dem
    Katalog, nicht aus einer zweiten Pflege – ein hier eingetragener Titel
    liefe bei der nächsten BVA-Fassung auseinander.
  */
  const abwaehlbaresKapitel =
    katalogZustand.art === 'fertig'
      ? (katalogZustand.index.katalog.kapitel
          .filter((kapitel) => kapitel.id === KAPITEL_IV)
          .map((kapitel) => ({ id: kapitel.id, titel: kapitel.titel }))[0] ?? null)
      : null;

  const profil = lernstand.profile.find((eintrag) => eintrag.id === lernstand.profilId) ?? null;
  const mitKapitel = !(profil?.kapitelAusschluss ?? []).includes(KAPITEL_IV);
  const { werte, aendern } = einstellungen;
  const sprechtempo = sprechtempoBereinigen(werte.sprechtempo);
  /* Zwei Gründe, zwei Kennungen: Der Knopf verweist über `aria-describedby`
     auf genau den Satz, der seine Sperre erklärt. */
  const pruefungGrundId = useId();
  const sucheGrundId = useId();
  const sprachausgabeMoeglich = typeof window !== 'undefined' && 'speechSynthesis' in window;

  const fehleranzahl = lernstand.uebersicht?.fehler ?? null;

  /* Fragenzahl je Kapitel und Abschnitt – für die Umfangsansage der
     Fragenliste. Aus dem Katalog und nicht aus dem Lernstand: Die Liste
     hängt am Katalog, sie ist für jedes Profil dieselbe. */
  const fragenJeBereich = useMemo(() => {
    const karte = new Map<string, number>();
    for (const frage of katalogIndex?.katalog.fragen ?? []) {
      karte.set(frage.kapitel, (karte.get(frage.kapitel) ?? 0) + 1);
      if (frage.abschnitt !== null) {
        karte.set(frage.abschnitt, (karte.get(frage.abschnitt) ?? 0) + 1);
      }
    }
    return karte;
  }, [katalogIndex]);

  return (
    <>
      <Einstieg
        einstiegRef={einstiegRef}
        lernstand={lernstand}
        lernplan={lernplan}
        katalogBereit={katalogBereit}
        onWeiterlernen={onWeiterlernen}
        onKapitelWahl={onKapitelWahl}
        onNurFehler={onNurFehler}
        onGemerkte={onGemerkte}
        onOffeneFragen={onOffeneFragen}
      />

      {/* Unmittelbar nach dem Einstieg und vor allem anderen: Die Reihenfolge
          der täglichen Handlungsknöpfe bleibt unverändert, und wer eine
          Simulation starten will, sieht vorher, dass noch eine offensteht.
          Auch vor dem Sprungmenü – eine offene Simulation ist eine Sache, ein
          Inhaltsverzeichnis ist keine. */}
      {offenePruefung.lauf === null ? null : (
        <Unterbrochen
          lauf={offenePruefung.lauf}
          onFortsetzen={onPruefungFortsetzen}
          onVerwerfen={offenePruefung.verwerfen}
        />
      )}

      <Sprungmenue ziele={SPRUNGZIELE} beschriftung="Weiter unten auf dieser Seite" />

      <section className="karte abschnitt" aria-labelledby="pruefungsteil-titel">
        <h2 id="pruefungsteil-titel" tabIndex={-1}>
          Prüfungssimulation
        </h2>

        {offenePruefung.lauf === null ? null : (
          <Hinweis art="hinweis">
            Es steht noch eine unterbrochene Simulation offen. Eine neue zu starten verwirft sie –
            setzen Sie sie oben fort oder verwerfen Sie sie zuerst ausdrücklich.
          </Hinweis>
        )}
        <p>
          Ein ganzer Bogen am Stück, ohne Rückmeldung zwischendurch – so, wie es in der Prüfung
          zugeht. Fragenzahl, Zeit und Bestehensgrenze wählen Sie über ein Profil; die Zeitvorgabe
          lässt sich verlängern oder ganz abschalten.
        </p>

        {/* Der Grund steht vor der Schaltfläche: Wer nicht weiterkommt, soll
            ihn gelesen haben, bevor er den gesperrten Knopf erreicht. Der
            Knopf verweist zusätzlich über `aria-describedby` darauf. */}
        {katalogBereit ? null : (
          <p className="startwahl__gesperrt" id={pruefungGrundId}>
            Solange der Fragenkatalog nicht geladen ist, lässt sich keine Simulation starten.
          </p>
        )}

        <div className="startwahl">
          {/* `aria-disabled` statt `disabled` (Projektregel, docs/stand.md
              7.13): Ein gesperrter Knopf fällt aus der Tabulatorreihenfolge,
              und der Fokus landet auf `<body>`. So bleibt er erreichbar,
              meldet sich als nicht verfügbar und nennt den Grund; der
              Klickbehandler kehrt früh zurück. */}
          <button
            type="button"
            className="knopf startwahl__knopf"
            aria-disabled={!katalogBereit}
            {...(katalogBereit ? {} : { 'aria-describedby': pruefungGrundId })}
            onClick={() => {
              if (katalogBereit) {
                onPruefung();
              }
            }}
          >
            {/* „vorbereiten“ und nicht „starten“: Der Knopf führt in die
                Vorbereitung („Prüfungssimulation vorbereiten“), und erst deren
                Schaltfläche „Simulation starten“ wirft die Uhr an. */}
            <span className="startwahl__name">Prüfungssimulation vorbereiten</span>
            <span className="startwahl__erklaerung">
              Profil, Zeitvorgabe und Umfang im nächsten Schritt wählen
            </span>
          </button>
        </div>
      </section>

      <section className="karte abschnitt" aria-labelledby="lernstand-titel">
        <h2 id="lernstand-titel" tabIndex={-1}>
          Ihr Lernstand im Einzelnen
        </h2>

        {lernstand.laedt ? <p>Ihr Lernstand wird geladen …</p> : null}

        {katalogZustand.art === 'fehler' ? (
          <>
            <Hinweis art="fehler">{katalogZustand.meldung}</Hinweis>
            <p>
              <button type="button" className="knopf" onClick={onKatalogNeuLaden}>
                Fragenkatalog erneut laden
              </button>
            </p>
          </>
        ) : null}

        {katalogZustand.art === 'laedt' ? <p>Der Fragenkatalog wird geladen …</p> : null}

        {lernstand.uebersicht !== null ? (
          <Lernstandsuebersicht uebersicht={lernstand.uebersicht} />
        ) : null}

        {/*
          Die Fragen, die immer wieder danebengehen.

          Hier und nicht auf der Einstiegskarte: Es ist eine Auskunft für den,
          der schon eine Weile lernt – vor der ersten Sitzung gibt es nichts
          zu zeigen, und die Liste blendet sich dann von selbst aus.
        */}
        <Hartnaeckige
          fragen={hartnaeckigeFragen}
          katalogIndex={katalogIndex}
          onUeben={onHartnaeckigeUeben}
        />
      </section>

      <section className="karte abschnitt" aria-labelledby="lernplan-titel">
        <h2 id="lernplan-titel" tabIndex={-1}>
          Ihr Lernplan
        </h2>
        <p>
          Das Programm schätzt für jede Frage, wie sicher Sie sie gerade noch abrufen können, und
          legt danach fest, wann sie wiederkommt. Mit einem Prüfungstermin rückt es die
          Wiederholungen zum Termin hin enger zusammen.
        </p>
        <Lernplanung
          zustand={lernplan}
          abwaehlbaresKapitel={abwaehlbaresKapitel}
          mitKapitel={mitKapitel}
          onMitKapitel={(mit) => {
            void lernplan.kapitelAusschlussSetzen(mit ? [] : [KAPITEL_IV]).then(() => {
              /* Beide Haken neu laden. Sie sind bewusst entkoppelt und haben
                 getrennte Zähler – wer nur einen anstößt, zeigt für eine Weile
                 575 im Lernstand und 486 im Plan, untereinander auf demselben
                 Bildschirm. */
              lernstand.neuLaden();
            });
          }}
        />
      </section>

      {/* Vor dem Glossar: Beides ist Nachschlagen, aber die Suche ist der
          allgemeinere Weg – wer einen Begriff sucht, findet ihn hier auch,
          und zwar in den Fragen selbst. Bewusst KEIN fünfter Knopf in der
          Einstieg-Karte: Deren vier sind die täglichen Wege, die Suche ist
          ein Nachschlagen. */}
      <section className="karte abschnitt" aria-labelledby="suche-titel">
        {/* Überschrift, Schaltfläche und die Überschrift der Zielansicht sagen
            dasselbe Wort. Bis Fassung 0.20.0 hieß dieselbe Sache hier „Fragen
            finden“, auf dem Knopf „Fragen durchsuchen“ und in der Hilfe
            „Fragen finden und nachschlagen“. */}
        <h2 id="suche-titel" tabIndex={-1}>
          Fragen durchsuchen
        </h2>
        <p>
          Den Wortlaut aller Fragen und ihrer Antwortmöglichkeiten durchsuchen – nach einem
          Stichwort aus dem Lehrgang, nach einer Fragennummer, oder ohne Suchbegriff einfach ein
          ganzes Kapitel der Reihe nach durchsehen. Von jedem Treffer geht es direkt ins Üben.
        </p>
        {/* Gesperrt ohne Katalog – wie die Prüfungssimulation. Ohne die
            Sperre führte der Knopf in eine Ansicht, die App.tsx mangels
            Katalogindex gar nicht rendert: leerer Hauptbereich, keine
            Überschrift, und der Fokus fiele auf <body>. */}
        {katalogBereit ? null : (
          <p className="startwahl__gesperrt" id={sucheGrundId}>
            Solange der Fragenkatalog nicht geladen ist, lässt sich nicht darin suchen.
          </p>
        )}
        <div>
          <button
            type="button"
            className="knopf"
            aria-disabled={!katalogBereit}
            {...(katalogBereit ? {} : { 'aria-describedby': sucheGrundId })}
            onClick={() => {
              if (katalogBereit) {
                onSuche();
              }
            }}
          >
            Fragen durchsuchen
          </button>
        </div>
      </section>

      <section className="karte abschnitt" aria-labelledby="glossar-titel">
        <h2 id="glossar-titel" tabIndex={-1}>
          Glossar
        </h2>
        <p>
          Das Waffenrecht benutzt Alltagswörter mit eigener Bedeutung. „Führen“ heißt nicht lenken,
          „Erwerben“ hat mit Kaufen nichts zu tun. Wer das nicht weiß, versteht die Frage nicht –
          unabhängig davon, wie gut er den Stoff kann.
        </p>
        <div>
          <button type="button" className="knopf" onClick={onGlossar}>
            Fachbegriffe nachschlagen
          </button>
        </div>
      </section>

      {/* Eine Karte für alle drei Dokumente. Vorher standen sie als drei
          gleichrangige Karten untereinander, jede mit einer eigenen Frage
          nach der Schriftgröße – zusammen rund 1740 der damals 9032 Pixel
          dieser Seite; nachgemessen sind es heute 8530. Die Begründung im
          Einzelnen steht in `Druckkarte.tsx`. */}
      <section className="karte abschnitt" aria-labelledby="drucken-titel">
        <h2 id="drucken-titel" tabIndex={-1}>
          Drucken
        </h2>
        <Druckkarte
          profilId={lernstand.profilId}
          fehleranzahl={fehleranzahl}
          kapitel={katalogIndex === null ? null : katalogIndex.katalog.kapitel}
          fragenJeBereich={fragenJeBereich}
          fragenGesamt={katalogIndex?.katalog.fragen.length ?? 0}
        />
      </section>

      {/*
        Eine eigene Karte mit `h2` und nicht ein Punkt unter „Einstellungen“:
        Eine Sicherung ist keine Einstellung, und als `h3` wäre sie eine unter
        zwölf. In der Überschriftenliste eines Bildschirmlesers (NVDA und F7)
        ist sie so überhaupt auffindbar.
      */}
      <section className="karte abschnitt" aria-labelledby="sicherung-titel">
        <h2 id="sicherung-titel" tabIndex={-1}>
          Lernstand sichern und übertragen
        </h2>
        <Datensicherung
          onEingespielt={(ersteProfilId) => {
            /*
              Der Wechsel ist nicht verzichtbar: `useLernstand` hält die
              zuletzt gewählte Nummer in einem Ref, das ein Neuladen überlebt.
              Steht dort eine Nummer, die es in der eingespielten Datenbank
              zufällig auch gibt – bei Nummern ab 1 der Regelfall –, führte sie
              geradewegs in das Profil einer anderen Person.
            */
            lernstand.wechselnZu(ersteProfilId);
            lernstand.neuLaden();
            lernplan.neuLaden();
          }}
        />
      </section>

      <section className="karte abschnitt" aria-labelledby="einstellungen-titel">
        <h2 id="einstellungen-titel" tabIndex={-1}>
          Einstellungen
        </h2>

        {/* Zuoberst: Wer die Anwendung nicht lesen kann, findet hier zuerst
            das, was ihm dabei hilft. */}
        <div>
          <h3 id="anzeigegroesse-titel">Anzeigegröße</h3>
          <Anzeigegroessenwahl gespeichert={werte.anzeigegroesse} />
        </div>

        {/* Gleich daneben, aber getrennt: Der Zoom skaliert alles gemeinsam
            und hilft bei zu kleiner Schrift. Wer mit Legasthenie liest,
            braucht oft nicht größere Buchstaben, sondern mehr Luft zwischen
            ihnen – das ist eine andere Einstellung mit anderem Zweck. */}
        <div>
          <h3 id="textabstand-titel">Textdarstellung</h3>
          <Textabstandswahl
            gespeichert={werte.textabstand}
            onWaehlen={(stufe) => {
              aendern({ textabstand: stufe });
            }}
          />
        </div>

        {/* Danach: wer lernt. Der Wechsel steht hier und nirgends sonst –
            der Startbildschirm ist der einzige Ort, an dem keine Sitzung
            und keine Prüfung läuft, die er durcheinanderbringen könnte. */}
        <div>
          <h3 id="profile-titel">Profile</h3>
          <Profilverwaltung
            profile={lernstand.profile}
            profilId={lernstand.profilId}
            laedt={lernstand.laedt}
            onWechseln={lernstand.wechselnZu}
            onGeaendert={lernstand.neuLaden}
          />
        </div>

        <div>
          <h3 id="farbschema-titel">Farbschema</h3>
          <ThemaWahl auswahl={themaAuswahl} onAuswahl={onThema} beschriftetVon="farbschema-titel" />
        </div>

        {/* Zwei Regler, beide ab Werk aus. Ausgeschaltet steht die Anwendung
            so nah am amtlichen Katalog wie möglich; eingeschaltet wird es
            schwerer. Die Beschriftung sagt bei beiden, was das kostet –
            keiner von ihnen verspricht einen Lernvorteil, den es nicht
            belegt gibt (siehe docs/entscheidung-antwortreihenfolge.md). */}
        <div>
          <h3 id="schwierigkeit-titel">Schwierigkeit</h3>

          <Schalter
            beschriftung="Anzahl der richtigen Antworten verbergen"
            aktiv={werte.antwortzahlVerbergen ?? false}
            onAktiv={(an) => {
              aendern({ antwortzahlVerbergen: an });
            }}
            erklaerung={
              <>
                Ausgeschaltet verrät die Lernsitzung, ob eine oder mehrere Antworten richtig sind.
                Eingeschaltet entfällt dieser Hinweis, und es erscheinen ausnahmslos
                Kontrollkästchen – so hält es die Prüfungssimulation ohnehin. Sie üben dann ohne
                einen Hinweis, den die Prüfung nicht gibt.
              </>
            }
          />

          <Schalter
            beschriftung="Antwortmöglichkeiten mischen"
            aktiv={werte.optionenMischen ?? false}
            onAktiv={(an) => {
              aendern({ optionenMischen: an });
            }}
            erklaerung={
              <>
                Ausgeschaltet stehen die Antwortmöglichkeiten in der Reihenfolge des amtlichen
                Katalogs: Die erste heißt a), die zweite b). Das erleichtert den Vergleich mit der
                gedruckten Vorlage und gibt allen Halt, die sich Antworten über ihre Stelle merken.
                Eingeschaltet wechseln die Antworten ihre Stelle; der Buchstabe wandert mit seinem
                Inhalt mit und steht dann nicht mehr der Reihe nach – die erste gezeigte Antwort
                kann c) heißen. Ein Lernvorteil des Mischens ist nicht belegt. Die Einstellung gilt
                auch in der Prüfungssimulation.
              </>
            }
          />
        </div>

        <div>
          <h3 id="vorlesen-titel">Vorlesen</h3>
          <Schalter
            beschriftung="Fragen und Antworten vorlesen lassen"
            aktiv={(werte.vorlesen ?? false) && sprachausgabeMoeglich}
            deaktiviert={!sprachausgabeMoeglich}
            onAktiv={(an) => {
              aendern({ vorlesen: an });
            }}
            erklaerung={
              <>
                Blendet in Lernsitzung und Prüfungssimulation eine Schaltfläche ein, die vorliest,
                was gerade dasteht: die Frage samt Antwortmöglichkeiten, nach dem Bestätigen die
                Rückmeldung. Gesprochen wird ausschließlich, wenn Sie darauf drücken – von selbst
                sagt die Anwendung nichts. Anhalten können Sie jederzeit mit derselben Schaltfläche.
                Es werden die Stimmen Ihres Betriebssystems benutzt und keine Daten übertragen.
              </>
            }
            hinweis={
              sprachausgabeMoeglich ? (
                hilfsmittelAktiv && (werte.vorlesen ?? false) ? (
                  <Hinweis art="hinweis">
                    Es läuft bereits ein Hilfsmittel wie ein Screenreader. Beide zugleich sprechen
                    durcheinander – diese Sprachausgabe ist für Menschen gedacht, die keinen
                    Screenreader benutzen, etwa bei einer Lese-Rechtschreib-Störung oder ermüdeten
                    Augen.
                  </Hinweis>
                ) : null
              ) : (
                <Hinweis art="hinweis">Dieses System bietet keine Sprachausgabe an.</Hinweis>
              )
            }
          />

          {/*
            Die beiden Zusatzschalter erscheinen erst, wenn die Sprachausgabe
            an ist – sie hätten sonst nichts, worauf sie wirken könnten.
            Bewusst nicht als gesperrte Kästchen: Ein Schalter, dessen
            Einstellung gerade auf nichts wirkt, ist ein Angebot ohne Ziel.
            Dass es sie gibt, sagt der Satz am Schalter darüber.

            Beide stehen für sich und sind ab Werk aus. Die nützlichste
            Einstellung ist die, die man sonst nicht treffen könnte: sonst
            selbst lesen, aber bei einem Fehler die Begründung hören.
          */}
          {sprachausgabeMoeglich && (werte.vorlesen ?? false) ? (
            <div className="einstellungen__untergeordnet">
              <Schalter
                beschriftung="Frage und Rückmeldung von selbst vorlesen"
                aktiv={werte.vorlesenAutomatisch ?? false}
                onAktiv={(an) => {
                  aendern({ vorlesenAutomatisch: an });
                }}
                erklaerung={
                  <>
                    Dann müssen Sie nicht bei jeder Frage drücken: Die Frage wird vorgelesen, sobald
                    sie erscheint, und die Rückmeldung, sobald Sie bestätigt haben. Gesprochen wird
                    dasselbe wie auf Knopfdruck. In der Prüfungssimulation gilt das nicht – dort
                    bleibt es bei der Schaltfläche.
                  </>
                }
              />

              <Schalter
                beschriftung="Bei falscher Antwort die ausführliche Begründung vorlesen"
                aktiv={werte.vorlesenErklaerungBeiFehler ?? false}
                onAktiv={(an) => {
                  aendern({ vorlesenErklaerungBeiFehler: an });
                }}
                erklaerung={
                  <>
                    Gemeint ist der lange Text unter „Warum das so ist“, nicht der eine Satz
                    darüber. Er wird sonst nirgends gesprochen, auch nicht auf Knopfdruck: Gelesen
                    dauert er über eine Minute. Wer eine Frage falsch hatte, hat diese Minute meist
                    übrig – bei jeder richtigen Antwort wäre sie lästig.
                  </>
                }
              />

              {/*
                Das Tempo stand bis 0.22.0 fest auf der Systemvorgabe: `rate`
                wurde nie gesetzt. Wer schneller oder langsamer hören musste,
                konnte nichts tun – bei minutenlangen Rechtstexten und der
                Zielgruppe, die der Schalter oben selbst benennt, ist das eine
                echte Hürde.
              */}
              <div className="tempowahl">
                <p id="sprechtempo-stand" className="tempowahl__stand" role="status">
                  {sprechtempoAnsage(sprechtempo)}
                </p>
                <div className="tempowahl__knoepfe">
                  {SPRECHTEMPI.map((stufe) => (
                    <button
                      key={stufe}
                      type="button"
                      className="knopf"
                      aria-pressed={stufe === sprechtempo}
                      aria-describedby="sprechtempo-stand"
                      onClick={() => {
                        aendern({ sprechtempo: stufe });
                      }}
                    >
                      {sprechtempoText(stufe)}
                    </button>
                  ))}
                </div>
              </div>
            </div>
          ) : null}
        </div>

        <div>
          <h3 id="tastenkuerzel-titel">Tastenkürzel</h3>
          <KuerzelHilfe
            aktiv={kuerzel.aktiv}
            onAktiv={kuerzel.setzen}
            wegenHilfsmittelAus={kuerzel.wegenHilfsmittelAus}
            meldung={kuerzel.meldung}
          />
        </div>

        {/* Ganz unten: Was Daten löscht, gehört nicht neben einen Schalter,
            den man beiläufig umlegt. */}
        <div>
          <h3 id="neuanfang-titel">Neu anfangen</h3>
          {/* Das Zurücksetzen nimmt einen offenen Bogen mit – die Karte
              oben muss danach verschwinden, nicht erst beim nächsten
              Start. */}
          <Neuanfang
            profilId={lernstand.profilId}
            onZurueckgesetzt={() => {
              lernstand.neuLaden();
              offenePruefung.neuLaden();
            }}
          />
        </div>

        {einstellungen.meldung === null ? null : (
          <Hinweis art="fehler" alsMeldung>
            {einstellungen.meldung}
          </Hinweis>
        )}
      </section>

      <section className="karte abschnitt" aria-labelledby="systemzustand-titel">
        <h2 id="systemzustand-titel" tabIndex={-1}>
          Systemzustand
        </h2>
        <p>
          Diese Angaben helfen bei Rückfragen zur Installation. Sie werden direkt vom Anwendungskern
          abgefragt.
        </p>
        <SystemStatus
          katalog={katalogZustand.art === 'fertig' ? katalogZustand.index.katalog.meta : null}
        />
      </section>

      <section className="karte abschnitt" aria-labelledby="ueber-start-titel">
        <h2 id="ueber-start-titel" tabIndex={-1}>
          Über diese Software
        </h2>
        <p>
          Lizenz dieser Anwendung, Rechtslage des amtlichen Fragenkatalogs und die Lizenzen aller
          mitgelieferten Fremdkomponenten.
        </p>
        <div>
          <button type="button" className="knopf" onClick={onUeber}>
            Lizenzen und Herkunft anzeigen
          </button>
        </div>
      </section>
    </>
  );
}
