/* ============================================================
   Astro Clicker — Dark-Space-Theme
   ============================================================ */

:root {
  --bg:        #070a14;
  --bg-panel:  rgba(18, 24, 42, 0.72);
  --bg-row:    rgba(30, 39, 66, 0.55);
  --border:    rgba(120, 150, 220, 0.16);
  --text:      #dfe6f5;
  --text-dim:  #8b97b5;
  --accent:    #6fd3ff;
  --accent-2:  #a98bff;   /* Progression: Wurmloch/Prestige/Sternenstaub UND Upgrades */
  --duel:      #ff9a5c;   /* Wettkampf: Duell — bewusst NICHT Violett (das war überladen) */
  --gold:      #ffcc66;
  --danger:    #ff7a7a;
  --ok:        #7ee08a;
  --radius:    12px;
}

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

/* ---------- Doppeltipp-Zoom auf iOS unterbinden ---------------
   In einem Klickspiel landen zwangsläufig zwei Tipps schnell
   hintereinander am selben Fleck — Safari deutet das als
   "hineinzoomen" und die Ansicht springt.

   `touch-action: manipulation` schaltet die Doppeltipp-Geste ab. Der
   Zwei-Finger-Zoom ist zusätzlich über das Viewport-Meta
   (`user-scalable=no`, siehe index.html) UND `verhindereZoom()` in
   game.js gesperrt — BEWUSST: Auf dem vergrößerten Riesen-Asteroiden
   erzeugten zwei abwechselnde Finger doppelt so viele Klicks wie ein
   Mensch mit einem Finger (gemeldeter Exploit). Der Klick-Deckel
   MIN_KLICK_MS in game.js fängt den Rest ab.

   `touch-action` vererbt sich NICHT, deshalb der Universalselektor
   statt einer Liste einzelner Elemente — sonst bleibt garantiert eine
   Fläche übrig, auf der es doch wieder springt. */
* { touch-action: manipulation; }

html {
  height: 100%;
  /* Der Hintergrund gehört auf html, NICHT auf body. Grund: #starfield
     liegt auf z-index -2. In der Malreihenfolge kommen negative
     z-index-Kinder VOR den Hintergründen normaler Block-Elemente — ein
     deckender body-Hintergrund würde das komplette Sternenfeld
     übermalen. Genau das war es: gemessen 74.800 Pixel, exakt eine
     Farbe, kein einziger Stern sichtbar. */
  background: var(--bg);
  color: var(--text);
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  overflow-x: hidden;
  /* Ohne das vergrößert iOS im Querformat eigenmächtig die Schrift und
     sprengt die Zeilen, die für die schmale Ansicht gerechnet sind. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  height: 100%;
  background: transparent;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}

.hidden { display: none !important; }

/* ---------- Sternenfeld ------------------------------------- */
#starfield {
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(ellipse at 20% 15%, rgba(110, 90, 200, 0.18), transparent 55%),
    radial-gradient(ellipse at 80% 80%, rgba(40, 130, 190, 0.16), transparent 55%),
    var(--bg);
}
.star {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  /* --o wird je Stern per JS gesetzt; in Keyframes funktioniert `inherit` nicht. */
  opacity: var(--o, 0.6);
  animation: twinkle 5s ease-in-out infinite;
}
@keyframes twinkle {
  0%, 100% { opacity: var(--o, 0.6); }
  50%      { opacity: calc(var(--o, 0.6) * 0.25); }
}

/* ---------- Kopfzeile --------------------------------------- */
#topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  /* Der obere Sicherheitsabstand gehoert HIERHER, nicht an <body>:
     Die Kopfzeile ist `sticky` und schob sich sonst unter die
     iOS-Statusleiste — auf dem iPhone lag die Uhr genau auf dem
     Titel. */
  padding: calc(10px + env(safe-area-inset-top)) 18px 10px;
  border-bottom: 1px solid var(--border);
  background: rgba(10, 14, 26, 0.85);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 20;
}
.brand { display: flex; align-items: center; gap: 8px; font-weight: 600; letter-spacing: 0.02em; }
.brand-mark { color: var(--accent); font-size: 18px; }
.brand-name { white-space: nowrap; }

.counters { margin-left: auto; text-align: center; line-height: 1.15; }
.counter-main { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.counter-unit { font-size: 14px; color: var(--text-dim); font-weight: 500; margin-left: 4px; }
.counter-rate { font-size: 13px; color: var(--accent); font-variant-numeric: tabular-nums; }

.icon-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  width: 38px; height: 38px;
  font-size: 18px;
  cursor: pointer;
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent); }

/* ---------- Layout ------------------------------------------ */
/* Zwei Spalten am Rechner: links der Asteroid (klebt beim Scrollen),
   rechts der gewählte Bereich. Vorher standen hier drei Spalten mit
   allem gleichzeitig — Statistik, Asteroid, Shop —, und auf schmalen
   Geräten klappte dieselbe Anordnung zu einer sehr langen Säule
   zusammen, durch die man am Asteroiden vorbeiscrollte. */
#layout {
  order: 2;                 /* body ist flex-column: Leiste davor */
  flex: 1;
  display: grid;
  grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
  gap: 16px;
  padding: 16px;
  align-items: start;
  min-height: 0;
}

#panes { min-width: 0; }
.pane { max-height: calc(100vh - 170px); overflow-y: auto; }

.panel {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  backdrop-filter: blur(6px);
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}
.panel-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-dim);
  margin-bottom: 10px;
}

/* ---------- Statistik --------------------------------------- */
.stats { display: grid; grid-template-columns: 1fr auto; gap: 6px 10px; font-size: 13px; }
.stats dt { color: var(--text-dim); }
.stats dd { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

/* ---------- Prestige ---------------------------------------- */
.prestige {
  margin-top: 20px;
  padding: 12px;
  border: 1px solid rgba(169, 139, 255, 0.35);
  border-radius: var(--radius);
  background: rgba(80, 50, 150, 0.14);
}
.prestige-text { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; margin-bottom: 10px; }
.prestige-text strong { color: var(--accent-2); }

/* ---------- Erfolge ----------------------------------------- */
.achievements { margin-top: 20px; }
.ach-count { float: right; color: var(--text-dim); letter-spacing: 0; }
.ach-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(34px, 1fr)); gap: 6px; }
.ach {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 8px;
  background: rgba(255, 204, 102, 0.12);
  border: 1px solid rgba(255, 204, 102, 0.35);
  font-size: 16px;
  cursor: default;
}
.ach.locked { background: rgba(255, 255, 255, 0.03); border-color: var(--border); }
.ach.locked .ach-icon { filter: grayscale(1); opacity: 0.25; }

/* Herausforderungen (+3 % statt +1 %) heben sich ab: kräftigerer Rahmen
   und eine kleine Ecke oben rechts. Auch im verschlossenen Zustand — man
   soll SEHEN, dass dort etwas Besonderes zu holen ist, sonst sucht
   niemand danach. */
.ach.challenge { border-color: rgba(255, 204, 102, 0.75); border-width: 2px; }
.ach.challenge::before {
  content: '';
  position: absolute;
  top: 0; right: 0;
  border-width: 0 7px 7px 0;
  border-style: solid;
  border-color: transparent var(--gold, #ffcc66) transparent transparent;
  border-top-right-radius: 6px;
}
.ach.challenge.locked { border-color: rgba(255, 204, 102, 0.35); }
.ach.challenge.locked::before { opacity: 0.4; }



/* ---------- Asteroid ---------------------------------------- */
#col-clicker {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 20px 0;
  min-height: 60vh;
}
/* Der Wrap reserviert die GRÖSSTE mögliche Darstellung, der Brocken
   selbst ist um `ASTEROID.maxSize` (1,45) kleiner angesetzt.

   Ohne das sprengte ein voller grosser Brocken sein Layoutfeld: Die
   Groesse steckt in `transform: scale(--scale)`, und Transformationen
   veraendern den Platzbedarf im Layout NICHT. Gemessen am Handy: Kasten
   230 px, gezeichnet 334 px — die Beschriftung und die Reserveleiste
   lagen danach halb unter dem Stein, oben ragte er unter die Kopfzeile.
   Die sichtbare Groesse bleibt unveraendert, nur der Platz stimmt jetzt. */
#asteroid-wrap {
  position: relative;
  display: grid;
  place-items: center;
  width: min(38vh, 300px);
  height: min(38vh, 300px);
}

#asteroid {
  position: relative;
  /* 300 / 1,45 / 1,05 — siehe #asteroid-wrap. Der letzte Faktor ist der
     Spielraum für Driften und Atmen (seit 4.22): Ohne ihn ragt der
     Brocken beim Ausatmen über sein reserviertes Feld hinaus, und die
     Beschriftung liegt wieder halb unter dem Stein (der Fehler aus 4.14).
     Auf dem Handy rechnet js/ui.js denselben Spielraum in
     `--asteroid-size` ein. */
  width: min(24.7vh, 197px);
  height: min(24.7vh, 197px);
  border: none;
  border-radius: 48% 52% 44% 56% / 52% 46% 54% 48%;
  cursor: pointer;
  /* Der Körper beschneidet die Beleuchtungsebene auf seinen Umriss.
     Ohne das stand die gegengedrehte Ebene schief zum Klumpen und zeigte
     einen hellen Saum an der einen und einen dunklen an der anderen
     Seite. Der Schein nach aussen (`box-shadow`) bleibt unberührt —
     `overflow` beschneidet Kinder, nicht den eigenen Schatten. */
  overflow: hidden;

  /* Nur noch der KÖRPER: Gestein, gleichmäßig gefärbt. Glanzpunkt und
     Schlagschatten sitzen seit 4.22 in `#asteroid::after` und drehen
     sich nicht mit (siehe dort). Der Schein nach außen bleibt hier — er
     gehört zum Brocken, nicht zur Beleuchtung. */
  background:
    radial-gradient(circle at 50% 50%, #8a7f6f 0%, #6b6154 58%, #564e44 100%);
  box-shadow: 0 0 60px rgba(120, 180, 255, 0.14);
  transition: transform 0.08s ease-out;
  /* verhindert Textmarkierung und Doppeltipp-Zoom beim schnellen Klicken */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* iOS feuert bei langem Druck kein verlässliches `contextmenu` — ohne
     das hier erscheint trotz preventDefault das Auswahl-Menü, sobald man
     den Finger beim Klicken kurz liegen lässt. */
  -webkit-touch-callout: none;
}
#asteroid {
  /* --scale steuert die Abtragung, gesetzt von ui.js. Die Klick-Animation
     multipliziert darauf, damit sich beides nicht gegenseitig aufhebt. */
  transform: scale(var(--scale, 1));
  transition: transform 0.28s cubic-bezier(0.34, 1.4, 0.64, 1), filter 0.2s;
  filter: hue-rotate(var(--tint-shift, 0deg));
}
#asteroid:hover { filter: hue-rotate(var(--tint-shift, 0deg)) brightness(1.08); }

#asteroid.hit { animation: punch 0.13s ease-out; }
@keyframes punch {
  0%   { transform: scale(var(--scale, 1)); }
  45%  { transform: scale(calc(var(--scale, 1) * 0.93)); }
  100% { transform: scale(var(--scale, 1)); }
}

/* Zerfall: kurz aufblitzen, dann in sich zusammenfallen. */
#asteroid.shattering {
  animation: shatter 0.38s ease-in forwards;
  pointer-events: none;
}
@keyframes shatter {
  0%   { transform: scale(var(--scale, 1)); filter: brightness(1); }
  25%  { transform: scale(calc(var(--scale, 1) * 1.16)); filter: brightness(2.4); }
  100% { transform: scale(0); filter: brightness(3); opacity: 0; }
}

/* Nachfolger zieht heran. */
#asteroid.arriving { animation: arrive 0.42s cubic-bezier(0.22, 1.3, 0.5, 1) backwards; }
@keyframes arrive {
  0%   { transform: scale(0) rotate(-25deg); opacity: 0; }
  100% { transform: scale(var(--scale, 1)) rotate(0); opacity: 1; }
}

/* Gesteinsbrocken, die beim Zerfall wegfliegen. */
.debris {
  position: absolute;
  left: 50%; top: 50%;
  border-radius: 40% 60% 55% 45%;
  background: linear-gradient(135deg, #9a8d7c, #4a4238);
  animation: debrisFly 0.7s ease-out forwards;
  pointer-events: none;
}
@keyframes debrisFly {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0); }
  100% { opacity: 0;
         transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy)))
                    scale(0.3) rotate(220deg); }
}

/* ---------- Reserve-Anzeige --------------------------------- */
#asteroid-info { width: min(280px, 78vw); }
.asteroid-head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 6px;
}
#asteroid-label {
  font-size: 13px; font-weight: 600; letter-spacing: 0.01em;
}
.asteroid-bonus {
  font-size: 12px; font-weight: 700; color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.reserve-track {
  height: 6px; border-radius: 3px; overflow: hidden;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--border);
}
.reserve-fill {
  height: 100%; width: 100%;
  /* Einfarbig statt Verlauf: Der Verlauf wurde mit der Breite gestaucht
     und sah bei 8 % Reserve genauso rot-gelb-grün aus wie bei 100 % —
     die Farbe trug also keine Information. Jetzt zeigt die Farbe den
     Füllstand: grün = viel, gold = halb, rot = fast leer. */
  background: var(--ok);
  transition: width 0.25s ease-out, background-color 0.3s;
}
.reserve-fill.mittel { background: var(--gold); }
.reserve-fill.knapp  { background: var(--danger); }
.asteroid-foot {
  margin-top: 5px; text-align: right;
  font-size: 11px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.crater {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, rgba(0,0,0,0.42), rgba(0,0,0,0.10) 70%);
  box-shadow: inset 0 2px 4px rgba(0,0,0,0.5), 0 1px 0 rgba(255,255,255,0.05);
  pointer-events: none;
  /* Bewusst KEIN `transform: translate(-50%,-50%)`: Die eigenen
     Eigenschaften werden in der Reihenfolge translate → scale → transform
     angewandt, die Zentrierung würde also von der Verkürzung mitskaliert
     und der Krater liefe aus der Bahn. js/ui.js rechnet die halbe Grösse
     gleich in die Verschiebung ein. */
}
/* Startwerte für den Fall, dass die Oberflächen-Rechnung nie läuft
   (weniger Bewegung eingestellt, oder JS aus): Dann steht der Brocken
   still und sieht aus wie bis 4.21. */
.c1 { width: 22%; height: 22%; top: 29%; left: 33%; }
.c2 { width: 14%; height: 14%; top: 59%; left: 23%; }
.c3 { width: 28%; height: 26%; top: 59%; left: 62%; }
.c4 { width: 11%; height: 11%; top: 30%; left: 68%; }
.c5 { width: 9%;  height: 9%;  top: 77%; left: 45%; }
.c6 { width: 12%; height: 12%; top: 42%; left: 44%; }
.c7 { width: 8%;  height: 8%;  top: 66%; left: 62%; }
.c8 { width: 10%; height: 10%; top: 22%; left: 48%; }

/* ---------- Die Beleuchtung dreht sich NICHT mit (seit 4.22) ---

   Bis 4.21 steckten Glanzpunkt und Schatten im Brocken selbst — sie
   drehten sich also mit ihm, und damit wanderte die Sonne im Kreis um
   den Asteroiden. Genau das liess die Drehung flach wirken.

   Jetzt liegt die Beleuchtung in einer eigenen Ebene, die js/ui.js
   GEGEN die Drehung hält: Der Stein dreht sich unter einer festen Sonne
   durch. Sie liegt über den Kratern, weil Licht auf allem liegt. */
#asteroid::after {
  content: '';
  position: absolute;
  /* Grösser als der Körper und rund: So bleibt beim Gegendrehen keine
     Ecke unbeleuchtet, und der Körper schneidet den Überstand weg. */
  inset: -7%;
  border-radius: 50%;
  pointer-events: none;
  rotate: var(--licht-dreh, 0deg);
  /* Diese Ebene trägt das VOLUMEN, nicht bloß einen Glanzpunkt: vom
     Licht oben links bis fast schwarz an der abgewandten Seite. Beim
     ersten Versuch stand hier nur ein zarter Schimmer — der Brocken sah
     danach aus wie eine blasse Scheibe, weil das Dunkel fehlte. */
  /* Die Halte-Punkte sind auf die VERGRÖSSERTE Ebene gerechnet: Der
     sichtbare Rand des Körpers liegt bei rund 88 % ihres Radius. Beim
     ersten Versuch stand das Dunkel bei 100 % — also ausserhalb des
     Sichtbaren, und der Brocken sah wieder flach aus. */
  background: radial-gradient(circle at 32% 27%,
                rgba(255, 244, 224, 0.36) 0%,
                rgba(255, 240, 214, 0.10) 22%,
                rgba(0, 0, 0, 0) 40%,
                rgba(0, 0, 0, 0.42) 64%,
                rgba(0, 0, 0, 0.72) 80%,
                rgba(0, 0, 0, 0.88) 92%);
  box-shadow:
    inset -22px -22px 46px rgba(0, 0, 0, 0.6),
    inset 14px 14px 30px rgba(255, 235, 200, 0.12);
}

#particles { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.particle {
  position: absolute;
  transform: translate(-50%, -50%);
  color: var(--gold);
  font-weight: 700;
  font-size: 17px;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
  animation: floatUp 1s ease-out forwards;
  white-space: nowrap;
}
@keyframes floatUp {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--drift, 0px)), -160%) scale(1.15); }
}

/* ---------- „Was jetzt?" ------------------------------------
   Eine Zeile, ein Schritt. Sie steht bewusst ruhig da (gedämpfte
   Schrift, kein Rahmen, keine Signalfarbe): Sie soll da sein, wenn man
   sie sucht, und nicht mit dem Asteroiden um Aufmerksamkeit ringen. */
.next-step {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 8px;
  max-width: min(340px, 92vw);
  margin: 0 auto;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.45;
  text-align: left;
}
.next-step-icon { font-size: 16px; line-height: 1; }
.next-step-text { min-width: 0; }
/* Der Balken gehört zum Sparziel und spannt sich unter beide Spalten. */
.next-step-track {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.next-step-fill {
  height: 100%;
  width: 0;
  border-radius: 3px;
  background: var(--accent);
  transition: width 0.25s ease-out;
}

/* ---------- Wurmloch-Zeile (seit 4.18) -----------------------
   Violett, weil Progression violett ist (Farbsemantik seit 2.3.1) — und
   als Zeile, nicht als Knopf: Sie führt zum Kasten im Bereich
   „Fortschritt", sie zündet nichts. Ein zündender Knopf neben dem
   Verkaufsknopf wäre die folgenschwerste Handlung des Spiels an der
   unauffälligsten Stelle. */
.wurmloch-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: min(340px, 92vw);
  margin: 0 auto;
  padding: 6px 12px;
  border: 1px solid rgba(169, 139, 255, 0.45);
  border-radius: 999px;
  background: rgba(169, 139, 255, 0.10);
  color: var(--accent-2);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.wurmloch-zeile:hover { background: rgba(169, 139, 255, 0.18); }
.wl-icon { font-size: 15px; line-height: 1; }
.wl-text { min-width: 0; }
.wl-mehr { opacity: 0.7; }

/* ---------- Erklärungen sichtbar machen ----------------------

   Die Tooltips gab es längst — nur sah man ihnen nicht an, dass sie da
   sind. Ein Neuling tippt nicht auf gut Glück auf „Sternenstaub". Also
   ein zurückhaltendes Fragezeichen in Cyan (= interaktiv, gemäß der
   Farbsemantik) und eine gepunktete Linie unter dem Wort. */
.has-tip { position: relative; cursor: help; }
.has-tip::after {
  content: '?';
  display: inline-grid;
  place-items: center;
  width: 14px; height: 14px;
  margin-left: 5px;
  vertical-align: 1px;
  border: 1px solid rgba(111, 211, 255, 0.45);
  border-radius: 50%;
  color: var(--accent);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  opacity: 0.75;
}
.has-tip:hover::after { opacity: 1; background: rgba(111, 211, 255, 0.12); }
/* In der Statistik trägt nur die Beschriftung links das Zeichen — an der
   Zahl rechts sähe es aus, als gehörte es zum Wert. */
.stats dd.has-tip::after { content: none; }

/* ---------- Shop -------------------------------------------- */
.shop-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.tab {
  flex: 1;
  padding: 8px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.tab.active { color: var(--text); border-color: var(--accent); background: rgba(111, 211, 255, 0.10); }
.badge {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  margin-left: 4px;
  border-radius: 9px;
  background: var(--ok);
  color: #07200c;
  font-size: 11px;
  font-weight: 700;
}

.buy-amounts { display: flex; align-items: center; gap: 5px; margin-bottom: 10px; }
.buy-label { font-size: 11px; color: var(--text-dim); margin-right: 2px; }
.amount {
  flex: 1;
  padding: 5px 0;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-dim);
  font-size: 12px;
  cursor: pointer;
}
.amount.active { color: var(--text); border-color: var(--accent); background: rgba(111, 211, 255, 0.12); }

/* Kaufen/Verkaufen-Umschalter. „Verkaufen" bekommt aktiv einen warmen
   Gold-Ton (statt Blau), damit auf einen Blick klar ist, dass ein Tap
   auf eine Zeile jetzt VERKAUFT statt kauft. */
.buy-mode { display: flex; gap: 5px; margin-bottom: 8px; }
.mode {
  flex: 1;
  padding: 6px 0;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.mode.active { color: var(--text); border-color: var(--accent); background: rgba(111, 211, 255, 0.12); }
#mode-sell.active { border-color: var(--gold); background: rgba(240, 200, 100, 0.14); }

/* Im Verkaufen-Modus bekommt die ganze Liste den Gold-Rand als Kontext;
   der Preis zeigt die Rückerstattung (in JS mit „+" davor). */
#building-list.sell-mode .shop-row { border-left-color: var(--gold); }
#building-list.sell-mode .shop-row.locked { border-left-color: var(--danger); }
#building-list.sell-mode .row-cost { color: var(--gold); }

.shop-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin-bottom: 6px;
  padding: 10px 12px;
  background: var(--bg-row);
  border: 1px solid var(--border);
  border-left: 3px solid var(--ok);
  border-radius: 10px;
  color: var(--text);
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, transform 0.08s;
}
.shop-row:hover { background: rgba(45, 58, 95, 0.75); }
.shop-row:active { transform: scale(0.985); }
.shop-row.locked {
  border-left-color: var(--danger);
  opacity: 0.5;
  cursor: not-allowed;
}
.row-main { flex: 1; min-width: 0; }
.row-name { font-size: 13.5px; font-weight: 600; }
.row-cost { font-size: 12px; color: var(--gold); font-variant-numeric: tabular-nums; }
.shop-row.locked .row-cost { color: var(--danger); }
.row-side { text-align: right; }
.row-count { font-size: 19px; font-weight: 700; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.row-out { font-size: 11px; color: var(--accent); font-variant-numeric: tabular-nums; }



.shop-row.upgrade { border-left-color: var(--accent-2); }
.shop-row.upgrade.locked { border-left-color: var(--danger); }

.empty-hint { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; padding: 8px 2px; }

/* ---------- Buttons ----------------------------------------- */
.btn {
  padding: 9px 14px;
  background: rgba(111, 211, 255, 0.12);
  border: 1px solid var(--accent);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover { background: rgba(111, 211, 255, 0.22); }
.btn-prestige { width: 100%; border-color: var(--accent-2); background: rgba(169, 139, 255, 0.16); }
.btn-prestige:hover { background: rgba(169, 139, 255, 0.28); }
.btn-danger { border-color: var(--danger); background: rgba(255, 122, 122, 0.12); }
.btn-danger:hover { background: rgba(255, 122, 122, 0.22); }
.btn-ghost { border-color: var(--border); background: none; color: var(--text-dim); }

/* ---------- Overlays ---------------------------------------- */
/* `place-items: start center` statt `center` plus `overflow-y: auto`:
   Ein zentrierter Dialog, der hoeher ist als das Fenster, ragt oben UND
   unten heraus — und weil nichts scrollt, ist der obere Teil samt
   Ueberschrift unerreichbar. Im Querformat (812x375) traf das den
   Konto-Dialog. `margin: auto 0` haelt ihn trotzdem mittig, solange er
   passt. */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: start center;
  overflow-y: auto;
  padding: 20px;
  background: rgba(4, 6, 12, 0.78);
  backdrop-filter: blur(4px);
}
.modal {
  width: min(440px, 100%);
  margin: auto 0;
  padding: 22px;
  background: #0e1322;
  border: 1px solid var(--border);
  border-radius: 14px;
}
.modal h2 { font-size: 17px; margin-bottom: 14px; }
.modal p { font-size: 13.5px; color: var(--text-dim); line-height: 1.6; margin-bottom: 16px; }
.modal-actions { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }

/* Knöpfe, die DIREKT im Dialog stehen (die „Schließen"-Knöpfe), waren
   nur inhaltsbreit und klebten dadurch am linken Rand — neben den
   vollbreiten Knöpfen aus `.modal-actions` sah das nach Versehen aus.
   `.modal-actions` selbst ist ein Flex-Container und bleibt unberührt.
   `#btn-new-invite` steckt eine Ebene tiefer (in `#invite-section`) und
   wird von `.modal > .btn` NICHT erfasst — deshalb ausdrücklich dazu,
   sonst klebt „Neuen Code erzeugen" schmal am linken Rand. */
.modal > .btn,
#btn-new-invite {
  display: block;
  width: 100%;
  text-align: center;
}
/* Luft nach unten: „Neuen Code erzeugen" und das darunter folgende
   „Abmelden" stehen in getrennten Containern (`#invite-section` bzw.
   `.modal-actions`), also greift der `gap` von `.modal-actions` NICHT
   dazwischen — ohne diesen Abstand kleben die beiden aneinander. */
#btn-new-invite { margin-bottom: 8px; }
.save-io {
  width: 100%;
  height: 110px;
  margin-bottom: 10px;
  padding: 8px;
  background: #070a14;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 11px;
  resize: vertical;
}
.menu-note { font-size: 12px; color: var(--ok); min-height: 16px; margin-bottom: 10px; }

/* ---------- Toast ------------------------------------------- */
.toast {
  position: fixed;
  left: 50%;
  /* Ueber Bereichsleiste UND Update-/Installations-Leiste hinweg: Die
     sitzen unten, der Toast rueckt darueber, damit er nicht dahinter
     verschwindet. `--tabbar-h` ist nur auf dem Handy gesetzt. */
  bottom: calc(var(--tabbar-h, 0px) + 78px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  /* 76, nicht 50: ueber Schranke (60) UND ueber den beiden unteren
     Leisten (74/75) — sonst verdeckt eine offene Update-Leiste genau die
     Meldung, die man lesen soll. */
  z-index: 76;
  padding: 10px 18px;
  background: #131a2c;
  border: 1px solid var(--gold);
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--gold);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  animation: toastIn 0.25s ease-out;
}
.toast.toast-gut    { border-color: var(--ok);     color: var(--ok); }
.toast.toast-fehler { border-color: var(--danger); color: var(--danger); }
@keyframes toastIn {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* ---------- Responsiv --------------------------------------- */
@media (max-width: 1080px) {
  #layout { grid-template-columns: 1fr 320px; }
  #col-stats { grid-column: 1 / -1; order: 3; max-height: none; }
}

@media (max-width: 760px) {
  /* Handy: Der Asteroid steht fest im oberen Drittel, NUR der Bereich
     darunter scrollt. Deshalb bekommt die Seite selbst keinen Scroll —
     sonst schöbe eine lange Gebäudeliste den Brocken aus dem Bild, und
     genau das war das Kernproblem der alten Anordnung. */
  body { overflow: hidden; }
  #layout {
    display: flex;
    flex-direction: column;
    /* `align-items: start` steht in der Rechner-Regel, damit die Spalten
       oben bündig beginnen. In der gestapelten Ansicht schrumpft es die
       Bereiche aber auf ihre INHALTSBREITE — der Shop stand dann als
       schmale Säule links, halber Bildschirm blieb leer. */
    align-items: stretch;
    padding: 8px 10px calc(var(--tabbar-h, 64px) + 8px);
    gap: 10px;
    min-height: 0;
  }
  #col-clicker { flex: 0 0 auto; min-height: auto; padding: 6px 0 0; }
  #panes {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .pane { max-height: none; overflow: visible; }

  /* Leiste an den unteren Rand — in Daumenreichweite, nicht am oberen
     Bildschirmrand, wo man sie nur mit Umgreifen erreicht. */
  .tabbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 25;
    max-width: none;
    margin: 0;
    gap: 2px;
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
    background: rgba(10, 14, 26, 0.94);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--border);
  }
  /* Auf dem Handy NUR die Symbole.

     Die Wörter kosteten Breite, die vier Reiter nebeneinander schlecht
     vertragen — und sie sagten wenig, was 🏗️ 📈 🎡 ⚔️ nicht auch sagen.
     Der Text bleibt im Markup und wird nur ausgeblendet; die
     Beschriftung für Screenreader steht als `aria-label` am Knopf.
     Dafür dürfen die Symbole deutlich größer werden. */
  .tabbtn {
    flex: 1 1 0;
    max-width: none;
    flex-direction: column;
    gap: 0;
    padding: 4px 2px;
  }
  .tabbtn-text { display: none; }
  .tabbtn-icon { font-size: 26px; }

  .counter-main { font-size: 22px; }
  /* Kleiner als vorher (240 px): Kopfzeile, verankerter Asteroid UND
     Bereichsleiste teilen sich die Höhe — auf einem iPhone SE bliebe
     sonst kaum Platz für den Bereich darunter. */
  #asteroid-wrap { width: min(46vw, 200px); height: min(46vw, 200px); }
  #asteroid { width: min(32vw, 138px); height: min(32vw, 138px); }

  /* Auf dem Handy erscheint der Tooltip per Antippen (siehe Tip.attach)
     und bleibt schmal genug, um nicht den halben Bildschirm zu füllen. */
  .tip { max-width: min(280px, calc(100vw - 24px)); }
}

/* ============================================================
   Multiplayer: Konto, Rangliste, Duelle
   ============================================================ */

.icon-btn.signed-in { border-color: var(--ok); color: var(--ok); }

.modal-wide { width: min(560px, 100%); }
.modal-hint { font-size: 12.5px; color: var(--text-dim); line-height: 1.55; margin-bottom: 14px; }
.subhead {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--text-dim); margin: 18px 0 6px;
}

/* ---------- Formularfelder ---------------------------------- */
.field { display: block; margin-bottom: 12px; }
.field span {
  display: block; margin-bottom: 5px;
  font-size: 12px; color: var(--text-dim);
}
.field input {
  width: 100%;
  padding: 10px 12px;
  background: #070a14;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit;
  /* 16px, nicht 15px. Der Kommentar stand vorher ueber dem Wert 15px
     und beschrieb damit genau den Fehler, den er verhindern wollte:
     Unter 16px zoomt iOS beim Fokussieren hinein. */
  font-size: 16px;
}
.field input:focus { outline: none; border-color: var(--accent); }

/* Betrags-Eingabe: Zahl + Einheit-Dropdown (Wetteinsatz & Geldgeschenk).
   `.field .amount-input` braucht höhere Spezifität als `.field span`, sonst
   bricht die Zeile als Block um statt nebeneinander zu stehen. */
.field .amount-input { display: flex; gap: 6px; align-items: stretch; margin-bottom: 0; }
.amount-input input { flex: 1; width: auto; min-width: 0; }
.amount-unit {
  flex: none;
  padding: 10px 12px;
  background: #070a14;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit;
  font-size: 16px;
}
.amount-unit:focus { outline: none; border-color: var(--accent); }

.auth-error { min-height: 18px; margin-bottom: 8px; font-size: 12.5px; color: var(--danger); }

/* ---------- Spielerliste ------------------------------------ */
.player-list { max-height: 240px; overflow-y: auto; margin-bottom: 10px; }
.player-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%; margin-bottom: 6px; padding: 10px 12px;
  background: var(--bg-row);
  border: 1px solid var(--border); border-radius: 10px;
  color: var(--text); font-family: inherit; font-size: 13.5px;
  text-align: left; cursor: pointer;
}
.player-row:hover:not(:disabled) { background: rgba(45, 58, 95, 0.75); border-color: var(--accent); }
.player-row:disabled { opacity: 0.45; cursor: not-allowed; }
.player-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--text-dim); flex: none;
}
.player-dot.online { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.player-name { flex: 1; font-weight: 600; }
.player-state { font-size: 11.5px; color: var(--text-dim); }

/* ---------- Rangliste --------------------------------------- */
.rank-tabs .tab { font-size: 12px; padding: 7px 4px; }
.ranking-body { min-height: 200px; max-height: 50vh; overflow-y: auto; margin-bottom: 10px; }

.rank-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.rank-table th {
  padding: 6px 8px; text-align: left;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-dim); font-weight: 600;
  border-bottom: 1px solid var(--border);
  cursor: pointer; white-space: nowrap;
}
.rank-table th.num { text-align: right; }
.rank-table th.sorted { color: var(--accent); }
.rank-table th:hover { color: var(--text); }
.rank-table td { padding: 7px 8px; border-bottom: 1px solid rgba(120, 150, 220, 0.07); }
.rank-table tr.me { background: rgba(111, 211, 255, 0.10); }
.rank-table tr.me .rank-name { color: var(--accent); font-weight: 700; }
.rank-pos { width: 34px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.rank-name { font-weight: 600; }

/* Alle drei Werte stehen nebeneinander. Die Spalte, nach der sortiert
   wird, ist hervorgehoben — die anderen bleiben lesbar, treten aber
   zurueck, damit die Tabelle nicht flimmert. */
.rank-value {
  text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap; color: var(--text-dim);
}
.rank-value.sorted { color: var(--gold); font-weight: 700; }

/* ---------- Duell-Leiste ------------------------------------ */
.duel-bar {
  position: fixed;
  left: 50%; transform: translateX(-50%);
  /* `--bar-top` misst js/ui.js aus der tatsächlichen Unterkante der
     Bereichs-Knopfleiste — die kann umbrechen und ist deshalb nicht
     fest vorhersagbar. Vorher lag die Leiste bei 64px genau auf den
     Knöpfen und verdeckte den mittleren. Der Ersatzwert gilt, solange
     die Knopfleiste nicht oben steht. */
  top: calc(var(--bar-top, 64px) + env(safe-area-inset-top));
  z-index: 35;
  display: flex; align-items: center; gap: 22px;
  padding: 12px 26px;
  background: rgba(14, 19, 34, 0.96);
  border: 1px solid var(--duel);
  border-radius: 14px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
}
.duel-side { text-align: center; min-width: 84px; }
.duel-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-dim); margin-bottom: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 110px;
}
.duel-score { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.duel-me .duel-score { color: var(--accent); }
.duel-them .duel-score { color: var(--gold); }

.duel-center { text-align: center; min-width: 96px; }
.duel-timer {
  font-size: 32px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.duel-phase {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.10em;
  color: var(--text-dim); margin-top: 3px;
}
.duel-stake {
  font-size: 11px; color: var(--gold); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.duel-bar.countdown .duel-timer { color: var(--duel); animation: pulse 1s ease-in-out infinite; }
.duel-bar.endgame { border-color: var(--danger); }
.duel-bar.endgame .duel-timer { color: var(--danger); animation: pulse 0.5s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.14); }
}

@media (max-width: 760px) {
  /* Hier stehen die Bereichs-Knöpfe unter dem Asteroiden, nicht oben —
     die Leisten dürfen also wieder dicht unter die Kopfzeile. */
  .duel-bar, .bonus-bar { top: calc(64px + env(safe-area-inset-top)); }
  .duel-bar { gap: 12px; padding: 10px 14px; width: calc(100% - 24px); justify-content: space-between; }
  .duel-side { min-width: 0; }
  .duel-score { font-size: 21px; }
  .duel-timer { font-size: 26px; }
  .duel-label { max-width: 70px; }
}

.auth-success { min-height: 18px; margin-bottom: 8px; font-size: 12.5px; color: var(--ok); line-height: 1.5; }
.field span em { font-style: normal; color: var(--text-dim); opacity: 0.75; font-size: 11px; }
.field-hint { display: block; margin-top: 6px; font-size: 11.5px; line-height: 1.45; color: var(--text-dim); }
.btn-link {
  background: none; border: none; color: var(--text-dim);
  font-size: 12.5px; text-decoration: underline; padding: 4px;
}
.btn-link:hover { color: var(--accent); background: none; }

/* ============================================================
   Anmelde-Schranke
   ============================================================ */

.gate {
  position: fixed;
  inset: 0;
  z-index: 60;                    /* über allem, auch über Duell-Leiste */
  display: grid;
  place-items: center;
  padding: 24px 16px calc(24px + env(safe-area-inset-bottom));
  overflow-y: auto;
  background:
    radial-gradient(ellipse at 50% 0%, rgba(111, 211, 255, 0.10), transparent 60%),
    rgba(5, 8, 16, 0.94);
  backdrop-filter: blur(10px);
}

/* Solange die Schranke steht, ist das Spiel dahinter nicht bedienbar —
   auch nicht per Tastatur oder versehentlichem Tap. */
body.gated #layout,
body.gated #tabbar,
body.gated #topbar .counters,
body.gated #btn-sound-quick,
body.gated #btn-menu { visibility: hidden; }

.gate-inner {
  width: min(400px, 100%);
  margin: auto;
}
.gate-brand {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font-size: 24px; font-weight: 700; letter-spacing: 0.01em;
  margin-bottom: 8px;
}
.gate-mark { color: var(--accent); }
.gate-claim {
  text-align: center; font-size: 13.5px; line-height: 1.6;
  color: var(--text-dim); margin-bottom: 24px;
}
.gate-status { margin-top: 14px; text-align: center; font-size: 12.5px; color: var(--danger); }
/* „Verbinde …" ist kein Fehler — neutral statt alarmrot. */
.gate-status.connecting { color: var(--text-dim); }

/* Die Formulare wandern per JS hierher — deshalb brauchen sie hier
   dieselbe Kartenoptik wie sonst im Dialog. */
#gate-slot > div {
  padding: 22px;
  background: #0e1322;
  border: 1px solid var(--border);
  border-radius: 14px;
}
#gate-slot h2 { font-size: 17px; margin-bottom: 14px; }

/* ---------- Prestige-Fortschritt ---------------------------- */
.prestige-track { margin-bottom: 6px; }
.prestige-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 0.3s ease-out;
}
.prestige-missing {
  font-size: 11px; color: var(--text-dim);
  text-align: right; margin-bottom: 10px;
  font-variant-numeric: tabular-nums;
}
.btn-prestige:disabled {
  opacity: 0.45; cursor: not-allowed;
  border-color: var(--border); background: rgba(255,255,255,0.04);
}
.btn-prestige:disabled:hover { background: rgba(255,255,255,0.04); }

/* ---------- Singularität (seit 4.19) -------------------------
   Sie steht unter dem Wurmloch und sieht ihm ähnlich — es ist dieselbe
   Familie (Progression, also Violett gemäß der Farbsemantik von 2.3.1),
   nur eine Ebene höher. Unterschieden wird über den GOLDENEN Rand der
   Kerne, nicht über eine vierte Farbe: Eine neue Farbe für „noch
   wichtiger" wäre genau die Überladung, die 2.3.1 beseitigt hat. */
.singularity {
  margin-top: 16px;
  padding: 14px;
  border: 1px solid rgba(169, 139, 255, 0.35);
  border-radius: var(--radius);
  background: linear-gradient(160deg, rgba(169, 139, 255, 0.10), rgba(255, 204, 102, 0.05));
}
.singularity-text { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; margin-bottom: 10px; }
.singularity-text strong { color: var(--gold); }
.singularity-have {
  font-size: 11.5px; color: var(--text-dim); margin-bottom: 8px;
}
.singularity-fill {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent-2), var(--gold));
  transition: width 0.3s ease-out;
}
.btn-singularity {
  width: 100%;
  border-color: var(--gold);
  background: rgba(255, 204, 102, 0.14);
  color: var(--gold);
}
.btn-singularity:hover { background: rgba(255, 204, 102, 0.24); }
.btn-singularity:disabled {
  opacity: 0.45; cursor: not-allowed;
  border-color: var(--border); background: rgba(255,255,255,0.04); color: var(--text-dim);
}
.btn-singularity:disabled:hover { background: rgba(255,255,255,0.04); }

/* Die Kern-Käufe. Eine Zeile je Kauf: links was es tut, rechts der
   Preis — dieselbe Anordnung wie im Gebäude-Shop, damit man nicht neu
   lesen lernen muss. */
.core-shop { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.core-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-row);
}
.core-row.core-voll { opacity: 0.6; }
.core-text { flex: 1 1 auto; min-width: 0; }
.core-name { font-size: 13px; font-weight: 600; }
.core-sub { font-size: 11.5px; color: var(--text-dim); line-height: 1.4; }
.btn-core {
  flex: 0 0 auto;
  padding: 6px 12px;
  font-size: 13px;
  border-color: rgba(255, 204, 102, 0.5);
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.btn-core:disabled { opacity: 0.4; cursor: not-allowed; }

/* ---------- Passwortregeln ---------------------------------- */
.pw-rules { list-style: none; margin: -6px 0 12px; padding: 0; }
.pw-rule {
  font-size: 11.5px; line-height: 1.6; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.pw-rule.met { color: var(--ok); }

.code-input {
  text-transform: uppercase; letter-spacing: 0.30em;
  font-family: ui-monospace, Consolas, monospace; font-weight: 700;
}

/* ---------- Einladungscodes --------------------------------- */
.invite-list { max-height: 160px; overflow-y: auto; margin-bottom: 10px; }
.invite-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 8px 12px; margin-bottom: 6px;
  background: var(--bg-row); border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
}
.invite-row:hover { border-color: var(--accent); }
.invite-row.used { opacity: 0.45; }
.invite-code {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 15px; font-weight: 700; letter-spacing: 0.18em; color: var(--gold);
}
.invite-state { font-size: 11.5px; color: var(--text-dim); }

/* ---------- Spielstand-Konflikt ----------------------------- */
.conflict-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.conflict-card {
  padding: 14px; background: var(--bg-row);
  border: 1px solid var(--border); border-radius: 10px;
}
.conflict-card h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent); margin-bottom: 10px;
}
.conflict-card .stats { font-size: 12px; margin-bottom: 12px; }
.conflict-card .btn { width: 100%; }

@media (max-width: 620px) {
  .conflict-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Tooltips — ein gemeinsames Element am <body>.
   Liegt bewusst AUSSERHALB der Panels: Die haben `overflow-y: auto`
   und schneiden alles ab, was über ihren Rand hinausragt.
   ============================================================ */
.tip {
  position: fixed;
  z-index: 70;                 /* über Panels, Duell-Leiste und Overlays */
  max-width: 280px;
  padding: 10px 12px;
  background: #0d1220;
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  pointer-events: none;        /* darf den Mauszeiger nie abfangen */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease-out;
}
.tip.visible { opacity: 1; visibility: visible; }
.tip strong {
  display: block; margin-bottom: 5px;
  font-size: 13px; color: var(--gold);
}
.tip .tip-text {
  font-size: 12.5px; line-height: 1.5; color: var(--text);
  margin: 0 0 6px;
}
.tip .tip-note {
  font-size: 11.5px; line-height: 1.45; color: var(--accent);
  margin: 0; padding-top: 6px;
  border-top: 1px solid rgba(120, 150, 220, 0.12);
}
.tip .tip-text:last-child, .tip .tip-note:last-child { margin-bottom: 0; }

/* Statistikzeilen als erklärbar kennzeichnen */
.stats .has-tip { cursor: help; }
.stats dt.has-tip { text-decoration: underline dotted rgba(139, 151, 181, 0.5); text-underline-offset: 3px; }
.stats dt.has-tip:hover, .stats dd.has-tip:hover { color: var(--accent); }

/* ---------- Konto löschen ----------------------------------- */
.danger-link { color: var(--danger); }
.danger-link:hover { color: var(--danger); }

/* Konto löschen: gleiche Form wie die übrigen Knöpfe, nur in der
   Warnfarbe und zurückhaltend gefüllt — es soll auffindbar sein, aber
   nicht zum Draufdrücken einladen. */
.btn-danger-ghost {
  background: none;
  border-color: rgba(255, 122, 122, 0.4);
  color: var(--danger);
}
.btn-danger-ghost:hover {
  background: rgba(255, 122, 122, 0.12);
  border-color: var(--danger);
}
.delete-box {
  margin-top: 16px; padding: 14px;
  border: 1px solid rgba(255, 122, 122, 0.35);
  border-radius: var(--radius);
  background: rgba(255, 122, 122, 0.07);
}
.delete-box .subhead { color: var(--danger); margin-top: 0; }

/* Gefahrenzone: die Kontolöschung sitzt bewusst abgesetzt unter einem Trenner
   und deutlich entfernt von „Abmelden" — ein gleich großer Knopf direkt daneben
   lud zum Fehlgriff ein. Zurückhaltender, mittiger Textknopf: auffindbar, aber
   nicht zum versehentlichen Drücken einladend. */
.danger-zone {
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  text-align: center;
}
.danger-link { color: var(--text-dim); opacity: 0.7; }
.danger-link:hover { color: var(--danger); opacity: 1; background: none; }

/* Die Löschzone sitzt unter „Schließen" (eigener Wrapper hinter dem geteilten
   Schließen-Knopf) und ist NUR angemeldet sichtbar. Bewusst rein per CSS an
   #account-user gekoppelt statt per eigenem JS-Toggle: so kann kein halb
   aktualisierter Service-Worker (neues HTML, altes JS) sie verschwinden lassen.
   `~` matcht den späteren Geschwister-Wrapper trotz Schließen-Knopf dazwischen. */
#account-danger { display: none; }
#account-user:not(.hidden) ~ #account-danger { display: block; }

/* ============================================================
   Kleine Bildschirme (iPhone 12 mini: 375 × 812 CSS-Pixel)

   Dort war die Kopfzeile überladen: Titel, große Zahl und drei
   Knöpfe nebeneinander haben sich überlagert. Auf schmalen Geräten
   wandert der Zähler deshalb in eine eigene Zeile.
   ============================================================ */
@media (max-width: 430px) {
  #topbar {
    display: grid;
    /* Nur noch zwei Symbole (Ton, Menü): Duell und Konto sind Bereich
       bzw. Menüeintrag geworden. Die Marke wird ausgeschrieben und weicht
       bei Bedarf per Ellipsis, damit die Knöpfe nie herausgedrängt
       werden. */
    grid-template-columns: minmax(0, auto) 1fr auto auto;
    grid-template-areas:
      "brand . sound menu"
      "counter counter counter counter";
    gap: 4px 6px;
    padding: calc(8px + env(safe-area-inset-top)) 12px 8px;
  }
  .brand   { grid-area: brand; font-size: 15px; min-width: 0; }
  .brand-mark { font-size: 15px; }
  /* „Astro Clicker" wieder ausgeschrieben (vorher nur ◆). */
  .brand-name { display: inline; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  #btn-sound-quick { grid-area: sound; }
  #btn-menu    { grid-area: menu; }

  .counters {
    grid-area: counter;
    margin-left: 0;
    text-align: left;
    display: flex; align-items: baseline; gap: 10px;
  }
  .counter-main { font-size: 21px; }
  .counter-unit { font-size: 12px; }
  .counter-rate { font-size: 12px; }

  /* Berührungsflächen auf 44 px. Vorher wurden sie hier KLEINER
     (34 px) — genau falsch herum fuer das Geraet, auf dem am meisten
     mit dem Finger getippt wird. */
  .icon-btn { width: 44px; height: 44px; font-size: 18px; }
  .btn, .tab, .amount, .player-row, .invite-row, .btn-link, .tabbtn {
    min-height: 44px;
  }
  .amount, .tab { display: inline-flex; align-items: center; justify-content: center; }
  .btn-link { display: inline-flex; align-items: center; }
  .rank-table th { padding-top: 12px; padding-bottom: 12px; }

  /* Overlays sind auf kleinen Geräten Vollbild statt zentrierte Karte —
     eine mittig schwebende Karte lässt oben und unten Rand, den man
     dort nicht hat. */
  .overlay { padding: 0; place-items: stretch; }
  .modal, .modal-wide {
    width: 100%; max-width: none;
    min-height: 100%;
    border-radius: 0;
    padding: calc(18px + env(safe-area-inset-top)) 16px
             calc(18px + env(safe-area-inset-bottom));
    overflow-y: auto;
  }

  /* Die Duell-Leiste darf die Kopfzeile nicht überdecken. */
  .duel-bar { top: calc(96px + env(safe-area-inset-top)); }

  /* Der Tooltip wird auf Antippen gezeigt — auf schmalen Geräten soll
     er die Bedienung nicht zustellen. */
  .tip { max-width: calc(100vw - 20px); font-size: 12px; }

  #layout { padding: 10px 10px calc(var(--tabbar-h, 64px) + 8px); gap: 10px; }
  .panel { padding: 12px; }
  #col-clicker { min-height: auto; padding: 4px 0 0; gap: 12px; }
  #asteroid-wrap { width: min(50vw, 190px); height: min(50vw, 190px); }
  #asteroid { width: min(35vw, 131px); height: min(35vw, 131px); }
  #asteroid-info { width: min(300px, 88vw); }

  /* Erfolgsraster: kleinere Kacheln, damit 43 Stück nicht die halbe
     Seite füllen. */
  /* 44 px statt 30 px: Auf 375 px passen damit immer noch sechs
     Kacheln nebeneinander, aber man trifft sie. */
  .ach-grid { grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 5px; }
  .ach { font-size: 16px; }

  /* Im Vollbild-Dialog scrollt schon das Modal — verschachtelte
     Scrollbereiche darin sind auf iOS unzuverlaessig. */
  .ranking-body, .player-list, .invite-list { max-height: none; overflow: visible; }

  .gate { padding: 16px 12px calc(16px + env(safe-area-inset-bottom)); }
  .gate-inner { width: 100%; }
  #gate-slot > div { padding: 18px 14px; }
}

/* Sehr niedrige Geräte im Querformat: Overlays dürfen scrollen.
   `min-height: 100%` machte den Dialog HOEHER und half deshalb nicht —
   gescrollt wird jetzt vom .overlay darueber. */
@media (max-height: 560px) {
  .modal, .modal-wide { min-height: auto; }
  .overlay { padding: 12px; }
  #asteroid-wrap { width: min(30vh, 180px); height: min(30vh, 180px); }
  #asteroid { width: min(21vh, 124px); height: min(21vh, 124px); }
}

/* Fassung im Menü — klein und unaufdringlich, aber ablesbar. */
.menu-version {
  margin-top: 14px;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  opacity: 0.7;
}

/* ---------- Wurmloch-Zündung ---------------------------------
   Ein Sprung, der Stunden Fortschritt kostet, darf sich nicht wie ein
   Formular-Absenden anfühlen. Ablauf: Sog nach innen, greller
   Kollaps, dann steht der Gewinn im Raum. */
.wormhole {
  position: fixed;
  inset: 0;
  z-index: 65;
  display: grid;
  place-items: center;
  pointer-events: none;          /* schluckt keine Klicks */
  background: radial-gradient(circle at 50% 50%,
              rgba(12, 4, 32, 0.92) 0%, rgba(4, 6, 12, 0.86) 45%, rgba(4, 6, 12, 0) 78%);
  animation: whFade 2.4s ease-out forwards;
}
.wormhole > * { grid-area: 1 / 1; }

.wh-disc {
  width: 210px; height: 210px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
              #000 0%, #1a0b3d 34%, #5b2ea8 58%, #b06fe8 74%, rgba(176,111,232,0) 80%);
  animation: whCollapse 2.4s cubic-bezier(0.5, 0, 0.2, 1) forwards;
}
.wh-ring {
  width: 210px; height: 210px;
  border-radius: 50%;
  border: 2px solid rgba(176, 111, 232, 0.85);
  animation: whRing 2.4s ease-out forwards;
}
.wh-ring2 { animation-delay: 0.22s; border-color: rgba(111, 211, 255, 0.75); }

.wh-flash {
  width: 40px; height: 40px;
  border-radius: 50%;
  background: #fff;
  opacity: 0;
  animation: whFlash 2.4s ease-out forwards;
}
.wh-text {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  opacity: 0;
  font-weight: 800;
  color: var(--gold);
  text-shadow: 0 0 18px rgba(240, 190, 90, 0.65);
  animation: whText 2.4s ease-out forwards;
}
.wh-text span { font-size: 40px; line-height: 1; }
.wh-text small { font-size: 12px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--text); }

@keyframes whFade {
  0%   { opacity: 0; }
  8%   { opacity: 1; }
  82%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes whCollapse {
  0%   { transform: scale(0.2) rotate(0deg); opacity: 0; }
  22%  { transform: scale(1.15) rotate(140deg); opacity: 1; }
  52%  { transform: scale(0.9) rotate(400deg); opacity: 1; }
  62%  { transform: scale(0.02) rotate(520deg); opacity: 1; }
  70%  { transform: scale(0.02) rotate(560deg); opacity: 0; }
  100% { transform: scale(0.02); opacity: 0; }
}
@keyframes whRing {
  0%   { transform: scale(1.9); opacity: 0; }
  18%  { opacity: 0.9; }
  60%  { transform: scale(0.06); opacity: 0.6; }
  68%  { transform: scale(0.06); opacity: 0; }
  100% { opacity: 0; }
}
@keyframes whFlash {
  0%, 58% { transform: scale(0.2); opacity: 0; }
  64%     { transform: scale(9); opacity: 0.95; }
  76%     { transform: scale(14); opacity: 0; }
  100%    { opacity: 0; }
}
@keyframes whText {
  0%, 62% { opacity: 0; transform: scale(0.7); }
  72%     { opacity: 1; transform: scale(1.08); }
  80%     { transform: scale(1); }
  90%     { opacity: 1; }
  100%    { opacity: 0; }
}

/* ---------- Bereichsleiste -----------------------------------

   Vier Bereiche, eine Leiste. Auf dem Handy klebt sie am unteren Rand
   (Daumenreichweite), am Rechner steht sie oben unter der Kopfzeile —
   dort ist der untere Bildschirmrand weit weg von den Händen.

   Mindesthöhe 52 px: Die alten Bereichsknöpfe hatten 40 px und lagen
   damit unter der Grenze, ab der ein Daumen zuverlässig trifft. */
.tabbar {
  /* Rechner: normale Leiste oben, direkt unter der Kopfzeile. `order`
     zieht sie im flex-column-Body vor das Spielfeld — im Markup steht
     sie hinter <main>, weil sie auf dem Handy an den unteren Rand
     gehört und die Reihenfolge dort für Screenreader stimmen soll. */
  order: 1;
  display: flex;
  /* Zentriert und in der Breite gedeckelt: Am Anfang ist nur EIN Bereich
     freigeschaltet, und ein einzelner Reiter ueber 1100 px sieht aus wie
     ein Fehler statt wie ein Reiter. */
  justify-content: center;
  gap: 4px;
  max-width: 1100px;
  width: 100%;
  margin: 0 auto;
  padding: 12px 16px 0;
}
.tabbtn {
  flex: 1 1 240px;
  max-width: 260px;
  position: relative;
  min-height: 52px;
  display: flex;
  /* Am Rechner nebeneinander und gross genug zum Lesen; auf dem Handy
     gestapelt, weil vier Reiter nebeneinander sonst umbrechen. */
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 4px 6px;
  font-family: inherit;
  font-size: 14px;
  color: var(--text-dim);
  background: none;
  border: 1px solid transparent;
  border-radius: 10px;
  cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.tabbtn-icon { font-size: 20px; line-height: 1; }
.tabbtn-text { line-height: 1.1; }
.tabbtn:hover { color: var(--text); }
/* Cyan = interaktiv/Auswahl. Der offene Bereich ist genau das. */
.tabbtn.active {
  color: var(--accent);
  background: rgba(111, 211, 255, 0.1);
  border-color: rgba(111, 211, 255, 0.4);
}
.tabbtn.hidden { display: none; }

/* Frisch freigeschaltet: kurz hervorheben, damit der neue Bereich nicht
   unbemerkt in der Leiste auftaucht. */
.tabbtn.frisch { animation: tabFrisch 1.4s ease-in-out 3; }
@keyframes tabFrisch {
  0%, 100% { box-shadow: 0 0 0 0 rgba(111, 211, 255, 0); }
  50%      { box-shadow: 0 0 0 4px rgba(111, 211, 255, 0.28); }
}

/* Ein Dreh liegt bereit — Gold, weil es um eine Belohnung geht. */
.tabbtn.bereit { color: var(--gold); }
.tabbtn.bereit .tabbtn-icon { animation: tabPuls 1.8s ease-in-out infinite; }
@keyframes tabPuls {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.16); }
}
@media (prefers-reduced-motion: reduce) {
  .tabbtn.frisch { animation: none; }
  .tabbtn.bereit .tabbtn-icon { animation: none; }
}

/* Abzeichen (wartende Geschenke, bereitliegende Drehe) sitzen jetzt am
   Reiter ihres Bereichs statt verstreut an Kopfzeilen-Symbolen. */
.tabbtn .dot-badge { top: 2px; right: 50%; margin-right: -22px; }


/* Abgelehnter Kauf: kurzes Wackeln. Ohne Rueckmeldung wirkt ein
   folgenloser Klick wie ein Fehler in der App. */
.shop-row.denied { animation: denyShake 0.4s ease-out; border-color: var(--danger); }
@keyframes denyShake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-5px); }
  45%      { transform: translateX(4px); }
  70%      { transform: translateX(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .shop-row.denied { animation: none; }
}

/* ---------- Installieren -------------------------------------- */
.install-bar {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  /* `--tabbar-h` misst js/ui.js: Auf dem Handy klebt die Bereichsleiste
     am unteren Rand, die Leiste muss darueber ausweichen. Vorher lag sie
     genau auf den Reitern. */
  bottom: calc(var(--tabbar-h, 0px) + 20px + env(safe-area-inset-bottom));
  z-index: 74;                 /* knapp unter der Update-Leiste */
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 8px 9px 16px;
  background: rgba(14, 19, 34, 0.97);
  border: 1px solid var(--accent);
  border-radius: 999px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  max-width: calc(100vw - 24px);
}
.install-text { font-size: 13px; color: var(--text); white-space: nowrap; }
.install-kurz { display: none; }
.install-bar .btn { flex: none; white-space: nowrap; }
.install-x {
  flex: none;
  width: 28px; height: 28px;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 13px;
  cursor: pointer;
}
.install-x:hover { color: var(--text); }

/* Beide Leisten sitzen unten. Liegt ein Update bereit, hat das Vorrang
   — sonst überdecken sie sich. */
.update-bar:not(.hidden) ~ .install-bar { display: none; }

.ios-steps {
  margin: 4px 0 16px;
  padding: 0;
  list-style: none;
  counter-reset: schritt;
}
.ios-steps li {
  position: relative;
  padding: 10px 0 10px 42px;
  font-size: 13.5px;
  line-height: 1.5;
  border-bottom: 1px solid var(--border);
}
.ios-steps li:last-child { border-bottom: none; }
.ios-steps li::before {
  counter-increment: schritt;
  content: counter(schritt);
  position: absolute;
  left: 0;
  top: 10px;
  width: 22px; height: 22px;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 800;
  color: #07121c;
  background: var(--accent);
  border-radius: 50%;
}
.ios-steps small { display: block; color: var(--text-dim); font-size: 12px; margin-top: 2px; }
.ios-step-icon { margin-right: 4px; color: var(--accent); }

@media (max-width: 430px) {
  /* Auf schmalen Geraeten der kurze Text — der lange brach in vier
     Zeilen um und sprengte die runde Pille. */
  .install-lang { display: none; }
  .install-kurz { display: inline; }
  .install-text { font-size: 12px; }
  .install-bar { gap: 8px; padding: 8px 6px 8px 12px; }
}

/* ---------- Update-Hinweis ------------------------------------ */
.update-bar {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--tabbar-h, 0px) + 20px + env(safe-area-inset-bottom));
  z-index: 75;                 /* unter dem Toast, über der Schranke */
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 12px 10px 18px;
  background: rgba(14, 19, 34, 0.97);
  border: 1px solid var(--accent);
  border-radius: 999px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  max-width: calc(100vw - 24px);
}
.update-text { font-size: 13px; color: var(--text); white-space: nowrap; }
.update-bar .btn { flex: none; white-space: nowrap; }

@media (max-width: 430px) {
  .update-bar { gap: 10px; padding: 8px 8px 8px 14px; }
  .update-text { font-size: 12px; }
}

/* ---------- Querformat ----------------------------------------
   Eine echte Orientierungssperre gibt es im Web nicht: `screen
   .orientation.lock()` kennt iOS Safari nicht, und die
   `orientation`-Angabe im Manifest beachtet iOS bei installierten
   Apps ebenfalls nicht. Bleibt der ehrliche Weg — freundlich bitten
   und das Spiel so lange verdecken.

   Bewusst NUR auf Touch-Geräten mit wenig Höhe: Ein Rechnerfenster
   ist immer "Querformat" und darf nicht zugedeckt werden. */
.rotate-hint { display: none; }

@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  .rotate-hint {
    position: fixed;
    inset: 0;
    z-index: 90;
    display: grid;
    place-items: center;
    padding: 20px;
    text-align: center;
    background: rgba(5, 8, 16, 0.97);
    backdrop-filter: blur(10px);
  }
  .rotate-inner { max-width: 380px; }
  .rotate-icon {
    display: block;
    font-size: 44px;
    margin-bottom: 12px;
    animation: rotateNudge 2.4s ease-in-out infinite;
  }
  .rotate-inner strong { display: block; font-size: 17px; margin-bottom: 8px; }
  .rotate-inner p { font-size: 13.5px; color: var(--text-dim); line-height: 1.6; }
}

@keyframes rotateNudge {
  0%, 60%, 100% { transform: rotate(0deg); }
  75%           { transform: rotate(-90deg); }
  90%           { transform: rotate(-90deg); }
}

@media (prefers-reduced-motion: reduce) {
  .rotate-icon { animation: none !important; }
}

/* ---------- Goldener Asteroid --------------------------------- */
.golden-layer {
  position: fixed;
  inset: 0;
  z-index: 45;
  pointer-events: none;      /* nur der Brocken selbst fängt Klicks */
  overflow: hidden;
}

.golden {
  position: absolute;
  width: 72px;
  height: 72px;
  padding: 0;
  border: none;
  border-radius: 46% 54% 52% 48% / 50% 46% 54% 50%;
  cursor: pointer;
  pointer-events: auto;
  background: radial-gradient(circle at 34% 30%,
              #fff3c4 0%, #ffd166 32%, #e0a020 62%, #8a5b0c 100%);
  box-shadow:
    inset -8px -8px 18px rgba(90, 55, 0, 0.6),
    inset 6px 6px 14px rgba(255, 255, 220, 0.5),
    0 0 26px rgba(255, 200, 90, 0.75),
    0 0 60px rgba(255, 180, 60, 0.35);
  animation: goldenDrift 12s linear forwards, goldenSpin 3.6s ease-in-out infinite;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.golden:hover { filter: brightness(1.12); }

/* Die Staubwolke muss sich DEUTLICH unterscheiden — sonst klickt man
   sie im Reflex an und ärgert sich. Grau, matt, ohne Leuchten. */
.golden.dust {
  background: radial-gradient(circle at 40% 34%,
              #8e8b86 0%, #5f5c58 40%, #3a3835 72%, #232120 100%);
  box-shadow:
    inset -8px -8px 18px rgba(0, 0, 0, 0.6),
    0 0 18px rgba(150, 150, 150, 0.25);
  opacity: 0.92;
}

/* Vier Flugbahnen statt einer (seit 4.12). Vorher zog JEDER Komet von
   links nach rechts — nach dem dritten wusste das Auge, wo es hinsehen
   muss, und ein Ereignis, das man erwartet, ist keines mehr. Die
   Richtung wird beim Erscheinen ausgewürfelt (js/mp-ui.js).

   `top`/`left` setzt das Skript passend zur Bahn; die Keyframes
   bewegen nur relativ dazu. */
@keyframes goldenDrift {
  0%   { transform: translateX(-14vw) translateY(0); }
  100% { transform: translateX(114vw) translateY(22px); }
}
@keyframes goldenDriftRL {
  0%   { transform: translateX(14vw) translateY(0); }
  100% { transform: translateX(-114vw) translateY(22px); }
}
@keyframes goldenDriftTD {
  0%   { transform: translateY(-16vh) translateX(0); }
  100% { transform: translateY(116vh) translateX(-18px); }
}
@keyframes goldenDriftDT {
  0%   { transform: translateY(16vh) translateX(0); }
  100% { transform: translateY(-116vh) translateX(18px); }
}
.golden.rl { animation-name: goldenDriftRL, goldenSpin; }
.golden.td { animation-name: goldenDriftTD, goldenSpin; }
.golden.dt { animation-name: goldenDriftDT, goldenSpin; }
@keyframes goldenSpin {
  0%, 100% { border-radius: 46% 54% 52% 48% / 50% 46% 54% 50%; }
  50%      { border-radius: 54% 46% 48% 52% / 46% 54% 48% 52%; }
}

/* ---------- Bonusleiste --------------------------------------- */
.bonus-bar {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  /* Unter der Bereichs-Knopfleiste, siehe .duel-bar. */
  top: calc(var(--bar-top, 64px) + env(safe-area-inset-top));
  z-index: 44;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: rgba(24, 18, 4, 0.92);
  border: 1px solid var(--gold);
  border-radius: 999px;
  box-shadow: 0 0 24px rgba(255, 200, 90, 0.28);
  backdrop-filter: blur(4px);
}
.bonus-bar.malus {
  background: rgba(20, 20, 22, 0.92);
  border-color: #6b6b70;
  box-shadow: none;
}
.bonus-icon { font-size: 18px; }
.bonus-text { display: flex; flex-direction: column; line-height: 1.15; }
.bonus-text strong { font-size: 13px; color: var(--gold); }
.bonus-bar.malus .bonus-text strong { color: #b9bcc4; }
.bonus-text small { font-size: 11px; color: var(--text-dim); }
.bonus-time {
  min-width: 26px;
  text-align: right;
  font-size: 16px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

@media (max-width: 430px) {
  /* Unter die zweizeilige Kopfzeile, wie die Duell-Leiste. */
  .bonus-bar { top: calc(96px + env(safe-area-inset-top)); padding: 6px 12px; }
  .golden { width: 62px; height: 62px; }
}

@media (prefers-reduced-motion: reduce) {
  /* Der Brocken muss anklickbar bleiben — er wandert nur nicht mehr,
     sondern steht ruhig am Rand. */
  .golden {
    animation: none !important;
    left: 8vw;
    top: 42vh;
  }
}

/* ---------- Schenken ------------------------------------------ */
.list-modes { margin-bottom: 12px; }

/* Zähler am Konto-Symbol. Ein Toast verschwindet nach drei Sekunden —
   wer gerade nicht hinsieht, erfährt sonst nie von einem Geschenk. */
.icon-btn { position: relative; }
.dot-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 800;
  line-height: 1;
  color: #07121c;
  background: var(--gold);
  border-radius: 999px;
  box-shadow: 0 0 10px rgba(255, 204, 102, 0.6);
  pointer-events: none;
}

.gift-inbox {
  margin-bottom: 16px;
  padding: 12px;
  border: 1px solid rgba(255, 204, 102, 0.4);
  border-radius: var(--radius);
  background: rgba(255, 204, 102, 0.08);
}
.inbox-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
}
.inbox-row + .inbox-row { border-top: 1px solid var(--border); }
.inbox-what { flex: 1; min-width: 0; font-size: 13px; }
.inbox-row .btn { flex: none; padding: 6px 12px; }

/* Einladungscodes: Kreuz zum Zurückziehen */
.invite-row { cursor: default; }
.invite-code, .invite-state { cursor: pointer; }
.invite-del {
  flex: none;
  width: 28px; height: 28px;
  font-size: 13px;
  border-color: rgba(255, 122, 122, 0.35);
  color: var(--danger);
}
.invite-del:hover:not(:disabled) { border-color: var(--danger); background: rgba(255, 122, 122, 0.12); }
.invite-del:disabled { opacity: 0.25; cursor: not-allowed; }

#gift-building {
  width: 100%;
  padding: 10px 12px;
  background: #070a14;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit;
  font-size: 16px;      /* < 16px lässt iOS beim Fokus hineinzoomen */
}

.gift-book {
  max-height: 50vh;
  max-height: 50dvh;
  overflow-y: auto;
  margin-bottom: 14px;
}
.book-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  gap: 8px;
  align-items: baseline;
  padding: 9px 4px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.book-row:last-child { border-bottom: none; }
.book-when { color: var(--text-dim); font-size: 11.5px; }
.book-who  { color: var(--text); overflow: hidden; text-overflow: ellipsis; }
.book-what { color: var(--gold); font-weight: 600; white-space: nowrap; }
.book-open {
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-dim);
  background: rgba(120, 150, 220, 0.14);
  border-radius: 6px;
}

/* Auf schmalen Geräten bricht die Zeile um, statt zu quetschen. */
@media (max-width: 430px) {
  .book-row { grid-template-columns: 40px 1fr; }
  .book-what { grid-column: 2; }
  .gift-book { max-height: none; overflow: visible; }
}

/* ---------- Bestätigungsdialog ------------------------------- */
.ask-body p {
  font-size: 13.5px;
  color: var(--text-dim);
  line-height: 1.6;
  margin-bottom: 10px;
}
.ask-body p:last-child { margin-bottom: 0; }
#ask-overlay .modal-actions {
  flex-direction: row-reverse;      /* Bestätigen rechts, wie gewohnt */
  margin-top: 18px;
  margin-bottom: 0;
}
#ask-overlay .modal-actions .btn { flex: 1; }

/* ---------- Sichtbarer Fokus --------------------------------
   Ohne das ist die Tastaturbedienung blind: `outline: none` auf den
   Eingabefeldern liess nur einen 1px-Rahmenwechsel uebrig. */
.btn:focus-visible,
.icon-btn:focus-visible,
.tabbtn:focus-visible,
.tab:focus-visible,
.amount:focus-visible,
.shop-row:focus-visible,
.player-row:focus-visible,
.admin-toggle:focus-visible,
.list-mode:focus-visible,
.field input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- Weniger Bewegung --------------------------------
   Dauerlaufendes Sternenfunkeln und ein `brightness(3)`-Blitz beim
   Zerfall sind fuer empfindliche Menschen ein echtes Problem. */
@media (prefers-reduced-motion: reduce) {
  .star { animation: none !important; }
  /* Der Kollaps bleibt, aber ohne Rotation und ohne den grellen Blitz. */
  .wh-flash { display: none; }
  .wh-disc, .wh-ring { animation-duration: 0.9s !important; }
  .duel-timer { animation: none !important; }
  #asteroid, #asteroid.hit, #asteroid.shattering, #asteroid.arriving,
  .debris, .particle, .toast {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* Suchtreffer hervorheben */
.player-name mark {
  background: rgba(111, 211, 255, 0.28);
  color: var(--accent);
  border-radius: 3px;
  padding: 0 1px;
}
.list-hint {
  font-size: 11.5px; color: var(--text-dim);
  text-align: right; margin: -4px 0 8px;
}

/* Rangliste auf schmalen Geraeten: aus jeder Zeile wird eine Karte,
   fuenf Spalten nebeneinander sind auf 375 px nicht lesbar. */
@media (max-width: 560px) {
  .rank-table thead { display: none; }
  .rank-table, .rank-table tbody, .rank-table tr, .rank-table td { display: block; width: 100%; }
  .rank-table tr {
    padding: 8px 10px; margin-bottom: 8px;
    background: var(--bg-row); border: 1px solid var(--border); border-radius: 10px;
    position: relative;
  }
  .rank-table tr.me { border-color: var(--accent); }
  .rank-pos {
    position: absolute; top: 8px; right: 10px;
    width: auto; border: none; padding: 0; font-size: 13px;
  }
  .rank-name { border: none; padding: 0 0 6px; font-size: 14.5px; }
  /* `.rank-table td` weiter oben setzt display:block und ist mit (0,1,1)
     spezifischer als ein blosses `.rank-value` (0,1,0) — deshalb hier
     mit td qualifiziert. Ohne das gewinnt block, der Flex-Abstand
     entfaellt und Beschriftung und Wert kleben aneinander
     ("KLICKS66" statt "KLICKS    66"). */
  .rank-table td.rank-value {
    border: none; padding: 3px 0; text-align: right;
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; font-size: 13px;
  }
  .rank-table td.rank-value::before {
    content: attr(data-label);
    color: var(--text-dim); font-weight: 400; text-transform: uppercase;
    font-size: 10.5px; letter-spacing: 0.06em;
  }
}

/* ============================================================
   Glücksrad — Rad und Aufgaben (der schwebende Knopf ist entfallen:
   das Rad wohnt jetzt im Bereich „Täglich").
   ============================================================ */
/* Das Rad selbst */
.wheel-wrap {
  /* Alles am Rad hängt an EINER Größe.

     Vorher waren 232 px fest verdrahtet — auf dem Handy blieb unter dem
     verankerten Asteroiden nicht genug Höhe, das Rad ragte aus dem
     Bereich heraus. Jetzt richtet es sich nach dem, was tatsächlich da
     ist: nie größer als 232 px, nie breiter als 62 % der Breite und nie
     höher als 30 % der Fensterhöhe. Die Höhe ist hier das entscheidende
     Maß — eng wird es nicht in der Breite.

     Symbole, Nabe und Zeiger rechnen als ANTEIL davon, damit das Rad in
     jeder Größe stimmig bleibt. Die Symbole setzt js/wheel-ui.js per
     calc() auf denselben Wert — sonst klebten sie bei kleinem Rad
     außerhalb der Scheibe. */
  --wheel-size: min(232px, 62vw, 30vh);
  position: relative;
  width: var(--wheel-size);
  height: var(--wheel-size);
  margin: 6px auto 14px;
}
.wheel-disc {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 4px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 0 22px rgba(0, 0, 0, 0.5), 0 6px 22px rgba(0, 0, 0, 0.4);
  will-change: transform;
}
.wheel-label {
  position: absolute;
  top: 50%; left: 50%;
  width: calc(var(--wheel-size) * 0.12);
  height: calc(var(--wheel-size) * 0.12);
  margin: calc(var(--wheel-size) * -0.06) 0 0 calc(var(--wheel-size) * -0.06);
  display: grid; place-items: center;
  font-size: calc(var(--wheel-size) * 0.09);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
  transform-origin: center;
}
.wheel-hub {
  position: absolute; top: 50%; left: 50%;
  width: calc(var(--wheel-size) * 0.17);
  height: calc(var(--wheel-size) * 0.17);
  margin: calc(var(--wheel-size) * -0.085) 0 0 calc(var(--wheel-size) * -0.085);
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(10, 14, 26, 0.95);
  border: 2px solid var(--gold);
  font-size: calc(var(--wheel-size) * 0.082);
  z-index: 2;
}
.wheel-pointer {
  position: absolute;
  top: calc(var(--wheel-size) * -0.06); left: 50%; transform: translateX(-50%);
  color: var(--gold);
  font-size: calc(var(--wheel-size) * 0.112);
  line-height: 1;
  z-index: 3;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6));
}
.wheel-status { text-align: center; color: var(--text-dim); margin: 0 0 12px; }
.btn-spin {
  display: block;
  width: 100%;
  background: linear-gradient(180deg, var(--gold), #e0a93e);
  color: #21160a;
  font-weight: 800;
  letter-spacing: 0.02em;
}
.btn-spin:disabled { opacity: 0.5; filter: grayscale(0.4); cursor: default; }
.wheel-prize {
  text-align: center;
  min-height: 1.2em;
  margin: 12px 0 4px;
  font-weight: 700;
  color: var(--gold);
}

/* Tagesaufgaben */
.wheel-tasks { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 14px; }
.wheel-tasks h3 { margin: 0 0 10px; font-size: 15px; }
.task-list { display: flex; flex-direction: column; gap: 10px; }
.task-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "head count" "bar bar";
  gap: 4px 8px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-row);
}
.task-row.done { border-color: rgba(126, 224, 138, 0.5); background: rgba(126, 224, 138, 0.08); }
.task-head { grid-area: head; font-size: 13.5px; }
.task-count { grid-area: count; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.task-bar { grid-area: bar; height: 6px; border-radius: 999px; background: rgba(0, 0, 0, 0.35); overflow: hidden; }
.task-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width 0.4s ease; }
.task-row.done .task-fill { background: var(--ok); }

/* Trenner zwischen Rangliste und dem Mitspieler-Block (Duelle/Geschenke),
   die aus dem Konto-Overlay hierher gezogen sind. */
.social-sep { border-top: 1px solid var(--border); margin: 20px 0 16px; }

/* „Deine Register" in einer Zeile: Duell-Bilanz links, Geschenkbuch-Link
   rechts. Hält das Geschenkbuch oben im Social-Kontext — als de-emphasierter
   Link statt Vollknopf — und damit weg vom Schließen-Knopf ganz unten. */
.social-records {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.social-records .modal-hint { margin-bottom: 0; }
.social-records .btn-link { flex: none; white-space: nowrap; }

/* Admin-Panel: Code-Berechtigungen je Spieler. */
.admin-users { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.admin-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-row);
}
.admin-name { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-tag { font-size: 12px; color: var(--accent-2); font-weight: 700; white-space: nowrap; }
.admin-tag.warn { color: var(--gold); }

/* ---------- Verkauf (seit 4.11) -------------------------------
   Ein Knopf, ein Satz. Der Schritt zwischen Fördern und Kaufen soll
   auffallen, aber den Brocken nicht verdrängen. */
.verkauf { display: flex; flex-direction: column; align-items: center; gap: 4px; }
/* Der Ausbau ist die leisere der beiden Entscheidungen — er konkurriert
   mit dem Maschinenkauf und soll nicht lauter sein als der Verkauf. */
/* Der Lagerausbau sitzt jetzt im Shop, ueber den Gebaeudezeilen. */
.btn-lager { width: 100%; margin-bottom: 8px; padding: 8px 14px; font-size: 13px; }

/* Zugeklappte Sammlung: Der Kopf soll wie eine Ueberschrift wirken, nicht
   wie ein Knopf — es ist Lesestoff, kein Angebot. */
.sammlung { margin-top: 14px; }
.sammlung summary {
  cursor: pointer;
  padding: 8px 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-dim);
}
.sammlung[open] summary { color: var(--text); }
.btn-sell {
  padding: 8px 18px;
  font-size: 14px;
  border-color: rgba(255, 204, 102, 0.5);
  color: var(--gold);
}
.btn-sell:disabled { opacity: 0.45; }
/* Ab 80 % Füllstand: Der Knopf drängt, bevor die Förderung steht. */
.btn-sell.dringend {
  border-color: var(--gold);
  background: rgba(255, 204, 102, 0.14);
  animation: sellPuls 1.6s ease-in-out infinite;
}
@keyframes sellPuls {
  0%, 100% { box-shadow: 0 0 0 rgba(255, 204, 102, 0); }
  50%      { box-shadow: 0 0 14px rgba(255, 204, 102, 0.45); }
}
.verkauf-hint { font-size: 12px; color: var(--text-dim); margin: 0; min-height: 1em; }

/* Lagerstand, dauerhaft (seit 4.18).

   Balken und Zahl in EINER Zeile: Der Balken beantwortet „wie voll?" auf
   einen Blick, die Zahl sagt, worüber wir reden. Die Farben lesen sich
   wie die Reserveleiste am Brocken — grün = Luft, gold = es drängt, rot =
   die Förderung steht. Vorher stand der Füllstand erst ab 80 % als
   Warntext da; bis dahin war der wichtigste Grenzwert des Spiels
   unsichtbar. */
.lager-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  width: min(280px, 78vw);
  margin-bottom: 2px;
}
.lager-track { flex: 1 1 auto; height: 5px; }
.lager-fill {
  height: 100%;
  width: 0;
  background: var(--ok);
  transition: width 0.25s ease-out, background-color 0.3s;
}
.lager-fill.mittel { background: var(--gold); }
.lager-fill.voll   { background: var(--danger); }
.lager-text {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* Der Erzkurs (seit 4.15). Gedämpft wie der Lagerhinweis — er ist
   Begleitinformation, keine Handlungsaufforderung. Farbe nur bei
   Abweichung: Gold heisst „guter Moment", Koralle „gerade schlecht".
   Im Normalfall bleibt die Zeile grau, sonst stumpft die Farbe ab. */
.markt-zeile {
  font-size: 12px;
  color: var(--text-dim);
  margin: 2px 0 0;
  font-variant-numeric: tabular-nums;
}
.markt-zeile.markt-hoch { color: var(--gold); }
.markt-zeile.markt-tief { color: var(--duel); }

/* Erz kaufen (seit 4.16). Cyan = interaktiv/Gelegenheit, NICHT Gold:
   Gold gehoert der Waehrung und dem Verkaufsknopf. Zwei goldene
   Knoepfe uebereinander waeren zwei gleich aussehende Angebote mit
   entgegengesetzter Wirkung. */
.btn-buy {
  padding: 6px 16px;
  font-size: 13px;
  margin-top: 4px;
  border-color: rgba(94, 234, 212, 0.5);
  color: var(--accent);
}
.btn-buy:disabled { opacity: 0.45; }

/* Stabilitäts-Warnung im Wurmloch-Kasten. Golden, nicht rot: Es ist ein
   Wagnis, kein Fehler. */
.prestige-stab {
  margin: 6px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--gold);
}

/* Einheiten-Tafel im Menü. Zugeklappt, weil man sie ein-, zweimal
   braucht und danach nie wieder. */
.menu-einheiten { margin: 4px 0 12px; text-align: left; }
.menu-einheiten summary {
  cursor: pointer;
  padding: 8px 0;
  color: var(--accent);
  font-size: 14px;
}
.einheiten-tafel { width: 100%; border-collapse: collapse; margin: 6px 0 8px; }
.einheiten-tafel th, .einheiten-tafel td {
  padding: 3px 6px;
  font-size: 12.5px;
  text-align: left;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.einheiten-tafel th { color: var(--text-dim); font-weight: 600; }
.einheiten-tafel td:first-child { color: var(--gold); font-weight: 700; width: 3.5em; }
.einheiten-tafel td:last-child { color: var(--text-dim); text-align: right; }

/* Erklärungs-ⓘ in Shop-Zeilen (seit 4.8.1).

   Vorher trug die ganze Zeile den Tooltip. Ein Tipp KAUFT dort aber —
   also klappte bei jedem Kauf die Erklärung auf und beim nächsten wieder
   zu. Zwei Bedeutungen auf einer Fläche; jetzt hat das Nachlesen einen
   eigenen kleinen Ort. Bewusst zurückhaltend gefärbt: Gekauft wird
   öfter als nachgelesen. */
.row-info {
  align-self: center;
  flex: none;
  margin-left: 6px;
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-dim);
  font-size: 15px;
  line-height: 1;
  cursor: help;
}
.row-info:hover, .row-info:focus-visible { color: var(--accent); }

/* ---------- Gebäude-Stufen (seit 4.6) -------------------------
   Ein schmaler Knopf am rechten Rand der Gebäudezeile. Gedämpft,
   solange er nicht bezahlbar ist — er soll die Zeile nicht dominieren,
   der Kauf bleibt die Hauptsache. */
.row-level {
  align-self: center;
  margin-left: 8px;
  padding: 4px 8px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-dim);
  cursor: pointer;
}
.row-level.bereit { color: var(--gold); border-color: rgba(255, 204, 102, 0.55); }
.row-level:disabled { opacity: 0.45; cursor: default; }
.shop-row { cursor: pointer; }
.shop-row .row-main, .shop-row .row-side { cursor: pointer; }

/* ---------- Saison (seit 4.8) ---------------------------------
   Ein farbiger Streifen im Bereich „Fortschritt" und ein Hauch der
   Saisonfarbe im Sternenhimmel. Bewusst zurückhaltend: Das Spiel soll
   im Dezember weihnachtlich WIRKEN, nicht wie eine andere App aussehen. */
.saison-box {
  margin: 0 0 10px;
  padding: 8px 12px;
  border-radius: 10px;
  border: 1px solid var(--saison, var(--border));
  background: rgba(255, 255, 255, 0.04);
  font-size: 13px;
}
body[data-saison]:not([data-saison=""]) #starfield {
  box-shadow: inset 0 0 220px color-mix(in srgb, var(--saison) 22%, transparent);
}

/* ---------- Clan ---------------------------------------------- */
.clan-box { margin-bottom: 14px; }
.clan-kopf { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.clan-mission {
  margin: 8px 0 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.03);
}
.clan-mission-titel { font-weight: 700; margin-bottom: 2px; }
.clan-mission .reserve-track { margin: 6px 0 4px; }
/* Geschafft: derselbe Grünton wie erfüllte Tagesaufgaben — der Balken
   soll ohne Text sagen, dass es steht. */
.prestige-fill.done { background: var(--accent-2); }
.clan-aktionen { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 8px; }
.clan-box .player-row { display: flex; align-items: center; gap: 8px; }
.clan-box .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--border); flex: none;
}
.clan-box .dot.on { background: var(--accent-2); }
.admin-toggle {
  flex: 0 0 auto;
  border: 1px solid var(--border); background: none; color: var(--text-dim);
  border-radius: 999px; padding: 6px 14px; font-size: 12px; font-family: inherit;
  cursor: pointer; transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.admin-toggle.on { border-color: var(--ok); color: var(--ok); background: rgba(126, 224, 138, 0.08); }
.admin-toggle:disabled { opacity: 0.5; cursor: default; }

/* ============================================================
   Erst-Einführung — drei Schritte beim allerersten Start.
   ============================================================ */
.modal-intro { text-align: center; max-width: 420px; }
.intro-icon {
  font-size: 44px;
  line-height: 1;
  margin-bottom: 10px;
}
.modal-intro h2 { margin-bottom: 8px; }
.intro-text {
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.6;
  margin-bottom: 16px;
}
/* „Was ist neu?" (seit 4.20). Linksbündig, obwohl der Dialog sonst
   mittig ist: Es ist eine Liste zum Lesen, kein Begrüßungsbild. */
.news-body { text-align: left; margin-bottom: 16px; }
.news-head {
  font-size: 14px;
  font-weight: 700;
  color: var(--accent);
  margin: 12px 0 4px;
}
.news-head:first-child { margin-top: 0; }
.news-list {
  margin: 0;
  padding-left: 18px;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.55;
}
.news-list li { margin-bottom: 5px; }

.intro-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-bottom: 6px;
}
.intro-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  transition: background 0.2s, transform 0.2s;
}
.intro-dot.active { background: var(--accent); transform: scale(1.25); }

/* ---------- Duell per Code -----------------------------------
   Zwei Spalten: links erzeugen, rechts einlösen. Auf schmalen Geräten
   untereinander — nebeneinander wären beide Eingabefelder zu schmal
   zum Tippen. */
.code-duell {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  align-items: start;
  margin-bottom: 4px;
}
.code-duell-spalte { min-width: 0; }
.code-duell .btn { width: 100%; }
.code-duell-code {
  margin-top: 8px;
  padding: 8px 10px;
  border: 1px dashed rgba(255, 122, 92, 0.5);   /* Koralle = Wettkampf */
  border-radius: 8px;
  text-align: center;
  line-height: 1.5;
}
.code-duell-code strong {
  display: block;
  font-size: 22px;
  letter-spacing: 0.22em;
  color: var(--duel);
  font-variant-numeric: tabular-nums;
}
.code-duell-code small { color: var(--text-dim); font-size: 11.5px; }

@media (max-width: 620px) {
  .code-duell { grid-template-columns: 1fr; gap: 6px; }
}

/* Das Rad auf dem Handy: Es teilt sich die Höhe mit Kopfzeile,
   verankertem Asteroiden und der Bereichsleiste — es bleibt deutlich
   weniger übrig als die 30 % des Fensters, die am Rechner passen. 20 %
   lassen Platz für Status, Drehen-Knopf und die Tagesaufgaben, ohne dass
   man scrollen muss, um den Knopf zu erreichen.

   Steht bewusst HIER am Ende und nicht im großen 760px-Block weiter
   oben: Der liegt in der Datei VOR der Rad-Definition, und bei gleicher
   Spezifität gewinnt die spätere Regel — die mobile Größe wäre dort
   wirkungslos überschrieben worden. */
@media (max-width: 760px) {
  .wheel-wrap { --wheel-size: min(232px, 58vw, 20vh); margin: 2px auto 10px; }
  .wheel-status { margin-bottom: 8px; }
  .wheel-prize { margin: 8px 0 2px; }
  .wheel-tasks .subhead { margin-top: 10px; }
}

/* Sehr niedrige Fenster (iPhone SE und Konsorten, ~568 px hoch).

   Dort teilen sich Kopfzeile, Asteroid, Bereich und Leiste eine Höhe, die
   kaum für eins davon reicht. Der Asteroid gibt etwas ab, das Rad wird
   noch kleiner — sonst liegt der Drehen-Knopf unterhalb des sichtbaren
   Bereichs und man muss blind scrollen, um überhaupt drehen zu können. */
/* Hoehenschwelle 840 statt 700: Auf dem iPhone ist `innerHeight` 812 —
   Notch und Home-Indikator gehen ueber env() ab, nicht ueber die
   Fensterhoehe. Die Regel feuerte damit ausgerechnet dort nicht, wo sie
   gebraucht wird, und der Brocken blieb bei 188 px. */
@media (max-width: 760px) and (max-height: 840px) {
  #asteroid-wrap { width: min(34vw, 130px); height: min(34vw, 130px); }
  #asteroid { width: min(24vw, 92px); height: min(24vw, 92px); }
  .wheel-wrap { --wheel-size: min(232px, 52vw, 17vh); margin: 0 auto 8px; }
  .wheel-status { margin-bottom: 6px; font-size: 12px; }
  .next-step { font-size: 12px; }
}

/* Letzte 40 Pixel für die kleinsten Geräte.

   Gemessen auf 320 × 568: sichtbarer Bereich 182 px, Inhalt bis zum
   Drehen-Knopf 176 px plus Ränder — es fehlte genau eine Handbreit. Statt
   das Rad weiter zu schrumpfen (es wäre kaum noch zu erkennen) fällt
   weg, was doppelt da ist: Die Überschrift „Glücksrad" steht bereits am
   aktiven Reiter, und die Gewinnzeile braucht keine Vorhaltehöhe. */
/* Hoehenschwelle 840 statt 700: Auf dem iPhone ist `innerHeight` 812 —
   Notch und Home-Indikator gehen ueber env() ab, nicht ueber die
   Fensterhoehe. Die Regel feuerte damit ausgerechnet dort nicht, wo sie
   gebraucht wird, und der Brocken blieb bei 188 px. */
@media (max-width: 760px) and (max-height: 840px) {
  #pane-taeglich .panel-title { display: none; }
  #pane-taeglich.pane { padding: 10px; }
  .wheel-prize { min-height: 0; margin: 6px 0 0; }
}


/* ============================================================
   Rechner-Ansicht (seit 4.7): Seitenleiste + zwei Bereiche

   Bis hierher war das Fenster am Rechner nur ein sehr breites Handy:
   eine Reiterleiste quer oben, darunter EIN Bereich — und rechts
   daneben viel leerer Raum. Ab 1100 px wandert die Leiste an die linke
   Seite (senkrecht, mit Beschriftung, weil dort Platz ist) und der
   Bereich teilt sich in zwei Spalten: links dauerhaft der Shop, rechts
   der gewählte Bereich (js/tabs.js entscheidet, welcher).

   Steht ganz am Dateiende, weil eine Medienabfrage bei gleicher
   Spezifität nur gewinnt, wenn sie SPÄTER kommt — dieselbe Falle wie
   beim Glücksrad in 3.2.1.
   ============================================================ */
@media (min-width: 1100px) {
  body { flex-direction: row; flex-wrap: wrap; }

  #topbar { width: 100%; order: 0; }

  .tabbar {
    order: 1;
    flex-direction: column;
    justify-content: flex-start;
    width: 190px;
    max-width: 190px;
    margin: 0;
    padding: 16px 10px;
    gap: 8px;
    align-self: stretch;
  }
  .tabbtn {
    flex: 0 0 auto;
    max-width: none;
    width: 100%;
    justify-content: flex-start;
    gap: 10px;
    padding: 0 14px;
  }
  /* Am Rechner ist Platz für Worte — auf dem Handy stehen nur Symbole. */
  .tabbtn-text { display: inline; }

  #layout {
    order: 2;
    flex: 1;
    /* Asteroid schmaler halten: Der Platz gehört jetzt den zwei
       Bereichen daneben. */
    grid-template-columns: minmax(260px, 320px) minmax(0, 1fr);
  }

  /* Zwei Bereiche nebeneinander. Der zweite erscheint nur, wenn
     tabs.js ihn eingeblendet hat — sonst nimmt der erste die Breite. */
  #panes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
    align-items: start;
  }
  #panes:has(.pane-zweit) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* Der Partner-Bereich steht links, der gewählte rechts — so bleibt
     der Shop dort, wo er beim Umschalten schon war. */
  .pane-zweit { order: -1; }
}

/* Auf dem Handy klebte die Kurzmeldung ueber dem Bereich — gemessen
   verdeckten Toast und Installationsleiste zusammen 83 % des sichtbaren
   Shops. Jetzt erscheint sie ueber dem Brocken: Dort ist Platz, und der
   Blick ist beim Klicken ohnehin dort. */
@media (max-width: 760px) {
  #toast { top: calc(env(safe-area-inset-top) + 96px); bottom: auto; }
}


/* ============================================================
   Vollflaechige Bereiche auf dem Handy (seit 4.17)

   Bis 4.16 lagen Brocken und Bereich untereinander: Der Brocken blieb
   immer sichtbar, dafuer quetschten sich Shop und Gluecksrad in die
   untere Haelfte und mussten vertikal scrollen. Auf 182 px sichtbarer
   Flaeche ist das kein Bereich, sondern ein Schlitz.

   Jetzt gehoert der Erstbildschirm dem Brocken, und ein angetippter
   Reiter faehrt ueber ihn. Das kehrt die Entscheidung von 3.0.0
   ("der Asteroid ist verankert") bewusst um: Bauen und Rad sind
   Pausen-Taetigkeiten, kein Takt. Im DUELL bleibt der Brocken sichtbar
   — dort zaehlt jeder Klick (siehe tabs.js, imDuell).

   Am Rechner (>= 1100 px) aendert sich nichts: Dort stehen zwei
   Bereiche fest nebeneinander und haben Platz.
   ============================================================ */
@media (max-width: 1099px) {
  body.bereich-offen #col-clicker { display: none; }

  body.bereich-offen #panes {
    position: fixed;
    top: var(--topbar-h, 56px);
    left: 0;
    right: 0;
    bottom: var(--tabbar-h, 60px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--bg, #070a14);
    z-index: 40;
    padding: 0 12px 16px;
  }

  /* Der Schliessen-Knopf liegt ueber dem Bereich und bleibt stehen —
     ein vollflaechiger Bereich ohne sichtbaren Ausweg ist eine
     Sackgasse. Rechts oben, weil der Daumen dort nichts verdeckt. */
  .pane-close {
    position: fixed;
    top: calc(var(--topbar-h, 56px) + 6px);
    right: 10px;
    z-index: 42;
    padding: 6px 12px;
    font-size: 13px;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 999px;
    background: rgba(10, 14, 26, 0.92);
    color: var(--text, #e8ecf8);
    backdrop-filter: blur(6px);
  }
  body.bereich-offen #panes { padding-top: 44px; }

  /* Solange ein Dialog offen ist, tritt der Schliessen-Knopf beiseite.

     Er liegt auf z-index 42 und damit ueber jedem `.overlay` (40) — im
     Betrieb stand er quer ueber dem Text der Singularitaets-Abfrage.
     Schlimmer als das Aussehen war die Bedienung: Er war durch den
     Dialog hindurch anklickbar und haette den Bereich hinter der Frage
     zugeklappt, waehrend die Frage noch offen stand.

     Ueber `:has()` statt ueber eine Klasse aus JavaScript, damit es fuer
     JEDEN Dialog gilt — auch fuer die, die es noch nicht gibt (dieselbe
     Ueberlegung wie bei `#panes:has(.pane-zweit)`). */
  body:has(.overlay:not(.hidden)) .pane-close { display: none; }
}

/* Am Rechner gibt es nichts zuzuklappen. */
@media (min-width: 1100px) {
  .pane-close { display: none !important; }
}


/* ============================================================
   Erstbildschirm in drei Zonen (seit 4.18)

   4.17 hat den Erstbildschirm dem Brocken gegeben — er sah nur noch
   nicht danach aus: Der Stein hing oben unter der Kopfzeile, darunter
   Beschriftung, Verkauf und viel Leere, weil der leere Bereichs-Kasten
   die restliche Höhe fraß.

   Jetzt: OBEN die Angaben zum Brocken, MITTE der Brocken (er nimmt sich
   allen Platz, den Kopf- und Fußzone übrig lassen), UNTEN Verkauf,
   „Was jetzt?" und die Wurmloch-Zeile.

   Die gezeichnete Größe des Steins steht in `--asteroid-size` und wird
   von js/ui.js aus dem gemessenen Feld gerechnet — dieselbe Lehre wie
   bei `--topbar-h`/`--tabbar-h`: messen, nicht raten. Reines CSS könnte
   „das Kleinere aus Feldbreite und Feldhöhe" nicht ausdrücken, denn
   `min()` mischt keine Prozentwerte zweier Achsen.

   Steht am Dateiende, weil eine Medienabfrage bei gleicher Spezifität
   nur gewinnt, wenn sie SPÄTER kommt (die Falle aus 3.2.1).
   ============================================================ */
@media (max-width: 760px) {
  #col-clicker {
    /* Der leere Bereichs-Kasten bekam bisher die ganze Resthöhe
       (`#panes { flex: 1 }`), obwohl darin nichts steht, solange kein
       Reiter offen ist. Ab jetzt gehört sie dem Brocken. */
    flex: 1 1 auto;
    min-height: 0;
    justify-content: flex-start;
    gap: 10px;
    padding: 4px 0 0;
  }
  #panes { flex: 0 0 auto; }

  #asteroid-wrap {
    flex: 1 1 0;
    /* Unter dieser Höhe ist der Brocken kein Ziel mehr, sondern ein
       Knopf — dann darf die Fußzone lieber überstehen. */
    min-height: 92px;
    width: 100%;
    height: auto;
  }
  #asteroid {
    width: var(--asteroid-size, 130px);
    height: var(--asteroid-size, 130px);
  }
}
