/* =========================================================================
   SAGA OF DILMUN -- Oberfläche
   =========================================================================
   EINE Bildsprache für alles: Charaktererstellung, Übersicht, Spiel und
   Kosmos. Sie ist bewusst schlicht -- dünne Linien, ruhige Flächen, kleine
   Eckwinkel als einziges Ornament.

   Warum nicht die Pixelart-Holzrahmen: das Spiel selbst IST Pixelart, die Welt
   ist bunt und detailliert. Wenn die Bedienelemente denselben Detailgrad haben,
   kämpfen beide um dieselbe Aufmerksamkeit, und man findet weder den Knopf noch
   den Gegner. Die Oberfläche tritt deshalb zurück: sie rahmt, sie konkurriert
   nicht.

   Die Farben sind ein warmes, gedecktes Braun -- Pergament, Holz, Messing.
   Kein Schwarzblau wie in einer Raumfahrtkonsole: dieses Spiel handelt von
   Ruinen und Gelehrten, nicht von Bildschirmen.

   ALLE Farben stehen als Variablen ganz oben. Wer den Ton ändern will, ändert
   sie dort und nirgendwo sonst.
   ========================================================================= */

:root {
  /* =====================================================================
     DIE SCHRIFTLEITER (16. September)
     =====================================================================
     Oliver: *„die buttons und die schriftgröße sind iwie noch immer nicht
     so richtig hübsch."*

     Nachgezählt standen in diesem Stilblatt **48 verschiedene
     Schriftgrößen**: 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14,
     15, 16, 17, 18, 19, 20, 21, 22, 26, 30, 34 -- praktisch jede Zahl, die
     es gibt. Ein Unterschied von einem halben Punkt liest sich nicht als
     Absicht, sondern als Unruhe; genau das ist „nicht hübsch".

     Schlimmer war die Lücke: `.panel` setzte GAR KEINE Größe. Gemessen im
     offenen Zauberbuch trugen dreizehn Elemente 16 Punkte -- die
     Browservorgabe -- neben Reitern mit 12,5. Der Sprung von 12,5 auf 16
     ist der größte im ganzen Fenster, und er war niemandes Entscheidung.

     Fünf Stufen, jede mit einem Zweck. Wer eine neue Größe braucht, nimmt
     die nächste Stufe -- oder begründet, warum es eine sechste geben muss. */
  --schrift-winzig: 10px;     /* Zahlen am Knopf, Marken, Fußnoten */
  --schrift-klein:  11.5px;   /* Nebentext, Hinweise, Reiter */
  --schrift-text:   13px;     /* Fließtext in Fenstern -- die Grundgröße */
  --schrift-gross:  15px;     /* Überschrift in einem Fenster */
  --schrift-titel:  19px;     /* Fenstertitel, Schaustücke */

  /* Grundflächen, von dunkel nach hell */
  --grund:       #17120d;   /* Hintergrund der ganzen Seite */
  --grund-2:     #1f1810;   /* Verlaufsmitte */
  --flaeche:     #241c14ee; /* Fenster (leicht durchscheinend) */
  --flaeche-fest:#241c14;   /* Fenster, wo Durchsicht stört */
  --feld:        #2b2219;   /* Zeilen, Slots, Eingabefelder */
  --feld-hell:   #342a1f;   /* dasselbe, angehoben (Hover) */

  /* Linien */
  --linie:       #4b3b2a;   /* sichtbare Kante */
  --linie-leise: #372b1e;   /* Trennung innerhalb eines Fensters */

  /* Akzente */
  --sand:        #d9bd93;   /* der Leitton: Überschriften, aktive Zustände */
  --sand-leise:  #8b7150;   /* derselbe Ton, zurückgenommen */
  --gold:        #e3bd6d;   /* Werte, Credits, Belohnungen */
  --gruen:       #a9c98d;   /* erledigt, bereit, Erfolg */
  --rot:         #d98a72;   /* Warnung, Schaden, Abbrechen */
  --violett:     #b99ad2;   /* Geschichte: Kapitel, Lore, Erfahrung */

  /* Schrift */
  --text:        #f2ece1;
  --text-leise:  #b6a894;
  --text-fern:   #7e7160;
}

* { box-sizing: border-box; }

html, body {
  margin:0; padding:0; height:100%;
  background:var(--grund); color:var(--text);
  font-family:'Segoe UI', system-ui, sans-serif;
  overflow:hidden;
}
.hidden { display:none !important; }
.screen { width:100vw; height:100vh; }

/* Die Eckwinkel: das einzige Ornament der ganzen Oberfläche. Zwei kurze Striche
   oben links und unten rechts, sonst nichts. Sie geben einem Rechteck Halt,
   ohne es zu verzieren. */
.eckig { position:relative; }
.eckig::before, .eckig::after {
  content:''; position:absolute; width:9px; height:9px;
  border:1px solid var(--sand-leise); pointer-events:none;
}
.eckig::before { top:-1px; left:-1px; border-right:none; border-bottom:none; }
.eckig::after  { bottom:-1px; right:-1px; border-left:none; border-top:none; }

/* ---------- Charaktererstellung ----------
   EINE KOMPOSITION. Das ganze Blatt der Vorlage ist ein Bild
   (assets/ui/cc_gerippe_frei.png, 972x900, gebaut von
   tools/cc_gerippe_bauen.py); alles Weitere liegt in Prozent darauf. Die
   Bühne hat das Seitenverhältnis des Blattes und bekommt die größte Breite,
   bei der sie in Höhe UND Breite passt (creatorPassen in client.js); der
   Maßstab steht als --ccK am Blatt, damit Schrift und Knöpfe mitgehen. */
#creatorScreen {
  position:relative;
  display:flex; align-items:center; justify-content:center;
  background:
    radial-gradient(ellipse at 50% 30%, rgba(120,150,150,.10), rgba(0,0,0,0) 62%),
    radial-gradient(ellipse at 50% 28%, var(--grund-2) 0%, #0d0a07 72%);
  overflow:hidden; padding:0;
}
/* Hier stand kurz das Logo als Wasserzeichen hinter dem Blatt. Es ist wieder
   raus: Beim Erstellen schaut man auf die Figur, und ein Wappen dahinter
   zieht den Blick weg. Das Logo hat seinen Platz auf der Anmeldung und in
   der Charakterübersicht. */
.ccBuehne {
  position:relative; z-index:1; width:min(972px, 96vw); aspect-ratio:972 / 900;
  flex:none;
}
/* Ein Hauch Licht hinter der Figur -- die Vorlage hat dort einen rauchigen
   Aufheller, damit die Figur nicht im Schwarz steht. */
.ccBuehne::before {
  content:''; position:absolute; left:6%; top:20%; width:52%; height:60%; z-index:1;
  background:radial-gradient(ellipse at 50% 55%, rgba(150,175,170,.16), rgba(0,0,0,0) 65%);
  pointer-events:none;
}
.ccGerippe { position:absolute; inset:0; width:100%; height:100%; z-index:3; pointer-events:none;
  filter:drop-shadow(0 10px 30px rgba(0,0,0,.55)); }

/* Der Satz im Banner-Schlitz (x 336..659, y 7..59): dieselbe Farbe, derselbe
   Schein wie die Gravur, die dort stand. Über dem Gerippe, weil der Schlitz
   im Bild geschlossen ist. */
.ccBannerText {
  position:absolute; left:34.6%; top:0.8%; width:33.2%; height:5.8%; z-index:4;
  display:flex; align-items:center; justify-content:center;
  /* Der Schlitz ist ein Bogen: In der Mitte 52 Punkte hoch, an den Enden
     dünner. Der Satz muss mit Luft an beiden Seiten darin stehen -- bei
     19 Punkten mit weitem Sperrsatz stieß er an die Metallkante. */
  font-size:calc(15.5px * var(--ccK, 1)); font-weight:700; letter-spacing:.07em;
  padding:0 8%;
  color:#9fe0cf; text-shadow:0 0 10px rgba(120,220,200,.7), 0 0 2px rgba(160,255,230,.9), 0 1px 2px #000;
  white-space:nowrap; pointer-events:none;
}

/* Das Volk: über der Figur, links, in der freien Fläche. */
/* AUSGEMESSEN: Links oben ist die Fläche erst ab y=122 (13.5%) und x=90
   (9.3%) wirklich frei -- darüber laufen der Runenknopf und der Arm des
   Banners. Der Text stand bei 8% und schnitt sich an beiden. */
.ccBuehne .volkText {
  position:absolute; left:10.5%; top:14%; width:45%; z-index:4;
  display:flex; flex-direction:column; gap:3px; text-align:left;
}
.volkText .volkName { font-size:calc(15px * var(--ccK, 1)); font-weight:700; letter-spacing:.1em;
  text-transform:uppercase; color:var(--sand); text-shadow:0 1px 3px #000; }
.volkText .volkKurz { font-size:calc(12.5px * var(--ccK, 1)); line-height:1.45; color:var(--text);
  text-shadow:0 1px 3px #000; }
.volkText .volkWarum { font-size:calc(11.5px * var(--ccK, 1)); line-height:1.5; color:var(--text-leise);
  font-style:italic; border-left:2px solid var(--linie); padding-left:8px; text-shadow:0 1px 3px #000; }

/* Die Figur steht FREI: kein Kasten, kein Rahmen -- nur die Lichtscheibe am
   Boden, auf der sie steht. Sie ist in der Vorlage deutlich zu sehen: ein
   heller Teller, der die Figur trägt, statt eines Schattens, der sie
   festnagelt. */
.ccFigur {
  position:absolute; left:8%; top:23%; width:48%; height:52%; z-index:2;
  display:flex; align-items:flex-end; justify-content:center;
}
.ccFigur::before {
  content:''; position:absolute; left:14%; right:14%; bottom:-1%; height:15%;
  border-radius:50%;
  background:radial-gradient(ellipse at 50% 50%, rgba(170,220,210,.30), rgba(120,190,180,.12) 55%, rgba(0,0,0,0) 72%);
  box-shadow:0 0 34px rgba(120,210,195,.18);
  pointer-events:none;
}
#creatorPreview {
  position:relative; width:100%; height:100%; display:block;
  background:transparent; image-rendering:pixelated;
}

/* MANN ODER FRAU: zwei Zeichen links neben der Figur, untereinander.
   Klein und ruhig -- es ist eine Wahl zwischen zwei Dingen, kein Abschnitt.
   Das gewählte Zeichen steht in Gold und trägt den Schein der Fassungen. */
.ccGeschlecht {
  position:absolute; left:2.5%; top:34%; z-index:3;
  display:flex; flex-direction:column; gap:8px;
}
.ccGeschlecht button {
  width:38px; height:38px; padding:0; cursor:pointer;
  border:1px solid #4a6b66; border-radius:50%;
  background:radial-gradient(circle at 50% 35%, rgba(30,58,55,.92), rgba(12,24,23,.92));
  color:#8fb9b2; font-size:19px; line-height:1; font-weight:700;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.5);
  transition:color .12s, border-color .12s, box-shadow .12s;
}
.ccGeschlecht button:hover { color:#d8efe8; border-color:#7fbdb2; }
.ccGeschlecht button.gewaehlt {
  color:#f0d69a; border-color:#d6b260;
  box-shadow:0 0 14px rgba(214,178,96,.35), inset 0 0 0 1px rgba(0,0,0,.5);
}

/* Der Ring: die Knöpfe werden mit den ausgemessenen Fassungen gesetzt
   (CC_OVALE in client.js, in Prozent von 972x900). Der Behälter ist die
   ganze Bühne. */
/* DIE FASSUNGEN LIEGEN ÜBER DEM RAHMEN, NICHT DARUNTER.
   Oliver, 11.9.: „Nammuri der name kann man kaum lesen abgeschnitten." Das
   gemalte Gerippe (.ccGerippe) liegt auf z-index 3 und damit ÜBER dem Ring --
   der Arm aus Metall, der an der Fassung der Nammuri vorbeiläuft, schnitt
   dem Namen das letzte Zeichen ab. Die Köpfe sitzen ohnehin in den Fassungen
   und ragen nirgends über sie hinaus; sie dürfen also darüber liegen. */
.ccOvale { position:absolute; inset:0; z-index:4; pointer-events:none; }
.ccOval {
  position:absolute; z-index:2; border:none; padding:0; background:transparent;
  border-radius:50%; overflow:hidden; pointer-events:auto; cursor:pointer;
}
.ccOval canvas {
  width:100%; height:100%; display:block; image-rendering:pixelated;
  /* Der Türkiston der Vorlage: die Köpfe sind Bildnisse in Glas. */
  filter:grayscale(1) sepia(1) hue-rotate(118deg) saturate(1.5) brightness(.78) contrast(1.05);
  opacity:.95;
  background:radial-gradient(ellipse at 50% 40%, #2a4a45, #10201e 75%);
}
.ccOval:hover canvas { opacity:1; filter:grayscale(1) sepia(1) hue-rotate(118deg) saturate(1.8) brightness(.95) contrast(1.05); }
/* EINE FASSUNG OHNE BILD IST DUNKEL, NICHT WEISS.
   Der gemalte Ring hat sechs Fassungen und nur vier Völker; die Innenflächen
   der beiden freien sind im Blatt WEISS und sahen deshalb aus wie zwei
   Portraits, die nicht geladen haben (Oliver, 11.9.: „leere portraits müssen
   raus"). Herausschneiden geht nicht -- die Ringe sind ineinander
   verschlungen. Also werden sie zugesetzt: derselbe Tiefenton wie hinter den
   Köpfen, dazu die Innenkante, die eine leere Fassung im Metall hätte. */
/* EINE FASSUNG OHNE BILD IST NICHT LEER, SIE IST BLIND.
   Zweiter Anlauf (Oliver, 11.9.: „zwei leere fenster das UI musst du anpassen
   hübsch machen"). Dunkel allein liest sich immer noch als „hier fehlt was".
   Also bekommt sie, was eine geschlossene Fassung im Metall hätte: eine
   Innenkante, einen schwachen Schimmer auf der oberen Rundung -- und ein
   eingraviertes Zeichen, dasselbe Keilschriftmotiv, das auch am Rahmen
   steht. Damit ist sie erkennbar ABSICHT und nicht ein Bild, das nicht
   geladen hat. */
.ccOvalBlind {
  position:absolute; z-index:1; border-radius:50%; pointer-events:none;
  background:
    radial-gradient(ellipse at 50% 30%, rgba(120,180,165,.07), rgba(0,0,0,0) 60%),
    radial-gradient(ellipse at 50% 42%, #18282300, #0b1512 82%),
    linear-gradient(#141f1c, #0a1310);
  box-shadow:
    inset 0 4px 12px rgba(0,0,0,.9),
    inset 0 -3px 8px rgba(120,160,150,.09),
    inset 0 0 0 1px rgba(150,190,178,.10);
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
}
/* Das Zeichen wird GEZEICHNET, nicht gesetzt: Eine Schriftart mit Keilschrift
   hat nicht jedes System, und ein fehlendes Zeichen malt ein leeres Kästchen --
   das wäre genau das, was hier weg sollte. Zwei gekreuzte Balken und ein Ring:
   ruhig, symmetrisch, erkennbar als Gravur. */
.ccOvalBlind::before, .ccOvalBlind::after {
  content:''; position:absolute; pointer-events:none;
}
.ccOvalBlind::before {
  width:26%; height:26%; border-radius:50%;
  border:1px solid rgba(150,205,190,.16);
  box-shadow:0 1px 0 rgba(0,0,0,.5), inset 0 1px 0 rgba(0,0,0,.4);
}
.ccOvalBlind::after {
  width:34%; height:1px; background:rgba(150,205,190,.13);
  box-shadow:0 1px 0 rgba(0,0,0,.45);
}
/* DIE GEWÄHLTE FASSUNG LEUCHTET -- deutlich, wie in der Vorlage: ein
   türkiser Schein, der über den Metallrand hinausstrahlt, und der Kopf darin
   hell. Man soll aus dem Augenwinkel sehen, wer man ist. */
.ccOval.gewaehlt { overflow:visible; }
.ccOval.gewaehlt canvas { opacity:1; border-radius:50%;
  filter:grayscale(1) sepia(1) hue-rotate(118deg) saturate(2.4) brightness(1.18) contrast(1.1); }
.ccOval.gewaehlt::after {
  content:''; position:absolute; inset:-3%; border-radius:50%; z-index:3;
  box-shadow:inset 0 0 16px rgba(150,255,225,.8), 0 0 22px 4px rgba(120,230,205,.55), 0 0 60px rgba(120,230,205,.25);
  pointer-events:none;
}
/* DER NAME DARF AUS SEINER FASSUNG HERAUSRAGEN.
   Oliver, 11.9.: „Nammuri der name kann man kaum lesen abgeschnitten." Die
   Fassung ist rund und schneidet ab (border-radius + overflow:hidden), und
   „Nammuri" ist eine Silbe länger als die anderen drei -- genau eine zu viel.
   Die Platte sitzt jetzt UNTER dem Oval statt darin, breiter als die Fassung
   und außerhalb des Schnitts. Damit passt jeder Name, auch der nächste. */
/* DAS NAMENSSCHILD HÄNGT AN DER FASSUNG, ES LIEGT NICHT IM BILD.
   Oliver, 11.9.: „oben Kishar hat den text und den balken über dem
   profilbild." Die Platte saß IM Oval -- und ein Oval schneidet rund ab. Um
   sie lesbar zu halten, war sie breiter als die Fassung gemacht worden; unten
   in der Rundung wurde daraus ein Balken quer über das Gesicht.
   Jetzt ist sie ein eigenes Stück, gesetzt auf die Metallkante am Fuß der
   Fassung: halb darauf, halb darunter, an ihrer Mitte ausgerichtet. Nichts
   schneidet mehr, nichts liegt im Bild, und jeder Name passt -- auch der
   nächste, der länger ist als Nammuri. */
.ccOvalName {
  position:absolute; z-index:6; transform:translate(-50%, -50%);
  padding:1px 6px 2px; border-radius:4px;
  background:linear-gradient(rgba(9,24,21,.94), rgba(4,14,12,.94));
  box-shadow:0 1px 3px rgba(0,0,0,.7), inset 0 0 0 1px rgba(150,200,186,.13);
  font-size:calc(10px * var(--ccK, 1)); font-weight:700; letter-spacing:.03em;
  color:#bfe4d6; text-shadow:0 1px 2px #000; pointer-events:none;
  white-space:nowrap;
}
.ccOvalName.gewaehlt {
  color:#ffffff;
  background:linear-gradient(rgba(16,54,48,.96), rgba(8,32,28,.96));
  box-shadow:0 1px 4px rgba(0,0,0,.75), inset 0 0 0 1px rgba(150,255,225,.35),
             0 0 12px rgba(120,230,205,.35);
  text-shadow:0 0 8px rgba(150,255,225,.9), 0 1px 2px #000;
}

/* Die Namensplatte (Innenfläche x 652..925, y 606..684): das Feld liegt
   IN der Platte, ohne eigenen Rahmen -- die Platte ist der Rahmen. */
.ccName { position:absolute; left:67.5%; top:67.6%; width:27.6%; height:8.4%; z-index:4; }
.ccName input {
  width:100%; height:100%; box-sizing:border-box; display:block;
  background:transparent; border:none; text-align:center;
  font-size:calc(17px * var(--ccK, 1)); font-weight:700; letter-spacing:.06em;
  color:#c9ecdf; text-shadow:0 0 8px rgba(120,220,200,.55);
}
.ccName input::placeholder { color:#6d8a80; font-weight:600; text-shadow:none; }
/* Der Fokus ist ein Hauch, kein Kasten: Das Feld ist die Platte, und die
   Platte hat schon einen Rand. */
.ccName input { border-radius:10px; }
.ccName input:focus { outline:none; box-shadow:inset 0 0 28px rgba(120,220,200,.16); }

/* Unter dem Namen: der Rückweg und die Meldung. Der Aufbruch steht einmal,
   unten auf dem Sockel -- zwei Knöpfe für dieselbe Handlung lasen sich wie
   ein Versehen. */
.ccStart {
  position:absolute; left:67.5%; top:77.2%; width:27.6%; z-index:4;
  display:flex; flex-direction:column; align-items:center; gap:calc(4px * var(--ccK, 1));
}

/* ====================================================================
   DIE WEGWAHL -- EIN EIGENER SCHIRM (15. September, dritter Anlauf)
   ====================================================================
   Zwei Anlaeufe im Editor waren beide falsch: erst drei Zeilen unter der
   Namensplatte („sehr verdeckt bzw unpassend"), dann eine Spalte daneben.
   Der Fehler war nicht die Anordnung, sondern dass zwei Fragen auf einem
   Schirm standen -- eine beliebig aenderbare (wie sehe ich aus?) und eine
   endgueltige (wer bin ich?).

   Jetzt: zwei Schritte, zwei Schirme. Dieser hier ist dunkel und leer bis
   auf die drei Tafeln -- wie das Wegwahlfenster im Spiel, und aus demselben
   Grund: Bei der einzigen Entscheidung, die bleibt, soll nichts danebenstehen,
   das ablenkt. */
#wegScreen {
  position:relative; display:flex; align-items:center; justify-content:center;
  background:
    radial-gradient(ellipse at 50% 34%, rgba(120,150,150,.10), rgba(0,0,0,0) 62%),
    radial-gradient(ellipse at 50% 30%, var(--grund-2) 0%, #0b0907 74%);
  overflow:auto; padding:24px 16px;
}
.wsInner { width:min(1080px, 96vw); display:flex; flex-direction:column; align-items:center; gap:10px; }
.wsOben {
  font-size:12px; letter-spacing:.22em; text-transform:uppercase; color:#8a7f60;
}
.wsTitel {
  margin:0; font-size:clamp(26px, 3.2vw, 40px); font-weight:700; letter-spacing:.06em;
  color:#e9fff8; text-shadow:0 0 18px rgba(120,230,205,.45), 0 2px 4px #000;
}
.wsText {
  margin:0 0 6px; max-width:62ch; text-align:center; font-size:13.5px; line-height:1.55; color:#9aa1a0;
}
.wsText b { color:#c9b98f; }

/* Drei Tafeln nebeneinander. Jede traegt alles, was man wissen muss, BEVOR
   man sich bindet: was der Weg tut, was er mitbringt, und den langen Satz --
   „Ohne dich haelt keine Gruppe einen langen Kampf durch." Das ist die
   Angabe, die sonst erst im Spiel auffaellt, wenn die Wahl gefallen ist. */
.wsKarten { display:flex; gap:14px; width:100%; align-items:stretch; justify-content:center; }
.wsKarte {
  flex:1 1 0; max-width:330px; min-width:0;
  display:flex; flex-direction:column; gap:7px; text-align:left;
  padding:18px 18px 20px;
  background:linear-gradient(180deg,#232f2c,#111917);
  border:1px solid #6f7a76; border-radius:10px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 10px 30px rgba(0,0,0,.55);
  cursor:pointer; color:#9fc9bd; font-family:inherit;
  transition:border-color .12s ease, box-shadow .12s ease, color .12s ease, transform .12s ease;
}
.wsKarte:hover { border-color:#9fe0cf; color:#d2f5ea; transform:translateY(-2px); }
.wsKarte.gewaehlt {
  border-color:#9fe0cf; color:#e9fff8; transform:translateY(-2px);
  box-shadow:inset 0 0 18px rgba(150,255,225,.30), 0 0 22px rgba(120,230,205,.45);
}
.wsIcon { font-size:34px; line-height:1; }
.wsName { font-size:19px; font-weight:700; letter-spacing:.04em; }
.wsKurz { font-size:13.5px; line-height:1.4; color:#a9d8c9; }
.wsBonus {
  font-size:11.5px; line-height:1.45; color:#c9b98f;
  border-top:1px solid rgba(201,185,143,.22); border-bottom:1px solid rgba(201,185,143,.22);
  padding:6px 0; margin:2px 0;
}
.wsDesc { font-size:12px; line-height:1.5; color:#8a9491; }
.wsKarte.gewaehlt .wsDesc { color:#a3b3ae; }

.wsMeldung { margin:2px 0 0; min-height:17px; font-size:12.5px; color:#c9b98f; text-align:center; }
.wsKnoepfe { display:flex; gap:14px; align-items:center; margin-top:8px; }
/* Die Masse stehen hier und nicht am Grundstil: `.primaryBtn` ist der
   Steinknopf des Spiels und traegt selbst keine Groesse -- jede Stelle sagt,
   wie gross er dort sein soll (siehe .ccStart .primaryBtn). */
.wsKnoepfe .primaryBtn {
  min-width:210px; padding:12px 26px; font-size:14px; letter-spacing:.04em; cursor:pointer;
}
/* Der Rueckweg ist die zweite Wahl -- das sagt `.ghostBtn`, und seit dem
   15. September sagt es das ueberall gleich (siehe `.primaryBtn.ghostBtn`).
   Hier bleibt nur die Breite: Der Hauptknopf traegt einen ganzen Satz
   ("Als Bewahrerin aufbrechen"), der Rueckweg zwei Woerter. */
#wsZurueck { min-width:0; }
/* Der Bestaetigungsknopf bleibt anklickbar und sagt, was fehlt -- dieselbe
   Bauart wie die Namenspruefung im Editor. Ein toter Knopf sagt nur NEIN. */
#wsBestaetigen.wartet { filter:grayscale(.55) brightness(.72); }

@media (max-width: 860px) {
  .wsKarten { flex-direction:column; align-items:stretch; }
  .wsKarte { max-width:none; }
  .wsKnoepfe { flex-direction:column-reverse; width:100%; }
  .wsKnoepfe .primaryBtn { width:100%; }
}
.ccStart .primaryBtn { width:100%; margin:0; padding:calc(7px * var(--ccK, 1)) 0; font-size:calc(13px * var(--ccK, 1)); }
.ccStart .msg { margin:0; font-size:calc(12px * var(--ccK, 1)); text-align:center; min-height:0; }
.ccStart .ghostBtn { padding:calc(5px * var(--ccK, 1)) 0; font-size:calc(11.5px * var(--ccK, 1)); }

/* DER SOCKEL: der große Satz auf der breiten Platte unten (Innenfläche
   x 341..666, y 783..865). Kein Kasten, keine Kante -- die Platte ist der
   Knopf, der Text glüht, und beim Zeigen glüht er stärker. */
.ccSockel {
  position:absolute; left:35.1%; top:87%; width:33.4%; height:9.1%; z-index:4;
  background:transparent; border:none; border-radius:12px; cursor:pointer;
  font-family:inherit; font-size:calc(27px * var(--ccK, 1)); font-weight:700; letter-spacing:.1em;
  color:#b6ecdc;
  text-shadow:0 0 14px rgba(120,230,205,.85), 0 0 3px rgba(190,255,240,.95), 0 2px 3px #000;
  transition:color .15s ease, text-shadow .15s ease, box-shadow .15s ease;
}
.ccSockel:hover, .ccSockel:focus-visible {
  outline:none; color:#e9fff8;
  text-shadow:0 0 22px rgba(140,240,215,1), 0 0 4px rgba(220,255,245,1), 0 2px 3px #000;
  box-shadow:inset 0 0 36px rgba(120,220,200,.22);
}

/* DIE FEINHEITEN: DREI REITER, EINE ZEILE.
   Links die drei Reiter (Haare / Frisur / Bart), jeder mit dem Bild seiner
   Wahl; rechts daneben, auf derselben Zeile, die Auswahl des offenen
   Reiters. Nichts liegt über der Figur, und wenn nichts offen ist, stehen
   nur drei kleine Fassungen da. */
.ccFeinheiten {
  position:absolute; left:8%; top:76.3%; width:52%; height:9%; z-index:4;
  display:flex; align-items:center; gap:calc(14px * var(--ccK, 1));
}
.ccTabs { display:flex; gap:calc(6px * var(--ccK, 1)); flex:none; }
/* Ein Reiter: dunkles Glas in einer Metallkante, wie die Platten des
   Blattes -- nicht der graue Knopf des Spiels. */
.ccTab {
  width:calc(46px * var(--ccK, 1)); height:calc(56px * var(--ccK, 1));
  padding:calc(4px * var(--ccK, 1)) 0 calc(3px * var(--ccK, 1));
  display:flex; flex-direction:column; align-items:center; justify-content:space-between;
  background:linear-gradient(180deg,#24312e,#121a18);
  border:1px solid #6f7a76; border-radius:calc(6px * var(--ccK, 1));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.08), 0 3px 10px rgba(0,0,0,.6);
  cursor:pointer; color:#9fc9bd; font-family:inherit;
  transition:border-color .12s ease, box-shadow .12s ease, color .12s ease;
}
.ccTab:hover { border-color:#9fe0cf; color:#d2f5ea; }
.ccTab.aktiv {
  border-color:#9fe0cf; color:#e9fff8;
  box-shadow:inset 0 0 12px rgba(150,255,225,.35), 0 0 14px rgba(120,230,205,.45);
}
.ccTabBild {
  width:calc(30px * var(--ccK, 1)); height:calc(30px * var(--ccK, 1));
  display:flex; align-items:center; justify-content:center; overflow:hidden;
  border-radius:50%; background:radial-gradient(ellipse at 50% 40%, #2a4a45, #10201e 75%);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6);
}
.ccTabBild canvas { width:100%; height:100%; display:block; image-rendering:pixelated; }
.ccTabFarbe { display:block; width:66%; height:66%; border-radius:50%;
  /* Ein heller Ring, damit auch schwarzes Haar auf dunklem Glas als
     Farbpunkt lesbar bleibt. */
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.5), 0 0 0 1.5px rgba(200,230,222,.45), 0 0 6px rgba(0,0,0,.6); }
.ccTabTitel { font-size:calc(8.5px * var(--ccK, 1)); font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; white-space:nowrap; }

/* Die aufgeklappte Reihe: nur der offene Abschnitt ist sichtbar, ohne
   Überschrift (die steht auf dem Reiter). */
.ccBuehne .charGrid.pdCreator {
  position:static; display:flex; flex-direction:row; align-items:center;
  width:auto; max-width:none; gap:0; padding:0; overflow:visible;
}
.ccBuehne .charGrid .pdBlock { margin:0; flex-direction:row; align-items:center; gap:0;
  padding:calc(5px * var(--ccK, 1)) calc(8px * var(--ccK, 1));
  background:rgba(10,16,15,.72); border:1px solid rgba(111,122,118,.55);
  border-radius:calc(6px * var(--ccK, 1)); }
.ccBuehne .charGrid .pdBlock.hidden { display:none; }
.ccBuehne .charGrid .pdBlockKopf { display:none; }
/* Auf dem Blatt sind alle Reihen FLEX, auch Frisur und Bart: Das Raster
   (pdRaster, acht Spalten) ist für das alte Fenster gedacht. */
.ccBuehne .charGrid .pdOpts, .ccBuehne .charGrid .pdOpts.pdRaster, .ccBuehne .charGrid .pdOpts.pdRaster.pdKlein {
  display:flex; grid-template-columns:none; gap:calc(4px * var(--ccK, 1)); flex:none; flex-wrap:nowrap; }
.ccBuehne .charGrid .pdOpt { width:calc(30px * var(--ccK, 1)); height:calc(30px * var(--ccK, 1)); font-size:calc(12px * var(--ccK, 1)); padding:0; }
.ccBuehne .charGrid .pdThumb { width:calc(26px * var(--ccK, 1)); height:calc(26px * var(--ccK, 1)); }
.ccBuehne .charGrid .pdFarbe { width:calc(16px * var(--ccK, 1)); height:calc(16px * var(--ccK, 1)); }
/* NICHT die Köpfe in den Ovalen -- die sind auch .pdThumb und sollen ihre
   Fassung ganz füllen. */
.ccOval > canvas.pdThumb { width:100%; height:100%; }

/* ===================== DIE CHARAKTERAUSWAHL (15. September) =====================

   Oliver: *„Räume die character Liste auf mach sie so wie bei world of wacraft
   rechts einen scrollbares Ui mit dem Namen etc darunter Login usw links der
   character übernimm das Layout 1 zu 1 von wow du kannst dir dafür auch noch
   einen background rendern und animieren"*

   Der Aufbau ist damit festgelegt und hier ohne Erfindung umgesetzt:

       +--------------------------------------------------+
       |  [gemalter Hintergrund, Nebel zieht darüber]      |
       |                                          +-----+ |
       |            DIE FIGUR                     |Logo | |
       |            groß, auf einem Podest        |Liste| |
       |            Name darunter                 | (ro)| |
       |                                          |Knöpfe| |
       +--------------------------------------------------+

   Die Spalte rechts ist FEST breit und scrollt für sich; die Bühne links
   nimmt den Rest. Bei schmalen Fenstern (unter 900 Punkten) rutscht die
   Spalte über die Bühne -- ein Nebeneinander, das nicht nebeneinander passt,
   ist schlechter als ein Übereinander. */
#rosterScreen {
  display:flex; align-items:stretch; justify-content:flex-end;
  position:relative; overflow:hidden;
  background:#0a0709;
}

/* ---- Der Hintergrund, in Lagen ---- */
/* Das gemalte Bild steht still. Darüber ziehen zwei Nebelbänder verschieden
   schnell, und ein warmer Schein atmet über den Fackeln. Genau derselbe
   Gedanke wie beim Portal im Anmeldeschirm: Was sich bewegen soll, muss eine
   eigene Lage sein -- ein Bild, das als Ganzes wandert, sieht aus wie ein
   Fehler. */
/* Der VERLAUF unter dem Bild ist kein Schmuck, sondern die Rückfallebene:
   Fehlt roster_bg.jpg (frischer Abzug, Bild noch nicht gerendert), steht dort
   immer noch eine Nachtlandschaft und kein schwarzes Loch. Ein fehlendes Bild
   soll wie Absicht aussehen, nicht wie ein Fehler. */
#rosterHintergrund { position:absolute; inset:0; z-index:0; pointer-events:none;
  background:url('/assets/ui/roster_bg.jpg') center/cover no-repeat,
             radial-gradient(ellipse 90% 70% at 28% 68%, #2a2135 0%, #140f1b 55%, #0a0709 100%); }
/* Die Feuerleinwand liegt ÜBER dem Bild und unter dem Nebel: Funken, durch
   die Nebel zieht, gehören dahinter -- sonst schwebt der Funke vor der
   Wolke und das Bild bekommt zwei Tiefen. */
#rosterFeuer { position:absolute; inset:0; width:100%; height:100%; pointer-events:none; }
#rosterNebel { position:absolute; inset:0; overflow:hidden; }
/* DIE ZAHLEN SIND NACHGEMESSEN, NICHT GEFÜHLT.
   Der erste Entwurf zog den Nebel in 71 Sekunden um 26 % und war bei einer
   Deckkraft von 0,16 -- pw_test_auswahl §5 mass DREIEINHALB SEKUNDEN UND FAND
   NULL geänderte Bildpunkte. Die Bewegung lief nachweislich (der Transform
   wanderte um 34 Punkte), sie war nur unsichtbar. Eine Animation, die läuft
   und nichts bewegt, ist der häufigste Fehler bei so etwas -- und der
   ärgerlichste, weil im Stilblatt alles richtig aussieht.
   Jetzt: schneller, dichter, und zwei Bänder mit verschiedener Höhe, damit
   es nach Nebel aussieht und nicht nach einem wandernden Fleck. */
#rosterNebel i {
  position:absolute; left:-60%; top:0; width:220%; height:100%;
  background:
    radial-gradient(ellipse 52% 22% at 22% 76%, rgba(196,212,232,.34), rgba(0,0,0,0) 72%),
    radial-gradient(ellipse 40% 16% at 58% 86%, rgba(184,200,226,.28), rgba(0,0,0,0) 74%),
    radial-gradient(ellipse 60% 14% at 86% 70%, rgba(206,216,236,.22), rgba(0,0,0,0) 74%),
    radial-gradient(ellipse 34% 12% at 40% 62%, rgba(176,192,218,.18), rgba(0,0,0,0) 76%);
  will-change:transform;
}
#rosterNebel i:nth-child(1) { animation:rosterZug 38s linear infinite; }
#rosterNebel i:nth-child(2) { animation:rosterZug 61s linear infinite reverse; opacity:.75; }
/* scaleY gehört IN die Bildfolge, nicht daneben: Ein transform auf dem
   Element wird von der Animation überschrieben -- die zweite Lage war
   deshalb nie höher als die erste, obwohl es so dastand. */
@keyframes rosterZug { from { transform:translateX(0) scaleY(1.25); } to { transform:translateX(26%) scaleY(1.25); } }
/* Die Glut der Fackeln: ein warmer Schein, der langsam atmet. Er liegt im
   linken Drittel, weil die Fackeln dort gemalt sind. */
/* KEIN mix-blend-mode:screen. Über einem fast schwarzen Grund addiert screen
   praktisch nichts -- der Schein atmete von 0,6 auf 0,96 und auf dem Schirm
   blieb alles gleich. Normale Überlagerung, dafür gedämpfter. */
#rosterGlut {
  position:absolute; inset:0;
  background:radial-gradient(circle 24% at 21% 60%, rgba(255,172,86,.30), rgba(0,0,0,0) 72%),
             radial-gradient(circle 9% at 30% 52%, rgba(255,196,120,.22), rgba(0,0,0,0) 70%);
  animation:rosterAtem 5.2s ease-in-out infinite alternate;
}
@keyframes rosterAtem { from { opacity:.42; } to { opacity:1; } }
/* Und ein Rand, der abdunkelt -- damit die Spalte rechts auf etwas Ruhigem
   liegt und die Figur links im Licht steht. */
#rosterVignette {
  position:absolute; inset:0;
  background:linear-gradient(90deg, rgba(8,6,9,.55) 0%, rgba(8,6,9,0) 26%, rgba(8,6,9,0) 52%, rgba(8,6,9,.78) 86%, rgba(8,6,9,.9) 100%),
             radial-gradient(ellipse 80% 70% at 50% 50%, rgba(0,0,0,0) 40%, rgba(8,6,9,.6) 100%);
}
/* Wer keine Bewegung will, bekommt keine -- dieselbe Regel wie beim Portal. */
@media (prefers-reduced-motion: reduce) {
  #rosterNebel i:nth-child(1), #rosterNebel i:nth-child(2), #rosterGlut { animation:none; }
}

/* ---- Links: die Bühne ---- */
/* DIE FIGUR STEHT AUF DEM GEMALTEN PODEST -- und das ist keine Kleinigkeit.
   Zuerst war die Bühne eine Flex-Spalte, die den Rest der Breite nahm; die
   Figur stand damit in deren Mitte, also bei 38 % des Fensters. Das gemalte
   Rundpodest liegt aber bei 32 %, und die Fackeln davor bei 13 % und 21 %.
   Eine Figur, die neben ihrem Podest steht, sieht nicht aus wie eine Figur an
   der falschen Stelle -- sie sieht aus wie ein Fehler im Bild.
   Also absolut gesetzt, an den ausgemessenen Punkten des Hintergrunds
   (assets/ui/roster_bg.jpg, 1536x864: Podestmitte x=0,32, Standfläche
   y=0,79). Wer das Bild austauscht, zieht diese beiden Zahlen nach. */
/* DER FUSSPUNKT IST DIE ZAHL, NICHT DIE UNTERKANTE (15. September).
   Oliver, mit Bild: *„die Figur steht nicht auf dem Podest"*.

   Vorher war die Bühne eine Spalte aus Leinwand, Lichtfleck, Name und Zeile,
   unten am Fenster festgemacht (`bottom:9.5%`). Unten stand damit die
   UNTERKANTE DER SCHRIFT -- und die Füße der Figur landeten dort, wo die drei
   Dinge darunter sie hinschoben: bei 1600x900 auf y=672, also 0,747 des
   Bildes. Das gemalte Podest hat seine Standfläche aber zwischen 0,57 (hintere
   Kante) und 0,62 (vordere Kante). Die Figur stand also gute hundert Punkte
   davor, auf dem Pflaster, und schnitt mit dem Körper durch die Podestkante.
   Im Stilblatt war nichts falsch -- nur war die gemessene Zahl (0,79) die
   Unterkante der Leinwand und nicht der Punkt, auf dem die Figur steht.

   Jetzt hängt die Bühne am FUSSPUNKT. Der liegt bei 93 % der Leinwandhöhe
   (client.js, `ROSTER_FIGUR.fussAnteil` -- die Zahl steht DORT und nur dort,
   hier nur ihr Gegenstück), die restlichen 7 % sind Platz für den Schatten,
   dessen Halbachse 0,11 Figurgrößen misst. `--fussAbstand` rechnet diese
   5,5 % aus der wirklichen Leinwandhöhe aus, und die Bühne wird um genau
   diesen Betrag tiefer gesetzt -- damit steht der Fußpunkt bei 0,602 des
   Bildes, in der Mitte der Podestfläche. Wer das Bild austauscht, ändert die
   eine Zahl 39.8% und sonst nichts.

   DIESE 7 % STANDEN SCHON EINMAL HIER, und sie waren trotzdem falsch: Ich
   hatte angenommen, `drawCharacterSprite` bekomme den Fußpunkt. Sie bekommt
   die MITTE, der Fußpunkt liegt 0,42 Größen darunter, und damit lagen Füße
   und Schatten 78 Punkte UNTER der Leinwandkante -- abgeschnitten. Die Zahl
   im Stilblatt war zufällig richtig, die im Zeichner falsch; korrigiert wurde
   der Zeichner.

   Die Leinwand ist min(30vw, 420px) breit und 420x560 im Seitenverhältnis,
   ihre Höhe also min(40vw, 560px). */
#rosterBuehne {
  --figurH: min(40vw, 560px);
  --fussAbstand: calc(var(--figurH) * 0.07);
  position:absolute; z-index:1;
  /* 0,355 UND 0,602 SIND BILDBRUCHTEILE, KEINE FENSTERBRUCHTEILE.
     Der Hintergrund liegt als `cover` -- er füllt das Fenster und wird an der
     langen Seite beschnitten. Nur bei genau 16:9 sind Bild und Fenster
     deckungsgleich; sonst wandert eine der beiden Achsen. Deshalb zwei
     Rechnungen, die sich bei 16:9 treffen:
       bis 16:9  Höhe füllt, Breite wird beschnitten -> senkrecht in %,
                 waagerecht aus vh (Bildbreite = 1,7778 x Fensterhöhe).
       ab 16:9   Breite füllt, Höhe wird beschnitten -> die Kehrseite, unten.
     Probe bei 16:9: 50% - 35.02vh = 50% - 19,7% = 30,3%. Stimmt.

     0,303 IST DIE MITTE DER GEMALTEN PLATTE, nachgemessen an Olivers
     Schirmabzug (die Platte reicht von 0,217 bis 0,386). Hier stand 0,355 --
     ein Stück rechts, damit die Figur die zweite Feuerschale nicht verdeckt.
     Oliver, 15. September: *„der character muss noch ein bisschen nach links,
     so dass er in der mitte der plattform steht"*. Die Schale steht bei
     0,3025 und damit jetzt HINTER der Figur; ihre Flamme reicht über deren
     Kopf hinaus. Mitte der Platte schlägt freie Schale -- er hat recht: Eine
     Figur, die neben ihrem Podest steht, fällt auf, eine verdeckte Fackel
     nicht. */
  left:calc(50% - 35.02vh); bottom:calc(39.8% - var(--fussAbstand));
  transform:translateX(-50%);
  width:min(34vw, 460px);
  display:block;
  pointer-events:none;
}
#rosterFigur { display:block; margin:0 auto; width:min(30vw, 420px); height:auto; image-rendering:pixelated;
  filter:drop-shadow(0 18px 26px rgba(0,0,0,.6)); }
/* Ein Lichtfleck unter den Füßen: Er bindet die Figur an den Boden. Ohne ihn
   steht sie vor dem Bild statt darin. Er liegt ABSOLUT, damit er die Höhe der
   Bühne nicht mitbestimmt -- sonst schöbe der Lichtfleck die Figur genauso
   nach oben wie früher die Schrift. Und er sitzt mittig AUF dem Fußpunkt,
   nicht unter der Leinwandkante. */
#rosterFigurFuss {
  position:absolute; left:50%; transform:translateX(-50%);
  bottom:calc(var(--fussAbstand) - min(2.5vw, 33px));
  width:min(26vw, 340px); height:min(5vw, 66px);
  background:radial-gradient(ellipse 50% 50% at 50% 50%, rgba(255,196,122,.28), rgba(0,0,0,0) 70%);
}
/* Die Tafel: Name und Zeile, am unteren Rand verankert statt an der Figur. */
#rosterTafel {
  position:absolute; z-index:1;
  left:calc(50% - 35.02vh); bottom:9.5%; transform:translateX(-50%);
  width:min(34vw, 460px); text-align:center; pointer-events:none;
}
#rosterFigurName {
  font-size:clamp(20px, 2.1vw, 30px); font-weight:700;
  color:#f4e6c3; letter-spacing:.6px; text-shadow:0 2px 10px #000, 0 0 22px rgba(0,0,0,.9);
}
#rosterFigurZeile {
  margin-top:3px; font-size:clamp(12px, 1.1vw, 15px); color:#cbb98f;
  text-shadow:0 2px 8px #000; letter-spacing:.3px;
}

/* ---- Rechts: die Spalte ---- */
#rosterSpalte {
  position:relative; z-index:2; flex:0 0 auto;
  width:min(380px, 34vw); min-width:300px;
  display:flex; flex-direction:column; gap:10px;
  padding:18px 20px 20px; box-sizing:border-box;
  background:linear-gradient(180deg, rgba(16,12,9,.86), rgba(10,8,6,.94));
  border-left:1px solid rgba(227,189,109,.28);
  box-shadow:-12px 0 32px rgba(0,0,0,.55);
  max-height:100vh;
}
#rosterSpalte .creatorLogo {
  display:block; width:auto; max-width:100%; max-height:min(16vh, 130px);
  height:auto; margin:0 auto 2px; object-fit:contain;
}
#rosterSpalte .sub { margin:0; text-align:center; font-size:12.5px; color:var(--text-leise); line-height:1.5; }
#rosterSpalte #rosterMsg { margin:0; text-align:center; min-height:0; }
/* DIE UNGEWÄHLTEN KARTEN LEISER. `--linie` ist ein Goldton, und auf der
   dunklen Spalte sah damit JEDE Karte aus wie die gewählte -- die Auswahl war
   nicht mehr zu erkennen, und genau sie ist seit dem 15. September die Frage.
   Nur innerhalb der Auswahl gedämpft; im Spiel bleibt die Linie, wie sie ist. */
#rosterSpalte .rosterCard { border-color:rgba(227,189,109,.12); background:rgba(26,20,14,.55); }
#rosterSpalte .rosterCard:hover { border-color:rgba(227,189,109,.4); background:rgba(40,31,20,.7); }
/* DIE DREI KNÖPFE UNTER DER LISTE -- „darunter Login usw". Betreten ist der
   Hauptweg und sieht auch so aus; Löschen ist die Ausnahme und steht leise
   daneben, nicht darüber. */
#rosterKnoepfe { display:flex; flex-direction:column; gap:7px; flex-shrink:0; }
/* DIE KNÖPFE SEHEN AUS WIE DAS SPIEL, nicht wie der Browser. Beim ersten
   Versuch standen dort drei weiße Systemknöpfe auf einer dunklen Tafel -- der
   hellste Fleck im ganzen Bild, und ausgerechnet unten rechts. */
/* NUR NOCH GRÖSSE. Grund, Schrift und Rand kommen aus der Grundform. */
#rosterKnoepfe button {
  width:100%; box-sizing:border-box;
  padding:9px 12px; font-size:13px; letter-spacing:.4px;
}
#rosterKnoepfe button:hover:not(:disabled) {
  background:linear-gradient(180deg, rgba(66,52,32,.9), rgba(32,24,16,.95));
  border-color:rgba(227,189,109,.7); color:#f4e6c3;
}
/* „Betreten" ist der Hauptweg und darf das auch zeigen: golden, etwas höher,
   in Versalien. Die beiden anderen bleiben leiser. */
#rosterKnoepfe #rosterBetreten {
  padding:12px 12px; font-size:14px; font-weight:700; text-transform:uppercase;
  color:#f4e6c3; border-color:rgba(227,189,109,.62);
  background:linear-gradient(180deg, rgba(122,94,46,.9), rgba(58,42,20,.95));
  text-shadow:0 1px 2px rgba(0,0,0,.8);
}
#rosterKnoepfe #rosterBetreten:hover:not(:disabled) {
  background:linear-gradient(180deg, rgba(160,124,58,.95), rgba(78,56,26,.98));
  border-color:var(--gold);
}
#rosterKnoepfe .gefahrBtn { background:transparent; border:1px solid rgba(226,105,95,.35); color:#c99189; font-size:12.5px; padding:7px 10px; }
#rosterKnoepfe .gefahrBtn:hover:not(:disabled) { border-color:rgba(226,105,95,.8); color:#e2695f; }
#rosterKnoepfe button:disabled { opacity:.38; cursor:not-allowed; filter:none; }

/* BREITE FENSTER (breiter als 16:9). Jetzt füllt das Bild die BREITE, und
   beschnitten wird oben und unten -- die senkrechten Bildbruchteile stimmen
   nicht mehr mit den Fensterbruchteilen überein. Bildhöhe auf dem Schirm =
   0,5625 x Fensterbreite, Mitte auf Fenstermitte. Der Fußpunkt bei 0,602 des
   Bildes liegt damit bei 50% + 5,74vw von oben.
   Probe bei genau 16:9: 50% - 5.74vw = 50% - 10,2% = 39,8%. Dieselbe Zahl wie
   oben -- die beiden Rechnungen gehen ohne Sprung ineinander über. */
@media (min-aspect-ratio: 16/9) {
  #rosterBuehne { left:30.3%; bottom:calc(50% - 5.74vw - var(--fussAbstand)); }
  #rosterTafel { left:30.3%; }
}

/* SCHMALE FENSTER: Die Spalte legt sich über die Bühne, statt sie zu
   erdrücken. Unter 900 Punkten Breite bliebe für die Figur sonst ein
   Streifen. */
/* SCHMALE FENSTER: Die Spalte liegt ohnehin am rechten Rand; hier rückt nur
   die Figur weiter nach links, damit sie nicht dahinter verschwindet. */
@media (max-width: 900px) {
  #rosterSpalte { width:min(340px, 82vw); }
  /* --figurH muss mitwandern: Die Leinwand ist hier min(46vw, 340px) breit,
     ihre Höhe also das Vierdrittelfache davon. Ohne diese Zeile rechnete der
     Fußabstand weiter mit der grossen Leinwand, und die Figur stünde im
     schmalen Fenster wieder neben dem Podest. */
  /* `left` bleibt bei der Rechnung von oben -- sie trifft das Podest auch
     hier (bei 860x720 liegt die Figur 37 Punkte rechts der Podestmitte, und
     die Platte ist 279 breit). Hier stand `left:26%`, eine Fensterzahl, die
     das Bild nicht kannte. */
  #rosterBuehne { width:min(46vw, 340px); --figurH: min(61.33vw, 453px); }
  #rosterFigur { width:min(46vw, 340px); }
  #rosterTafel { width:min(46vw, 340px); }
}

/* Die alte Karte bleibt für den Charaktereditor (creatorScreen) -- dort ist
   eine mittige Spalte genau richtig. */
.creatorCard {
  width:min(560px, 92vw); max-height:calc(100vh - 40px);
  display:flex; flex-direction:column; gap:12px;
  padding:20px 22px; box-sizing:border-box;
}
.creatorCard .creatorLogo {
  display:block; width:auto; max-width:100%; max-height:min(26vh, 210px);
  height:auto; margin:0 auto; object-fit:contain;
}
.creatorCard .sub { margin:0; text-align:center; }
.creatorCard #rosterMsg { margin:0; text-align:center; min-height:0; }
.creatorCard #newCharBtn { flex-shrink:0; }
/* SCROLLBAR, und das ist der Punkt („rechts einen scrollbares Ui"): Die
   Liste nimmt, was zwischen Logo und Knöpfen übrig ist, und rollt FÜR SICH.
   Wer zwölf Figuren hat, schiebt damit nicht die Knöpfe aus dem Bild. */
.rosterList { display:flex; flex-direction:column; gap:7px; flex:1 1 auto; min-height:0;
  overflow-y:auto; overflow-x:hidden; padding-right:5px; text-align:left; }
/* Ein schmaler, dunkler Balken statt des hellen Systembalkens -- der wäre
   auf dieser Tafel der hellste Fleck im Bild. */
.rosterList::-webkit-scrollbar { width:8px; }
.rosterList::-webkit-scrollbar-track { background:rgba(0,0,0,.35); }
.rosterList::-webkit-scrollbar-thumb { background:rgba(227,189,109,.28); border-radius:4px; }
.rosterList::-webkit-scrollbar-thumb:hover { background:rgba(227,189,109,.5); }
.rosterEmpty { color:var(--text-leise); font-size:13px; text-align:center; padding:22px 0; }
.rosterCard {
  display:flex; align-items:center; gap:10px; padding:8px 10px;
  border:1px solid var(--linie); background:var(--feld); cursor:pointer; text-align:left;
  transition:border-color .12s ease, background .12s ease;
}
.rosterCard:hover { background:var(--feld-hell); border-color:var(--sand-leise); }
/* DIE GEWÄHLTE KARTE. Sie muss sich vom Überfahren unterscheiden, sonst weiß
   man beim Wandern mit der Maus nicht mehr, wer eigentlich gewählt ist --
   und genau das ist seit dem 15. September die Frage, denn der Klick wählt
   nur noch aus. Goldene Kante plus eine Marke am linken Rand. */
.rosterCard.gewaehlt {
  border-color:var(--gold); background:rgba(227,189,109,.10);
  box-shadow:inset 3px 0 0 var(--gold), 0 0 0 1px rgba(227,189,109,.22);
}
.rosterCard.gewaehlt .rosterName { color:#f4e6c3; }
.rosterCard.gewaehlt .rosterGo { color:var(--gold); }
.rosterCard canvas { width:46px; height:46px; image-rendering:pixelated; flex-shrink:0; }
/* Umbruch VERBIETEN und lieber abschneiden: In der schmalen Spalte brach
   „Stufe 12 · Edin — Der Außenposten · 0k" in fünf Zeilen um, und die
   Karte wurde dreimal so hoch wie nötig. Drei sichtbare Figuren statt
   acht -- für eine Auskunft, die ohnehin unter dem Namen steht. */
.rosterInfo > * { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rosterMetaLeise { color:var(--text-fern); font-size:11px; }
.rosterInfo { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.rosterName { font-size:14.5px; font-weight:700; color:var(--text); }
.rosterMeta { font-size:11.5px; color:var(--text-leise); }
.rosterGo { font-size:12px; color:var(--sand); font-weight:700; flex-shrink:0; }
.rosterDot { display:inline-block; width:7px; height:7px; border-radius:50%; background:var(--linie); margin-right:6px; vertical-align:middle; }
.rosterDot.online { background:var(--gruen); box-shadow:0 0 6px rgba(169,201,141,.7); }

/* ---------- Einen Charakter löschen ----------
   Oliver, 11. September: „characktere müssen löschbar sein, mülleimer neben
   dem character namen dann eine sicherheitsabfrage, name des characters
   eintippen dann erscheint ein lösch knopf".

   Der Mülleimer ist bewusst LEISE: Er steht neben dem Namen, wird aber erst
   deutlich, wenn die Maus darüber liegt. Eine Karte, auf der das Löschen so
   laut ist wie das Weiterspielen, lädt zum Verklicken ein. */
.rosterWeg {
  flex-shrink:0; background:transparent; border:1px solid transparent;
  color:var(--text-leise); font-size:15px; line-height:1; padding:6px 8px;
  cursor:pointer; opacity:.35; transition:opacity .12s ease, color .12s ease, border-color .12s ease;
}
.rosterCard:hover .rosterWeg { opacity:.8; }
.rosterWeg:hover { opacity:1; color:#e2695f; border-color:rgba(226,105,95,.45); }
.rosterPlaetze { margin:0 0 4px; font-size:12px; color:var(--text-leise); text-align:center; }
#newCharBtn:disabled { opacity:.4; cursor:not-allowed; filter:none; }

/* Die Abfrage liegt über allem -- auch über dem Spielbildschirm, falls
   jemand sie aus einer laufenden Sitzung heraus öffnet. */
.loeschHinter {
  position:fixed; inset:0; z-index:120; background:rgba(0,0,0,.72);
  display:flex; align-items:center; justify-content:center; padding:20px;
}
.loeschKasten {
  width:min(420px, 100%); background:var(--feld); border:1px solid var(--linie);
  padding:22px 24px; text-align:left; display:flex; flex-direction:column; gap:12px;
}
.loeschKasten h3 { margin:0; font-size:18px; color:var(--text); }
.loeschWarnung { margin:0; font-size:13px; color:var(--text-leise); line-height:1.5; }
.loeschLeise { color:var(--text-leise); opacity:.7; font-size:12px; }
.loeschLabel { font-size:13px; color:var(--text-leise); }
.loeschLabel b { color:var(--text); }
.loeschFeld {
  width:100%; box-sizing:border-box; padding:9px 11px; font-size:14px;
  background:var(--feld-hell); border:1px solid var(--linie); color:var(--text);
}
.loeschFehler { margin:0; min-height:16px; font-size:12px; color:#e2695f; }
.loeschKnoepfe { display:flex; gap:10px; justify-content:flex-end; }
.loeschJetzt {
  background:#7e2f2a; border:1px solid #a3453d; color:#f6e7e4;
  font-size:13px; padding:10px 18px; cursor:pointer;
}
.loeschJetzt:hover { background:#93362f; }
.loeschJetzt:disabled { opacity:.5; cursor:progress; }
/* Der Knopfbalken sitzt UNTEN und geht nicht mit auf Reisen: Die Optionen
   scrollen fuer sich, "Reise beginnen" bleibt immer sichtbar und erreichbar.
   Vorher schwamm er mitten in den Farbpunkten. */
.creatorActions { display:flex; gap:12px; justify-content:center; align-items:center;
  flex-shrink:0; margin-top:18px; padding-top:16px; border-top:1px solid var(--linie); }
.ghostBtn { background:transparent; border:1px solid var(--linie); color:var(--text-leise); font-weight:400; font-size:13px; padding:10px 20px; }
.ghostBtn:hover { color:var(--text); border-color:var(--sand-leise); filter:none; }

/* EIN KNOPF, DER GERADE NICHTS ZU ZEIGEN HAT.
   Der Helmschalter, solange kein Helm angelegt ist: Er bleibt bedienbar (die
   Einstellung wird ja gemerkt), sagt aber schon von weitem, dass hier nichts
   passieren wird. Das ist ehrlicher als ein Knopf, der aussieht wie jeder
   andere und stumm bleibt -- genau die Beschwerde vom 11. September. */
#helmSchalter.leerlauf { opacity:.45; }

/* ---------- Spiel ---------- */
#gameScreen { position:relative; background:#000; }
#gameCanvas { display:block; width:100%; height:100%; cursor:crosshair; }
#topBar {
  position:absolute; top:0; left:0; right:0; display:flex; justify-content:space-between;
  align-items:center; padding:10px 16px;
  background:linear-gradient(180deg, rgba(15,11,7,.88), transparent); z-index:5;
}
#topBarLeft { display:flex; align-items:center; gap:10px; pointer-events:none; }
#planetInfo #planetName { font-weight:700; font-size:16px; margin-right:10px; color:var(--text); }
#planetInfo #planetDesc { font-size:12px; color:var(--text-leise); }
/* ---------- Die Minimap ----------
   Rund, wie man sie kennt -- das Runde ist keine Zier: Ein Kreis hat keine
   Ecken, in denen sich die Frage "wie weit ist die Ecke weg?" stellt. Sie
   liegt unter der Kopfleiste, rechts, wo im Spiel nichts anderes hinsieht. */
#minimap {
  position:absolute; top:52px; right:14px; z-index:8;
  width:176px; display:flex; flex-direction:column; align-items:center; gap:4px;
  pointer-events:none;
}
/* Die Tag-und-Nacht-Scheibe sitzt in der linken oberen Ecke des Kreises,
   wie ein kleiner Mond neben einem großen. */
#minimapUhr {
  position:absolute; left:-2px; top:-2px; width:36px; height:36px; z-index:2;
  border-radius:50%; pointer-events:auto;
  box-shadow:0 3px 10px rgba(0,0,0,.6);
}
#minimapCanvas {
  width:176px; height:176px; border-radius:50%;
  border:3px solid #6b563c; box-shadow:0 0 0 1px #2a2119, 0 8px 22px rgba(0,0,0,.6),
    inset 0 0 26px rgba(0,0,0,.65);
  background:#0d0a07; pointer-events:auto; image-rendering:pixelated;
}
#minimapOrt {
  font-size:10.5px; letter-spacing:.06em; color:var(--sand); text-align:center;
  text-shadow:0 1px 3px #000, 0 0 6px #000; max-width:176px; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis;
}
#minimapSuche { display:flex; gap:3px; pointer-events:auto; }
#minimapSuche button {
  width:30px; height:24px; padding:0; font-size:12px; line-height:1;
  background:rgba(36,28,20,.92); color:var(--text-leise); border:1px solid var(--linie);
  cursor:pointer; font-family:inherit;
}
#minimapSuche button:hover { border-color:var(--sand); color:var(--text); }
#minimapSuche button.aktiv { border-color:var(--gold); color:#ffe9a8; background:#3b2f1e; }
#minimapZoom { width:34px !important; font-size:10.5px !important; font-weight:700; }

#onlineCount, #creditsCount {
  font-size:12.5px; background:rgba(36,28,20,.9); border:1px solid var(--linie);
  padding:4px 10px; pointer-events:none;
}
/* DER ZÄHLER IST EIN KNOPF, SOBALD ER ETWAS ZU SAGEN HAT (20. September).
   `pointer-events:none` stand dort, solange die Zahl nur Schmuck war -- jetzt
   führt sie zur Liste, und was man anklicken kann, muss man anklicken können.
   Hervorgehoben wird er erst ab zwei: Eine „1", die leuchtet, wäre ein
   Versprechen, das niemand einlöst. */
#onlineCount { cursor:pointer; pointer-events:auto; transition:color .3s, border-color .3s; }
#onlineCount.mehrere { color:var(--gold); border-color:var(--gold); }
#creditsCount { color:var(--gold); }
/* Der Rückweg zum Kosmos war ein 34px-Kästchen mit einem Sternsymbol darin --
   auf einer 256x256-Welt sucht man den eine Weile. Jetzt beschriftet und breit
   genug, dass er nicht umbricht. */
#returnToCloudBtn {
  pointer-events:auto; white-space:nowrap; height:32px; padding:0 14px;
  border:1px solid var(--linie); background:rgba(36,28,20,.94); color:var(--text);
  font-size:12.5px; font-weight:700; font-family:inherit; cursor:pointer; flex-shrink:0;
}
#returnToCloudBtn:hover { border-color:var(--sand-leise); background:var(--feld-hell); }
#returnToCloudBtn.dimmed { opacity:.5; }

/* ---------- Lebensanzeige oben links ----------
   Im Kampf schaut man dorthin, wo die eigene Figur ist -- also nach oben links,
   und groß genug, dass ein Blick reicht. */
/* Unit-Frame oben links: Porträt links, Leisten rechts daneben. */
/* ---------------------------------------------------------------------------
   DIE LEISTE -- Leben, Ressource und Fähigkeiten auf einem Band
   ---------------------------------------------------------------------------
   Die Maße stammen alle aus EINEM Bild (assets/ui/leiste.png, 1000x183) und
   stehen deshalb in Prozent: Wer die Leiste breiter zieht, verschiebt keine
   einzige Fassung. Ausgemessen wurde das Bild einmal (die Zahlen stehen in
   client.js bei LEISTE_PLAETZE), nicht geschätzt.

   Das Porträt und die alte Lebensleiste oben links sind weg. Sie standen dort,
   wo man im Kampf NICHT hinsieht.                                            */
.vitalTrack { position:relative; height:26px; background:var(--feld); border:1px solid var(--linie); overflow:hidden; }
.vitalFill { height:100%; transition:width .25s ease; }
.vitalLabel { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:var(--text); text-shadow:0 1px 3px rgba(0,0,0,.9); }

/* ================= DIE AKTIONSLEISTE (15. September, neu) =================

   Oliver: *„Die Aktionsleiste wirkt etwas starr und past nicht recht zum
   Rest des UIs"*.

   SIE WAR EIN BILD. assets/ui/leiste.png, 1000x183 Punkte, jeder Platz auf
   einem ausgemessenen Prozentwert darin. Deshalb konnte sie dreizehn
   Fassungen haben und nie vierzehn, nicht wachsen, nicht schrumpfen -- und
   deshalb passte sie nicht: Das übrige Fenster besteht aus dunklen Tafeln mit
   goldener Haarlinie, und mittendrin lag ein gemaltes Messingband.

   Jetzt ist sie gebaut wie jede andere Tafel. Drei Größen bestimmen alles:

     --slotGr     Kantenlänge eines Feldes
     --slotLuft   Abstand zwischen zwei Feldern
     --leisteSp   Felder je Reihe (nur zur Erinnerung; gesetzt wird in JS)

   Wer sie ändert, ändert die ganze Leiste -- es gibt keine zweite Stelle. */
#actionDock { position:absolute; bottom:0; left:50%; transform:translateX(-50%); z-index:6;
  display:flex; flex-direction:column; align-items:center; gap:4px; pointer-events:none; }

#leiste {
  --slotGr:42px;
  --slotLuft:4px;
  position:relative; display:flex; align-items:flex-end; gap:10px;
  padding:7px 12px 8px; pointer-events:auto; user-select:none;
  /* Dieselbe Tafel wie überall: dunkler Grund, goldene Haarlinie, ein Hauch
     Licht von oben. Kein Messing, kein Nietenband -- die Leiste soll zum
     Fenster gehören und nicht das Fenster sein. */
  background:linear-gradient(180deg, rgba(28,22,16,.93), rgba(14,11,8,.96));
  border:1px solid rgba(227,189,109,.34);
  border-bottom:none;
  border-radius:9px 9px 0 0;
  box-shadow:0 -2px 18px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,235,190,.10);
}
/* Drei Größen, ein Wert. „Klein" ist für 1366er Laptops gedacht, „groß" für
   alles ab WQHD -- die Leiste bleibt dabei physisch gleich lesbar, statt mit
   dem Fenster mitzuwachsen. */
#leiste.klein { --slotGr:34px; --slotLuft:3px; }
#leiste.gross { --slotGr:52px; --slotLuft:5px; }

#leisteMitte { display:flex; flex-direction:column; gap:5px; align-items:center; }

/* Der Erfahrungsbalken über den Feldern, über die ganze Breite der Reihen.
   Lila bleibt lila: Erfahrung ist weder Leben noch Kraft, und drei Farben für
   drei Dinge sind der ganze Sinn der Sache. */
#xpBar { position:relative; width:100%; height:11px; pointer-events:none; }

/* ---- Die Reihen ---- */
#abilityBar { display:flex; flex-direction:column-reverse; gap:var(--slotLuft); }
/* column-reverse: Reihe 1 liegt UNTEN, direkt über dem Bildschirmrand, und
   jede zugeschaltete Reihe wächst nach oben. Andersherum verschöbe das
   Zuschalten einer Reihe die Tasten 1..9 unter dem Daumen. */
.leisteReihe { display:flex; gap:var(--slotLuft); }

.abilitySlot {
  position:relative; box-sizing:border-box;
  width:var(--slotGr); height:var(--slotGr);
  background:linear-gradient(180deg, rgba(46,36,24,.72), rgba(20,15,10,.85));
  border:1px solid rgba(227,189,109,.28);
  border-radius:5px;
  cursor:pointer; pointer-events:auto;
  box-shadow:inset 0 1px 0 rgba(255,235,190,.07);
  transition:border-color .12s, box-shadow .12s, background .12s;
}
.abilitySlot:hover { background:linear-gradient(180deg, rgba(66,52,32,.8), rgba(30,22,14,.9));
  border-color:rgba(227,189,109,.6); box-shadow:0 0 0 1px rgba(227,189,109,.25), inset 0 1px 0 rgba(255,235,190,.12); }
.abilitySlot .slotKey { position:absolute; top:1px; left:3px; font-size:9px; line-height:1;
  color:#c9b98f; text-shadow:0 1px 2px #000; z-index:2; pointer-events:none; }
#leiste.ohneTasten .slotKey { display:none; }
/* DAS ICON IST DIE ANZEIGE (15. September, abends).
   -----------------------------------------------------------------------
   Oliver: *„lass die icons selbst die progressionsbar sein, von entsättigt
   (betätigt) auf hell (wieder verfügbar), von oben nach unten."*

   Die MECHANIK stimmte schon: Der Überlagerer sitzt unten und schrumpft nach
   unten weg -- oben wird also zuerst wieder frei, genau die Richtung, die
   Oliver nennt. Falsch war nur, WAS er tut: Er legte einen fast schwarzen
   Schleier über das Feld. Ein Knopf, der abkühlt, sah aus wie ein Knopf, der
   fehlt.

   Jetzt entsättigt er, was unter ihm liegt, statt es zuzudecken
   (`backdrop-filter`). Das Zeichen bleibt lesbar -- man sieht die ganze Zeit,
   WELCHE Fähigkeit da abkühlt, und der helle Teil wandert von oben herunter.

   Die Kante oben ist eine Haarlinie, kein Balken: Sie macht die Bewegung
   sichtbar, auch wenn der Unterschied zwischen grau und farbig bei einem
   26-Punkt-Zeichen klein ist.

   OHNE `backdrop-filter` (ältere Browser) greift der @supports-Block darunter
   und es bleibt beim Schleier -- lieber die alte Anzeige als gar keine. */
.abilitySlot .cooldownOverlay { position:absolute; left:0; right:0; bottom:0;
  background:rgba(8,6,3,.42);
  backdrop-filter:grayscale(1) brightness(.4) contrast(.85);
  -webkit-backdrop-filter:grayscale(1) brightness(.4) contrast(.85);
  border-top:1px solid rgba(255,240,196,.62);
  box-shadow:0 -1px 4px rgba(255,230,170,.18);
  transition:height .2s linear; pointer-events:none; border-radius:0 0 4px 4px; }
@supports not (backdrop-filter:grayscale(1)) {
  .abilitySlot .cooldownOverlay { background:rgba(10,7,4,.72); border-top:none; }
}
/* Bei Höhe null darf keine Linie stehenbleiben -- sonst liegt auf jedem
   fertigen Knopf ein heller Strich am unteren Rand. */
.abilitySlot .cooldownOverlay[style*="height:0%"],
.abilitySlot .cooldownOverlay[style*="height: 0%"] { border-top:none; }
/* Die Rolle steht als Kante unten am Feld -- man sieht auf einen Blick, was
   Angriff, was Schutz und was Heilung ist, ohne ein Symbol zu deuten. */
.abilitySlot.roleTank { box-shadow:inset 0 -2px 0 var(--sand-leise); }
.abilitySlot.roleHeal { box-shadow:inset 0 -2px 0 var(--gruen); }
.abilitySlot.roleDd   { box-shadow:inset 0 -2px 0 var(--rot); }
.abilitySlot.basicAttack { box-shadow:inset 0 -2px 0 var(--gold); }
.abilitySlot.basicAttack.noTarget { filter:grayscale(.7) brightness(.8); }
.abilitySlot.basicAttack.autoOn { border-color:var(--gold); animation:swingPulse 1.5s linear infinite; }
.abilitySlot .slotIcon { position:absolute; inset:0; margin:auto; display:flex; align-items:center; justify-content:center;
  font-size:calc(var(--slotGr) * 0.58); pointer-events:none; }
.abilitySlot .slotKosten { position:absolute; right:2px; bottom:0; font-size:9px; color:#9ad7ff; text-shadow:0 1px 2px #000; z-index:2; pointer-events:none; }
.abilitySlot.leer { background:rgba(22,17,12,.55); border-style:dashed; border-color:rgba(227,189,109,.16); cursor:default; }
.abilitySlot.leer:hover { background:rgba(40,31,20,.6); border-color:rgba(227,189,109,.34); }
.abilitySlot.zielAktiv { border-color:var(--gold); box-shadow:0 0 0 2px rgba(227,189,109,.45); }
/* GESPERRT heisst: anklicken ja, verschieben nein. Wer seine Leiste einmal
   eingerichtet hat, soll sie im Kampf nicht versehentlich umbauen. */
#leiste.gesperrt .abilitySlot { cursor:pointer; }

/* ---- Die beiden Kugeln ---- */
/* Sie hingen in Löchern des gemalten Bandes. Jetzt haben sie eine eigene
   Fassung: ein Ring aus derselben goldenen Haarlinie wie die Tafel. */
.kugelFassung { position:relative; width:calc(var(--slotGr) * 1.62); height:calc(var(--slotGr) * 1.62);
  border-radius:50%; flex:0 0 auto;
  border:1px solid rgba(227,189,109,.42);
  box-shadow:0 2px 10px rgba(0,0,0,.6), inset 0 0 0 2px rgba(0,0,0,.5);
  background:#0a0709; }
.kugel { position:absolute; inset:2px; border-radius:50%; overflow:hidden;
  background:radial-gradient(circle at 38% 30%, #241d26, #08060a 70%);
  pointer-events:auto; }
/* EINE LEERE KUGEL BLEIBT EINE KUGEL. Wer keinen Weg gewählt hat, hat keine
   Ressource; die Fassung bleibt trotzdem, nur dunkel. Die allgemeine
   .hidden-Regel würde sie ganz entfernen -- hier ausdrücklich überstimmt. */
.kugel.hidden { display:block; }
.kugel.hidden .kugelFuell, .kugel.hidden .kugelWert { display:none; }
/* Glas: ein Lichtreflex über der Füllung. Er macht aus der flachen Scheibe
   eine Kugel, ohne dass dafür ein zweites Bild nötig wäre. */
.kugel::after {
  content:''; position:absolute; inset:0; z-index:2; pointer-events:none;
  border-radius:50%;
  background:radial-gradient(circle at 36% 26%, rgba(255,255,255,.32), rgba(255,255,255,.06) 38%, rgba(0,0,0,0) 62%),
             radial-gradient(circle at 50% 118%, rgba(255,255,255,.14), rgba(0,0,0,0) 55%);
  box-shadow:inset 0 0 14px rgba(0,0,0,.75);
}
/* BEDROHUNG (alpha_playtest.md, Punkt 15): Wer das Ziel einer Kreatur ist,
   sieht es an seiner Lebenskugel -- ein roter Ring, und beim Boss pulst er.
   overflow:hidden der Kugel frisst den Schatten, also liegt der Ring als
   eigenes Element darüber. */
#bedrohungRing { position:absolute; inset:-2px; border-radius:50%; pointer-events:none; z-index:3; display:none; box-sizing:border-box; }
#bedrohungRing.an { display:block; border:3px solid rgba(220,70,50,.85); box-shadow:0 0 12px rgba(220,70,50,.7); }
#bedrohungRing.boss { display:block; border:4px solid #ff5a3c; box-shadow:0 0 18px rgba(255,90,60,.9); animation:bedrohtPuls .9s ease-in-out infinite alternate; }
@keyframes bedrohtPuls { from { box-shadow:0 0 8px rgba(255,90,60,.5); } to { box-shadow:0 0 24px rgba(255,90,60,1); } }
#targetFrame .tZiel { font-size:11px; margin-top:2px; color:var(--text-fern); }
#targetFrame .tZiel.dich { color:#ff8a6a; font-weight:700; }
/* Von UNTEN füllen, nicht von links: Eine Kugel, die sich seitlich leert,
   sieht aus wie ein Fehler. Der Wert ist die Höhe. */
.kugelFuell { position:absolute; left:0; right:0; bottom:0; height:100%;
  transition:height .25s ease; }
#hpFill { background:linear-gradient(180deg,#d8493c,#7a1f18); }
#resFill { background:linear-gradient(180deg,#4aa8ff,#17406e); }
.kugelWert { position:absolute; inset:0; z-index:3; display:flex;
  align-items:center; justify-content:center; pointer-events:none;
  font-size:calc(var(--slotGr) * 0.26); font-weight:700; color:#f3e9d6;
  text-shadow:0 1px 3px #000, 0 0 6px #000; letter-spacing:.3px; }

/* ---- Das Zahnrad und sein Menü ---- */
#leisteZahnrad { position:absolute; right:2px; top:-11px;
  width:20px; height:20px; padding:0; line-height:18px; font-size:12px;
  background:rgba(20,15,10,.92); color:#c9b98f; cursor:pointer; pointer-events:auto;
  border:1px solid rgba(227,189,109,.34); border-radius:5px; }
#leisteZahnrad:hover { color:#f0dfae; border-color:rgba(227,189,109,.7); }
/* ÜBER der Leiste, nicht darunter. Im Markup steht es dahinter (dort gehört
   es hin: es beschreibt sie), aber unten am Bildschirmrand ist unter der
   Leiste nichts mehr -- beim ersten Versuch stand das halbe Menü ausserhalb
   des Bildes und im Chat. `order` dreht nur die Anzeige, nicht den Baum. */
#leisteMenue { order:-1; pointer-events:auto; align-self:flex-end; margin-bottom:2px;
  /* Schmal halten: Ohne Deckel wird das Menü so breit wie sein längster
     Satz -- beim ersten Versuch über siebenhundert Punkte, quer über das
     halbe Bild und unter das Chatfenster. */
  min-width:250px; max-width:320px; box-sizing:border-box; padding:10px 12px 11px;
  background:linear-gradient(180deg, rgba(28,22,16,.97), rgba(14,11,8,.98));
  border:1px solid rgba(227,189,109,.4); border-radius:8px;
  box-shadow:0 6px 22px rgba(0,0,0,.7); font-size:12px; color:var(--text); }
#leisteMenue.hidden { display:none; }
.lmKopf { font-weight:700; color:var(--gold); letter-spacing:.4px; margin-bottom:7px; }
.lmZeile { display:flex; align-items:center; justify-content:space-between; gap:10px;
  margin:5px 0; cursor:pointer; }
.lmKnoepfe { display:flex; gap:3px; }
.lmKnoepfe button { min-width:26px; padding:2px 6px; font-size:11px; cursor:pointer;
  background:rgba(46,36,24,.7); color:var(--text); border:1px solid rgba(227,189,109,.28); border-radius:4px; }
.lmKnoepfe button.an { background:rgba(227,189,109,.24); border-color:var(--gold); color:#f4e6c3; }
.lmFuss { margin-top:9px; padding-top:8px; border-top:1px solid rgba(227,189,109,.18);
  color:var(--text-leise); font-size:11px; line-height:1.45; }

.xpTrack { position:relative; height:100%; background:rgba(10,7,12,.85);
  border:1px solid rgba(0,0,0,.6); overflow:hidden;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.8); }
#xpBar .xpFill { background:linear-gradient(180deg,#b07bff,#5b2f9e);
  box-shadow:0 0 8px rgba(176,123,255,.55); }
.xpLabel { position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:clamp(8px, 0.72vw, 11px); font-weight:700; color:#efe6f7;
  text-shadow:0 1px 3px #000, 0 0 5px #000; letter-spacing:.3px; }

.barRow { display:flex; align-items:center; gap:8px; }
.barLabel { font-size:11px; color:var(--text-leise); min-width:64px; text-align:right; }
.barTrack { flex:1; height:14px; background:var(--feld); border:1px solid var(--linie); overflow:hidden; }
.barFill { height:100%; transition:width .25s ease; }
.hpFill { background:linear-gradient(90deg,#a8442f,#d9704d); }
/* Die Erfahrungsleiste ist violett: sie gehört zur Geschichte, nicht zum Kampf,
   und muss sich auf einen Blick vom Rot des Lebens unterscheiden. */
.xpFill { height:100%; width:0%; background:linear-gradient(90deg,#6b4a8f,#b99ad2); transition:width .25s ease; }
/* ---- Das Handwerk im Zauberbuch ---- */
.zauberBerufe { padding:6px 14px 10px; display:flex; flex-direction:column; gap:6px;
  border-bottom:1px solid var(--linie-leise); margin-bottom:8px; }
.zauberBerufe.hidden { display:none; }
/* `.sectionLabel` stand im Skillbaum-Fenster mit einem eigenen Innenabstand
   im Markup; auf der Buchseite steht er hier, damit er nicht an jeder Zeile
   wiederholt wird. */
.buchSeite .sectionLabel { padding:0 14px; }
.berufEintrag {
  display:flex; align-items:center; gap:11px; width:100%; text-align:left;
  padding:9px 11px; background:var(--feld); border:1px solid var(--linie);
  color:var(--text); font-family:inherit;
  /* KEIN cursor:grab. Hier stand einer, und er hat nie gewirkt: Weiter unten
     in dieser Datei nagelt eine Regel mit !important EINEN Mauszeiger für das
     ganze Spiel fest (assets/ui/cursor.png) -- mit voller Absicht und mit
     einer Begründung, die dort steht. Eine Zeile, die nie greift, ist
     schlimmer als keine: Sie sieht aus wie eine Lösung.
     Dass ein Handwerk ziehbar ist, sagt deshalb der Hinweistext am Eintrag
     (client.js, refreshSpellbook) -- und das Aufhellen beim Überfahren. */
  transition:border-color .12s ease, background .12s ease;
}
/* Ein Handwerk auf der Leiste: dieselbe Ecke wie Preis und Stückzahl,
   diesmal der Fertigkeitsstand. Es ist dieselbe Frage -- wie weit bin ich? */
.abilitySlot.leisteBeruf .slotAnzahl { color:#a8d8a0; }
.abilitySlot.leisteBeruf.leerVorrat { filter:grayscale(.85) brightness(.62); }
.berufEintrag:hover { border-color:var(--sand-leise); background:var(--feld-hell); }
.berufEintrag .bIcon { font-size:20px; flex:none; }
.berufEintrag .bMitte { display:flex; flex-direction:column; gap:2px; min-width:0; flex:1; }
.berufEintrag .bName { font-weight:700; font-size:13px; color:var(--sand); }
.berufEintrag .bText { font-size:11px; color:var(--text-leise); }
.berufEintrag .bSkill { flex:none; font-size:13px; font-weight:700; color:var(--gold); }

#craftOffen { color:var(--sand); margin:0 0 10px; }
#craftOffen.hidden { display:none; }

.statList { padding:4px 14px 14px; font-size:12px; color:var(--text-leise); display:grid; grid-template-columns:1fr 1fr; gap:5px 12px; }
.statList span.v { color:var(--sand); font-weight:700; }

/* ---------- Skillbaum ---------- */
#skillHint { padding:0 14px; }
/* Ein Knopf MITTEN IM SATZ (20. September). Der Hinweis über den freien
   Punkten sagt jetzt nicht nur, wohin sie können, sondern führt auch dorthin.
   Er sieht aus wie ein Wort, auf das man treten kann, und nicht wie ein
   zweiter Bestätigungsknopf -- der Satz soll ein Satz bleiben. */
.hinweisKnopf {
  display:inline; padding:0; margin:0; border:0; background:none;
  color:var(--gold); font:inherit; font-weight:700; cursor:pointer;
  text-decoration:underline; text-underline-offset:2px;
}
.hinweisKnopf:hover { color:#ffe9a8; }
#skillBranches { padding:8px 14px 14px; }
#abilityUnlocks { padding:4px 14px 14px; }
.skillBranch { border:1px solid var(--linie); padding:12px; margin-bottom:10px; background:var(--feld); }
.skillBranch .sbHead { display:flex; justify-content:space-between; align-items:center; margin-bottom:6px; }
.skillBranch .sbTitle { font-weight:700; color:var(--text); }
.skillBranch .sbDesc { font-size:12px; color:var(--text-leise); margin-bottom:8px; line-height:1.45; }
.skillBranch .sbRanks { display:flex; gap:4px; margin-bottom:8px; }
.skillBranch .sbRank { flex:1; height:7px; background:var(--grund); border:1px solid var(--linie); }
.skillBranch .sbRank.filled { background:var(--sand); border-color:var(--sand); }

/* Ein Knopfstil für das ganze Spiel. Vorher hatte jedes Fenster seinen eigenen. */
.skillBranch button, .abilityCard button, .questCard button, .recipeCard button,
.itemDetail button, .shopBuy, .inviteBtns button, .chatInputRow button,
#partyInviteBtn, #partyLeaveBtn, .pathCard button, #lootPanel .lootAll,
#deathPanel button, .partyRow button {
  padding:7px 14px; font-size:12px; font-weight:700;
}
.skillBranch button:hover, .abilityCard button:hover, .questCard button:hover,
.recipeCard button:hover, .itemDetail button:hover, .shopBuy:hover,
.inviteBtns button:hover, .chatInputRow button:hover, #partyInviteBtn:hover,
#partyLeaveBtn:hover, .pathCard button:hover, #lootPanel .lootAll:hover,
#deathPanel button:hover:not(:disabled), .partyRow button:hover {
  background:var(--sand); color:#2a2016; border-color:var(--sand);
}
.skillBranch button:disabled, .abilityCard button:disabled, .recipeCard button:disabled,
.shopBuy:disabled, #deathPanel button:disabled, .questCard button:disabled {
  border-color:var(--linie); color:var(--text-fern); background:transparent; cursor:not-allowed;
}
/* Die Nadel. Angeheftete Aufgaben stehen immer im Verfolger -- der Knopf ist
   deshalb ein Schalter und muss auch so aussehen: gedrückt = golden.
   FARBEN STEHEN HIER KEINE MEHR (16. September): `color:var(--text-leise)`
   war für den dunklen Knopf geschrieben und blieb stehen, als der Knopf
   golden wurde -- helles Sandgrau auf Gold, und Oliver: *„SCHRIFT SIEHT MAN
   WIEDER SO SCHLECHT"*. Leise und gedrückt sind jetzt Sprachen der Grundform
   (`.leiseBtn`, `.gedruecktBtn`, unten bei `button`), nicht dieser Karte. */
/* "… 2 weitere" unter dem Verfolger: leise, aber anklickbar. */
.trackMehr {
  margin:4px 0 0; padding:4px 8px; font-size:11.5px; color:var(--text-leise);
  background:rgba(18,14,10,.72); border:1px solid var(--linie); border-radius:3px;
  text-align:right;
}
.trackMehr:hover { color:var(--text); border-color:var(--gold); }
/* Abbrechen, Gruppe verlassen, Ablehnen: siehe `.gefahrBtn` und `.leiseBtn`
   bei der Grundform. Hier stand `color:var(--rot)` ohne eigenen Grund --
   Lachsrot auf Gold, kaum zu lesen. */

/* Menü rechts unten in die Ecke: die Mitte gehört der Aktionsleiste. */
/* Sechs Spalten, seit der Klangknopf dazugekommen ist: bei fünf blieb er als
   elfter allein in einer dritten Reihe stehen. */
/* Das Menü ist ein RECHTECK, kein Band: fünf Spalten, drei volle Zeilen.
   Eine lange Reihe wandert bei jedem neuen Fenster weiter nach links und
   schiebt sich irgendwann unter die Fähigkeitenleiste; ein angefangene vierte
   Zeile mit einem einzelnen Knopf sieht aus wie ein Fehler. Kommt ein Fenster
   dazu, wird aus 5x3 eben 5x4 -- der Block bleibt ein Block. */
/* Die Knöpfe rücken über die Leiste -- und zwar genau so weit, wie sie
   WIRKLICH hoch ist. --leisteHoehe wird gemessen (siehe leistenHoehe() in
   client.js), nicht geschätzt: Die Leiste ist ein Bild und skaliert mit der
   Fensterbreite. Feste Pixelwerte hier ließen das Menü bei jeder zweiten
   Auflösung in der Luft schweben. */
/* ---------------------------------------------------------------------------
   WARUM DAS MENÜ TROTZDEM NOCH SCHWEBTE
   ---------------------------------------------------------------------------
   Erster Anlauf war: "geh so weit hoch, wie die Leiste hoch ist". Das war an
   zwei Stellen falsch.
   (1) --leisteHoehe wurde per Zeitschalter gemessen (300ms, 1500ms) -- da war
       der Spieler aber noch im Anmeldebildschirm, die Leiste also 0 hoch, und
       der Notwert 120px blieb für immer stehen. Gemessen wurde 139.
   (2) Die Leiste ist nur 760 Punkte breit und steht MITTIG. Rechts daneben ist
       gar keine Leiste -- das Menü ist also über einer Lücke hochgerückt und
       hing genau deshalb in der Luft.
   Jetzt entscheidet eine Messung: Steht das Menü über der Leiste, rückt es
   hoch. Steht es daneben, geht es bündig auf den Boden. Und gemessen wird per
   ResizeObserver, also immer dann, wenn sich wirklich etwas ändert
   (randmasseMelden() in client.js).
   Dazu bekommt der Block EINEN Rahmen. Fünfzehn einzelne Kacheln über der
   Landschaft sind keine Leiste, sondern Streusel. */
:root { --leisteHoehe: 140px; --hudUnten: 12px; --hudOben: 270px; --hudZeilen: 15; --hudSpalten: 1; --chatUnten: 12px; --chatBreite: 360px; }
/* SENKRECHT AM RECHTEN RAND.
   Der Block stand als 5x3-Raster unten rechts -- ein Klotz auf der Welt.
   Jetzt ist er eine Leiste am rechten Rand, unter der Minimap, bis zum
   Boden. Die Knöpfe füllen die Höhe SPALTENWEISE: Auf einem hohen Fenster
   ist es eine Spalte, auf einem niedrigen wachsen sie in eine zweite --
   nach links, nicht nach unten (direction:rtl sorgt dafür, dass die erste
   Spalte am Rand steht). Wo die Leiste beginnt, wird gemessen
   (--hudOben = Unterkante der Minimap), nicht geraten. */
/* Die Knopfleiste liegt ÜBER den Fenstern: Sie ist die Werkzeugleiste des
   Spiels, und ein Menüknopf, der unter einem offenen Fenster verschwindet,
   ist kein Menüknopf mehr (im Prüflauf fing das Rucksackfenster die Klicks
   auf den Questknopf ab). */
#hud { position:absolute; top:var(--hudOben); right:12px; z-index:3000;
  display:grid; grid-auto-flow:column;
  grid-template-rows:repeat(var(--hudZeilen, 15), var(--hudKnopf, 36px));
  grid-template-columns:repeat(var(--hudSpalten, 1), var(--hudKnopf, 36px));
  gap:3px; align-content:start; direction:rtl;
  padding:5px; background:rgba(18,14,10,.88);
  border:1px solid var(--linie);
  box-shadow:0 8px 22px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05); }
.hudBtn {
  width:var(--hudKnopf, 36px); height:var(--hudKnopf, 36px); direction:ltr;
  font-size:calc(var(--hudKnopf, 36px) * 0.47); background:rgba(36,28,20,.92); border:1px solid var(--linie);
  color:var(--text); font-size:17px; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:border-color .12s ease, background .12s ease;
}
.hudBtn:hover { border-color:var(--sand); background:var(--feld-hell); }
/* Die beiden Austritte sind abgesetzt -- sie schließen keine Fenster auf,
   sondern beenden etwas. */
.hudBtn.menuBtn { color:var(--text-leise); }
.hudBtn.menuBtn:hover { border-color:var(--rot); color:var(--rot); }
.hudIcon { width:calc(var(--hudKnopf, 36px) * 0.61); height:calc(var(--hudKnopf, 36px) * 0.61); image-rendering:pixelated; }
.hudIconSmall { width:calc(var(--hudKnopf, 36px) * 0.42); height:calc(var(--hudKnopf, 36px) * 0.42); image-rendering:pixelated; }

/* ---------- Der Gießbalken ----------
   Mittig über der Leiste, so breit wie ein Drittel davon. Alles liegt IM
   Balken: Symbol links, Name in der Mitte, Restzeit rechts -- eine Zeile, die
   man mit einem Blick liest, ohne den Kopf zu bewegen. */
#giessBalken {
  position:relative; width:284px; height:24px; margin-bottom:6px;
  pointer-events:none; display:block;
  box-shadow:0 4px 14px rgba(0,0,0,.6);
}
#giessBalken.hidden { display:none; }
.giessSpur {
  position:absolute; inset:0; overflow:hidden;
  background:rgba(10,8,6,.92); border:1px solid #5e4a2c;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.9);
}
.giessFuell {
  height:100%; width:0%;
  background:linear-gradient(180deg,#f0cf80,#b98a2f 60%,#8a6420);
  box-shadow:0 0 10px rgba(240,207,128,.45);
  transition:none;   /* jeder Frame setzt die Breite selbst -- siehe giessRahmen() */
}
.giessIcon { position:absolute; left:7px; top:0; height:100%; display:flex; align-items:center;
  font-size:13px; text-shadow:0 1px 3px #000; }
.giessText {
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:700; letter-spacing:.02em; color:#f6efe0;
  text-shadow:0 1px 3px #000, 0 0 6px #000; padding:0 46px;
  overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
}
.giessZeit { position:absolute; right:7px; top:0; height:100%; display:flex; align-items:center;
  font-size:11px; font-weight:700; color:#e7dcc4; text-shadow:0 1px 3px #000; }

/* ===========================================================================
   WAS AUF MIR WIRKT -- OBEN LINKS, WIE BEI EVERQUEST
   ===========================================================================
   Diese Bloecke sind an EINEM Tag dreimal umgezogen, und jeder Umzug kam aus
   einem Bildschirmfoto:

     1. Eine Textreihe mittig ueber der Aktionsleiste -- zu viel Text.
     2. Symbole aussen an den Kanten des Bandes -- sie schwebten ueber den
        beiden runden Kugeln und gehoerten sichtbar zu nichts.
     3. Symbole an den Enden der Erfahrungsleiste -- besser, aber immer noch
        mitten im Gedraenge der Leiste.
     4. Jetzt: *"Leg die wie bei EverQuest mal nach oben, Debuff und Buff."*

   Und DAS ist die Lage, die traegt, aus einem Grund, den die drei Versuche
   davor erst sichtbar gemacht haben: Die Aktionsleiste ist zum HANDELN da,
   die Wirkungen sind zum NACHSEHEN. Beides an denselben Fleck zu legen, hiess
   sie dauernd gegeneinander auszuspielen -- jeder neue Effekt musste sich an
   Kugeln, Giessbalken und Erfahrungsleiste vorbeidruecken. Am Rand ist Platz,
   und zwar dauerhaft.

   OBEN LINKS statt oben rechts wie in EverQuest: Rechts sitzt die Minikarte
   (1310..1486) und darunter der Auftragsverfolger. Links ist unter der
   Kopfleiste alles frei; die Mitte gehoert den Einblendungen (#toastLayer ab
   x 530).

   ZWEI FESTE BLOECKE NEBENEINANDER, nicht uebereinander: Stuenden sie
   uebereinander, sprаenge der untere jedes Mal, wenn oben ein Effekt ablaeuft.
   Ein Symbol, das wandert, waehrend man darauf zeigt, ist schlimmer als eines
   an der falschen Stelle. So bleibt jeder Block, wo er ist -- links das Gute,
   rechts das Schlechte, wie an der Leiste zuvor. */
#wirkLeiste {
  position:absolute; left:12px; top:68px; z-index:7;
  /* 22 Pixel zwischen den Bloecken, 4 innerhalb. Der Abstand ist der einzige
     Hinweis darauf, dass es ZWEI Bloecke sind und nicht eine lange Reihe --
     die Randfarbe (gruen/blau) sagt es zwar auch, aber erst beim Hinsehen. */
  display:flex; gap:22px; align-items:flex-start; pointer-events:none;
}
/* Vier Symbole je Zeile, dann faellt es nach unten -- ein Quadrat, das nach
   UNTEN waechst (hier normales wrap, nicht wrap-reverse: oben am Bildschirm
   ist unten die freie Richtung). */
.wirkGitter {
  display:flex; flex-wrap:wrap; align-content:flex-start;
  gap:4px; width:148px; pointer-events:none;
}

/* DAS SYMBOL. Quadratisch, gerahmt, ohne Text -- der steht im Tooltip.
   34 Pixel sind gross genug, dass ein Emoji lesbar bleibt, und klein genug,
   dass zwoelf davon nicht die Sicht nehmen. */
.wirkIcon {
  position:relative; width:34px; height:34px; flex:none;
  display:flex; align-items:center; justify-content:center;
  font-size:19px; line-height:1;
  background:rgba(20,15,10,.92); border:1px solid var(--linie);
  box-shadow:0 3px 10px rgba(0,0,0,.6);
  pointer-events:auto; cursor:help;
}
/* Gruen fuer das Gute, blaugrau fuer das Schlechte. Bis zum 13. September sah
   in dieser Leiste ALLES gleich aus -- die Geistheiler-Schwaeche wie ein
   Segen, das Gift wie eine Staerkung. Solange fast nur Gutes darin stand,
   fiel es nicht auf. */
.wirkIcon.gut     { border-color:#5fbf68; }
.wirkIcon.schlecht{ border-color:#7a92c8; background:rgba(16,22,34,.92); }
.wirkIcon:hover   { box-shadow:0 0 0 2px rgba(227,189,109,.55), 0 3px 10px rgba(0,0,0,.6); }
/* Die Restzeit steht KLEIN in der unteren Ecke des Symbols, nicht daneben.
   Sie ist eine Nebenauskunft: Man sieht am Symbol, DASS etwas wirkt, und in
   der Ecke, wie lange noch. */
/* Das Symbol selbst sitzt mittig; die Ecke gehoert der Restzeit. Ein eigener
   Span, damit die Zahl das Emoji nicht verschiebt. */
.wirkIcon .wirkSymbol { display:block; line-height:1; transform:translateY(-1px); }
.wirkIcon .wirkZeit {
  position:absolute; right:1px; bottom:1px; font-size:9px; font-weight:700;
  line-height:1; padding:1px 2px; border-radius:2px;
  background:rgba(8,6,4,.72);
  color:#e6d6b4; text-shadow:0 1px 2px #000; letter-spacing:0;
}

/* Der Sammelverkauf: vorher grauer Text auf dunklem Grund, zweizeilig
   abgeschnitten -- unlesbar (Spieltest). Jetzt heller Text, eigener Grund,
   Umbruch erlaubt, Zeilenabstand. */
.shopBulk {
  display:block; width:calc(100% - 4px); margin:8px 2px 4px; padding:9px 12px;
  background:rgba(201,162,39,.12); border:1px solid rgba(201,162,39,.55); color:#f2e6c2;
  font-size:12.5px; line-height:1.5; white-space:normal; text-align:left; cursor:pointer;
}
.shopBulk:hover:not(:disabled) { background:rgba(201,162,39,.22); }
.shopBulk:disabled { opacity:.45; cursor:default; }
.shopBulkNote { margin:0 2px 12px; font-size:11px; line-height:1.5; color:var(--text-fern); }

/* ---------- Der Widerhall ----------
   Klingende Echos leuchten, stille sind gedämpft, ungelernte fast dunkel --
   der Zustand ist auf einen Blick lesbar, ohne ein Wort zu lesen. */
#widerhallKopf { padding: 8px 14px 0; }
.whZeile { display:flex; justify-content:space-between; font-size:12.5px; color:var(--text-leise); padding:2px 0; }
.whZeile b { color:var(--sand); }
.whHinweis { padding:6px 0 2px; }
#widerhallList { padding: 8px 14px 14px; }
.echoCard { border:1px solid var(--linie); background:var(--feld); padding:11px 12px; margin-bottom:10px; }
.echoCard.klingt { border-color:#e3bd6d; box-shadow: inset 0 0 18px rgba(227,189,109,.08); }
.echoCard.fremd { opacity:.62; }
.echoKopf { font-size:13px; color:var(--text); margin-bottom:4px; }
.echoBadge { font-size:10px; color:#e3bd6d; border:1px solid #e3bd6d55; padding:1px 6px; margin-left:8px; }
.echoBadge.sperr { color:var(--text-leise); border-color:var(--linie); }
.echoWirkung { font-size:12px; color:var(--gruen); margin-bottom:5px; }
.echoText { font-size:11.5px; color:var(--text-leise); line-height:1.45; margin-bottom:8px; }
.echoCard button.ghost { background:transparent; }

/* Der Tipp der Einführung: die leise Zeile unter den Questzielen. Bewusst
   gedämpft -- sie hilft, sie ruft nicht. */
.trackTipp { font-size:11px; color:#b9a97e; margin-top:5px; padding:5px 7px;
  background:rgba(36,28,20,.75); border-left:2px solid #b9a97e; line-height:1.45; }
.itemWirkung { font-size:12px; color:var(--gruen); margin:6px 0; }

/* HIER STAND DIE ALTE FASSUNGSTABELLE (bis 15. September).
   Jede Fassung lag absolut auf einem Prozentwert des gemalten Bandes
   (assets/ui/leiste.png). Die Regeln stehen jetzt weiter oben bei der neuen
   Leiste, in EINEM Block -- der zweite hier hätte sie stillschweigend
   überstimmt, denn bei gleicher Genauigkeit gewinnt in CSS der spätere.
   Zwei Sachen von damals bleiben, weil sie unabhängig von der Bauform sind: */
@keyframes swingPulse { 0%,100% { border-color:var(--gold); } 50% { border-color:var(--sand-leise); } }
svg.slotIcon { width:72%; height:72%; }

/* ---------- Ein Gegenstand auf der Aktionsleiste ----------
   Oliver, 11. September: „essen muss auf die aktionsleiste ziehbar sein und
   anklickbar".

   Die Zahl unten rechts ist die STÜCKZAHL im Rucksack -- an derselben Stelle,
   an der eine Fähigkeit ihren Preis trägt, denn es ist dieselbe Frage: Kann
   ich das jetzt? Sie steht in Sandfarbe statt im Ressourcenblau, damit man
   die beiden nicht verwechselt.

   Leerer Vorrat leert NICHT den Platz (siehe leisteSicherstellen): Er wird
   blass und zeigt die 0. Der Platz sagt dann „hier gehört Brot hin". */
.abilitySlot .slotAnzahl {
  position:absolute; right:2px; bottom:0; font-size:9px; font-weight:700;
  color:#e3bd6d; text-shadow:0 1px 2px #000; z-index:2;
}
.abilitySlot.leisteItem.leerVorrat { filter:grayscale(.85) brightness(.62); }
.abilitySlot.leisteItem.leerVorrat .slotAnzahl { color:#c98b84; }

/* ---------- Zauberbuch ---------- */
.zauberListe { padding:6px 14px 14px; display:flex; flex-direction:column; gap:7px; max-height:52vh; overflow-y:auto; }
.zauberEintrag {
  display:flex; align-items:center; gap:10px; padding:8px 10px;
  background:var(--feld); border:1px solid var(--linie); cursor:grab;
}
.zauberEintrag:hover { background:var(--feld-hell); border-color:var(--sand-leise); }
.zauberEintrag.aufLeiste { opacity:.55; }
.zauberEintrag .zIcon { font-size:22px; width:30px; text-align:center; flex-shrink:0; }
.zauberEintrag .zName { font-weight:700; font-size:13px; color:var(--text); }
.zauberEintrag .zText { font-size:11.5px; color:var(--text-leise); line-height:1.45; }
.zauberEintrag .zPlatz { margin-left:auto; font-size:10.5px; color:var(--text-fern); white-space:nowrap; }

/* ---------- Planetenkarte ---------- */
#worldMapWrap { padding:10px 14px 4px; display:flex; justify-content:center; }
#worldMapCanvas { image-rendering:pixelated; background:#0d0a07; border:1px solid var(--linie); cursor:grab; max-width:100%; }
#worldMapCanvas:active { cursor:grabbing; }
#worldMapBar { display:flex; align-items:center; gap:8px; padding:4px 14px 14px; font-size:12px; color:var(--text-leise); }
.mapZoomBtn { width:26px; height:26px; background:var(--feld); border:1px solid var(--linie); color:var(--text); cursor:pointer; font-size:15px; line-height:1; font-family:inherit; }
.mapZoomBtn:hover { border-color:var(--sand); }

/* ---------- Händler ---------- */
#shopPanel { width:400px; }
#shopHint { padding:0 14px; }
#shopList { padding:6px 14px 14px; display:flex; flex-direction:column; gap:6px; max-height:400px; overflow-y:auto; }
.shopRow { display:flex; align-items:center; gap:10px; padding:9px 11px; border:1px solid var(--linie); background:var(--feld); }
.shopIcon { font-size:22px; width:28px; text-align:center; flex-shrink:0; }
/* Name, Werte, Preis und Knopf brauchen jeweils eine eigene Zeile bzw. Spalte --
   nebeneinander lief in einem schmalen Fenster alles ineinander. */
.shopInfo { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.shopName { display:block; font-size:13px; font-weight:700; line-height:1.2; }
.shopStats { display:block; font-size:11px; color:var(--text-leise); line-height:1.3; }
.shopBuy { flex-shrink:0; padding:6px 12px; }
.shopPrice { color:var(--gold); font-weight:700; font-size:12px; flex-shrink:0; min-width:56px; text-align:right; }
/* Der durchgestrichene Preis beim Nachthändler (11. September). Er steht
   klein und blass vor dem echten -- ein Vergleich, kein Aushängeschild. */
.shopPrice .shopAlt { color:var(--text-leise); font-weight:400; opacity:.65; margin-right:5px; }
.shopKeinAnkauf { margin-left:10px; font-size:11px; color:var(--text-leise); align-self:center; }
.shopTabs { display:flex; gap:4px; margin-bottom:4px; }
.shopTab { flex:1; background:transparent; border:none; border-bottom:1px solid var(--linie-leise); color:var(--text-leise); font-size:12px; font-weight:600; padding:6px 4px; cursor:pointer; font-family:inherit; }
.shopTab.active { color:var(--sand); border-bottom-color:var(--sand); }
.shopTab:hover { color:var(--text); }

/* ---------- Fähigkeitenkarten ---------- */
.roleHeadTank { color:var(--sand); }
.roleHeadHeal { color:var(--gruen); }
.roleHeadDd   { color:var(--rot); }
.abilityCard { border:1px solid var(--linie); padding:11px 12px; margin-bottom:8px; background:var(--feld); }
.abilityCard .acHead { display:flex; justify-content:space-between; align-items:center; margin-bottom:5px; gap:8px; }
.abilityCard .acTitle { font-weight:700; color:var(--text); }
.abilityCard .acRole { font-size:10px; color:var(--text-fern); white-space:nowrap; }
.abilityCard .acDesc { font-size:12px; color:var(--text-leise); margin-bottom:5px; line-height:1.45; }
/* Die harten Zahlen einer Fähigkeit (Reichweite, Zauberzeit, Abklingzeit).
   Sie stehen absichtlich UNTER der Beschreibung und in anderer Farbe: Der Satz
   sagt, was die Fähigkeit tut, diese Zeile sagt, wie weit und wie oft. Sie
   wird aus den Feldern gerechnet, nicht getippt (client.js,
   fertigkeitZahlen) -- deshalb kann sie nicht veralten. */
.abilityCard .acZahlen { font-size:11px; color:var(--gold, #c9a227); opacity:.85; margin-bottom:9px;
  letter-spacing:.3px; font-variant-numeric:tabular-nums; }
.abilityCard .acZahlen:empty { display:none; }
.zZahlen { color:var(--gold, #c9a227); opacity:.8; font-size:.92em; white-space:nowrap; }
.abilityRoleHeading { padding:10px 14px 3px; font-size:11px; text-transform:uppercase; letter-spacing:.12em; color:var(--text-fern); }
/* Fähigkeiten, die noch nicht an der Reihe sind: sichtbar, aber zurückgenommen.
   Sie sollen als Ziel taugen, nicht als Angebot. */
.abilityCard.acLocked { opacity:.5; }
.abilityCard.acFremd { opacity:.3; }
.acStufe { display:inline-block; padding:1px 6px; border:1px solid var(--linie); color:var(--text-leise); font-size:10px; }
.acStufe.acAuto { border-color:var(--sand-leise); color:var(--sand); }

/* ---------- Fenster ---------- */
.panel {
  /* DIE GRUNDGRÖSSE. Ohne sie erbt jedes Fenster die 16 Punkte des Browsers
     (gemessen: dreizehnmal im Zauberbuch). Alles, was keine eigene Größe
     nennt, liegt jetzt auf der Leiter -- auch die Knöpfe, denn deren
     Grundform trägt `font:inherit`. */
  font-size:var(--schrift-text);
  position:absolute; top:60px; right:var(--fensterRechts, 16px); width:360px; max-height:70vh;
  background:var(--flaeche); border:1px solid var(--linie);
  backdrop-filter:blur(5px);
  overflow:auto; z-index:10; box-shadow:0 16px 46px rgba(0,0,0,.55);
}
/* Charakter-Fenster sitzt links, damit es zusammen mit dem Rucksack (rechts) offen
   bleiben kann -- Ausrüstung wird ja per Drag&Drop vom Rucksack ins Charakter-Fenster
   gezogen, beide müssen also gleichzeitig sichtbar sein können, wie bei WoW. */
/* DAS CHARAKTERBLATT IST DAS WICHTIGSTE FENSTER DES SPIELS.
   Es war 320 Punkte breit und so hoch, dass man an der eigenen Figur
   vorbeiscrollen musste, um ihre Werte zu sehen. Jetzt: zwei Spalten,
   560 Punkte, und die Figur so gross, dass man erkennt, was sie traegt. */
/* GROSS. Ein Charakterblatt ist das Fenster, das man am längsten ansieht --
   und es zeigt die eigene Figur. Bei 640 Punkten Breite war die Figur
   briefmarkengroß und die Werte standen in zwei engen Spalten daneben. */
/* Mittig OHNE transform: Die Fenster sind verschiebbar, und der Code dafür
   setzt left/top direkt -- ein zusätzlicher transform hätte jeden Griff um die
   halbe Fensterbreite versetzt. */
/* Breite nach der Vorlage: die Puppe nimmt gut zwei Drittel, die Wertetafel
   das letzte Drittel. 940 Punkte waren zu viel -- die Werte standen in zwei
   Spalten quer über den halben Bildschirm, und dazwischen war Luft. */
/* HOCHFORMAT AM LINKEN RAND -- UND OHNE SCROLLEN.
   Ein Charakterblatt ist ein Blatt: höher als breit. Es öffnet links, wo es
   die Sicht auf die Welt am wenigsten nimmt, und es MUSS ganz hineinpassen:
   Ein Fenster, in dem man scrollen muss, um die eigenen Werte zu sehen, ist
   ein Fenster zu klein. Deshalb hängt die Größe der Figur an der
   Fensterhöhe (siehe .charFigur canvas). */
#characterPanel { top:16px; left:16px; right:auto;
  width:min(440px, 42vw); max-height:calc(100vh - 32px); overflow:hidden;
  display:flex; flex-direction:column; }
/* Der Chat gehört nach unten LINKS -- so steht er in jedem MMO, und so steht
   er auch in der Kosmos. Er lag vorher wie jedes andere Fenster oben
   rechts und musste erst von Hand dorthin gezogen werden, wo er ohnehin
   hingehört. Rechts unten sitzt die Knopfleiste, links unten ist frei.
   Offen ist er von Anfang an: ein Chat, den man erst aufklappen muss, ist
   für den, der etwas fragen will, nicht da. */
/* DREI SACHEN WAREN AM CHAT FALSCH.
   Er war 340 breit -- zu schmal für seine eigene Eingabezeile, weshalb
   "Senden" rechts abgeschnitten war. Er war 26vh hoch, wovon nach Kopfzeile
   und Eingabe rund vier Zeilen Text blieben: man scrollte ab der fünften
   Nachricht. Und er rückte über die Leiste hoch, die an dieser Stelle gar
   nicht liegt (siehe #hud) -- also stand er ohne Grund in der Luft.
   Jetzt: breiter, deutlich höher, und unten verankert wie in jedem MMO. */
#chatPanel {
  top:auto; bottom:var(--chatUnten); left:12px; right:auto;
  width:var(--chatBreite, 360px); max-height:38vh;
  display:flex; flex-direction:column;
}
#chatPanel #chatMessages { flex:1; min-height:170px; max-height:none; }
.panelHead {
  display:flex; justify-content:space-between; align-items:center;
  padding:12px 14px; font-weight:700; font-size:13.5px; letter-spacing:.02em;
  color:var(--sand);
  border-bottom:1px solid var(--linie);
  position:sticky; top:0; background:var(--flaeche-fest); z-index:2;
}
.panelHead.draggable, .charHead.draggable { cursor:move; touch-action:none; user-select:none; }
/* Der Griff zum Skalieren: unten rechts, drei kleine Striche wie an jedem
   Fenster, das man kennt.
   ABSOLUT IN DER ECKE DES FENSTERS, NICHT STICKY IM INHALT (21. September).
   Vu, 18. September, 20:20: *„Der Eckpfeil des Fensterrahmens zum Ändern der
   Größe bleibt an der ursprünglichen Position."* Hier stand
   `position:sticky; bottom:0; left:100%; margin:-18px 0 0 auto` -- und sticky
   bezieht sich auf den ROLLBEREICH, nicht auf den Fensterrahmen. Bei einem
   verschobenen, skalierten oder kurzen Fenster lag der Griff deshalb
   irgendwo im Inhalt statt in der Ecke: Wer ihn einmal nicht findet, ändert
   die Fenstergröße nie wieder. `.panel` ist absolut positioniert, also
   verankert `position:absolute` hier zuverlässig an dessen Kasten. */
.panelGriff {
  position:absolute; right:0; bottom:0; width:18px; height:18px;
  cursor:nwse-resize; z-index:5; touch-action:none;
  background:
    linear-gradient(135deg, transparent 0 46%, rgba(201,162,39,.75) 46% 54%, transparent 54% 62%,
                    rgba(201,162,39,.75) 62% 70%, transparent 70% 78%, rgba(201,162,39,.75) 78% 86%, transparent 86%);
}
.panelGriff:hover { filter:brightness(1.3); }
.closeBtn { background:none; border:none; color:var(--text-leise); font-size:16px; cursor:pointer; line-height:1; padding:0 2px; }
.closeBtn:hover { color:var(--text); }

/* ---------- Rucksack und Ausrüstung ---------- */
.invLayout { padding:12px 14px; }
.sectionLabel { font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-fern); margin:12px 0 7px; }
.equipSlots { display:flex; gap:8px; flex-wrap:wrap; padding:8px 14px 14px; }
.slot {
  /* Kräftigere Kante + hellere Füllung: die Slots gingen im dunklen Panel
     unter ("sehr schwach zu sehen"). Doppelte Kontur wie bei WoW-Slots. */
  width:50px; height:50px; background:#3a2e20; border:1px solid #6b563c;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.06);
  display:flex; align-items:center; justify-content:center; font-size:22px;
  cursor:pointer; position:relative; transition:border-color .12s ease;
}
.slot:hover { border-color:#c9a227; }
.slot.dragOver { border-color:var(--sand); background:var(--feld-hell); }
.slot[draggable="true"] { cursor:grab; }
.equipIconSlot.empty { opacity:.6; }
.equipZeichen { font-size:20px; opacity:.5; filter:grayscale(1); }
/* Die brennende Fackel am Gürtel: Glutrand, damit man auf einen Blick sieht,
   warum die Hand gerade nicht frei ist. */
.slot.brennt { border-color:#ff9b3d; box-shadow:0 0 12px rgba(255,155,61,.55), inset 0 0 0 1px rgba(255,200,120,.4); }
.equipIcon { width:26px; height:26px; image-rendering:pixelated; }
.slot .qty { position:absolute; bottom:1px; right:3px; font-size:10px; color:var(--sand); text-shadow:0 1px 2px #000; }
.invGrid { display:grid; grid-template-columns:repeat(6, 50px); gap:8px; }
/* Sechs Slots à 50 + fünf Lücken à 8 = 340 Bildpunkte; in einem 360er
   Fenster mit Rahmen und Innenabstand blieb dafür kein Platz -- die sechste
   Spalte war seit dem Goldrahmen angeschnitten (pw_test_fenster, 8. Sept.). */
#inventoryPanel, #lagerPanel { width:404px; }
/* Geldanzeige unten rechts am Rucksack -- dort, wo sie in jedem Spiel dieser
   Art sitzt, und damit dort, wo das Auge sie ohne Suchen findet. */
.invGeld {
  display:flex; justify-content:flex-end; align-items:center; gap:5px;
  margin-top:10px; padding-top:9px; border-top:1px solid var(--linie-leise);
  font-size:14px; font-weight:700; color:#f2d98b; letter-spacing:.02em;
}
/* Reiter (Werkstatt: Bank / Feuer, Zauberbuch: Wege) */
.reiterLeiste { display:flex; gap:6px; padding:10px 14px 0; }
.reiter {
  flex:1; padding:7px 10px; font-size:12.5px; font-weight:600;
  background:var(--feld); color:var(--text-leise);
  border:1px solid var(--linie); border-bottom-color:transparent;
  cursor:pointer; transition:background .12s ease, color .12s ease;
}
.reiter:hover { color:var(--text); }
.reiter.aktiv { background:var(--flaeche-fest); color:var(--text); border-bottom-color:var(--sand-leise); }

.itemDetail { padding:12px 14px; border-top:1px solid var(--linie-leise); font-size:13px; }
.itemDetail .itName { font-weight:700; margin-bottom:4px; color:var(--text); }
.itemDetail .itFlavor { color:var(--text-leise); margin-bottom:9px; font-style:italic; line-height:1.5; }

#itemTooltip {
  position:fixed; z-index:200; max-width:240px;
  background:var(--flaeche-fest); border:1px solid var(--linie);
  padding:10px 12px; font-size:12.5px; pointer-events:none;
  box-shadow:0 10px 30px rgba(0,0,0,.6);
}
#itemTooltip .ttName { font-weight:700; margin-bottom:4px; color:var(--text); }
#itemTooltip .ttEffect { color:var(--gruen); margin-bottom:4px; }
#itemTooltip .ttFlavor { color:var(--text-leise); font-style:italic; line-height:1.45; }
#itemTooltip .ttHint { color:var(--sand); margin-top:7px; font-size:11px; }

/* ===================================================================
   DAS GEGENSTANDSFENSTER IM AUFBAU DES VORBILDS
   ===================================================================
   Oliver, 11.9., mit einem Bild von Thunderfury: „genauso so ein Fenster wie
   in wow das ist übersichtlich". Übersichtlich ist daran vor allem DREIERLEI:

     1. Eine feste Reihenfolge -- Name, Stufe, Bindung, dann was es kann,
        dann was es kostet, ganz unten die Geschichte. Man lernt sie einmal
        und liest danach nur noch die Zeile, die einen interessiert.
     2. Zwei Spalten für die Dinge, die paarweise gehören: Platz und Art,
        Schaden und Tempo. Das Auge springt nicht, es vergleicht.
     3. Farbe als Bedeutung, nicht als Schmuck -- weiß die Tatsachen, grün
        die Wirkung, gold die Werte, rot die Absage, grau die Erzählung. */
#itemTooltip { max-width:270px; }
#itemTooltip .ttStufe { color:var(--text-leise); font-size:11.5px; margin-bottom:1px; }
#itemTooltip .ttBindung { color:var(--text); opacity:.85; margin-bottom:5px; }
/* Die zweispaltige Zeile: links der Platz, rechts die Art. */
#itemTooltip .ttZeile { display:flex; justify-content:space-between; gap:14px; color:var(--text); }
#itemTooltip .ttSchaden { margin-top:5px; }
#itemTooltip .ttDps { color:var(--text-leise); font-size:11.5px; margin-bottom:4px; }
/* Die Werte: gold und einer je Zeile, wie im Vorbild. Nebeneinander gesetzt
   liest man sie als Satz statt als Liste und übersieht den einen, der zählt. */
#itemTooltip .ttWert { color:var(--sand); }
#itemTooltip .ttErfordert { color:var(--text-leise); margin-top:5px; }
#itemTooltip .ttErfordert.zuNiedrig { color:#e2695f; }
/* ---- Besser oder schlechter als das Angelegte ----
   Die eine Zeile, die Oliver am 11. September gefehlt hat: Er fand keine
   Beute, die "den Satzboni übersteigt" -- sie lag in seiner Tasche, nur
   musste man sechs Werte gegen sechs Werte im Kopf rechnen, um es zu sehen.
   Grün und Rot, weil das die einzigen zwei Antworten sind; ein Pfeil davor,
   damit es auch ohne Farbe lesbar bleibt. */
#itemTooltip .ttVergleich { margin-top:6px; font-weight:600; font-size:11.5px; letter-spacing:.2px; }
#itemTooltip .ttBesser { color:#7ee081; }
#itemTooltip .ttSchlechter { color:#e2695f; }
/* Warum der Pfeil so zeigt, wenn die Zahlen etwas anderes sagen: der
   Satzbonus. Leise gesetzt -- er ist die Begründung, nicht die Antwort. */
#itemTooltip .ttVergleichGrund { color:var(--text-leise); font-size:11px; margin-top:2px; }
#itemTooltip .ttMacher { color:var(--text-leise); font-size:11.5px; margin-top:4px; }
#itemTooltip .ttPreis { color:var(--text-leise); font-size:11.5px; margin-top:4px; }
#itemTooltip .ttFlavor { margin-top:6px; }

/* ---------- Questsystem ---------- */
#npcPanel { width:400px; }
#npcHeader { display:flex; gap:12px; align-items:center; margin:12px 14px 8px; }
#npcPortrait { width:70px; height:70px; background:var(--feld); border:1px solid var(--linie); flex-shrink:0; }
#npcName { font-weight:700; font-size:15px; color:var(--text); }
#npcTitle { font-size:11.5px; color:var(--violett); letter-spacing:.03em; }
#npcLore { font-size:12px; color:var(--text-leise); font-style:italic; line-height:1.55; margin:0 14px 12px; }
.npcGreeting { font-size:12.5px; color:var(--gold); line-height:1.55; margin-bottom:14px; }

.questCard { border:1px solid var(--linie); background:var(--feld); padding:11px 12px; margin-bottom:10px; }
.questCard.mainChain { border-left:2px solid var(--gold); }
.questCard.ready { border-left:2px solid var(--gruen); }
/* Die verfolgte Aufgabe: dieselbe, auf die der Peiler zeigt. Das Buch
   schlaegt auf ihrem Reiter auf, also muss sie in der Liste auch zu finden
   sein, ohne sie zu suchen. */
.questCard.verfolgt { box-shadow:0 0 0 1px var(--gold) inset; background:#241d13; }
.questCard .qHead { font-weight:700; font-size:13.5px; margin-bottom:7px; display:flex; justify-content:space-between; align-items:center; gap:8px; color:var(--text); }
.questCard .qGiver { font-size:11px; color:var(--violett); margin-bottom:7px; }
.questCard .qText { font-size:12px; color:var(--text-leise); line-height:1.6; margin-bottom:9px; }
.questCard .qObjectives { font-size:12px; margin-bottom:9px; }
.questCard .qRewards { font-size:11.5px; color:var(--gold); margin-bottom:9px; }
.questCard .qShare { margin-right:6px; }

.qBadge { font-size:10px; padding:2px 7px; white-space:nowrap; font-weight:600; border:1px solid transparent; }
.qBadge.new    { border-color:var(--gold);       color:var(--gold); }
.qBadge.active { border-color:var(--sand-leise);  color:var(--sand); }
.qBadge.ready  { border-color:var(--gruen);      color:var(--gruen); }
/* Wiederholbar und schon einmal gemacht: ruhiger als "Neu", damit ein
   tägliches Angebot nicht wie ein Fund aussieht. */
.qBadge.wieder { border-color:var(--sand-leise);  color:var(--sand-leise); }
/* Was BALD kommt: die Stufentuer als Zeile, nicht als Wand. Leiser als ein
   Angebot, ohne Knopf -- man sieht, dass hier mehr ist, und ab wann. */
.questCard.locked { opacity:.62; padding:8px 12px; }
.questCard.locked .qHead { margin-bottom:0; font-weight:600; color:var(--text-leise); }
.qBadge.locked { border-color:var(--text-fern); color:var(--text-fern); }

.objDone { color:var(--gruen); }
.objOpen { color:var(--text-leise); }
.objDone b, .objOpen b { color:var(--text); }

.questOutro { border:1px solid var(--gruen); background:var(--feld); padding:11px 12px; margin-bottom:12px; }
.questDoneHead { font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-fern); margin:14px 0 6px; }
.questDoneRow { font-size:12px; color:var(--text-fern); padding:3px 0; }

/* Unter der Minimap (52 + 176 + Beschriftung + Knöpfe ≈ 270). Vorher stand er
   bei 120 und lag damit auf ihr. */
/* DAS AUFGABENFELD LAG UNTER DER KNOPFLEISTE (15. September, gefunden im
   Durchlauf P1). Nachgemessen auf vier Bildschirmbreiten -- und zwar auf
   allen vieren gleich: 83 x 84 Punkte Überdeckung. Das Feld ist 250 breit
   und 146 hoch, es fehlte also ein Drittel der Breite und mehr als die halbe
   Höhe -- genau dort, wo bei zwei laufenden Aufträgen der zweite steht.
   Und ausgerechnet dieses Feld ist das einzige, das einem neuen Spieler sagt,
   was er tun soll.
   `--fensterRechts` gab es längst: Es sagt jedem Fenster, wo die Leiste
   anfängt (client.js, randmasseMelden), und alle Panel benutzen es. Das
   Aufgabenfeld ist kein .panel und war deshalb übersehen worden. */
#questTracker { position:absolute; top:282px; right:var(--fensterRechts, 16px); width:250px; z-index:5; pointer-events:none; display:flex; flex-direction:column; gap:8px; }
#questTracker.hidden { display:none; }
.trackQuest { background:rgba(23,18,13,.78); border-left:2px solid var(--sand-leise); padding:7px 11px; font-size:11.5px; line-height:1.55; text-shadow:0 1px 2px rgba(0,0,0,.8); }
.trackQuest.ready { border-left-color:var(--gruen); }
.trackTitle { font-weight:700; color:var(--text); margin-bottom:2px; }
.trackReady { color:var(--gruen); font-weight:400; }

/* ---------- Questjournal: Haupt / Neben / Abgeschlossen ---------- */
.questChapter { padding:10px 14px 0; font-size:12.5px; font-weight:700; color:var(--violett); letter-spacing:.02em; }
.questTabs { display:flex; gap:4px; padding:10px 14px 6px; border-bottom:1px solid var(--linie-leise); }
.questTab { flex:1; background:transparent; border:none; border-bottom:1px solid transparent; color:var(--text-leise); font-size:12px; font-weight:600; padding:6px 4px; cursor:pointer; font-family:inherit; }
.questTab:hover { color:var(--text); }
.questTab.active { color:var(--sand); border-bottom-color:var(--sand); }
.questTab .tabCount { display:inline-block; min-width:16px; padding:0 4px; margin-left:3px; border:1px solid var(--linie); font-size:10px; color:var(--text-leise); }
.questTab.active .tabCount { border-color:var(--sand-leise); color:var(--sand); }

/* ---------- Werkbank ---------- */
#recipeList { padding:8px 14px 14px; }
.recipeCard { border:1px solid var(--linie); background:var(--feld); padding:11px 12px; margin-bottom:10px; }
.recipeCard .rTitle { font-weight:700; margin-bottom:6px; color:var(--text); }
.recipeCard .rEffect { font-size:11.5px; color:var(--gruen); margin-bottom:6px; }
.recipeCard .rMats { font-size:12px; margin-bottom:9px; color:var(--text-leise); }
.recipeCard .rMats span { margin-right:10px; }
.recipeCard .ok { color:var(--gruen); }
.recipeCard .bad { color:var(--rot); }

/* ---------- Die Berufe ----------
   Der Farbpunkt links am Rezeptnamen ist die wichtigste Auskunft im ganzen
   Fenster: Er sagt ohne ein Wort, ob dieses Rezept noch Fertigkeit bringt.
   Deshalb steht er VOR dem Namen und nicht irgendwo rechts. */
.berufKopf { display:flex; justify-content:space-between; align-items:baseline; padding:8px 14px 4px; font-size:12.5px; color:var(--text-leise); }
.berufKopf b { color:var(--sand); }
#craftSkill .barTrack { margin:0 14px 6px; }
.barFill.berufBar { background:linear-gradient(90deg,#8a6a35,#e3bd6d); }
.reiter i { font-style:normal; opacity:.7; font-size:11px; }

.farbPunkt { display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:7px; vertical-align:middle; background:#8b8f9c; }
.recipeCard.farbe_orange .farbPunkt { background:#e08a3c; }
.recipeCard.farbe_gelb   .farbPunkt { background:#e0d24a; }
.recipeCard.farbe_gruen  .farbPunkt { background:#5fbf68; }
.recipeCard.farbe_grau   .farbPunkt { background:#8b8f9c; }
.recipeCard.farbe_gesperrt { opacity:.55; }
.recipeCard .rSkill { font-size:11px; color:var(--text-leise); margin:-2px 0 7px 15px; }
.recipeCard .rTitle i { font-style:normal; color:var(--text-leise); font-size:11.5px; }
.craftKnoepfe { display:flex; gap:8px; }
.craftKnoepfe button.alles { background:transparent; color:#f2e6c2; border:1px solid rgba(201,162,39,.55); }
.craftKnoepfe button.alles:disabled { color:rgba(242,230,194,.45); }

.berufAngebot { border:1px solid var(--linie); background:var(--feld); padding:14px; }
.berufAngebot .rEffect { font-size:12px; color:var(--text-leise); margin:6px 0 10px; }
.lehrerKopf { font-size:11.5px; color:var(--text-leise); text-transform:uppercase; letter-spacing:.08em; margin:14px 0 8px; }
.recipeCard.lehrerRezept { border-style:dashed; }

/* ---- Werkstatt in WoW-Bauart: Liste links, Detailtafel rechts ---- */
/* DAS BUCH IST WIEDER RAUS -- UND DAS LAYOUT BLEIBT (15. September).
   Hier stand eine eigene Haut für das Zauberbuch: der gerenderte Buchdeckel
   als Neunfeld, die Schieferseite als Kachel, das Bronzeband als Kopfzeile.
   Oliver, nachdem er es im Spiel gesehen hat:

     *„Ne es muss kein Buch sein lass das mal weg glaube ich - lass das
      Layout so und erstelle das Fenster genauso wie die anderen Fenster
      aussehen"*

   Und das ist die richtige Trennung, die ich selbst nicht gezogen hatte: Die
   ORDNUNG (drei Seiten, Reiter oben und unten) war das, was gefehlt hat --
   die HAUT nicht. Ein Fenster, das als einziges anders aussieht, ist kein
   besonderes Fenster, sondern ein fremdes: Das Auge sucht den Unterschied und
   findet keinen Sinn darin.

   Also trägt das Zauberbuch wieder die Steinhaut aller Fenster (`.panel` mit
   stein_dunkel.png und rahmen_gold.png, weiter unten). Das Werkzeug, das aus
   einem Bild ein dehnbares Bedienfeld schneidet, bleibt im Kasten stehen
   (tools/ui_rahmen.py) -- es hat nichts falsch gemacht, es wurde nur nicht
   gebraucht. */

/* DAS ZAUBERBUCH (15. September). Hier stand `#craftPanel { width:560px; }`
   -- die Werkstatt war ein eigenes Fenster. Jetzt ist sie eine Seite, und die
   Breite gehört dem Buch. 640 statt 560: Auf der Handwerksseite stehen jetzt
   Berufsliste UND Rezeptbuch übereinander, und die Rezeptspalte war bei 560
   gerade so breit wie ihr längster Name. */
/* DIE REITER BLEIBEN STEHEN, DER INHALT ROLLT (15. September).
   Oliver: *„springt das zauberbuch nur aus der reihe wenn ich -Weg- drücke,
   die anderen beiden tabs bleiben, nur Weg öffnet ein eigenes fenster"* und
   *„gib dem zauberbuch mal einen button um zurück zu kommen, so muss ich
   immer Z drücken"*.

   Beides dasselbe, und es ist kein zweites Fenster: `.panel` rollt als GANZES
   (`overflow:auto`). Die Fähigkeiten- und die Handwerksseite passen hinein,
   die Wegseite nicht -- sie ist mit Wegwahl und allen freischaltbaren
   Fähigkeiten die längste (gemessen: 4620 Punkte Inhalt in einem Fenster von
   640). Sobald sie überläuft, rollen Kopfzeile UND untere Reiterleiste mit
   weg: Das ✕ ist oben aus dem Bild, die Reiter sind unten darunter, und übrig
   bleibt eine lange Liste ohne Rahmen. Die sieht aus wie ein eigenes Fenster,
   und zurück kommt man nur mit Z.

   ZWEI ANLÄUFE, UND DER ZWEITE GILT. Erst wurde geklebt (position:sticky für
   Kopf und beide Reiterreihen), danach der Flexkasten weiter unten gebaut
   (Kopf fest, Seitenkasten rollend, Reiter fest). Beide Blöcke standen
   danebeneinander im Stilblatt -- und genau daraus wurde der nächste Fehler:

   Oliver, 15. September, mit Bild: *„das zauberbuch verschluckt auch text
   aktuell leider."* Im Bild fehlte der Titel „📕 Rezeptbuch" ganz, und der Satz
   darunter war oben abgeschnitten.

   Der Grund: `.reiterOben` klebte mit `top:41px` -- gerechnet für die Zeit,
   als das GANZE Fenster rollte und die 41 Punkte die Kopfzeile waren. Seit
   der Flexkasten steht, rollt nur noch `#buchSeiten`, und dessen Oberkante
   liegt bereits UNTER dem Kopf. Die 41 Punkte schoben die Reiterleiste also
   um 41 Punkte nach unten, während ihr Platzhalter oben stehen blieb -- oben
   eine Lücke, unten deckte sie den Titel und die halbe Zeile darunter zu.

   Der Fehler war nicht die Zahl, sondern dass es zwei Blöcke für dasselbe
   Fenster gab: einer beschrieb eine Bauart, die es nicht mehr gibt. Jetzt
   steht nur noch der Flexkasten (weiter unten), und `.reiterOben` klebt am
   Rand SEINES Kastens -- also bei 0. */
#spellbookPanel .zauberListe,
#spellbookPanel .zauberBerufe { max-height:none; overflow:visible; }
/* Die obere Reiterreihe bleibt beim Rollen stehen: Sie gehört zur Seite, die
   man gerade liest, und eine Seite, deren Register wegrollt, ist dasselbe
   Problem eine Ebene tiefer. `top:0` -- der rollende Kasten ist `#buchSeiten`,
   und der fängt unter dem Kopf an. Deckender Grund, sonst liest man die
   Liste durch die Reiter hindurch. */
#spellbookPanel .reiterLeiste.reiterOben {
  position:sticky; top:0; z-index:2;
  background:#17141a; background-image:url('/assets/ui/stein_dunkel.png');
}

/* DAS BUCH IST WIEDER RAUS -- UND DAS LAYOUT BLEIBT (15. September).
   Hier stand eine eigene Haut für das Zauberbuch: der gerenderte Buchdeckel
   als Neunfeld, die Schieferseite als Kachel, das Bronzeband als Kopfzeile.
   Oliver, nachdem er es im Spiel gesehen hat:

     *„Ne es muss kein Buch sein lass das mal weg glaube ich - lass das
      Layout so und erstelle das Fenster genauso wie die anderen Fenster
      aussehen"*

   Und das ist die richtige Trennung, die ich selbst nicht gezogen hatte: Die
   ORDNUNG (drei Seiten, Reiter oben und unten) war das, was gefehlt hat --
   die HAUT nicht. Ein Fenster, das als einziges anders aussieht, ist kein
   besonderes Fenster, sondern ein fremdes: Das Auge sucht den Unterschied und
   findet keinen Sinn darin.

   Also trägt das Zauberbuch wieder die Steinhaut aller Fenster (`.panel` mit
   stein_dunkel.png und rahmen_gold.png, weiter unten). Das Werkzeug, das aus
   einem Bild ein dehnbares Bedienfeld schneidet, bleibt im Kasten stehen
   (tools/ui_rahmen.py) -- es hat nichts falsch gemacht, es wurde nur nicht
   gebraucht. */

/* DAS ZAUBERBUCH (15. September). Hier stand `#craftPanel { width:560px; }`
   -- die Werkstatt war ein eigenes Fenster. Jetzt ist sie eine Seite, und die
   Breite gehört dem Buch. 640 statt 560: Auf der Handwerksseite stehen jetzt
   Berufsliste UND Rezeptbuch übereinander, und die Rezeptspalte war bei 560
   gerade so breit wie ihr längster Name. */
/* DIE REITER BLEIBEN STEHEN, DER INHALT ROLLT (15. September).
   Oliver: *„springt das zauberbuch nur aus der reihe wenn ich -Weg- drücke,
   die anderen beiden tabs bleiben, nur Weg öffnet ein eigenes fenster"* und
   *„gib dem zauberbuch mal einen button um zurück zu kommen, so muss ich
   immer Z drücken"*.

   Beides dasselbe, und es ist kein zweites Fenster: `.panel` rollt als GANZES
   (`overflow:auto`). Die Fähigkeiten- und die Handwerksseite passen hinein,
   die Wegseite nicht -- sie ist mit Wegwahl und allen freischaltbaren
   Fähigkeiten die längste. Sobald sie über die Höhe hinausgeht, rollen
   Kopfzeile UND untere Reiterleiste mit weg: Das ✕ ist oben aus dem Bild,
   die Reiter unten darunter, und übrig bleibt eine lange Liste ohne Rahmen --
   die sieht aus wie ein eigenes Fenster, und zurück kommt man nur mit Z.

   Also rollt nur noch der SEITENKASTEN. Kopf und Reiter stehen fest, wie bei
   jedem Buch: Der Daumen bleibt am Register, egal wie lang die Seite ist. */
#spellbookPanel {
  width:640px;
  display:flex; flex-direction:column;
  max-height:80vh; overflow:hidden;
}
#spellbookPanel .panelHead { flex:0 0 auto; }
#spellbookPanel #buchSeiten { flex:1 1 auto; overflow-y:auto; min-height:0; }
/* `margin-top:auto` schiebt die Leiste im nicht-rollenden Fenster nach unten
   -- in einem Flexkasten mit einem wachsenden Nachbarn schiebt es sie
   allerdings ÜBER den Rand hinaus (gemessen: 6 Punkte, genug, dass die Reiter
   angeschnitten sind). Hier drückt schon der Seitenkasten, die Leiste braucht
   nichts zu schieben. */
#spellbookPanel .reiterLeiste.reiterUnten { flex:0 0 auto; margin-top:0; }
/* DER HINWEISSATZ IN EINEM FENSTER (15./16. September)
   -----------------------------------------------------------------------
   `.msg` wird an einem Dutzend Stellen vergeben -- und es gab die Regel dazu
   GAR NICHT, außer im Charaktereditor (`.ccStart .msg`). Jeder so markierte
   Satz erbte darum einfach die Fensterschrift und stand ohne Polster
   zwischen seinen Nachbarn.

   Zweimal ist mir dasselbe an zwei Elementen begegnet -- erst
   `#spellbookHint` („das zauberbuch verschluckt text"), dann `#craftHint`
   (der Fließtext klebte am Fensterrand). Beim zweiten Mal ist es kein
   Einzelfall mehr, sondern eine fehlende Regel. Also steht sie hier, einmal,
   für alle Fenster: ein Hinweis ist kein Fließtext -- kleiner, leiser, mit
   Luft nach oben und unten. */
.panel .msg {
  font-size:var(--schrift-klein); line-height:1.5;
  padding:8px 14px 10px; margin:0;
  color:var(--text-leise);
}
.panel .msg:empty { display:none; }
/* Kein Rollen IM Rollen: Die Listen hatten eigene Höhengrenzen, solange sie
   in einem Fenster standen, das selbst nicht rollte. Jetzt rollt die Seite,
   und zwei Rollbalken ineinander sind einer zu viel. */
#spellbookPanel .zauberListe,
#spellbookPanel .zauberBerufe { max-height:none; overflow:visible; }
/* Die Seiten liegen übereinander, immer eine sichtbar. Die Höhe hängt am
   Fenster und nicht am Inhalt: Ein Buch, das beim Umblättern die Größe
   wechselt, springt unter der Hand weg. */
#buchSeiten { display:flex; flex-direction:column; min-height:min(52vh, 460px); }
/* ZWEI REITERREIHEN, ZWEI RICHTUNGEN (15. September).
   Oben die Abteilungen des aufgeschlagenen Buchs, unten die drei Bücher --
   und das Auge muss auf einen Blick sehen, welche welche ist. Die obere Reihe
   sitzt deshalb AUF der Seite (Kante unten offen, sie geht in die Seite
   über), die untere UNTER ihr (Kante oben offen, sie trägt die Seite). Wären
   beide gleich gezeichnet, wären es zwei gleichrangige Listen. */
.reiterLeiste.reiterOben { padding:10px 14px 0; border-bottom:1px solid rgba(227,189,109,.16); }
.reiterLeiste.reiterUnten {
  padding:8px 14px 10px; margin-top:auto;
  border-top:1px solid rgba(227,189,109,.22);
  background:linear-gradient(180deg, rgba(0,0,0,.18), rgba(0,0,0,.34));
}
.reiterLeiste.reiterUnten .reiter { font-weight:700; }
.buchSeite { display:flex; flex-direction:column; }
.buchSeite.hidden { display:none; }
/* Die Überschrift der Handwerksseite -- vormals die Kopfzeile des eigenen
   Fensters. */
.buchKopf { padding:10px 14px 0; font-weight:700; color:#f0e3c2; letter-spacing:.3px; }
/* Auf der Handwerksseite stehen zwei Listen übereinander; die obere (die
   Berufe) darf nicht die ganze Höhe nehmen. */
#buchFaehigkeiten .zauberBerufe { max-height:30vh; overflow-y:auto; }
.craftSplit { display:flex; gap:10px; padding:10px 14px 14px; align-items:stretch; }
#recipeList { flex:0 0 46%; max-height:46vh; overflow-y:auto; padding-right:2px; }
#craftDetail { flex:1; border:1px solid var(--linie); background:var(--feld);
  padding:11px 12px; align-self:flex-start; width:100%; }
.rZeile { display:flex; align-items:center; gap:7px; padding:6px 8px;
  margin-bottom:4px; cursor:pointer; }
.rZeile:hover { border-color:#c9a227; }
.rZeile.aktiv { border-color:#c9a227; background:rgba(201,162,39,.12); }
.rZeile .rIcon { flex:0 0 auto; }
.rZeile .rName { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; font-size:12.5px; }
.rZeile .rName i { font-style:normal; color:var(--text-leise); font-size:11px; }
.rZeile .rBaubar { color:var(--gruen); font-size:10px; }
/* WAS FÜR EIN STÜCK, UND AB WANN TRAGBAR. Zwei kleine Marken hinter dem
   Namen -- L/M/S für die Rüstungsklasse, "St 8" für die Tragestufe. Sie
   nehmen keine eigene Zeile: Wer die Liste überfliegt, soll sehen, was für
   ihn ist, ohne dafür etwas anzuklicken. Rot heißt: kannst du nicht tragen
   (falsche Klasse) oder noch nicht (zu niedrige Stufe). */
.rZeile .rMarken { display:inline-flex; gap:4px; margin-left:5px; vertical-align:middle; }
.rZeile .rKlasse, .rZeile .rStufe {
  font-size:9.5px; line-height:1.5; padding:0 4px; border-radius:3px;
  background:rgba(255,255,255,.07); color:var(--text-leise);
  border:1px solid rgba(255,255,255,.10); font-weight:600; letter-spacing:.3px; }
.rZeile .rVerwehrt { color:#e2695f; border-color:rgba(226,105,95,.45); background:rgba(226,105,95,.10); }
/* Der Rezeptname trägt die WoW-Farbe seiner Lernchance. */
.rZeile.farbe_orange .rName { color:#e08a3c; }
.rZeile.farbe_gelb   .rName { color:#e0d24a; }
.rZeile.farbe_gruen  .rName { color:#7ee081; }
.rZeile.farbe_grau   .rName { color:#8b8f9c; }
.rZeile.farbe_gesperrt .rName { color:#8b8f9c; }
.rZeile.farbe_gesperrt { opacity:.55; }
.craftDetail .dLeer, #craftDetail .dLeer { color:var(--text-leise); font-size:12px; }
#craftDetail .dKopf { display:flex; gap:9px; align-items:center; margin-bottom:8px; }
#craftDetail .dIcon { font-size:26px; line-height:1; }
#craftDetail .dName { font-weight:700; font-size:14px; }
#craftDetail .dName i { font-style:normal; color:var(--text-leise); font-size:11.5px; }
#craftDetail .dErgibt { font-size:11px; color:var(--text-leise); margin-top:2px; }
#craftDetail .dFarbe.farbe_orange { color:#e08a3c; }
#craftDetail .dFarbe.farbe_gelb   { color:#e0d24a; }
#craftDetail .dFarbe.farbe_gruen  { color:#7ee081; }
#craftDetail .dFarbe.farbe_grau   { color:#8b8f9c; }
#craftDetail .dFarbe.farbe_gesperrt { color:#ff9b6b; }
#craftDetail .dZeile { font-size:12px; margin-bottom:6px; }
#craftDetail .dEffekt { color:var(--gruen); }
#craftDetail .dHinweis { color:var(--text-leise); font-style:italic; }
/* „Noch nicht — ab Schmiedekunst 8" (21. September): Der Satz, der erklärt,
   warum der Herstellen-Knopf grau ist. Nicht rot (es ist kein Fehler) und
   nicht leise (er ist die Antwort auf die Frage, die der Spieler hat) --
   also die warme Sandfarbe und aufrecht statt kursiv. */
#craftDetail .dNochNicht { color:#e0c07a; font-style:normal; }
#craftDetail .dMatKopf { font-size:10.5px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--text-leise); margin:8px 0 5px; }
#craftDetail .dMat { font-size:12.5px; margin-bottom:4px; }
#craftDetail .dMat.ok { color:var(--gruen); }
#craftDetail .dMat.bad { color:var(--rot); }
#craftDetail button { margin-top:8px; }

/* ---------- Galaxiekarte ---------- */
#mapList { padding:10px 14px; }
.mapEntry { display:flex; justify-content:space-between; align-items:center; gap:10px; padding:11px; border:1px solid var(--linie); background:var(--feld); margin-bottom:8px; cursor:pointer; transition:border-color .12s ease; }
.mapEntry:hover { border-color:var(--sand); }
.mapEntry .mName { font-weight:700; color:var(--text); }
.mapEntry .mDesc { font-size:11px; color:var(--text-leise); }
.mapEntry.locked { opacity:.5; cursor:default; }
.mapEntry.locked:hover { border-color:var(--linie); }

/* ---------- Logbuch, Chat ---------- */
#logList { padding:10px 14px; font-size:13px; }
.logEntry { padding:7px 0; border-bottom:1px solid var(--linie-leise); color:var(--text-leise); line-height:1.5; }
.logEntry .lt { display:block; font-size:10px; color:var(--text-fern); }

#chatMessages { padding:10px 14px; font-size:13px; max-height:280px; overflow-y:auto; }
.chatMsg { margin-bottom:6px; line-height:1.45; }
.chatMsg .from { color:var(--sand); font-weight:700; margin-right:6px; }
.chatMsg.sys { color:var(--violett); font-style:italic; }
/* ---- Systemzeilen im Chat: was mir gerade passiert ist ----
   Sie sind schmaler gesetzt als Gerede und haben keinen Sprechernamen --
   man erkennt auf einen Blick, dass hier niemand spricht. */
.chatMsg.sysZeile { margin-bottom:3px; line-height:1.4; font-size:12.5px; }
.chatMsg.zugang .zgKopf { color:var(--text-fern); }
.chatMsg.zugang .zgIcon { font-size:13px; }
.chatMsg.zugang .zgMenge { color:var(--text-leise); }
/* Die Seltenheitsfarben -- dieselbe Sprache wie in jedem MMO: weiß,
   blau, violett, orange. Wer die Zeile im Augenwinkel sieht, weiß an der
   FARBE, ob es sich lohnt hinzusehen. */
.sel-common { color:#e7dfd0; }
.sel-rare { color:#5aa9f5; }
.sel-epic { color:#b07bff; }
.sel-ultra { color:#ef9a3c; }
/* UMBRECHEN STATT ZUSAMMENQUETSCHEN (15. September, aus dem Durchlauf P1).
   Gemessen auf sieben Bildschirmbreiten: Die Kanalwahl ist 87 Punkte breit,
   "Senden" 81 -- zusammen mit den Abständen 180, und die ändern sich nie.
   Was übrig bleibt, bekommt das Eingabefeld, und bei 1280x760 waren das
   29 Punkte. Man konnte nicht sehen, was man tippt.
   Der Fehler war nicht die Breite, sondern dass die Zeile nur EINE sein
   durfte: Drei Dinge, die zusammen nicht passen, passen auch nicht besser,
   wenn man eines davon auf null schrumpft. */
.chatInputRow { display:flex; flex-wrap:wrap; gap:6px; padding:10px 14px; border-top:1px solid var(--linie-leise); }
.chatInputRow select, .chatInputRow input {
  background:var(--feld); border:1px solid var(--linie); color:var(--text);
  padding:7px 9px; font-family:inherit; font-size:12.5px;
}
/* 150 ist keine runde Zahl, sondern die gemessene: Darunter sieht man vom
   eigenen Satz weniger als zwei Wörter. Als flex-basis UND als min-width --
   das erste sagt „so breit hätte ich gern", das zweite „darunter gehe ich
   lieber in die nächste Zeile". Ohne min-width bliebe es beim alten Verhalten
   (min-width:auto lässt ein Flex-Kind zwar nicht unter seinen Inhalt, ein
   leeres Feld hat aber keinen), und die Zeile bräche nie um. */
.chatInputRow input { flex:1 1 150px; min-width:150px; }
.chatInputRow select { flex:0 0 auto; max-width:100px; }
.chatInputRow button { flex:0 0 auto; white-space:nowrap; }
.chatInputRow select:focus, .chatInputRow input:focus { outline:none; border-color:var(--sand-leise); }

#toastLayer { position:absolute; top:70px; left:50%; transform:translateX(-50%); z-index:20; display:flex; flex-direction:column; gap:8px; pointer-events:none; }

/* ---------- Ein Gebiet geht auf ----------
   Oliver, 11. September: „wenn auf der karte ein neues gebiet aufgedeckt
   wird text: gebiet x entdeckt und einen sound effekt".

   Kein Kasten, kein Rahmen: Der Name steht frei über der Welt, so wie der
   Gebietsname in WoW. Lesbar bleibt er durch den Schatten, nicht durch einen
   Hintergrund -- ein Kasten würde die Welt zudecken, die man gerade entdeckt.
   Weit oben (22 %), damit er nicht in der Figur steht, und ohne
   Mausereignisse, damit er mitten im Laufen keinen Klick wegnimmt. */
#gebietBanner {
  position:absolute; top:22%; left:50%; transform:translate(-50%, -8px);
  z-index:19; pointer-events:none; text-align:center;
  opacity:0; transition:opacity .45s ease, transform .45s ease;
}
#gebietBanner.an { opacity:1; transform:translate(-50%, 0); }
#gebietBanner .gbName {
  display:block; font-size:34px; font-weight:600; letter-spacing:.02em;
  color:#f0d99a; text-shadow:0 2px 10px rgba(0,0,0,.85), 0 0 26px rgba(0,0,0,.6);
}
#gebietBanner .gbUnter {
  display:block; margin-top:2px; font-size:13px; letter-spacing:.28em;
  text-transform:uppercase; color:rgba(240,217,154,.72);
  text-shadow:0 2px 8px rgba(0,0,0,.85);
}
.toast { background:var(--flaeche-fest); border:1px solid var(--sand-leise); color:var(--text); padding:10px 18px; font-size:13px; box-shadow:0 10px 28px rgba(0,0,0,.5); animation:fadein .2s ease; }
@keyframes fadein { from{opacity:0; transform:translateY(-8px);} to{opacity:1; transform:translateY(0);} }

/* ---------- Der Nachthinweis ----------
   Es wird dunkel, und man weiß nicht, warum man nichts mehr sieht. Ein
   Spieler, der die Taste T nicht kennt, steht dann einfach im Schwarzen und
   hält es für einen Fehler. Also sagt es ihm jemand -- einmal, ruhig, und
   nur solange die Fackel aus ist.

   Er sitzt oben mittig UNTER den Meldungen (die kommen und gehen, er bleibt),
   in Fackelfarben statt im Sandton der übrigen Fenster: Er gehört zur Welt
   draußen, nicht zur Bedienung. */
#nachtHinweis { position:absolute; top:118px; left:50%; transform:translateX(-50%); z-index:19;
  display:flex; align-items:center; gap:14px; max-width:min(520px, 84vw);
  padding:12px 16px 12px 12px;
  background:linear-gradient(180deg, rgba(30,20,10,.94), rgba(18,12,6,.96));
  border:1px solid #6b4a1e; border-left:3px solid #e8a53f;
  box-shadow:0 12px 34px rgba(0,0,0,.6), 0 0 22px rgba(232,165,63,.12);
  animation:fadein .25s ease; }
#nachtHinweis.hidden { display:none; }
#nachtHinweisFlamme { flex:0 0 auto; display:block; }
#nachtHinweisText { flex:1; min-width:0; color:#f3e6cf; font-size:13px; line-height:1.5; }
#nachtHinweisText b { color:#ffd27a; }
/* Die Taste sieht aus wie eine Taste. Das spart den halben Satz. */
#nachtHinweisText kbd { display:inline-block; min-width:19px; text-align:center;
  padding:1px 6px; margin:0 1px; border:1px solid #a8813c; border-bottom-width:2px;
  background:#3a2a13; color:#ffd995; font:inherit; font-weight:700; font-size:12px; }
#nachtHinweisWeg { flex:0 0 auto; align-self:flex-start; width:22px; height:22px; line-height:1;
  background:none; border:1px solid transparent; color:#b79a6f;
  font-size:15px; cursor:pointer; }
#nachtHinweisWeg:hover { color:#ffd27a; border-color:#6b4a1e; }

/* ---------- Charakterblatt ---------- */
.charPanelBody { display:flex; gap:16px; padding:14px; align-items:flex-start; }
/* Die Figur ist das Größte im Fenster -- sie ist der Grund, es zu öffnen.
   Hier stand einmal 140x140: eine Briefmarke in einem Blatt, das dreimal so
   hoch ist. Rahmen und Grund liegen jetzt an .charFigur, damit die Leinwand
   selbst nur noch die Zeichnung ist. */
/* Die Figur nimmt, was übrig ist: Der Rest des Blattes (Kopfzeile, Werte)
   braucht rund 380 Punkte, alles darüber gehört ihr. So bleibt sie so groß
   wie möglich UND das Fenster passt auf jeden Bildschirm.
   SEIT DEN SECHS RÜSTUNGSPLÄTZEN sind es 380 statt 340 und höchstens 250
   statt 300: Die Werteliste hat eine Zeile mehr (Zauberkraft) und darunter
   die Satzboni, und die Platzspalte daneben ist sechs Felder hoch. Bei 300
   stieß das Fenster auf einem 900er Schirm oben und unten an. */
#charPanelPreview { display:block; flex-shrink:0;
  height:min(250px, calc(100vh - 420px)); width:auto; aspect-ratio:190 / 256; }
.charPanelInfo { flex:1; min-width:0; }
.charPanelName { font-size:18px; font-weight:700; color:var(--text); }
.charPanelLvl { font-size:12px; color:var(--text-leise); margin:3px 0 12px; }

/* ---------- Archiv ---------- */
#archivePanel { width:420px; }
#archiveList { padding:10px 14px 14px; max-height:420px; overflow-y:auto; display:flex; flex-direction:column; gap:8px; }
.archiveChapter { font-size:12.5px; font-weight:700; color:var(--violett); padding-bottom:4px; }
.archiveRow { padding:11px 12px; border:1px solid var(--linie); background:var(--feld); }
.archiveTitle { font-size:13px; font-weight:700; color:var(--text); margin-bottom:5px; }
.archiveText { font-size:12px; color:var(--text-leise); line-height:1.55; }

/* ---------- Gruppenanzeige ----------
   Unter der eigenen Lebensanzeige, gleiche Bauart, nur kleiner -- man soll auf
   einen Blick sehen, wem es schlecht geht, ohne ein Fenster zu öffnen. */
/* Unter dem Zielrahmen (top 96, ~76 hoch) -- vorher lagen beide auf 92/96 px
   übereinander, und sobald man eine Kreatur anklickte, verdeckte ihr Rahmen
   die Gruppe. Genau dann braucht die Bewahrerin sie. */
#partyFrames { position:absolute; top:182px; left:16px; width:230px; z-index:6; display:flex; flex-direction:column; gap:4px; pointer-events:none; }
.pFrame { background:rgba(36,28,20,.9); border:1px solid var(--linie); padding:6px 9px; }
.pFrame.away { opacity:.5; }
.pName { font-size:12px; font-weight:700; color:var(--text); display:flex; justify-content:space-between; gap:6px; }
.pName .pLvl { color:var(--text-leise); font-weight:400; }
.pBar { position:relative; height:8px; margin-top:4px; background:var(--grund); border:1px solid var(--linie-leise); overflow:hidden; }
.pBar > i { display:block; height:100%; background:linear-gradient(90deg,#a8442f,#d9704d); }
.pWhere { font-size:10px; color:var(--text-fern); margin-top:3px; }
/* Gefallen: wo der Körper liegt (B24) -- die Bewahrerin muss dorthin. */
.pWhere.pTot { color:#9aa1c2; }
.pLeaderMark { color:var(--gold); }

/* ---------- Zielanzeige ---------- */
/* Oben LINKS, wie das Zielfenster in jedem MMO -- mittig stand er unter den
   Meldungen (#toastLayer) und dem Questhinweis und war dort unsichtbar. */
#targetFrame {
  position:absolute; top:96px; left:14px; width:290px; z-index:6;
  background:rgba(36,28,20,.92); border:1px solid var(--linie); padding:7px 10px; pointer-events:none;
  display:flex; align-items:center; gap:10px;
}
#targetFrame.hidden { display:none; }
#targetFrame .tPortrait {
  flex:0 0 44px; width:44px; height:44px; border-radius:50%;
  border:2px solid var(--gold); background:radial-gradient(circle at 50% 35%, #4a3a28, #1a1410 80%);
  box-shadow:0 0 0 1px rgba(0,0,0,.7), 0 2px 6px rgba(0,0,0,.6); image-rendering:pixelated;
}
#targetFrame[data-art="mob"] .tPortrait { border-color:var(--rot); }
#targetFrame[data-art="ich"] .tPortrait { border-color:#8fe4ff; }
#targetFrame[data-art="spieler"] .tPortrait { border-color:#7ee081; }
#targetFrame .tBody { flex:1 1 auto; min-width:0; }
#targetFrame .tName { font-size:13px; font-weight:700; color:var(--text); display:flex; justify-content:space-between; gap:8px; }
#targetFrame .tName > span:first-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
#targetFrame .tSub { font-size:11px; color:var(--text-fern); margin-top:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
#targetFrame .tBar.freund > i { background:linear-gradient(90deg,#3f8a45,#7ee081); }
#targetFrame .tRank { font-size:11px; }
#targetFrame .tRank.elite { color:var(--gold); }
#targetFrame .tRank.boss { color:var(--rot); }
#targetFrame .tBar { position:relative; height:13px; margin-top:5px; background:var(--grund); border:1px solid var(--linie-leise); overflow:hidden; }
#targetFrame .tBar > i { display:block; height:100%; background:linear-gradient(90deg,#a8442f,#d9704d); transition:width .2s ease; }
#targetFrame .tBar > span { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-size:10px; font-weight:700; color:var(--text); text-shadow:0 1px 2px rgba(0,0,0,.9); }

/* ---------- Gruppeneinladung ---------- */
#inviteToast {
  position:absolute; top:120px; left:50%; transform:translateX(-50%); z-index:20;
  background:var(--flaeche-fest); border:1px solid var(--sand-leise);
  padding:14px 20px; text-align:center; box-shadow:0 12px 34px rgba(0,0,0,.55);
}
#inviteText { font-size:13px; margin-bottom:10px; }
.inviteBtns { display:flex; gap:8px; justify-content:center; }

/* ---------- Gruppenfenster ---------- */
#partyPanel { width:320px; }
#partyHint { padding:0 14px; }
#partyInviteName { flex:1; background:var(--feld); border:1px solid var(--linie); padding:7px 9px; color:var(--text); font-size:12px; font-family:inherit; }
#partyInviteName:focus { outline:none; border-color:var(--sand-leise); }
#partyList { padding:0 14px 10px; display:flex; flex-direction:column; gap:6px; }
.partyRow { display:flex; align-items:center; gap:8px; padding:8px 10px; border:1px solid var(--linie); background:var(--feld); font-size:12px; }
/* Das Botvolk in der Liste "Auf dieser Welt": leiser, mit ◇ -- kein Mensch. */
.partyRow.botvolk { opacity:.72; }
.partyRow.botvolk .prName { color:var(--text-leise); }
.partyRow .prName { flex:1; font-weight:700; }
.partyRow .prMeta { color:var(--text-leise); font-size:11px; }
.partyRow button { padding:3px 9px; font-size:10px; }

/* ---------- Geteilte Aufgabe ----------
   Gleiche Bühne wie die Gruppeneinladung, aber eine Stufe tiefer, damit beide
   gleichzeitig lesbar bleiben. */
#questOfferToast {
  position:absolute; top:180px; right:20px; width:280px; z-index:26;
  background:var(--flaeche-fest); border:1px solid var(--sand-leise);
  padding:13px 15px; box-shadow:0 12px 34px rgba(0,0,0,.55);
}
#questOfferText { font-size:13px; font-weight:700; margin-bottom:5px; color:var(--text); }
#questOfferSummary { font-size:11px; color:var(--text-leise); line-height:1.45; margin-bottom:10px; }

/* ---------- Tod: Geistermodus ----------
   Die ganze Bühne verliert die Farbe, nicht nur die Leinwand -- sonst sähe es
   nach einem Grafikfehler aus statt nach einem Zustand. Der kalte Rand ist das,
   was von der Welt übrig bleibt, wenn man nicht mehr dazugehört. */
#gameScreen.istGeist #gameCanvas { filter:grayscale(1) brightness(.7) contrast(1.05); }
#gameScreen.istGeist #vitals,
#gameScreen.istGeist #actionDock,
#gameScreen.istGeist #topBar { filter:grayscale(.85) brightness(.85); }
#gameScreen.istGeist::after {
  content:''; position:absolute; inset:0; pointer-events:none; z-index:4;
  background:radial-gradient(circle at 50% 50%, rgba(120,140,170,0) 35%, rgba(30,38,52,.6) 100%);
}

#deathPanel {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  width:340px; z-index:30; text-align:center;
  background:var(--flaeche-fest); border:1px solid var(--linie);
  padding:22px 24px; color:var(--text); box-shadow:0 20px 60px rgba(0,0,0,.7);
}
/* Der erste Tod: die Erklärung im Fenster (B19). Einmal je Charakter. */
#deathPanel:has(.dpErklaerung) { width:430px; }
#deathPanel .dpWoran { font-size:12px; color:var(--rot); margin:-4px 0 8px; }
#deathPanel .dpErklaerung { text-align:left; border:1px solid var(--linie); background:rgba(0,0,0,.25); padding:10px 12px; margin:0 0 12px; font-size:12.5px; line-height:1.55; }
#deathPanel .dpErklaerungKopf { font-weight:700; color:var(--sand); margin-bottom:6px; font-size:12px; letter-spacing:.06em; text-transform:uppercase; }
#deathPanel .dpErklaerung p { margin:0 0 6px; }
#deathPanel .dpErklaerung p.dpGruppe { margin-top:8px; color:var(--gold); }
/* Erwecken läuft (B24): jemand steht am Körper. Gold, über den Knöpfen. */
#deathPanel .dpErweckung { border:1px solid var(--gold); background:rgba(227,189,109,.10); color:var(--gold); padding:8px 10px; margin:0 0 12px; font-size:12.5px; line-height:1.5; }
#deathPanel .dpBewahrerin { color:var(--gold); margin-bottom:10px; }
#deathPanel .dpTitel { font-size:21px; font-weight:700; letter-spacing:.06em; color:#c6ccd6; margin-bottom:10px; }
#deathPanel .dpText { font-size:13px; color:var(--text-leise); line-height:1.6; margin-bottom:16px; }
#deathPanel button { width:100%; padding:10px; font-size:13.5px; }
#deathPanel .dpNote { font-size:11px; color:var(--text-fern); margin-top:7px; line-height:1.45; }
#deathPanel .dpTrenner { margin:14px 0 9px; font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-fern); }
/* Der Geistheiler ausser Reichweite: der Knopf tut trotzdem etwas (er peilt),
   also darf er nicht wie ein toter Knopf aussehen -- nur leiser. */
#deathPanel button.dpFern { opacity:.72; }
.buffPill.buffSick { border-color:var(--rot); color:var(--rot); }

/* ---------- Beutetasche ---------- */
#lootPanel {
  position:absolute; left:50%; top:58%; transform:translate(-50%,-50%);
  width:260px; z-index:24;
  background:var(--flaeche-fest); border:1px solid var(--linie);
  box-shadow:0 16px 44px rgba(0,0,0,.6);
}
#lootPanel .lootCredits { color:var(--gold); font-size:13px; padding:9px 14px 3px; }
#lootPanel .lootList { display:flex; flex-direction:column; gap:5px; padding:9px 14px; }
.lootRow {
  display:flex; align-items:center; gap:9px; padding:7px 10px; cursor:pointer;
  border:1px solid var(--linie); background:var(--feld); transition:border-color .12s ease, background .12s ease;
}
.lootRow:hover { border-color:var(--sand); background:var(--feld-hell); }
.lootRow .lootIcon { font-size:18px; }
.lootRow .lootName { flex:1; font-size:13px; }
/* "Nehmen" bekam die helle Steinkachel des Standardknopfs UND sandfarbene
   Schrift -- hell auf hell, es sah aus wie markierter Text. Jetzt ein
   kleiner dunkler Knopf, wie "Alles nehmen" darunter. */
.lootRow .lootTake {
  font-size:11px; color:var(--sand); padding:4px 10px;
  background-color:var(--feld); background-image:none;
  border:1px solid var(--linie); text-shadow:none; border-radius:3px;
}
.lootRow:hover .lootTake { border-color:var(--sand-leise); background-color:var(--feld-hell); filter:none; }
#lootPanel .lootLeer { color:var(--text-leise); font-size:12px; padding:10px; text-align:center; }
#lootPanel .lootAll { width:calc(100% - 28px); margin:0 14px 14px; padding:9px; font-size:13px; }

/* ---------- Der eigene Weg ---------- */
#pathChoice { padding:0 14px 12px; }
.pathHint { font-size:12px; color:var(--text-leise); line-height:1.55; padding:4px 0 10px; }
/* ---------- DIE HALTUNG (15. September, docs/designleitung_2001.md B) ----------
   Sie steht dort, wo bis zur Wegwahl nur „warte bis Stufe 5" stand. Deshalb
   sieht sie aus wie eine gewählte Rolle und nicht wie ein Hinweis: Sie IST
   die Rolle, nur eine, die sich mit den Händen ändert. */
.haltungJetzt { display:flex; align-items:flex-start; gap:12px; padding:11px 12px; margin-bottom:9px;
  background:rgba(227,189,109,.09); border:1px solid rgba(227,189,109,.34); border-radius:6px; }
.haltungIcon { font-size:26px; line-height:1; flex:none; }
.haltungName { font-weight:700; color:var(--gold); font-size:14px; margin-bottom:3px; letter-spacing:.3px; }
.haltungText { font-size:12px; color:var(--text-leise); line-height:1.5; }
/* Die beiden anderen stehen daneben -- nicht als Auswahl, sondern als
   Auskunft: SO kommt man dorthin. Ohne sie wäre die eigene Haltung ein
   Zustand, den man nicht beeinflussen kann, und das wäre das Gegenteil des
   Punktes. */
/* Das Wort der Wegfigur im Gesprächsfenster. Es steht unter der Begrüßung
   und ist eine ZWEITE Stimme derselben Person -- deshalb eingerückt und mit
   einem Zeichen davor, nicht als Kasten. Wer „seinen" Weg trägt, bekommt eine
   goldene Kante; wer nicht, eine stumpfe. Der Unterschied ist die halbe
   Auskunft. */
.npcHaltung { display:flex; gap:9px; align-items:flex-start; margin:10px 0 2px; padding:8px 11px;
  border-left:3px solid var(--linie); background:rgba(0,0,0,.2);
  font-size:12.5px; line-height:1.55; color:var(--text-leise); font-style:italic; }
.npcHaltung.eigen { border-left-color:var(--gold); color:var(--text); background:rgba(227,189,109,.08); }
.npcHaltung .nhIcon { font-size:15px; flex:none; font-style:normal; }
.haltungListe { display:flex; flex-direction:column; gap:4px; margin-top:9px; }
.haltungZeile { display:flex; align-items:center; gap:9px; padding:6px 9px; font-size:11.5px;
  background:rgba(0,0,0,.22); border:1px solid var(--linie-leise); border-radius:4px; color:var(--text-fern); }
.haltungZeile.an { border-color:rgba(227,189,109,.5); color:var(--text); background:rgba(227,189,109,.07); }
.hzIcon { font-size:15px; flex:none; }
.hzName { font-weight:700; min-width:68px; flex:none; }
.hzKurz { min-width:0; }
.pathHint.pathReady { color:var(--text); }
.pathCards { display:grid; grid-template-columns:repeat(3,1fr); gap:8px; }
.pathCard { padding:12px 9px; text-align:center; border:1px solid var(--linie); background:var(--feld); }
.pathCard .pathIcon { font-size:26px; }
.pathCard .pathName { font-weight:700; font-size:14px; margin:4px 0; color:var(--text); }
.pathCard .pathKurz { font-size:11px; color:var(--text-leise); min-height:32px; line-height:1.4; }
.pathCard .pathBonus { font-size:11px; color:var(--sand); margin:8px 0; }
.pathCard button { width:100%; padding:7px 4px; font-size:11.5px; }
.pathChosen { display:flex; gap:13px; align-items:flex-start; padding:12px; border:1px solid var(--sand-leise); background:var(--feld); }
.pathChosen .pathIcon { font-size:30px; }
.pathChosen .pathName { font-weight:700; font-size:15px; color:var(--text); }
.pathChosen .pathBonus { font-size:12px; color:var(--sand); margin:3px 0 5px; }
.pathChosen .pathDesc { font-size:11px; color:var(--text-leise); line-height:1.5; }

/* ---------- Bildlaufleisten ----------
   Die voreingestellten sind hellgrau und stechen aus jedem dunklen Fenster
   heraus wie ein Fremdkörper. */
@supports not selector(::-webkit-scrollbar) { * { scrollbar-width:thin; scrollbar-color:var(--linie) transparent; } }
/* Firefox kennt ::-webkit-scrollbar nicht -- dort dieselbe Absicht über
   scrollbar-width/-color (A9, Browser-Matrix). */
* { scrollbar-width:thin; scrollbar-color:var(--linie) transparent; }
*::-webkit-scrollbar { width:9px; height:9px; }
*::-webkit-scrollbar-track { background:transparent; }
*::-webkit-scrollbar-thumb { background:var(--linie); }
*::-webkit-scrollbar-thumb:hover { background:var(--sand-leise); }

/* ---------- Ladebild ----------
   Ein Szenenwechsel braucht einen Moment, in dem man ankommt. Ohne ihn steht
   man von einem Bild aufs nächste woanders, und das liest sich wie ein
   Aussetzer statt wie eine Reise.

   Das Bild bringt seinen Schriftzug unten selbst mit. Der Balken sitzt
   deshalb darüber -- nicht mittig, nicht darunter -- sonst zerschneidet er
   das Logo.

   Ausdrücklich mit voller Deckung: Das Ladebild verdeckt, dass die Welt
   dahinter gerade umgebaut wird. Halbtransparent würde man genau das sehen. */
#ladeScreen {
  position:fixed; inset:0; z-index:9000;
  background:#0b0810;
  display:flex; align-items:center; justify-content:center;
  opacity:1; transition:opacity .45s ease;
}
#ladeScreen.hidden { display:none; }
#ladeScreen.verblasst { opacity:0; pointer-events:none; }
/* 'versionAlt': Der Server ist neuer als diese Seite. Ueber allem, bis man
   neu laedt -- das ist die einzige Handlung, die hier noch Sinn hat. */
#versionScreen { position:fixed; inset:0; z-index:9500; background:rgba(11,8,16,.92); display:flex; align-items:center; justify-content:center; }
#versionScreen.hidden { display:none; }
#versionKasten { max-width:420px; padding:22px 26px; border:1px solid var(--gold, #c9a227); background:#17121d; color:#e6d6b4; text-align:center; box-shadow:0 0 30px rgba(0,0,0,.7); }
#versionKopf { font-size:16px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; margin-bottom:10px; color:var(--gold, #c9a227); }
#versionText { font-size:13px; line-height:1.55; margin-bottom:16px; }
#versionNeuLaden { padding:8px 18px; font-size:13px; cursor:pointer; }
/* Fehler melden (F9) */
/* Der Spielleiter im Chat (Verwaltung): Gold, nicht klickbar. */
.chatMsg.spielleiter { color:var(--gold); }
/* Die Einschätzung (Taste E): ein Satz in seiner Farbe, ohne Absender. */
.chatMsg.einschaetzung { font-style:italic; }
.chatMsg.einschaetzung .from { color:inherit; }
.chatMsg.einschaetzung.grau { color:#9aa1c2; }
.chatMsg.einschaetzung.gruen { color:#7ee081; }
.chatMsg.einschaetzung.gelb { color:#e3d16d; }
.chatMsg.einschaetzung.orange { color:#ff9b3d; }
.chatMsg.einschaetzung.rot { color:#ff4d4d; }
.chatMsg.einschaetzung.boss { color:#c07bff; }
.chatMsg.spielleiter .from { color:var(--gold); font-weight:700; }
#berichtPanel { width:420px; }
#berichtText { width:100%; box-sizing:border-box; font:inherit; font-size:12.5px; padding:8px; background:var(--feld); color:var(--text); border:1px solid var(--linie); resize:vertical; margin-bottom:8px; }
#berichtBild { margin-bottom:8px; }
#berichtBild img { max-width:100%; border:1px solid var(--linie); display:block; }
.berichtKnoepfe { display:flex; gap:8px; margin-bottom:6px; }
.berichtKnoepfe button.leise { opacity:.7; }
#berichtStand { min-height:1.2em; }
/* DER TESTRAHMEN: ein Zettel, kein Fenster voller Knöpfe. Breit genug für
   die Tastentabelle, Kapitel wie im Sagenbuch, die drei Karten des Abends
   oben -- das ist, was man tun soll; der Rest ist Nachschlagen. */
#rahmenPanel { width:520px; max-height:80vh; }
#rahmenInhalt { padding:6px 18px 18px; }
.rahmenEinstieg { font-size:13px; color:var(--text); line-height:1.7; padding:8px 0 4px; }
.rahmenKapitel {
  margin:18px 0 8px; padding-bottom:5px;
  font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--gold); border-bottom:1px solid var(--linie);
}
.rahmenText { font-size:12.5px; color:var(--text); line-height:1.65; }
.rahmenFehler { border-left:2px solid var(--rot, #c0392b); padding-left:10px; }
.rahmenListe { margin:0; padding-left:18px; font-size:12.5px; color:var(--text); line-height:1.6; }
.rahmenListe li { margin-bottom:5px; }
.rahmenKarten { display:flex; flex-direction:column; gap:8px; }
.rahmenKarte {
  display:block; border:1px solid var(--linie); background:var(--feld); padding:10px 12px; cursor:pointer;
  border-left:2px solid var(--gold);
}
.rahmenKarte.erledigt { border-left-color:var(--gruen); opacity:.75; }
.rahmenKarte.erledigt .rkTitel { text-decoration:line-through; }
.rahmenKarte input { vertical-align:middle; margin-right:6px; }
.rahmenKarte .rkTitel { font-weight:700; font-size:13px; color:var(--text); }
.rahmenKarte .rkText { font-size:12px; color:var(--text-leise); line-height:1.6; margin-top:6px; }
.rahmenKarte .rkBeleg { font-size:11.5px; color:var(--gold); line-height:1.55; margin-top:6px; }
.rahmenTasten { border-collapse:collapse; width:100%; font-size:12px; }
.rahmenTasten td { padding:4px 6px 4px 0; vertical-align:top; color:var(--text); border-bottom:1px solid rgba(255,255,255,.05); }
.rahmenTasten td.rtTaste { white-space:nowrap; font-weight:700; color:var(--sand); width:34%; }
.rahmenFuss { margin-top:16px; font-size:10.5px; color:var(--text-fern); letter-spacing:.04em; }
/* Der Kasten ist EXAKT so groß wie das gezeigte Bild, nicht wie das Fenster.
   Das ist der Grund, warum er sein Seitenverhältnis selbst ausrechnet: bei
   `contain` in einem breiteren Fenster liegen oben und unten schwarze Balken,
   und ein Balken bei "78 % der Fensterhöhe" landete dann mitten im Schriftzug.
   Prozentangaben hier drin beziehen sich auf das Bild. */
#ladeBild {
  position:relative;
  width:min(100vw, calc(100vh * 1408 / 768));
  height:min(100vh, calc(100vw * 768 / 1408));
  /* Welches Bild, würfelt index.html (--ladebild) -- der Zuschnitt steht
     hier, damit er nur an einer Stelle steht. */
  background:var(--ladebild, url('/ladebild.jpg')) center/contain no-repeat;
}
/* 64 % der BILDhöhe: knapp über dem Schriftzug.
   Hier stand 71 %, passend zum alten Bild (Schriftzug ab 77 %). Die drei
   neuen Ladebilder vom 14. September tragen ihn ab 70 % -- dort lag der
   Balken quer im Logo. 64 % stimmt für alle vier. */
#ladeLeiste {
  position:absolute; left:50%; top:64%; transform:translateX(-50%);
  width:min(38vw, 460px); height:7px;
  background:rgba(10,8,14,.72);
  border:1px solid rgba(227,189,109,.55);
  box-shadow:0 0 18px rgba(0,0,0,.65);
}
#ladeFortschritt {
  height:100%; width:0%;
  background:linear-gradient(90deg, #b98a3a, #e3bd6d);
  box-shadow:0 0 10px rgba(227,189,109,.7);
  transition:width .18s linear;
}
#ladeText {
  position:absolute; left:0; right:0; top:calc(64% - 26px);
  text-align:center; font-size:13px; letter-spacing:.06em;
  color:#e6d6b4; text-shadow:0 2px 8px #000;
}
/* Die Zahl unter dem Balken beim ersten Laden: "37 % · 5,6 von 15,1 MB".
   Bei der Reise zwischen zwei Szenen bleibt sie leer. */
#ladeZahl {
  position:absolute; left:0; right:0; top:calc(64% + 14px);
  text-align:center; font-size:12.5px; letter-spacing:.06em;
  color:#e6d6b4; text-shadow:0 2px 8px #000, 0 0 3px #000; font-variant-numeric:tabular-nums;
}
#ladeLeiste { overflow:hidden; }
/* Solange nur die Skripte kommen, sucht der Balken (siehe index.html). */
#ladeFortschritt.sucht { width:22%; animation:ladeSuche 1.3s ease-in-out infinite alternate; }
@keyframes ladeSuche { from { transform:translateX(-30%); } to { transform:translateX(400%); } }

/* ---------- Legende der Planetenkarte ----------
   Farben ohne Legende sind Dekoration. Erst mit ihr wird aus dem Punktemuster
   eine Karte, auf der man ablesen kann, wo man besser nicht hinläuft. */
#worldMapLegend {
  display:flex; flex-wrap:wrap; gap:10px 18px;
  padding:0 14px 12px; font-size:11px; color:var(--text-leise);
}
.legendGroup { display:flex; flex-wrap:wrap; align-items:center; gap:4px 10px; }
.legendTitel {
  font-weight:700; color:var(--sand); letter-spacing:.04em;
  text-transform:uppercase; font-size:10px; margin-right:2px;
}
.legendEintrag { display:flex; align-items:center; gap:5px; white-space:nowrap; }
.legendEintrag i { width:9px; height:9px; border-radius:50%; display:inline-block; }
.legendEintrag i.ring { box-shadow:0 0 0 2px var(--text); }
.legendHinweis { color:var(--text-leise); font-style:italic; opacity:.85; }
/* Die gemalte Karte braucht Platz: ein breiteres Fenster als die anderen. */
#worldMapPanel { width:600px; max-height:90vh; }
#worldMapCanvas { image-rendering:auto; background:#cdb78d; cursor:crosshair; }

/* ---------- Questpeiler ----------
   Sitzt unter der Aufgabenanzeige. Bewusst klein und unauffällig: er ist eine
   Hilfe für den, der sich verlaufen hat, und kein ständig sichtbarer Marker. */
#questPingBtn {
  /* Direkt unter der Aufgabenanzeige (top:120px + deren Höhe), rechts bündig. */
  position:absolute; top:112px; right:16px; z-index:6;
  font-size:11.5px; padding:6px 11px;
  background:var(--flaeche-fest); border:1px solid var(--linie); color:var(--sand);
  cursor:pointer; opacity:.85;
}
#questPingBtn:hover { opacity:1; border-color:var(--sand-leise); }
#questPingBtn.hidden { display:none; }

/* ---------- Klangregler ---------- */
#klangPanel { width:300px; }
.klangZeile {
  display:flex; align-items:center; gap:10px;
  padding:8px 14px; font-size:12.5px; color:var(--text-leise);
}
.klangZeile span:first-child { min-width:56px; color:var(--text); }
.klangZeile input[type=range] { flex:1; accent-color:var(--gold); }
.klangZeile label { display:flex; align-items:center; gap:7px; color:var(--text); cursor:pointer; }
.klangNote { padding:2px 14px 14px; font-size:11px; color:var(--text-leise); line-height:1.5; }

/* ---------- Nachfrage im Spiel ----------
   Ersetzt das confirm() des Browsers bei der Wegwahl. Ein graues Systemfenster
   mit "localhost" in der Kopfzeile liest sich wie ein Fehler; die einzige
   unumkehrbare Entscheidung des Spiels hat etwas Besseres verdient. */
#frageOverlay {
  /* `fixed` statt `absolute`: Das Fenster haengt seit dem 15. September am
     Koerper (siehe frageNach) und nicht mehr am Spielschirm -- absolut
     positioniert waere es sonst am naechsten positionierten Vorfahren
     ausgerichtet und koennte beim gescrollten Wegschirm verrutschen. */
  position:fixed; inset:0; z-index:60;
  background:rgba(9,7,5,.72); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center;
}
#frageOverlay.hidden { display:none; }
.frageBox {
  width:400px; max-width:88vw; padding:22px 24px 18px;
  background:var(--flaeche-fest); border:1px solid var(--sand-leise);
  box-shadow:0 24px 70px rgba(0,0,0,.7); text-align:center;
}
.frageIcon { font-size:34px; line-height:1; margin-bottom:8px; }
.frageTitel { font-size:17px; font-weight:700; color:var(--sand); margin-bottom:10px; }
.frageText { font-size:13px; color:var(--text); line-height:1.6; }
.frageWarnung { margin-top:12px; font-size:12px; color:var(--rot); font-weight:700; }
.frageKnoepfe { display:flex; gap:10px; justify-content:center; margin-top:20px; }
/* JA IST DER HAUPTKNOPF, NEIN DER LEISE -- der Unterschied liegt jetzt in
   der Lautstärke derselben Form, nicht in zwei Formen. */
.frageKnoepfe button { padding:9px 18px; font-size:12.5px; font-weight:700; }
.frageKnoepfe .frageNein {
  background-image:linear-gradient(180deg, #cabfa4 0%, #b6a888 62%, #a89a7c 100%);
  border-color:#6f6247;
}

/* Ohne Station steht hier, wo das Rezept gebaut wird -- statt eines toten Knopfes. */
.rWo { font-size:11.5px; color:var(--text-leise); padding:2px 0 2px; }

/* ---------- Sagenbuch ----------
   Bewusst wie eine Buchseite gesetzt und nicht wie eine Liste: größere
   Laufweite, echte Absätze, Kapitelüberschriften. Es ist der einzige Ort im
   Spiel, an dem man LIEST statt abliest. */
#sagaPanel { width:430px; max-height:74vh; }
#sagaBuch { padding:6px 20px 20px; }
.sagaLeer { font-size:12.5px; color:var(--text-leise); line-height:1.7; padding:10px 0; }
.sagaKapitel {
  margin:20px 0 4px; padding-bottom:6px;
  font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--gold); border-bottom:1px solid var(--linie);
}
.sagaKapitel:first-child { margin-top:6px; }
.sagaKapitelBlurb { font-size:11.5px; color:var(--text-leise); font-style:italic; margin:6px 0 12px; line-height:1.6; }
.sagaEintrag { margin:0 0 20px; }
.sagaTitel { font-size:14px; font-weight:700; color:var(--sand); margin-bottom:6px; }
.sagaOrt { font-size:10.5px; color:var(--text-fern); letter-spacing:.05em; margin-bottom:7px; }
.sagaText { font-size:13px; color:var(--text); line-height:1.75; white-space:pre-line; }
/* Der erste Buchstabe eines Eintrags größer -- eine Initiale, wie im Buch. */
.sagaText::first-letter { font-size:20px; color:var(--gold); font-weight:700; }
.sagaFuss { margin-top:16px; padding-top:10px; border-top:1px solid var(--linie);
  font-size:11px; color:var(--text-leise); font-style:italic; }

/* Seltenheit im Tooltip -- eine Zeile unter dem Namen, in derselben Farbe. */
.ttSelten { font-size:11px; letter-spacing:.08em; text-transform:uppercase; margin:-2px 0 6px; opacity:.9; }
/* Erbeutete Stücke im Rucksack: farbiger Rahmen statt farbiger Schrift --
   die Symbole sind klein, ein Rand ist auf einen Blick zu sehen. */
.slot.gefunden { box-shadow:inset 0 0 0 2px currentColor; }

/* WEG HEISST WEG.
   Der Knopf "Zum Grabstein" sagt: Peilung gesetzt, jetzt lauf. Genau dann ist
   das Fenster nur noch im Weg -- es schrumpfte vorher in die linke untere Ecke
   und lag dort auf dem Chat. Es verschwindet jetzt ganz und kommt von selbst
   zurück, sobald man am Grabstein steht. Wer vorher wieder hineinsehen will,
   hat den kleinen Griff oben. */
#deathPanel.beiseite { display:none; }
#deathReopen {
  position:absolute; top:56px; left:50%; transform:translateX(-50%); z-index:19;
  padding:6px 14px; font-family:inherit; font-size:12px; font-weight:700;
  background:rgba(24,18,14,.92); color:var(--sand);
  border:1px solid var(--linie); cursor:pointer;
}
#deathReopen:hover { border-color:var(--sand); color:var(--text); }
#deathReopen.hidden { display:none; }

/* Die verfolgte Aufgabe: die, die der Peiler zeigt. Ein Klick wechselt sie. */
.trackQuest.verfolgt { border-left-color:var(--gold); background:rgba(40,30,18,.86); }
.trackQuest:hover { background:rgba(40,32,22,.9); }

/* Zutaten direkt am Herstellungsziel -- sonst muss man an die Werkbank laufen,
   nur um zu erfahren, was man sammeln soll. */
.zutaten { display:flex; flex-wrap:wrap; gap:3px 10px; margin:4px 0 2px 14px; font-size:11px; }
.zutaten .zutatOk { color:var(--gruen); }
.zutaten .zutatFehlt { color:var(--rot); }
.zutaten .zutatWo { color:var(--text-leise); font-style:italic; }

/* Ressourcenleiste unter dem Leben: schmaler, damit klar ist, was zuerst zählt. */
/* Die Ressource der Klasse (Wut/Mana/Energie) ist KEINE Fußnote: gleicher
   Balken wie das Leben, direkt darunter -- so liest man beide mit einem
   Blick, wie es jedes MMO hält. */
.resTrack { height:26px; margin-top:4px; }
.resTrack.hidden { display:none; }
.resTrack .vitalLabel { font-size:13px; }

/* Kosten am Fähigkeitsknopf, und ein matter Knopf, wenn sie nicht reichen. */
.slotKosten {
  position:absolute; bottom:1px; right:3px; font-size:9.5px; font-weight:700;
  color:var(--sand); text-shadow:0 1px 2px #000; pointer-events:none;
}
.abilitySlot.zuTeuer { opacity:.42; }
.abilitySlot.zuTeuer .slotIcon { filter:grayscale(1); }

/* ---------- Anmeldung ----------
   Das Bild IST die Maske. Die beiden Eingabefelder liegen deshalb in Prozent
   auf den zwei Platten des Torbogens statt in einem Formular daneben --
   sonst wäre die Zeichnung nur Tapete hinter einem Kasten.

   Alles hängt an #loginBild, nicht am Fenster: Das Bild behält sein
   Seitenverhältnis, die Felder wandern mit. */
/* Das Anmeldebild in voller Länge, mit Rand statt Beschnitt.
   Ein Versuch mit `cover` (bildschirmfüllend) ist wieder raus: Er schnitt an
   den Seiten den gemalten Rahmen ab und zog das Bild bei jedem anderen
   Seitenverhältnis anders zu -- die Eingabefelder liegen aber in PROZENT auf
   dem Bild und wanderten mit. Ein schwarzer Rand ist ehrlicher als ein
   angeschnittener Rahmen. */
#loginScreen {
  display:flex; align-items:center; justify-content:center;
  background:#0b0906;
}
/* WIE GROSS DAS BILD WIRD (14. September).
   Hier stand `min(1408px, 96vw)` -- also eine Obergrenze in Bildpunkten, und
   die war die eigentliche Fessel: Auf einem breiten Schirm blieb der
   Anmeldeschirm bei 1408 Punkten stehen und lag als Briefmarke in der Mitte
   (Olivers Bildschirmfoto vom 14. September: „gut nur viel zu klein").

   Die Zahl 1408 ist die AUFLÖSUNG des Bildes, nicht seine Anzeigegröße --
   das zu verwechseln ist der Klassiker. Jetzt füllt es den Schirm bis an die
   engere der beiden Kanten, genau wie das Ladebild (#ladeBild), und die
   Formel ist absichtlich dieselbe: zwei Schirme desselben Spiels sollen sich
   nicht verschieden verhalten. */
#loginBild {
  position:relative;
  width:min(100vw, calc(100vh * 1408 / 768));
  aspect-ratio:1408 / 768;
}
#loginBild img { width:100%; height:100%; object-fit:contain; display:block; }

/* ---------------------------------------------------------------------------
   DER WIRBEL IM TOR (14. September)
   ---------------------------------------------------------------------------
   Oliver: *„kannst du mir das Portal im Login Screen noch animieren nur das
   was im Portal ist bitte"* -- und „nur das" ist die ganze Anforderung. Der
   Stein steht still, die Ruine steht still, der Schriftzug steht still.

   Die Scheibe ist aus dem Bild geschnitten (tools/login_wirbel.py) und liegt
   passgenau wieder an ihrem Platz. Die Zahlen sind AUSGERECHNET und nicht
   geschätzt: Mitte 707/400 und Durchmesser 376 von 1408x768 -- das Werkzeug
   druckt sie beim Bauen aus, damit hier niemand nachmessen muss.

   ZWEI LAGEN, GEGENLÄUFIG. Eine einzelne sich drehende Scheibe sieht aus wie
   ein Plattenteller: Das Auge findet einen Punkt und verfolgt ihn. Zwei
   Lagen in verschiedenem Tempo und verschiedener Richtung haben keinen
   solchen Punkt mehr -- daraus wird eine Strömung.

   Die zweite Lage war zuerst mit 42 % Deckkraft dabei, und das war zu viel:
   Zwei gegeneinander verdrehte Kopien DESSELBEN Bildes mitteln sich, und aus
   dem tiefen Violett mit goldenem Rand wurde ein milchiges Flieder. Im
   Schirmabzug war es sofort zu sehen. Jetzt trägt die erste Lage das Bild
   allein (volle Deckkraft, sie ersetzt die Malerei darunter genau), und die
   zweite ist nur noch ein Hauch Schlieren darüber.

   SEHR LANGSAM. 54 und 82 Sekunden je Umdrehung. Ein Portal, dem man beim
   Drehen zusehen kann, ist ein Ventilator; eines, bei dem man nach zehn
   Sekunden merkt, dass sich etwas verändert hat, ist ein Portal. */
#loginWirbel {
  position:absolute;
  /* Ausgedruckt von tools/login_wirbel.py, nicht geschätzt. Seit dem
     hochgerechneten Bild (2112x1152) sind es 1060 von 2112 statt 707 von
     1408 -- derselbe Punkt, nur genauer getroffen. */
  left:50.189%; top:52.083%;
  width:26.705%; aspect-ratio:1 / 1;
  /* Mittig auf den Punkt: über transform und nicht über negative Ränder.
     Ein Prozentwert bei margin-top bezieht sich in CSS auf die BREITE des
     Elternteils, nicht auf seine Höhe -- das ist die Sorte Falle, die erst
     auffällt, wenn jemand das Fenster schmaler zieht. */
  transform:translate(-50%, -50%);
  pointer-events:none;
  /* Ein sehr langsames Atmen über allem -- das Licht des Tores ist nicht
     konstant. Ohne das wirkt die Drehung mechanisch, mit ihm lebendig. */
  animation:wirbelAtem 11s ease-in-out infinite;
}
#loginWirbel i {
  position:absolute; inset:0;
  background:url('/assets/ui/login_wirbel.png') center/contain no-repeat;
  will-change:transform;
}
#loginWirbel i:nth-child(1) { animation:wirbelA 54s linear infinite; }
#loginWirbel i:nth-child(2) { animation:wirbelB 82s linear infinite; opacity:.16; }
@keyframes wirbelA { from { transform:rotate(0deg); } to { transform:rotate(360deg); } }
@keyframes wirbelB { from { transform:rotate(360deg) scale(1.07); } to { transform:rotate(0deg) scale(1.07); } }
@keyframes wirbelAtem { 0%, 100% { filter:brightness(1); } 50% { filter:brightness(1.06); } }
/* Wer Bewegung abgestellt hat, bekommt das Bild wie vorher. Ein Anmeldeschirm
   ist nichts, wovor man sich rechtfertigen muss. */
@media (prefers-reduced-motion: reduce) {
  /* DIE AUSWAHL MUSS SO GENAU SEIN WIE DIE, DIE SIE AUFHEBT.
     Hier stand `#loginWirbel i` -- und die Drehung lief weiter, weil
     `#loginWirbel i:nth-child(1)` genauer ist (ein Pseudo-Merkmal mehr) und
     deshalb gewinnt, auch innerhalb einer Medienabfrage. Ein „animation:none",
     das nichts abschaltet, sieht im Quelltext aus wie erledigte Arbeit;
     aufgefallen ist es nur, weil pw_test_anmeldung §6 hinsieht. */
  #loginWirbel,
  #loginWirbel i:nth-child(1),
  #loginWirbel i:nth-child(2) { animation:none; }
  #loginWirbel i:nth-child(2) { display:none; }
}
/* Die Schlitze liegen GANZ OBEN -- Begründung in index.html. */
#loginSchlitze { position:absolute; inset:0; pointer-events:none; }

/* ---------------------------------------------------------------------------
   DER SCHRIFTZUG -- OBEN LINKS (14. September)
   ---------------------------------------------------------------------------
   Oliver: *„setze das logo testweise mal nach oben links wie bei wow, dann
   sieht man den rest des bildes"*

   Und das ist der ganze Gewinn: Unten mittig stand er genau dort, wo das Tor
   auf dem Boden aufsetzt -- also vor dem einzigen Teil des Bildes, der die
   Größe des Tores erklärt. Oben links liegt Himmel, und Himmel verträgt einen
   Schriftzug.

   Alle Maße in Prozent, wie alles auf diesem Bild: Der Rahmen hat ein festes
   Seitenverhältnis, also wandert der Schriftzug beim Vergrößern mit und
   bleibt an derselben Stelle der Malerei.

   Er ist jetzt ein ELEMENT und nicht mehr Teil des JPEGs. Verschieben kostet
   damit eine Zeile statt eines neuen Durchgangs auf der Grafikkarte -- und
   der Schriftzug bleibt bei jeder Größe scharf, weil er als PNG in voller
   Auflösung vorliegt. */
/* ZWEI TEILE IM WÄHLER, NICHT EINER. `#loginBild img` (eine Kennung plus ein
   Elementname) ist genauer als `#loginLogo` (nur eine Kennung) -- und setzt
   damit width:100%/height:100% durch. Beim ersten Versuch stand der
   Schriftzug bildschirmfüllend über dem ganzen Tor. Dieselbe Falle wie bei
   der Bewegungsabschaltung eine Stunde vorher; CSS entscheidet nicht nach
   Reihenfolge, sondern nach Genauigkeit. */
#loginBild #loginLogo {
  position:absolute;
  left:2.6%; top:3.0%;
  /* 12 %, nicht 19 % (Oliver, 14. September: „zu groß das logo oben links").
     Der Schriftzug ist eine Marke, kein Bildinhalt -- er soll da sein und
     nicht auffallen. Zum Vergleich: World of Warcraft gibt seinem Zeichen
     oben links rund ein Neuntel der Bildbreite. Bei 1408 Punkten sind 12 %
     etwa 169 Punkte, und der Torbogen bleibt vollständig frei. */
  width:12%; height:auto;
  object-fit:contain;
  pointer-events:none;
  /* Ein weicher Schatten, sonst klebt er auf dem Bild statt davor zu stehen. */
  filter:drop-shadow(0 6px 14px rgba(0,0,0,.75)) drop-shadow(0 0 3px rgba(0,0,0,.6));
}

/* ---------------------------------------------------------------------------
   DIE BEIDEN SCHLITZE IM TOR
   ---------------------------------------------------------------------------
   Das Bild hat zwei gravierte Schlitze -- einen für den Namen, einen für das
   Passwort. Die Zahlen hier sind AUSGEMESSEN, nicht geschätzt: Im Bild
   (1408x768) liegt der obere Schlitz bei x 573..838 / y 284..314, der untere
   bei x 570..840 / y 429..458. In Prozent umgerechnet sitzen die Felder
   deshalb bei jeder Fenstergröße genau in ihrer Fassung -- der Rahmen hat ein
   festes Seitenverhältnis, also wandert nichts.

   Die Felder haben KEINEN eigenen Rahmen. Die Fassung ist gemalt; ein zweiter
   Kasten darüber wäre ein Rahmen im Rahmen. Sichtbar ist nur der Text und,
   beim Tippen, ein leises Leuchten aus der Tiefe des Schlitzes. */
.loginFeld { position:absolute; left:40.6%; width:18.9%; height:3.9%; }
.loginOben  { top:36.98%; }
.loginUnten { top:55.86%; }
.loginFeld .loginLabel {
  /* MITTIG ÜBER DER ZEILE, nicht links daneben. */
  position:absolute; bottom:100%; left:0; right:0; margin-bottom:7px;
  text-align:center;
  font-size:clamp(9px, .82vw, 13px); font-weight:700;
  letter-spacing:.18em; text-transform:uppercase; color:#f0dfae;
  text-shadow:0 2px 6px rgba(0,0,0,.95), 0 0 12px rgba(120,180,255,.5);
  white-space:nowrap;
  /* Die obere Beschriftung steht vor dem leuchtenden Stein -- ohne eine
     dunkle Unterlage geht Gold auf Gold verloren. Nur ein Hauch, damit es
     nicht wie ein aufgeklebtes Schild wirkt. */
  background:radial-gradient(ellipse at 50% 55%, rgba(6,4,10,.72), rgba(6,4,10,0) 72%);
  padding:2px 0;
}
.loginFeld input {
  width:100%; height:100%; display:block; box-sizing:border-box;
  background:transparent; border:none;
  color:#f6eee0; font-family:inherit; font-size:clamp(11px, .95vw, 15px);
  padding:0 12px; letter-spacing:.06em; text-align:center;
  text-shadow:0 1px 3px rgba(0,0,0,.9);
}
.loginFeld input:focus {
  outline:none;
  box-shadow:inset 0 0 14px rgba(150,200,255,.35);
}

#loginAktionen {
  position:absolute; left:50%; top:64%; transform:translateX(-50%);
  display:flex; gap:12px; white-space:nowrap;
}
/* DIE BEIDEN KNÖPFE (14. September).
   Oliver: *„nur das eintreten und Konto anlegen sehen so Hässlich aus"* --
   sie trugen die helle Steintextur aus dem Spiel: richtig in einer Leiste
   über dunklem Grund, falsch mitten auf einer gemalten Szene.

   Die Antwort war damals eine Ausnahme nur für diesen Schirm. Seit dem
   15. September ist daraus die REGEL geworden (Oliver: *„nimm für alle mal
   die die du im Login Schirm verwendet hast"*) -- die Farben stehen jetzt bei
   `.primaryBtn` weiter unten. Hier bleibt nur, was wirklich nur hier gilt:
   die Größe und die weite Sperrung, mit denen die beiden Knöpfe auf dem Tor
   stehen. */
#loginAktionen .primaryBtn {
  margin-top:0;
  padding:11px 28px;
  font-size:clamp(11.5px, 1.02vw, 14px);
  letter-spacing:.16em; text-transform:uppercase;
}
#loginAktionen .ghostBtn { font-weight:600; letter-spacing:.13em; }
.loginMsg {
  position:absolute; left:50%; top:71.5%; transform:translateX(-50%);
  margin:0; font-size:13px; color:#ffb2a0; text-shadow:0 2px 6px rgba(0,0,0,.9);
  white-space:nowrap;
}
.loginMsg.gut { color:#b6e8a8; }
/* Der Einladungscode: unter den Knöpfen, auf keiner Gravur -- deshalb mit
   eigener dunkler Unterlage, damit man das Feld auf dem Stein findet. */
.loginCode { left:50%; transform:translateX(-50%); top:76.5%; }
.loginCode input {
  background:rgba(6,4,10,.55); border:1px solid rgba(240,223,174,.35); border-radius:3px;
  letter-spacing:.2em; text-transform:uppercase;
}
.loginCode input::placeholder { color:rgba(246,238,224,.35); letter-spacing:.2em; }
/* Dank & Lizenzen: klein unten rechts auf dem Anmeldebild. Die Welt kommt
   aus Ryzom (CC BY-SA / FAL) -- die Namensnennung gehört ins Spiel, nicht
   nur in eine Textdatei. */
.creditsKnopf {
  position:absolute; right:2.2%; bottom:2.4%; font-size:11.5px; letter-spacing:.04em;
  background:rgba(14,10,7,.55); color:#c9b98f; border:1px solid rgba(201,185,143,.35);
  padding:4px 10px; cursor:pointer; text-shadow:0 1px 3px rgba(0,0,0,.9);
}
.creditsKnopf:hover { color:#f2e6c2; border-color:rgba(242,230,194,.6); }
/* „Passwort ändern" trägt dieselbe Klasse und säße damit exakt unter „Dank &
   Lizenzen" -- zwei Knöpfe übereinander, von denen man nur einen trifft.
   Deshalb rückt dieser eine Knopfbreite nach links. Prozente und nicht
   Pixel, weil das Anmeldebild mitskaliert. */
#passwortBtn { right:14%; }
@media (max-width: 720px) { #passwortBtn { right:2.2%; bottom:9%; } }

/* ---------- Ein eigenes Passwort setzen (20. September) ----------
   Dieselbe Sprache wie „Dank & Lizenzen": dunkles Glas über dem Tor. Die
   Tafel ist schmaler, weil vier kurze Felder untereinander stehen und eine
   breite Spalte sie auseinanderreißen würde. */
#passwortPanel {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); width:min(420px, 92vw);
  background:rgba(22,17,12,.97); border:1px solid var(--linie); z-index:31; display:flex; flex-direction:column;
  box-shadow:0 20px 60px rgba(0,0,0,.7);
}
#passwortPanel.hidden { display:none; }
#passwortBox { padding:14px 18px 18px; display:flex; flex-direction:column; gap:10px; }
#passwortHinweis { margin:0 0 2px; font-size:12.5px; line-height:1.5; color:var(--text-leise); }
/* Der Zwangsfall spricht anders als der freiwillige -- und er soll ins Auge
   fallen, weil der Spieler nicht selbst hierhergekommen ist. */
#passwortHinweis.muss { color:#ffcf9a; }
.pwFeld { display:flex; flex-direction:column; gap:3px; }
.pwFeld span { font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:#c9b98f; }
.pwFeld input {
  background:rgba(6,4,10,.55); border:1px solid rgba(240,223,174,.35); border-radius:3px;
  color:var(--text); font-family:inherit; font-size:14px; padding:6px 8px; width:100%;
}
.pwFeld input:focus { outline:none; border-color:rgba(242,230,194,.75); }
/* Die Meldung liegt hier IM Fluss, nicht absolut wie auf dem Anmeldebild --
   sonst stünde sie quer über den Feldern. Und sie darf umbrechen: „Das neue
   Passwort muss sich vom alten unterscheiden" passt in keine Zeile. */
#pwMsg { position:static; transform:none; white-space:normal; margin:0; }
#pwBtn { width:100%; }

/* ---------- Der Lautstärkeregler auf dem Anmeldeschirm ----------
   Gegenüber von „Dank & Lizenzen", in derselben Sprache: dunkles Glas,
   Sandfarbe, dünne Linie. Er soll dort sein, wenn man ihn sucht, und
   verschwinden, wenn man ihn nicht sucht -- deshalb ist der Schieber
   schmal und liegt fast im Bild.

   Ausgeklappt wird nichts: Ein Knopf, der erst ein Feld öffnet, in dem
   dann ein Regler steht, ist für eine einzige Zahl ein Umweg. */
#loginKlang {
  position:absolute; left:2.2%; bottom:2.4%; display:flex; align-items:center; gap:7px;
  background:rgba(14,10,7,.55); border:1px solid rgba(201,185,143,.35); padding:1px 8px 1px 4px;
}
#loginKlangBtn {
  background:none; border:0; color:#c9b98f; font-size:13px; line-height:1;
  padding:2px 2px; cursor:pointer; text-shadow:0 1px 3px rgba(0,0,0,.9);
}
#loginKlangBtn:hover { color:#f2e6c2; }
/* Der Schieber in derselben Höhe wie die Schrift daneben -- ein Bedienteil,
   das aus seinem Kasten herausragt, sieht aus wie hineingerutscht. */
#loginKlangRegler { width:92px; height:14px; accent-color:#c9b98f; cursor:pointer; }
/* Auf schmalen Fenstern rückt der Regler über den Knopf hinaus ins Bild --
   dann lieber nur der Lautsprecher: Ton an/aus ist die Hälfte der Frage und
   die wichtigere. */
@media (max-width: 520px) { #loginKlangRegler { display:none; } }
#creditsPanel {
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); width:min(720px, 92vw); max-height:84vh;
  background:rgba(22,17,12,.97); border:1px solid var(--linie); z-index:30; display:flex; flex-direction:column;
  box-shadow:0 20px 60px rgba(0,0,0,.7);
}
#creditsPanel.hidden { display:none; }
.creditsKopf { display:flex; justify-content:space-between; align-items:center; padding:10px 14px; font-weight:700; color:var(--gold); border-bottom:1px solid var(--linie-leise); }
#creditsText { margin:0; padding:14px 18px; overflow:auto; font:12.5px/1.55 ui-monospace, monospace; color:var(--text); white-space:pre-wrap; }

/* Knopf oben rechts: zurück zur Charakterauswahl. */
#charSelectBtn {
  background:var(--feld); border:1px solid var(--linie); color:var(--text-leise);
  font-family:inherit; font-size:12px; padding:6px 12px; cursor:pointer;
  transition:color .12s ease, border-color .12s ease;
}
#charSelectBtn:hover { color:var(--text); border-color:var(--sand-leise); }

/* ---------- Einfassung (Splitter in der Ausrüstung) ---------- */
.fassungListe { padding:2px 14px 6px; display:flex; flex-direction:column; gap:6px; }
.fassungZeile {
  display:flex; align-items:center; gap:9px; padding:7px 9px;
  background:var(--feld); border:1px solid var(--linie); font-size:12px;
}
.fassungZeile .fName { color:var(--text); font-weight:600; }
.fassungZeile .fStufe { color:var(--violett); letter-spacing:.14em; }
.fassungZeile .fBonus { color:var(--gruen); font-size:11px; }
.fassungZeile .fRechts { margin-left:auto; display:flex; gap:6px; align-items:center; }
.fassungZeile button { font-size:11.5px; padding:5px 9px; }
.fassungZeile button:hover:not(:disabled) { border-color:var(--sand-leise); }
.fassungZeile button:disabled { opacity:.45; cursor:default; }
.fassungHinweis { padding:0 14px 10px; font-size:11.5px; color:var(--text-fern); line-height:1.5; }
.fassungHinweis b { color:var(--violett); font-weight:600; }

/* ---------- Charakterblatt: Figur zwischen den Ausrüstungsplätzen ----------
   Der Aufbau folgt dem, was Spieler aus MMOs kennen: die Figur in der Mitte,
   ihre Ausrüstung links und rechts daneben, die Werte darunter. Er beantwortet
   damit auf einen Blick, was die Reihe unter der Figur nie konnte -- welches
   Teil an welcher Stelle sitzt. */
/* ---------- Kopfzeile des Charakterblatts ----------
   Bildnis, Name, Titel, Schließen -- in einer Zeile, wie bei einem Ausweis.
   Sie ersetzt die alte Fensterleiste: Zwei Kopfzeilen übereinander (einmal
   "Charakter", einmal der Name) waren eine zu viel. */
.charHead {
  display:flex; align-items:center; gap:14px;
  padding:14px 16px; border-bottom:1px solid var(--linie);
  background:linear-gradient(180deg, rgba(60,46,30,.55), rgba(0,0,0,0));
}
.charBildnis {
  width:54px; height:54px; flex:none; border-radius:50%; overflow:hidden;
  border:2px solid #6b563c; background:#15100c;
  box-shadow:0 3px 12px rgba(0,0,0,.55), inset 0 0 0 2px rgba(0,0,0,.45);
}
.charBildnis canvas { width:100%; height:100%; display:block; image-rendering:pixelated; }
.charHeadText { min-width:0; }
.charHead .closeBtn { margin-left:auto; }
.charKopf { padding:12px 14px 4px; }
.charPanelName { font-size:20px; font-weight:700; color:var(--sand); letter-spacing:.02em; }
.charPanelLvl { font-size:12.5px; color:var(--text-leise); margin-top:3px; }
/* Das Geld im Charakterfenster (20. September, Befund 11 von Vu): eine
   Zeile unter Stufe und Weg, in denselben Muenzfarben wie ueberall. */
.charPanelGeld { font-size:12.5px; color:var(--text-leise); margin-top:2px; }

/* ---------- Die Puppe ----------
   Plätze ringsherum statt in zwei Spalten daneben: oben, was am Kopf sitzt,
   unten, was in den Händen liegt, links die Rüstung, rechts das Zubehör. */
.slotReihe { display:flex; gap:8px; justify-content:center; }
.slotOben { margin-bottom:10px; }
.slotUnten { margin-top:10px; }
.charMitte { display:grid; grid-template-columns:auto auto auto; gap:10px; align-items:center; }
/* Die Tafeln rechts: jede ein eigenes Feld mit Überschrift, wie ein zweites
   Blatt neben der Puppe. */
/* DAS BLATT MUSS AUF DEN SCHIRM PASSEN (9. September).
   Mit sechs Rüstungsplätzen statt drei wuchs das Fenster auf 828 Punkte --
   auf einem Bildschirm von 900 stand es bis an beide Ränder, ließ sich nicht
   mehr vergrößern (pw_test_heilung_essen) und wäre auf einem Laptop mit 768
   Punkten abgeschnitten gewesen. Also überall ein wenig enger: Plätze 42
   statt 46, Bildnis 54 statt 66, Zeilen 3 statt 5 Punkte Luft, Tafeln 8 statt
   12. Zusammen gut hundert Punkte -- und nichts davon sieht man. */
.charTafel {
  background:rgba(20,15,10,.55); border:1px solid var(--linie);
  padding:8px 12px 9px; margin-bottom:8px;
}
.charTafelKopf {
  font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--text-fern); font-weight:700; margin-bottom:8px;
  border-bottom:1px solid var(--linie-leise); padding-bottom:6px;
}
.charZwei {
  display:grid; grid-template-columns:minmax(0,1fr); gap:10px;
  padding:10px; align-items:start; overflow:hidden;
}
/* Die Puppe steht in einem eigenen Feld -- wie in der Vorlage, wo sie in
   einem abgesetzten Rahmen sitzt und nicht auf dem Fensterhintergrund. */
.charLinks {
  background:rgba(20,15,10,.55); border:1px solid var(--linie);
  padding:16px 10px; display:flex; justify-content:center;
}
.charRechts { min-width:0; }
.charRechts .sectionLabel { padding:0; margin-top:12px; }
.charBuehne { display:flex; flex-direction:column; align-items:center; }
.slotSpalte { display:flex; flex-direction:column; gap:8px; }
/* Der Rahmen um die Figur: dieselbe Steinkachel wie die Fenster, plus ein
   warmer Lichtkegel von oben -- die Figur soll BELEUCHTET aussehen, nicht
   ausgeschnitten. */
.charFigur {
  background:
    radial-gradient(ellipse at 50% 34%, rgba(214,178,96,.18), rgba(0,0,0,.6) 72%),
    linear-gradient(180deg, #2a2118, #15100c);
  border:1px solid #6b563c;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6), inset 0 0 26px rgba(0,0,0,.72);
  padding:6px;
}
.charFigur canvas { display:block; image-rendering:pixelated; }
/* Im Charakterfenster duerfen die Plaetze groesser sein als im Rucksack:
   Dort zaehlt die Menge, hier zaehlt das einzelne Stueck.
   SECHS STATT VIER (9. September): Seit die Ruestung sechs Plaetze hat, ist
   die linke Spalte die hoechste Sache im Fenster. Bei 52 Punkten je Platz
   waere sie 352 hoch geworden -- hoeher als die Figur daneben (312) und
   damit der Grund, warum das Blatt auf kleinen Bildschirmen scrollen muesste.
   46 Punkte und 6 Zwischenraum ergeben 306: Die Spalte bleibt neben der
   Figur, nicht ueber ihr. */
#characterPanel .slot { width:42px; height:42px; }
#characterPanel .slotSpalte { gap:5px; }
#characterPanel .equipIcon { width:30px; height:30px; }
/* Die Werteliste steht jetzt in der rechten Spalte und braucht dort keinen
   eigenen Rand mehr -- den hat die Spalte. */
/* Die Werte in der rechten Spalte: groesser und luftiger als im schmalen
   Fenster. Sie sind der Grund, warum man das Blatt oeffnet -- sie duerfen
   nicht wie eine Fussnote aussehen. */
/* EINE Spalte, Bezeichnung links, Wert rechts -- wie in der Vorlage. Zwei
   Spalten brauchten die doppelte Breite und lasen sich schlechter: Man sucht
   einen Wert, man vergleicht sie nicht. */
/* Unter der Puppe: zwei Spalten, damit das Fenster nicht endlos lang wird.
   Bezeichnung links, Wert rechts -- eine Zeile je Wert, wie in der Vorlage. */
.charRechts .statList {
  padding:0; display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
  gap:0 18px; font-size:12.5px;
}
.charRechts .statList > div {
  display:flex; align-items:baseline; gap:10px;
  padding:3px 2px; border-bottom:1px solid rgba(255,255,255,.045);
}
.charRechts .statList span.v { margin-left:auto; font-size:13.5px; }
/* ---- Der Pfeil am Wert ----
   Klein, rechts neben der Zahl, und nur dann kräftig, wenn wirklich ein Punkt
   frei ist. Ein Knopf, der immer leuchtet und beim Drücken "kein Punkt frei"
   sagt, ist eine Falle. */
.statList .wertPlus {
  flex:none; width:19px; height:19px; padding:0; line-height:1;
  font-family:inherit; font-size:10px; cursor:pointer;
  background:var(--feld-hell); color:var(--sand);
  border:1px solid var(--linie);
  transition:border-color .12s ease, color .12s ease, background .12s ease;
}
.statList .wertPlus:hover:not(:disabled) { border-color:var(--gold); color:#ffe9a8; background:#3b2f1e; }
.statList .wertPlus.leer { opacity:.22; cursor:default; }
.statList .wertGesetzt {
  flex:none; font-size:10px; color:var(--gruen); min-width:12px; text-align:right;
}
/* ---- Der Preis am Pfeil ----
   Nur dort, wo ein Kauf mehr als einen Punkt kostet (data/werte.js: Angriff
   kostet drei). Er steht DIREKT am Pfeil und nicht im Tooltip, weil die Wahl
   zwischen den Werten nur dann eine Wahl ist, wenn man alle Preise auf einmal
   sieht. Gold, weil es eine Kostenangabe ist -- die grüne Zahl daneben sagt,
   was schon gekauft wurde, und die beiden dürfen sich nicht ähnlich sehen. */
.statList .wertPreis {
  flex:none; font-size:9.5px; color:var(--gold); opacity:.85;
  min-width:10px; text-align:left; letter-spacing:-.2px;
}
.statList .wertPreis::before { content:'×'; opacity:.55; }
/* Ohne Pfeil bleibt die Spalte trotzdem ausgerichtet. */
.statList .wertZeile { min-height:29px; }
/* Freie Punkte: eine Zeile mit einem Weg dorthin, wo man sie ausgibt. */
.charPunkteZeile {
  display:flex; align-items:center; gap:12px; margin-top:16px;
  padding:10px 12px; background:var(--feld); border:1px solid var(--linie);
  font-size:13px; color:var(--sand);
}
.charPunkteZeile.hidden { display:none; }
.charPunkteZeile button { margin-left:auto; }
/* Ein belegter Platz zeigt seinen Seltenheitsrahmen -- dieselbe Sprache wie
   im Rucksack. */
.slot.gefasst { box-shadow:inset 0 0 0 1px rgba(185,154,210,.9); }
.slot .fassMark {
  position:absolute; bottom:1px; right:2px; font-size:9px;
  color:var(--violett); letter-spacing:-1px; text-shadow:0 1px 2px #000;
}

/* ---------- Das Item-Fenster ----------
   Ein Fenster pro Gegenstand, gleich aufgebaut für alles: Kopf mit Symbol und
   Art, Werte, Fließtext, Einfassung, Handlungen. Wer einmal gelernt hat, wo
   etwas steht, findet es bei jedem Gegenstand an derselben Stelle. */
#itemPanel { width:320px; }
#itemPanelBody { padding:12px 14px 14px; }
.itemKopf { display:flex; gap:11px; align-items:center; margin-bottom:11px; }
.itemIcon {
  width:52px; height:52px; flex-shrink:0; display:flex; align-items:center; justify-content:center;
  font-size:26px; background:var(--feld); border:1px solid var(--linie);
}
.itemName { font-size:15px; font-weight:700; line-height:1.25; }
.itemAnzahl { color:var(--text-leise); font-weight:400; }
.itemArt { font-size:11px; color:var(--text-fern); letter-spacing:.05em; margin-top:3px; }
.itemWerte { display:flex; flex-direction:column; gap:3px; margin-bottom:10px; }
.itemWert { display:flex; justify-content:space-between; gap:10px; font-size:12.5px; color:var(--text-leise); }
.itemWert .v { color:var(--gruen); font-weight:600; }
.itemWert .ausFassung { color:var(--violett); font-weight:400; font-size:11px; }
.itemFlavor { font-size:12px; font-style:italic; color:var(--text-fern); line-height:1.5; margin-bottom:11px; }

.itemFassung { border:1px solid var(--linie); background:rgba(43,34,25,.55); padding:9px 10px; margin-bottom:11px; }
/* DIE HÄRTUNG steht neben der Einfassung und muss auf einen Blick von ihr zu
   unterscheiden sein: Es sind zwei verschiedene Handwerke am selben Stück,
   und wer sie verwechselt, gibt einen Sud auf etwas, das er fassen wollte.
   Die Fassung ist violett (Splitter von Dilmun), die Härtung grün (Kessel
   und Kraut) -- dieselbe Farbe, die auch die Alchemie im Handwerksfenster
   trägt. */
.itemHaertung { border-color:rgba(126,224,129,.45); background:rgba(28,44,30,.55); }
.itemHaertung .ifPunkte { color:var(--gruen, #7ee081); }
.itemHaertung .ifKnoepfe button:hover:not(:disabled) { border-color:var(--gruen, #7ee081); }
.ifKopf { font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--text-fern);
          display:flex; justify-content:space-between; align-items:center; }
.ifPunkte { color:var(--violett); font-size:13px; letter-spacing:1px; }
.ifText { font-size:12px; color:var(--text-leise); margin:6px 0 8px; line-height:1.45; }
.ifKnoepfe { display:flex; gap:6px; flex-wrap:wrap; }
.ifKnoepfe button { flex:1; font-size:12px; padding:6px 9px; }
.ifKnoepfe button:hover:not(:disabled) { border-color:var(--violett); }
.ifKnoepfe button:disabled { opacity:.42; cursor:default; }
.ifKnoepfe button.ghost { flex:0 0 auto; }
.ifHinweis { font-size:10.5px; color:var(--text-fern); margin-top:7px; line-height:1.45; }

.itemAktionen { display:flex; gap:7px; }
.itemAktionen button {
  flex:1; font-family:inherit; font-size:12.5px; padding:8px 10px;
  background:var(--sand); color:#2a2016; border:1px solid var(--sand); font-weight:600; cursor:pointer;
}
.itemAktionen button:hover:not(:disabled) { filter:brightness(1.08); }
.itemAktionen button:disabled { opacity:.45; cursor:default; }

.itemGuete { font-size:11.5px; font-weight:600; margin-top:2px; }
.itemZeile { font-size:12px; color:var(--text-leise); margin-bottom:7px; }
.itemZeile b { color:var(--text); }
.itemZeile.leise { color:var(--text-fern); margin-top:9px; }

/* ---------- Münzen ----------
   Gold, Silber, Kupfer stehen nebeneinander und sind an der Farbe zu
   unterscheiden -- das ist der halbe Nutzen des Systems. Der Buchstabe ist
   klein und tiefgestellt, damit die Zahl die Hauptsache bleibt. */
.muenze { font-weight:700; font-variant-numeric:tabular-nums; white-space:nowrap; }
.muenze i { font-style:normal; font-size:.78em; opacity:.85; margin-left:1px; }

/* ---------- Paperdoll-Creator (New_World-Patch) ---------- */
/* Der Creator ersetzt das 15er-Roster durch Wahlreihen: Volk, Gestalt,
   Frisur, Haarfarbe, Bart. Jede Reihe ist eine Zeile aus kleinen Knöpfen;
   die Vorschau links zeigt sofort die zusammengesetzte Figur. */
/* ----------------------------------------------------------------
   DER CHARAKTEREDITOR
   ----------------------------------------------------------------
   Vorher: vier schmale Zeilen mit rechtsbuendiger Minibeschriftung und
   30px-Knoepfen. Neun Voelker, sieben Frisuren und acht Farben sahen
   darin alle gleich aus -- man WAEHLTE nicht, man klickte herum.

   Jetzt: Abschnitte mit einer knappen Ueberschrift, sonst nichts. Kein
   Erklaertext -- was eine Wahl bewirkt, sieht man an der Vorschau daneben,
   und wer es dort nicht sieht, dem hilft ein Satz auch nicht.

   Die Raster sind unterschiedlich gross, weil der Inhalt es ist: Voelker
   gross und mit Namen, Farben als Punkte, Frisuren und Baerte klein. Die
   Reihenfolge folgt der Abhaengigkeit -- erst die Haarfarbe, dann Frisur
   und Bart, denn die Farbe faerbt deren Bildchen.
   ---------------------------------------------------------------- */
.charGrid.pdCreator {
  display:flex; flex-direction:column; gap:13px;
  grid-template-columns:none; max-height:none; padding-right:6px;
}
/* KEIN ABSCHNITT DARF GEQUETSCHT WERDEN.
   Ohne flex-shrink:0 verteilt der Flexkasten den Platzmangel auf alle
   Abschnitte: Der letzte (Bart) behielt seine Ueberschrift, seine Knoepfe
   lagen aber UNTERHALB des sichtbaren Bereichs -- man konnte keinen Bart
   waehlen und sah auch nicht, dass es einen gaebe. Jetzt behalten die
   Abschnitte ihre Hoehe, und wenn es eng wird, wird eben gescrollt (und man
   sieht den Balken). */
.pdBlock { display:flex; flex-direction:column; gap:8px; flex-shrink:0; }
.pdBlockKopf { border-bottom:1px solid var(--linie); padding-bottom:5px; }
.pdBlockTitel { font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--sand); }

.pdOpts { display:flex; flex-wrap:wrap; gap:7px; }
/* Voelker: Raster mit fester Spaltenzahl, damit die Namen untereinander
   stehen statt zu treppen. */
/* Sechs Voelker in EINER Reihe. Bei drei Spalten brauchte der Block zwei
   Zeilen und 154 Punkte Hoehe -- genau die, die dem Bart am Ende fehlten. */
.pdOpts.pdRaster { display:grid; grid-template-columns:repeat(6, minmax(0,1fr)); gap:6px; }
.pdOpts.pdRaster.pdKlein { grid-template-columns:repeat(8, minmax(0,1fr)); gap:6px; }
.pdOpts.pdFarbreihe { gap:9px; }

.pdOpt {
  min-width:34px; min-height:38px; padding:5px 4px 4px;
  background:var(--feld); border:1px solid var(--rand);
  border-radius:7px; cursor:pointer; color:var(--text);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:3px; font-size:11px; line-height:1.15;
  transition:border-color .12s, background .12s, transform .08s;
}
.pdOpt:hover { background:var(--feld-hell); border-color:var(--sand-leise); transform:translateY(-1px); }
.pdOpt.selected {
  border-color:var(--sand); background:var(--feld-hell);
  box-shadow:0 0 0 1px var(--sand) inset, 0 0 10px -4px var(--sand);
}
.pdOpt.mitText { min-height:52px; padding:4px 2px 3px; }
/* Der Name darf umbrechen statt abgeschnitten zu werden -- "Drakonier" mit
   drei Punkten hilft niemandem bei der Wahl. */
.pdOptText { font-size:10px; letter-spacing:0; color:var(--text-fern);
  max-width:100%; text-align:center; line-height:1.15;
  /* Ein Name, der nicht passt, wird umgebrochen -- nicht ueber die Kante
     geschoben. "Die Verlorenen" stand vorher halb neben dem Knopf. */
  overflow-wrap:anywhere; word-break:break-word; }
.pdOpt.selected .pdOptText { color:var(--sand); }
/* Die Bildchen werden in genau der Groesse GEZEICHNET, in der sie stehen
   (csThumb im Client) -- ein herunterskaliertes Pixelbild ist Matsch. */
.pdThumb { width:34px; height:34px; image-rendering:pixelated; image-rendering:crisp-edges; }
.pdOpt.mitText .pdThumb { width:40px; height:40px; }
/* Farbpunkte: rund, damit man sie nicht fuer Bildchen haelt. */
.pdFarbe { display:inline-block; width:20px; height:20px; border-radius:50%;
  border:1px solid rgba(0,0,0,.55); box-shadow:0 1px 2px rgba(0,0,0,.4) inset; }

/* Denzi-Item-Icons: Ausschnitte aus dem Atlas assets/items/icons.png. */
.dIcon { display:inline-block; vertical-align:middle; background-image:url('/assets/items/icons.png'); background-repeat:no-repeat; image-rendering:pixelated; image-rendering:crisp-edges; }
.emojiIcon { display:inline-flex; align-items:center; justify-content:center; }

/* Der Panzerhandschuh als Mauszeiger -- das ganze Spiel zeigt mit ihm. */
/* ---------------------------------------------------------------------------
   EIN ZEIGER, ÜBERALL
   ---------------------------------------------------------------------------
   Der eigene Zeiger galt nur für den Spielbildschirm und ein paar Knöpfe.
   Überall sonst -- Leiste, Fenster, Listen, Chat -- sprang der Browser auf
   seine eigenen zurück: mal der schräge Standardpfeil, mal die weiße Hand von
   `cursor:pointer`. Beim Überfahren der Oberfläche wechselte das Bild also
   ständig, und zwar mitten in der Bewegung.

   Deshalb EINE Regel für alles. Sie braucht !important, weil an achtundzwanzig
   Stellen `cursor:pointer` steht und jede davon spezifischer ist als ein
   Sternchen -- diese Zeilen einzeln zu jagen hieße, die Falle beim nächsten
   neuen Knopf wieder aufzustellen.

   Die Affordanz geht dabei nicht verloren: Knöpfe, Plätze und Listenzeilen
   hellen beim Überfahren ohnehin auf. Das war schon vorher das eigentliche
   Signal -- die Hand war nur das Echo des Browsers.

   Ausnahme: Textfelder. Dort ist der Balken keine Zierde, sondern sagt, dass
   man tippen kann. */
*, *::before, *::after { cursor:url('/assets/ui/cursor.png') 6 2, default !important; }
input[type="text"], input[type="password"], input[type="number"], textarea {
  cursor:text !important;
}
.dSpell { display:inline-block; vertical-align:middle; background-image:url('/assets/items/spells.png'); background-repeat:no-repeat; image-rendering:pixelated; image-rendering:crisp-edges; }
/* Ein Atlas aus gemalten Icons (pixelart:false im JSON) wird glatt skaliert. */
.dSpell.glatt { image-rendering:auto; border-radius:3px; box-shadow:0 0 0 1px rgba(0,0,0,.55) inset; }

/* ================================================================
   DENZI-UI (New_World-Patch): Steinpanels, Goldrahmen, Steinknöpfe.
   Die Texturen kommen aus den GUI-Blättern des Addons
   (assets/ui/stein_dunkel.png, rahmen_gold.png, knopf_stein.png).
   ================================================================ */
.panel {
  background-color:#17141a;
  background-image:url('/assets/ui/stein_dunkel.png');
  background-repeat:repeat;
  border:8px solid transparent;
  border-image:url('/assets/ui/rahmen_gold.png') 4 / 8px repeat;
  border-radius:0;
  image-rendering:pixelated;
}
.panelHead {
  background:rgba(10,8,6,.72);
  border-bottom:1px solid #a8843c;
  color:#e8cf9a;
  letter-spacing:.4px;
}
.slot, .equipIconSlot {
  background-color:#191519;
  background-image:url('/assets/ui/stein_dunkel.png');
  background-repeat:repeat;
  border:1px solid #6d6d74;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6), inset 0 2px 4px rgba(0,0,0,.5);
}
.slot:hover { border-color:#c9a45c; }
.slot.dragOver { border-color:#ffd76a; }
/* ======================================================================
   EIN KNOPF FUER DAS GANZE SPIEL (15. September) -- DIE GRUNDFORM
   ======================================================================
   Oliver: *„Super du hast nur leider wieder diese alten Buttons verwendet
   nimm für alle mal die die du im Login Schirm verwendet hast."*

   „Für alle" heißt: am ELEMENT, nicht an einer Klasse. Nachgemessen gab es
   im laufenden Spiel drei Knopfsprachen nebeneinander -- den hellen Stein
   (`.primaryBtn`), durchsichtig mit goldener Kante (die Knöpfe im Gespräch)
   und blanke Browservorgabe (alles, was jemand ohne Klasse angelegt hat).
   Eine vierte kam mit jedem neuen Schirm dazu, weil sich jeder neu
   entscheiden musste.

   Also steht die Form jetzt einmal am `button` selbst. Wer etwas anderes
   sein will, sagt es weiterhin über seine Klasse und gewinnt (eine Klasse
   sticht ein Element): die Fensterzeichen der Leiste, die Bildchen im
   Editor, die Ovale des Volksrings, das ✕ -- alle bringen ihren eigenen
   Grund mit und bleiben, wie sie sind.

   `font: inherit` steht dabei, weil es sonst ALLES erklärt: Ein Knopf ohne
   diese Zeile erbt die Schrift des Betriebssystems, und genau daran erkennt
   man „alte Buttons" auf hundert Schritt. */
/* ZWEITE RUNDE, 15. September abends: GOLDEN, NICHT SCHWARZ.
   -----------------------------------------------------------------------
   Oliver: *„im spiel ist der schwarze hintergund für die buttons die
   schlechtere wahl als der goldene, noch dazu ist die schrift sehr
   veschwommen."*

   Das ist kein Widerspruch zu vorhin, sondern die Antwort auf eine Frage,
   die vorhin nicht gestellt wurde. Die dunkle Form kam aus dem ANMELDESCHIRM
   -- dort steht sie auf einem ruhigen, dunklen Bild, und heller Text auf
   Dunkel liest sich gut. IM SPIEL steht derselbe Knopf auf sandfarbenen
   Fenstern vor heller Wüste: da ist ein dunkler Kasten ein Loch.

   UND DIE UNSCHÄRFE HAT EINE URSACHE, kein Gefühl. Hier stand
   `text-shadow:0 1px 3px rgba(0,0,0,.95)`: ein drei Pixel weicher, fast
   schwarzer Schatten unter hellem Text. Bei 12 px Schriftgröße ist das
   breiter als die Strichstärke -- der Schatten läuft unter dem Buchstaben
   hervor und frisst seine Unterkante. Auf dunklem Grund verschmilzt beides.
   Genau das sieht man auf Olivers Bild: „Schmiedekunst lernen" weich,
   „Annehmen" (dunkler Text auf hell, Schatten ohne Weichzeichner) scharf.

   Also: warmer Grund, dunkle Schrift, und ein Schatten mit Radius NULL. Ein
   scharfer Lichtsaum nach oben statt eines Weichzeichners nach unten. */
button {
  font:inherit; cursor:pointer;
  background-color:#d9c08a;
  background-image:linear-gradient(180deg, #e8d3a2 0%, #cdb17c 62%, #bf9f66 100%);
  border:1px solid #7d6132;
  border-radius:3px;
  color:#241a0c;
  font-weight:600;
  text-shadow:0 1px 0 rgba(255, 248, 222, .55);
  transition:color .18s ease, border-color .18s ease, box-shadow .18s ease, background-color .18s ease, filter .18s ease;
}
/* KEINE GROESSE IN DER GRUNDFORM. Ein `padding` hier haette jeden kleinen
   Schalter im Spiel aufgeblasen -- gemessen am Helmschalter im
   Charakterfenster, der damit über die Kopfzeile hinauswuchs. Die Form ist
   gemeinsam, die Groesse gehoert der Stelle: ein Knopf in einer Fensterzeile
   ist nicht so gross wie einer unter einem Charakterblatt. */
button:hover { color:#140e05; border-color:#a5813f; filter:brightness(1.09); }
/* GESPERRT HEISST BLASS, NICHT UNSICHTBAR. Ein Knopf, den man gerade nicht
   drücken kann, muss trotzdem lesbar bleiben -- sonst rät man, was dort
   stand. Deshalb gedämpfte Farbe statt opacity auf dem ganzen Knopf. */
button:disabled {
  background-image:linear-gradient(180deg, #bdae90 0%, #a89a7d 62%, #9a8c70 100%);
  border-color:#6d6047; color:#4a4133; text-shadow:none; cursor:default;
}
button:disabled:hover { filter:none; border-color:#6d6047; color:#4a4133; }

/* DREI STIMMLAGEN DERSELBEN FORM (16. September).
   -----------------------------------------------------------------------
   Oliver, mit Bild von „Anheften" und „Abbrechen" im Aufgabenbuch:
   *„SCHRIFT SIEHT MAN WIEDER SO SCHLECHT"*.

   Gemessen am Bild: Knopfgrund (224,201,151), Schrift (217,138,114) -- das
   ist `--rot` aus einer Regel, die für den DUNKLEN Knopf geschrieben wurde
   (`.questCard button.qAbandon { color:var(--rot) }`) und beim Wechsel auf
   Gold stehen blieb. Daneben „Anheften" in `--text-leise`: Sandgrau auf
   Gold. Sechs solcher Regeln standen im Blatt, jede in ihrem Fenster, jede
   mit eigener Farbe und keine mit eigenem Grund.

   Ein Knopf, der etwas ANDERES sagen will als „drück mich", sagt es jetzt
   über eine dieser drei Klassen -- und die bringen Grund UND Schrift mit,
   nie nur eines von beiden. pw_test_knopfschrift misst jeden sichtbaren
   Knopf gegen seinen Grund (Kontrast >= 4.5).

   gefahrBtn    Abbrechen, Verlassen, Löschen: dunkles Rostrot, helle Schrift
   leiseBtn     die zweite Wahl neben einem Hauptknopf: matteres Gold
   gedruecktBtn ein Schalter, der AN ist (die Nadel): Gold mit Lichtsaum */
.gefahrBtn, .questCard button.qAbandon, #partyLeaveBtn {
  background-color:#8a4638;
  background-image:linear-gradient(180deg, #a8574a 0%, #8a4638 62%, #73382c 100%);
  border-color:#4e2419;
  color:#f6e4d2;
  text-shadow:0 1px 0 rgba(0, 0, 0, .45);
}
.gefahrBtn:hover, .questCard button.qAbandon:hover, #partyLeaveBtn:hover {
  background:#8a4638 linear-gradient(180deg, #b5604f 0%, #944b3c 62%, #7a3c2f 100%);
  color:#fff3e6; border-color:#5e2b1e; filter:brightness(1.06);
}
.leiseBtn, .inviteBtns button:last-child, .fassungZeile button.loesen,
.ifKnoepfe button.ghost, .questCard button.qPin:not(.an) {
  background-image:linear-gradient(180deg, #d6c8a6 0%, #c2b28c 58%, #b3a279 100%);
  border-color:#7a6c4c;
  color:#463a22; font-weight:400;
  text-shadow:none;
}
.leiseBtn:hover, .inviteBtns button:last-child:hover, .fassungZeile button.loesen:hover,
.ifKnoepfe button.ghost:hover, .questCard button.qPin:not(.an):hover {
  background:#c2b28c linear-gradient(180deg, #ddd0b0 0%, #c9b994 58%, #b9a880 100%);
  color:#2e2513; border-color:#9c8452; filter:brightness(1.04);
}
.gedruecktBtn, .questCard button.qPin.an {
  background-image:linear-gradient(180deg, #f2dfae 0%, #d9bd84 58%, #c5a568 100%);
  border-color:var(--gold); color:#201607; font-weight:700;
  box-shadow:0 0 0 1px rgba(227, 189, 109, .55), 0 0 10px rgba(227, 189, 109, .45);
}
.gedruecktBtn:hover, .questCard button.qPin.an:hover {
  background:#d9bd84 linear-gradient(180deg, #f6e6bb 0%, #dfc48c 58%, #cbab6e 100%);
  color:#140e03; border-color:var(--gold);
}

/* ======================================================================
   DER HAUPTKNOPF -- dieselbe Sprache, eine Spur lauter
   ======================================================================
   Oliver: *„Super du hast nur leider wieder diese alten Buttons verwendet
   nimm für alle mal die die du im Login Schirm verwendet hast."*

   Hier stand die HELLE Steintextur (`stein_hell.png`) -- ein grauer Klotz mit
   dunkler Schrift. Am 14. September hat Oliver sie schon einmal beanstandet
   (*„nur das eintreten und Konto anlegen sehen so Hässlich aus"*), und die
   Antwort damals war eine AUSNAHME nur für den Anmeldeschirm: dunkle Tiefe,
   goldene Kante, heller Text.

   Das war der halbe Schritt. Ein Spiel mit zwei Knopfsprachen hat keine --
   und jeder neue Schirm musste sich wieder entscheiden, welche er spricht
   (der Wegschirm hat sich prompt für die falsche entschieden). Also ist die
   Ausnahme jetzt die Regel, und `#loginAktionen` hat nur noch seine eigene
   GROESSE.

   Warum nicht `.pdOpt` und `.hudBtn`: Das sind keine Textknöpfe. `.pdOpt`
   sind die Bildchen im Charaktereditor (Frisur, Farbe, Gesicht) -- eine
   goldene Kante um vierzig kleine Köpfe wäre ein Gitter, kein Editor; sie
   haben ihren eigenen Rahmen weiter unten. `.hudBtn` sind die Zeichen der
   Fensterleiste und tragen ihren eigenen, dunkleren Stein. */
.primaryBtn, .shopBuy, .lootTake, #chatSendBtn, .questPingBtn {
  background-color:#dcbf88;
  background-image:linear-gradient(180deg, #f2dfae 0%, #d9bd84 58%, #c5a568 100%);
  border:1px solid #8a6a34;
  border-radius:3px;
  color:#201607;
  font-weight:700; letter-spacing:.06em;
  text-shadow:0 1px 0 rgba(255, 250, 230, .6);
  box-shadow:inset 0 1px 0 rgba(255, 250, 225, .55),
             inset 0 -10px 18px rgba(120, 88, 38, .22),
             0 2px 10px rgba(0, 0, 0, .45);
  transition:color .18s ease, border-color .18s ease, box-shadow .18s ease, filter .18s ease;
}
.primaryBtn:hover, .shopBuy:hover, .lootTake:hover, #chatSendBtn:hover, .questPingBtn:hover {
  filter:brightness(1.08);
  color:#140e03;
  border-color:#b08a42;
  box-shadow:inset 0 1px 0 rgba(255, 253, 240, .65),
             inset 0 -10px 18px rgba(120, 88, 38, .18),
             0 0 16px rgba(227, 189, 109, .42);
}
.primaryBtn:active, .shopBuy:active, .lootTake:active { filter:brightness(.94); transform:translateY(1px); }
.primaryBtn:disabled, .shopBuy:disabled, .lootTake:disabled {
  background-image:linear-gradient(180deg, #c8b896 0%, #b0a181 58%, #9e8f72 100%);
  border-color:#6d6047; color:#494032; text-shadow:none;
  box-shadow:none; cursor:default; transform:none;
}
.primaryBtn:disabled:hover, .shopBuy:disabled:hover, .lootTake:disabled:hover {
  filter:none; color:#494032; border-color:#6d6047; box-shadow:none;
}

/* DIE BILDCHEN IM EDITOR behalten den Stein -- sie tragen Köpfe, keine
   Wörter, und eine goldene Kante um jedes wäre ein Gitter. */
.pdOpt, button.hudBtn {
  background-color:#8b8b91;
  background-image:url('/assets/ui/stein_hell.png');
  background-size:64px 64px;
  image-rendering:pixelated;
  border:1px solid #2c2c31;
  color:#17130c;
  text-shadow:0 1px 0 rgba(255,255,255,.35);
  font-weight:700;
}
.pdOpt:hover, button.hudBtn:hover { filter:brightness(1.14); }
button.hudBtn:active { filter:brightness(.85); }
.pdOpt.selected { outline:2px solid #ffd76a; filter:brightness(1.12); }

/* DER ZWEITRANGIGE KNOPF -- gleiche Form, halbe Stimme.
   `.ghostBtn` steht weiter oben im Stilblatt und verlor deshalb jeden Streit
   gegen `.primaryBtn`: Jeder Knopf mit beiden Klassen sah aus wie der
   Hauptknopf. Auf der Charakterübersicht standen dadurch zwei gleich laute
   Angebote nebeneinander. Hier gewinnt es zurück. */
/* Mit dem Wechsel auf Gold (O24) wurde auch hier umgestellt: „leiser" heißt
   jetzt blasser und matter, nicht dunkler. Wichtig bleibt, DASS ein
   Unterschied da ist -- pw_test_anmeldung misst ihn („Der zweite ist leiser
   als der erste"), und zwei gleich laute Angebote nebeneinander sind keine
   Wahl, sondern eine Verlegenheit. */
.primaryBtn.ghostBtn {
  background-image:linear-gradient(180deg, #d6c8a6 0%, #c2b28c 58%, #b3a279 100%);
  border-color:#7a6c4c;
  color:#463a22; font-weight:400; letter-spacing:.06em;
  text-shadow:none;
  box-shadow:inset 0 1px 0 rgba(255, 250, 230, .3);
}
.primaryBtn.ghostBtn:hover {
  filter:brightness(1.06);
  border-color:#9c8452; color:#2e2513;
  box-shadow:inset 0 1px 0 rgba(255, 250, 230, .4);
}
.hudBtn {
  background-color:#6f6f76;
  border:1px solid #2c2c31;
  box-shadow:0 2px 0 rgba(0,0,0,.55);
}
#topBar {
  background:rgba(12,10,8,.9) url('/assets/ui/stein_dunkel.png');
  background-blend-mode:multiply;
  border-bottom:2px solid #a8843c;
}
#actionBar .slot, .abilitySlot {
  background-image:url('/assets/ui/stein_dunkel.png');
  border:1px solid #6d6d74;
}
.creatorCard, .rosterCard, #loginKarte {
  background-color:#17141a;
  background-image:url('/assets/ui/stein_dunkel.png');
  border:8px solid transparent;
  border-image:url('/assets/ui/rahmen_gold.png') 4 / 8px repeat;
  image-rendering:pixelated;
}
.rosterCard:hover { filter:brightness(1.12); }
#itemTooltip, .npcTooltip {
  background-color:#141118f2;
  background-image:url('/assets/ui/stein_dunkel.png');
  border:4px solid transparent;
  border-image:url('/assets/ui/rahmen_gold.png') 4 / 4px repeat;
}
/* Schrift auf Stein: die Sandtöne bleiben, nur Überschriften goldener */
.panel h3, .zName, .shopName { color:#ecd7a5; }


/* ---- Das Erwachen des Observatoriums: Vollbild-Sternprojektion ---- */
#obsEreignis {
  position:fixed; inset:0; z-index:200; cursor:pointer;
  background:radial-gradient(ellipse at 50% 40%, rgba(14,20,40,.96), rgba(4,6,14,.98));
  animation:obsAuf .9s ease;
}
@keyframes obsAuf { from { opacity:0; } to { opacity:1; } }
#obsEreignis svg { position:absolute; inset:0; width:100%; height:70%; }
#obsEreignis svg line {
  stroke:rgba(180,210,255,.7); stroke-width:.35; stroke-dasharray:60; stroke-dashoffset:60;
  animation:obsLinie 1.4s ease forwards;
}
@keyframes obsLinie { to { stroke-dashoffset:0; } }
.obsStern {
  position:absolute; width:5px; height:5px; border-radius:50%;
  background:#eaf2ff; box-shadow:0 0 12px 3px rgba(170,205,255,.9);
  opacity:0; animation:obsStern 1s ease forwards;
}
@keyframes obsStern { from { opacity:0; transform:scale(.2); } to { opacity:1; transform:scale(1); } }
.obsText {
  position:absolute; left:0; right:0; bottom:12%; text-align:center;
  color:#e8edf8; text-shadow:0 2px 10px rgba(0,0,0,.8);
}
.obsZeile { opacity:0; animation:obsZeile 1.2s ease forwards; }
.obsZeile.z1 { font-size:15px; letter-spacing:.14em; text-transform:uppercase; color:#9fb4d8; animation-delay:.8s; }
.obsZeile.z2 { font-size:21px; margin-top:10px; animation-delay:2.2s; }
.obsZeile.z3 { font-size:30px; font-weight:700; margin-top:12px; color:#ffd76a; letter-spacing:.08em; animation-delay:3.6s; }
.obsZeile.z4 { font-size:11px; margin-top:22px; color:#77809a; animation-delay:5s; }
@keyframes obsZeile { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:none; } }

/* Der Warnsatz unter dem Lernknopf beim Lehrer. Er ist keine Randnotiz,
   also sieht er auch nicht so aus. */
.lehrWarnung {
  color: var(--sand);
  border-left: 2px solid var(--sand-leise);
  padding-left: 8px;
  font-size: 12px;
  line-height: 1.45;
}

/* Hier standen die Regeln der Attributkarten. Die Karten sind raus
   (data/attribute.js) -- und mit ihnen ihr Aussehen. */

/* Ein Tooltip gehört ÜBER alles. Er lag hinter dem Rucksackfenster, und man
   las die Werte eines Gegenstands durch das Fenster hindurch, das man gerade
   offen hatte. */
#itemTooltip { z-index:4000; }

/* ---------- Die Wegwahl über den ganzen Bildschirm ----------
   Die einzige unumkehrbare Entscheidung des Spiels. Sie hat vorher in einem
   Seitenfenster gestanden, zwischen Fähigkeitenlisten; jetzt hält sie den
   Bildschirm an. */
#wegwahlOverlay {
  position:fixed; inset:0; z-index:3000;
  display:flex; align-items:center; justify-content:center;
  background:radial-gradient(ellipse at 50% 36%, rgba(40,30,16,.86), rgba(6,5,4,.96) 70%);
  backdrop-filter:blur(3px);
  animation:wwAuf .5s ease both;
}
#wegwahlOverlay.hidden { display:none; }
@keyframes wwAuf { from { opacity:0 } to { opacity:1 } }
.wwInner { width:min(1040px, 92vw); text-align:center; padding:20px; }
.wwOben {
  font-size:12px; letter-spacing:.34em; text-transform:uppercase;
  color:var(--sand-leise); margin-bottom:6px;
}
.wwTitel {
  margin:0 0 10px; font-size:clamp(28px, 4.2vw, 46px); letter-spacing:.04em;
  color:#f0d79a; text-shadow:0 3px 0 rgba(0,0,0,.6), 0 0 34px rgba(214,178,96,.35);
}
.wwText { margin:0 auto 26px; max-width:640px; color:var(--text-leise); line-height:1.65; font-size:14px; }
.wwText b { color:var(--sand); }
.wwKarten { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:16px; }
.wwKarte {
  display:flex; flex-direction:column; align-items:center; gap:8px;
  padding:22px 16px 20px; cursor:pointer; font-family:inherit; text-align:center;
  color:var(--text);
  background:linear-gradient(180deg, rgba(48,38,25,.96), rgba(24,18,12,.96));
  border:1px solid #6b563c;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6), 0 14px 40px rgba(0,0,0,.5);
  transition:transform .14s ease, border-color .14s ease, box-shadow .14s ease;
}
.wwKarte:hover {
  transform:translateY(-4px);
  border-color:var(--sand);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.6), 0 18px 46px rgba(0,0,0,.6), 0 0 26px -6px var(--sand);
}
.wwIcon { font-size:40px; line-height:1; }
.wwName { font-size:20px; font-weight:700; color:#f0d79a; letter-spacing:.03em; }
.wwKurz { font-size:13px; color:var(--text-leise); }
.wwBonus { font-size:12.5px; color:var(--gruen); font-weight:600; }
.wwDesc { font-size:12px; color:var(--text-fern); line-height:1.55; margin-top:4px; }
.wwFuss { margin:24px auto 0; max-width:660px; font-size:12.5px; color:var(--text-fern); line-height:1.6; }
.wwSpaeter {
  margin-top:18px; font-family:inherit; font-size:12.5px; padding:8px 18px;
  background:transparent; color:var(--text-fern); border:1px solid var(--linie); cursor:pointer;
}
.wwSpaeter:hover { color:var(--text); border-color:var(--sand-leise); }
@media (max-width: 780px) {
  .wwKarten { grid-template-columns:1fr; }
  .wwDesc { display:none; }
}

/* ---- Ausbildung: die ganze Leiter des Lehrers ----
   Drei Zustände je Zeile: gelernt (leise), lernbar (grün), später (Schloss). */
.rZeile .rPreis { flex:0 0 auto; font-size:11px; color:var(--text-leise); white-space:nowrap; }
.recipeCard.lehrerRezept.gelernt { opacity:.6; border-style:solid; }
.recipeCard.lehrerRezept.lernbar { border-color:rgba(126,224,129,.7); }
.recipeCard.lehrerRezept.lernbar .rName { color:#b8f0b0; }
.recipeCard.lehrerRezept.spaeter { color:var(--text-leise); }
#spellbookReiter { padding:8px 14px 0; }

/* ---- Die Knopfleiste lässt sich verschieben und skalieren ----
   Griff oben (Punktmuster) zum Ziehen, Griff unten links zum Skalieren.
   Die Knopfgröße steckt in --hudKnopf, damit Raster und Knöpfe gemeinsam
   wachsen; die Spaltenzahl rechnet der Client daraus (randmasseMelden). */
:root { --hudKnopf:36px; }
/* (#hud ist schon absolut positioniert -- die Griffe hängen daran.) */
/* Der Ziehgriff sitzt LINKS an der Leiste, nicht darüber: Über ihr liegt die
   Minikarte, und ein Griff, der unter einem anderen Fenster steckt, lässt
   sich nicht fassen. */
#hud .hudGriff {
  position:absolute; left:-12px; top:0; bottom:16px; width:12px; cursor:move;
  background:linear-gradient(90deg, rgba(201,162,39,.10), rgba(201,162,39,.32));
  border:1px solid var(--linie); border-right:none; z-index:1;
}
#hud .hudGriff::after {
  content:''; position:absolute; top:50%; left:4px; transform:translateY(-50%);
  width:3px; height:26px; border-left:1px dotted rgba(242,237,225,.65); border-right:1px dotted rgba(242,237,225,.35);
}
#hud .hudSkala {
  position:absolute; left:-12px; bottom:0; width:12px; height:14px; cursor:nesw-resize; z-index:2;
  background:linear-gradient(45deg, rgba(201,162,39,.55) 0 45%, transparent 45%);
  border:1px solid var(--linie);
}

/* ==========================================================================
   DAS MENGENFENSTER
   ==========================================================================
   Oliver, 5. September: "bei allen dingen bei denen man eine menge einstellen
   kann, ein fenster eine option für menge hinzufügen, beim einkaufen als auch
   beim verkaufen."

   Ein Fenster, vier Wege es zu bedienen: Regler ziehen, Zahl tippen, − und +,
   oder einer der Schnellknöpfe (1, 5, 10, Alles). Wer nur einen davon mag,
   braucht die anderen nie zu sehen. Unten steht IMMER, was das kostet oder
   bringt -- die Zahl, wegen der man die Menge überhaupt einstellt. */
.mengeSchicht {
  position:fixed; inset:0; z-index:400;
  display:flex; align-items:center; justify-content:center;
  background:rgba(10,7,4,.62);
}
.mengeSchicht.hidden { display:none; }
.mengeFenster {
  width:min(330px, calc(100vw - 32px));
  background:var(--flaeche-fest); border:1px solid var(--linie);
  box-shadow:0 18px 48px rgba(0,0,0,.6); padding:0 14px 14px;
}
.mengeFenster .panelHead { margin:0 -14px 12px; }
.mengeZeile { display:flex; align-items:center; gap:9px; margin-bottom:12px; }
.mengeIcon { font-size:22px; line-height:1; flex-shrink:0; }
.mengeIcon img { width:26px; height:26px; vertical-align:middle; }
.mengeName { color:var(--sand); font-weight:700; font-size:13px; }
.mengeSteller { display:flex; align-items:stretch; gap:6px; margin-bottom:10px; }
.mengeSteller button {
  width:40px; flex-shrink:0; background:transparent; border:1px solid var(--sand-leise);
  color:var(--sand); font-size:18px; font-weight:700; cursor:pointer; font-family:inherit;
}
.mengeSteller button:hover { background:var(--sand); color:#2a2016; }
.mengeSteller input {
  flex:1; min-width:0; background:var(--feld); border:1px solid var(--linie);
  color:var(--text); font-family:inherit; font-size:16px; font-weight:700;
  text-align:center; padding:8px 4px;
}
/* Die Pfeilchen des Zahlenfeldes sind winzig und liegen genau da, wo − und +
   schon stehen. Weg damit -- doppelte Bedienung, halbe Trefferfläche. */
.mengeSteller input::-webkit-outer-spin-button,
.mengeSteller input::-webkit-inner-spin-button { -webkit-appearance:none; margin:0; }
.mengeSteller input[type=number] { -moz-appearance:textfield; appearance:textfield; }
.mengeRegler { width:100%; margin:0 0 10px; accent-color:var(--gold); cursor:pointer; }
.mengeSchnell { display:flex; gap:6px; margin-bottom:12px; }
.mengeSchnell button {
  flex:1; background:transparent; border:1px solid var(--linie); color:var(--text-leise);
  font-family:inherit; font-size:11px; font-weight:700; padding:6px 2px; cursor:pointer;
}
.mengeSchnell button:hover { border-color:var(--sand-leise); color:var(--sand); }
.mengeSumme {
  text-align:center; font-size:13px; color:var(--text-leise);
  padding:9px 0; border-top:1px solid var(--linie-leise); margin-bottom:12px;
}
.mengeSumme b { color:var(--gold); }
.mengeSumme.zuwenig b { color:var(--rot); }
.mengeKnoepfe { display:flex; gap:8px; }
.mengeKnoepfe button {
  flex:1; background:transparent; border:1px solid var(--sand-leise); color:var(--sand);
  padding:9px 10px; cursor:pointer; font-size:12px; font-weight:700; font-family:inherit;
}
.mengeKnoepfe button:hover { background:var(--sand); color:#2a2016; }
.mengeKnoepfe .mengeOk { border-color:var(--gold); color:var(--gold); }
.mengeKnoepfe .mengeOk:hover { background:var(--gold); color:#2a2016; }
.mengeKnoepfe .mengeOk:disabled {
  border-color:var(--linie); color:var(--text-fern); background:transparent; cursor:not-allowed;
}
/* Der kleine Mengenknopf an einer Zeile: "⋯" statt eines zweiten Wortes.
   Er steht neben dem Hauptknopf, nicht an seiner Stelle -- ein Klick auf
   "Kaufen" bleibt ein Klick. */
.mengeMehr {
  flex-shrink:0; background:transparent; border:1px solid var(--linie);
  color:var(--text-leise); font-family:inherit; font-size:12px; font-weight:700;
  padding:6px 8px; cursor:pointer; margin-left:4px;
}
.mengeMehr:hover { border-color:var(--sand-leise); color:var(--sand); }
.mengeMehr:disabled { color:var(--text-fern); cursor:not-allowed; }

/* ==========================================================================
   DAS KLASSENSYSTEM -- Gruppenrahmen und Takt
   ========================================================================== */
/* Die Ressource der Mitspieler unter dem Leben: Wut, Mana, Energie. Farbe
   kommt von der Ressourcenart (data/ressourcen.js). */
.pRes { position:relative; height:4px; margin-top:2px; background:var(--grund); border:1px solid var(--linie-leise); overflow:hidden; }
.pRes > i { display:block; height:100%; }
.pPfad { font-size:11px; opacity:.85; }
/* Der GCD-Schleier: kurz und heller als eine Abklingzeit, damit man den
   Takt vom "noch nicht bereit" unterscheidet. */
.abilitySlot.imTakt .cooldownOverlay { background:rgba(242,237,225,.22); transition:none; }

.pMarken { font-size: 11px; line-height: 12px; letter-spacing: 1px; opacity: .9; }

/* Einladen-Knopf im Zielrahmen: der Rahmen selbst lässt Klicks durch
   (pointer-events:none), der Knopf fängt sie. */
#targetFrame .tAktion { pointer-events:auto; margin-top:5px; font:inherit; font-size:12px; padding:2px 8px; cursor:pointer;
  background:rgba(60,48,32,.95); color:var(--text, #f2ede1); border:1px solid var(--linie); border-radius:3px; }
#targetFrame .tAktion:hover { background:rgba(90,70,40,.95); }
#targetFrame .tAktion.still { pointer-events:none; background:none; border:none; padding:2px 0; opacity:.75; cursor:default; }

/* ---------- Spielermenü (Rechtsklick) ---------- */
#spielerMenue { position:absolute; z-index:60; min-width:190px; background:var(--flaeche-fest, rgba(36,28,20,.97)); border:1px solid var(--sand-leise, #a08a5a);
  box-shadow:0 10px 30px rgba(0,0,0,.6); padding:4px 0; font-size:13px; }
#spielerMenue.hidden { display:none; }
#spielerMenue .smKopf { padding:6px 12px 5px; font-weight:bold; border-bottom:1px solid var(--linie); margin-bottom:3px; color:var(--sand-hell, #e8d9b5); }
#spielerMenue .smKopf small { display:block; font-weight:normal; opacity:.7; font-size:11px; }
#spielerMenue .smEintrag { padding:6px 12px; cursor:pointer; display:flex; gap:8px; align-items:center; }
#spielerMenue .smEintrag:hover { background:rgba(255,255,255,.08); }
#spielerMenue .smEintrag.aus { opacity:.4; cursor:default; }
#spielerMenue .smTrenner { height:1px; background:var(--linie); margin:3px 0; }

/* ---------- Handelsanfrage ---------- */
#handelToast { position:absolute; top:190px; left:50%; transform:translateX(-50%); z-index:20;
  background:var(--flaeche-fest); border:1px solid var(--sand-leise); padding:14px 20px; text-align:center; box-shadow:0 12px 34px rgba(0,0,0,.55); }
#handelToastText { font-size:13px; margin-bottom:10px; }

/* ---------- Handelsfenster ---------- */
#handelPanel { width:560px; top:110px; left:16px; right:auto; }
.handelSeiten { display:flex; gap:14px; padding:0 14px; }
.handelSeite { flex:1; min-width:0; }
.handelGrid { grid-template-columns:repeat(3, 1fr); padding:6px 0; }
.handelGeld { display:flex; align-items:center; gap:6px; font-size:12px; padding:4px 0; }
.handelGeld input { width:90px; background:var(--feld); border:1px solid var(--linie); color:var(--text); padding:4px 6px; font:inherit; }
.handelBereit { font-size:12px; padding:4px 0 8px; opacity:.75; }
.handelBereit.ja { opacity:1; color:#8fd18f; }
.handelKnoepfe { display:flex; gap:8px; padding:6px 14px 14px; }
#handelBereitBtn.ja { background:#3f6b3f; }
#handelPanel .slot.angebot { cursor:pointer; }

/* ---------- Inspizieren: dieselbe Gestalt wie das eigene Charakterblatt ---------- */
#inspectPanel { top:16px; left:470px; right:auto; width:min(440px, 42vw); max-height:calc(100vh - 32px); overflow:hidden; display:flex; flex-direction:column; }
#inspectPanel .slot { width:52px; height:52px; }
#inspectPanel .equipIcon { width:30px; height:30px; }
#inspectPanel .slot.equipIconSlot { cursor:default; }
#inspectPanel .statList { display:flex; flex-direction:column; gap:4px; }
#inspectPanel .statList > div { display:flex; align-items:center; gap:6px; }
#inspectPanel .statList span.v { margin-left:auto; font-size:13.5px; }

/* ---------- Freunde ---------- */
#freundeList .partyRow .prName.online { color:#8fd18f; }
#freundeList .partyRow .prName.offline { opacity:.6; }
#freundeList .partyRow button { margin-left:4px; }
.chatMsg.fluester .from { color:#d78fe8; }
.chatMsg.fluester { color:#e6c6f0; }
.chatMsg .from.klick { cursor:pointer; text-decoration:underline dotted; }

/* ---- Gesten (13. September, classic_gefuehl A2) ---------------------------
   Eine Geste ist keine Rede, sondern eine Regieanweisung: „Kuku winkt".
   Sie steht deshalb kursiv, in einem waermeren Ton als der Chat, und ohne
   Namen davor -- der Name steht im Satz. Wer das gleich wie Rede setzt,
   bekommt ein Chatfenster, in dem niemand mehr sieht, wer etwas GESAGT hat. */
.chatMsg.geste { color:#e8c98a; font-style:italic; }
/* Auskünfte des Servers im Chat (/wer, /gesten): grau, ohne Absender.
   Sie sollen lesbar sein und trotzdem nicht wie eine Wortmeldung wirken. */
.chatMsg.system { color:#a9b6c4; }

/* ---- Sätze und Rüstungsklassen im Gegenstandsfenster (9. September) ---- */
/* Der Satz steht als eigener Block unter den Werten: Kopf mit Zählstand,
   darunter die beiden Stufen. Erreicht = hell, offen = grau. So sieht man auf
   einen Blick, wofür sich ein drittes Teil lohnt. */
.satzBlock { margin: 6px 0 2px; padding: 5px 7px; border-left: 2px solid #6a7c4a; background: rgba(106,124,74,.10); border-radius: 3px; }
.satzKopf { color: #b9d08a; font-weight: 600; font-size: 12px; }
.satzZahl { color: #8a9a6a; font-weight: 400; }
.satzStufe { color: #7b8470; font-size: 11px; line-height: 1.35; }
.satzStufe.aktiv { color: #d8e4b8; }
.ttSperre { margin-top: 5px; color: #e0806a; font-size: 11px; }
/* Die Satzboni stehen UNTER den Werten und über die ganze Breite -- als
   Element im zweispaltigen Raster hätten sie in einer halben Spalte
   umgebrochen und dreimal so hoch gestanden wie ihr Text. */
.satzAktiv { grid-column: 1 / -1; margin-top: 5px; padding-top: 5px; border-top: 1px solid #3a4030; }
.satzZeile { color: #b9d08a; font-size: 11px; line-height: 1.4; }

/* =========================================================================
   DIE POST (16. September, data/post.js) -- ein Fenster an der Botentafel
   ========================================================================= */
#postPanel { width:440px; }
.postReiter { display:flex; gap:6px; padding:8px 14px 0; }
.postTab { flex:1; padding:6px 8px; font-size:var(--schrift-klein); }
.postTab:not(.an) { background-image:linear-gradient(180deg, #d6c8a6 0%, #c2b28c 58%, #b3a279 100%); border-color:#7a6c4c; color:#463a22; font-weight:400; }
.postListe { padding:8px 14px; display:flex; flex-direction:column; gap:4px; max-height:320px; overflow:auto; }
.postZeile { display:flex; gap:8px; align-items:center; padding:6px 8px; border:1px solid var(--linie); background:var(--feld); cursor:pointer; font-size:var(--schrift-klein); }
.postZeile:hover { border-color:var(--sand-leise); }
.postZeile.neu .pzBetreff { font-weight:700; color:var(--text); }
.postZeile .pzVon { color:var(--text-leise); min-width:84px; }
.postZeile .pzBetreff { flex:1; color:var(--text-leise); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.postZeile .pzWann { color:var(--text-fern); font-size:var(--schrift-winzig); }
.postZeile .pzAnhang { color:var(--gold); }
.postLeer { padding:18px 14px; color:var(--text-fern); font-size:var(--schrift-klein); text-align:center; }
.postBrief { padding:8px 14px 14px; }
.postBrief .pbKopf { font-weight:700; color:var(--text); margin-bottom:2px; }
.postBrief .pbVon { color:var(--text-leise); font-size:var(--schrift-klein); margin-bottom:8px; }
.postBrief .pbText { white-space:pre-wrap; line-height:1.5; font-size:var(--schrift-text); color:var(--text); background:var(--feld); border:1px solid var(--linie); padding:8px 10px; max-height:180px; overflow:auto; }
.postBrief .pbAnhang { display:flex; gap:6px; align-items:center; margin-top:8px; flex-wrap:wrap; }
.postBrief .pbGeld { color:var(--gold); font-size:var(--schrift-klein); }
.postBrief .pbKnoepfe { display:flex; gap:6px; margin-top:10px; flex-wrap:wrap; }
.postBrief .pbKnoepfe button { padding:6px 10px; font-size:var(--schrift-klein); }
.postFeld { display:flex; gap:8px; align-items:center; padding:6px 14px 0; font-size:var(--schrift-klein); }
.postFeld label { min-width:56px; color:var(--text-leise); }
.postFeld input { flex:1; padding:5px 8px; background:var(--feld); border:1px solid var(--linie); color:var(--text); font:inherit; font-size:var(--schrift-klein); }
#postText { display:block; width:calc(100% - 28px); margin:8px 14px 0; height:80px; padding:6px 8px; background:var(--feld); border:1px solid var(--linie); color:var(--text); font:inherit; font-size:var(--schrift-klein); resize:vertical; }
#postSchreiben .sectionLabel { padding:8px 14px 0; }
/* Die Plätze im Brief und im Lager teilen die Form der Rucksackplätze
   (.slot) -- `.invSlot` hatte bis heute gar keine Regel, das Lager zeigte
   nackte Zeichen. Ein leerer Platz ist ein leerer Kasten, kein Nichts. */
.invSlot {
  width:42px; height:42px; background:#3a2e20; border:1px solid #6b563c;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.06);
  display:inline-flex; align-items:center; justify-content:center; font-size:20px;
  cursor:pointer; position:relative; transition:border-color .12s ease; box-sizing:border-box;
}
.invSlot:hover { border-color:#c9a227; }
.invSlot.leer { background:#2a2118; border-color:#4b3b2a; cursor:default; }
.invSlot .qty { position:absolute; bottom:1px; right:3px; font-size:10px; color:var(--sand); text-shadow:0 1px 2px #000; }
.postAnhang { padding:6px 14px 0; display:flex; gap:6px; }
.postAnhang .invSlot.leer { border-style:dashed; cursor:pointer; }
.postAnhang .invSlot.ziel { border-color:var(--gold); border-style:solid; box-shadow:0 0 0 1px rgba(227,189,109,.45); }
.postRucksack { padding:6px 14px 0; display:flex; flex-wrap:wrap; gap:6px; max-height:150px; overflow:auto; }
#postSchreiben .sectionLabel { font-size:var(--schrift-winzig); }
.postFuss { white-space:nowrap; }
.postFuss .msg { white-space:normal; }
.postFuss { display:flex; justify-content:space-between; align-items:center; padding:10px 14px 14px; gap:8px; }
.postFuss button { padding:7px 14px; font-size:var(--schrift-klein); }
/* DAS POSTZEICHEN AN DER MINIKARTE (20. September).
   Gegenüber der Tag-und-Nacht-Scheibe, am unteren Rand des Kreises -- dieselbe
   Bauart (runde Marke, die den Rand überlappt), damit die beiden wie ein Paar
   aussehen und nicht wie zwei Einfälle. Es ist anklickbar, obwohl der Kreis
   selbst `pointer-events:none` hat; deshalb steht das hier ausdrücklich. */
#postBadge {
  /* AM KREIS, NICHT AM KASTEN. Die Marke wird von OBEN gemessen und nicht von
     unten: Unter dem Kreis hängen noch der Ortsname und die Suchknöpfe, und
     ein `bottom` hätte sie über deren Zeile gelegt statt an den Rand der
     Scheibe. 134px ist die untere rechte Schräge eines 176er Kreises. */
  position:absolute; right:2px; top:134px; z-index:3; pointer-events:auto;
  display:flex; align-items:center; justify-content:center; gap:1px;
  min-width:34px; height:28px; padding:0 6px;
  border:2px solid #6b563c; border-radius:14px;
  background:rgba(36,28,20,.96); color:var(--gold);
  font-size:13px; font-weight:700; line-height:1; cursor:pointer;
  box-shadow:0 3px 10px rgba(0,0,0,.6);
  animation:postPochen 2.4s ease-in-out infinite;
}
#postBadge:hover { border-color:var(--gold); color:#ffe9a8; }
#postBadgeZahl { font-size:11px; }
/* Ein ruhiges Pochen, kein Blinken: Es soll auffallen, wenn man hinsieht, und
   nicht am Rand des Blickfelds zappeln, während man kämpft. */
@keyframes postPochen {
  0%, 100% { box-shadow:0 3px 10px rgba(0,0,0,.6); }
  50%      { box-shadow:0 3px 10px rgba(0,0,0,.6), 0 0 12px 2px rgba(227,189,109,.55); }
}
@media (prefers-reduced-motion: reduce) { #postBadge { animation:none; } }

/* =========================================================================
   DER MARKT (16. September, data/markt.js) -- ein Fenster am Markttisch
   ========================================================================= */
#marktPanel { width:520px; }
#marktKaufen .postFeld { padding-top:8px; }
#marktKaufen .postFeld button { padding:5px 12px; font-size:var(--schrift-klein); }
.marktListe { padding:8px 14px 14px; display:flex; flex-direction:column; gap:4px; max-height:340px; overflow:auto; }
.marktZeile { display:grid; grid-template-columns:34px 1fr auto auto; gap:8px; align-items:center; padding:5px 8px; border:1px solid var(--linie); background:var(--feld); font-size:var(--schrift-klein); }
.marktZeile .mzName { color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.marktZeile .mzName small { display:block; color:var(--text-fern); font-size:var(--schrift-winzig); }
.marktZeile .mzPreis { text-align:right; color:var(--gold); white-space:nowrap; }
.marktZeile .mzPreis small { display:block; color:var(--text-fern); font-size:var(--schrift-winzig); font-weight:400; }
.marktZeile button { padding:5px 10px; font-size:var(--schrift-klein); white-space:nowrap; }
.marktZeile .invSlot { width:34px; height:34px; font-size:18px; cursor:default; }
.marktLeer { padding:18px 14px; color:var(--text-fern); font-size:var(--schrift-klein); text-align:center; }
.marktWahl { padding:8px 14px 0; font-size:var(--schrift-klein); color:var(--text-leise); min-height:20px; }
.marktWahl b { color:var(--text); }
#marktVerkaufen select { padding:5px 8px; background:var(--feld); border:1px solid var(--linie); color:var(--text); font:inherit; font-size:var(--schrift-klein); }

/* Der Ruf im Charakterblatt (data/ruf.js): Name, Stufe, ein Balken. */
.rufZeile { display:flex; flex-direction:column; gap:3px; padding:4px 0; border-bottom:1px solid rgba(75,59,42,.5); }
.rufZeile:last-child { border-bottom:0; }
.rufZeile .rzKopf { display:flex; justify-content:space-between; font-size:var(--schrift-klein); }
.rufZeile .rzKopf b { color:var(--text); font-weight:600; }
.rufZeile .rzKopf span { color:var(--gold); }
.rufZeile .rzBalken { height:6px; background:var(--grund); border:1px solid var(--linie); }
.rufZeile .rzBalken i { display:block; height:100%; background:linear-gradient(90deg, #a5813f, #e3bd6d); }
.rufZeile .rzZahl { font-size:var(--schrift-winzig); color:var(--text-fern); }
.rufLeer { font-size:var(--schrift-klein); color:var(--text-fern); padding:4px 0; }
/* Die Sperre an der Tür des Abstiegs (data/sperre.js) */
.npcSperre { font-size:var(--schrift-klein); color:var(--gold); margin-top:6px; padding:6px 8px; border:1px solid var(--linie); background:rgba(0,0,0,.25); }

/* =========================================================================
   DER WURF -- das Fenster in der Kammer (20. September, data/wurf.js)
   =========================================================================
   Oliver: „genau im dungeon machen wir es so, ab selten alles würfeln etc".

   Bewusst KEIN Modalfenster. Ein Boss kann mehrere Stücke hinterlassen, und
   wer drei davon vor sich hat, soll dreimal entscheiden können, ohne dass
   das Spiel dreimal stillsteht. Also ein Stapel am linken Rand, unter der
   Kopfleiste, der das Spiel durchlässt -- nur die Karten selbst nehmen
   Klicks an.

   Die Farbe des Randes ist die Seltenheitsfarbe des Stücks (data/beute.js,
   SELTENHEITEN). Sie wird als Stilvariable gesetzt, nicht als Klasse: So
   braucht eine neue Sprosse in der Leiter hier keine Zeile. */
#wurfStapel {
  position:absolute; top:70px; left:14px; z-index:22;
  display:flex; flex-direction:column; gap:8px;
  pointer-events:none; max-width:320px;
}
.wurfKarte {
  pointer-events:auto; width:300px;
  background:rgba(24,19,13,.97); border:1px solid var(--linie);
  border-left:3px solid var(--wurfFarbe, var(--gold));
  box-shadow:0 10px 30px rgba(0,0,0,.65);
  padding:10px 12px 9px; font-size:var(--schrift-klein);
  animation:wurfRein .22s ease-out;
}
@keyframes wurfRein { from { opacity:0; transform:translateX(-14px); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) { .wurfKarte { animation:none; } }

.wurfKopf { display:flex; align-items:flex-start; gap:8px; margin-bottom:2px; }
.wurfKopf .wkIcon { font-size:20px; line-height:1.2; }
/* DER NAME DARF UMBRECHEN. Erzeugte Stuecke heissen „Zäher Enkuri-Rundschild
   des Bären" -- mit einer Zeile und Ellipse stand dort „Zäher Enkuri-Rund…",
   und genau der Teil, der das Stueck unterscheidet (Fassung und Affix), fiel
   weg. Zwei Zeilen kosten nichts; ein abgeschnittener Name kostet die
   Entscheidung. */
.wurfKopf .wkName { font-weight:700; color:var(--wurfFarbe, var(--gold)); flex:1;
                    line-height:1.3; }
.wurfKopf .wkUhr { font-variant-numeric:tabular-nums; color:var(--text-fern);
                   font-size:var(--schrift-winzig); padding-top:2px; white-space:nowrap; }
.wurfKopf .wkUhr.knapp { color:var(--rot); font-weight:700; }
.wurfUnter { color:var(--text-fern); font-size:var(--schrift-winzig); margin-bottom:8px; }

/* Die Frist als Balken. Er läuft per CSS-Übergang ab und nicht per Bild-
   schleife: Das kostet nichts und stockt nicht, wenn der Kampf ruckelt. */
.wurfBalken { height:2px; background:var(--linie); margin:0 0 9px; overflow:hidden; }
.wurfBalken i { display:block; height:100%; background:var(--wurfFarbe, var(--gold));
                width:100%; transform-origin:left center; }

.wurfKnoepfe { display:flex; gap:6px; }
.wurfKnoepfe button { flex:1; padding:6px 4px; font-size:var(--schrift-klein); cursor:pointer; }
.wurfKnoepfe button.gewaehlt { border-color:var(--gold); color:#ffe9a8; background:#3b2f1e; }
.wurfKnoepfe button:disabled { opacity:.55; cursor:default; }

.wurfLeute { margin-top:8px; display:flex; flex-wrap:wrap; gap:4px 10px;
             font-size:var(--schrift-winzig); color:var(--text-fern); }
.wurfLeute span b { color:var(--text-leise); font-weight:400; }
.wurfLeute .wlBedarf { color:#7ee081; }
.wurfLeute .wlGier   { color:var(--gold); }
.wurfLeute .wlVerzicht { color:var(--text-fern); }
.wurfLeute .wlOffen  { color:var(--text-fern); opacity:.6; }

/* Das Ergebnis bleibt kurz stehen -- lange genug, dass man die Zahlen der
   anderen liest, kurz genug, dass es nicht im Weg steht. */
.wurfKarte.fertig .wurfKnoepfe { display:none; }
.wurfErgebnis { margin-top:6px; font-size:var(--schrift-klein); color:var(--text); }
.wurfErgebnis.meins { color:#7ee081; font-weight:700; }
.wurfWuerfe { margin-top:5px; font-size:var(--schrift-winzig); color:var(--text-fern); line-height:1.7; }
.wurfWuerfe .wwZeile { display:flex; justify-content:space-between; gap:10px; }
.wurfWuerfe .wwZeile.sieger { color:var(--gold); }
