/* Eloquarium – Mobile-first Grundlayout. Der Seitenhintergrund folgt dem
   aktuellen Rang über --rank-color. */
:root {
  --rank-color: #A97BE6;      /* FLIEDER als Start */
  --bg: #14121a;
  --panel: rgba(20, 18, 26, 0.82);
  --panel-solid: #1e1b28;
  --text: #f2eefa;
  --text-dim: #b3abc4;
  /* R30: Türkis ist die Bedienfarbe der App. Bernstein (#ffd166) und das alte
     Rot (#ff6b6b) sind jetzt CITRIN und RUBIN – Farben, die einen Wert bedeuten.
     Ein Knopf darf nicht aussehen wie ein Multiplikator. --danger ist deshalb
     ein dunkleres, unbunteres Rot als der RUBIN-Chip. */
  --accent: #2FD8D0;
  /* GOLD gehört den COMBS – dem Punktestand, nicht der Bedienung (R37). Bis R30
     war Bernstein die Bedienfarbe; als Türkis das übernahm, wurde das ⬢ mit
     eingefärbt und die Combs verloren ihren Ton, obwohl sie mit der Bedienung
     nichts zu tun haben. Der Ton ist WÄRMER als CITRIN #F3CE3E (Gelbstich ~50°
     gegen ~40°): Der Zitrin ist ein Multiplikator und darf mit der Währung nicht
     verwechselbar sein. Verwendet nur dort, wo eine Comb-Zahl steht. */
  --gold: #FFC24B;
  --danger: #C33B4C;
  /* Bewusst NICHT der SMARAGD-Ton (#35C48A): "hat geklappt" ist eine Meldung,
     kein Multiplikator. Heller und blasser als der Chip. */
  --ok: #7FE0A8;
  --vowel: #D8D8E0;
  --consonant: #FFFFFF;
  --radius: 14px;
  font-size: 16px;
}

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

html, body { height: 100%; }

body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--text);
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--rank-color) 55%, var(--bg)) 0%, var(--bg) 70%);
  transition: background 0.8s ease;
  min-height: 100dvh;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

button {
  font: inherit;
  border: none;
  border-radius: var(--radius);
  padding: 0.65rem 1rem;
  background: var(--panel-solid);
  color: var(--text);
  cursor: pointer;
}
button.primary { background: var(--accent); color: #241c00; font-weight: 700; }
button:disabled { opacity: 0.5; cursor: default; }

/* R33: Auf ANTIPPBAREN Elementen darf keine Textauswahl aufgehen. Am Handy
   öffnete ein etwas längerer Druck auf ein Icon die Markierung samt
   "Ausschneiden/Kopieren"-Leiste – die Symbole sind Beschriftungen von Knöpfen,
   kein Text zum Herausziehen. Fließtext, Listen und Eingabefelder bleiben
   bewusst markierbar: Es ging nie ums Kopieren, sondern um die Fehlbedienung.
   Die Liste führt die klickbaren Nicht-Knöpfe auf (alles mit cursor:pointer,
   das kein <button> ist). */
button, a, label,
.word-block, .mlabel-rank, .swap-points, .rank-tip, .medal {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

input, select, textarea {
  font: inherit;
  width: 100%;
  padding: 0.65rem 0.8rem;
  border-radius: 10px;
  border: 1px solid #3a3450;
  background: #241f33;
  color: var(--text);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); border-color: transparent; }

a { color: var(--accent); text-decoration: none; }

.hidden { display: none !important; }

/* --- Auth-Seite --- */
.auth-wrap {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  gap: 1.2rem;
}
.logo {
  font-size: 2.4rem;
  font-weight: 800;
  letter-spacing: 0.35em;
  text-shadow: 0 2px 18px rgba(0,0,0,0.4);
}
.logo .hexline { display: flex; gap: 0.3rem; justify-content: center; }
.card {
  width: min(400px, 100%);
  background: var(--panel);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius);
  padding: 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.card h2 { font-size: 1.1rem; font-weight: 600; }
.field label { display: block; font-size: 0.85rem; color: var(--text-dim); margin-bottom: 0.3rem; }
.msg { min-height: 1.3em; font-size: 0.9rem; }
.msg.error { color: var(--danger); }
.msg.ok { color: var(--ok); }
.switch-line { font-size: 0.9rem; color: var(--text-dim); text-align: center; }

.lang-switch { display: flex; gap: 0.4rem; justify-content: center; }
.lang-switch button {
  padding: 0.3rem 0.7rem; font-size: 0.85rem; border-radius: 999px;
  background: rgba(255,255,255,0.1);
}
.lang-switch button.active { background: var(--accent); color: #241c00; font-weight: 700; }

/* --- Spielseite --- */
.game-wrap {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  max-width: 640px;
  margin: 0 auto;
  /* Bezugsrahmen für das absolut positionierte Menü-Popup: sonst misst es
     seine Position von der Fensterkante und klebt auf breiten Desktops
     losgelöst ganz links statt unter dem ☰-Knopf. */
  position: relative;
}

/* R25: Symbolknöpfe ohne Fläche. Die Kacheln waren ein zweites Raster über
   Kopf- und Fußzeile; das Symbol allein trägt die Bedeutung. Rückmeldung beim
   Drücken gibt jetzt eine kurze Verkleinerung statt eines Aufleuchtens.
   Ausnahme: .sound-btn behält seine Zustandsfarben (siehe unten). */
.icon-btn {
  background: transparent;
  padding: 0.4rem 0.55rem;
  font-size: 1.1rem;
  transition: transform 90ms ease, opacity 140ms ease;
}
.icon-btn:active { transform: scale(0.88); }
/* R43c – EIN KNOPF, ZWEI AUFGABEN (nur fuer Admins): kurz tippen wuerfelt, lang
   druecken oeffnet die Werkzeuge. Das zweite Zeichen liegt deshalb AUF dem
   ersten, statt daneben zu stehen - die Reihe bleibt dadurch bei sechs Knoepfen.
   Der Schatten haelt es auf jedem Untergrund lesbar. */
.icon-btn.admin-merged { position: relative; }
.icon-btn.admin-merged::after {
  content: '🔧';
  position: absolute;
  right: 0.05rem;
  bottom: 0.05rem;
  font-size: 0.6em;
  line-height: 1;
  text-shadow: 0 0 3px #12101A, 0 0 3px #12101A;
  pointer-events: none;
}
.icon-btn:disabled { opacity: 0.32; }
.icon-btn:disabled:active { transform: none; }

/* Seit R26 steht das ☰ auf BEIDEN Seiten oben rechts, also klappt sein Menü
   auch überall rechts auf – direkt unter dem Knopf statt quer über die Leiste. */
.menu-dropdown {
  position: absolute;
  top: 3.2rem;
  right: 0.6rem;
  z-index: 50;
  background: var(--panel-solid);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--radius);
  padding: 0.8rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  min-width: 220px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.5);
}
.menu-dropdown a { padding: 0.35rem 0.2rem; color: var(--text); }
/* Nachgeordnete Menüpunkte (z. B. "auf allen Geräten abmelden") treten
   optisch zurück – sie sind der seltene Sonderfall, nicht der Normalweg. */
.menu-dropdown .menu-sub {
  font-size: 0.82rem;
  opacity: 0.75;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.15);
}
.menu-dropdown a:active { color: var(--accent); }
.menu-head { display: flex; flex-direction: column; gap: 0.15rem; padding-bottom: 0.4rem; border-bottom: 1px solid rgba(255,255,255,0.1); }
.menu-credits { color: var(--accent); font-size: 0.9rem; }

/* Modi-Popup am ⬡ (R27): dieselbe Bauart wie das ☰-Menü, nur an der anderen
   Außenkante – links unter dem ⬡, das dort steht. Die Zeilen stehen kompakt
   untereinander, Symbol und Name linksbündig wie der Knopf darüber. */
.mode-dropdown {
  left: 0.6rem;
  right: auto;
  min-width: 12rem;
  gap: 0.1rem;
  padding: 0.5rem;
}
.mode-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.5rem;
  background: transparent;
  border-radius: 8px;
  font-weight: 700;
  text-align: left;
}
.mode-row:hover:not(:disabled) { background: rgba(255,255,255,0.09); }
.mode-row-emoji { font-size: 1.15rem; line-height: 1.2rem; width: 1.4rem; text-align: center; }
.mode-row-name { flex: 1; }
/* Der laufende Modus ist keine Wahl: Häkchen statt Klickziel, gedämpft. */
.mode-row.current { color: var(--text-dim); opacity: 1; }
.mode-row:disabled { cursor: default; }
.mode-row-check { color: var(--accent); font-weight: 900; }

/* --- Wortfeld mit Punktrechnung (R28b) -------------------------------------
   EIN Raster über vier Zeilen: Reiter (0), Beschriftungen (1), Wort (2),
   Rechnung (3). Die Spalten setzt renderTabs() als `1fr repeat(N, auto) 1fr` –
   die 1fr-Ränder zentrieren die Kette, jede Faktorspalte ist so breit wie das
   breitere von Reiter und Beschriftung. Dadurch steht jede Zahl garantiert über
   ihrem Namen, ohne dass irgendwo Breiten nachgerechnet werden müssen.
   Alle Zeilenhöhen stehen fest: Über dem Brett darf nichts wachsen, sonst
   rutschen die Chips (Lehre aus R11). */
.word-block {
  display: grid;
  grid-template-rows: auto auto 2.8rem 1.15rem;
  /* R37: Luft ZWISCHEN den Faktorspalten. Die Reiter sind inhaltsbreit und
     stießen am Handy aneinander – „+1" neben „+1,5" neben „+1" las sich wie eine
     einzige Fläche.
     Der Wert ist die Obergrenze, die noch passt: Im schlimmsten Fall (alle sechs
     Spalten, drei Früchte, dreifach rein, FLIEDER) misst die Kette bei 320 px
     mit 0,35 rem 285 von 294 px – mit 0,45 rem waren es 294,5 und damit ein
     halber Pixel zu viel. Gemessen, nicht geschätzt (Lehre aus R30/R33). */
  column-gap: 0.35rem;
  /* align-items bleibt auf stretch: Sonst schrumpfen die Rasterzellen auf ihre
     Inhaltshöhe – die schwarze Fläche wäre dann nur so hoch wie ihr Rahmen. */
  margin: 0.5rem 0.8rem 0;
  cursor: pointer;
  user-select: none;
}
/* Die schwarze Fläche liegt HINTER den Zeilen 1–3 und läuft über die volle
   Breite, während die Kette darüber mittig und inhaltsbreit bleibt. Sie trägt
   weiterhin Rahmen, Pulsieren und Wackeln. */
.word-bar {
  grid-area: 2 / 1 / 5 / -1;
  border-radius: var(--radius);
  background: var(--panel);
  border: 2px solid transparent;
  pointer-events: none;
}
.word-bar.committable {
  border-color: var(--accent);
  animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 209, 102, 0.35); }
  50% { box-shadow: 0 0 0 8px rgba(255, 209, 102, 0); }
}
.word-bar.shake { animation: shake 0.35s; }
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-7px); }
  75% { transform: translateX(7px); }
}
/* Zeile 2: das Wort – die größte Schrift des Feldes. Die Zeilenhöhe steht fest
   (2,8rem im Raster), die SCHRIFT wächst und schrumpft darin (fitWord in
   main.js): So bleibt das Wort immer so groß wie möglich, ohne dass das Brett
   bei einem langen Wort verrutscht. */
.word-row {
  grid-area: 3 / 1 / 4 / -1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.6rem;
  min-width: 0;
}
.word-display {
  font-size: 2.1rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  line-height: 1;
  /* Platz für das ⌫ rechts – und derselbe Abzug links, damit das Wort trotzdem
     mittig steht.
     R43: von 6 auf 7 rem erhöht. Gemessen bei 375 px blieben zwischen Wortende
     und ⌫ nur 8 px, rechnerisch sind es je nach Gerät bis herunter zu 3 – und
     das ⌫ ist ein Symbolzeichen, das auf manchen Systemen breiter ausfällt.
     Genau dort schob es sich über die letzten Buchstaben. */
  max-width: calc(100% - 7rem);
  display: flex;
  align-items: center;
  /* R43 – SCHIEBEN STATT ABSCHNEIDEN. Vorher lief ein langes Wort in `hidden`
     und war ab etwa 18 Buchstaben schlicht weg. fitWord() verkleinert weiterhin
     bis 1,1 rem (Lesbarkeitsgrenze); was dann noch übersteht, wird jetzt
     gescrollt statt abgeschnitten, und updateWordBar hält das ENDE im Blick –
     dort wächst das Wort. Die Leiste selbst bleibt dabei gleich hoch. */
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  white-space: nowrap;
}
.word-display::-webkit-scrollbar { display: none; }
.wletter { display: inline-block; }

/* GEZEICHNETE MARKEN (R37) – Sechseck = Stein, Kreis = Frucht, Quadrat =
   FARBREIN. Keine Schriftglyphen mehr: Deren Tinte sitzt je nach Schrift anders
   im Kasten (gemessen in Segoe UI: ⬣ 10 px hoch und genau auf der Versalmitte,
   ● 6 px hoch und 1 px darunter), ein fester Ausgleich verschiebt das Problem
   also nur auf fremde Geräte.
   AUSRICHTUNG, schrift- und größenunabhängig: Der Kasten einer Marke ist genau
   VERSALHOCH (--cap, zur Laufzeit aus der echten Schrift gemessen, siehe
   marks.js) und sitzt mit seiner Unterkante auf der Grundlinie – ein
   inline-block ohne eigene Zeilenboxen wird genau so ausgerichtet. Die Form
   steht mittig darin und damit mittig zu den Großbuchstaben daneben.
   Größen kommen aus dem Ort (--fruit/--stone-w/…), weil Leiste, Wortfeld und
   Vorschlagsliste verschiedene Schriftgrößen haben. */
.mark {
  position: relative;
  display: inline-block;
  height: calc(var(--cap, 0.72) * 1em);
  width: var(--mw);
  vertical-align: baseline;
}
.mark > i {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: var(--mw);
  height: var(--mh);
  background: currentColor;
}
.mark + .mark { margin-left: 0.14em; }
/* Kreis. Bewusst etwas größer als die Versalhöhe: Eine gefüllte Fläche wirkt
   kleiner als ein Umriss derselben Höhe. */
.mark-fruit { --mw: var(--fruit, 0.87em); --mh: var(--fruit, 0.87em); }
.mark-fruit > i { border-radius: 50%; }
/* Liegendes Sechseck – dieselbe Silhouette wie das frühere ⬣ (gemessen 11 × 10
   px bei 13,6 px Schrift, also gut 1,1 : 1). */
.mark-stone { --mw: var(--stone-w, 0.80em); --mh: var(--stone-h, 0.72em); }
.mark-stone > i { clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
/* Quadrat für FARBREIN: eine EIGENE Form, die weder nach Stein noch nach Frucht
   aussieht. Vorher standen dort Sechsecke in der Rangfarbe – das las sich wie
   „zwei Steine" und zeigte die falsche Farbe, sobald Stein und Frucht
   übereinstimmten, der Rang aber nicht. */
.mark-pure { --mw: var(--pure, 0.62em); --mh: var(--pure, 0.62em); }
.mark-pure > i { border-radius: 2px; }
/* Zeile 3: die Rechnung (Grundpunkte × Multiplikator = Ergebnis). Sie trägt
   auch „wird geprüft …" und den Wartehinweis für angefangene Chips. */
.calc-line {
  grid-area: 4 / 1 / 5 / -1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--text-dim);
  line-height: 1.15rem;
  overflow: hidden;
  white-space: nowrap;
}
.backspace-btn {
  position: absolute;
  right: 0.45rem;
  top: 50%;
  transform: translateY(-50%);
  padding: 0.35rem 0.65rem;
  font-size: 1.05rem;
  background: rgba(255,255,255,0.12);
}

.msg-line {
  text-align: center;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.15rem 0.5rem;
  /* FESTE Hoehe statt min-height: Vorher wuchs die Zeile mit dem Text und
     schob das Brett nach unten (eine lange Meldung kostete bis zu 24 px).
     Ueber dem Brett darf sich nichts in der Hoehe aendern. */
  height: 1.6rem;
  line-height: 1.3rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.msg-line.error { color: var(--danger); }
.msg-line.ok { color: var(--ok); }
/* Die Meldungszeile trägt seit R28 zugleich den Ergebnis-Reiter. Beide liegen
   im selben Kasten übereinander – die Zeile behält damit ihre feste Höhe, egal
   welches von beidem gerade zu sehen ist. */
.msg-row { position: relative; height: 1.6rem; }
.msg-row .msg-line { position: absolute; inset: 0; }
/* Ergebnis-Reiter: dieselbe schwarze Fläche wie das Wortfeld, nur unten
   abgerundet – er liest sich als dessen Fortsetzung. Zahl weiß, ⬢ gelb wie in
   der Kopfzeile, wo derselbe Wert steht. */
.score-tab {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  padding: 0.1rem 0.9rem;
  border-radius: 0 0 10px 10px;
  background: var(--panel-solid);
  color: var(--text);
  font-weight: 900;
  font-size: 1.05rem;
  line-height: 1.4rem;
  white-space: nowrap;
  box-shadow: 0 2px 10px rgba(0,0,0,0.35);
}
.score-tab-mark { color: var(--gold); }
.score-tab[hidden] { display: none; }

/* Schwebende Zeile über dem Brett (R27): Raster 1fr auto 1fr über die ganze
   Brettbreite, absolut positioniert – sie kostet keine Bretthöhe. Seit R28
   trägt sie nur noch Tauschguthaben und Tauschpreis (mittig); die
   Multiplikator-Infos sind in die Reiterreihe am Wortfeld gewandert. Die drei
   Spalten bleiben, damit die Mitte die Mitte ist. Durchklickbar bleibt sie,
   damit man das Brett darunter erreicht; nur die echten Knöpfe fangen ihre
   Tipps selbst ab. */
.mult-stack {
  position: absolute;
  top: 0.3rem;
  left: 0.4rem;
  right: 0.4rem;
  z-index: 5;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  pointer-events: none;
}
/* Guthaben oben, Tauschpreis darunter – beide rechtsbündig in der freien Ecke. */
.swap-zone { display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; }

/* R37 – SCHWEBELEISTE: „ein Chip ist angehoben". Spiegelbild des Guthabens in
   der LINKEN oberen Brettecke; das Sechseck hat oben nur drei Chips, links und
   rechts bleibt Fläche frei (gemessen 51 px bei 320 px Fenster). Absolut
   positioniert wie .mult-stack, kostet also KEINE Bretthöhe – über dem Brett
   darf nichts wachsen, sonst rutschen die Chips (R4/R11).
   pointer-events wieder AN: Anders als die Multiplikatorleiste trägt sie einen
   echten Knopf. */
.swap-hold {
  position: absolute;
  top: 0.3rem;
  left: 0.4rem;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  max-width: calc(100% - 6rem);
  padding: 0.22rem 0.35rem 0.22rem 0.6rem;
  background: rgba(20, 18, 30, 0.88);
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-size: 0.72rem;
  line-height: 1.2;
  color: var(--text);
}
.swap-hold.hidden { display: none; }
.swap-hold-x {
  width: auto;
  padding: 0.1rem 0.4rem;
  font-size: 0.85rem;
  line-height: 1;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

/* Die gezeichnete Nadel auf dem 📌-Knopf (R37). Sie erbt die Knopfgröße über
   em, damit sie in jeder Media-Query mitschrumpft wie ein Emoji es täte – etwas
   größer als 1em, weil ein Emoji seine Kastenhöhe nie ausfüllt und die Nadel
   daneben sonst kleiner wirkt als 🎲 und 💡. */
.pin-glyph { width: 1.2em; height: 1.2em; display: block; }
/* Angepinnt: Der Knopf leuchtet, die Nadel bleibt dieselbe. */
.pin-btn[aria-pressed="true"] .pin-glyph { filter: drop-shadow(0 0 3px var(--accent)); }
/* Tauschpreis während des Ziehens. Sitzt im selben schwebenden Bereich wie das
   Guthaben, damit das Brett keine Höhe verliert. */
.drag-cost {
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  font-weight: 900;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  color: #1c1524;
  background: #F7DC6F;
  box-shadow: 0 2px 10px rgba(0,0,0,0.45);
}
/* Guthaben reicht nicht – der Server würde den Tausch ablehnen. */
.drag-cost.unaffordable { background: #d9534f; color: #fff; }

.board-container {
  flex: 1;
  position: relative;
  margin: 0.2rem 0.4rem;
  min-height: 0;
}
.board-container canvas {
  position: absolute;
  inset: 0;
  touch-action: none;
}

/* Drei Spalten statt space-between: Die mittlere Spalte ist "auto" und die
   beiden Seiten je "1fr", damit der Einloggen-Knopf exakt in der Fenstermitte
   sitzt – auch wenn rechts das 🔧 fehlt (Nicht-Admin) oder links ein breiterer
   Knopf steht. Mit space-between hing seine Position an den Textbreiten. */
.bottombar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.8rem calc(0.55rem + env(safe-area-inset-bottom));
}
.bar-side { display: flex; align-items: center; gap: 0.4rem; min-width: 0; }
.bar-right { justify-content: flex-end; }

/* Einloggen-Knopf mittig unten – einhändiges Spielen am Smartphone */
.commit-btn {
  background: var(--accent);
  color: #241c00;
  font-weight: 800;
  font-size: 1.05rem;
  padding: 0.75rem 1.6rem;
  border-radius: 999px;
  /* R37: Der Schein war noch das alte Bernstein (#FFD166) aus der Zeit, als das
     die Bedienfarbe war – ein goldener Schatten unter einem türkisen Knopf.
     Gold gehört seit R37 den COMBS; ein Knopf leuchtet in der Bedienfarbe. */
  box-shadow: 0 4px 16px rgba(47, 216, 208, 0.35);
}
.commit-btn:disabled { background: rgba(255,255,255,0.14); color: var(--text-dim); box-shadow: none; }
/* R37 – der Knopf darf die Seitenspalten nicht mehr auffressen. Im Training
   trägt die linke Seite ↺ + 💡 (im Auffüllen zusätzlich 📌), rechts stehen bis
   zu vier Knöpfe; die Mitte ist `auto` und wuchs bisher mit ihrer Beschriftung,
   bis der 💡 daneben klebte. Ein kürzeres Wort allein wäre keine Garantie –
   die nächste Sprache bringt das Problem sonst zurück. */
.commit-btn { max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Gemeinsame Kopfleiste von Spiel und Übersicht (R27). EINE Klasse, damit 🔊 und
   ☰ in beiden Oberflächen exakt gleich groß sind und an derselben Stelle sitzen:
   gleiche Polster, gleiche Mindesthöhe, gleiche Knopfgrößen. Raster 1fr auto 1fr
   statt space-between – nur so steht die Mitte (⬢ Punktestand bzw. ELOQUARIUM)
   wirklich mittig, unabhängig von den Breiten der Symbolgruppen. Beide Spalten
   (.game-wrap / .hub-wrap) sind auf 640 px begrenzt und zentriert, deshalb
   stimmen die Positionen auch auf breiten Desktops überein.
   Unverändert gilt: Die Leiste muss in JEDEM Zustand gleich hoch sein, sonst
   rutschen die Chips darunter (Lehre aus R11). */
.appbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.8rem;
  min-height: 3.25rem;
  background: var(--panel);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 10;
}
.appbar .bar-left { justify-self: start; }
.appbar .bar-right { justify-self: end; }
/* In der Übersicht ohne Fläche – und dann auch OHNE Kleben (R28): Eine
   durchsichtige Leiste, die oben stehen bleibt, ließe die Modus-Kacheln beim
   Scrollen sichtbar durch ⬡, ELOQUARIUM und ☰ hindurchwandern. Im Spiel wird
   nicht gescrollt, dort bleiben Fläche und sticky. Polster, Höhe und
   Knopfgrößen bleiben in BEIDEN gleich – nur so stehen 🔊 und ☰ weiter
   pixelgleich. */
.hub-head {
  background: none;
  backdrop-filter: none;
  position: static;
}
.topbar .stat { font-weight: 700; }
/* 🏆 ist ein Link, soll aber exakt wie die Symbolknöpfe aussehen und – wichtig
   für die konstante Leistenhöhe – exakt so hoch sein. */
.topbar a.icon-btn {
  display: inline-flex;
  align-items: center;
  color: inherit;
  text-decoration: none;
  line-height: 1;
}
/* ⬢ (Combs) und ⬡ (Weg nach draußen) sind TEXTzeichen und füllen ihre
   Schriftgröße nur zur Hälfte – neben den Emoji-Knöpfen wirkten sie zu klein.
   Beide stehen deshalb auf denselben 1,6rem wie das ↺ in der Fußzeile, und die
   line-height klammert die Zeilenhöhe, damit die Leiste nicht wächst (R26/R27). */
.topbar .score-mark {
  color: var(--gold);
  font-size: 1.6rem;
  line-height: 1.45rem;
  vertical-align: -0.18rem;
}
/* R43 – OPTISCHER Ausgleich, kein metrischer. NACHGEMESSEN (Tinte auf Canvas,
   nicht Textbox): Bei gleicher font-size zeichnen ⬡ (U+2B21) und ⬢ (U+2B22) exakt
   dieselbe Flaeche, 16 × 19 px. Die erste Vermutung „die Konturfassung ist
   kleiner" war damit falsch. Das ⬡ WIRKT trotzdem kleiner - gefuellte Flaechen
   wirken groesser als Konturen derselben Groesse (Irradiation), und das goldene
   ⬢ leuchtet zusaetzlich gegen den dunklen Grund. Deshalb hier eine bewusst
   KLEINE Korrektur von 6 %: genug, um den Eindruck auszugleichen, zu wenig, um
   messbar aus der Reihe zu fallen. Wer es exakt will, zeichnet beide Marken als
   SVG wie in R37 - das ist eine eigene Aufgabe. */
.hex-btn { font-size: 1.7rem; line-height: 1.45rem; color: var(--text); }

/* --- Unterseiten (Sammlung, Markt, Rangliste, …) --- */
.page-wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 0.8rem 0.8rem 2.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.page-head h1 { font-size: 1.25rem; }
.back-link { font-size: 0.9rem; white-space: nowrap; }

.tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.tabs button {
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  background: rgba(255,255,255,0.1);
  font-size: 0.9rem;
}
.tabs button.active { background: var(--accent); color: #241c00; font-weight: 700; }

.list { display: flex; flex-direction: column; gap: 0.5rem; }
.list-item {
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: var(--radius);
  padding: 0.7rem 0.85rem;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
}
.list-item .grow { flex: 1; min-width: 0; }
/* R31: Fett bedeutet jetzt ETWAS. Bis dahin standen ALLE Wörter auf 800, ein
   gefärbtes Wort unterschied sich nur im Ton – und Ton allein trägt bei
   RUBIN/MANDARIN/CITRIN/SMARAGD für Rot-Grün-Schwäche zu wenig. Die schlichten
   Wörter treten deshalb auf 600 zurück; die Liste wird insgesamt ruhiger und
   die Edelsteine stechen heraus. */
.word-chip {
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: 0.06em;
}
.word-chip.colored { font-weight: 800; }
.meta { font-size: 0.78rem; color: var(--text-dim); }
.badge {
  display: inline-block;
  padding: 0.05rem 0.5rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  background: rgba(255,255,255,0.12);
}
.price-tag { font-weight: 800; color: var(--accent); white-space: nowrap; }
.small-btn { padding: 0.35rem 0.75rem; font-size: 0.85rem; }
.empty-note { color: var(--text-dim); text-align: center; padding: 1.5rem 0; }

.lb-row { display: flex; align-items: center; gap: 0.7rem; }
.lb-pos { width: 2.2rem; text-align: right; font-weight: 800; color: var(--text-dim); }
.lb-row.top1 .lb-pos { color: gold; }
.lb-row.top2 .lb-pos { color: silver; }
.lb-row.top3 .lb-pos { color: #cd7f32; }
.period-nav { display: flex; align-items: center; gap: 0.5rem; justify-content: center; }
.period-nav .label { min-width: 11rem; text-align: center; font-weight: 600; font-size: 0.95rem; }

.form-row { display: flex; gap: 0.5rem; align-items: end; flex-wrap: wrap; }
.form-row .field { flex: 1; min-width: 130px; }

/* --- Modale --- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgba(8, 6, 12, 0.65);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
/* R29: JEDES Fenster kappt sich selbst. Vorher hatten nur der Werkzeugkasten und
   das Erfolge-Popup je eine eigene Kappung – das Statistik-Panel wuchs deshalb
   über den Bildschirm, und weil der Hintergrund mittig ausrichtet, ragte es oben
   UND unten hinaus. Als Regel an einer Stelle kann das nicht wiederkommen. */
.modal {
  width: min(380px, 100%);
  background: var(--panel-solid);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: var(--radius);
  padding: 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  box-shadow: 0 18px 50px rgba(0,0,0,0.55);
  max-height: 88vh;
  overflow-y: auto;
}
.modal h2 { font-size: 1.05rem; }
/* Titel und Schließen-Knopf bleiben beim Scrollen stehen – sonst muss man erst
   ans Listenende wischen, um das Fenster zuzumachen. `sticky` ist wirkungslos,
   solange nichts überläuft, kurze Fenster (Bestätigung, Joker) bleiben also
   unberührt.
   Zwei Schlagschatten in Panelfarbe je Element, weil ZWEI Streifen abzudecken
   sind: das Fensterpolster (1,2rem) nach außen und der Reihenabstand (0,8rem)
   nach innen. Ohne den zweiten scrollte eine Wortzeile sichtbar durch die Lücke
   direkt unter der Überschrift. Die Schatten liegen im Stapelkontext des
   klebenden Elements (z-index 2) und damit über dem laufenden Inhalt. */
.modal > h2 {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--panel-solid);
  box-shadow: 0 -1.2rem 0 var(--panel-solid), 0 0.8rem 0 var(--panel-solid);
}
.modal > button[data-close-modal] {
  position: sticky;
  bottom: 0;
  z-index: 2;
  box-shadow: 0 1.2rem 0 var(--panel-solid), 0 -0.8rem 0 var(--panel-solid);
}
/* Der volle Werkzeugkasten im Spiel ist hoch – scrollbar halten, damit er auf
   das Handy passt. Die Kopfzeile mit den Werten bleibt oben stehen. */
/* Erfolge-Popup (R25): dieselbe Lösung wie beim Werkzeugkasten – acht
   Kategorien passen nicht auf ein Handy, also scrollt das Fenster selbst. Etwas
   breiter, weil in jeder Zeile vier Medaillen rechts stehen. Kappung und
   Scrollen stehen seit R29 in .modal. */
.trophies-modal {
  width: min(480px, 100%);
  gap: 0.6rem;
}
.trophies-modal .list { gap: 0.3rem; }

.admin-panel-modal {
  width: min(440px, 100%);
  gap: 0.4rem;
}
.admin-panel-modal .stats-head { margin-top: 0.3rem; }
.admin-panel-modal .tool-row { margin: 0; }

.setting-row {
  display: grid;
  grid-template-columns: 4.5rem 2.4rem 1fr;
  align-items: center;
  gap: 0.6rem;
}
.setting-row label { font-size: 0.9rem; color: var(--text-dim); }
.mute-btn { padding: 0.25rem 0.4rem; font-size: 0.95rem; background: rgba(255,255,255,0.1); }
/* .off ist der Schalter für Einstellungen ohne Regler (Wischen, R32) – gleiche
   Optik wie „stumm", weil es dieselbe Aussage ist: dieser Weg ist zu. */
.mute-btn.muted, .mute-btn.off { background: rgba(255,107,107,0.3); }
.mute-btn.off { opacity: 0.6; }
.setting-note { font-size: 0.78rem; color: var(--text-dim); }
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: linear-gradient(to right, var(--accent), var(--accent)) no-repeat #3a3450;
  background-size: var(--fill, 100%) 100%;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid #241c00;
  cursor: pointer;
}

.joker-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0.35rem;
}
.joker-grid button {
  padding: 0.5rem 0;
  font-weight: 800;
  font-size: 1rem;
  background: rgba(255,255,255,0.12);
}
/* Kombi-Bereich: breitere Knöpfe für 2–3 Zeichen, optisch abgesetzt */
.joker-grid.joker-combos {
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid rgba(255,255,255,0.12);
  padding-top: 0.5rem;
}
.joker-grid.joker-combos button { font-size: 0.9rem; }

/* Modal-Aufwärmphase: verhindert Ghost-Clicks (Tipp öffnet Modal, der
   nachfolgende click darf nicht sofort einen Knopf treffen) */
.modal-backdrop.warming button { pointer-events: none; }
.joker-grid .animal-btn { font-size: 1.6rem; padding: 0.4rem 0; }

/* --- Effekt-Ebenen --- */
#flash-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: 0;
}
#fx-layer {
  position: fixed;
  inset: 0;
  z-index: 70;
  pointer-events: none;
  overflow: hidden;
}
/* Nur für die Effekt-Probe aus dem Einstellungsfenster (R25): Effekt- und
   Blitz-Ebene steigen über die Modale (95), damit man sieht, was man einstellt.
   Befristet – testCelebration nimmt die Klasse nach der Feier wieder weg, sonst
   überdeckten Feuerwerk und Trophäen-Feiern künftig jeden echten Dialog. */
body.fx-front #fx-layer { z-index: 97; }
body.fx-front #flash-overlay { z-index: 96; }
.wletter-clone {
  position: fixed;
  font-size: 1.7rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--accent);
  transition: transform 0.7s cubic-bezier(0.2, 0.6, 0.4, 1), opacity 0.7s ease-out;
  will-change: transform, opacity;
}
.score-float {
  position: fixed;
  transform: translateX(-50%);
  font-weight: 900;
  color: var(--gold);
  text-shadow: 0 2px 12px rgba(0,0,0,0.5);
  animation: floatUp 1.3s ease-out forwards;
  white-space: nowrap;
}
@keyframes floatUp {
  0% { opacity: 0; margin-top: 0; }
  15% { opacity: 1; }
  100% { opacity: 0; margin-top: -90px; }
}

/* Das Zählwerk (R44, Kapitel 4 „Balatro"): Die Rechnung läuft nach dem
   Einloggen Posten für Posten sichtbar durch, statt als fertige Zahl zu
   erscheinen. Steht an derselben Stelle wie .score-float, damit der Blick
   nicht wandert – die Zahl, die am Ende hochschwebt, kommt genau dort heraus,
   wo die Kette aufgehört hat. */
.zaehlwerk {
  position: fixed;
  transform: translateX(-50%);
  font-weight: 900;
  font-size: 1.5rem;
  color: var(--text);
  text-shadow: 0 2px 12px rgba(0,0,0,0.55);
  white-space: nowrap;
  pointer-events: none;
}
/* Der Schlussposten ist das Ergebnis der Kette – golden wie der Punktestand
   in der Kopfzeile und eine Spur größer. */
.zaehlwerk.summe { color: var(--gold); font-size: 2rem; }
/* Ein Posten „schlägt ein". 160 ms, also klar unter der 250-ms-Grenze für
   blockierende Bewegung aus Kapitel 6 – und sie blockiert ohnehin nichts. */
/* DIE NAHT (R46, Tor 6). Das Brett verglüht: Es verliert Sättigung und Licht,
   während eingefahren wird – „die Blüte verglüht, die Saat bleibt in der
   Asche". Bewusst am Brettkasten, nicht am Körper: Kopfzeile und Punktestand
   bleiben lesbar, es wird nichts zugedeckt.

   NACHGEMESSEN UND SO GEWOLLT: Der Weg HINEIN blendet über eine halbe Sekunde
   (0 ms → 250 ms → saturate 0.37, 650 ms → 0.25). Der Weg HERAUS springt
   dagegen: Von einer Filterliste auf `none` interpoliert der Browser nicht,
   die Helligkeit ist im nächsten Frame wieder voll da.

   Das bleibt so, weil es genau auf den richtigen Takt fällt: Das Aufhellen
   passiert bei 2000 ms, gleichzeitig mit dem Licht in der neuen Rangfarbe
   (NAHT_PLAN.licht). Ein langsames Zurückblenden würde diesen Schlag
   verschmieren – die neue Generation soll ANKOMMEN, nicht verblassen.

   Der Grundzustand bleibt `filter: none` und nicht `saturate(1)`: Ein
   dauerhaft gesetzter Filter zwingt das Brett in eine eigene Compositing-Ebene,
   und das kostet auf dem Handy in JEDEM Zug etwas – für einen Übergang, den man
   alle 85 Wörter einmal sieht. */
.board-container { transition: filter 0.5s ease; }
.board-container.naht-verglueht { filter: saturate(0.25) brightness(0.55); }

/* Die Auszahlung an der Naht. Gleiche Bahn wie der Punkte-Aufstieg, aber
   langsamer und größer: Münzen gibt es sonst nie zu sehen, und dies ist der
   einzige Moment, in dem das Spiel welche ausschüttet. */
.muenz-float {
  font-size: 2.4rem;
  animation: floatUp 2.1s ease-out forwards;
}

/* R47 – DIE AUSZAHLUNG ALS BEWEGUNG (Kapitel 4, Candy Crush: „jede Stufe hat
   ihr eigenes Bild"). Bis R46 erschien an der Naht eine Zahl aus dem Nichts.
   Jetzt steigen die eingefahrenen Früchte einzeln vom Brett auf (gezeichnet
   auf dem Canvas, siehe render.js drawErnteFlug) und werden hier gezählt.

   Der mitlaufende Münzstand sitzt am oberen Brettrand, also GENAU DORT, wo die
   Früchte ankommen – der Blick muss nicht wandern. Kleiner als die
   Punkte-Summe: Er läuft, während noch etwas fliegt, und darf das Brett nicht
   zudecken. */
.muenz-zaehler { font-size: 1.6rem; }

/* Der letzte Schlag der Kaskade: Die Summe verlässt das Brett Richtung ☰ –
   dort steht der Münzstand von jetzt an. Ohne diesen Puls endete die Bewegung
   im Nichts, und die Frage „wo sind die Münzen hin?" bliebe offen.
   Bewusst OHNE `transform`: ein Leuchten, kein Hüpfen. Ein Knopf, der springt,
   verrutscht unter dem Finger, der ihn gerade treffen will. */
.icon-btn.muenz-puls {
  animation: muenzPuls 0.9s ease-out;
}
@keyframes muenzPuls {
  0%   { box-shadow: 0 0 0 0 rgba(243, 206, 62, 0); color: inherit; }
  25%  { box-shadow: 0 0 14px 4px rgba(243, 206, 62, 0.75); color: var(--gold); }
  100% { box-shadow: 0 0 0 0 rgba(243, 206, 62, 0); color: inherit; }
}

.zaehlwerk.pop { animation: zaehlPop 0.16s ease-out; }
@keyframes zaehlPop {
  0% { transform: translateX(-50%) scale(1.28); }
  60% { transform: translateX(-50%) scale(0.97); }
  100% { transform: translateX(-50%) scale(1); }
}
.shake-hard { animation: shakeHard 0.5s; }
@keyframes shakeHard {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-6px, 3px); }
  40% { transform: translate(5px, -4px); }
  60% { transform: translate(-4px, -2px); }
  80% { transform: translate(3px, 3px); }
}
/* `.wletter.bridge` ist mit R37 entfallen: Leere Joker stehen gar nicht mehr in
   der Wortleiste (siehe updateWordBar), es gibt also nichts mehr zu dämpfen. */
/* R25: angefangener Mehrbuchstaben-Chip. Der Rest steht blass und gestrichelt
   unterstrichen da – sichtbar getippt, aber noch nicht auf dem Brett. */
.wletter.pending {
  opacity: 0.45;
  text-decoration: underline dashed;
  text-underline-offset: 0.18em;
}

/* --- Spielen-Hub --- */
/* Seit R27 trägt nicht mehr die Spalte das Polster, sondern .hub-body: Die
   Kopfleiste soll exakt so breit und so hoch sein wie die im Spiel, und dort
   sitzt sie ohne umgebendes Polster am oberen Rand der Spalte. */
.hub-wrap {
  max-width: 640px;
  margin: 0 auto;
  padding: 0 0 2.5rem;
  min-height: 100dvh;
  /* Bezugsrahmen fürs Menü-Popup – dieselbe Ursache wie im Spiel (R19): ohne
     das misst das absolut positionierte Dropdown von der FENSTERkante und klebt
     auf breiten Desktops ganz links, weit weg vom ☰. */
  position: relative;
}
/* Kein Sonderweg mehr für das Hub-Menü (R27): Beide Spalten sind gleich breit
   und die Leisten gleich hoch, also gilt die Grundregel (.menu-dropdown) hier
   wie im Spiel – gleicher Abstand zur Kante, gleicher Abstand nach unten.
   .hub-body trägt das Innenpolster, das vorher an .hub-wrap hing. */
.hub-body { padding: 0.8rem 0.9rem 0; }
/* padding-left gleicht den Sperrsatz aus: letter-spacing setzt auch HINTER den
   letzten Buchstaben 0,2em, die Schrift stünde sonst 0,1em links der Mitte. */
.logo-sm { font-size: 1.4rem; font-weight: 800; letter-spacing: 0.2em; text-align: center; padding-left: 0.2em; }
/* Begrüßung und Meldungszeile gehören optisch zum mittigen Logo darüber. */
.hub-greeting { margin: 0.6rem 0 0.2rem; color: var(--text-dim); font-size: 0.95rem; text-align: center; }
.hub-body > .msg { text-align: center; }
.resume-banner {
  width: 100%; margin: 0.6rem 0; padding: 0.75rem;
  background: var(--accent); color: #241c00; font-weight: 800; border-radius: var(--radius);
}
.mode-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.7rem;
  margin-top: 0.8rem;
}
.mode-tile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.2rem;
  padding: 1rem; min-height: 6.5rem;
  background: var(--panel); border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius); text-align: left;
}
.mode-tile:active { transform: scale(0.98); }
.mode-tile.disabled { opacity: 0.45; }
.mode-emoji { font-size: 1.9rem; }
.mode-name { font-weight: 800; font-size: 1.05rem; }
.mode-desc { font-size: 0.78rem; color: var(--text-dim); }

.versus-panel {
  margin-top: 1rem; background: var(--panel); border-radius: var(--radius);
  padding: 1rem; display: flex; flex-direction: column; gap: 0.7rem;
}
.versus-panel h2 { font-size: 1.1rem; }
.code-box { display: flex; align-items: center; gap: 0.6rem; justify-content: center; }
.code-label { color: var(--text-dim); }
.code-value { font-size: 1.8rem; font-weight: 900; letter-spacing: 0.3em; color: var(--accent); }

/* --- Match-HUD --- */
.match-hud {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.4rem 0.7rem; background: var(--panel); position: sticky; top: 0; z-index: 8;
}
.match-timer { display: flex; flex-direction: column; min-width: 3.4rem; }
#match-clock { font-weight: 800; font-size: 1rem; }
.timer-bar { height: 4px; border-radius: 2px; background: #3a3450; overflow: hidden; }
#timer-fill { height: 100%; width: 100%; background: var(--accent); transition: width 0.25s linear; }
#timer-fill.low { background: var(--danger); }
.match-scores { flex: 1; display: flex; gap: 0.35rem; overflow-x: auto; }
.score-chip {
  white-space: nowrap; padding: 0.2rem 0.55rem; border-radius: 999px;
  background: rgba(255,255,255,0.1); font-size: 0.82rem; font-weight: 700;
}
.score-chip.me { background: var(--accent); color: #241c00; }
.score-chip.out { opacity: 0.45; text-decoration: line-through; }
.countdown-num.reveal-text { font-size: 2.2rem; text-align: center; padding: 0 1rem; }

/* --- Vollbild-Overlays (Countdown, Ergebnis) --- */
.overlay-full {
  position: fixed; inset: 0; z-index: 95;
  background: rgba(8, 6, 12, 0.85); backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center; padding: 1rem;
}
.countdown-num {
  font-size: 8rem; font-weight: 900; color: var(--accent);
  animation: cd-pop 1s ease-out infinite;
}
@keyframes cd-pop { 0% { transform: scale(0.5); opacity: 0.3; } 40% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1); opacity: 0.85; } }
.results-card {
  width: min(440px, 100%); background: var(--panel-solid);
  border: 1px solid rgba(255,255,255,0.12); border-radius: var(--radius);
  padding: 1.3rem; display: flex; flex-direction: column; gap: 0.8rem;
}
.results-list { display: flex; flex-direction: column; gap: 0.4rem; }
.results-reward { text-align: center; font-weight: 800; font-size: 1.1rem; color: var(--accent); min-height: 1.2em; }
.results-actions { display: flex; gap: 0.6rem; }
.results-actions button { flex: 1; }

.checklist-list { display: flex; flex-direction: column; gap: 0.3rem; max-height: 55vh; overflow-y: auto; }
.check-row { display: flex; gap: 0.5rem; font-size: 0.9rem; color: var(--text-dim); }
.check-row.done { color: var(--text); font-weight: 600; }

/* --- Trophäen / Wochen-Challenge --- */
.weekly-card {
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 22%, var(--panel-solid)), var(--panel-solid));
  border: 1px solid rgba(255,209,102,0.3);
  border-radius: var(--radius);
  padding: 1rem;
  display: flex; flex-direction: column; gap: 0.6rem;
}
.weekly-head { display: flex; align-items: center; gap: 0.7rem; }
.weekly-emoji { font-size: 1.8rem; }
.weekly-label { font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; }
.weekly-text { font-weight: 800; font-size: 1.05rem; }
.weekly-bar { height: 8px; border-radius: 999px; background: #3a3450; overflow: hidden; }
#weekly-fill { height: 100%; width: 0; background: var(--accent); transition: width 0.4s ease; }
.weekly-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }

.trophy-row { display: flex; align-items: center; gap: 0.7rem; }
.trophy-row.locked { opacity: 0.55; }
.trophy-emoji { font-size: 1.5rem; width: 1.9rem; text-align: center; }
.medals { display: flex; gap: 0.15rem; }
.medal { font-size: 1.1rem; filter: grayscale(1) opacity(0.35); }
.medal.on { filter: none; }

/* --- R24: Kategorien (66 Leitern) --------------------------------------
   Zugeklappt sind es acht Karten statt 66 Zeilen – ausgeklappt sieht man
   alles. Beides erreichbar, ohne die Seite auf dem Handy meterlang zu machen. */
.cat-tools { display: flex; justify-content: flex-end; }
.cat-box {
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius);
  overflow: hidden;
}
.cat-head {
  display: flex; align-items: center; gap: 0.7rem;
  width: 100%; text-align: left; background: none; border-radius: 0;
  padding: 0.7rem 0.9rem;
}
.cat-head .grow { min-width: 0; }
.cat-arrow { color: var(--text-dim); font-size: 1.1rem; }
.cat-bar {
  height: 4px; border-radius: 999px; background: rgba(255,255,255,0.12);
  margin-top: 0.35rem; overflow: hidden;
}
.cat-bar > div { height: 100%; background: var(--accent); transition: width 300ms ease; }
.cat-body { border-top: 1px solid rgba(255,255,255,0.08); }
/* Die Leitern sitzen INNERHALB der Karte – dort kein eigener Rahmen, sonst
   wird aus einer Karte eine Schachtel voller Schachteln. */
.cat-body .ladder-row {
  background: none; border: none; border-radius: 0;
  border-bottom: 1px solid rgba(255,255,255,0.05);
}
.cat-body .ladder-row:last-child { border-bottom: none; }

/* Gesamtauszeichnung – dieselbe, die im Mehrspieler hinterm Namen steht. */
.honor-card {
  display: flex; align-items: center; gap: 0.8rem;
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
}
.honor-mark { font-size: 1.8rem; width: 2.2rem; text-align: center; }
/* Auszeichnung neben einem Spielernamen (Rangliste, Markt, Match-HUD). */
.honor-badge { margin-left: 0.25rem; }

/* --- Trophäen-Toast (im Spiel) --- */
.trophy-toasts {
  position: fixed; top: 3.4rem; left: 50%; transform: translateX(-50%);
  z-index: 96; display: flex; flex-direction: column; gap: 0.4rem; align-items: center;
  pointer-events: none; width: max-content; max-width: 92vw;
}
.trophy-toast {
  background: var(--panel-solid); border: 1px solid rgba(255,209,102,0.5);
  color: var(--accent); font-weight: 800; padding: 0.5rem 1rem; border-radius: 999px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.5);
  opacity: 0; transform: translateY(-12px); transition: opacity 0.4s, transform 0.4s;
}
.trophy-toast.show { opacity: 1; transform: translateY(0); }

/* --- Runde 10: Bestätigungsdialog, Statistik, Tastatur, Neustart --- */

/* Punktestand ist antippbar (Statistik) */
.stat-btn {
  background: none;
  border: none;
  padding: 0.1rem 0.3rem;
  font: inherit;
  color: inherit;
  cursor: pointer;
  border-radius: 8px;
}
.stat-btn:hover { background: rgba(255,255,255,0.09); }

/* Zeilenlisten in Bestätigung und Statistik */
.confirm-rows, .stats-rows {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  background: rgba(255,255,255,0.05);
  border-radius: 10px;
  padding: 0.5rem 0.65rem;
}
.confirm-row, .stats-row {
  display: flex;
  justify-content: space-between;
  gap: 0.8rem;
  font-size: 0.92rem;
}
.confirm-row span, .stats-row span { color: var(--text-dim); }
.confirm-row strong, .stats-row strong { text-align: right; }

/* Wochen-Wort-Set auf dem Marktplatz. */
.wordset-card { display: flex; flex-direction: column; gap: 0.6rem; }
.wordset-head { display: flex; align-items: center; justify-content: space-between; }
.wordset-head h2 { font-size: 1rem; }
.wordset-count { font-weight: 800; color: var(--text-dim); }
.wordset-words { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.wordset-word {
  width: auto; margin: 0; padding: 0.3rem 0.7rem;
  border-radius: 999px; font-weight: 800; letter-spacing: 0.04em;
  border: 1px solid transparent;
}
.wordset-word.owned {
  background: rgba(120, 200, 140, 0.22);
  color: #cdeccf; border-color: rgba(120, 200, 140, 0.5);
  cursor: default;
}
.wordset-word.missing {
  background: rgba(255,255,255,0.06);
  color: var(--text); border-color: rgba(255,255,255,0.25);
}

/* Strukturelle Grundstock-Sets (sets.html) */
.set-card { margin-bottom: 0.9rem; }
.set-card.complete { border-color: rgba(120, 200, 140, 0.6); }
.set-head { display: flex; align-items: center; gap: 0.6rem; }
.set-toggle {
  display: flex; align-items: center; gap: 0.6rem;
  background: none; border: none; padding: 0; margin: 0;
  color: var(--text); cursor: pointer; text-align: left; font: inherit;
}
.set-name { font-weight: 800; font-size: 1.05rem; }
.set-count { color: var(--muted); font-weight: 700; }
.set-bar {
  height: 8px; border-radius: 999px; background: #3a3450;
  overflow: hidden; margin: 0.55rem 0;
}
.set-fill { height: 100%; width: 0; background: var(--accent); transition: width 0.4s ease; }
.set-slots { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.5rem 0; }
.set-slot {
  padding: 0.25rem 0.6rem; border-radius: 999px;
  font-weight: 700; font-size: 0.85rem; border: 1px solid transparent;
}
.set-slot.owned {
  background: rgba(120, 200, 140, 0.22);
  color: #cdeccf; border-color: rgba(120, 200, 140, 0.5);
}
.set-slot.missing {
  background: rgba(255,255,255,0.06);
  color: var(--muted); border-color: rgba(255,255,255,0.2);
}
.set-foot { display: flex; justify-content: flex-end; min-height: 1.6rem; }

/* Wortliste des Laufs. R29: KEINE eigene Bildlaufzone mehr (war max-height 32vh).
   Zwei ineinanderliegende Scrollflächen kämpfen um denselben Wisch – die innere
   fing ihn ab, während Kopf und Fuß des Fensters aus dem Bild ragten. Gekappt
   wird jetzt das Fenster selbst (.modal), hier fließt die Liste einfach mit. */
.stats-words {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin-top: 0.4rem;
}
.stats-words:empty { display: none; }
.stats-word {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9rem;
  padding: 0.15rem 0.2rem;
}
.stats-word .n { color: var(--text-dim); min-width: 1.6rem; text-align: right; }
.stats-word .w { font-weight: 700; letter-spacing: 0.04em; flex: 1; }
.stats-word .p { font-weight: 800; }
.stats-word .badge { font-size: 0.7rem; padding: 0.05rem 0.4rem; }

/* Admin-Werkzeugkasten: Knopfreihen, die auf dem Handy umbrechen. */
.tool-row {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 0.5rem;
  margin: 0.4rem 0 0.2rem;
}
.tool-row button { flex: 0 0 auto; width: auto; margin: 0; }
.tool-row label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  font-size: 0.78rem;
  color: var(--text-dim);
}
.tool-row input[type="number"], .tool-row select { width: 8rem; margin: 0; }
.tool-row label:has(input[type="checkbox"]) { flex-direction: row; align-items: center; }
/* Sprach-Haken an einer Wortanfrage. */
.lang-row { display: flex; gap: 0.8rem; margin-top: 0.35rem; }
.lang-check { display: flex; align-items: center; gap: 0.25rem; font-size: 0.82rem; color: var(--text-dim); }
.lang-check input { width: auto; margin: 0; }
#word-add-input { width: 12rem; }

.tool-state {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: rgba(255,255,255,0.05);
  border-radius: 10px;
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.6rem;
}
#pane-tools .meta { margin: 0.1rem 0 0.6rem; }
#pane-tools code {
  background: rgba(255,255,255,0.1);
  padding: 0 0.25rem;
  border-radius: 4px;
}

.stats-head {
  font-size: 0.82rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  margin-top: 0.2rem;
}
.confirm-actions { display: flex; gap: 0.6rem; }
.confirm-actions button { flex: 1; }
button.danger { background: #d9534f; color: #fff; }

/* Joker-Popup: aktive (per Tastatur markierte) Option + Filteranzeige.
   Türkis wie die Markierung am Brett (R32) – dieselbe Rolle, dieselbe Farbe. */
.joker-grid button.marked {
  outline: 3px solid var(--accent);
  outline-offset: -3px;
  background: rgba(47, 216, 208, 0.22);
}
.joker-typed {
  font-size: 0.85rem;
  color: var(--accent);
  letter-spacing: 0.08em;
}

/* Neustart-Knopf im Zeitrennen mit Restzähler */
#restart-btn { position: relative; }
.restart-left {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 1.05rem;
  padding: 0 0.18rem;
  border-radius: 999px;
  background: var(--accent);
  color: #1c1524;
  font-size: 0.62rem;
  font-weight: 800;
  line-height: 1.05rem;
}


/* --- Runde 11: geplante Joker-Buchstaben in der Wortleiste --- */
.wletter.joker-planned {
  color: var(--accent);
  text-decoration: underline dotted;
  text-underline-offset: 0.18em;
}

.topbar > * { transition: margin 180ms ease, opacity 180ms ease; }

/* ↺ unten links (R25). Er steht dauerhaft da und ist ausgegraut, wenn nichts
   offen ist – ein Knopf, der auftaucht und verschwindet, verschiebt sonst bei
   jedem Zug die Fußzeile. Ausgeblendet wird er nur im Match. */
.undo-btn[hidden] { display: none; }
/* ↺ ist ein Textzeichen (U+21BA) und füllt seine Schriftgröße nur zur Hälfte –
   neben den Emoji-Knöpfen (🎲 🔧 📌) wirkte er deutlich zu klein, obwohl er
   formal gleich groß war. Die line-height ist so gewählt, dass der Knopf exakt
   so hoch bleibt wie 🎲 und 🔧 (36 px) – die Fußzeile behält ihre Höhe, das
   Tippziel wird nur um die vier Pixel breiter, die das größere Zeichen braucht. */
.undo-btn { font-size: 1.6rem; line-height: 1.45rem; }

/* 📌 Pin-Knopf (R22). Seit R27 steht er unten in der Fußzeile rechts neben dem ↺
   – spiegelbildlich zum 🔧 und damit im Daumenbereich fürs einhändige Spielen.
   Auftauchen und Verschwinden (nur Auffüllen) darf die Fußzeilenhöhe nicht
   verändern, und der Einloggen-Knopf bleibt durch das Raster 1fr auto 1fr in der
   Mitte, egal ob die Nadel da ist. Seit R25 zeigt der aktive Zustand keinen gefüllten
   Hintergrund mehr (alle Symbolknöpfe sind flächenlos), sondern gelbes Symbol
   plus Leuchtring – Form UND Farbe, damit er nicht nur an der Farbe hängt. */
.pin-btn[hidden] { display: none; }
.pin-btn.active {
  color: var(--accent);
  text-shadow: 0 0 8px rgba(47, 216, 208, 0.9);
  box-shadow: 0 0 0 2px rgba(47, 216, 208, 0.85) inset;
  border-radius: 999px;
}
/* Im Pin-Modus baut kein Tipp mehr ein Wort – das soll man dem Brett ansehen. */
body.pin-mode #board-container { outline: 2px dashed rgba(255, 209, 102, 0.55); outline-offset: 3px; }

/* Schmale Geräte: Die Sparmaßnahmen aus R23–R26 sind mit R27 ERSATZLOS weg –
   das 🏆-Verstecken unter 340 px, das Ausweichen des Tauschguthabens und die
   kleineren Symbolknöpfe unter 400 px. Grund: Rang, Fortschrittsbalken,
   Tauschguthaben und 📌 sind aus der Kopfzeile ausgewandert (Reiter an der
   Wortleiste, schwebende Zeile über dem Brett, Fußzeile). Übrig sind fünf
   Elemente, die auch auf 320 px bequem passen – und ein einziger Satz
   Knopfgrößen für alle Breiten ist die Voraussetzung dafür, dass 🔊 und ☰ in
   Spiel und Übersicht wirklich gleich groß sind.
   Der Punktestand darf trotzdem nie umbrechen: Er ist das einzige Element mit
   veränderlicher Breite. */
.topbar .stat-btn { white-space: nowrap; }

/* --- R21: Lautsprecher-Knopf ---------------------------------------------
   Zustand doppelt codiert – Symbol UND Farbe. Nur Farbe wäre für Rot-Grün-
   Blindheit unbrauchbar, nur das Symbol auf einen Blick zu klein. */
.sound-btn { transition: color 140ms ease, background 140ms ease; }
.sound-btn.on { color: var(--accent); }
.sound-btn.off {
  color: var(--danger);
  background: rgba(195, 59, 76, 0.22);
}

/* --- R21: Songliste im Einstellungsmenü ----------------------------------
   Acht Stücke plus Zufall und Aus passen nicht mehr in eine Knopfreihe. */
.track-list {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  max-height: 15rem;
  overflow-y: auto;
  padding: 0.2rem;
  border-radius: 0.6rem;
  background: rgba(0,0,0,0.18);
}
.track-item {
  display: grid;
  grid-template-columns: 1.2rem 1fr;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.5rem;
  border-radius: 0.45rem;
  background: transparent;
  font-size: 0.92rem;
  text-align: left;
}
.track-item .track-check { opacity: 0; color: var(--accent); font-weight: 800; }
.track-item.active { background: rgba(255,255,255,0.1); font-weight: 700; }
.track-item.active .track-check { opacity: 1; }

/* Probe-Knöpfe neben Sound- und Effekte-Regler. */
.setting-row:has(.test-btn) { grid-template-columns: 4.5rem 2.4rem 1fr auto; }
.test-btn {
  padding: 0.25rem 0.5rem;
  font-size: 0.78rem;
  white-space: nowrap;
  background: rgba(255,255,255,0.1);
}
.test-btn[hidden] { display: none; }

/* --- Runde 12: Rang-Seltenheitsliste --- */
.rank-info { width: min(340px, 100%); }
.rank-rows { display: flex; flex-direction: column; gap: 0.3rem; }
.rank-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.3rem 0.5rem;
  border-radius: 8px;
  font-size: 0.92rem;
}
.rank-row.here { background: rgba(255,255,255,0.12); font-weight: 700; }
.rank-dot { width: 0.95rem; height: 0.95rem; border-radius: 999px; flex: none; }
.rank-name.grow { flex: 1; }
.rank-meta { color: var(--text-dim); font-size: 0.82rem; }
.rank-tip { cursor: pointer; }
.medal { cursor: pointer; }

/* --- Reiter und Beschriftungen der Punktrechnung (R28b) ---------------------
   Zeile 0 sind die Reiter (nur ZAHLEN), Zeile 1 die Beschriftungen (die NAMEN).
   Beide liegen im selben Raster (.word-block), stehen also spaltengenau
   übereinander. Die Reiter sitzen spältchenlos auf der schwarzen Fläche. */
.mult-tab {
  grid-row: 1;
  /* Nur so breit wie ihr Inhalt und mittig in der Spalte (R28c): Gestreckte
     Reiter füllten ihre ganze Spalte und stießen mit 4 px Abstand aneinander –
     das wirkte gedrungen. Die Luft kommt jetzt aus der Spaltenbreite, die
     ohnehin von den längeren Beschriftungen bestimmt wird; weil Reiter UND
     Beschriftung mittig in derselben Spalte sitzen, bleiben sie exakt
     übereinander. Kostet keine Breite. */
  justify-self: center;
  min-width: 1.7rem;
  align-self: end;
  text-align: center;
  padding: 0.1rem 0.45rem;
  border-radius: 8px 8px 0 0;
  background: rgba(255,255,255,0.88);
  color: #1c1524;
  font-weight: 800;
  font-size: 0.74rem;
  letter-spacing: 0.02em;
  line-height: 1.15rem;
  white-space: nowrap;
}
.mult-tab[hidden] { display: none; }
/* Der Faktor ist das Ergebnis der Kette – fett und eine Spur größer. */
.tab-sum { font-size: 0.85rem; font-weight: 900; }
/* Das „=" ist Zeichensetzung, kein Reiter: keine Fläche, gedämpft. */
.tab-eq {
  grid-row: 1;
  align-self: end;
  text-align: center;
  color: var(--text-dim);
  font-weight: 800;
  font-size: 0.8rem;
  line-height: 1.15rem;
}
/* Beschriftungen in Zeile 1, IM Feld. Jede trägt die Farbe ihrer Sache; BASIS
   und FAKTOR sind Struktur und stehen deshalb gedämpft da. */
.mlabel {
  grid-row: 2;
  justify-self: stretch;
  align-self: center;
  text-align: center;
  /* Seitenpolster als Variable, weil der Fortschrittsbalken darunter denselben
     Rand einhalten muss (R33). Vorher stand er starr auf 0,45 rem, während die
     Polsterung in den Media-Queries auf 0,2 bzw. 0,12 rem schrumpfte – auf
     schmalen Geräten war der Balken damit unnötig kurz. */
  --mlabel-pad: 0.45rem;
  padding: 0.12rem var(--mlabel-pad);
  font-size: 0.65rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  line-height: 1rem;
  white-space: nowrap;
}
.mlabel[hidden] { display: none; }
.mlabel-dim { color: var(--text-dim); }
/* Die Fruchtpunkte sind das einzige Zeichen der Leiste, das FLÄCHE tragen muss –
   ein ● in Beschriftungsgröße ist bei 0,65 rem ein Krümel, während ⬣ und die
   Rangnamen aus Strichen bestehen und in dieser Größe lesbar bleiben (R37,
   Nutzerbefund „viel zu klein"). Die `line-height` bleibt bei 1 rem: Das
   Zeilenraster darf NICHT mitwachsen, sonst rutscht das Brett (R11). Der Punkt
   ragt über seine Zeilenbox hinaus, und genau das ist beabsichtigt.
   Farbe wird inline gesetzt (fruitColor); Gold steht nur da, falls nicht. */
/* Die Fruchtspalte trägt seit R37 gezeichnete Kreise (.fruit-dot). Der
   Durchmesser ist an der TINTENHÖHE des ⬣ in der Nachbarspalte ausgerichtet
   (gemessen 7 px bei 10,4 px Schrift) und eine Spur größer, weil eine gefüllte
   Fläche kleiner wirkt als ein Umriss derselben Höhe. `line-height` bleibt bei
   1 rem: Das Zeilenraster darf nicht wachsen, sonst rutscht das Brett (R11). */
/* Die Fruchtspalte trägt gezeichnete Kreise (.mark-fruit). Die Ausrichtung
   erledigt der Markenkasten selbst (Versalhöhe, siehe .mark); hier steht nur die
   Größe. `line-height` bleibt bei 1 rem – das Zeilenraster darf nicht wachsen,
   sonst rutscht das Brett (R11). */
.mlabel-symbol { color: #F3CE3E; line-height: 1rem; }
/* FARBREIN (R30): Der Reiter trägt die Edelsteinfarbe (inline gesetzt), die
   Beschriftung die Rangfarbe – sie sind derselbe Ton, und genau das IST die
   Regel. Ein zusätzlicher Rahmen wäre Deko; der doppelte Farbklang reicht. */
.mlabel-suited { color: var(--rank-color); }
/* Unter dem Rangnamen läuft der Fortschritt zur nächsten Stufe als dünner
   Balken – dieselbe Form wie früher in der Kopfzeile (R28c). Vorher war es eine
   Füllung HINTER dem Namen; als Balken ist der Füllstand genauer ablesbar und
   der Name steht ungestört in voller Rangfarbe.
   Der Balken hängt 4 px unter der Zeile im Spalt zur Wortzeile (die ihr Wort
   mittig führt und dort Luft hat) – dadurch kostet er KEINE Bretthöhe. */
.mlabel-rank {
  position: relative;
  border-radius: 6px;
  color: var(--rank-color);
  cursor: pointer;
  /* Mindestbreite der Rangspalte (R33). Die Spalte ist inhaltsbreit – bei KLEE
     oder MOHN blieb vom Fortschrittsbalken kaum etwas übrig, bei FLIEDER war er
     halb so lang wieder da. Der Wert ist am DOM gemessen (Breite des längsten
     Rangnamens), nicht geschätzt, und die Kette passt damit noch auf 320 px. */
  min-width: 4.4rem;
}
.rank-track {
  position: absolute;
  left: var(--mlabel-pad);
  right: var(--mlabel-pad);
  bottom: -4px;
  height: 3px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  overflow: hidden;
}
#rank-fill {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--rank-color);
  transition: width 320ms ease;
}
/* Namenloser Rang: Die Spalte behält ihre Höhe. */
#rank-badge:empty { display: inline-block; min-height: 1rem; }

/* Schmale Geräte. Maßgeblich ist der schlimmste Fall, nicht der übliche:
   BASIS · AMETHYST · FARBREIN · FLIEDER · 💎💎💎 · = · FAKTOR mit den breitesten
   Zahlen. Gespart wird an Polster und Schriftgröße der BESCHRIFTUNGEN – die
   Namen bleiben damit alle lesbar, statt dass einer wegfällt oder abgeschnitten
   wird.
   R30: Die Grenze lag bei 360 px und musste hoch. Mit FARBREIN ist die Kette
   sechs- statt fünfspaltig; gemessen braucht sie in voller Schriftgröße 392 px,
   bei 375 px Gerätebreite stehen aber nur 350 zur Verfügung – die Zeile schob
   das ganze Fenster seitlich weg. 440 px deckt alle gängigen Telefone ab
   (375/390/393/412/414/430). */
@media (max-width: 440px) {
  /* FUSSZEILE AM HANDY (R37). Sie war schlicht über Budget: Im Training stehen
     rechts bis zu vier Knöpfe (💪 🍀 🔧 🎲) und links zwei bis drei (↺ 💡 📌).
     Bei 375 px maßen sich 7 Symbolknöpfe à 37 px plus ein 99 px breiter
     Einloggen-Knopf – zusammen mehr als die 359 px, die zwischen den Polstern
     liegen. Das Raster 1fr|auto|1fr hält die Mitte zwar mittig, die Seiten
     laufen aber über ihre Spalte hinaus und schoben sich UNTER den Knopf.
     Deshalb schrumpfen hier alle drei zugleich, nicht nur die Beschriftung. */
  /* R43 – DIE SYMBOLE SIND WIEDER SO GROSS WIE VOR R37. Moeglich, weil das 🔧
     die Reihe verlassen hat (jetzt oben links): Statt sieben Knoepfen stehen
     hier hoechstens sechs (↺ 📌 💡 links, 💪 🍀 🎲 rechts). Nachgerechnet bei
     375 px: 6 × 38,6 px = 232 px, dazu 25,6 px Abstaende in den Seiten, 9,6 px
     zwischen den Gruppen und 12,8 px Rand = 280 px; der Einloggen-Knopf misst
     hier 84 px. Zusammen 364 von 375 px. Es passt, aber ohne Reserve - kommt je
     ein siebter Knopf zurueck, muss wieder etwas weichen.
     Die Symbole behalten damit ihre Grundgroesse (1,1 rem, 0,55 rem Polster);
     verkleinert wird nur noch der Einloggen-Knopf. */
  .commit-btn { padding: 0.7rem 0.9rem; font-size: 0.95rem; }
  .bottombar { gap: 0.3rem; padding-left: 0.4rem; padding-right: 0.4rem; }
  .mlabel { font-size: 0.58rem; --mlabel-pad: 0.2rem; letter-spacing: 0.03em; }
  .mlabel-rank { min-width: 3.4rem; }
  /* Auch die Mindestbreite schrumpft mit: Sonst füllt ein "+2,5"-Reiter die hier
     schmalere Spalte fast aus und die Luft zwischen den Reitern verschwindet. */
  .mult-tab { padding-left: 0.3rem; padding-right: 0.3rem; font-size: 0.7rem; min-width: 1.4rem; }
  .tab-sum { font-size: 0.8rem; }
}

/* Zweite Stufe für die schmalsten Geräte (320 px). Dort braucht die sechs-
   spaltige Kette 297 px, verfügbar sind 294 – die letzten Pixel holt die
   engere Laufweite. Gemessen, nicht geschätzt. */
@media (max-width: 340px) {
  /* Auf 320 px ist die Kette der Faktoren am Anschlag: Im schlimmsten Fall
     (sechs Spalten, drei Früchte, dreifach rein, FLIEDER) misst sie mit
     0,35 rem Spalte 291 von 294 px. Hier gilt deshalb der kleinere Wert –
     Zusammenpassen geht vor Luft. */
  .word-block { column-gap: 0.2rem; }
  .commit-btn { padding: 0.6rem 0.7rem; font-size: 0.9rem; }
  /* Auf 320 px reicht die Breite fuer sechs volle Knoepfe nicht mehr - hier
     bleibt eine Verkleinerung noetig, aber eine mildere als vor R43. */
  .icon-btn { padding: 0.4rem 0.3rem; font-size: 1.05rem; }
  .mlabel { font-size: 0.55rem; letter-spacing: 0.01em; --mlabel-pad: 0.12rem; }
  .mlabel-rank { min-width: 3rem; }
  .mult-tab { padding-left: 0.22rem; padding-right: 0.22rem; min-width: 1.2rem; }
}

/* Symbol des Wortes hinter den Buchstaben (R28). Kleiner als die Buchstaben und
   in Gold wie der Symbol-Reiter – es ist eine Auszeichnung, kein Buchstabe. */
.wsymbol {
  /* Die Fruchtmarke hinter dem Wort – seit R37 gezeichnete Kreise (.fruit-dot).
     Durchmesser 0,45 em der WORTGRÖSSE: gut sichtbar neben Versalien (Versalhöhe
     ~0,73 em), aber klar kleiner als ein Buchstabe – sie ist eine Auszeichnung,
     kein Buchstabe. Die Wortzeile hat feste Höhe (2,8 rem), die Bretthöhe bleibt
     also unberührt, egal wie groß der Punkt wird. */
  color: #F7DC6F;
  margin-left: 0.2em;
  --fruit: 0.45em;
}

.swap-points {
  font-size: 0.82rem;
  font-weight: 800;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: rgba(47, 216, 208, 0.22);
  color: var(--accent);
  white-space: nowrap;
  /* Seit R27 schwebt das Guthaben über dem Brett (die Zeile ist durchklickbar) –
     sein eigener Tipp muss aber weiter die Tausch-Info öffnen. */
  pointer-events: auto;
  cursor: pointer;
}
.swap-points.empty { background: rgba(255,255,255,0.08); color: var(--text-dim); }

/* --- Runde 13b: Kopien im Wortschatz --- */
.copy-tag {
  font-size: 0.72rem;
  font-weight: 800;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: var(--text-dim);
  margin-left: 0.3rem;
  white-space: nowrap;
}
/* Klickbarer Doppelte-Zähler (Sammelverkauf dieses Wortes). */
.copy-tag-btn {
  width: auto;
  border: 1px solid rgba(120,200,140,0.4);
  cursor: pointer;
}
.copy-tag-btn:hover { background: rgba(120,200,140,0.25); }
/* Überzählige Fassungen: sichtbar, aber erkennbar zweitrangig. */
.list-item.spare-copy { opacity: 0.72; }

/* --- R36: TRAINING (Leiste, Vorschlagsliste, Vorschau) ---------------------
   Alles hier ist im echten Spiel unsichtbar. Die Leiste steht ZWISCHEN
   Meldungszeile und Brett und ist die einzige Stelle, die dem Brett Höhe
   nimmt – deshalb ist sie flach gehalten (Lehre aus R11: über dem Brett darf
   nichts wachsen, sonst rutschen die Chips). */
.train-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.15rem 0.6rem 0.35rem;
  min-height: 1.9rem;
}
.train-bar .grow { flex: 1; }
/* Das Etikett trägt die Bedienfarbe, nicht die Rangfarbe: „hier zählt nichts"
   ist eine Ansage der App, kein Multiplikator (R30-Regel). */
.train-badge {
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--accent);
  color: var(--accent);
  white-space: nowrap;
}
/* Platz X von Y – ein Knopf, weil das Antippen das beste Wort verrät. */
.retro-line {
  width: auto;
  padding: 0.15rem 0.5rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-dim);
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 999px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 60vw;
}
.retro-line:hover { color: var(--text); }
#preview-btn { width: auto; white-space: nowrap; }
#preview-btn.active { border-color: var(--accent); color: var(--accent); }

.hints-head, .hints-foot { display: flex; align-items: center; gap: 0.5rem; }
.hints-head .grow, .hints-foot .grow { flex: 1; }
#hints-langs, #hints-more { width: auto; }
.hints-list { display: flex; flex-direction: column; gap: 0.3rem; }
/* Eine Zeile: Wort links, Multiplikatoren mittig, Punkte rechtsbündig – dieselbe
   Leserichtung wie die Multiplikatorleiste über dem Brett. */
.hint-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  text-align: left;
  padding: 0.45rem 0.7rem;
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: var(--radius);
}
.hint-row:hover { border-color: var(--accent); }
.hint-word { font-weight: 600; letter-spacing: 0.06em; flex: 1; min-width: 0; }
.hint-mult { font-size: 0.85rem; letter-spacing: 0.05em; white-space: nowrap; line-height: 1; }
/* Die Fruchtpunkte in der Vorschlagsliste sind GEZEICHNETE Kreise, keine Glyphe
   (R37, siehe training.js): Nur so sitzen sie unabhängig von der Schrift genau
   auf der Versalmitte, wo das ⬣ daneben von sich aus schon sitzt.
   Der Durchmesser ist an der TINTENHÖHE des ⬣ ausgerichtet (gemessen 10 px bei
   13,6 px Zeilenschrift ⇒ 0,75 em) und eine Spur größer gewählt, weil eine
   gefüllte Fläche kleiner wirkt als ein Umriss derselben Höhe. */
/* In der Liste sind die Marken etwas kleiner als über dem Brett: Die Zeile ist
   dichter gesetzt und das Wort daneben steht in 16 px. */
.hint-mult { --fruit: 0.8em; --stone-w: 0.8em; --stone-h: 0.72em; --pure: 0.58em; }
.hint-pure { color: var(--text-dim); margin-left: 0.15rem; }
.hint-score { font-weight: 800; color: var(--accent); min-width: 2.5rem; text-align: right; }

/* Vorschau: zwei Reihen Auswahlchips über einer schlichten Zahlentafel. */
.chip-row { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.preview-row { display: flex; flex-direction: column; gap: 0.35rem; }
.preview-row label { font-size: 0.78rem; color: var(--text-dim); }
.preview-chip {
  width: auto;
  padding: 0.25rem 0.6rem;
  font-size: 0.8rem;
  border-radius: 999px;
}
.preview-chip.active { background: var(--accent); color: #241c00; font-weight: 700; }
.preview-table {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.6rem 0.75rem;
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: var(--radius);
}
.preview-line { display: flex; justify-content: space-between; font-size: 0.85rem; }
.preview-foot { padding-top: 0.35rem; border-top: 1px solid rgba(255,255,255,0.07); }

/* FENSTER „ABO & WOCHENZIEL" (R37). Die vier Stufen als Karten untereinander –
   nebeneinander wären es auf 320 px vier Spalten à 70 px, in denen weder die
   Schlagzeile noch die Reglerzeilen lesbar blieben. Die eigene Stufe ist am
   Rahmen erkennbar, nicht an einer Farbfläche: Die Karte soll sich nicht als
   Werbung lesen. */
.sub-tiers { display: flex; flex-direction: column; gap: 0.5rem; }
.sub-tier {
  padding: 0.6rem 0.75rem;
  background: var(--panel);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: var(--radius);
}
.sub-tier.mine { border-color: var(--accent); }
.sub-tier-head { display: flex; align-items: center; gap: 0.5rem; }
.sub-claim { padding: 0.15rem 0 0.4rem; }
.sub-measured { padding-top: 0.35rem; }
.sub-soon { opacity: 0.75; }
