/* ============ CodeQuest – Design ============ */
:root {
  --bg: #0d1117;
  --bg-soft: #161b22;
  --bg-card: #1c2128;
  --bg-hover: #262c36;
  --border: #30363d;
  --text: #e6edf3;
  --text-dim: #9198a1;
  --accent: #58a6ff;
  --accent-soft: rgba(88, 166, 255, .12);
  --green: #3fb950;
  --green-soft: rgba(63, 185, 80, .12);
  --red: #f85149;
  --red-soft: rgba(248, 81, 73, .12);
  --yellow: #d29922;
  --yellow-soft: rgba(210, 153, 34, .15);
  --purple: #bc8cff;
  /* Mehrstufige, weiche Schatten für Tiefe (dunkles Theme => dezent halten) */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .30), 0 2px 8px rgba(0, 0, 0, .20);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, .30), 0 8px 24px rgba(0, 0, 0, .35);
  --shadow-lg: 0 8px 16px rgba(0, 0, 0, .40), 0 24px 56px rgba(0, 0, 0, .55);
  --radius: 12px;
  --sidebar-w: 250px;
  --mono: 'Cascadia Code', 'Consolas', 'Fira Code', monospace;
  /* Code-Blöcke im Fließtext (Theorie, Cheatsheets, Lückentext): folgen dem Theme */
  --code-bg: #11151c;
  /* Terminal-Flächen (Programm-Ausgabe, stdin-Feld): bleiben in BEIDEN Themes
     bewusst dunkel wie ein echtes Terminal — diese Werte werden im hellen
     Theme absichtlich NICHT überschrieben. */
  --terminal-bg: #080b10;
  --terminal-text: #e6edf3;
  --terminal-dim: #9198a1;
  --terminal-accent: #58a6ff;
  /* Buttons & Akzent-Flächen: Textfarbe + Verläufe (im hellen Theme invertiert) */
  --btn-text: #0d1117;
  --btn-grad: linear-gradient(180deg, #6cb6ff, #4b9af8);
  --btn-green-grad: linear-gradient(180deg, #4ac95e, #35a745);
  --text-strong: #fff;
  --selection-bg: rgba(88, 166, 255, .35);
  --scrollbar-thumb: #2d333c;
  --scrollbar-thumb-hover: #3d444f;
  --sidebar-shadow: 0 0 40px rgba(0, 0, 0, .6);
}

/* ============ Helles Theme (GitHub-Light-Palette) ============
   Aktiviert über <html data-theme="light">. js/pwa.js setzt das Attribut
   schon im <head> (kein Theme-Flash), js/app.js beim Umschalten.
   Bewusste Ausnahme: --terminal-* bleibt dunkel (siehe oben). */
:root[data-theme="light"] {
  --bg: #ffffff;
  --bg-soft: #f6f8fa;
  --bg-card: #ffffff;
  --bg-hover: #eaeef2;
  --border: #d0d7de;
  --text: #1f2328;
  /* Vier Toene dunkler als bei GitHub „default", naemlich deren
     „emphasis"-Stufe. Der Grund ist gemessen (axe-core, WCAG 2 AA, 4,5:1):
     Auf ihrem EIGENEN getoenten Grund reichten die helleren Werte nicht.
       .badge-pill.yellow  #9a6700 auf #f3ede0 = 4,17:1   (26x je Pfadseite)
       .badge-pill.green   #1a7f37 auf #e4f0e7 = 4,33:1
       .nav-item.active    #0969da auf #deeaf7 = 4,26:1   (immer sichtbar)
       .nav-progress       #656d76 auf #deeaf7 = 4,30:1
     Auf weissem Grund waren dieselben Werte in Ordnung – deshalb fiel es nie
     auf, und deshalb war ausgerechnet das HELLE Theme die schlechtere Haelfte.
     Jetzt: 4,88 bis 6,11:1 auf den getoenten Flaechen, 6,09 bis 7,59:1 auf
     weiss. Weisser Text auf den Knopf-Farben bleibt bei 7,4 bis 7,6:1. */
  --text-dim: #5b636c;
  --accent: #0550ae;
  --accent-soft: rgba(5, 80, 174, .10);
  --green: #116329;
  --green-soft: rgba(17, 99, 41, .12);
  --red: #cf222e;
  --red-soft: rgba(207, 34, 46, .10);
  --yellow: #7d4e00;
  --yellow-soft: rgba(125, 78, 0, .12);
  --purple: #8250df;
  /* Helle Fläche braucht deutlich dezentere Schatten */
  --shadow-sm: 0 1px 2px rgba(31, 35, 40, .06), 0 2px 6px rgba(31, 35, 40, .05);
  --shadow-md: 0 2px 4px rgba(31, 35, 40, .08), 0 8px 24px rgba(31, 35, 40, .10);
  --shadow-lg: 0 8px 16px rgba(31, 35, 40, .12), 0 24px 48px rgba(31, 35, 40, .16);
  --code-bg: #f6f8fa;
  --btn-text: #ffffff;
  --btn-grad: linear-gradient(180deg, #1168d8, #0550ae);
  --btn-green-grad: linear-gradient(180deg, #23883f, #116329);
  --text-strong: #1f2328;
  --selection-bg: rgba(5, 80, 174, .22);
  --scrollbar-thumb: #c6ccd2;
  --scrollbar-thumb-hover: #a8b0b9;
  --sidebar-shadow: 0 0 40px rgba(31, 35, 40, .25);
}

/* Einzelne fest eingefärbte Flächen im hellen Theme nachziehen */
:root[data-theme="light"] .continue-card {
  background: linear-gradient(120deg, rgba(9, 105, 218, .08), rgba(130, 80, 223, .06));
  border-color: rgba(9, 105, 218, .35);
}
:root[data-theme="light"] .player-progress { box-shadow: inset 0 1px 3px rgba(31, 35, 40, .12); }

/* ============ Schriftgrößen-Stufen ============
   Die Stylesheets nutzen fast durchgehend rem/em — eine geänderte Wurzel-
   Schriftgröße skaliert also Fließtext, Lektionstexte UND den Editor mit.
   Standard (mittel) = 16px ohne Attribut; body nutzt dafür 1rem. */
:root[data-fontsize="s"] { font-size: 14px; }
:root[data-fontsize="l"] { font-size: 18px; }

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

html { scroll-behavior: smooth; }

/* Keine Font-Ligaturen im Code: Anfänger sollen >= als zwei Zeichen sehen,
   nicht als ≥ (Cascadia/Fira Code würden das sonst zusammenziehen). */
.CodeMirror, .fallback-editor, .fill-code, pre, code, .output {
  font-variant-ligatures: none;
}

/* Eingaben-Feld („Terminal-Ersatz") unter dem Editor */
.stdin-panel { margin: 10px 0 4px; }
.stdin-panel label { display: block; font-size: .82rem; color: var(--text-dim); margin-bottom: 6px; }
.stdin-area {
  width: 100%;
  /* Bewusst in beiden Themes dunkel — gehört optisch zum Terminal (Ausgabe) */
  background: var(--terminal-bg);
  color: var(--terminal-text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  font-family: var(--mono);
  font-size: .9rem;
  resize: vertical;
}
.stdin-area:focus { border-color: var(--terminal-accent); outline: none; }

/* Terminal-Eingabezeile in der Ausgabe (Python im Worker-Modus) */
.term-input-row { display: flex; align-items: center; gap: 8px; margin: 2px 0; }
/* Aktive Eingabezeile: dezenter Akzent-Balken links, damit man sie sofort sieht */
.term-input-row.term-live {
  border-left: 2px solid var(--terminal-accent);
  padding-left: 6px;
}
.term-prompt { color: var(--terminal-accent); white-space: pre; }
/* Blinkender Block-Cursor am Prompt – nur solange die Zeile auf Eingabe wartet
   (Klasse term-live wird beim Enter im JS wieder entfernt) */
.term-input-row.term-live .term-prompt::after {
  content: '▊';
  animation: blink 1s steps(1) infinite;
}
@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}
.term-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--terminal-dim);
  color: var(--terminal-text);
  font-family: var(--mono);
  font-size: inherit;
  padding: 2px 4px;
  outline: none;
}
.term-input:focus { border-bottom-color: var(--terminal-accent); }
.term-echo { color: #d29922; } /* fix, da die Terminal-Fläche nie hell wird */

/* Terminal-STEP (Lektionstyp 'terminal') – simuliertes Terminal, offline.
   In BEIDEN Themes dunkel (Terminal-Charakter). */
.terminal {
  background: var(--terminal-bg);
  color: var(--terminal-text);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .45);
  padding: 12px 14px;
  font-family: var(--mono);
  font-size: .88rem;
  margin: 14px 0;
}
.term-output { max-height: 260px; overflow-y: auto; white-space: pre-wrap; }
.term-line { line-height: 1.5; }
.term-cmd { color: #e6edf3; }               /* eingetippter Befehl, hell */
.term-cmd .term-prompt { color: var(--terminal-accent); }
.term-err { color: #ff7b72; }               /* Fehlermeldung, kräftiges Rot (Kontrast > 4.5:1 auf #080b10) */
.term-sys { color: #7ee787; }               /* System-/Willkommenszeile, Grün */
.term-input-line { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.term-input-line .term-prompt::after {
  content: '▊';
  margin-left: 2px;
  color: var(--terminal-accent);
  animation: blink 1s steps(1) infinite;
}
.terminal .term-input { border-bottom: none; }

/* Die Brücke ins echte Linux (js/lesson-engine.js, linuxBruecke).
   Bewusst leise: Sie steht unter JEDEM Terminal-Schritt des Linux-Pfads und
   wäre als Knopf eine Aufforderung, die Lektion zu verlassen. Ein Satz in
   Fußnoten-Größe ist ein Angebot. */
.term-bruecke {
  margin: -6px 0 14px;
  font-size: .85rem;
  color: var(--text-dim);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: baseline;
}
.term-bruecke a { color: var(--accent); font-weight: 600; text-decoration: none; }
.term-bruecke a:hover { text-decoration: underline; }
.term-bruecke-was { color: var(--text-dim); }

/* ============ Barrierefreiheit ============ */
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Editor-Kommentare aufhellen: das material-darker-Standardgrau (#545454)
   erreicht nur ~2.4:1 Kontrast und fällt damit unter WCAG AA. #8b949e liegt
   bei ~5.5:1 auf dem Editor-Hintergrund und bleibt trotzdem dezent. */
.cm-s-material-darker span.cm-comment,
.CodeMirror .cm-comment { color: #8b949e !important; }
/* … aber NICHT im hellen Theme: Dort steht der Editor auf Weiss, und #8b949e
   ergibt darauf 3,07:1 (gemessen mit axe-core). Ein Kommentar ist der Teil des
   Codes, der erklaert, warum etwas so ist – ausgerechnet den unlesbar zu
   machen, waere in einer Lern-App die falsche Stelle zum Sparen. #57606a
   schafft 5,9:1 und bleibt trotzdem deutlich zurueckhaltender als der Code. */
:root[data-theme="light"] .CodeMirror .cm-comment { color: #57606a !important; }
/* Dieselbe Rechnung noch zweimal – und der Anlass war ein Test, der EINEN TAG
   lang rot war.

   tests/barrierefreiheit.test.mjs prüft unter anderem `#/daily`, und welche
   Aufgabe dort steht, entscheidet der Kalender (js/views-practice.js wählt
   deterministisch aus dem Datum). Am 15.09.2026 war die CI grün, am 16.09.
   rot – ohne dass jemand an der Daily oder am Editor etwas geändert hätte.
   Rot war nicht der Code, sondern die Aufgabe des Tages: Sie enthält einen
   f-String, und CodeMirror färbt den als `string-2`.

   Deshalb stehen die beiden Farben hier und nicht in einer Ausnahmeliste im
   Test. Eine Ausnahme hätte den Tag repariert und den nächsten f-String
   wieder rot werden lassen; sie hätte ausserdem eine echte Verletzung
   stillgelegt – 2,65:1 auf den Zeilennummern ist keine Messungenauigkeit.

     Zeilennummern: #999999 (hell) bzw. #545454 (dunkel) sind die Vorgaben von
     CodeMirror bzw. material-darker und erreichen 2,65:1 und 2,12:1. Dieselben
     zwei Töne wie beim Kommentar eine Zeile höher – 5,2:1 auf dem dunklen
     Bundsteg, 5,9:1 auf dem hellen.

     `string-2` (f-Strings, rohe Strings): #ff5500 auf Weiss sind 3,2:1.
     #b34700 ist derselbe Ton, nur dunkel genug – 5,5:1. Nur im hellen Theme,
     weil material-darker seinen eigenen, ausreichenden Wert mitbringt. */
.CodeMirror .CodeMirror-linenumber { color: #8b949e !important; }
:root[data-theme="light"] .CodeMirror .CodeMirror-linenumber { color: #57606a !important; }
:root[data-theme="light"] .CodeMirror .cm-string-2 { color: #b34700 !important; }
#main:focus { outline: none; } /* programmatischer Fokus (Skip-Link), kein Ring nötig */

/* Nur für Screenreader – visuell unsichtbar */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Skip-Link: unsichtbar, bis er per Tab fokussiert wird */
.skip-link {
  position: absolute; left: -9999px; top: 10px; z-index: 300;
  background: var(--accent); color: var(--btn-text);
  border: none; border-radius: 8px; padding: 10px 16px;
  /* 44 px hoch: Es ist das erste Tab-Ziel der Seite und am Handy ein
     Antippziel wie jedes andere. WCAG 2.5.8 verlangt 24x24 CSS-Pixel,
     2.5.5 empfiehlt 44x44 - hier ist Platz genug fuer die Empfehlung. */
  min-height: 44px;
  display: inline-flex; align-items: center;
  font-size: .9rem; font-weight: 600; cursor: pointer;
}
.skip-link:focus { left: 10px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
}

/* ============ Kontrastmodus des Betriebssystems ============

   `forced-colors` greift, wenn Windows den Kontrastmodus einschaltet (früher
   „High Contrast"). Der Browser ersetzt dann JEDE Farbe durch eine aus der
   Palette des Nutzers – auch die, auf denen diese App Bedeutung transportiert.
   Zwei Dinge gehen dabei kaputt, wenn man nichts tut:

   1. Ränder verschwinden. Karten, Editor-Kästen und Optionsknöpfe stehen hier
      auf Flächenfarbe, nicht auf Rahmen; im Kontrastmodus werden die Flächen
      gleich, und man sieht nicht mehr, wo eine Karte anfängt. Deshalb bekommen
      die Container hier einen echten Rahmen aus der Systempalette.

   2. Richtig und falsch sehen gleich aus. Grün und Rot sind der Kern der
      Rückmeldung im Player. `forced-color-adjust: none` an genau diesen
      Stellen behält die Ampelfarben – die Ausnahme ist erlaubt und hier
      begründet: Ihre Bedeutung IST die Farbe.

   `prefers-contrast: more` ist der leisere Fall (macOS/iOS „Kontrast
   erhöhen"): keine erzwungene Palette, nur der Wunsch nach mehr Trennung.
   Dort reicht es, Rahmen und gedämpften Text kräftiger zu machen. */
@media (forced-colors: active) {
  .card, .lang-card, .quiz-option, .editor-wrap, .output, .terminal,
  .modal, .toast, .order-item, .fill-code {
    border: 1px solid CanvasText;
  }
  .btn, .pref-btn, .skip-link { border: 1px solid ButtonText; }
  /* Der aktive Navigationseintrag ist sonst nur eine Hintergrundfarbe. */
  .nav-item.active { outline: 2px solid Highlight; outline-offset: -2px; }
  .feedback.ok, .feedback.err, .quiz-option.correct, .quiz-option.wrong,
  .fill-input.correct, .fill-input.wrong { forced-color-adjust: none; }
}

@media (prefers-contrast: more) {
  /* Bewusst NUR der Rahmen. `--text-dim` auf `--text` zu ziehen, waere die
     naheliegende zweite Zeile - und der Fehler: Dann saehen Ueberschrift,
     Fliesstext und Nebenbemerkung gleich aus, und die Hierarchie, die beim
     Lesen hilft, waere weg. Mehr Kontrast heisst besser unterscheidbar, nicht
     ununterscheidbar. */
  :root { --border: var(--text-dim); }
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
  font-size: 1rem; /* folgt der Wurzel-Schriftgröße (data-fontsize), statt fixer 16px */
  line-height: 1.55;
}

/* ============ Layout ============ */
.app { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  background: var(--bg-soft);
  border-right: 1px solid var(--border);
  padding: 20px 14px;
  position: fixed;
  top: 0; left: 0; bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 50;
  overflow-y: auto;
}

/* Der Statusstreifen („CodeQuest v179 · Runner bereit", angelegt in
   js/app.js). Er sagt, welche Version laeuft und ob der Runner bereit ist –
   beides will man beim Melden eines Fehlers ablesen koennen, also bleibt er.

   Bis Version 179 lag er fest unten LINKS, also ueber der Seitenleiste, und
   verdeckte den Fortschrittszaehler der untersten sichtbaren Pfad-Zeile
   (Gutachten v163, Befund 4f, gemessen an `…/97` von Python). Ein
   `padding-bottom` an der Leiste haette nur das Ende der Liste freigeraeumt –
   mitten im Scrollen waeren die Eintraege weiter unter ihm durchgelaufen.
   Deshalb steht er jetzt RECHTS der Leiste; auf dem Telefon, wo es keine
   Leiste gibt, wieder links. Den Platz unter dem Inhalt reserviert
   `.main { padding-bottom }`. */
.build-info {
  position: fixed;
  left: calc(var(--sidebar-w) + 8px);
  bottom: 8px;
  z-index: 99998;
  background: #065f46;
  color: #d1fae5;
  padding: 4px 10px;
  border-radius: 8px;
  font: 11px/1.3 system-ui, -apple-system, sans-serif;
  opacity: .9;
  pointer-events: none;
}

.main {
  flex: 1;
  /* Reserve fuer den Statusstreifen unten (siehe .build-info): Ohne sie
     liegt er am Seitenende ueber der letzten Zeile. */
  padding-bottom: 44px;
  /* min-width: 0 ist hier KEIN Detail, sondern der Unterschied zwischen
     „passt aufs Handy" und „passt nicht".

     .main ist ein Flex-Kind von .app. Flex-Kinder haben von Haus aus
     `min-width: auto` – sie schrumpfen also nicht unter die natürliche Breite
     ihres Inhalts. Ein einziges <pre> mit einer langen Codezeile (die haben
     `white-space: pre`, brechen also nie um) zieht damit die GANZE Seite auf:
     gemessen 431 px bei einem 375-px-Viewport. Folge auf dem Handy: Die Seite
     lässt sich seitlich wegschieben, die Topbar hängt halb daneben, und die
     „Prüfen"-Schaltfläche liegt teils außerhalb des Bildschirms.

     Mit min-width: 0 darf .main schmaler werden als sein Inhalt – und die
     einzelnen breiten Elemente scrollen dann in sich selbst (siehe pre/output
     weiter unten), statt das Layout zu sprengen. */
  min-width: 0;
  margin-left: var(--sidebar-w);
  padding: 32px clamp(16px, 4vw, 48px);
  max-width: 1100px;
}

.topbar { display: none; }

/* ============ Sidebar ============ */
.logo {
  display: flex; align-items: center; gap: 10px;
  font-size: 1.3rem; font-weight: 700;
  padding: 6px 10px 18px;
  cursor: pointer;
  /* Dezenter Text-Gradient (accent → purple) für den Schriftzug */
  background: linear-gradient(90deg, var(--accent), var(--purple));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.logo-icon { font-size: 1.5rem; -webkit-text-fill-color: initial; } /* Emoji-Icon vom Gradient ausnehmen */
img.logo-icon { width: 28px; height: 28px; display: block; flex-shrink: 0; } /* SVG-Logo (assets/logo.svg) sauber ausrichten */

.nav { display: flex; flex-direction: column; gap: 2px; }
.nav-fold > summary, .nav-paths-fold > summary {
  cursor: pointer; color: var(--text-dim); border-radius: 8px;
  padding: 10px 12px; font-size: .82rem; font-weight: 700;
}
.nav-fold > summary:hover, .nav-paths-fold > summary:hover { background: var(--bg-hover); color: var(--text); }
.nav-fold[open] > summary, .nav-paths-fold[open] > summary { color: var(--accent); }
.nav-fold .nav-item { margin-left: 8px; }
.nav-paths-fold { border-top: 1px solid var(--border); margin-top: 8px; }
.nav-paths-fold > summary { display: flex; align-items: center; gap: .4rem; }
.nav-paths-fold > summary::before { content: '▸'; }
.nav-paths-fold[open] > summary::before { content: '▾'; }
#nav-path-count { margin-left: auto; color: var(--text-dim); }

.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  color: var(--text-dim);
  text-decoration: none;
  font-weight: 500;
  transition: background .15s, color .15s, box-shadow .15s;
  /* Der Pfadname steht als nackter Textknoten zwischen den beiden <span>
     (js/app.js, buildLangNav) und ist damit ein ANONYMES Flex-Item. Solche
     Items haben `min-width: auto` und schrumpfen nicht unter ihr laengstes
     Wort - bei „Spieleprogrammierung" oder „Versionsverwaltung" wird die Zeile
     dadurch breiter als die 250 px der Leiste, der Zaehler rutscht hinaus und
     unten erscheint ein waagrechter Scrollbalken. Gemessen: 261 px Inhalt bei
     249 px Platz, mit der grossen Schrift (A+) 287 px.

     `anywhere` statt `break-word`, und das ist hier der ganze Punkt: Nur
     `anywhere` senkt auch die INTRINSISCHE Mindestbreite auf null, wirkt also
     auf die Berechnung des Flex-Layouts. `break-word` bricht zwar ebenfalls
     um, laesst die Mindestbreite aber stehen - die Zeile bliebe zu breit.
     `hyphens: auto` bricht davor, wo es geht, mit Trennstrich (das Dokument
     traegt lang="de"). */
  overflow-wrap: anywhere;
  hyphens: auto;
}
.nav-item:hover { background: var(--bg-hover); color: var(--text); }
/* Aktiver Eintrag: Akzent-Balken links (per Inset-Schatten, kein Layout-Shift) */
.nav-item.active {
  background: var(--accent-soft);
  color: var(--accent);
  box-shadow: inset 3px 0 0 var(--accent);
}
.nav-item .nav-progress {
  margin-left: auto;
  font-size: .75rem;
  color: var(--text-dim);
  /* Nicht schrumpfen und nicht umbrechen: Der Zaehler ist die Auskunft, wegen
     der die Zeile ueberhaupt zwei Teile hat. `flex: none` haelt ihn ganz,
     `nowrap` verhindert, dass das geerbte overflow-wrap „28/28" zerlegt. */
  flex: none;
  white-space: nowrap;
}

/* Die Zahl ungelesener Post (V258). Anders als `.nav-progress` ist sie ein
   Hinweis und keine Statistik – deshalb gefüllt und nicht nur getönt.

   Der Farbwert ist nicht frei gewählt: `--accent` auf `--accent-soft` ist der
   Kontrast, der oben bei `.nav-item.active` schon nachgemessen ist (4,26:1 im
   hellen Thema). Weiß auf `--accent` liegt darüber. Eine eigene Ampelfarbe
   hätte hier eine vierte Messung gebraucht, für nichts. */
.nav-item .nav-zahl {
  margin-left: auto;
  flex: none;
  white-space: nowrap;
  font-size: .72rem;
  font-weight: 700;
  min-width: 18px;
  text-align: center;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
}

.nav-section-title {
  font-size: .72rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--text-dim);
  padding: 18px 12px 6px;
}

/* Gruppenueberschrift INNERHALB der Pfadliste (Grundlagen, Sprachen, …).
   Kleiner und leiser als .nav-section-title: Die steht ueber der ganzen
   Liste, diese hier gliedert sie nur. Die Zahl dahinter sagt, wie viele
   Pfade der Block hat – dieselbe Auskunft wie im Raster der Startseite. */
.nav-group-title {
  display: flex; align-items: center; gap: 8px;
  font-size: .68rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-dim);
  padding: 12px 12px 4px;
}
.nav-group-title::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.nav-group-count { font-size: .68rem; opacity: .75; order: 3; }

.sidebar-footer { margin-top: auto; padding: 14px 10px 4px; border-top: 1px solid var(--border); }
.mini-stats { display: flex; gap: 14px; font-size: .85rem; color: var(--text-dim); }
.mini-stats b { color: var(--text); }

/* Anzeige-Einstellungen (Theme-Toggle + A−/A+) unter den Mini-Stats */
.pref-row { display: flex; gap: 6px; margin-top: 10px; }
.pref-btn {
  flex: 1;
  background: var(--bg-hover);
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: 8px;
  padding: 5px 0;
  /* Gemessen waren diese Knoepfe 28 px hoch - unter der Zielgroesse aus
     WCAG 2.5.8 (24x24 ist das Minimum, 44x44 die Empfehlung aus 2.5.5).
     Theme und Schriftgroesse sind genau die Einstellungen, die jemand mit
     eingeschraenkter Sicht oder Motorik zuerst sucht; ausgerechnet sie
     schwer treffbar zu machen, waere die falsche Stelle zum Sparen. */
  min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.pref-btn:hover { color: var(--text); border-color: var(--accent); }
.pref-btn:disabled { opacity: .4; cursor: not-allowed; border-color: var(--border); color: var(--text-dim); }

/* ============ Allgemeine Bausteine ============ */
h1 { font-size: 1.85rem; font-weight: 700; letter-spacing: -.01em; margin-bottom: 6px; }
h2 { font-size: 1.25rem; margin: 26px 0 12px; }
.subtitle { color: var(--text-dim); margin-bottom: 24px; }

.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  box-shadow: var(--shadow-sm); /* dezente Tiefe statt „flacher Fläche" */
}

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--accent);
  /* Dezenter Verlauf für mehr Wertigkeit; Fallback bleibt --accent */
  background-image: var(--btn-grad);
  color: var(--btn-text);
  border: none;
  padding: 10px 18px;
  border-radius: 8px;
  font-size: .95rem;
  font-weight: 600;
  cursor: pointer;
  transition: filter .15s, transform .1s, box-shadow .15s;
  text-decoration: none;
}
.btn:hover {
  filter: brightness(1.1);
  box-shadow: 0 2px 10px rgba(88, 166, 255, .35), 0 4px 18px rgba(0, 0, 0, .25);
  transform: translateY(-1px);
}
.btn:active { transform: scale(.98); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover { filter: none; box-shadow: none; transform: none; } /* kein Hover-Effekt auf inaktiven Buttons */
.btn.secondary { background: var(--bg-hover); color: var(--text); border: 1px solid var(--border); }
.btn.secondary:hover { box-shadow: var(--shadow-sm); }
.btn.green { background: var(--green); background-image: var(--btn-green-grad); }
.btn.green:hover { box-shadow: 0 2px 10px rgba(63, 185, 80, .35), 0 4px 18px rgba(0, 0, 0, .25); }
.btn.ghost { background: transparent; color: var(--text-dim); border: 1px solid var(--border); }
.btn.ghost:hover { color: var(--text); border-color: var(--accent); box-shadow: none; }
.btn.small { padding: 6px 12px; font-size: .85rem; }

.badge-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 99px;
  font-size: .75rem;
  font-weight: 600;
}
/* Feiner Rand per Inset-Schatten (kein Layout-Shift durch echte Border) */
.badge-pill.green { background: var(--green-soft); color: var(--green); box-shadow: inset 0 0 0 1px rgba(63, 185, 80, .35); }
.badge-pill.blue { background: var(--accent-soft); color: var(--accent); box-shadow: inset 0 0 0 1px rgba(88, 166, 255, .35); }
.badge-pill.yellow { background: var(--yellow-soft); color: var(--yellow); box-shadow: inset 0 0 0 1px rgba(210, 153, 34, .35); }
/* Kontrast 4,57:1 hell, 4,55:1 dunkel */
.badge-pill.red { background: var(--red-soft); color: var(--red); box-shadow: inset 0 0 0 1px rgba(248, 81, 73, .35); }

/* ============ Dashboard ============ */
.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; margin-bottom: 28px; }
.stat-card {
  text-align: center;
  padding: 18px 10px;
  /* Sehr subtiler radialer Glanz am oberen Rand */
  background-image: radial-gradient(120% 65% at 50% 0%, rgba(88, 166, 255, .07), transparent 70%);
}
.stat-card .stat-icon { font-size: 1.6rem; }
.stat-card .stat-value {
  font-size: 1.5rem; font-weight: 700; margin: 4px 0 0;
  /* Zahl mit Text-Gradient accent → purple */
  background: linear-gradient(135deg, var(--accent), var(--purple));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.stat-card .stat-label { font-size: .8rem; color: var(--text-dim); }

.level-bar { height: 8px; background: var(--bg-hover); border-radius: 99px; overflow: hidden; margin-top: 8px; }
.level-bar > div { height: 100%; background: linear-gradient(90deg, var(--accent), var(--purple)); border-radius: 99px; transition: width .4s; }

.lang-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }

/* ---- Kategorien im Pfad-Raster (js/views-learn.js langGrid) ----
   Ohne Gruppierung stehen 24 gleichwertige Kacheln nebeneinander und der
   Einstieg ist reine Glückssache. */
.lang-section { margin: 22px 0 6px; }
.lang-section-title {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 2px; font-size: 1.05rem; font-weight: 700;
}
.lang-section-count {
  font-size: .75rem; font-weight: 600; color: var(--text-dim);
  background: var(--bg-soft); border-radius: 99px; padding: 2px 9px;
}
.lang-section-text { margin: 0 0 12px; font-size: .88rem; color: var(--text-dim); }

/* ---- Etappen auf der Pfadseite (stufenKopf) ---- */
.stufe-kopf {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 26px 0 10px; font-size: 1rem; font-weight: 700;
  padding-bottom: 6px; border-bottom: 1px solid var(--border);
}
.stufe-kopf.done { color: var(--green, #3fb950); }
.stufe-fortschritt {
  display: flex; align-items: center; gap: 8px;
  margin-left: auto; font-size: .82rem; font-weight: 600; color: var(--text-dim);
}
.stufe-fortschritt .level-bar { width: 90px; }

/* ---- „Weiter geht's mit …" (weiterHinweis / Zertifikat) ---- */
.weiter-card { margin-top: 22px; display: flex; flex-direction: column; gap: 12px; }
.weiter-liste { display: flex; flex-wrap: wrap; gap: 10px; }

.lang-card {
  display: block;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: border-color .15s, transform .15s, box-shadow .15s;
  position: relative;
}
/* Hover: sanft anheben + weicher Schatten mit Akzent-Glow am Rand */
.lang-card:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: var(--shadow-md), 0 8px 24px rgba(88, 166, 255, .10);
}
.lang-card .lang-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.lang-card .lang-icon { font-size: 1.8rem; }
.lang-card .lang-name { font-weight: 700; font-size: 1.05rem; }
.lang-card .lang-desc { font-size: .85rem; color: var(--text-dim); min-height: 40px; }

/* Aufbau-Hinweis auf der Pfadkarte und im Pfad-Kopf (Feld `requires`).
   Bewusst dezent: Es ist eine Empfehlung, keine Sperre. */
.lang-card .lang-requires {
  font-size: .78rem;
  color: var(--text-dim);
  /* KEIN `opacity` mehr. `--text-dim` ist auf beiden Themes so gewaehlt, dass
     es 4,5:1 schafft – eine zusaetzliche Deckkraft von .85 zog genau daran und
     landete bei 4,39:1 (gemessen, 35 Elemente auf der Startseite). Wer dezent
     will, nimmt einen dezenteren TON, nicht weniger Deckkraft: Der Ton laesst
     sich pruefen, die Multiplikation sieht niemand. */
  margin-top: 4px;
}
.path-requires {
  font-size: .85rem;
  color: var(--text-dim);
  margin: 6px 0 0;
}
.path-requires a { color: var(--accent); text-decoration: none; }
.path-requires a:hover { text-decoration: underline; }
/* Kein `opacity` auf Text – siehe .lang-requires weiter oben. */
.path-requires-hint { color: var(--text-dim); }
.lang-card .lang-progress { margin-top: 12px; display: flex; align-items: center; gap: 10px; font-size: .8rem; color: var(--text-dim); }
.lang-card .lang-progress .level-bar { flex: 1; margin: 0; }

.continue-card {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: linear-gradient(120deg, rgba(88,166,255,.14), rgba(188,140,255,.10));
  border-color: rgba(88,166,255,.4);
  margin-bottom: 28px;
  flex-wrap: wrap;
}

.daily-card { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 28px; }

/* ============ Lernpfad ============ */
.path-header { display: flex; align-items: center; gap: 16px; margin-bottom: 8px; }
.path-header .lang-icon { font-size: 2.4rem; }

.module {
  margin: 26px 0;
  border-left: 3px solid var(--border);
  padding-left: 22px;
  position: relative;
}
.module.done { border-left-color: var(--green); }
.module-title { font-size: 1.1rem; font-weight: 700; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.module-desc { color: var(--text-dim); font-size: .9rem; margin: 4px 0 14px; }

/* Mini-Fortschrittsbalken pro Modul (im Modul-Titel) */
.module-progress {
  display: inline-flex; align-items: center; gap: 8px;
  margin-left: auto;
  font-size: .78rem; font-weight: 600; color: var(--text-dim);
  white-space: nowrap;
}
.module-progress .level-bar { width: 72px; margin-top: 0; }

.lesson-list { display: flex; flex-direction: column; gap: 8px; }

.lesson-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: border-color .15s, background .15s, box-shadow .15s, transform .15s;
  box-shadow: var(--shadow-sm);
}
.lesson-row:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
  box-shadow: var(--shadow-md), 0 4px 16px rgba(88, 166, 255, .08);
  transform: translateX(2px);
}
.lesson-row.locked { opacity: .5; cursor: not-allowed; }
.lesson-row.locked:hover { border-color: var(--border); background: var(--bg-card); box-shadow: var(--shadow-sm); transform: none; }
.lesson-row .lesson-status { font-size: 1.2rem; width: 28px; text-align: center; }
.lesson-row .lesson-name { font-weight: 500; flex: 1; }
.lesson-row .lesson-xp { font-size: .8rem; color: var(--text-dim); }
.lesson-row.project-row { border-style: dashed; border-color: var(--purple); }
.lesson-row.project-row:hover { background: rgba(188,140,255,.08); }

/* ============ Lesson-Player ============ */
.player { max-width: 820px; margin: 0 auto; }

.player-top { display: flex; align-items: center; gap: 14px; margin-bottom: 26px; }
.player-progress {
  flex: 1; height: 12px;
  background: var(--bg-hover);
  border-radius: 99px;
  overflow: hidden;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, .4); /* leichte Rinne für den Balken */
}
.player-progress > div {
  height: 100%;
  background: linear-gradient(90deg, var(--green), #56d364);
  border-radius: 99px;
  transition: width .3s;
  box-shadow: 0 0 10px rgba(63, 185, 80, .55); /* weicher Glow */
}
.player-quit { color: var(--text-dim); text-decoration: none; font-size: 1.3rem; }
.player-quit:hover { color: var(--text); }

/* Schritt-Zähler „3 / 8" neben dem Balken. Der Balken zeigt, WIE VIEL
   geschafft ist – beim Vor- und Zurückblättern will man zusätzlich wissen,
   WO man gerade steht. tabular-nums, damit die Zahl beim Wechseln nicht
   springt. */
.player-step { color: var(--text-dim); font-size: .85rem; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Kasten auf einem Schritt, den man schon hinter sich hat (js/lesson-engine.js).
   Ohne ihn sieht man beim Zurückblättern ein leeres Quiz und hält sich für
   zurückgeworfen. */
.step-erledigt {
  margin-bottom: 16px; padding: 8px 12px;
  border: 1px solid var(--border); border-left: 3px solid var(--green);
  border-radius: 8px;
  background: var(--bg-hover);
  color: var(--text-dim); font-size: .88rem;
}
.step-erledigt b { color: var(--text); }

.step-title { font-size: 1.35rem; margin-bottom: 16px; }

.step-content { animation: fadeIn .25s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* Theorie-Text */
.md { overflow-wrap: anywhere; }
.md p { margin: 10px 0; }
/* Seit V163 rendert js/md.js `###` als h2 (Schritt-Titel ist h1) – die
   Groesse bleibt bewusst dieselbe, geaendert hat sich nur die Ebene. */
.md h2 { margin: 18px 0 8px; font-size: 1.05rem; }
.md ul, .md ol { margin: 10px 0 10px 22px; }
.md li { margin: 4px 0; }
.md code {
  background: var(--bg-hover);
  border: 1px solid var(--border);
  padding: 1px 6px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: .88em;
}
.md pre {
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  overflow-x: auto;
  margin: 12px 0;
}
.md pre code { background: none; border: none; padding: 0; font-size: .9rem; }
/* Lange Inline-Pfade müssen auch mit breiteren Systemschriften auf dem Handy
   umbrechen. Mehrzeilige Codeblöcke behalten ihren eigenen Scrollbereich. */
.md :not(pre) > code { overflow-wrap: anywhere; }
.md blockquote {
  border-left: 3px solid var(--yellow);
  background: var(--yellow-soft);
  padding: 10px 14px;
  border-radius: 0 8px 8px 0;
  margin: 12px 0;
}
.md strong { color: var(--text-strong); }

/* Tabellen in Theorie-Texten (js/md.js). Der Wrapper scrollt waagrecht, damit
   eine breite Tabelle auf dem Handy nicht die ganze Seite verschiebt. */
.md-table-wrap { overflow-x: auto; margin: 14px 0; }
.md-table-wrap table {
  border-collapse: collapse;
  width: 100%;
  min-width: 320px;
  font-size: .92rem;
}
.md-table-wrap th,
.md-table-wrap td {
  border: 1px solid var(--border);
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
}
.md-table-wrap th {
  background: var(--bg-soft);
  color: var(--text-strong);
  font-weight: 600;
  white-space: nowrap;
}
.md-table-wrap tbody tr:nth-child(even) td { background: var(--bg-soft); }
.md-table-wrap code { white-space: nowrap; }

/* Quiz */
.quiz-options { display: flex; flex-direction: column; gap: 10px; margin: 18px 0; }
.quiz-option {
  padding: 13px 16px;
  background: var(--bg-card);
  border: 2px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color .12s, background .12s;
  font-family: inherit; font-size: .95rem; color: var(--text); text-align: left;
}
.quiz-option:hover { border-color: var(--accent); }
.quiz-option.selected { border-color: var(--accent); background: var(--accent-soft); }
.quiz-option.correct { border-color: var(--green); background: var(--green-soft); }
.quiz-option.wrong { border-color: var(--red); background: var(--red-soft); }
.quiz-option code { font-family: var(--mono); background: var(--bg-hover); padding: 1px 5px; border-radius: 4px; }

/* Lückentext */
.fill-code {
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px 18px;
  font-family: var(--mono);
  font-size: .95rem;
  line-height: 2.1;
  white-space: pre-wrap;
  margin: 16px 0;
}
.fill-input {
  background: var(--bg-hover);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--text);
  font-family: var(--mono);
  font-size: .92rem;
  padding: 3px 8px;
  width: 110px;
  text-align: center;
}
.fill-input.correct { border-color: var(--green); background: var(--green-soft); }
.fill-input.wrong { border-color: var(--red); background: var(--red-soft); animation: shake .3s; }

/* Code-Blöcke ordnen (Parsons) */
.order-list { display: flex; flex-direction: column; gap: 8px; margin: 16px 0; }
.order-item {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  font-family: var(--mono);
  font-size: .9rem;
  cursor: grab;
  user-select: none;
}
.order-item.dragging { opacity: .4; }
.order-item .order-handle { color: var(--text-dim); cursor: grab; }
.order-item .order-btns { margin-left: auto; display: flex; gap: 4px; }
.order-item .order-btns button {
  background: var(--bg-hover); border: 1px solid var(--border); color: var(--text-dim);
  border-radius: 6px; width: 26px; height: 26px; cursor: pointer; font-size: .8rem;
}
.order-item .order-btns button:hover { color: var(--text); border-color: var(--accent); }
.order-item pre { margin: 0; white-space: pre; }

/* Editor & Ausgabe */
.editor-wrap {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  margin: 16px 0 10px;
  box-shadow: var(--shadow-sm);
}

/* Statusleiste für Native-Aufgaben (echter Prozess auf dem PC statt Pyodide).
   Sagt ehrlich, ob der lokale Runner läuft und ob dieser PC die nötigen
   Fähigkeiten hat (z. B. os.fork gibt es unter Windows nicht). */
.native-bar {
  margin: 16px 0 -6px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-soft);
  font-size: 0.92em;
  line-height: 1.5;
}
.native-bar code { font-size: 0.95em; }
.native-bar.native-on { border-color: #2ea04366; background: #2ea04314; }
.native-bar.native-partial { border-color: #d2992266; background: #d2992214; }
.native-bar.native-off { border-color: #58a6ff66; background: #58a6ff14; }
.editor-toolbar {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-soft);
  border-bottom: 1px solid var(--border);
  padding: 8px 12px;
  font-size: .8rem; color: var(--text-dim);
}
.editor-toolbar .spacer { flex: 1; }
.CodeMirror { height: auto; min-height: 120px; font-family: var(--mono); font-size: .92rem; }
/* Dunkle Editor-Fläche NUR fürs dunkle Editor-Theme erzwingen (material-darker
   bringt #212121 mit, wir wollen unser #11151c). Das helle 'default'-Theme
   (heller App-Modus, siehe lesson-engine.js/createEditor) behält sein Weiß. */
.cm-s-material-darker.CodeMirror { background: #11151c !important; }
.CodeMirror-scroll { max-height: 420px; }
.fallback-editor {
  width: 100%; min-height: 160px; resize: vertical;
  background: var(--code-bg); color: var(--text); border: none; outline: none;
  font-family: var(--mono); font-size: .92rem; padding: 12px; tab-size: 4;
}

.run-row { display: flex; gap: 10px; margin: 12px 0; flex-wrap: wrap; }

.output {
  /* Bewusst in BEIDEN Themes dunkel => „Terminal"-Charakter (siehe --terminal-*) */
  background: var(--terminal-bg);
  color: var(--terminal-text);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .45); /* Innen-Schatten: leicht vertieft */
  padding: 12px 16px;
  font-family: var(--mono);
  font-size: .88rem;
  white-space: pre-wrap;
  min-height: 44px;
  max-height: 300px;
  overflow-y: auto;
  scroll-behavior: smooth; /* sanftes Mitscrollen beim Live-Streamen */
}
/* Fixe Farben: die Terminal-Fläche wird nie hell, Theme-Rot/-Dim wären dort zu dunkel */
.output .out-err { color: #f85149; }
.output .out-dim, .output.out-dim { color: var(--terminal-dim); }

/* Die Leinwand (js/leinwand.js): das Bild unter der Konsole.

   Anders als `.output` bewusst HELL in beiden Themes – eine Zeichnung ist
   kein Terminal, und ein schwarzer Strich auf schwarzem Grund ist kein
   Strich. Die Strichfarben selbst passt der Renderer ans Theme an; der
   Untergrund bleibt Papier. */
.leinwand-box {
  margin-top: 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  background: #fdfdfb;
  text-align: center;
}
[data-theme="dark"] .leinwand-box { background: #15171c; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .leinwand-box { background: #15171c; }
}
.leinwand {
  /* max-width, damit das Bild auf dem Telefon nicht aus dem Kasten läuft:
     Das Canvas hat eine feste Pixelgröße, die Anzeige darf schrumpfen. */
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}
.leinwand-fuss {
  margin: 8px 0 0;
  font-size: .78rem;
  color: var(--text-dim);
}

/* Fehlermeldung: die Aussage nach oben, der Rahmen weg.

   Vorher stand der ganze stderr als ein Block da – bei Python sechs Zeilen,
   von denen die erste die Maschinerie zeigt und die letzte die Aussage. Man
   liest aber von oben. Jetzt: Aussage groß und zuerst, die Zeilennummer als
   Marke daneben, alles Übrige zusammengeklappt erreichbar. */
.output .out-err-kopf {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  flex-wrap: wrap;
}
.output .out-err-kopf .out-err {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
}
.output .out-err-zeile {
  flex: 0 0 auto;
  background: rgba(248, 81, 73, .16);
  color: #ff8c84;
  border-radius: 999px;
  padding: .05rem .5rem;
  font-size: .8rem;
  white-space: nowrap;
}
.output .out-err-mehr { margin-top: .5rem; }
.output .out-err-mehr summary {
  cursor: pointer;
  color: var(--terminal-dim);
  font-size: .82rem;
  /* Der Marker steht sonst als schwarzes Dreieck auf dunklem Grund. */
  list-style: none;
}
.output .out-err-mehr summary::before { content: '▸ '; }
.output .out-err-mehr[open] summary::before { content: '▾ '; }
.output .out-err-mehr summary:hover { color: var(--text); }
.output .out-err-roh {
  display: block;
  margin-top: .35rem;
  padding-left: .6rem;
  border-left: 2px solid rgba(248, 81, 73, .35);
  color: var(--terminal-dim);
}

/* Eingaben-Feld: es soll führen, nicht nur dastehen.

   „Eingaben aufgebraucht" ist einer der häufigsten Fehlschläge überhaupt –
   das Programm will eine Zeile mehr, als im Feld steht. Die Zeile darunter
   sagt deshalb laufend, wie viele Zeilen da sind, und der Knopf holt die
   Beispiel-Eingaben der Aufgabe zurück, ohne dass man sie abtippen muss. */
.stdin-fuss {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
  margin-top: .35rem;
  font-size: .82rem;
  color: var(--text-dim);
}
.stdin-fuss .stdin-zahl { font-variant-numeric: tabular-nums; }
.stdin-fuss .stdin-warn { color: var(--yellow, #d29922); }

/* web-Großprojekt: „Ausführen" zeigt im Ausgabefeld keine Zeilen, sondern die
   Seite selbst. Die dunkle Terminal-Fläche darum würde ihre Farben verfälschen
   – und genau die prüft die Abnahme später (Kontrast). */
.output.vorschau {
  padding: 0; border: 0; background: none; box-shadow: none;
  max-height: none; overflow: visible;
}
.output.vorschau .web-preview { margin: 0; }

.web-preview {
  width: 100%; height: 300px;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 10px;
  margin: 12px 0;
}

/* SQL-Ergebnistabelle */
.sql-table { border-collapse: collapse; width: 100%; font-size: .85rem; font-family: var(--mono); }
.sql-table th, .sql-table td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; }
.sql-table th { background: rgba(255, 255, 255, .08); } /* liegt im dunklen Terminal → fixer heller Schleier */

/* Feedback-Boxen */
.feedback {
  border-radius: 10px;
  padding: 14px 18px;
  margin: 16px 0;
  animation: fadeIn .2s;
}
/* Weicherer Hintergrund + kräftiger Farbbalken links: Status auf einen Blick */
.feedback.ok { background: rgba(63, 185, 80, .08); border: 1px solid rgba(63, 185, 80, .35); border-left: 3px solid var(--green); }
.feedback.err { background: rgba(248, 81, 73, .08); border: 1px solid rgba(248, 81, 73, .35); border-left: 3px solid var(--red); }
.feedback.hint { background: rgba(210, 153, 34, .08); border: 1px solid rgba(210, 153, 34, .35); border-left: 3px solid var(--yellow); }
.feedback b:first-child { display: block; margin-bottom: 4px; }
.feedback pre { margin: 8px 0 0; font-size: .85rem; overflow-x: auto; font-family: var(--mono); }

@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
.shake { animation: shake .3s; }

.player-actions {
  display: flex; gap: 10px; align-items: center;
  margin-top: 22px; padding-top: 18px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.player-actions .spacer { flex: 1; }

/* Lesson fertig */
.lesson-done { text-align: center; padding: 40px 20px; }
.lesson-done .done-icon { font-size: 4rem; animation: pop .4s ease; }
@keyframes pop { 0% { transform: scale(.3); } 70% { transform: scale(1.15); } 100% { transform: scale(1); } }
.lesson-done h2 { margin: 12px 0 6px; }
.lesson-done .xp-gain { font-size: 1.2rem; color: var(--yellow); font-weight: 700; }
.lesson-done .xp-bonus { margin-top: 2px; font-size: .9rem; color: var(--green); font-weight: 600; }

/* ============ Profil ============ */
.badge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
.badge-card { text-align: center; padding: 16px 8px; }
.badge-card .badge-icon { font-size: 2rem; }
.badge-card .badge-name { font-weight: 600; font-size: .85rem; margin-top: 6px; }
.badge-card .badge-desc { font-size: .72rem; color: var(--text-dim); }
/* Gesperrte Badges: das SYMBOL dimmen, den Text nicht.
   Vorher stand hier `.badge-card.locked { opacity: .35 }` fuer die ganze
   Karte. Auf 11,5-px-Text ergab das 1,72:1 im dunklen und 1,61:1 im hellen
   Theme – praktisch unlesbar, und zwar ausgerechnet bei der Liste, deren
   einziger Zweck es ist zu erklaeren, WIE man die Badges bekommt.
   Das graue, blasse Symbol traegt den Hinweis „noch nicht verdient" allein. */
.badge-card.locked .badge-icon { opacity: .35; filter: grayscale(1); }
.badge-card.locked .badge-name { color: var(--text-dim); font-weight: 500; }

/* ============ Nachschlagen ============ */
.ref-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.ref-search {
  width: 100%; padding: 11px 16px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px;
  color: var(--text); font-size: .95rem; margin-bottom: 18px; outline: none;
}
.ref-search:focus { border-color: var(--accent); }
.cheat-section { margin-bottom: 22px; }
.cheat-section h2 { margin-bottom: 10px; font-size: 1.15rem; }
.cheat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.cheat-card { padding: 14px 16px; }
.cheat-card .cheat-title { font-weight: 600; font-size: .9rem; margin-bottom: 8px; }
.cheat-card pre {
  background: var(--code-bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; font-family: var(--mono); font-size: .82rem; overflow-x: auto;
}
.cheat-card .cheat-note { font-size: .8rem; color: var(--text-dim); margin-top: 8px; }
/* ============ Toasts ============ */
.toast-container { position: fixed; bottom: 24px; right: 24px; display: flex; flex-direction: column; gap: 10px; z-index: 200; }
.toast {
  background: var(--bg-card);
  border: 1px solid var(--accent);
  border-radius: 10px;
  padding: 13px 18px;
  min-width: 220px;
  box-shadow: var(--shadow-lg);
  animation: slideIn .3s ease;
  font-size: .92rem;
}
.toast.badge-toast { border-color: var(--yellow); }
@keyframes slideIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
.toast.hide { opacity: 0; transition: opacity .4s; }

/* ============ Modal ============ */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.6);
  z-index: 150;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.modal-backdrop[hidden] { display: none; }
/* Weichzeichner hinter dem Modal – nur wo unterstützt, sonst bleibt das Abdunkeln */
@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .modal-backdrop {
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
    background: rgba(0, 0, 0, .5);
  }
}
.modal {
  background: var(--bg-soft);
  border: 1px solid var(--border);
  border-radius: 14px;
  max-width: 760px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: 26px;
  position: relative;
  box-shadow: var(--shadow-lg);
}
.modal-close {
  position: absolute; top: 12px; right: 14px;
  background: none; border: none; color: var(--text-dim);
  font-size: 1.1rem; cursor: pointer;
}
.modal-close:hover { color: var(--text); }

/* ============ Responsive ============ */
@media (max-width: 860px) {
  .sidebar { transform: translateX(-100%); transition: transform .25s; box-shadow: var(--sidebar-shadow); }
  .sidebar.open { transform: none; }
  .main { margin-left: 0; padding-top: 76px; }
  /* Ohne Seitenleiste gehoert der Streifen wieder an den linken Rand; die
     Reserve darunter steht schon in der Grundregel von .main. */
  .build-info { left: 8px; }
  .topbar {
    display: flex; align-items: center; gap: 4px;
    position: fixed; top: 0; left: 0; right: 0;
    background: var(--bg-soft);
    border-bottom: 1px solid var(--border);
    /* 4px statt 12px senkrecht: Der Burger darunter ist jetzt 44 px hoch und
       gibt die Höhe vor. Zusammen bleibt die Leiste bei denselben 52 px, auf
       die .main mit padding-top: 76px ausgelegt ist. */
    padding: 4px 16px;
    z-index: 40;
  }
  /* Der Burger ist auf dem Handy das einzige Tor zur Navigation – als reines
     Glyph war er nur 19 × 27 px groß und damit unter dem WCAG-Mindestziel von
     24 × 24 (2.5.8). Jetzt 44 × 44 (das AAA-Maß 2.5.5), ohne dass das Symbol
     wandert: Der negative linke Rand hebt die zusätzliche Breite wieder auf,
     sodass das ☰ optisch weiter am selben Platz sitzt. */
  .burger {
    background: none; border: none; color: var(--text); font-size: 1.3rem; cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: 0;
    margin-left: -12px;
  }
  .topbar-stats { margin-left: auto; font-size: .85rem; color: var(--text-dim); }
}

/* ============ Scrollbars & Selektion ============ */
/* Text-Markierung in Akzentfarbe statt Browser-Standard (folgt dem Theme) */
::selection { background: var(--selection-bg); color: var(--text); }

/* Dezente Scrollbars (Chromium/WebKit) — Farbe per Variable, folgt dem Theme */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: var(--scrollbar-thumb);
  border-radius: 99px;
  border: 2px solid transparent; /* schmaler wirkender Daumen mit Luft zum Rand */
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar-thumb-hover); }
::-webkit-scrollbar-corner { background: transparent; }

/* Firefox */
html, .sidebar, .output, .modal, .CodeMirror-scroll {
  scrollbar-color: var(--scrollbar-thumb) transparent;
}
.sidebar, .output, .modal { scrollbar-width: thin; }

/* ============ Autocomplete (CodeMirror show-hint) ============ */
/* Theme-Overrides für das Vorschlags-Popup: Das Addon-CSS ist fix hell und
   würde im dunklen Editor wie ein Fremdkörper wirken — Variablen lassen es
   beiden Themes folgen. z-index über dem Modal (150), damit Vorschläge auch
   in Dialogen nicht darunter verschwinden. */
.CodeMirror-hints {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  font-family: var(--mono);
  font-size: .9rem;
  padding: 4px;
  z-index: 400;
}
.CodeMirror-hint {
  color: var(--text);
  border-radius: 5px;
  padding: 3px 10px;
}
li.CodeMirror-hint-active {
  background: var(--accent);
  color: var(--btn-text); /* kontrastiert mit --accent in beiden Themes */
}

/* ============ Syntax-Lint (CodeMirror lint-Addon) ============
   Tooltip und Gutter-Marker per Variablen ans jeweilige Theme angepasst;
   die rote Wellenlinie selbst kommt aus vendor/codemirror/addon/lint.min.css. */
.CodeMirror-lint-tooltip {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  color: var(--text);
  font-family: var(--mono);
  font-size: .85rem;
  padding: 6px 10px;
  z-index: 400;
}
.CodeMirror-lint-message-error { color: var(--red); }
.CodeMirror-lint-message-warning { color: var(--yellow); }

/* ============ Lern-Statistik (Profil) ============
   Liste der kniffligsten Aufgaben: Name links, Details in der Mitte,
   Fehlerquote dezent rechts – ab 50 % rot, da lohnt ein Blick in den Content. */
.insight-list { display: flex; flex-direction: column; gap: 4px; }

/* ---------- „Wo stehst du?" (js/lernstand.js, Profil) ----------

   Die Vorschläge sehen bewusst aus wie die Karten auf der Startseite
   (.daily-card): Text links, Knopf rechts. Sie tun dasselbe – sie schicken
   jemanden an genau eine Stelle –, und zwei Gestalten für dieselbe Handlung
   wären zwei Sprachen in einer App. */
.lernstand-vorschlaege { display: flex; flex-direction: column; gap: 10px; }
.lernstand-vorschlag { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.lernstand-vorschlag-icon { font-size: 1.6rem; line-height: 1; }
.lernstand-vorschlag-text { flex: 1 1 240px; }
.lernstand-vorschlag-titel { font-weight: 700; }
.lernstand-vorschlag-sub { font-size: .88rem; color: var(--text-dim); margin-top: 2px; }

/* Zwei Spalten, wo Platz ist, untereinander am Handy. `1fr 1fr` statt
   `auto-fit`: Steht nur eine der beiden Spalten da („alles sitzt", oder noch
   nichts sitzt), soll sie die halbe Breite behalten und nicht über die ganze
   Seite laufen – eine einzelne Spalte in voller Breite sieht aus wie eine
   Liste und nicht wie die eine Hälfte eines Vergleichs. */
.lernstand-spalten { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; }
.lernstand-spalte h3 { margin: 0 0 2px; font-size: 1rem; }
.lernstand-modul { padding: 8px 0; border-bottom: 1px solid var(--border); }
.lernstand-modul:last-child { border-bottom: none; }
.lernstand-modul-kopf { display: flex; gap: 10px; align-items: baseline; justify-content: space-between; }
.lernstand-modul-titel { font-weight: 600; }
.lernstand-quote { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.lernstand-quote.schwach { color: var(--yellow); }
.lernstand-quote.stark { color: var(--green); }
.lernstand-modul-detail { font-size: .82rem; color: var(--text-dim); margin-top: 2px; }
.lernstand-link { display: inline-block; margin-top: 6px; font-size: .85rem; color: var(--accent); }

@media (max-width: 760px) {
  .lernstand-spalten { grid-template-columns: 1fr; }
}
/* Die Vorschau auf das, was beim Teilen übertragen würde (Profil).
   Klein, scrollbar und mit fester Höhe: Sie soll vollständig sein dürfen,
   ohne die Seite zu sprengen – eine gekürzte Vorschau wäre keine. */
/* Die drei Auswahlmöglichkeiten im Melde-Dialog (js/lesson-engine.js).
   Als große Klickflächen und nicht als <select>: Wer gerade an einer Aufgabe
   hängt, soll nicht auch noch ein Menü aufklappen müssen. */
.melde-arten { display: flex; flex-direction: column; gap: 8px; }
.melde-art {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; font-weight: 400;
}
.melde-art:hover { background: var(--bg-hover); }
.melde-art input { width: auto; margin: 3px 0 0; }
.melde-art:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

.teilen-vorschau {
  margin: 8px 0 0; padding: 10px 12px;
  max-height: 220px; overflow: auto;
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: 8px;
  font-size: .78rem; line-height: 1.45; white-space: pre; color: var(--text-dim);
}

.insight-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
  font-size: .92rem;
}
.insight-row:last-child { border-bottom: none; }
.insight-name { font-weight: 600; }
.insight-detail { color: var(--text-dim); font-size: .85rem; flex: 1; }
.insight-rate {
  margin-left: auto;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.insight-rate.high { color: var(--red); font-weight: 700; }

/* ============ Wochenziel-Karte (Startseite) ============ */
.goal-card {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 28px;
}
.goal-btns { display: flex; gap: 6px; }
.goal-btns .pref-btn { font-size: 1rem; width: 44px; flex: none; }
.goal-btns .pref-btn:disabled { opacity: .35; cursor: default; }

/* ============ Globale Suche ============ */
#search-results h2 { margin: 22px 0 10px; }
.search-crumb {
  display: block;
  font-weight: 400;
  font-size: .78rem;
  color: var(--text-dim);
}

/* ============ Konto (Login / Registrierung / Passwort-Reset) ============ */
.auth-card {
  max-width: 420px;
  display: flex; flex-direction: column; gap: 6px;
  padding: 20px;
}
.auth-card label { font-weight: 600; font-size: .88rem; margin-top: 8px; }
.auth-card input {
  padding: 11px 14px;
  background: var(--bg-soft); border: 1px solid var(--border); border-radius: 10px;
  color: var(--text); font-size: .95rem; outline: none;
}
.auth-card input:focus { border-color: var(--accent); }
.auth-card button[type="submit"] { margin-top: 14px; }
/* Altersbestätigung bei der Registrierung (Art. 8 DSGVO / § 4 Abs. 4 DSG).
   Eigene Regel, weil `.auth-card label` auf gestapelte Feldbeschriftungen
   ausgelegt ist – hier stehen Haken und Text nebeneinander, und der Text ist
   Fließtext statt Beschriftung, also normal gewichtet. Das Ziel ist 44 px
   hoch: Es ist ein Pflichtfeld auf einem Handy. */
.auth-card label.auth-check {
  display: flex; flex-direction: row; align-items: flex-start; gap: 10px;
  margin-top: 14px; min-height: 44px;
  font-weight: 400; font-size: .85rem; line-height: 1.45;
  color: var(--text-dim); cursor: pointer;
}
.auth-card label.auth-check input[type="checkbox"] {
  flex: none; width: 20px; height: 20px; margin-top: 2px;
  padding: 0; accent-color: var(--accent); cursor: pointer;
}
.auth-error {
  margin: 8px 0 0; padding: 9px 12px;
  background: var(--red-soft); border: 1px solid var(--red); border-radius: 8px;
  color: var(--red); font-size: .85rem;
}
.auth-links {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  flex-wrap: wrap; margin-top: 12px; font-size: .85rem;
}
.auth-links a { color: var(--accent); text-decoration: none; }
.auth-links a:hover { text-decoration: underline; }
.auth-hint { font-weight: 400; font-size: .78rem; color: var(--text-dim); }
.auth-hint a { color: var(--accent); }

/* Impressum/Datenschutz-Links am Profil-Ende */
.legal-links { margin-top: 26px; font-size: .8rem; color: var(--text-dim); }
/* Impressum und Datenschutz waren 15 px hoch - die einzigen Ziele der App,
   die selbst das Minimum aus WCAG 2.5.8 (24x24) rissen. Und es sind die
   beiden Links, auf die jemand klickt, der etwas Rechtliches sucht. */
.legal-links a {
  color: var(--text-dim); text-decoration: underline;
  display: inline-flex; align-items: center;
  min-height: 24px; padding: 4px 2px;
}
.legal-links a:hover { color: var(--text); }

/* Bestenliste: eigene Zeile hervorheben */
tr.lb-me { background: var(--bg-soft, rgba(88, 166, 255, .08)); }
tr.lb-me td:first-child { font-weight: 700; }

/* ---------- Landing / Schaufenster (Erstbesuch, js/views.js renderLanding) ---------- */
.landing-hero {
  text-align: center;
  padding: 40px 16px 30px;
  border-radius: var(--radius);
  background:
    radial-gradient(80% 120% at 50% -10%, var(--accent-soft), transparent 60%),
    var(--bg-soft);
  border: 1px solid var(--border);
  margin-bottom: 22px;
}
.landing-badge {
  display: inline-block;
  font-size: .8rem;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--border);
  padding: 5px 12px;
  border-radius: 999px;
  margin-bottom: 18px;
}
.landing-title {
  font-size: clamp(1.8rem, 5vw, 2.9rem);
  line-height: 1.12;
  margin: 0 0 14px;
  letter-spacing: -.02em;
}
.landing-accent {
  background: var(--btn-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.landing-sub {
  max-width: 640px;
  margin: 0 auto 22px;
  color: var(--text-dim);
  font-size: 1.02rem;
  line-height: 1.6;
}
.landing-cta {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}
.landing-cta .btn { font-size: 1.02rem; padding: 12px 22px; }
.landing-note { margin: 14px 0 0; font-size: .82rem; color: var(--text-dim); }

.landing-features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 14px;
  margin-bottom: 30px;
}
.landing-feature { text-align: left; }
.landing-feature-icon { font-size: 1.7rem; margin-bottom: 8px; }
.landing-feature-title { font-weight: 700; margin-bottom: 6px; }
.landing-feature-text { font-size: .9rem; color: var(--text-dim); line-height: 1.55; }

/* ---------- Ausgabe-Abweichung (js/output-diff.js + lesson-engine.js) ----------
   Die Gegenueberstellung „erwartet / du hast" mit einer Marke unter dem ersten
   abweichenden Zeichen. Monospace ist hier Pflicht, nicht Geschmack: Die Marke
   sitzt nur dann unter dem richtigen Buchstaben, wenn jedes Zeichen gleich
   breit ist. Aus demselben Grund darf nichts umbrechen - eine umgebrochene
   Zeile verschoebe die Marke. Stattdessen scrollt der Block waagrecht. */
.diff-block { margin: 10px 0 4px; }
.diff-zeile {
  border-left: 3px solid var(--red);
  padding: 6px 0 6px 10px;
  margin-bottom: 8px;
}
.diff-nr { font-size: .75rem; color: var(--text-dim); margin-bottom: 4px; }
.diff-paar { overflow-x: auto; }
.diff-paar > div { display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
.diff-paar code {
  font-family: var(--mono); font-size: .88rem;
  background: var(--code-bg); padding: 1px 6px; border-radius: 4px;
  white-space: pre;
}
.diff-label {
  flex: 0 0 auto; width: 62px; text-align: right;
  font-size: .74rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .03em;
}
.diff-label-ist { color: var(--red); }
/* Die Markenzeile traegt denselben Einzug und dieselbe Schrift wie die Zeilen
   darueber - nur so zeigt das ^ auf die richtige Spalte. */
.diff-markenzeile code { background: transparent; padding: 1px 6px; }
.diff-marke { color: var(--red); font-weight: 700; }
.diff-rest { font-size: .82rem; color: var(--text-dim); margin: 6px 0 0; }

/* Nachtrag bei toleriert bestandenen Aufgaben: sichtbar, aber nicht alarmierend -
   die Loesung gilt ja. */
.feedback-nachtrag {
  margin-top: 10px; padding: 10px 12px;
  background: var(--yellow-soft); border-radius: 8px;
  border: 1px solid var(--yellow);
  font-size: .9rem;
}
.feedback-nachtrag .diff-zeile { border-left-color: var(--yellow); }
.feedback-nachtrag .diff-label-ist { color: var(--yellow); }
.feedback-nachtrag .diff-marke { color: var(--yellow); }

/* ---------- Code-Tastenleiste auf Touchgeräten (js/lesson-engine.js) ----------
   Auf einer Handy-Tastatur liegen Doppelpunkt, Klammern, Anführungszeichen und
   Unterstrich hinter zwei Ebenenwechseln. Für `print("Hallo")` wechselt man
   viermal die Ebene – bei einer Lern-App, die vom Tippen lebt, ist das die
   eigentliche Hürde am Handy.

   Die Leiste erscheint nur bei grobem Zeiger (Touch); an einer echten Tastatur
   wäre sie im Weg. Sie scrollt waagrecht, statt umzubrechen: eine feste Höhe
   ist verlässlicher als eine Leiste, die je nach Sprache zwei oder drei Zeilen
   hoch ist und den Editor wegschiebt. */
.code-keys {
  display: flex; gap: 6px;
  padding: 6px 8px;
  background: var(--bg-soft);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  /* Kein Umbruch und kein Zurückschnappen – die Leiste ist eine Reihe. */
  flex-wrap: nowrap;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.code-key {
  flex: 0 0 auto;
  min-width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-card); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  font-family: var(--mono); font-size: 1rem; line-height: 1;
  cursor: pointer;
  /* Ohne das markiert ein langer Druck das Zeichen statt es einzufügen. */
  user-select: none; -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.code-key:active { background: var(--accent-soft); border-color: var(--accent); }
.code-key-wide { min-width: 52px; }

/* ---------- Einstiegs-Assistent (js/views-learn.js) ----------
   Steht auf der Landing zwischen den Vorteilen und dem vollständigen Raster:
   zwei Fragen, drei Vorschläge. Bewusst als Karte und nicht als Overlay – der
   Assistent soll ein Angebot sein, kein Tor, durch das man muss. */
.assistent { margin: 28px 0 8px; padding: 22px; }
.assistent-titel { margin: 0; font-size: 1.25rem; }
.assistent-sub { margin: 6px 0 0; }
.assistent-frage { margin-top: 18px; }
.assistent-frage[hidden] { display: none; }
.assistent-label {
  font-size: .82rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-dim); margin-bottom: 10px;
}
.assistent-optionen {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.assistent-option {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  align-items: start; text-align: left;
  padding: 12px 14px; min-height: 44px;
  background: var(--bg-soft); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  cursor: pointer; font: inherit;
  transition: border-color .15s, background .15s, transform .15s;
}
.assistent-option:hover { background: var(--bg-hover); border-color: var(--accent); }
.assistent-option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.assistent-option.gewaehlt { border-color: var(--accent); background: var(--accent-soft); }
.assistent-option-icon { grid-row: span 2; font-size: 1.4rem; line-height: 1.2; }
.assistent-option-titel { font-weight: 700; font-size: .95rem; }
.assistent-option-text { font-size: .82rem; color: var(--text-dim); line-height: 1.45; }

.assistent-ergebnis { margin-top: 20px; border-top: 1px solid var(--border); padding-top: 16px; }
.assistent-ergebnis[hidden] { display: none; }
.assistent-top-label {
  font-size: .82rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-dim); margin-bottom: 8px;
}
.assistent-top-karte {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; text-decoration: none; color: var(--text);
  background: var(--accent-soft); border: 1px solid var(--accent);
  border-radius: var(--radius);
}
.assistent-top-karte:hover { background: var(--bg-hover); }
.assistent-top-text { display: flex; flex-direction: column; gap: 3px; flex: 1; min-width: 0; }
.assistent-top-warum { font-size: .84rem; color: var(--text-dim); }
.assistent-top-pfeil { font-size: 1.2rem; color: var(--accent); }
.assistent-alternativen {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap; margin-top: 12px;
}
.assistent-alt-label { font-size: .85rem; color: var(--text-dim); }

@media (max-width: 640px) {
  .assistent { padding: 16px; }
  .assistent-optionen { grid-template-columns: 1fr; }
}

/* ---------- Pro-Inhalte: gesperrte Kacheln & Paywall (js/views.js) ---------- */
.lock-pill { position: absolute; top: 12px; right: 12px; }
.lang-card.locked { opacity: .82; }
.lang-card.locked:hover { opacity: 1; }
.lang-locked-hint {
  margin-top: 10px;
  font-size: .85rem;
  font-weight: 600;
  color: var(--yellow);
}

.paywall { max-width: 620px; margin: 20px auto 0; text-align: center; padding: 30px 24px; }
.paywall-icon { font-size: 2.6rem; margin-bottom: 6px; }
.paywall h2 { margin: 0 0 10px; font-size: 1.3rem; }
.paywall-cta {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 18px;
}
.paywall-note { margin: 14px 0 0; font-size: .82rem; color: var(--text-dim); }

/* ---------- Abschluss-Zertifikat (js/views.js renderCertificate) ---------- */
.cert-page { max-width: 720px; margin: 0 auto; }
.cert-name-edit { margin-bottom: 16px; display: flex; flex-direction: column; gap: 6px; }
.cert-name-edit label { font-size: .85rem; color: var(--text-dim); }
.cert-name-edit input {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  color: var(--text);
  font-size: 1rem;
  max-width: 320px;
}
.certificate {
  position: relative;
  text-align: center;
  padding: 40px 32px 30px;
  border-radius: var(--radius);
  color: var(--text);
  background:
    radial-gradient(90% 130% at 50% -10%, var(--accent-soft), transparent 60%),
    var(--bg-card);
  border: 2px solid var(--accent);
  box-shadow: var(--shadow-md);
}
.cert-top { font-size: 1.5rem; font-weight: 800; letter-spacing: -.01em; }
.cert-kicker {
  text-transform: uppercase;
  letter-spacing: .22em;
  font-size: .78rem;
  color: var(--accent);
  margin: 6px 0 22px;
  font-weight: 700;
}
.cert-intro { color: var(--text-dim); margin: 12px 0 6px; font-size: .95rem; }
.cert-name {
  font-size: clamp(1.6rem, 5vw, 2.3rem);
  font-weight: 800;
  line-height: 1.15;
  margin: 2px 0;
  word-break: break-word;
}
.cert-path { font-size: 1.35rem; font-weight: 700; margin: 4px 0; }
.cert-meta {
  display: flex;
  gap: 18px;
  justify-content: center;
  flex-wrap: wrap;
  margin: 22px 0 10px;
  font-size: .9rem;
  color: var(--text-dim);
}
.cert-foot {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: .78rem;
  color: var(--text-dim);
}
.cert-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }

/* ============ Bonus-Themes (Extras, js/views.js Profil) ============
   Zusätzliche Farbwelten – auswählbar im Profil unter „Darstellung".
   Aktiviert über <html data-theme="…"> (wie light); js/pwa.js wendet sie
   schon im <head> an, js/app.js beim Umschalten. Die dunklen Varianten
   erben die meisten Werte vom Standard-Dunkel und färben nur Flächen/
   Akzente um; Matcha ist hell und überschreibt entsprechend mehr. */

/* 🌆 Synthwave: Neon-Lila/Pink auf tiefem Violett-Schwarz */
:root[data-theme="synthwave"] {
  --bg: #16101f;
  --bg-soft: #1d1529;
  --bg-card: #231933;
  --bg-hover: #2d2140;
  --border: #3d2d55;
  --text: #f2e9ff;
  --text-dim: #a394bd;
  --accent: #ff7edb;
  --accent-soft: rgba(255, 126, 219, .14);
  --purple: #c792ea;
  --code-bg: #120d1a;
  --btn-text: #16101f;
  --btn-grad: linear-gradient(180deg, #ff9ee4, #f461c9);
  --selection-bg: rgba(255, 126, 219, .35);
  --scrollbar-thumb: #3d2d55;
  --scrollbar-thumb-hover: #524070;
}

/* 🌊 Ozean: Tiefblau mit Türkis-Akzenten */
:root[data-theme="ocean"] {
  --bg: #0a161f;
  --bg-soft: #0f1e2a;
  --bg-card: #132534;
  --bg-hover: #1a3040;
  --border: #24435a;
  --text: #e3f2f7;
  --text-dim: #8aa8b8;
  --accent: #2dd4bf;
  --accent-soft: rgba(45, 212, 191, .13);
  --code-bg: #081119;
  --btn-text: #0a161f;
  --btn-grad: linear-gradient(180deg, #4be0cd, #14b8a5);
  --selection-bg: rgba(45, 212, 191, .30);
  --scrollbar-thumb: #24435a;
  --scrollbar-thumb-hover: #305a78;
}

/* 🍵 Matcha: warmes Hell-Beige mit Grün (helles Theme) */
:root[data-theme="matcha"] {
  --bg: #f6f4ec;
  --bg-soft: #eeeadf;
  --bg-card: #fbfaf5;
  --bg-hover: #e6e1d2;
  --border: #d5cfbc;
  --text: #2c3327;
  --text-dim: #6d7565;
  --accent: #4a7c59;
  --accent-soft: rgba(74, 124, 89, .12);
  --green: #3a7a4b;
  --green-soft: rgba(58, 122, 75, .12);
  --red: #b3392f;
  --red-soft: rgba(179, 57, 47, .10);
  --yellow: #8a6d1a;
  --yellow-soft: rgba(138, 109, 26, .12);
  --purple: #6f5bb5;
  --shadow-sm: 0 1px 2px rgba(44, 51, 39, .06), 0 2px 6px rgba(44, 51, 39, .05);
  --shadow-md: 0 2px 4px rgba(44, 51, 39, .08), 0 8px 24px rgba(44, 51, 39, .10);
  --shadow-lg: 0 8px 16px rgba(44, 51, 39, .12), 0 24px 48px rgba(44, 51, 39, .16);
  --code-bg: #eeeadf;
  --btn-text: #fbfaf5;
  --btn-grad: linear-gradient(180deg, #5c936c, #4a7c59);
  --btn-green-grad: linear-gradient(180deg, #4a9a5e, #3a7a4b);
  --text-strong: #1f241b;
  --selection-bg: rgba(74, 124, 89, .25);
  --scrollbar-thumb: #cdc6b1;
  --scrollbar-thumb-hover: #b8b09a;
  --sidebar-shadow: 0 0 40px rgba(44, 51, 39, .25);
}

/* Theme-Auswahl im Profil: kleine Vorschau-Kacheln */
.theme-grid { display: flex; gap: 12px; flex-wrap: wrap; }
.theme-tile {
  position: relative;
  width: 132px;
  border: 2px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-card);
  padding: 0;
  text-align: left;
  font: inherit;
  color: var(--text);
}
.theme-tile.active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.theme-tile:hover { border-color: var(--accent); }
.theme-swatch { display: flex; height: 44px; }
.theme-swatch span { flex: 1; }
.theme-tile-name { display: block; padding: 7px 10px; font-size: .82rem; font-weight: 600; }
.theme-tile .lock-pill { top: 6px; right: 6px; font-size: .68rem; }
.theme-tile.locked { opacity: .75; }
.theme-tile.locked:hover { opacity: 1; }

.lang-choice-card {
  text-align: left;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  border-radius: var(--radius);
  padding: 16px;
  font: inherit;
  transition: border-color .15s, background .15s, transform .1s;
}
.lang-choice-card:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}
.lang-choice-card.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

/* Druck/PDF: nur das Zertifikat sichtbar, alles andere raus (App-Chrome,
   Buttons, Namensfeld). Der klassische visibility-Trick greift unabhängig von
   dynamisch eingefügten Elementen (Versions-Badge etc.). */
@media print {
  body * { visibility: hidden; }
  .certificate, .certificate * { visibility: visible; }
  .certificate {
    position: absolute;
    left: 0; right: 0; top: 0;
    margin: 0 auto;
    max-width: 100%;
    border: 3px solid #333;
    box-shadow: none;
    background: #fff;
    color: #111;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .certificate .cert-kicker { color: #444; }
  .certificate .cert-intro, .certificate .cert-meta, .certificate .cert-foot { color: #333; }
  .cert-name-edit, .cert-actions, .no-print { display: none; }
}

/* ============ Großprojekte (js/project-engine.js) ============
   Nutzt durchgehend die bestehenden Variablen und lehnt sich an .module /
   .feedback / .output an – ein Großprojekt soll wie CodeQuest aussehen,
   nicht wie ein zweites Produkt. */

/* --- Karte am Fuß der Pfadseite --- */
.grossprojekt-karte {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin: 28px 0 8px; padding: 20px 22px;
  background: var(--bg-card); border: 1px solid var(--border);
  border-left: 3px solid var(--yellow);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.grossprojekt-karte .gp-icon { font-size: 2.4rem; line-height: 1; }
.grossprojekt-karte .gp-text { flex: 1; min-width: 220px; }
.grossprojekt-karte h2 { margin: 8px 0 4px; font-size: 1.25rem; }
.grossprojekt-karte p { margin: 0; color: var(--text-dim); font-size: .92rem; }
.grossprojekt-karte .gp-fortschritt { margin-top: 8px; font-size: .85rem; color: var(--text-dim); }

/* --- Projekt-Übersicht --- */
.projekt-kopf { margin-bottom: 22px; }
.projekt-kopf h1 { margin: 10px 0 6px; }
.projekt-icon { font-size: 1.6rem; }
.projekt-tagline { color: var(--accent); font-size: 1.02rem; margin: 0 0 12px; }
.projekt-beschreibung { color: var(--text-dim); }
.zurueck-link { font-size: .88rem; color: var(--text-dim); text-decoration: none; }
.zurueck-link:hover { color: var(--accent); }
.projekt-fortschritt { display: flex; align-items: center; gap: 12px; margin: 16px 0; flex-wrap: wrap; }
.projekt-fortschritt .progress {
  flex: 1; min-width: 140px; height: 8px; border-radius: 999px;
  background: var(--bg-soft); overflow: hidden;
}
.projekt-fortschritt .progress > div { height: 100%; background: var(--btn-green-grad); transition: width .35s ease; }
.projekt-fortschritt span { font-size: .85rem; color: var(--text-dim); }

.etappen-liste { list-style: none; padding: 0; margin: 0; }
.etappe-zeile {
  display: flex; gap: 14px; align-items: flex-start;
  padding: 14px 16px; margin-bottom: 8px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius);
}
.etappe-zeile.fertig { border-left: 3px solid var(--green); }
.etappe-zeile.gesperrt { opacity: .62; }
.etappe-zeile a { text-decoration: none; color: var(--text); }
.etappe-zeile a:hover b { color: var(--accent); }
.etappe-nr { font-size: 1.1rem; min-width: 1.4em; }
.etappe-ziel { display: block; margin-top: 4px; font-size: .87rem; color: var(--text-dim); }
.etappe-hinweis { display: inline-block; margin-top: 6px; font-size: .8rem; color: var(--yellow); }

/* --- Etappen-Player --- */
.etappe-player { max-width: 980px; }
.etappe-top { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.etappe-titel { margin: 0 0 6px; }
.etappe-ziel-gross {
  margin: 0 0 18px; padding: 10px 14px; font-size: .93rem;
  background: var(--accent-soft); border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(88, 166, 255, .28);
}
.etappe-aufgabe { margin-bottom: 16px; }

.stolpersteine {
  margin: 0 0 16px; padding: 12px 16px;
  background: var(--yellow-soft); border-radius: 8px;
  box-shadow: inset 0 0 0 1px rgba(210, 153, 34, .3);
}
.stolpersteine summary { cursor: pointer; font-weight: 600; font-size: .92rem; }
.stolpersteine ul { margin: 10px 0 0; padding-left: 20px; }
.stolpersteine li { margin-bottom: 8px; font-size: .9rem; }
.stolpersteine li:last-child { margin-bottom: 0; }
.nachlesen { font-size: .87rem; color: var(--text-dim); margin: 0 0 14px; }

/* --- Dateireiter über dem Editor --- */
.datei-reiter { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: -1px; }
.datei-tab {
  padding: 7px 15px; font-family: var(--mono); font-size: .84rem; cursor: pointer;
  color: var(--text-dim); background: var(--bg-soft);
  border: 1px solid var(--border); border-bottom: none;
  border-radius: 8px 8px 0 0;
}
.datei-tab:hover { color: var(--text); background: var(--bg-hover); }
.datei-tab.aktiv { color: var(--text); background: var(--bg-card); border-bottom: 1px solid var(--bg-card); }

.abnahme-name { font-size: .87rem; color: var(--text-dim); margin: 6px 0; }
.abnahme-weiter { margin-top: 14px; }

/* --- Gatter-Netzlisten (Step-Typ `logik`) --- */
.logik-ziel, .logik-ergebnis { margin: 14px 0; }
.logik-ziel-kopf {
  font-size: .84rem; font-weight: 600; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 6px;
}
.logik-tabelle-wrap { overflow-x: auto; }
.logik-tabelle {
  border-collapse: collapse; font-family: var(--mono); font-size: .88rem;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px;
}
.logik-tabelle th, .logik-tabelle td {
  padding: 5px 12px; text-align: center; border-bottom: 1px solid var(--border);
}
.logik-tabelle tbody tr:last-child td { border-bottom: none; }
.logik-tabelle th { color: var(--text-dim); font-weight: 600; }
.logik-tabelle .logik-aus { background: var(--accent-soft); }
.logik-tabelle .logik-takt { color: var(--text-dim); }
.logik-tabelle .logik-falsch { background: var(--red-soft, rgba(248, 81, 73, .22)); font-weight: 700; }
.logik-tabelle .logik-zeile-falsch td { box-shadow: inset 0 0 0 1px rgba(248, 81, 73, .45); }
.logik-legende { font-size: .85rem; color: var(--text-dim); margin: 0 0 10px; }
.logik-legende code { font-size: .85em; }

/* --- „Getippt wird hier: …" auf der Pfadseite --- */
.sprach-hinweis {
  margin: 16px 0 4px; padding: 12px 16px;
  background: var(--bg-soft); border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--border);
}
.sprach-kopf { margin: 0 0 6px; font-size: .93rem; }
.sprach-warum { font-size: .88rem; color: var(--text-dim); }
.sprach-warum p { margin: 0; }
.sprach-vorwissen { margin: 8px 0 0; font-size: .86rem; }

/* --- Arbeitsstand: sichern, laden, wiederherstellen --- */
.arbeitsstand {
  margin-top: 28px; padding: 18px 20px;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius);
}
.arbeitsstand h2 { margin: 0 0 6px; font-size: 1.05rem; }
.arbeitsstand-hinweis { margin: 0 0 12px; font-size: .87rem; color: var(--text-dim); }
.arbeitsstand-knoepfe { display: flex; gap: 8px; flex-wrap: wrap; }
.sicherungen { margin-top: 14px; }
.sicherungen summary { cursor: pointer; font-weight: 600; font-size: .92rem; }
.sicherungen > p { margin-top: 10px; }
.sicherungen ul { list-style: none; padding: 0; margin: 0; }
.sicherung-zeile {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; padding: 10px 0; border-top: 1px solid var(--border);
}
.sicherung-zeile b { font-size: .9rem; }
.sicherung-anlass { display: block; margin-top: 2px; font-size: .82rem; color: var(--text-dim); }

@media (max-width: 640px) {
  .grossprojekt-karte { gap: 12px; padding: 16px; }
  .grossprojekt-karte .gp-icon { font-size: 1.9rem; }
  .etappe-player { max-width: none; }
}

/* Gesperrte Lektionszeile: gleiche Höhe wie eine offene, damit die Liste
   nicht springt – aber ohne Hover-Anfassen, weil es nichts zu öffnen gibt. */
.lesson-row.gesperrt {
  display: flex; align-items: center; gap: 10px;
  cursor: default; opacity: .72;
}
.lesson-row.gesperrt:hover { background: none; }
.lesson-row.gesperrt .lesson-name { color: var(--text-dim); }

/* ---------- Anmelde-Schranke (js/views-account.js) ----------
   Die erste Seite, die ein neuer Besucher sieht. Sie soll nicht wie eine
   Fehlermeldung wirken, sondern wie ein Anfang – deshalb mittig, luftig und
   mit den Lernpfaden als Schaufenster. */
.schranke { max-width: 760px; margin: 0 auto; padding: 8px 0 40px; }
.schranke h1 { font-size: 2.1rem; margin-bottom: 6px; }

.schranke-pfade { display: flex; flex-wrap: wrap; gap: 8px; }
.schranke-pfad {
  display: inline-block; padding: 6px 12px; border-radius: 999px;
  background: var(--card); border: 1px solid var(--border);
  font-size: .88rem; color: var(--text-dim); max-width: 100%;
  white-space: normal; overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .schranke h1 { font-size: 1.7rem; }
  .schranke-pfad { font-size: .82rem; padding: 5px 10px; }
}

/* ---------- 🛝 Spielplatz (js/views-spielplatz.js) ----------
   Bewusst wenig Eigenes: Editor, Ausgabe, Dateireiter und Knopfreihe sind
   dieselben Bausteine wie im Lesson- und im Großprojekt-Player. Neu ist nur
   die Sprachauswahl obendrüber und die Schnipsel-Zeile darunter. */
.spielplatz-sprachen { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 20px; }
.spielplatz-sprache {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border-radius: 999px;
  background: var(--bg-card); border: 1px solid var(--border);
  color: var(--text-dim); font-size: .9rem; text-decoration: none; white-space: nowrap;
}
.spielplatz-sprache:hover { color: var(--text); background: var(--bg-hover); }
.spielplatz-sprache.aktiv {
  color: var(--text); border-color: var(--accent);
  background: var(--accent-soft);
}

/* Der erklärende Satz über dem Editor – und in der extern-Variante die
   ehrliche Zeile, dass der Code das Gerät verlässt. Die sticht bewusst
   heraus: Sie ist kein Tipp, sondern eine Information, die man vor dem
   Tippen gelesen haben muss. */
.spielplatz-hinweis {
  font-size: .88rem; color: var(--text-dim); line-height: 1.55;
  background: var(--bg-soft); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 14px; margin-bottom: 14px;
}
.spielplatz-hinweis.extern {
  border-color: var(--yellow);
  background: var(--yellow-soft);
  color: var(--text);
}
/* Derselbe Kasten, andere Botschaft: Der Compiler liegt auf diesem Rechner,
   der Code geht nirgendwohin (js/views-spielplatz.js, istExtern). Grün statt
   der Warnfarbe – es ist eine Entwarnung, keine Warnung. */
.spielplatz-hinweis.lokal {
  border-color: var(--green);
  background: var(--green-soft);
}
.spielplatz-hinweis a { color: inherit; }

.spielplatz-schnipsel { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 12px; }
.spielplatz-schnipsel select,
.spielplatz-schnipsel input {
  padding: 6px 10px; font-size: .85rem;
  color: var(--text); background: var(--bg-card);
  border: 1px solid var(--border); border-radius: 8px;
}
.spielplatz-schnipsel select { max-width: 240px; }
.spielplatz-schnipsel input { flex: 1 1 180px; min-width: 140px; }
.spielplatz-schnipsel select:disabled { opacity: .5; }

.spielplatz-merker { font-size: .8rem; }

@media (max-width: 640px) {
  .spielplatz-sprache { font-size: .84rem; padding: 6px 11px; }
  .spielplatz-schnipsel select { max-width: 100%; flex: 1 1 100%; }
}

/* ---------- 🐧 Linux-Spielplatz (js/views-linux.js) ----------
   Das Terminal bekommt bewusst KEINE Theme-Variablen: Ein Terminal ist in
   jedem Theme dunkel – genau wie die Programm-Ausgabe weiter oben, die aus
   demselben Grund in beiden Themes dunkel bleibt. */
.linux-leiste {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 16px 0 8px; font-size: .88rem;
}
.linux-leiste .spacer { flex: 1; }

.linux-terminal {
  background: #0b0f14;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 6px 6px 10px;
  /* Feste Höhe statt „wächst mit": Ein Terminal, das bei jeder Ausgabezeile
     die Seite länger macht, schiebt die Knöpfe darüber aus dem Bild – und
     zwar genau dann, wenn man sie braucht. */
  height: min(60vh, 520px);
  overflow: hidden;
}
.linux-terminal .xterm { height: 100%; }

.linux-fuss {
  font-size: .85rem; color: var(--text-dim); line-height: 1.6;
  margin: 10px 0 0;
}
.linux-fuss code {
  font-size: .95em; padding: 1px 5px;
  background: var(--code-bg); border-radius: 4px;
}

/* Der Eingang zum Linux in der Sprachleiste des Spielplatzes. Sichtbar
   anders als die Sprachen daneben – es ist keine Sprache, sondern ein
   ganzer Rechner hinter einer eigenen Freigabe. */
.spielplatz-linux {
  border-style: dashed;
  margin-left: 4px;
}
.spielplatz-linux:hover { border-style: solid; }

@media (max-width: 640px) {
  .linux-terminal { height: 50vh; }
}

/* ============================================================================
   Deine Woche (js/views-account.js, wocheSectionHtml)
   ============================================================================
   Sieben Säulen statt einer Summe. Der Grund steht dort im Kommentar: Fünf
   Lektionen an fünf Tagen und fünf am Sonntagabend sind dieselbe Zahl und ein
   völlig anderes Lernverhalten. */
.woche-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  align-items: end;
}
.woche-tag { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.woche-saeule {
  width: 100%;
  height: 54px;
  background: var(--bg);
  border-radius: 6px;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.woche-fuell {
  width: 100%;
  background: var(--accent, #2f81f7);
  border-radius: 6px 6px 0 0;
  /* Auch bei einer einzigen Lektion sichtbar bleiben: Ein 2-Pixel-Streifen
     liest sich als „nichts", und das wäre schlicht falsch. */
  min-height: 6px;
  transition: height .25s ease;
}
.woche-tag:not(.voll) .woche-fuell { min-height: 0; }
.woche-label { font-size: .72rem; color: var(--text-dim); }
.woche-tag.heute .woche-label { color: var(--text); font-weight: 600; }
.woche-tag.heute .woche-saeule { outline: 1px solid var(--border); }
.woche-trend { font-size: .84rem; margin-left: .4rem; color: var(--text-dim); }
.woche-trend.auf { color: var(--green, #3fb950); }
.woche-trend.ab { color: var(--text-dim); }

/* ============================================================================
   Deine Stolpersteine (js/views-account.js, stolpersteineSectionHtml)
   ============================================================================
   Zwei Spalten nebeneinander – die eigene Ausgabe und die erwartete. Das ist
   der ganze Punkt: Selbstvergleichen geht nur, wenn beides gleichzeitig zu
   sehen ist. Auf schmalen Geräten untereinander, dann mit den Marken als
   Orientierung. */
.stolper-eintrag { margin-bottom: 10px; }
.stolper-kopf {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: .5rem;
}
.stolper-titel { font-weight: 600; flex: 1 1 auto; min-width: 0; }
.stolper-zahl {
  background: var(--bg);
  border-radius: 999px;
  padding: .05rem .5rem;
  font-size: .78rem;
  color: var(--yellow, #d29922);
  font-weight: 600;
}
.stolper-wann { font-size: .78rem; color: var(--text-dim); }
.stolper-weg { padding: .1rem .45rem; line-height: 1; }
.stolper-vergleich {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
@media (max-width: 620px) {
  .stolper-vergleich { grid-template-columns: 1fr; }
}
.stolper-marke {
  display: inline-block;
  font-size: .74rem;
  margin-bottom: .25rem;
  color: var(--text-dim);
}
.stolper-marke.meins { color: #f85149; }
.stolper-marke.soll { color: var(--green, #3fb950); }
.stolper-vergleich pre,
.stolper-fehler {
  margin: 0;
  padding: .5rem .6rem;
  background: var(--bg);
  border-radius: 6px;
  font-family: var(--mono);
  font-size: .82rem;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 140px;
  overflow-y: auto;
}
.stolper-fehler { color: #f85149; }

/* ============================================================================
   Einstufung (js/views-einstufung.js, js/views-path.js)
   ============================================================================ */
.einstufung-kasten { border-left: 3px solid var(--accent, #2f81f7); margin: 12px 0; }
.einstufung-regel { border-left: 3px solid var(--yellow, #d29922); margin-bottom: 14px; }
.einstufung-frage { margin-bottom: 10px; }
.einstufung-kopf {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .5rem;
}
.einstufung-nr { font-size: .78rem; color: var(--text-dim); font-weight: 600; }
.einstufung-text { margin: 0 0 .6rem; font-weight: 600; }
/* Die gewaehlte Antwort wird MARKIERT, nicht bewertet: Waehrend der Einstufung
   gibt es kein Richtig-Feedback. Wer nach der ersten Frage weiss, ob er
   richtig lag, raet die zweite anders - und das Ergebnis misst dann das
   Raten, nicht das Koennen. */
.quiz-option.gewaehlt {
  border-color: var(--accent, #2f81f7);
  background: color-mix(in srgb, var(--accent, #2f81f7) 12%, transparent);
}
/* Uebersprungenes Modul: da, aber leise. */
.module.uebersprungen {
  opacity: .62;
  padding-top: .55rem;
  padding-bottom: .55rem;
}
.module.uebersprungen .module-title { margin: 0; font-size: .92rem; }
.module.uebersprungen:hover { opacity: 1; }

/* ============================================================================
   Klassen-Ansicht (js/views-social.js)
   ============================================================================
   Eine Zeile je Mitglied, eine Spalte je Modul. Bei 19 Modulen und dreissig
   Namen wird das breit - deshalb scrollt die Tabelle in sich selbst, statt
   die Seite zu sprengen, und die Namensspalte bleibt dabei stehen. */
.klassen-raster { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px; }
.klassen-raster.leer { color: var(--text-dim); }
.klassen-kopf { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .6rem; }
.klassen-pfadwahl {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: 6px; padding: .15rem .4rem; font-size: .84rem;
}
.klassen-scroll { overflow-x: auto; }

/* Der Klassen-Stand (js/views-social.js, Version 210).

   Die Rueckmeldung war „unuebersichtlich", und das lag nicht an zu wenig
   Inhalt, sondern an fehlender Gliederung: Tabellen, Raster und Formular
   standen ohne Trennung untereinander. `.klassen-block` bekommt deshalb eine
   sichtbare Kante, und die Kennzahlen stehen als Chip-Zeile darueber -
   lesbar, bevor man eine Tabelle anfaengt. */
.klassen-kennzahlen { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; }

.stand-tabelle { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: .9rem; }
.stand-tabelle th, .stand-tabelle td { padding: 6px 10px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.stand-tabelle th { color: var(--text-dim); font-size: .82rem; font-weight: 600; white-space: nowrap; }
.stand-tabelle tbody tr:last-child td { border-bottom: 0; }
/* Zebra erst ab drei Zeilen waere Spielerei - eine ruhige Hover-Spur reicht,
   um in einer 24-Zeilen-Klassenliste die Zeile nicht zu verlieren. */
.stand-tabelle tbody tr:hover { background: var(--bg-soft, rgba(127, 127, 127, .07)); }

/* Ein Duell je Aufklapper: Eine Klasse hat schnell zehn davon, und zehn
   Tabellen untereinander sind wieder genau das, was gemeldet wurde. Das
   laufende steht offen (js/views-social.js setzt `open`), die alten zu. */
.duell-ergebnis { margin-top: 10px; border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; }
.duell-ergebnis + .duell-ergebnis { margin-top: 8px; }
.duell-ergebnis > summary { cursor: pointer; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.duell-ergebnis > summary::-webkit-details-marker { color: var(--text-dim); }
.duell-ergebnis[open] > summary { margin-bottom: 6px; }
.klassen-tabelle { border-collapse: collapse; font-size: .82rem; }
.klassen-tabelle th, .klassen-tabelle td {
  padding: .2rem .35rem; text-align: center; white-space: nowrap;
}
.klassen-tabelle th { color: var(--text-dim); font-weight: 500; }
/* Die Namensspalte bleibt beim Scrollen stehen - ohne sie ist eine Zeile
   weiter rechts nicht mehr zuzuordnen. */
.klassen-tabelle .kz-name {
  position: sticky; left: 0; z-index: 1;
  background: var(--card); text-align: left; padding-right: .8rem;
}
.klassen-tabelle tbody tr:nth-child(even) .kz-name { background: var(--card); }
.kz-fertig { color: var(--green, #3fb950); }
.kz-teil { color: var(--yellow, #d29922); }
.kz-offen, .kz-nichts { color: var(--text-dim); }
.klassen-teilen { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 10px; }
.klassen-teilen .switch-row { display: flex; gap: .6rem; align-items: flex-start; cursor: pointer; }
.klassen-teilen input { margin-top: .2rem; }

/* ---------- Der gläserne Lauf (Zeitreise durch die Ausführung) ----------
   Zwei Spalten: links der Code, mit dem gelaufen wurde, rechts Variablen und
   die Ausgabe, wie sie an dieser Stelle dastand. Unter 760 px untereinander –
   auf einem Handy ist eine 40-Zeichen-Spalte keine Spalte mehr. */
.lauf {
  margin-top: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-card);
  overflow: hidden;
}
.lauf-kopf {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: var(--bg-soft);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.lauf-kopf .lauf-regler { flex: 1 1 160px; min-width: 120px; accent-color: var(--accent); }
.lauf-stand { font-size: .82rem; color: var(--text-dim); font-family: var(--mono); }
.lauf-koerper { display: flex; gap: 0; align-items: stretch; }
.lauf-code {
  flex: 1 1 60%;
  margin: 0;
  padding: 10px 0;
  max-height: 320px;
  overflow: auto;
  background: var(--terminal-bg);
  color: var(--terminal-text);
  font-family: var(--mono);
  font-size: .85rem;
  line-height: 1.5;
}
.lauf-zeile { display: block; padding: 0 10px 0 0; white-space: pre; }
.lauf-nr {
  display: inline-block;
  width: 2.6em;
  margin-right: .8em;
  text-align: right;
  color: var(--terminal-dim);
  user-select: none;
}
.lauf-zeile.jetzt { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }
/* Der Code in einem `vorhersage`-Step: dieselbe Darstellung, aber ohne Marke –
   dort wird ja erst geraten. */
.lauf-code-still { border-radius: 10px; border: 1px solid var(--border); margin: 12px 0; }
.lauf-seite {
  flex: 1 1 40%;
  min-width: 0;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  border-left: 1px solid var(--border);
}
.lauf-block b { font-size: .8rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em; }
.lauf-vars { margin-top: 6px; display: flex; flex-direction: column; gap: 3px; }
.lauf-var {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--mono);
  font-size: .82rem;
  padding: 2px 6px;
  border-radius: 6px;
}
.lauf-var.geaendert { background: var(--green-soft); }
.lauf-var-name { color: var(--accent); }
.lauf-var-wert { color: var(--text); overflow-wrap: anywhere; }
.lauf-var-marke { margin-left: auto; font-size: .68rem; color: var(--green); text-transform: uppercase; }
.lauf-ausgabe {
  margin: 6px 0 0;
  padding: 8px 10px;
  max-height: 140px;
  overflow: auto;
  background: var(--terminal-bg);
  color: var(--terminal-text);
  border-radius: 8px;
  font-family: var(--mono);
  font-size: .8rem;
  white-space: pre-wrap;
}
.lauf-fuss { margin: 0; padding: 8px 12px; font-size: .8rem; color: var(--text-dim); border-top: 1px solid var(--border); }

.vorhersage-eingabe { margin: 12px 0; }
.vorhersage-feld {
  width: 100%;
  max-width: 320px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg-soft);
  color: var(--text);
  font-family: var(--mono);
  font-size: 1rem;
}
.vorhersage-feld:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.vorhersage-feld.richtig { border-color: var(--green); background: var(--green-soft); }
.vorhersage-feld.falsch { border-color: var(--red); background: var(--red-soft); }

@media (max-width: 760px) {
  .lauf-koerper { flex-direction: column; }
  .lauf-seite { border-left: none; border-top: 1px solid var(--border); }
  .lauf-code { max-height: 220px; }
}

/* ---------- Klassenzimmer: Aufträge, Abgabe, Prüfungsblatt ---------- */
.auftrag-lektionen { list-style: none; padding: 0; margin: 8px 0 0; }
.auftrag-lektionen li { padding: 4px 0; border-bottom: 1px solid var(--border); }
.auftrag-lektionen li:last-child { border-bottom: none; }
.auftrag-lektionen .auth-hint { margin-left: 8px; }

.abgabe-karte { max-width: 560px; }
.abgabe-liste { margin: 8px 0; padding-left: 1.2em; color: var(--text-dim); font-size: .9rem; }
.abgabe-liste li { margin: 3px 0; }

.auftrag-form { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.auftrag-zeile { display: flex; gap: 12px; flex-wrap: wrap; margin: 8px 0; }
.auftrag-zeile label, .auftrag-form > label {
  display: block;
  font-size: .85rem;
  font-weight: 600;
  flex: 1 1 180px;
}
.auftrag-form input[type="text"], .auftrag-form input[type="date"],
.auftrag-form input[type="number"], .auftrag-form select {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-soft);
  color: var(--text);
  font: inherit;
}
.auftrag-form .auftrag-pruefung { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.auftrag-form .auftrag-pruefung input { width: auto; margin: 0; }

/* Das Prüfungsblatt am Ende einer Prüfung. */
.blatt-tabelle {
  width: 100%;
  max-width: 620px;
  margin: 14px auto;
  border-collapse: collapse;
  font-size: .9rem;
  text-align: left;
}
.blatt-tabelle th, .blatt-tabelle td { padding: 6px 8px; border-bottom: 1px solid var(--border); }
.blatt-tabelle th { color: var(--text-dim); font-size: .82rem; font-weight: 600; }
.blatt-wert { white-space: nowrap; }
.blatt-nummer { font-size: .85rem; color: var(--text-dim); }
.blatt-hinweis { font-size: .82rem; color: var(--text-dim); max-width: 52ch; margin: 8px auto 0; }
.blatt-knoepfe { display: flex; gap: 10px; justify-content: center; align-items: center; flex-wrap: wrap; margin-top: 18px; }

/* ---------- Die Klassensprecher-Wahl (js/views-social.js) ----------

   Die Kandidat:innen stehen als große Knöpfe nebeneinander und nicht in einem
   Auswahlfeld. Eine Wahl ist ein einziger, endgültiger Klick – ein
   zugeklapptes Menü, aus dem man erst etwas heraussuchen muss, macht daraus
   ein Formular. Derselbe Gedanke wie bei den Melde-Arten und der Längenwahl
   der Prüfung. */
/* ---------- Der Sitzplan (js/sitzplan.js, Klassenseite und Gruppenliste) ----

   Die Tafel steht oben, und das ist keine Verzierung: Ein Sitzplan ohne
   Bezugspunkt lässt sich nicht lesen – man weiß nicht, ob man von vorn oder
   von hinten draufschaut. Genau dieser Zweifel macht einen Sitzplan wertlos.

   Die Plätze sind Knöpfe und keine Tabellenzellen: Wer einen Platz besetzt,
   klickt ihn an, und ein Knopf sagt das von selbst (und ist mit der Tastatur
   erreichbar). In der Gruppenliste stehen dieselben Kästchen als <div> – dort
   gibt es nichts zu klicken. */
.sitz-tafel {
  margin: 12px auto 10px;
  max-width: 420px;
  padding: 5px 0;
  text-align: center;
  font-size: .78rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-bottom: 3px solid var(--border);
}
.sitz-raster { display: flex; flex-direction: column; gap: 8px; overflow-x: auto; padding-bottom: 4px; }
.sitz-reihe { display: flex; gap: 8px; justify-content: center; }
.sitz {
  flex: 0 0 auto;
  width: 88px;
  min-height: 54px;
  padding: 6px 4px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: .8rem;
  line-height: 1.25;
  cursor: pointer;
  overflow: hidden;
}
.sitz:hover:not(:disabled) { border-color: var(--accent); }
.sitz:disabled { cursor: default; }
.sitz.belegt {
  border-style: solid;
  background: var(--bg-hover);
  color: var(--text);
  font-weight: 600;
}
/* Der eigene Platz – damit man sich in zweiundzwanzig Kästchen wiederfindet. */
.sitz.ich { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.sitz-nr { display: block; font-size: .68rem; font-weight: 400; color: var(--text-dim); }
.sitz-name { display: block; overflow-wrap: anywhere; }
.sitz-raster.nur-ansehen .sitz { cursor: default; }
.sitz-block { margin-top: 8px; }

@media (max-width: 640px) {
  .sitz { width: 72px; min-height: 48px; font-size: .74rem; }
}

.wahl-karte { max-width: 620px; margin-top: 12px; }
.wahl-knoepfe { display: flex; gap: 8px; flex-wrap: wrap; }
.wahl-knoepfe .btn { flex: 1 1 140px; }

/* ---------- Prüfung üben (js/views-pruefung.js) ----------

   Die Kacheln der Übersicht sind bewusst dieselben `.lang-card` wie die
   Lernpfade: Eine Prüfung ist etwas, das man aufmacht und durchgeht, genau
   wie ein Pfad – ein eigener Kachel-Stil hätte nichts erklärt und die Seite
   fremd aussehen lassen. Dazu kommen nur zwei Zeilen Zusatzangaben. */
.pruefung-meta { margin-top: 10px; font-size: .85rem; color: var(--text-dim); }
.pruefung-letzte { margin-top: 6px; font-size: .85rem; font-weight: 600; color: var(--green); }
.pruefung-letzte.leer { font-weight: 400; color: var(--text-dim); }
.pruefung-pfadwahl { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.pruefung-pfadwahl select {
  flex: 1 1 220px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-card);
  color: var(--text);
  font-size: .95rem;
}

/* Die Auswertung hängt im Blatt an derselben Stelle, an der beim Auftrag der
   Abgabe-Kasten sitzt – und das ist `.blatt-knoepfe`, eine zentrierte
   Flex-Zeile. `flex-basis: 100%` schickt sie in eine eigene Zeile darunter,
   sonst stünde sie neben dem Druck-Knopf. Links ausgerichtet, weil sie
   gelesen und nicht betrachtet wird. */
.pruefung-auswertung { flex: 1 0 100%; text-align: left; margin-top: 10px; }
.pruefung-auswertung .blatt-tabelle { margin-left: 0; }
.pruefung-faecher .level-bar { margin: 0; }
.pruefung-lektionen { margin: 0; padding-left: 1.2em; }
.pruefung-lektionen li { margin: 6px 0; }
/* Ohne diese Zeile nimmt der Link die Browser-Voreinstellung (#0000ee) und
   steht im dunklen Theme mit 1,3:1 auf der Karte – unlesbar, und ausgerechnet
   in einem Projekt, das Barrierefreiheit unterrichtet. `--accent` trägt in
   allen fünf Themes genug Kontrast, weil er dafür gesetzt ist. */
.pruefung-lektionen a { color: var(--accent); font-weight: 600; }
.pruefung-uebernehmen { margin-top: 14px; }
.pruefung-trend-zeile { margin: 0 0 12px; }
.pruefung-trend { font-weight: 600; font-size: .9rem; }
.pruefung-trend.besser { color: var(--green); }
.pruefung-trend.schlechter { color: var(--yellow); }

/* Die Längenwahl. Drei Knöpfe und kein <select>: Die Wahl steht vor der
   Prüfung und ist Teil der Entscheidung, sie hier zu machen – ein
   zugeklapptes Menü versteckt genau das, worum es gerade geht. Derselbe
   Gedanke wie bei den Melde-Arten weiter oben. */
.pruefung-laenge { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 16px; }
.pruefung-laenge-knopf {
  flex: 1 1 150px;
  text-align: left;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.pruefung-laenge-knopf:hover { background: var(--bg-hover); }
.pruefung-laenge-knopf.aktiv { border-color: var(--accent); background: var(--bg-hover); }
.pruefung-laenge-name { display: block; font-weight: 700; font-size: .92rem; }
.pruefung-laenge-text { display: block; font-size: .8rem; color: var(--text-dim); margin-top: 1px; }
.pruefung-lektionen .auth-hint { display: block; margin: 0; }
.pruefung-knoepfe { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

/* Gedruckt wird das Blatt, nicht die App.

   DERSELBE Trick wie beim Zertifikat weiter oben – und das ist kein Zufall,
   sondern Pflicht: Dort steht `body * { visibility: hidden }`. Ein zweiter
   Druckblock mit `display: none` auf der Seitenleiste würde daran nichts
   ändern; das Blatt bliebe unsichtbar und niemand wüsste warum. Wer hier ein
   drittes druckbares Ding ergänzt, ergänzt es genauso. */
@media print {
  .blatt, .blatt * { visibility: visible; }
  .blatt {
    position: absolute;
    left: 0; right: 0; top: 0;
    margin: 0 auto;
    max-width: 100%;
    background: #fff;
    color: #0f172a;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .blatt h2 { font-size: 16pt; font-weight: 800; border-bottom: 1.5pt solid #0f172a; padding-bottom: 4pt; margin-bottom: 6pt; }
  .blatt .subtitle { color: #475569; font-size: 9pt; margin-bottom: 8pt; }
  .blatt .blatt-nummer, .blatt .blatt-hinweis { color: #64748b; font-size: 8pt; }
  .blatt .blatt-tabelle { width: 100%; border-collapse: collapse; margin: 6pt 0; font-size: 9pt; }
  .blatt .blatt-tabelle th { background: #f1f5f9; color: #0f172a; font-weight: 700; border-top: 1.5pt solid #0f172a; border-bottom: 1.2pt solid #0f172a; padding: 4pt 6pt; text-align: left; }
  .blatt .blatt-tabelle td { border-bottom: .5pt solid #e2e8f0; padding: 4pt 6pt; }
  .blatt .blatt-tabelle tbody tr:nth-child(even) td { background: #f8fafc; }
  .blatt .blatt-knoepfe, .blatt .done-icon { display: none; }
}
.seiten-abschnitte {
  margin: 0 0 1.25rem;
  padding: .65rem .8rem;
  border: 1px solid var(--border, #d8dee8);
  border-radius: 12px;
  background: var(--bg-card);
}
.seiten-abschnitte label { display: flex; align-items: center; gap: .7rem; font-weight: 600; }
.seiten-abschnitte select { min-width: min(100%, 22rem); padding: .5rem .65rem; border-radius: 8px; background: var(--bg-soft); color: var(--text); border: 1px solid var(--border); }
.main > h2, .cheat-section > h2 { scroll-margin-top: 1.25rem; }
.news-hinweis { max-width: 70ch; color: var(--muted, #687386); }
.news-liste { display: grid; gap: .85rem; max-width: 62rem; }
.news-eintrag { padding: 1rem 1.15rem; }
.news-meta { display: flex; align-items: center; flex-wrap: wrap; gap: .65rem; color: var(--muted, #687386); font-size: .9rem; }
.news-eintrag h2 { margin: .7rem 0 .35rem; font-size: 1.15rem; }
.news-eintrag p { margin: 0; max-width: 72ch; }
.news-archiv { margin: 1.2rem 0; max-width: 62rem; }
.news-archiv summary { cursor: pointer; font-weight: 600; }
.news-archiv p { max-width: 70ch; }
.seiten-abschnitte label { flex-wrap: wrap; }
.seiten-abschnitte select { min-width: 0; max-width: 100%; flex: 1 1 180px; }

/* Practice workbench: keyboard controls and readable content at 320px. */
.prueflabor {
  max-width: 1100px;
  margin-inline: auto;
  overflow-wrap: anywhere;
}
.prueflabor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 16px;
}
.prueflabor-field {
  display: grid;
  gap: 7px;
  margin: 16px 0;
  font-weight: 600;
}
.prueflabor-field textarea,
.prueflabor-field input,
.prueflabor-field select {
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font: 0.94rem/1.5 var(--font-mono, monospace);
}
.prueflabor-field textarea {
  resize: vertical;
  tab-size: 4;
}
.prueflabor :disabled {
  opacity: 0.6;
}
.prueflabor :focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}
.prueflabor pre {
  max-width: 100%;
  overflow-x: auto;
  white-space: pre-wrap;
}
.prueflabor-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 16px 0;
}
.prueflabor-controls .btn {
  white-space: normal;
}
.prueflabor-result {
  white-space: pre-wrap;
  min-height: 3em;
}
.prueflabor-table {
  overflow-x: auto;
  max-height: 500px;
}
.prueflabor-table table {
  width: 100%;
  border-collapse: collapse;
}
.prueflabor-table th,
.prueflabor-table td {
  text-align: left;
  padding: 8px;
  border: 1px solid var(--border);
}
.prueflabor-table button[aria-pressed='true'] {
  outline: 3px solid var(--accent);
}
.prueflabor-preview {
  width: 100%;
  box-sizing: border-box;
  min-height: 160px;
  background: #fff;
  border: 1px solid var(--border);
}

.prueflabor a:not(.btn) {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Display choices never change access rights. */
.cq-focus-hidden {
  display: none !important;
}
.focus-tools {
  margin-bottom: 1rem;
}
[data-class-editor] input:not([type='checkbox']),
[data-class-editor] textarea,
[data-class-editor] select {
  max-width: 100%;
  box-sizing: border-box;
}
[data-class-editor] textarea {
  min-height: 5rem;
}
[data-feedback] {
  width: 14rem;
  max-width: 100%;
  min-height: 5rem;
}
[data-private-runner],
[data-class-editor] input[type='checkbox'] {
  min-width: 24px;
  min-height: 24px;
  vertical-align: middle;
}
[data-class-editor] input:not([type='checkbox']),
[data-class-editor] textarea,
[data-class-editor] select,
[data-feedback] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px;
  font: inherit;
}
[data-class-editor] select {
  min-height: 40px;
}
[data-class-editor] input:focus-visible,
[data-class-editor] textarea:focus-visible,
[data-class-editor] select:focus-visible,
[data-feedback]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
