:root {
  --bg: #101823;
  --surface: #17222F;
  --surface-2: #1E2B3C;
  --border: #2A3A4D;
  --ink: #EDF2F7;
  --ink-soft: #93A2B5;

  --accent-sun: #FFB020;
  --accent-mint: #3ED6A7;
  --accent-coral: #FF6B5B;
  --accent-ocean: #3D5A80;

  --success-bg: #1E3A2E;
  --success-text: #4ADE9C;
  --success-border: #2F5C46;
  --error-bg: #3A1F22;
  --error-text: #FF8A80;
  --error-border: #5C2E33;

  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 22px;

  --font-display: 'Fredoka', ui-rounded, sans-serif;
  --font-body: 'Manrope', ui-sans-serif, system-ui, sans-serif;

  --hekto-plumage: #7C8794;
  --hekto-plumage-mark: #F3F6F8;
}

/* Ohne diesen Reset zählt Padding/Rahmen bei content-box (Browser-Default)
   zur Breite hinzu statt sie einzuschließen - genau das ließ Textfelder,
   Dropdowns, Textareas und die Datei-Auswahl auf schmalen Bildschirmen
   (Handy) über den Kartenrand hinausragen. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  font-family: var(--font-body);
  max-width: 640px;
  margin: 2rem auto;
  padding: 0 1rem;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
}

.page-background {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 2rem;
  color: var(--ink);
}

h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.35rem;
  color: var(--ink);
  margin-top: 0;
}

h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--ink);
}

/* form { display: flex } unten würde sonst das hidden-Attribut auf
   #typed-form (ein <form>) überschreiben, da Autor-Regeln immer vor der
   User-Agent-Regel [hidden] { display: none } gewinnen. */
[hidden] {
  display: none !important;
}

section {
  margin-bottom: 1.5rem;
  padding: 1.5rem;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}

/* Größerer Abstand zwischen den Bereichen von "Auswahl" (Kopfzeile, Name+
   Sprache, Themenauswahl, Trainingsziel) als innerhalb eines Bereichs. */
#selector-section {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.selector-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.selector-header h2 {
  margin: 0;
}

.selector-header #area-switcher {
  margin: 0;
}

.selector-header-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

/* margin-left: auto schiebt Admin-/Hilfe-Buttons unabhängig von der Breite
   des Training/Verwalten-Umschalters immer an den rechten Rand - bleiben
   dabei als Gruppe zusammen, auch wenn die Zeile umbricht. */
.admin-help-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

#help-button,
#admin-login-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border-radius: 50%;
  font-size: 1.1rem;
  flex: 0 0 auto;
  color: var(--accent-sun);
  font-weight: 700;
}

#help-dialog-body h4,
#impressum-dialog h4,
#datenschutz-dialog h4 {
  margin: 1rem 0 0.3rem;
}

#help-dialog-body h4:first-child,
#impressum-dialog h4:first-child,
#datenschutz-dialog h4:first-child {
  margin-top: 0;
}

#help-dialog-body p,
#help-dialog-body li,
#impressum-dialog p,
#datenschutz-dialog p {
  max-width: 60ch;
  line-height: 1.5;
}

#help-dialog-body ul {
  margin: 0.3rem 0;
  padding-left: 1.2rem;
}

#help-dialog-body li {
  margin-bottom: 0.4rem;
}

#datenschutz-dialog .meta-line {
  margin-top: 1.5rem;
  font-size: 0.85rem;
  color: var(--ink-soft);
}

#help-dialog-body table {
  border-collapse: collapse;
  margin: 0.4rem 0 0.8rem;
  font-size: 0.85rem;
}

#help-dialog-body th,
#help-dialog-body td {
  padding: 0.25rem 0.6rem;
  text-align: right;
  border-bottom: 1px solid var(--border);
}

#help-dialog-body th:first-child,
#help-dialog-body td:first-child {
  text-align: left;
}

.identity-panel,
.topic-selection {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

#user-name-panel,
#shared-language-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

/* Verhindert, dass z. B. "Nach:" von seinem <select> getrennt umbricht - ein
   Umbruch soll immer zwischen zwei Labels passieren, nie innerhalb eines. */
#user-name-panel label,
#shared-language-panel label {
  white-space: nowrap;
}

#user-pin {
  width: 5rem;
}

form {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}

input, select, button, textarea, .file-picker-label {
  font-family: inherit;
  font-size: 1rem;
  padding: 0.4rem 0.6rem;
  background: var(--surface-2);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  max-width: 100%;
}

/* Versteckt das native <input type="file"> visuell, bleibt aber fokussier-
   und bedienbar - das zugehörige <label> (siehe .file-picker-label) öffnet
   den Datei-Dialog per Klick. So kontrollieren wir den Button-Text selbst,
   statt den vom Browser vorgegebenen ("Datei auswählen" u. Ä.) zu erben. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.file-picker-label {
  display: inline-block;
  cursor: pointer;
}

.file-picker-name {
  font-size: 0.85rem;
  color: var(--ink-soft);
  margin-left: 0.4rem;
}

input:focus-visible, select:focus-visible, button:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent-sun);
  outline-offset: 2px;
}

button {
  cursor: pointer;
}

/* <fieldset> hat browserseitig ein implizites min-width: min-content, das
   sich anders als bei normalen Boxen NICHT von box-sizing/min-width:0 auf
   Vorfahren "vererbt" - es ragte dadurch (z. B. bei "Wortquelle"/"Sätze" im
   Kommunikationstest) über schmale Karten hinaus, obwohl alle Inhalte selbst
   längst schrumpfen konnten. Betrifft grundsätzlich jedes <fieldset>. */
fieldset {
  min-width: 0;
}

#test-setup,
#communication-test-setup {
  min-width: 0;
}

input[type="radio"], input[type="checkbox"] {
  accent-color: var(--accent-sun);
}

/* Primäre Trainings-Aktionen (Workflow starten) heben sich farblich ab -
   Verwalten-Formulare bleiben bewusst neutral, siehe CLAUDE.md Phase 9. */
#start-memorize-vocab,
#start-memorize-grammar,
#start-practice-vocab,
#start-practice-grammar,
#start-test,
#start-communication-test,
#check-practice-cloze,
#submit-test,
#next-question,
#submit-vocab-answer {
  background: var(--accent-sun);
  color: #1A1305;
  font-weight: 700;
  border-color: var(--accent-sun);
}

.practice-settings-card,
.practice-question-card,
.practice-result-card {
  border-radius: var(--radius-md);
  padding: 0.9rem 1rem;
  margin: 0.8rem 0;
}

.practice-settings-card {
  background: var(--surface-2);
}

.practice-question-card {
  background: color-mix(in srgb, var(--surface) 85%, white 10%);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent-mint);
}

.practice-result-card {
  background: var(--surface-2);
}

.practice-settings-card {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.practice-settings-card fieldset {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.2rem;
}

.practice-settings-card #test-type-switcher {
  margin: 0;
}

.practice-settings-card fieldset {
  border: none;
  padding: 0;
  margin: 0;
}

.practice-settings-card legend {
  padding: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-soft);
}

/* Vorher white-space:nowrap - hielt zwar Label-Text und Steuerelement
   zusammen, verhinderte aber JEDES Umbrechen, auch innerhalb langer
   Radiobutton-Texte ("Aus ausgewählten Kategorien") oder vor breiten
   <select>-Elementen ("Satzlänge: ..."), was auf schmalen Bildschirmen zum
   Überlaufen führte. Jetzt per Flex gelöst: Label-Inhalt bleibt als Einheit
   zusammen (bricht komplett auf eine neue Zeile um, dank flex-wrap oben am
   Fieldset), kann bei Bedarf aber selbst schrumpfen statt zu überlaufen. */
.practice-settings-card label {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  max-width: 100%;
  min-width: 0;
}

.practice-settings-card label select,
.practice-settings-card label input[type="number"] {
  min-width: 0;
  flex: 0 1 auto;
}

.practice-button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.8rem 0;
}

.topic-block {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1rem 1.2rem;
  margin-bottom: 1.2rem;
}

.topic-block:last-child {
  margin-bottom: 0;
}

.topic-block h3 {
  margin-top: 0;
}

/* Oberste Navigations-Ebenen als Pill-Tabs - natives Radio bleibt fokussierbar,
   nur visuell versteckt (kein display:none), Label zeigt den Zustand an. */
#area-switcher,
#mode-switcher,
#test-type-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0;
}

#area-switcher input,
#mode-switcher input,
#test-type-switcher input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

#area-switcher label,
#mode-switcher label,
#test-type-switcher label {
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--ink-soft);
  cursor: pointer;
  font-weight: 600;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

#area-switcher label:has(input:checked),
#mode-switcher label:has(input:checked),
#test-type-switcher label:has(input:checked) {
  background: var(--accent-sun);
  color: #1A1305;
  border-color: var(--accent-sun);
}

#area-switcher label:has(input:focus-visible),
#mode-switcher label:has(input:focus-visible),
#test-type-switcher label:has(input:focus-visible) {
  outline: 2px solid var(--accent-sun);
  outline-offset: 2px;
}

ul#language-list {
  list-style: none;
  padding: 0;
}

#language-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  max-width: 420px;
  margin-bottom: 0.3rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.translation-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-width: 0;
  margin-bottom: 0.5rem;
}

.translation-arrow {
  color: var(--ink-soft);
  font-weight: 700;
  flex: 0 0 auto;
}

.translation-row .translation-language {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 45%;
}

.translation-row .translation-text {
  flex: 1 1 auto;
  min-width: 0;
}

#translation-rows {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1 1 100%;
  min-width: 0;
}

.mc-option-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}

.mc-option-button {
  flex: 1 1 auto;
  text-align: left;
}

#mc-options button.correct {
  background: var(--success-bg);
  color: var(--success-text);
  border-color: var(--success-border);
}

#mc-options button.incorrect {
  background: var(--error-bg);
  color: var(--error-text);
  border-color: var(--error-border);
}

.answer-row {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  max-width: 100%;
}

#typed-answer {
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
}

#typed-answer.correct {
  background: var(--success-bg);
  color: var(--success-text);
  border-color: var(--success-border);
}

#typed-answer.incorrect {
  background: var(--error-bg);
  color: var(--error-text);
  border-color: var(--error-border);
}

#test-items-list input[type="text"] {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin-top: 0.3rem;
}

#practice-result {
  font-weight: bold;
  margin-bottom: 0.2rem;
}

#result-answer-line {
  margin: 0 0 0.6rem 0;
  font-weight: bold;
}

#memorize-grammar-list article {
  margin-bottom: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 1px dashed var(--border);
}

#memorize-grammar-list h3 {
  margin-bottom: 0.3rem;
}

#practice-cloze-sentences li {
  margin-bottom: 0.8rem;
}

#practice-cloze-sentences select.correct {
  background: var(--success-bg);
  color: var(--success-text);
  border-color: var(--success-border);
}

#practice-cloze-sentences select.incorrect {
  background: var(--error-bg);
  color: var(--error-text);
  border-color: var(--error-border);
}

#practice-cloze-score {
  font-weight: bold;
}

/* Selektor war bisher .status-override (Klasse), das Element hat aber nur
   die id="status-override" - diese Regel griff dadurch nie, was u. a. das
   Umbrechen zwischen Radiobutton und Text erklärt (kein nowrap aktiv). */
#status-override {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.9rem;
}

#status-override label {
  display: inline-block;
  margin-right: 0.5rem;
  font-weight: normal;
  white-space: nowrap;
}

#memorize-vocab-pagination {
  margin: 0.5rem 0;
}

.review-item {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: flex-start;
  max-width: 640px;
  width: 100%;
  margin: 0 auto 0.6rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-sizing: border-box;
}

.review-item input,
.review-item textarea {
  flex: 1 1 160px;
  min-width: 0;
}

.translation-fields {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  flex: 1 1 220px;
  min-width: 0;
}

.translation-field {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.translation-field-label {
  min-width: 5.5rem;
  color: var(--ink-soft);
  font-size: 0.85rem;
}

.translation-field input {
  flex: 1 1 auto;
  min-width: 0;
}

/* Der Resize-Griff selbst ist ein natives Browser-Element und lässt sich
   nicht per CSS vergrößern - stattdessen die Textarea von vornherein
   großzügiger, damit auf dem Handy seltener manuell nachvergrößert werden
   muss (der winzige Griff ist dort besonders schwer zu treffen). */
.review-item textarea {
  min-height: 6rem;
  width: 100%;
  resize: vertical;
}

.category-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  margin-bottom: 0.3rem;
}

.category-row-status {
  color: var(--error-text);
  font-size: 0.85rem;
}

.speak-button {
  padding: 0.1rem 0.4rem;
  font-size: 0.9rem;
  line-height: 1;
  vertical-align: middle;
  margin: 0 0.2rem;
}

#points-balance {
  font-weight: bold;
  font-size: 1.1rem;
}

#rewards-list,
#rewards-manage-list {
  list-style: none;
  padding: 0;
}

/* Wimpelkette über der Olympiade-Liste: eine Wellenlinie in drei Schwüngen
   über die volle Breite des Dialogs, Wimpel in den drei App-Akzentfarben. */
/* aspect-ratio statt fester Höhe + preserveAspectRatio="none": das viewBox
   (600x110) wird dadurch immer gleichmäßig skaliert (x/y-Faktor identisch),
   sonst verzerrt eine ungleichmäßige Streckung die rotate()-Winkel der
   Wimpel und die Dreiecksbasis liegt nicht mehr parallel zur Schnur. */
.leaderboard-bunting {
  display: block;
  width: 100%;
  aspect-ratio: 600 / 98;
  margin-bottom: 0.6rem;
}

/* list-style:none statt der nativen Nummerierung - eigenes .leaderboard-rank
   Element (app.js) übernimmt die Rangzahl, funktioniert auch im
   Grid-Layout der Desktop-Media-Query unten (dort ist das <li> selbst kein
   list-item mehr). */
#leaderboard-list {
  max-width: 420px;
  list-style: none;
  padding: 0;
}

#leaderboard-list li {
  padding: 0;
}

.leaderboard-rank {
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  min-width: 1.4rem;
}

/* Mehr Padding/Gap als bei den anderen Listen hier bewusst: bricht der
   Zeileninhalt (Handy-Breite) nach dem Namen um, steht die Trophäen-Zeile
   mit ihren 2.2rem hohen Icons sonst zu dicht an der Trennlinie darunter
   bzw. am Namen darüber. Höhe passt sich automatisch an (kein fixes
   height/line-height), das Padding sorgt für Luft auf beiden Seiten. */
.leaderboard-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.leaderboard-row:last-child {
  border-bottom: none;
}

/* Kleiner als vorher (war 5rem) - macht mehr Platz für die Chips-Gruppe,
   die jetzt garantiert in einer Zeile bleiben soll (s. u.). */
.leaderboard-name {
  min-width: 3.5rem;
}

/* Garantiert eine Zeile: flex-wrap: nowrap verbietet den Chips, selbst
   umzubrechen - die äußere .leaderboard-row bricht weiterhin bevorzugt
   nach dem Namen um (die Chips-Gruppe ist dort ein einzelnes Flex-Item).
   Reicht der Platz selbst dafür auf einem sehr schmalen Gerät oder bei
   einem langen Namen nicht aus, scrollt NUR diese kleine Gruppe seitlich
   (overflow-x: auto) statt umzubrechen oder überzulaufen - das war vorher
   das eigentliche Problem (nowrap ohne Scroll-Sicherheitsnetz lief seitlich
   über den Rand hinaus). Abstand zwischen den Chips etwas verringert
   (1.125rem -> 0.75rem), damit der Scroll-Fall möglichst selten gebraucht
   wird. */
.leaderboard-medal-chips {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.75rem;
  overflow-x: auto;
  padding-bottom: 2px;
}

.leaderboard-medal-chip {
  display: flex;
  flex: 0 0 auto;
  flex-direction: row;
  align-items: center;
  gap: 0.3rem;
}

/* Trennlinie: unsichtbar/ohne Wirkung im schmalen Fallback (dort hat
   .leaderboard-row selbst schon ihren eigenen border-bottom). Erst in der
   Media Query unten bekommt sie ihre eigentliche Rolle. */
.leaderboard-row-divider {
  display: none;
}

/* Ab hier reicht die Breite für echte Spaltenausrichtung: Rang/Name/die
   3 Trophäen richten sich per CSS-Grid über ALLE Zeilen hinweg exakt
   untereinander aus (max-content je Spalte, wächst automatisch mit dem
   längsten Namen/Inhalt in dieser Spalte), unabhängig davon, wie
   unterschiedlich lang einzelne Namen sind - das kann die einfache
   Flex-Lösung unten (die als schmale-Bildschirme-Fallback aktiv bleibt)
   nicht leisten, weil dort jede Zeile für sich eigenständig layoutet statt
   sich an den anderen Zeilen zu orientieren. .leaderboard-row und
   .leaderboard-medal-chips werden dafür zu display:contents - ihre Kinder
   (Rang, Name, die 3 Chips) werden direkte Grid-Items von #leaderboard-list.

   Zwei Korrekturen gegenüber der ersten Grid-Version:
   1) align-items: stretch (statt center) + display:flex/align-items:center
      auf den Zellen selbst - sonst haben unterschiedlich hohe Zellen (die
      2.2rem hohen Trophäen-Icons vs. einzeiliger Text bei Rang/Name) auch
      unterschiedlich hohe eigene Boxen, und ihre individuellen Ränder
      landen dadurch auf verschiedenen Höhen (wirkte "nicht auf gleicher
      Höhe"). Mit stretch füllt jede Zelle die volle Zeilenhöhe aus.
   2) Trennlinie NICHT mehr pro Zelle einzeln, sondern ein eigenes,
      volle-Breite-überspannendes Element (.leaderboard-row-divider,
      grid-column: 1/-1) als 6. Kind pro Zeile - einzelne Zellränder rissen
      an den column-gap-Lücken auseinander statt durchgezogen zu wirken. */
@media (min-width: 480px) {
  #leaderboard-list {
    display: grid;
    grid-template-columns: 1.6rem minmax(3.5rem, max-content) repeat(3, max-content);
    align-items: stretch;
    column-gap: 0.75rem;
    row-gap: 0.5rem;
  }

  .leaderboard-row,
  .leaderboard-medal-chips {
    display: contents;
  }

  .leaderboard-rank,
  .leaderboard-name,
  .leaderboard-medal-chip {
    display: flex;
    align-items: center;
  }

  .leaderboard-row-divider {
    display: block;
    grid-column: 1 / -1;
    border-bottom: 1px solid var(--border);
  }

  .leaderboard-row:last-child .leaderboard-row-divider {
    display: none;
  }
}

#rewards-list li,
#rewards-manage-list li,
#user-pins-list li,
#currency-tiers-list li,
#currency-tiers-manage-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  max-width: 520px;
  margin-bottom: 0.4rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

#user-pins-list {
  list-style: none;
  padding: 0;
}

/* Nur der erste Button bekommt margin-left:auto - das schiebt ihn (und
   alles danach, hier "Löschen") als geschlossene Gruppe an den rechten
   Rand. Hätten beide Buttons margin-left:auto, würde sich der freie Platz
   auf beide Ränder aufteilen und eine Lücke zwischen ihnen reißen. */
#user-pins-list li .user-pin-reset-btn {
  margin-left: auto;
}

#rewards-list li button {
  margin-left: auto;
}

#rewards-manage-list li input[type="text"] {
  flex: 1 1 140px;
}

#rewards-manage-list li input[type="number"] {
  width: 5rem;
}

.reward-redeemed {
  opacity: 0.55;
}

.reward-redeemed-label {
  font-size: 0.85rem;
  font-weight: bold;
  color: var(--ink-soft);
}

.icon-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.4rem 0;
}

.icon-option {
  font-size: 1.3rem;
  line-height: 1;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-sm);
}

.icon-option.active {
  border-color: var(--accent-sun);
  background: var(--surface-2);
}

.reward-icon {
  font-size: 1.2rem;
  flex: 0 0 auto;
}

.reward-icon:empty {
  display: none;
}

/* Ein Basis-Emoji auf einem farbigen Kreis (Farbe kommt vom Admin, tier.color
   - "Bronze" soll auch wirklich bronzefarben aussehen) + der Punktewert als
   kleines Badge oben drauf. */
/* margin-right/-bottom reservieren den Platz, den .currency-icon-value
   (absolut positioniert, bottom/right: -0.3rem) über die 2.2rem-Box hinaus
   nach außen ragt, PLUS etwas zusätzlichen Luft-Abstand (0.3rem Überstand
   + 0.2rem Abstand = 0.5rem) - sonst würde das Badge zwar nicht mehr
   überlappen, aber direkt an nachfolgendem Inhalt (Trennlinie, nächster
   Chip) kleben. */
.currency-icon {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  width: 2.2rem;
  height: 2.2rem;
  margin: 0 0.5rem 0.5rem 0;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
}

.currency-icon-emoji {
  font-size: 1.3rem;
  line-height: 1;
}

/* Eine der gestapelten Masken-Ebenen einer Trophäen-Icon-Grafik
   (Körper/gedämpfte Teilform/Glanz/Detail) - siehe buildCurrencyIcon() in
   app.js. Absolut positioniert, füllt den .currency-icon-Kreis komplett. */
.currency-icon-layer {
  position: absolute;
  inset: 0;
}

.currency-icon-value {
  position: absolute;
  bottom: -0.3rem;
  right: -0.3rem;
  font-size: 0.6rem;
  font-weight: 700;
  background: var(--accent-sun);
  color: var(--bg);
  border-radius: 999px;
  padding: 0.05rem 0.3rem;
  line-height: 1.2;
}

.currency-tier-name {
  font-weight: 600;
  min-width: 5rem;
}

/* Gleicher Badge-Stil wie .currency-icon-value (Punktezahl auf dem Icon),
   aber in Blau statt Orange, damit "Wert" (Icon-Badge) und "Anzahl" (dieses
   Badge) auf den ersten Blick unterscheidbar bleiben - fixe Breite +
   tabular-nums, damit die Stückzahlen über alle Zeilen hinweg exakt
   untereinanderstehen, egal wie lang der Stufenname ist. */
.currency-tier-owned {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.2rem;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--accent-ocean);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* margin-left: auto schiebt Mengenfeld+Kaufen-Button an den rechten Rand der
   Zeile, unabhängig davon, wie lang Name/Bestand daneben sind. */
.currency-tier-buy-controls {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
}

.currency-tier-qty {
  width: 4.5rem;
}

/* Nochmal kürzer (70% von vorher: 5.5rem -> 3.85rem) und mit zusätzlichem
   Abstand zur Icon-Vorschau davor, damit beide klar getrennt wirken.
   Gezielt auf den Stufentitel beschränkt, sonst würde auch das Hex-Feld
   der Farbwahl (ebenfalls type="text") mitschrumpfen. */
#currency-tiers-manage-list li .currency-tier-manage-name {
  flex: 0 1 3.85rem;
  margin-left: 0.6rem;
}

#currency-tiers-manage-list li input[type="number"] {
  width: 4rem;
}

#currency-tiers-manage-list li input.currency-tier-points-input {
  width: 5.5rem;
}

/* Eigene Farbpalette statt des nativen <input type="color"> - siehe
   buildColorPicker() in app.js für die Begründung. */
.color-picker {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.color-picker-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  max-width: 11rem;
}

.color-swatch-option {
  width: 1.4rem;
  height: 1.4rem;
  padding: 0;
  border-radius: 50%;
  border: 2px solid transparent;
}

.color-swatch-option.active {
  border-color: var(--ink);
}

.color-picker-hex {
  width: 7.5rem;
  font-variant-numeric: tabular-nums;
}

#currency-theme-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.5rem;
}

.cloze-rule-label,
.test-item-context {
  font-size: 0.8rem;
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  margin-bottom: 0.15rem;
}

.test-item-feedback {
  font-size: 0.85rem;
  font-style: italic;
  color: var(--ink-soft);
  margin: 0.15rem 0 0.3rem;
}

.extra-vocabulary-legend {
  font-size: 0.85rem;
  font-style: italic;
  color: var(--ink-soft);
  margin: 0.15rem 0 0.3rem;
}

.pool-word {
  color: var(--accent-mint);
  font-weight: 600;
}

.view-content-button {
  margin-left: 0.5rem;
  font-size: 0.8rem;
  padding: 0.15rem 0.4rem;
}

#vocab-module-search,
#grammar-module-search {
  display: block;
  margin: 0.3rem 0;
  width: 100%;
  box-sizing: border-box;
}

#category-list-controls {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0.8rem 0 0.4rem;
}

#dashboard-overview {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

#dashboard-overview h3 {
  margin-top: 0;
  margin-bottom: 0.4rem;
}

#dashboard-overview ul {
  list-style: none;
  padding: 0.5rem;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  min-width: 260px;
}

#dashboard-overview li {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.3rem 0.5rem;
  margin-bottom: 0.3rem;
}

.module-list-empty {
  background: none;
  border: none;
  padding: 0.2rem 0;
  color: var(--ink-soft);
  font-size: 0.9rem;
}

#test-items-list li {
  margin-bottom: 0.6rem;
}

#test-results-list {
  list-style: none;
  padding: 0;
}

#test-results-list li {
  margin-bottom: 0.4rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--radius-sm);
}

#test-results-list li.correct {
  background: var(--success-bg);
  color: var(--success-text);
}

#test-results-list li.incorrect {
  background: var(--error-bg);
  color: var(--error-text);
}

#test-score {
  font-weight: bold;
}

.hekto-widget {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.9rem;
  margin: 0.75rem 0 1.25rem;
  animation: hekto-hop 0.6s ease-out;
}

@keyframes hekto-hop {
  0% { transform: translateY(0) scale(0.9); opacity: 0; }
  40% { transform: translateY(-14px) scale(1.05); opacity: 1; }
  65% { transform: translateY(0) scale(1); }
  80% { transform: translateY(-6px); }
  100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .hekto-widget {
    animation: none;
  }
}

.spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spinner-rotate 0.7s linear infinite;
  vertical-align: middle;
}

.spinner-label {
  margin-left: 0.5rem;
  vertical-align: middle;
}

@keyframes spinner-rotate {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

.spinner-row {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin: 0.4rem 0;
  color: var(--ink-soft);
  font-size: 0.9rem;
}

.hekto-figure {
  width: 72px;
  height: auto;
  flex-shrink: 0;
}

.hekto-bubble {
  position: relative;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 0.6rem 0.9rem;
  font-weight: 600;
  font-size: 0.92rem;
  margin: 0;
  max-width: 32ch;
}

.hekto-bubble::before {
  content: "";
  position: absolute;
  left: -8px;
  top: 50%;
  transform: translateY(-50%);
  border-width: 6px 8px 6px 0;
  border-style: solid;
  border-color: transparent var(--surface-2) transparent transparent;
}

.dashboard-intro {
  color: var(--ink);
  font-size: 1.1rem;
  font-weight: 700;
  margin: 0.8rem 0 0.5rem 0;
}

#status-summary {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

#status-summary h3 {
  margin: 0;
}

.status-summary-empty {
  color: var(--ink-soft);
  font-size: 0.9rem;
  margin: 0;
}

.status-summary-row {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.8rem;
}

.status-summary-topline {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.status-summary-label {
  min-width: 5.5rem;
  font-weight: 700;
  color: var(--ink);
}

.status-summary-topics {
  color: var(--ink-soft);
}

.status-summary-barline {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.status-summary-value {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.status-summary-bar {
  flex: 1 1 auto;
  height: 6px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}

.status-summary-bar span {
  display: block;
  height: 100%;
  background: var(--success-text);
}

dialog {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  max-width: 640px;
  width: 90vw;
  max-height: 80vh;
  overflow-y: auto;
}

dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

#toast {
  position: fixed;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%) translateY(-12px);
  z-index: 100;
  max-width: 90vw;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-md);
  background: var(--success-bg);
  color: var(--success-text);
  border: 1px solid var(--success-border);
  font-weight: 600;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

#toast.toast-error {
  background: var(--error-bg);
  color: var(--error-text);
  border-color: var(--error-border);
}

#toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  #toast {
    transition: none;
  }
}

.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

#category-delete-step-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.6rem;
}

#category-delete-step-confirm,
#category-delete-step-move {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
  margin-top: 0.6rem;
}

#category-delete-step-confirm div,
#category-delete-step-move div {
  display: flex;
  gap: 0.6rem;
}

.app-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

.app-header h1 {
  margin: 0;
}

.app-header-titles {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.app-header-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Eigenes SVG statt Emoji (✉️/📧) fürs Kontakt-Icon - Emoji-Rendering ist
   je nach Betriebssystem/Schriftart unzuverlässig (zeigte sich bei einem
   Nutzer als leeres weißes Rechteck statt Brief). CSS-Maske + feste Farbe
   (--accent-sun, dasselbe Gelb/Orange wie bei den Trophäen-Icons) rendert
   dagegen überall identisch. */
.envelope-icon {
  display: inline-block;
  width: 1.1rem;
  height: 1.1rem;
  vertical-align: -0.2rem;
  background: var(--accent-sun);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A//www.w3.org/2000/svg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Crect%20x%3D%272%27%20y%3D%274%27%20width%3D%2720%27%20height%3D%2716%27%20rx%3D%272%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.6%27/%3E%3Cpath%20d%3D%27M3%205.5%20L12%2013%20L21%205.5%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.6%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A//www.w3.org/2000/svg%27%20viewBox%3D%270%200%2024%2024%27%3E%3Crect%20x%3D%272%27%20y%3D%274%27%20width%3D%2720%27%20height%3D%2716%27%20rx%3D%272%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.6%27/%3E%3Cpath%20d%3D%27M3%205.5%20L12%2013%20L21%205.5%27%20fill%3D%27none%27%20stroke%3D%27black%27%20stroke-width%3D%271.6%27%20stroke-linecap%3D%27round%27%20stroke-linejoin%3D%27round%27/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

#site-footer {
  display: flex;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 2.5rem;
  padding: 1.25rem 0;
  border-top: 1px solid var(--border);
}

#site-footer button {
  background: none;
  border: none;
  padding: 0;
  color: var(--ink-soft);
  font-size: 0.85rem;
  text-decoration: underline;
  cursor: pointer;
}

#site-footer button:hover {
  color: var(--ink);
}

#access-config-link-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

#access-config-link {
  flex: 1 1 260px;
  min-width: 0;
  font-family: ui-monospace, monospace;
  font-size: 0.85rem;
}

#access-config-copy {
  flex: 0 0 auto;
  padding: 0.4rem 0.6rem;
  font-size: 1.1rem;
  line-height: 1;
}

.app-subtitle {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--ink);
}

#theme-options {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.theme-option {
  text-align: left;
  padding: 0.6rem 0.9rem;
}

.theme-option.active {
  border-color: var(--accent-sun);
  background: var(--surface-2);
}

.theme-option:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Browser dimmen den Text bei :disabled sonst über -webkit-text-fill-color
   zusätzlich zu opacity/color ab (WebKit/Blink) - dadurch war der Text im
   "Inhalt ansehen"-Dialog kaum lesbar. Explizit auf --ink-soft gesetzt statt
   verlassen auf Browser-Default. */
input:disabled, select:disabled, textarea:disabled {
  opacity: 1;
  color: var(--ink-soft);
  -webkit-text-fill-color: var(--ink-soft);
  cursor: default;
}
