:root {
  color-scheme: dark;
  /* Navy and teal separate the stage from the bright stones; gold and coral highlight rewards. Every pair below is checked for contrast by qa/syntax-surge.mjs. */
  --ink: #f4fbff; --muted: #b7ccd9; --cyan: #7ce9ff; --gold: #ffd77a; --pink: #ff8ae8; --green: #6ff0bd; --violet: #bb9dff; --red: #ff7183;
  --line: #ffffff26; --panel: #173747; --panel-2: #234857; --glass: #153645c0; --void: #000000;
  /* 🚨 DIE SICHEREN RÄNDER STEHEN EINMAL HIER — und quer sind es die SEITEN, nicht oben und unten.
     Gemeldet: „Landscape am Handy und Insets werden ignoriert." Beim Kippen wandert die Aussparung an den
     linken oder rechten Rand; `env(safe-area-inset-left/right)` war nirgends benutzt, also lag der Text
     eines bildschirmfüllenden Blatts unter der Kamera. Über Variablen, weil `env()` in jeder Regel neu
     ausgeschrieben unweigerlich irgendwo vergessen wird — und weil eine Prüfung sie so überschreiben und
     nachmessen kann. */
  --sa-oben: env(safe-area-inset-top,0px); --sa-rechts: env(safe-area-inset-right,0px);
  --sa-unten: env(safe-area-inset-bottom,0px); --sa-links: env(safe-area-inset-left,0px);
  font-family: ui-rounded, "Trebuchet MS", system-ui, sans-serif;
}
* { box-sizing: border-box; }
/* ONE edge colour for the whole app, exactly like KelRaid (#070b16), Kellerkind (#04070d) and Odyssee (#0d1420):
   the same value is the meta theme-color, both manifest colours and the html/body ground. Whatever iOS paints
   itself at the screen edges (status-bar band at cold start, launch backdrop) then equals the page and never
   shows as a seam. Set on html AND body so the canvas is painted even before body lays out. */
html, body { width: 100%; height: 100dvh; overflow: hidden; overscroll-behavior: none; background: var(--void); }
/* The topmost colour is flat and equals theme-color, so Safari's tinted status bar and the page meet without a seam;
   the glows start below the notch. In standalone the page itself paints under the status bar. */
body { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; background:
    /* Front layer: the top strip stays exactly --void, so the page continues the iOS band without a step. */
    linear-gradient(180deg,var(--void) 0,var(--void) 68px,rgba(12,10,26,0) 200px),
    radial-gradient(70% 55% at 15% 48%,#216b7980,transparent 60%),
    radial-gradient(58% 48% at 88% 88%,#204b68,transparent 60%),
    radial-gradient(52% 38% at 80% 34%,#286b6855,transparent 65%),
    linear-gradient(#0d1424 0,#0f2f40 38%,#103444 56%,#081e2e 100%) no-repeat var(--void);
  color: var(--ink); }
.ambient { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; opacity: 0; transition: opacity .8s ease; }
.ambient[hidden] { display: none; }
/* 🚨 AUCH IM SPIEL. Der Sternenhimmel der Welt liegt hinter dem Brett (`.shell` ist durchsichtig,
   z-index 1 über dieser Leinwand). Dort steht er still — siehe `ambientSync()`. Damit ist die
   Leinwand auf allen vier Bildschirmen sichtbar und der Überblendung bleibt nichts zu tun; sie
   bleibt nur stehen, falls je ein Bildschirm ohne Himmel dazukommt. */
body[data-screen="menu"] .ambient, body[data-screen="progress"] .ambient, body[data-screen="leaderboard"] .ambient, body[data-screen="game"] .ambient { opacity: 1; }
button, input { font: inherit; }
input, textarea, .selectable { user-select: text; -webkit-user-select: text; }
button, a { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
button { cursor: pointer; color: inherit; border: 1px solid var(--line); transition: transform .15s ease, box-shadow .2s ease, filter .2s ease; }
button:active { transform: translateY(1px); }
button:focus-visible, a:focus-visible, input:focus-visible, summary:focus-visible { outline: 3px solid var(--cyan); outline-offset: -3px; }
/* 🚨 `summary` FEHLTE HIER — und Safari zeichnet dort seinen eigenen, dicken blauen Ring. `showModal()` setzt den
   Fokus auf das erste fokussierbare Element im Blatt; in den Spielregeln war das ein Aufklapp-Titel, der stand
   dann blau umrandet mitten im Text. Gemeldet: „Das sieht auch noch nicht gut aus." Jetzt trägt auch er den
   Ring des Spiels, und nur bei Tastaturbedienung. */
summary:focus:not(:focus-visible) { outline: none; }
/* The board is focused by script on every tap, and Safari paints :focus-visible for script focus. The ring is
   for keyboard players only, so the body flags keyboard use and a pointer clears it again. */
#board:focus { outline: 0; }
button:disabled { cursor: default; opacity: .45; }
svg { fill: none; flex: 0 0 auto; }
[hidden] { display: none !important; }
.shell {
  /* Pinned to all four screen edges like the Kellerkind/KelRaid shells: no vh/dvh math, the fixed box tracks
     Safari's collapsing toolbars by itself. Safe areas pad only the controls; the background is the page. */
  position: fixed; inset: 0; z-index: 1; width: 100%;
  padding: var(--sa-oben) var(--sa-rechts) var(--sa-unten) var(--sa-links);
  display: flex; flex-direction: column; overflow: hidden;
}
.top { flex: 0 0 52px; min-height: 0; display: flex; align-items: center; justify-content: space-between; padding: 0 16px; gap: 8px; }
/* 🚨 DIE KOPFLEISTE ZEIGT SICH NUR, WENN SIE ETWAS ZU SAGEN HAT. Gemeldet: „wieso gibt es oben links
   nochmal so ein icon?!?" — dort stand das App-Icon als Weg zurück ins Menü. Im Spiel ist das doppelt
   gemoppelt: Nova sitzt schon in der Kopfzeile des Bretts, und der Weg zurück läuft über die Pause. Auf
   den Listenseiten macht es der Zurück-Knopf. Das Icon ist deshalb weg — und damit bleibt in Menü und
   Spiel eine leere Leiste übrig, die nur Platz frisst. Also weg mit ihr: Im Spiel sind das 52 px mehr
   für das Brett. */
body[data-screen="menu"] .top, body[data-screen="game"] .top { display: none; }.top-spacer { flex: 1; }
/* 🚨 RUND HEISST RUND. `border-radius: 50%` auf einem Kasten, der nicht quadratisch ist, ergibt eine Ellipse —
   und genau das passierte zweimal: quer bekam JEDER runde Knopf 44×36 (die Regel war für die Kopfleiste
   gedacht und traf auch das Schließen-Kreuz in jedem Blatt), und in einer schmalen Kopfzeile drückte der
   Flex-Kasten ihn auf 36×44 zusammen. `flex: none` hält ihn, `aspect-ratio` fängt jede künftige Höhenangabe
   ab, ohne dass man daran denken muss. */
.round-button { flex: none; width: 44px; height: 44px; aspect-ratio: 1; border-radius: 50%; background: #ffffff10; display: grid; place-items: center; color: white; }
/* 🚨 HOVER NUR, WO ES HOVER GIBT. Gemeldet vom iPhone: Nach einem Tipp auf „Einstellungen" blieb eine
   Umrandung stehen. Safari auf iOS setzt `:hover` beim Tippen und LÄSST ES STEHEN, bis woanders hingetippt
   wird — jeder Hover-Effekt wird so zu einem Rest, der nach dem Tippen hängen bleibt (weiße Schrift, hellerer
   Grund, angehobene Karte). Darum steht jede `:hover`-Regel in `@media(hover:hover)`, und zwar AN IHRER
   STELLE: Eine Media-Query ändert die Spezifität nicht, nach unten verschoben würde sie aber gegen
   `.pressed` gewinnen, das bei gleicher Spezifität nur deshalb siegt, weil es später steht.
   `qa/polaris-haptik.mjs` besteht darauf, dass keine Hover-Regel mehr frei steht. */
@media(hover:hover) { .round-button:hover { background: #ffffff22; } }
.screen { display: none; flex: 1 1 0; min-height: 0; min-width: 0; animation: screenIn .28s ease-out; }
@keyframes screenIn { from { opacity: 0; } }
body.reduced .screen { animation: none; }
body[data-screen="menu"] #menu { display: flex; }
body[data-screen="game"] #game { display: grid; }
body[data-screen="nova-egg"] #nova-egg { display: flex; }
body[data-screen="nova-egg"] .top { display: none; }
body[data-screen="progress"] #progress-screen, body[data-screen="leaderboard"] #leaderboard-screen { display: flex; }
.eyebrow { font-size: 10px; font-weight: 800; letter-spacing: .16em; color: var(--cyan); margin: 0; display: inline-flex; align-items: center; gap: 6px; }

/* ── Menu ─────────────────────────────────────────────────────────────── */

@keyframes rise { from { opacity: 0; transform: translateY(18px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes twinkle { 50% { transform: scale(1.5); opacity: .6; } }
@keyframes shimmer { to { background-position: 200% center; } }
@keyframes sheen { 0%, 60% { transform: translateX(-140%) skewX(-20deg); } 100% { transform: translateX(240%) skewX(-20deg); } }
@keyframes breathe { 50% { box-shadow: 0 6px 0 #995335, 0 14px 40px #ffbb7744; } }

/* ── Game ─────────────────────────────────────────────────────────────── */
.game { grid-template-columns: 250px minmax(0,1fr) 230px; grid-template-rows: minmax(0,1fr) auto; gap: 0 20px; padding: 0 24px 24px; }
/* 🚨 HIER STAND DIE WERKZEUGLEISTE. Hammer, Extra-Züge, Mischen und Hinweis sind keine Knöpfe mehr, sondern
   Novas Angebote — sie schlägt vor, ein Tipp auf sie führt aus (siehe `angebotZeigen()` in app.mjs). Damit sind
   `.game-dock`, `.dock-button`, `.booster*`, `.count` und der Ziel-Modus des Hammers (`.board-wrap.aim`)
   ersatzlos weg: 62 bis 66 px Höhe unten plus Abstand, die jetzt das Brett bekommt. */
.moves-stat.time { background: linear-gradient(140deg,#ff9c57,#c24d26); border-color: #ffd6b8; }
.hud-panel { align-self: center; min-width: 0; background: var(--glass); border: 1px solid var(--line); border-radius: 26px; padding: 18px; backdrop-filter: blur(10px); }
.level-heading { display: grid; grid-template-columns: 44px 1fr auto; gap: 0 10px; align-items: center; margin: 0 0 12px; }
.level-heading h2 { font-size: 22px; margin: 2px 0 0; }.heading-text { min-width: 0; grid-area: 1 / 2; }
.nova-hud { position: relative; width: 44px; height: 44px; filter: drop-shadow(0 0 8px #7ce9ff55); cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
/* Nova ist im Spiel ein echter Knopf (sie IST das Werkzeug), aber sie darf nicht wie einer aussehen: kein
   Rahmen, keine Fläche, kein Innenabstand — nur ihre Figur und ihre Marke. */
button.nova-hud { padding: 0; border: 0; background: none; display: block; overflow: visible; }
button.nova-hud:active { transform: none; }
button.nova-hud:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; border-radius: 50%; }
.nova-hud.pressed { transform: none !important; filter: drop-shadow(0 0 14px #7ce9ffcc) brightness(1.08); }
/* Keeps Nova's grid column reserved while her single live rig flies to the result. */
/* Nova's charge ring: a conic sweep masked to a thin ring around her mount, golden and breathing when full. */
.nova-figure.look-hud::before { content: ""; position: absolute; inset: -3px; border-radius: 50%; background: conic-gradient(var(--gold) calc(var(--charge,0) * 360deg), #ffffff16 0); -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 2.5px)); mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 2.5px)); pointer-events: none; }
.nova-figure.look-hud.ready { filter: drop-shadow(0 0 12px #ffd77aaa); }.nova-figure.look-hud.ready::before { background: conic-gradient(var(--gold), #fff1a6, var(--gold)); animation: nova-ready 1.1s ease-in-out infinite; }
@keyframes nova-ready { 50% { transform: scale(1.12); opacity: .75; } }
body.reduced .nova-figure.look-hud.ready::before { animation: none; }
/* Things Nova throws: positioned by app.mjs every frame along an arc from her mount to the target. */
.fly { position: fixed; left: 0; top: 0; z-index: 70; pointer-events: none; will-change: transform; }
.fly svg { width: 100%; height: 100%; display: block; overflow: visible; }
.fly-hammer { width: 56px; height: 56px; margin: -28px 0 0 -28px; filter: drop-shadow(0 8px 12px #000a) drop-shadow(0 0 10px #ff6d8266); }
.fly-orb { width: 44px; height: 44px; margin: -22px 0 0 -22px; filter: drop-shadow(0 0 16px #ffd77a); }.fly-orb .go-star { transform-origin: 32px 32px; animation: orb-star .9s linear infinite; }
@keyframes orb-star { to { transform: rotate(180deg); } }
.fly-mote { width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%; background: radial-gradient(circle, #ffffff, #7ce9ff 45%, #7ce9ff00 75%); box-shadow: 0 0 16px #7ce9ff, 0 0 4px #fff; }
.fly-mote.green { background: radial-gradient(circle, #ffffff, #6ff0bd 45%, #6ff0bd00 75%); box-shadow: 0 0 16px #6ff0bd, 0 0 4px #fff; }
.fly-mote.farbig { background: radial-gradient(circle, #ffffff, var(--c,#7ce9ff) 45%, transparent 75%); box-shadow: 0 0 12px var(--c,#7ce9ff), 0 0 3px #fff; }
.fly-mote.tiny { width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; box-shadow: 0 0 10px #7ce9ff; }.fly-mote.gold { background: radial-gradient(circle, #ffffff, #ffd77a 45%, #ffd77a00 75%); box-shadow: 0 0 10px #ffd77a; }
/* Trails: ghosts along the flight that fade and shrink, dropped by `flyFrom` where the flying Web Animation
   currently is. Their fade is a Web Animation too; `opacity: 0` keeps a ghost invisible should it outlive it. */
.trail-box { position: fixed; left: 0; top: 0; width: 0; height: 0; z-index: 69; pointer-events: none; }
.trail { position: fixed; left: 0; top: 0; z-index: 69; pointer-events: none; border-radius: 50%; opacity: 0; }
.trail-spark { width: 10px; height: 10px; margin: -5px 0 0 -5px; background: radial-gradient(circle, #fff, #ff8fa2 50%, #ff8fa200 75%); }
.trail-gold { width: 14px; height: 14px; margin: -7px 0 0 -7px; background: radial-gradient(circle, #fff8dc, #ffd77a 45%, #ffd77a00 75%); }
.trail-cyan { width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; background: radial-gradient(circle, #fff, #7ce9ff 50%, #7ce9ff00 75%); }
.trail-green { width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; background: radial-gradient(circle, #fff, #6ff0bd 50%, #6ff0bd00 75%); }
/* Impact: a bright flash and an expanding shock ring where something lands; the board takes a punch. */
.impact { position: fixed; left: 0; top: 0; z-index: 68; pointer-events: none; }
.impact-flash { width: 120px; height: 120px; margin: -60px 0 0 -60px; border-radius: 50%; background: radial-gradient(circle, #ffffffee, var(--c, #ffd77a) 35%, transparent 70%); animation: impact-flash .32s ease-out forwards; }
.impact-ring { width: 40px; height: 40px; margin: -20px 0 0 -20px; border-radius: 50%; border: 4px solid var(--c, #ffd77a); box-shadow: 0 0 18px var(--c, #ffd77a); animation: impact-ring .5s cubic-bezier(.2,.8,.2,1) forwards; }
@keyframes impact-flash { to { opacity: 0; transform: translate(var(--x), var(--y)) scale(1.6); } }
@keyframes impact-ring { to { opacity: 0; transform: translate(var(--x), var(--y)) scale(4); border-width: 1px; } }
.board-wrap.punch { animation: punch .3s ease-out; }
/* Der Zoom-Stoß großer Momente (knall in app.mjs) und der Lichtschlag des Scheins dahinter. */
.board-wrap.zoom { animation: zoom .55s cubic-bezier(.2,.8,.2,1); }
@keyframes zoom { 18% { transform: scale(1.045); } }
.board-aura.knall { animation: knall .5s ease-out; }
@keyframes knall { 0% { opacity: 1; filter: brightness(2.4) saturate(1.3); transform: scale(1.3); } 100% { opacity: 1; filter: none; transform: scale(1); } }
@keyframes punch { 30% { transform: scale(1.025); } }
body.reduced .trail, body.reduced .impact { display: none; }
.nova-chip { grid-area: 1 / 2; position: relative; margin: 0; padding: 5px 10px; border-radius: 12px; background: #7ce9ff14; border: 1px solid #7ce9ff44; color: var(--ink); font-size: 12.5px; line-height: 1.35; }
.nova-chip::before { content: ""; position: absolute; left: -7px; top: 14px; width: 12px; height: 12px; transform: rotate(45deg); background: #1d3a4e; border: 1px solid #7ce9ff44; border-right: 0; border-top: 0; border-radius: 0 0 0 3px; }
.nova-chip.bump { animation: rise .25s ease; }
.level-heading.talking .heading-text { display: none; }
.hud-stats { display: grid; grid-template-columns: 66px 1fr; gap: 12px; align-items: center; }
.hud-stats small { display: block; font-size: 10px; letter-spacing: .12em; color: var(--muted); }.hud-stats b { font-size: 23px; display: block; font-variant-numeric: tabular-nums; }
.moves-stat { border: 2px solid #ffd9fb; border-radius: 22px; text-align: center; background: linear-gradient(140deg,#b262c0,#6a3f9c); padding: 8px; box-shadow: 0 4px 0 #311e5a, 0 0 24px #b262c055; transition: box-shadow .3s; }
.moves-stat b { font-size: 30px; line-height: 1.1; }.moves-stat small { color: white; }.combo-stat { grid-column: span 2; }
@keyframes bump { 30% { transform: scale(1.18); } }
@keyframes alarm { 50% { box-shadow: 0 4px 0 #5a1e2e, 0 0 30px #ff5d73aa; border-color: #ffb3c0; } }
.moves-stat.bump b { animation: bump .35s ease; display: block; }
.moves-stat.low { background: linear-gradient(140deg,#d2496a,#8a2f52); animation: alarm 1s ease-in-out infinite; }
.combo-stat b { transition: color .2s; }.combo-stat.hot b { color: var(--gold); text-shadow: 0 0 14px var(--gold); }.combo-stat.bump b { animation: bump .4s ease; display: inline-block; }
.score-track { position: relative; margin-top: 6px; padding-top: 10px; }
.score-track progress { width: 100%; height: 6px; accent-color: var(--gold); display: block; border-radius: 3px; overflow: hidden; }
.star-marks { position: absolute; left: 0; right: 0; top: 0; height: 12px; pointer-events: none; }
.star-marks svg { position: absolute; top: -3px; width: 13px; height: 13px; margin-left: -6px; color: #ffffff3a; transition: color .3s, transform .3s; }
.star-marks svg.lit { color: var(--gold); filter: drop-shadow(0 0 6px var(--gold)); animation: bump .5s ease; }
.meter { position: relative; height: 14px; margin-top: 8px; border-radius: 7px; background: #ffffff14; overflow: hidden; }
.meter i { position: absolute; inset: 0; width: 0; border-radius: 7px; background: linear-gradient(90deg,#ff9c57,#ff79e5,#7ce9ff); transition: width .35s ease; box-shadow: 0 0 12px #ff79e5aa; }
.meter span { position: absolute; inset: 0; display: grid; place-items: center; font-size: 10px; letter-spacing: .2em; font-weight: 900; color: #fff; text-shadow: 0 1px 2px #000; }
body.fever .meter i { animation: fever-bar .5s linear infinite; background: linear-gradient(90deg,#ff9c57,#ffd35c,#ff79e5,#7ce9ff,#ff9c57); background-size: 200% 100%; }
@keyframes fever-bar { to { background-position: -200% 0; } }
body.fever .board-aura { background: radial-gradient(ellipse,#ff79e566,transparent 70%); animation: twinkle 1s ease-in-out infinite; }
body.fever #combo-stat b { color: var(--pink); text-shadow: 0 0 16px var(--pink); }
.stat-strip { display: grid; grid-template-columns: repeat(auto-fit,minmax(88px,1fr)); gap: 6px; margin: 0 0 12px; }
.stat-strip div { background: #ffffff0c; border-radius: 12px; padding: 8px 6px; text-align: center; }.stat-strip b { display: block; font-size: 17px; }.stat-strip small { font-size: 10px; letter-spacing: .1em; color: var(--muted); }
.reward { text-align: center; }.reward h2 { margin: 8px 0 14px; }
.streak { display: flex; justify-content: center; gap: 8px; margin-bottom: 16px; }
.streak i { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-style: normal; font-size: 11px; font-weight: 800; background: #ffffff10; color: var(--muted); }
.streak i.done { background: var(--gold); color: #3a2600; box-shadow: 0 0 12px #ffd35c88; }.streak i.today { border: 2px solid var(--gold); color: white; animation: bump 1.2s ease-in-out infinite; }
.reward-box { display: flex; justify-content: center; gap: 10px; margin-bottom: 12px; }
.reward-box div { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 12px 16px; border-radius: 16px; background: #ffd35c14; border: 1px solid #ffd35c55; font-size: 12px; animation: starPop .6s cubic-bezier(.3,1.4,.5,1) both; }
.reward-box b { font-size: 22px; color: var(--gold); }.reward-box svg { color: var(--c); filter: drop-shadow(0 0 8px var(--c)); }
.share { background: #2f6a5a; border-color: #95f4bb66; }
.goals { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.goal { flex: 1 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px; background: #061d2b66; padding: 5px 10px 5px 5px; border: 1px solid #ffffff15; border-radius: 14px; font-size: 12px; transition: background .3s, border-color .3s; }
.goal b { display: flex; align-items: center; gap: 5px; }.goal canvas { width: 30px; height: 30px; display: block; }
.goal span { color: var(--gold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.goal.bump { animation: bump .35s ease; }
.goal.done { background: #2b7c5c55; border-color: #95f4bb; }.goal.done span { color: #baffcf; display: inline-flex; align-items: center; gap: 4px; }
.board-wrap { position: relative; width: 100%; height: 100%; min-width: 0; min-height: 0; align-self: stretch; overflow: hidden; }
.board-aura { position: absolute; inset: 8% 0; background: radial-gradient(ellipse, color-mix(in srgb, var(--world-accent, #9b7bf0) 26%, transparent), transparent 70%); pointer-events: none; }
/* Der Puls einer Kette: der Schein schlägt in der Kettenfarbe (`--kette`, gesetzt in playClear) aus und klingt ab. */
.board-aura.kette { background: radial-gradient(ellipse, color-mix(in srgb, var(--kette, #7ce9ff) 42%, transparent), transparent 70%); animation: kette-puls .9s ease-out; }
@keyframes kette-puls { 0% { opacity: 1; transform: scale(1.18); } 100% { opacity: .9; transform: scale(1); } }
#board { position: absolute; inset: 0; display: block; width: 100%; height: 100%; touch-action: none; user-select: none; -webkit-user-select: none; }
/* Grafikkarte: Über dem Brett liegen die GPU-Ebene (Steine und Effekte) und darüber eine 2D-Ebene für Hinweis-
   und Auswahlrahmen. Beide genau deckungsgleich, beide fangen keinen Finger ab. */
.board-fx, .board-oben { position: absolute; left: 0; top: 0; display: block; pointer-events: none; }
@keyframes shake { 0%, 100% { transform: none; } 20% { transform: translate(-5px,3px); } 40% { transform: translate(5px,-3px); } 60% { transform: translate(-4px,-2px); } 80% { transform: translate(3px,2px); } }
.board-wrap.shake { animation: shake .4s ease; }
/* Der Rahmen (`.banner`) wird animiert, die Schrift darin (`.banner-in`) trägt Verlauf und Leuchtfilter. Ein Filter
   auf dem skalierten Element selbst zwang Safari, die Einblendung in jedem Bild neu zu malen. `will-change` hält die
   Ebene bereit, statt sie im ersten Bild der Einblendung anzulegen. */
.banner { position: absolute; left: 0; right: 0; top: 30%; text-align: center; pointer-events: none; opacity: 0; font-weight: 900; font-size: clamp(28px,7vw,52px); letter-spacing: -.02em; color: white; -webkit-text-stroke: 1px #0006; text-shadow: 0 4px 18px #000a, 0 0 26px var(--banner-glow,#7ce9ff), 0 0 60px var(--banner-glow,#7ce9ff); transform-origin: center; }
.banner-in { display: inline-block; max-width: 100%; }
.banner.callout { font-style: italic; font-size: clamp(34px,9vw,64px); -webkit-text-stroke: 0; }
.banner.callout .banner-in { background: linear-gradient(180deg,#fff,var(--banner-glow,#ffd35c)); -webkit-background-clip: text; background-clip: text; color: transparent; filter: drop-shadow(0 4px 12px #000a) drop-shadow(0 0 22px var(--banner-glow,#ffd35c)); }
.banner b { display: block; font-size: .42em; letter-spacing: .3em; color: var(--banner-glow,#7ce9ff); }
/* 1.9 s with the hold from 10 % to 82 % leaves about 1.4 s fully legible. At 1.1 s the readable window was
   barely half a second, which is not enough for two lines. */
@keyframes bannerIn { 0% { opacity: 0; transform: scale(.55) rotate(-5deg); } 10% { opacity: 1; transform: scale(1.06) rotate(1deg); } 18% { transform: scale(1) rotate(0); } 82% { opacity: 1; transform: translateY(0) scale(1); } 100% { opacity: 0; transform: translateY(-26px) scale(1.04); } }
.banner.show { animation: bannerIn 1.9s cubic-bezier(.2,.8,.2,1) forwards; }
.level-intro { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: min(88%,360px); background: #16123bf0; border: 1px solid #b2a2d855; border-radius: 24px; padding: 18px 20px; text-align: center; box-shadow: 0 24px 70px #000a; pointer-events: auto; }
.level-intro h3 { margin: 6px 0 4px; font-size: 26px; }.level-intro p { margin: 0; color: var(--muted); font-size: 13px; }
.intro-goals { display: flex; justify-content: center; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.intro-goals span { display: inline-flex; align-items: center; gap: 4px; font-weight: 800; color: var(--gold); font-size: 14px; }.intro-goals canvas { width: 34px; height: 34px; }
@keyframes introIn { from { opacity: 0; transform: translate(-50%,-50%) scale(.7); } to { opacity: 1; transform: translate(-50%,-50%) scale(1); } }
@keyframes introOut { to { opacity: 0; transform: translate(-50%,-60%) scale(.92); } }
.level-intro.show { animation: introIn .4s cubic-bezier(.3,1.4,.5,1) both; }.level-intro.leave { animation: introOut .35s ease forwards; }
.side-card { align-self: center; color: var(--muted); font-size: 14px; line-height: 1.7; }.side-card h2 { color: white; line-height: 1.3; }
.legend { display: grid; gap: 8px; color: var(--gold); }.legend span { display: flex; align-items: center; gap: 8px; }.legend i { width: 10px; height: 10px; border-radius: 50%; background: var(--c); box-shadow: 0 0 10px var(--c); }
/* Pause und Vollbild sind keine Spielaktionen, sondern Rahmen — sie stehen still in der Kopfzeile. */
.head-tools { grid-area: 1 / 3; display: flex; gap: 6px; align-self: center; }
.head-tools .round-button { width: 34px; height: 34px; background: #ffffff0c; }
/* Auf dem Finger mindestens 40 × 40: 34 px sind mit der Maus genug, mit dem Daumen trifft man daneben. */
@media(pointer:coarse) { .head-tools .round-button { width: 40px; height: 40px; } }
.head-tools svg { opacity: .7; }@media(hover:hover) { .head-tools .round-button:hover svg { opacity: 1; } }
/* Desktop-only pieces: the round panel under the HUD, the keyboard help, the key badges on the controls and the
   numbers strip in the menu. Phones and tablets never see them (touch has no keys, and the columns are not there). */
.run-panel { display: none; }
/* Novas Marke: das Zeichen dessen, was ein Tipp auf sie gerade tut. Sie sitzt auf ihrem Kreis, nimmt die Farbe
   der Aktion an und atmet — der einzige Knopf, den das Spiel im Lauf noch hat. */
.nova-badge { position: absolute; right: -3px; bottom: -3px; width: 23px; height: 23px; border-radius: 50%; display: grid; place-items: center; background: var(--c,#7ce9ff); color: #0d1524; box-shadow: 0 2px 8px #0009, 0 0 14px var(--c,#7ce9ff); animation: breathe-badge 1.5s ease-in-out infinite; }
.nova-badge svg { width: 14px; height: 14px; }
.reduced .nova-badge { animation: none; }
@keyframes breathe-badge { 50% { transform: scale(1.14); box-shadow: 0 2px 8px #0009, 0 0 22px var(--c,#7ce9ff); } }
/* Steht ein Angebot, trägt ihre Sprechblase die Farbe der Aktion — ohne dass die Zeile umspringt. */
.nova-chip.offer { background: color-mix(in srgb, var(--c,#7ce9ff) 12%, transparent); border-color: color-mix(in srgb, var(--c,#7ce9ff) 55%, transparent); }
.nova-chip .confirm { display: block; margin-top: 2px; font-size: 11px; font-weight: 700; color: var(--c,#7ce9ff); }

/* Desktop: status on the left, a centered board, and supporting information on the right.
   Side columns have equal widths; each panel can scroll without shrinking the board. */
@media(min-width:1001px) and (orientation:landscape) {
  .game { grid-template-columns: minmax(200px,20vw) minmax(0,1fr) minmax(200px,20vw); grid-template-rows: repeat(2,minmax(0,1fr)); gap: 16px 24px; padding: 6px 24px 22px; }
  .hud-panel { grid-area: 1 / 1 / 3 / 2; align-self: center; max-height: 100%; overflow: auto; padding: 22px; border-radius: 28px; }
  /* Equal side columns center the board. Round history and the legend share the right column,
     grouped around its midpoint without reserving space for the removed booster controls. */
  .run-panel { display: block; grid-area: 1 / 3; align-self: end; max-height: 100%; overflow: auto; padding: 16px 18px 14px; border-radius: 24px; background: var(--glass); border: 1px solid var(--line); }
  .run-stats { margin: 10px 0; grid-template-columns: repeat(3,1fr); }.run-stats b { font-size: 18px; }.run-stats b.beat { color: var(--gold); text-shadow: 0 0 12px #ffd77a88; }
  .run-feed { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 12px; }
  .run-feed li { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 4px 8px 4px 9px; border-radius: 8px; background: #ffffff09; border-left: 3px solid var(--c,#7ce9ff); white-space: nowrap; overflow: hidden; animation: rise .3s ease backwards; }
  .run-feed b { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; letter-spacing: .02em; }.run-feed span { flex: 1 1 auto; min-width: 0; text-align: right; color: var(--muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; }
  .run-feed:empty::before { content: "Deine Spezialsteine und Ketten landen hier."; display: block; padding: 6px 2px; color: var(--muted); font-size: 12px; }
  .level-heading { grid-template-columns: 56px minmax(0,1fr); grid-template-rows: 56px 88px; margin-bottom: 16px; row-gap: 8px; }
  .heading-text, .nova-chip { grid-area: 2 / 1 / 3 / 3; max-height: 88px; overflow: auto; }
  .head-tools { grid-area: 1 / 2; justify-self: end; }.nova-hud { width: 56px; height: 56px; }.level-heading h2 { font-size: 24px; }.nova-chip { font-size: 13.5px; }
  .hud-stats { grid-template-columns: 78px 1fr; gap: 14px; }.moves-stat b { font-size: 34px; }.score-stat b { font-size: 26px; }
  .goals { gap: 8px; margin-top: 16px; }.goal { font-size: 13px; padding: 6px 12px 6px 6px; }.goal canvas { width: 34px; height: 34px; }
  .board-wrap { grid-area: 1 / 2 / 3 / 3; padding: 0; }
  /* Both supporting cards scroll within their own half when the window is short. */
  .side-card { grid-area: 2 / 3; align-self: start; max-height: 100%; overflow: auto; overscroll-behavior: contain; padding: 18px 20px; border-radius: 22px; background: var(--glass); border: 1px solid var(--line); font-size: 13px; line-height: 1.6; }
  .side-card h2 { font-size: 18px; margin: 4px 0 8px; }.side-card .eyebrow { font-size: 10px; }.legend { gap: 6px; font-size: 12px; }
  .level-intro { width: min(88%,420px); padding: 22px 26px; }.level-intro h3 { font-size: 30px; }.level-intro p { font-size: 14px; }.intro-goals canvas { width: 40px; height: 40px; }.intro-goals span { font-size: 15px; }
  /* Campaign: the winding path on the left, achievements beside it instead of below. */

  #progress-screen .list-scroll { display: grid; grid-template-rows: minmax(0,1fr); column-gap: 40px; align-content: start; }
  /* Am Rechner gehören sie optisch zur Levelkarte, also auf deren Breite. */
  #progress-screen .head-books { max-width: 560px; }
  #progress-screen .level-map { grid-column: 1; width: 100%; margin: 0; }
  #progress-screen .list-subhead { margin-top: 4px; }#progress-screen .achievements { align-content: start; grid-template-columns: 1fr; }
  .node { --w: 112px; }.node-disc { width: 64px; height: 64px; }.node-disc strong { font-size: 24px; }.node-name { font-size: 11px; }.map-prop.mark { width: 104px; height: 104px; }.map-prop.far { width: 66px; height: 66px; }
  .leader-list .row { padding: 14px 20px; grid-template-columns: 48px 1fr auto; }.leader-list .rank { width: 40px; height: 40px; font-size: 15px; }.leader-list .pts { font-size: 18px; }
  .board-tabs button { flex: 0 1 auto; padding: 10px 22px; font-size: 14px; }

}

/* Wide desktop screens: the side columns grow with the window instead of leaving the board alone in the middle. */
@media(min-width:1600px) and (orientation:landscape) {
  /* 🚨 DIE MITTELSPALTE DARF NICHT DEN GANZEN REST NEHMEN. Gemeldet: „das sieht am pc sehr gestreckt aus."
     Mit `minmax(0,1fr)` bekam sie auf einem 2000 px breiten Fenster 1120 px — das BRETT ist aber immer ein
     Quadrat und damit höchstens so breit wie hoch (dort 664 px). Der Überschuss war unsichtbare Leere IN
     der Mittelspalte, und weil die Randspalten am Rand der Spalte kleben, wurden die beiden Karten dadurch
     an die äußersten Ränder des Fensters geschoben: links Zahlen, rechts Legende, dazwischen ein halber
     Meter Nichts. Nicht das Brett war gestreckt, sondern alles darum herum.

     Die Mitte wird deshalb bei `94dvh` gedeckelt — das ist die Höhe, die dem Brett tatsächlich zur
     Verfügung steht, also genau seine größtmögliche Breite. Was dann übrig bleibt, verteilt
     `justify-content: center` nach AUSSEN, statt es in die Mitte zu stopfen: Die drei Spalten rücken
     zusammen und stehen als Block in der Mitte des Fensters. `minmax(0,…)` lässt die Mitte weiterhin
     schrumpfen, wenn das Fenster schmal ist — sonst würde sie auf einem flachen, breiten Schirm die
     Randspalten hinausdrücken. */
  .game { grid-template-columns: minmax(calc(300px * var(--ui,1)),calc(360px * var(--ui,1))) minmax(0,84dvh) minmax(calc(300px * var(--ui,1)),calc(360px * var(--ui,1)));
          justify-content: center; gap: calc(16px * var(--ui,1)) calc(32px * var(--ui,1)); padding: 8px 48px 28px; }
  /* 🚨 DIE KARTEN WACHSEN MIT, NICHT NUR IHRE SPALTE. Gemeldet: „das spielfeld ist rießig der rest ist klein".
     Eine breitere Spalte allein hätte nur mehr Luft um dieselbe 12-px-Schrift gelegt. `zoom` vergrößert
     alles darin — Zahlen, Ziele, Nova in der Kopfzeile, Abstände — im selben Verhältnis wie die Spalte, und
     anders als `transform` rechnet das Raster mit der neuen Größe. `--ui` setzt `uiScale()` in `app.mjs`:
     1 bis zu dem Maß, für das die Karten gebaut sind, darüber bis 1,8. Das Brett bekommt dafür höchstens
     84 % der Höhe statt 94 %: Es bleibt der größte Teil, aber nicht mehr der einzige. */
  .hud-panel, .run-panel, .side-card { zoom: var(--ui,1); }
  .run-feed { font-size: 13px; }.run-feed span { font-size: 12px; }
  .level-intro { width: min(80%,460px); }
}
/* ── Lists ────────────────────────────────────────────────────────────── */
.screen-list { flex-direction: column; width: min(100%,940px); align-self: center; padding: 8px 18px 14px; }
.list-head { animation: rise .5s cubic-bezier(.2,.8,.2,1) backwards; }
.screen-list h1 { font-size: clamp(26px,4vw,44px); margin: 6px 0 4px; }.list-summary { margin: 0 0 12px; color: var(--muted); font-size: 13px; }
.list-subhead { font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin: 22px 0 10px; }
.list-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 4px 12px; }
/* ── Die Levelkarte ──────────────────────────────────────────────────────
   Eine STRASSE durch Novas Welt, keine Liste: breiter Belag mit dunkler Kante und Mittellinie, runde Münzen
   darauf, Sterne direkt darunter, und dahinter je Kapitel ein getöntes Band mit seinem Wahrzeichen. */
.level-map { position: relative; width: min(100%,560px); margin: 0 auto; }
/* 🚨 HÖHE KOMMT VOM INHALT, NICHT VON `100%`. Am Rechner rollt `.level-map` SELBST (`overflow-y:auto`), dort
   sind 100 % nur das sichtbare Fenster — Straße und Landschaft klebten oben und waren beim Scrollen weg. Beide
   Lagen bekommen ihre Pixelhöhe deshalb aus `renderProgress()`, genau wie die Münzen. */
/* 🚨 KEIN KASTEN UM DEN PFAD. Gemeldet: „die deutliche Pfad-Abgrenzung sollte weggehen! Aktuell sieht man
   deutlich ein Viereck um den ganzen Pfad." Die Landschaft war auf die Breite der Karte begrenzt und endete
   an einer harten Kante — auf dem breiten Bildschirm stand dadurch eine getönte Säule im dunklen Raum. Jetzt
   greift sie über die Karte hinaus und blendet nach links und rechts aus; die Bänder tun das oben und unten
   schon. Damit gibt es keine Kante mehr, an der sie aufhört. */
.level-scenery { position: absolute; left: 0; top: 0; right: 0; pointer-events: none; overflow: hidden;
  /* Der Verlauf muss INNERHALB der Karte auf null sein: Am Rechner rollt `.level-map` selbst, und `overflow-y`
     macht `overflow-x` mit — die Landschaft wird also genau an der Kartenkante abgeschnitten. Ein Überstand
     hilft da nichts, ein früh auslaufender Verlauf schon. Die zweite Lage nimmt dem allerersten Band die
     Oberkante. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 38%, #000 62%, transparent), linear-gradient(180deg, transparent, #000 150px);
  mask-image: linear-gradient(90deg, transparent, #000 38%, #000 62%, transparent), linear-gradient(180deg, transparent, #000 150px);
  -webkit-mask-composite: source-in; mask-composite: intersect; }
.map-band { --c: var(--cyan); position: absolute; left: 0; right: 0;
  background: radial-gradient(120% 60% at 15% 12%, color-mix(in srgb, var(--c) 26%, transparent), transparent 70%),
              radial-gradient(110% 55% at 88% 78%, color-mix(in srgb, var(--c) 20%, transparent), transparent 72%),
              linear-gradient(180deg, color-mix(in srgb, var(--c) 13%, transparent), transparent 60%);
  /* Die Gegenden gehen ineinander über statt an einer harten Kante zu wechseln. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent); }
/* Ein gesperrtes Kapitel behält seine Farbe: Man soll sehen, wohin die Reise geht, nur eben gedämpft. */
.map-band.locked { filter: saturate(.6); opacity: .72; }
.map-prop { --c: var(--cyan); position: absolute; color: var(--c); opacity: .38; }
.map-prop svg { width: 100%; height: 100%; display: block; filter: drop-shadow(0 0 14px color-mix(in srgb, var(--c) 45%, transparent)); }
.map-prop.mark { width: 86px; height: 86px; }
.map-prop.far { width: 54px; height: 54px; opacity: .24; }
.level-path { position: absolute; left: 0; top: 0; width: 100%; pointer-events: none; }
.level-path path { fill: none; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.level-path .edge { stroke: #0a0a1f; stroke-width: 30; }
.level-path .road { stroke: #3b3466; stroke-width: 24; }
.level-path .dashes { stroke: #ffffff1f; stroke-width: 3; stroke-dasharray: 5 13; }
.level-path .edge.done { stroke: #6a4a05; }
.level-path .road.done { stroke: url(#roadgold); stroke: #e3aa27; filter: drop-shadow(0 0 12px #ffd35c55); }
.level-path .dashes.done { stroke: #fff3c8aa; }
.level-nodes { position: relative; }
.node { --i: 0; --w: 96px; --c: var(--cyan); position: absolute; width: var(--w); margin-left: calc(var(--w) / -2); display: grid; justify-items: center; gap: 3px; padding: 0; border: 0; background: none; box-shadow: none; animation: rise .45s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 40ms); }
/* Die Münze ist das einzige dicke Ding auf der Seite — hier soll es knallen, anders als in der Leiste im Spiel. */
.node-disc { display: grid; place-items: center; width: 58px; height: 58px; border-radius: 50%; background: radial-gradient(circle at 32% 24%,#8fefff,#2183b3 72%); box-shadow: 0 5px 0 #08283a, 0 0 0 4px #ffffff14, 0 0 22px #7ce9ff44, inset 0 -4px 0 #0000002e; }
.node-disc strong { font-size: 22px; color: #06222f; text-shadow: 0 1px 0 #ffffff5c; }
.node-disc .lock { color: #ffffff6b; }
.node-stars { display: flex; gap: 1px; padding: 2px 5px; border-radius: 9px; background: #0d0a26cc; box-shadow: 0 1px 0 #0006; margin-top: -8px; }
.node-stars svg { width: 13px; height: 13px; color: #ffffff2b; }.node-stars svg.lit { color: var(--gold); filter: drop-shadow(0 0 4px var(--gold)); }
.node-name { font-size: 10px; font-weight: 700; line-height: 1.15; color: #cfc9ef; text-align: center; text-shadow: 0 1px 3px #000, 0 0 9px #000c; }
.node.done .node-disc { background: radial-gradient(circle at 32% 24%,#ffe9a3,#dc9d16 72%); box-shadow: 0 5px 0 #6a4a05, 0 0 0 4px #ffffff1a, 0 0 22px #ffd35c55, inset 0 -4px 0 #0000002e; }
.node.done .node-disc strong { color: #4a3100; }
.node.current { z-index: 2; }
.node.current .node-disc { width: 68px; height: 68px; background: radial-gradient(circle at 32% 24%,#ffffff,#7ce9ff 40%,#1b9fd4 78%); box-shadow: 0 6px 0 #08283a, 0 0 0 5px var(--gold), 0 0 34px #ffd35c77, inset 0 -4px 0 #0000002e; animation: breathe-node 1.6s ease-in-out 1s infinite; }
.node.current .node-disc strong { font-size: 26px; }
.node.current .node-name { color: var(--gold); font-size: 11px; }
@keyframes breathe-node { 50% { box-shadow: 0 3px 0 #061824, 0 0 34px #ffd35caa; } }
/* Auch eine gesperrte Münze trägt die Farbe ihres Kapitels — die Straße vorn liest sich dann als Gegenden. */
.node.locked { opacity: .72; }.node.locked .node-disc { background: radial-gradient(circle at 32% 24%, color-mix(in srgb, var(--c) 34%, #453d6d), #262045 74%); box-shadow: 0 4px 0 #14102c, inset 0 -3px 0 #0000002e; }
@media(hover:hover) { .node:hover:not(:disabled) .node-disc { transform: translateY(-2px); } }.node .node-disc { transition: transform .12s ease; }
.achievements { display: grid; grid-template-columns: repeat(auto-fill,minmax(180px,1fr)); gap: 8px; }
.ach { --i: 0; display: grid; grid-template-columns: 38px 1fr; gap: 10px; align-items: center; padding: 10px; border: 1px solid var(--line); border-radius: 14px; color: var(--muted); font-size: 12px; animation: rise .45s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 40ms + 200ms); }
.ach i { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; background: #ffffff0c; color: #ffffff50; }
.ach b { display: block; color: #ffffffb0; }.ach.earned { color: var(--ink); border-color: #ffd35c66; background: #ffd35c12; }.ach.earned i { background: #ffd35c22; color: var(--gold); box-shadow: 0 0 16px #ffd35c66; }.ach.earned b { color: var(--gold); }
/* Leaderboard tabs: four equal cells, a short word on top and the long name small underneath, nothing may overflow. */
.board-tabs { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 6px; margin-bottom: 8px; }
.board-tabs button { min-width: 0; display: grid; gap: 1px; padding: 7px 4px; min-height: 48px; border-radius: 14px; background: var(--panel); line-height: 1.15; }
.board-tabs b { font-size: 13px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }.board-tabs small { font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: .02em; }
.board-tabs .active { color: #161132; background: var(--cyan); box-shadow: 0 0 18px #7ce9ff66; }.board-tabs .active small { color: #161132aa; }
.board-scope { margin: 0 0 10px; color: var(--muted); font-size: 12.5px; }
.board-controls { flex: none; min-width: 0; }
/* Empty state: Nova and one clear call to action instead of a bare sentence. */
.board-empty { display: grid; justify-items: center; gap: 8px; margin: 12px auto 0; max-width: 360px; padding: 18px 16px; border-radius: 20px; background: var(--panel); border: 1px solid var(--line); text-align: center; animation: rise .4s ease backwards; }
.board-empty .nova-small { width: 64px; height: 64px; }.board-empty p { margin: 0; color: var(--ink); font-size: 14px; line-height: 1.45; }.board-empty .primary { min-height: 46px; padding: 8px 18px; margin-top: 4px; }
.board-empty.offline .primary { display: none; }
.board-loading { display: flex; align-items: center; justify-content: center; gap: 10px; min-height: 96px; color: var(--muted); }
.board-loading svg { color: var(--cyan); animation: spin 1.2s linear infinite; }
.board-empty .wide { display: inline-flex; justify-content: center; align-items: center; gap: 8px; width: 100%; margin: 0; }
.leader-list .row { --i: 0; display: grid; grid-template-columns: 40px 1fr auto; gap: 10px; align-items: center; padding: 10px 14px; background: var(--panel); border-radius: 14px; margin-bottom: 8px; animation: rise .4s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 30ms); }
.leader-list .row.me { background: linear-gradient(90deg,#2f6a5a,#221c46); border: 1px solid #95f4bb88; }
.leader-list .rank { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; font-weight: 900; background: #ffffff10; font-size: 13px; }
.rank.r1 { background: linear-gradient(#ffe8a3,#e0a41f); color: #4a3100; box-shadow: 0 0 14px #ffd35c88; }.rank.r2 { background: linear-gradient(#f4f4f4,#a9adb8); color: #2c2f38; }.rank.r3 { background: linear-gradient(#f5c29c,#b26a3a); color: #3e1f08; }
.leader-list .who { min-width: 0; }.leader-list .who b { display: block; overflow-wrap: anywhere; }.leader-list .who small { color: var(--muted); font-size: 11px; }
.leader-list .pts { color: var(--gold); font-weight: 900; font-variant-numeric: tabular-nums; text-align: right; }.leader-list .pts small { display: block; color: var(--muted); font-weight: 400; font-size: 10px; }
.leader-list p { color: var(--muted); }
.tag { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--cyan); font-size: 12px; letter-spacing: .08em; }
.board-me { flex: 0 0 auto; margin-top: 8px; padding: 10px 14px; border-radius: 16px; background: #102e40d0; border: 1px solid #95f4bb55; display: flex; justify-content: space-between; align-items: center; gap: 10px; font-size: 13px; }
.board-me b { color: var(--green); }.board-me.name { display: block; }.board-me label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }.board-me .code-row { flex: 1; margin: 0; }.board-me .code-row input { flex: 1; min-width: 0; }.board-me .hint { display: block; margin-top: 6px; color: var(--muted); font-size: 11px; }

/* ── Dialogs ──────────────────────────────────────────────────────────── */
/* Breite UND Höhe lassen die sicheren Ränder frei. Quer am Handy liegt die Aussparung links oder rechts,
   also begrenzt `max-width` das Blatt — sonst steht ein 92-vw-Blatt auf einem 844-px-Gerät mit 59 px
   Aussparung mit seinem Rand genau darunter. */
dialog { width: min(92vw,460px); max-width: calc(100vw - var(--sa-links) - var(--sa-rechts) - 24px); max-height: calc(var(--vvh,100dvh) - 40px - var(--sa-oben) - var(--sa-unten)); overflow-y: auto; border: 1px solid #a2cdd866; border-radius: 26px; padding: 24px; background: #221c46; color: var(--ink); box-shadow: 0 24px 90px #0008; }
/* 🚨 EIN BLATT MIT TASTATUR HÄNGT OBEN, NICHT IN DER MITTE. Gemeldet: „der Dialog wo man für Nova seinen Namen
   einträgt scrollt die UI unnötig nach oben mobil auf iOS". Ein `dialog` sitzt in der Mitte der LAYOUT-Fläche;
   die Tastatur verkleinert aber nur die SICHTBARE Fläche, also steht das Blatt zur Hälfte dahinter, und iOS hebt
   dann die ganze Seite an, um das Feld freizulegen. `--vvh` (aus `visualViewport.height`, siehe app.mjs) begrenzt
   die Höhe auf das, was übrig ist, und solange getippt wird, hängt das Blatt oben. */
body.typing dialog[open] { margin-top: max(10px, var(--sa-oben)); margin-bottom: auto; }
body.typing .settings { border-radius: 26px; }
@keyframes sheetIn { from { opacity: 0; transform: translateY(30px) scale(.94); } to { opacity: 1; transform: none; } }
@keyframes fadeIn { from { opacity: 0; } }
dialog[open] { animation: sheetIn .35s cubic-bezier(.2,.9,.3,1.1); }
/* The story sheet only fades: Nova flies into it as a fixed element, and a transform on the sheet during its
   entrance would become her containing block and bend the flight. */
.story[open] { animation: fadeIn .3s ease; }
/* No backdrop-filter here: iOS Safari sometimes keeps the blurred backdrop layer painted after a dialog closes, which
   left the whole screen behind it soft. A plain darkening never lingers. */
dialog::backdrop { background: #08051bd6; animation: fadeIn .3s ease; }
dialog h2 { font-size: 30px; margin: 10px 0 20px; }
.settings { padding: 0 0 16px; }.settings h2 { margin: 2px 0 0; font-size: 26px; }.sheet-head { position: sticky; top: 0; z-index: 2; display: flex; justify-content: space-between; align-items: center; padding: 18px 20px 12px; background: linear-gradient(#221c46 70%,#221c4600); }
/* 🚨 DER KOPF EINES BLATTS BLEIBT STEHEN — WEGEN NOVA. Gemeldet: „Die Header sollten sich nicht mit scrollen,
   denn das sorgt dafür, dass Nova sich sonst bewegt!" Ihr Dock sitzt in der Kopfzeile (`data-nova-dock`), und die
   Bühne misst dessen Lage in JEDEM Bild neu (`stage.mjs`, `track()`). Rollt der Kopf weg, zieht sie mit nach oben
   aus dem Bild — sie klebt ja am Dock. `.sheet-head` klebte schon, Novas Zeile darunter aber nicht; genau die
   trägt das Dock. Beide stehen jetzt zusammen in `.sheet-top`, und das klebt als Ganzes. */
.sheet-top { position: sticky; top: 0; z-index: 3; background: #221c46; }
.sheet-top .sheet-head { background: none; }
/* 🚨 KEIN SAUM UNTER DEM KOPF. Ein verlaufender Streifen darunter sah beim Rollen hübsch aus, lag aber auch im
   Ruhezustand über dem ersten Absatz und liess dessen erste Zeile verblassen. Gemeldet: „Hier ist der erste Satz
   aber nicht komplett sichtbar". Der Kopf deckt jetzt schlicht, und darunter beginnt der Inhalt.
   Ebenso kein negativer Rand am Kopf: Der zog den Fluss um 24 px hoch, sodass der erste Absatz UNTER dem
   stehenden Kopf begann und dort verschwand. Spielregeln und Pause tragen ihren Innenabstand deshalb im
   Kopf und im Rumpf (`.sheet-body`), nicht mehr im Blatt selbst — so wie die anderen Blätter es schon tun. */
#help-dialog, #pause-dialog { padding: 0 0 20px; }
#pause-dialog .sheet-top { padding: 24px 24px 12px; }
/* Die Spielregeln tragen jetzt dieselbe Kopfzeile wie die anderen Blätter, mitsamt Schliessen-Knopf. Der ist
   zugleich das erste fokussierbare Element, sodass der Fokus beim Öffnen dort landet statt im Text. */
#help-dialog .sheet-head { padding: 24px 24px 12px; }
/* Kleiner als die 30 px eines gewöhnlichen Blatt-Titels: Neben dem Schliessen-Knopf bliebe sonst zu wenig Breite,
   und „So wird gespielt" bräche auf zwei Zeilen. Dieselbe Größe wie in den Einstellungen. */
#help-dialog .sheet-head h2 { font-size: 26px; margin: 2px 0 0; }
#help-dialog .sheet-top .nova-line { margin: 0 24px 12px; }
#help-dialog .sheet-top h2, #pause-dialog .sheet-top h2 { margin-bottom: 12px; }
.sheet-body { padding: 0 24px; }
.sheet-body > :first-child { margin-top: 0; }
/* Sehr flache Fenster im Querformat: Dort frisst ein stehender Kopf zu viel Höhe. Er bleibt trotzdem stehen —
   gerade dort rollt am meisten (fast 900 px), Nova würde also am weitesten mitwandern. Statt ihn rollen zu lassen,
   wird er schlank: kleinerer Titel, engere Zeile, kleinere Figur. */
@media (orientation: landscape) and (max-height: 520px) {
  .sheet-top .sheet-head { padding: 10px 16px 6px; }
  .sheet-top h2 { font-size: 20px; }
  .sheet-top .nova-line { font-size: 12px; padding: 4px 10px 4px 4px; margin-bottom: 4px; }
  .sheet-top .nova-small { width: 34px; height: 34px; }
  #pause-dialog .sheet-top { padding: 14px 24px 8px; }
  #help-dialog .sheet-head { padding: 14px 24px 6px; }
}
.group { padding: 4px 20px 10px; }.group h3 { margin: 10px 0 6px; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.row { display: flex; align-items: center; gap: 12px; min-height: 60px; padding: 8px 10px; border-radius: 16px; background: #ffffff08; margin-bottom: 6px; cursor: pointer; }@media(hover:hover) { label.row:hover { background: #ffffff10; } }
.row-icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 12px; background: color-mix(in srgb, var(--c) 18%, transparent); color: var(--c); flex: 0 0 auto; }
.row-body { flex: 1; min-width: 0; }.row-body span, .row-body label { display: block; font-weight: 700; font-size: 14px; }.row-body small { display: block; color: var(--muted); font-size: 11px; margin-top: 2px; }
.row-body .name-field { width: 100%; margin-top: 6px; }.settings .device-box { margin: 6px 20px 10px; padding: 12px 14px; }.settings .device-box p { font-size: 12px; margin: 4px 0 10px; }.settings .primary { width: calc(100% - 40px); margin: 6px auto 0; }.settings .danger { margin-top: 0; }
.inventory { display: grid; grid-template-columns: repeat(3,1fr); gap: 8px; }.inventory div { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px 6px; border-radius: 14px; background: #ffffff08; font-size: 11px; color: var(--muted); }.inventory b { font-size: 20px; color: white; }.inventory b i { font-style: normal; font-size: 12px; font-weight: 700; color: var(--muted); }.inventory div.full b i { color: var(--gold); }.inventory div.full { background: #ffffff12; box-shadow: inset 0 0 0 1px var(--c); }.inventory svg { color: var(--c); filter: drop-shadow(0 0 6px var(--c)); }
/* 🚨 DIESE REGEL MUSS HINTER `.inventory` STEHEN — und zwar genau deshalb, weil sie dieselbe Spezifität hat:
   eine Klasse. Bei Gleichstand gewinnt die SPÄTERE Regel. Erst stand sie oben im Spiel-Abschnitt, und damit
   war sie tot: `.inventory` setzte drei Spalten und Kachelform zurück, der Vorrat wurde quer 140 px hoch
   statt 34, und „Weiterspielen" stand 49 px unter dem Fensterrand. Im Quelltext sah die Überschreibung
   dabei völlig richtig aus — genau diesen Fehler hat diese Datei schon mehrfach gehabt.
   In der Pause zählt jeder Punkt Höhe, also: eine Zeile aus Symbol und Zahl, vier nebeneinander. */
.pause-stock { margin: 0 0 6px; grid-template-columns: repeat(4,1fr); gap: 6px; }
.pause-stock div { flex-direction: row; justify-content: center; gap: 5px; padding: 6px 4px; }
.pause-stock b { font-size: 16px; }.pause-stock b i { font-size: 11px; }
dialog p, dialog li { color: var(--muted); line-height: 1.6; }dialog li { margin-bottom: 10px; }dialog li b { color: var(--ink); }
.primary, .wide { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 48px; padding: 12px; border-radius: 16px; margin-top: 10px; background: #285061; }
.primary { background: linear-gradient(#acffd0,#7bd7b6); color: #17263c; font-weight: 800; border-color: #d6ffe8; box-shadow: 0 4px 0 #995335; }
.primary:active { box-shadow: 0 1px 0 #995335; }.hotfix { background: linear-gradient(#ffe9a3,#ffb347); border-color: #fff1c8; box-shadow: 0 4px 0 #7a4a10; color: #3a2000; }@media(hover:hover) { .wide:hover { background: #55467a; } }.danger { color: #ffb3c0; background: transparent; border-color: #ff5d7344; font-size: 12px; min-height: 40px; }.app-version { margin: 8px 0 0; text-align: center; color: var(--muted); font-size: 11px; letter-spacing: .08em; }
.setting { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 54px; }
.name-field { display: flex; align-items: center; gap: 8px; width: 60%; }.name-field input { flex: 1; }
input[type=text], input:not([type]) { min-width: 0; width: 100%; padding: 10px; background: #0d2938; color: white; border: 1px solid var(--line); border-radius: 10px; font-size: 16px; }
.switch { appearance: none; -webkit-appearance: none; width: 48px; height: 28px; border-radius: 14px; background: #3a325d; position: relative; cursor: pointer; transition: background .25s; margin: 0; flex: 0 0 auto; }
.switch::before { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: white; transition: transform .25s cubic-bezier(.3,1.4,.5,1); box-shadow: 0 2px 6px #0006; }
.switch:checked { background: var(--cyan); }.switch:checked::before { transform: translateX(20px); }
.device-box { margin: 14px 0 6px; padding: 14px; border-radius: 16px; background: #0d293899; border: 1px solid var(--line); }
.device-box p { font-size: 12px; margin: 6px 0 10px; }
.code-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.code-row code { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 15px; letter-spacing: .1em; padding: 10px; background: #091f2d; border-radius: 10px; color: var(--cyan); text-align: center; user-select: all; -webkit-user-select: all; }
.mini { min-height: 44px; min-width: 44px; padding: 8px 12px; border-radius: 12px; background: #285061; display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 700; }
.import-status { font-size: 12px; min-height: 1em; margin: 0; }.import-status.ok { color: var(--green); }.import-status.error { color: #ffb3c0; }
.help-modules { display: grid; grid-template-columns: repeat(3,1fr); gap: 8px; margin: 6px 0 14px; }
.help-modules div { display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: 11px; color: var(--muted); }.help-modules canvas { width: 40px; height: 40px; }

/* ── Result ───────────────────────────────────────────────────────────── */
.result { width: 100%; height: 100%; max-width: 100vw; max-height: 100vh; max-height: 100dvh; margin: 0; padding: 16px; border: 0; border-radius: 0; background: transparent; box-shadow: none; display: none; place-items: center; overflow: hidden; }
.result[open] { display: grid; animation: none; }
.result-fx { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; }
@keyframes resultIn { from { opacity: 0; transform: translateY(40px) scale(.85); } to { opacity: 1; transform: none; } }
@keyframes stampIn { from { opacity: 0; transform: scale(2.4) rotate(-8deg); } 60% { opacity: 1; transform: scale(.94) rotate(2deg); } to { transform: scale(1) rotate(-2deg); } }
@keyframes starPop { 0% { transform: scale(0) rotate(-40deg); } 60% { transform: scale(1.35) rotate(8deg); } 100% { transform: scale(1) rotate(0); } }
@keyframes glow { 50% { filter: drop-shadow(0 0 16px var(--gold)) brightness(1.2); } }
@keyframes resultFade { from { opacity: 0; } to { opacity: 1; } }
.result.nova-arriving .result-card, .result.nova-arrived .result-card { animation: resultFade .28s ease both; }
.result-card { position: relative; width: min(94vw,440px); max-width: calc(100vw - var(--sa-links) - var(--sa-rechts) - 20px); max-height: calc(var(--vvh,100dvh) - 32px - var(--sa-oben) - var(--sa-unten)); overflow-y: auto; border: 1px solid #a2cdd866; border-radius: 28px; padding: 24px; background: linear-gradient(#204757,#102e40); color: var(--ink); box-shadow: 0 24px 90px #000a; text-align: center; animation: resultIn .5s cubic-bezier(.2,.9,.3,1.15) both; }
.stamp { display: inline-block; margin: 0; padding: 6px 14px; border: 3px solid var(--green); border-radius: 10px; color: var(--green); font-weight: 900; letter-spacing: .2em; font-size: 12px; transform: rotate(-2deg); animation: stampIn .55s cubic-bezier(.2,.9,.3,1) .25s both; }
.result.lose .stamp { color: var(--red); border-color: var(--red); }
/* Stars and score share one row: the eye reads both at once, and the card stays short. */
.result-score-row { display: flex; justify-content: center; align-items: center; gap: 18px; margin: 8px 0 0; }
.result-stars { display: flex; justify-content: center; align-items: center; gap: 2px; margin: 0; }.result-stars .star { width: 32px; height: 32px; }.result-stars .star:nth-child(2) { width: 42px; height: 42px; }
.result-points { text-align: left; }.result-stars[hidden] + .result-points { text-align: center; }
.result-stars .star { color: #ffffff22; transform: scale(.9); }
.result-stars .star.lit { color: var(--gold); animation: starPop .55s cubic-bezier(.3,1.4,.5,1) var(--d,0s) both, glow 2s ease-in-out calc(var(--d,0s) + .6s) infinite; }
.result-score-label { margin: 0; font-size: 10px; letter-spacing: .2em; color: var(--muted); }
.result-score { margin: 0; line-height: 1.05; font-size: 34px; font-weight: 900; font-variant-numeric: tabular-nums; letter-spacing: -.03em; background: linear-gradient(#fff,#ffd35c); -webkit-background-clip: text; background-clip: text; color: transparent; }
.result-stats { display: grid; grid-template-columns: repeat(4,1fr); gap: 4px; margin: 8px 0 0; }
.result-stats div { background: #ffffff0c; border-radius: 10px; padding: 5px 3px; }.result-stats b { display: block; font-size: 15px; line-height: 1.2; }.result-stats small { font-size: 10px; letter-spacing: .08em; color: var(--muted); line-height: 1.2; display: block; }
.result-rank { margin: 10px 0 0; padding: 10px; border-radius: 12px; background: #2f6a5a55; border: 1px solid #95f4bb66; color: var(--ink); font-size: 14px; animation: rise .4s ease backwards; }
.result-rank b { color: var(--green); font-size: 18px; }.result-rank small { display: block; color: var(--muted); font-size: 11px; }
.result-name { margin: 10px 0 0; text-align: left; }.result-name label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.result-actions { margin-top: 8px; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 6px; }.result-actions .primary { grid-column: span 2; }.result-actions button { margin-top: 0; }.result-actions .wide { font-size: 14px; padding-left: 10px; padding-right: 10px; white-space: nowrap; }
.result.lose .result-card { animation: resultIn .5s cubic-bezier(.2,.9,.3,1.15) both, shake .5s ease .5s; }
.splash.leaving { opacity: 0; transition: opacity .28s ease; pointer-events: none; }
/* Im Blatt bleibt der Streifen am FENSTER stehen (`position: fixed` wie sonst auch) — er hängt nur im Blatt,
   damit er mit ihm im Top Layer liegt. 🚨 NICHT `position: absolute`: Ein Blatt rollt (`overflow-y: auto`),
   und dann meint „unten" das Ende des gerollten INHALTS, nicht die sichtbare Kante — gemessen landete der
   Streifen so 253 px über dem oberen Bildrand. */
.toasts { position: fixed; left: 50%; bottom: max(24px, var(--sa-unten)); transform: translateX(-50%); z-index: 60; display: flex; flex-direction: column-reverse; align-items: center; gap: 6px; width: max-content; max-width: 92vw; pointer-events: none; }
.toast { display: inline-flex; align-items: center; gap: 8px; background: #102e40f0; border: 1px solid var(--line); padding: 10px 16px; border-radius: 14px; font-size: 13px; animation: rise .3s ease backwards; pointer-events: none; }
.toast svg { color: var(--gold); flex: 0 0 auto; }.toast.quest svg { color: #ffb0ff; }.toast.rank svg { color: var(--cyan); }.toast.gift svg { color: var(--green); }.toast.streak svg { color: #ff9c57; }

/* ── Responsive ───────────────────────────────────────────────────────── */
@media(max-width:1000px), (orientation:portrait) {
  .game { grid-template-columns: minmax(0,1fr); grid-template-rows: auto minmax(0,1fr); padding: 0 0 8px; gap: 0; }
  /* The head of the phone screen is plain page background: no card, no gradient band, no blur. */
  .hud-panel { align-self: stretch; padding: 10px 14px 8px; border: 0; border-radius: 0; background: none; backdrop-filter: none; }
  body[data-screen="game"] .top { display: none; }
  .level-heading { grid-template-columns: 56px 1fr auto; gap: 0 12px; width: min(100%,500px); margin: 0 auto 8px; }.heading-text { display: block; }.level-heading h2 { font-size: 17px; line-height: 1.15; margin: 1px 0 0; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.level-heading .eyebrow { font-size: 10px; }.nova-hud { width: 56px; height: 56px; }.nova-chip { font-size: 13px; padding: 6px 11px; }
  .hud-stats { grid-template-columns: 72px minmax(0,1fr) auto; gap: 14px; max-width: 500px; margin: auto; }
  .moves-stat { padding: 6px 4px; border-radius: 20px; }.moves-stat b { font-size: 30px; }.score-stat b { font-size: 24px; }.combo-stat { grid-column: auto; text-align: right; min-width: 56px; }.combo-stat b { font-size: 20px; }
  .goals { justify-content: center; margin: 10px auto 0; max-width: 580px; }.goal { flex: 0 1 auto; padding: 3px 10px 3px 3px; font-size: 11.5px; }.goal canvas { width: 28px; height: 28px; }
  .side-card { display: none; }.board-wrap { padding: 0; }
  /* 🚨 DAS BODENBLATT IST EINE HOCHKANT-FORM. Die Regel galt für jeden Bildschirm unter 1000 px, also auch
     für ein gekipptes Handy: Dort wurde daraus ein 844 px breites, 366 px hohes Band über die ganze Breite,
     dessen Text unter der Kamera lag und das nach unten aus dem Bild lief. Quer ist ein mittiges Blatt die
     richtige Form — genau wie bei den Spielregeln und den Missionen, die quer immer schon gut standen. */
  .settings { width: 100%; max-width: none; margin: auto 0 0; border-radius: 26px 26px 0 0; max-height: calc(var(--vvh,100dvh) - 24px - var(--sa-oben)); padding-bottom: max(16px, var(--sa-unten)); }
}
@media(orientation:portrait) {
  .level-heading { --nova-size: 56px; grid-template-rows: var(--nova-size); }
  .level-heading > .nova-hud { grid-area: 1 / 1; }
  .level-heading > .heading-text, .level-heading > .nova-chip { grid-area: 1 / 2; }
  .level-heading > .head-tools { grid-area: 1 / 3; }
  .nova-chip { max-height: 100%; min-height: 0; overflow: auto; overscroll-behavior: contain; }
  .nova-chip::before { display: none; }
}
@media(orientation:portrait) and (min-height:760px) {
  .level-heading { --nova-size: 64px; }
}
@media(orientation:portrait) and (max-height:650px) {
  .level-heading { --nova-size: 40px; }
}
@media(max-width:1000px) and (orientation:landscape) {
  .settings { width: min(92vw,520px); max-width: calc(100vw - var(--sa-links) - var(--sa-rechts) - 24px); margin: auto; border-radius: 26px; max-height: calc(var(--vvh,100dvh) - 24px - var(--sa-oben) - var(--sa-unten)); padding-bottom: 16px; }
}
/* A phone board is limited by width, so on a tall screen vertical slack is left over no matter what.
   Spend it on what is read: bigger numbers, bigger goal pills, a bigger Nova. NICHT auf die Leiste unten —
   die bekam hier einmal 88 px und 66 px hohe Knöpfe und sah danach aus, als wäre sie das eigentliche Spiel. */
@media(max-width:1000px) and (min-height:760px), (orientation:portrait) and (min-height:760px) {
  .game { grid-template-rows: auto minmax(0,1fr); }
  .moves-stat b { font-size: 34px; }.score-stat b { font-size: 28px; }.combo-stat b { font-size: 22px; }
  .level-heading { grid-template-columns: 64px 1fr auto; margin-bottom: 10px; }.nova-hud { width: 64px; height: 64px; }.level-heading h2 { font-size: 19px; }
  .goal { font-size: 12.5px; padding: 5px 12px 5px 5px; }.goal canvas { width: 32px; height: 32px; }
}
/* 🚨 TABLET HOCHKANT. Seit das Hochformat unabhängig von der Breite das Handy-Raster bekommt, steht auf einem iPad
   ein bildschirmbreites Brett unter einer Kopfleiste in Handygröße (500 px). Beides wächst hier mit: Die Kopfleiste
   wird breiter und größer, das Brett bekommt einen Rand, damit es nicht an der Gehäusekante klebt. */
@media(orientation:portrait) and (min-width:700px) {
  .game { padding: 0 28px 24px; }
  .level-heading { grid-template-columns: 76px 1fr auto; width: min(100%,720px); --nova-size: 76px; }.nova-hud { width: 76px; height: 76px; }
  .level-heading h2 { font-size: 22px; }.nova-chip { font-size: 15px; }.head-tools .round-button { width: 44px; height: 44px; }
  .hud-stats { grid-template-columns: 92px minmax(0,1fr) auto; gap: 20px; max-width: 720px; }.hud-stats small { font-size: 12px; }
  .moves-stat b { font-size: 42px; }.score-stat b { font-size: 36px; }.combo-stat b { font-size: 28px; }
  .goals { max-width: 760px; gap: 8px; }.goal { font-size: 14px; padding: 6px 14px 6px 6px; }.goal canvas { width: 38px; height: 38px; }
}
.intro-goals .assist { color: var(--green); font-size: 12.5px; font-weight: 700; }
@media(max-width:380px) {
  .top { padding: 0 10px; }.board-tabs small { display: none; }.board-tabs button { min-height: 42px; }
  .result-card { padding: 18px; }.node { --w: 84px; }.node-disc { width: 52px; height: 52px; }
}
@media(max-height:650px) and (orientation:portrait) {

.game { grid-template-rows: auto minmax(0,1fr); }
  .hud-panel { padding-top: 4px; }.level-heading { grid-template-columns: 40px 1fr auto; gap: 0 8px; margin-bottom: 4px; }.nova-hud { width: 40px; height: 40px; }.level-heading h2 { font-size: 14px; }.level-heading .eyebrow { font-size: 10px; }.nova-chip { font-size: 11.5px; padding: 4px 9px; }
  /* Short portrait phones: the whole card, Nova included, has to fit without scrolling. */
  .result-card { padding: 12px 14px; }.result-hero { grid-template-columns: 52px minmax(0,1fr) auto; column-gap: 10px; }.result-nova-dock { width: 52px; height: 52px; }.result-hero h2 { font-size: 17px; }.result-bubble { font-size: 11.5px; padding: 5px 9px; margin-top: 6px; }
  .result-stars .star { width: 28px; height: 28px; }.result-stars .star:nth-child(2) { width: 36px; height: 36px; }.result-score-label { display: none; }.result-score { font-size: 28px; }.result-score-row { margin-top: 4px; }
  .result-stats { gap: 4px; margin: 4px 0; }.result-stats b { font-size: 14px; }.result-stats small { font-size: 10px; }.result-stats div { padding: 4px 3px; }.result-wish { font-size: 11px; padding: 4px 10px; margin-top: 4px; }.result-xp { padding: 5px 10px; font-size: 11px; }.result-progress { margin-top: 4px; }
  .result-name { margin-top: 6px; }.result-actions { gap: 4px; margin-top: 6px; }.result-actions button { min-height: 40px; padding-top: 6px; padding-bottom: 6px; }.stamp { font-size: 11px; padding: 4px 10px; }
}
@media(orientation:landscape) and (max-height:600px) {
  .top { flex-basis: 40px; }.top .round-button { width: 36px; height: 36px; }
  /* 🚨 IM SPIEL BLEIBT DIE MARKENLEISTE AUCH QUER WEG. Sie zeigt dort nur das App-Symbol — und das IST Nova.
     Neben ihrer Figur im Kopf stand sie damit zweimal auf dem Schirm; gemeldet mit Bild: „Einmal Nova und
     einmal Nova App Icon." Der Knopf darin (zurück) ist im Spiel ohnehin versteckt, und Pause steht seit dem
     Umbau im Kopf. Es geht also nichts verloren, und das Brett gewinnt 40 Punkte Höhe — genau in der Lage,
     die am wenigsten davon hat. (Hoch war die Leiste im Spiel längst weg, quer holte diese Zeile sie zurück.) */
  /* 🚨 DREI SPALTEN QUER: ZAHLEN LINKS, BRETT IN DER MITTE, ZIELE RECHTS. Gemeldet mit Bild: „Rechte Seite ist
     fast gar nichts. Da könnte man doch das platzieren wo man sieht was man noch braucht?" Vorher stapelten
     sich Kopf, Zahlen UND vier Ziele in einer 150-px-Spalte links, während rechts vom Brett nichts stand.
     Das Brett verliert dadurch NICHTS: Quer ist es höhenbegrenzt, die Breite daneben hatte es ohnehin übrig.
     Und zwei gleich breite Randspalten halten es in der Mitte, auch wenn es (endlos, Zeitspiel) gar keine
     Ziele gibt. */
  .game { grid-template-columns: clamp(148px,20vw,180px) minmax(0,1fr) clamp(148px,20vw,180px); grid-template-rows: minmax(0,1.15fr) minmax(0,.85fr); padding: 0 8px 8px; gap: 4px 8px; }
  /* `display: contents` löst nur die Karte auf, nicht ihren Inhalt: Kopf, Zahlen und Ziele bekommen damit
     eigene Gitterplätze in `.game`. Ein Kasten drumherum gibt es quer ohnehin nicht (`background: none`). */
  .hud-panel { display: contents; }
  .level-heading { grid-column: 1; grid-row: 1; align-self: end; }
  .hud-stats { grid-column: 1; grid-row: 2; align-self: start; }/* `margin: auto` aus der Handy-Regel schrumpft die Zahlen auf ihren Inhalt und stellt sie mittig — in einer
     148-px-Spalte bleiben davon 102 px, und die Sternleiste unter den Punkten wird zum Stummel. Quer soll
     die Spalte gefüllt werden. */
  .hud-stats { grid-template-columns: 60px minmax(0,1fr); gap: 8px; margin: 0; max-width: none; }
  .combo-stat { grid-column: span 2; text-align: center; }
  .level-heading { grid-template-columns: minmax(0,1fr) 40px; grid-template-rows: 88px 60px; gap: 6px; margin-bottom: 4px; }
  .level-heading > .nova-hud { grid-area: 1 / 1; width: 88px; height: 88px; justify-self: center; }
  .level-heading > .heading-text, .level-heading > .nova-chip { grid-area: 2 / 1 / 3 / 3; }
  .heading-text { text-align: center; }.heading-text .eyebrow { display: none; }
  .head-tools { grid-area: 1 / 2; flex-direction: column; justify-self: end; gap: 6px; margin: 0; }
  .head-tools .round-button { width: 40px; height: 40px; }
  .level-heading h2 { font-size: 16px; margin: 0; white-space: normal; }
  .nova-chip { font-size: 12px; padding: 5px 8px; max-height: 60px; overflow: auto; overscroll-behavior: contain; }
  .nova-chip::before { display: none; }
  .goals { grid-column: 3; grid-row: 1 / -1; align-self: center; flex-direction: column; flex-wrap: nowrap; gap: 5px; margin: 0; max-height: 100%; overflow: auto; scrollbar-width: none; }
  .goals::-webkit-scrollbar { display: none; }
  .goal { width: 100%; }
  .board-wrap { grid-column: 2; grid-row: 1 / -1; }
  .side-card { display: none; }.run-panel { display: none; }

.result-card { width: min(94vw,680px); padding: 14px 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; align-items: center; }.result-main { text-align: center; }
  .result-nova-dock { width: 80px; height: 80px; }.result-hero { grid-template-columns: 80px minmax(0,1fr) auto; }.result-hero h2 { font-size: 24px; }.result-score-row { justify-content: flex-start; margin-top: 12px; }.result-score { font-size: 34px; }.result-stats { margin: 0; }.result-stats b { font-size: 15px; }.result-rank { margin-top: 6px; padding: 6px 10px; font-size: 12px; }.result-actions { margin-top: 4px; }.result-actions .primary, .result-actions .wide { min-height: 40px; margin-top: 6px; padding: 6px; }
}

@media(prefers-reduced-motion:reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
body.reduced *, body.reduced *::before, body.reduced *::after { animation: none !important; transition: none !important; }

/* ── iOS standalone cold-start viewport (same bug Kellerkind, KelRaid and Odyssee document) ──────────────
   On launch as an installed app iOS reports the viewport used by position:fixed / inset:0 / dvh one safe-area
   strip SHORT until a rotation forces a recompute. Odyssee and Kellerkind size html/body by 100lvh so the page
   canvas still covers the whole screen. The seam itself is handled by the single --void colour above, not by
   geometry, which is why nothing interactive is stretched to 100lvh here. */
@media (display-mode: standalone) {
  /* Only the page itself is sized by 100lvh. The shell must NOT be: it is a flex column whose last child is the
     control dock, and at cold start iOS's visible viewport is one status bar SHORTER than 100lvh — a taller shell
     pushes the dock off the screen. It keeps inset:0 so it always equals the visible area and the dock stays
     reachable; the strip iOS paints above it is already the same --void colour, so nothing shows as a seam. */
  html, body { height: 100lvh; }}

/* ── Press feedback ──────────────────────────────────────────────────────────────────────────────────
   On a phone every control felt dead: iOS does not apply :active for touch, and the native tap highlight
   is switched off above. app.mjs therefore sets .pressed from pointer events. The transform needs
   !important because element:hover rules (higher specificity) and any animation fill both outrank a
   plain class declaration. */
/* transition-duration 0 only while pressed: the button sinks in on the same frame as the touch and eases
   back out once the class goes again. Buttons with a hard 3D shadow are pushed DOWN by exactly that
   shadow height and lose it, which reads as a physical press; flat buttons shrink a touch and tint.
   No brightness filter: it blew out the gradients (the green play button went almost white). */
/* Never scale a pressed element: iOS rasterises the layer at the smaller size and keeps that blurry raster after
   the press ends (the back button stayed soft). Presses move down instead. */
.pressed { transition-duration: 0s !important; transform: translateY(2px) !important; filter: brightness(.93); }
.node.pressed .node-disc { transform: translateY(4px); box-shadow: 0 1px 0 #08283a, 0 0 0 4px #ffffff14; filter: brightness(1.08); }
.primary.pressed { transform: translateY(4px) !important; box-shadow: 0 0 0 #995335; filter: brightness(.97); }
.hotfix.pressed { box-shadow: 0 0 0 #7a4a10; }
/* Die Fußzeile im Menü (Einstellungen, Spielregeln, Shop) hat keinen eigenen Grund. Gedrückt bekam sie hier
   bisher denselben harten `#ffffff2a`-Kasten wie ein runder Knopf — ohne Rundung sah das aus wie ein
   Auswahlrahmen, gemeldet als „so eine Umrandung". Jetzt: gerundet (siehe oben), leiser Schimmer, helle Schrift. */
.round-button.pressed, .mini.pressed { transform: translateY(2px) !important; background: #ffffff2a; filter: none; }
.board-tabs button.pressed, .wide.pressed, .danger.pressed { transform: translateY(2px) !important; background: #315d70; filter: none; }
.board-tabs button.active.pressed { background: #5ed3ee; }

/* Objective progress stays inside the existing pills, preserving the mobile board area. */
.goal { position: relative; overflow: hidden; padding-bottom: 8px; }
.goal progress { appearance: none; -webkit-appearance: none; position: absolute; bottom: 0; left: 0; width: 100%; height: 3px; border: 0; background: #ffffff12; color: var(--goal-color); }
.goal progress::-webkit-progress-bar { background: #ffffff12; }
.goal progress::-webkit-progress-value { background: var(--goal-color); transition: width .3s ease; }
.goal progress::-moz-progress-bar { background: var(--goal-color); }
.goal.done { --goal-color: var(--green); }
.match-guide { display: grid; gap: 8px; margin: 18px 0; }
.match-guide > div { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px; background: #ffffff08; border: 1px solid #ffffff20; border-radius: 14px; padding: 12px; }
.match-guide b { color: var(--gold); font-size: 12px; }
.match-guide strong { text-align: right; color: var(--cyan); }
.match-guide span { grid-column: 1 / -1; font-size: 13px; color: var(--muted); }
#help-dialog details { padding: 12px 0; border-top: 1px solid var(--line); font-size: 14px; line-height: 1.6; }
#help-dialog summary { cursor: pointer; font-weight: 800; padding: 4px 0; }
#help-dialog p, .pause-objective { color: var(--muted); line-height: 1.6; }
@media (prefers-reduced-motion: reduce) { .goal progress::-webkit-progress-value { transition: none; } }
body.reduced .goal progress::-webkit-progress-value { transition: none; }

/* ── v18: rank, missions, chapters, achievements with progress, level preview ───────────────────── */
/* 🚨 AUF DER FORTSCHRITTS-SEITE KOMMEN DIE LEVEL ZUERST. Vom Betreiber gemeldet, mit Foto: „diese seite ist
   mobile unbenutzbar" — Rang, Vertrauen, Kiste, zwei Bücher und sechs Zahlen standen ÜBER der Levelkarte und
   füllten auf einem iPhone die ganzen ersten 507 von 844 Pixeln. Wer die Seite öffnet, will ein Level wählen.
   Alles andere liegt seitdem in `#campaign-extra` UNTER der Karte (am Rechner in der rechten Spalte). */
.campaign-extra { margin-top: 18px; }
/* Die Karten richten sich nach dem Platz, den sie WIRKLICH haben: zwei nebeneinander auf einem Handy, eine
   untereinander in der schmalen rechten Spalte am Rechner. Feste zwei Spalten liessen die Titel dreizeilig brechen. */
.campaign-bars { display: grid; grid-template-columns: repeat(auto-fit,minmax(168px,1fr)); gap: 8px; margin: 0 0 10px; }
/* The diary: a bookmark-like button on the campaign screen, a sheet with every collected story page inside. */
/* 🚨 NOTIZBUCH UND TAGEBUCH SIND EINSTIEGE, KEINE STATISTIK. Gemeldet: „Notizbuch sieht man vielleicht im
   Browser, aber ich finde es nicht mobil — soll man aber!" Mit v67 waren sie unter die Levelkarte gerutscht,
   auf dem Handy also hinter 40 Level und ~5000 Pixel Weg. Sie stehen jetzt wieder in der Kopfzeile, aber zu
   zweit in EINER Reihe, damit die Karte trotzdem gleich beginnt. Die Zahlen daneben bleiben unten. */
/* Die Karten dürfen schrumpfen (`min-width: 0`): Sonst wuchs `1fr` mit dem Text und lief auf 320 px rechts aus dem
   Bild. Erst unter 300 px (Fold zugeklappt) stehen sie untereinander. */
.head-books { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 2px 0 12px; }
.head-books > * { min-width: 0; }
@media(max-width:300px) { .head-books { grid-template-columns: minmax(0,1fr); } }
.head-books .diary-button { margin: 0; padding: 8px 12px; }
.head-books .diary-button span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.head-books .diary-button small { margin-left: auto; white-space: nowrap; }
/* Auf schmalen Handys passt die Zahl nicht mehr daneben, dann rutscht sie unter den Namen. */
@media(max-width:480px) { .head-books .diary-button { flex-wrap: wrap; row-gap: 0; } .head-books .diary-button small { flex: 1 1 calc(100% - 26px); min-width: 0; margin-left: 26px; white-space: normal; } }
.diary-button { display: flex; align-items: center; gap: 8px; width: 100%; margin: 0 0 10px; padding: 9px 14px; border-radius: 14px; background: linear-gradient(90deg,#7ce9ff1c,#bb9dff14); border: 1px solid #7ce9ff44; color: var(--ink); font-size: 13px; font-weight: 800; text-align: left; }
.diary-button svg { color: var(--cyan); flex: 0 0 auto; }.diary-button span { flex: 1; }.diary-button small { color: var(--muted); font-weight: 600; font-size: 11.5px; }
.diary { padding: 0 0 18px; }.diary-title { display: flex; align-items: center; gap: 12px; }.diary-title h2 { margin: 2px 0 0; font-size: 21px; white-space: nowrap; }.diary-title .nova-small { width: 48px; height: 48px; }
/* 🚨 HINTER DER GRUNDREGEL, nicht im Block für schmale Geräte weiter oben: Bei gleicher Spezifität gewinnt
   die spätere Regel, und die Grundregel steht später in der Datei. Genau daran ist der Deckel für große
   Bildschirme schon einmal wirkungslos gewesen (siehe der Block am Dateiende).
   320 px: Zwischen Novas Dock und dem Schließen-Kreuz bleiben für „Novas Tagebuch" rund 187 px — die Zeile
   braucht 192. Eine Nummer kleiner reicht also NICHT, der Titel stünde weiter als „Novas Tageb…" da. Er
   darf hier deshalb umbrechen; zwei kurze Zeilen lesen sich besser als ein abgeschnittener Name. */
@media(max-width:380px) {
  .diary-title { gap: 9px; }.diary-title .nova-small { width: 40px; height: 40px; }
  .diary-title h2 { font-size: 18px; white-space: normal; }
}
.diary-summary { margin: 0 20px 10px; color: var(--muted); font-size: 13px; }
.diary-body { display: grid; gap: 14px; padding: 0 20px; }
.diary-section { --c: var(--cyan); border-left: 3px solid var(--c); padding-left: 12px; }
.diary-section h3 { margin: 0 0 8px; font-size: 13px; letter-spacing: .08em; color: var(--c); text-transform: uppercase; }
.diary-entry { margin: 0 0 8px; padding: 10px 12px; border-radius: 14px; background: #ffffff0a; border: 1px solid color-mix(in srgb, var(--c) 35%, transparent); font-size: 13px; line-height: 1.45; }
.diary-entry small { display: block; color: var(--c); font-size: 10.5px; letter-spacing: .1em; margin-bottom: 4px; font-weight: 800; }
.diary-entry .after { margin-top: 6px; padding-top: 6px; border-top: 1px dashed color-mix(in srgb, var(--c) 35%, transparent); color: var(--muted); }
.diary-open { margin: 0; color: var(--muted); font-size: 12px; font-style: italic; }
.diary-empty { margin: 0 20px; padding: 16px; border-radius: 14px; background: #ffffff0a; border: 1px dashed var(--line); color: var(--muted); font-size: 13px; text-align: center; }
.result-wish.near { background: #ff9c5718; border-color: #ff9c5766; color: var(--ink); }.result-wish.near svg { color: #ffb47a; }
.bar-card { background: #ffffff0c; border: 1px solid var(--line); border-radius: 14px; padding: 8px 12px; font-size: 12px; }
.bar-card span { display: flex; align-items: center; gap: 6px; }.bar-card span svg { color: var(--gold); }.bar-card b { font-size: 12px; }
.bar-card progress { width: 100%; height: 6px; margin: 6px 0 3px; accent-color: var(--gold); display: block; border-radius: 3px; overflow: hidden; }
#rank-card progress { accent-color: var(--cyan); }#rank-card span svg { color: var(--cyan); }
.bar-card small { color: var(--muted); font-size: 10.5px; }
.chapter { --i: 0; --c: var(--cyan); position: absolute; left: 4%; right: 4%; display: grid; grid-template-columns: 1fr auto; gap: 0 10px; align-items: center; padding: 10px 14px; border-radius: 18px; background: linear-gradient(120deg, color-mix(in srgb, var(--c) 22%, #16123b), #16123bf0); border: 1px solid color-mix(in srgb, var(--c) 55%, transparent); box-shadow: 0 6px 24px #0006; animation: rise .45s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 45ms); }
.chapter-no { grid-column: 1; font-size: 10px; letter-spacing: .18em; font-weight: 800; color: var(--c); }
.chapter strong { grid-column: 1; font-size: 16px; line-height: 1.1; }.chapter small { grid-column: 1; color: var(--muted); font-size: 11px; line-height: 1.3; margin-top: 2px; }
.chapter em { grid-column: 2; grid-row: 1 / 4; font-style: normal; font-size: 11px; font-weight: 700; color: var(--gold); text-align: right; display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.chapter.locked { opacity: .6; }.chapter.locked em { color: var(--muted); }.chapter.done { border-color: var(--gold); }.chapter.done em { color: var(--green); }
.ach-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }.ach-count { color: var(--gold); font-size: 12px; font-weight: 700; }
.achievement-groups { display: grid; gap: 6px; }
.ach-group { --i: 0; animation: rise .45s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 60ms + 120ms); }
.ach-group h3 { display: flex; justify-content: space-between; align-items: baseline; margin: 10px 0 6px; font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--cyan); }.ach-group h3 span { color: var(--muted); letter-spacing: 0; text-transform: none; font-weight: 600; }
.ach { align-items: start; }.ach > div { min-width: 0; }
.ach progress { display: block; width: 100%; height: 4px; margin: 6px 0 2px; accent-color: var(--gold); border-radius: 2px; overflow: hidden; }
.ach small { display: block; font-size: 10px; color: var(--muted); font-variant-numeric: tabular-nums; }.ach.earned small { color: var(--green); }
.level-sheet { padding: 0 0 16px; }.level-sheet h2 { margin: 2px 0 0; font-size: 24px; }.level-body { padding: 4px 20px 6px; }
.level-intro-text { margin: 0 0 12px; font-size: 14px; line-height: 1.55; color: var(--ink); }
.level-goals { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.level-goals span { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px 4px 4px; border-radius: 14px; background: #061d2b66; border: 1px solid #ffffff15; font-weight: 800; color: var(--gold); font-size: 13px; }.level-goals canvas { width: 34px; height: 34px; }
.level-obstacles { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.chip { display: inline-flex; align-items: center; gap: 4px; padding: 5px 10px; border-radius: 12px; background: #ffffff0c; border: 1px solid var(--line); font-size: 12px; color: var(--muted); }.chip b { color: var(--ink); }
.level-best { font-size: 13px; color: var(--muted); margin-bottom: 8px; }.level-best b { color: var(--ink); }.level-best em { font-style: normal; color: var(--green); }
.level-star-list { display: flex; gap: 8px; }
.level-star-list span { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 4px; padding: 6px; border-radius: 12px; background: #ffffff08; font-size: 12px; font-weight: 700; color: var(--muted); }
.level-star-list span svg { color: #ffffff30; }.level-star-list span.lit { color: var(--ink); background: #ffd35c14; }.level-star-list span.lit svg { color: var(--gold); filter: drop-shadow(0 0 4px var(--gold)); }
.level-sheet .primary { width: calc(100% - 40px); margin: 8px auto 0; }
.quest-sheet { padding: 0 0 16px; }.quest-sheet h2 { margin: 2px 0 0; font-size: 24px; }.quest-intro { margin: 4px 20px 10px; font-size: 13px; }
.quest-list { display: grid; gap: 8px; padding: 0 20px; }
.quest { --i: 0; display: grid; grid-template-columns: 38px 1fr auto; gap: 10px; align-items: center; padding: 10px 12px; border-radius: 16px; background: #ffffff08; border: 1px solid var(--line); animation: rise .4s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i) * 60ms); }
.nova-ask { text-align: center; }
.ask-head { display: grid; place-items: center; margin-bottom: 4px; }.nova-ask .nova-big { width: 110px; height: 110px; }
.nova-ask h2 { font-size: 21px; line-height: 1.35; margin: 6px 0 16px; }
.ask-options { display: grid; gap: 8px; }
.ask-options button { min-height: 52px; padding: 10px 16px; border-radius: 16px; background: linear-gradient(150deg,#285061,#102e40); box-shadow: 0 3px 0 #061824; font-size: 15px; font-weight: 700; color: var(--ink); }
@media(hover:hover) { .ask-options button:hover { filter: brightness(1.15); } }
.ask-reply { margin: 14px 0 0; padding: 10px 14px; border-radius: 16px; background: #7ce9ff14; border: 1px solid #7ce9ff44; font-size: 14px; line-height: 1.45; color: var(--ink); }
.ask-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }.ask-actions button { margin: 0; font-size: 12.5px; }
.ask-name { margin: 0 0 12px; text-align: left; }.ask-name label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.book-list { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; margin: 10px 0 16px; }
/* 🚨 NOVAS NOTIZBUCH STAND AM RAND. Es ist mit den Klassen der Bildschirm-Listen gebaut (`.list-summary`,
   `.book-list`); dort bringt der Bildschirm seinen Innenabstand mit. Als Blatt steht es auf `.diary`, und das
   hat `padding: 0` — Zusammenfassung, Karten und Knopf klebten mit 1 px am Rand, während das Tagebuch nebenan
   seine 20 px hat. Gemeldet: „Hier fehlt auch Abstand bei den Karten und Text oben." */
#nova-book-dialog .list-summary { margin: 4px 20px 12px; }
#nova-book-dialog .book-list { margin: 0 20px 16px; }
#nova-book-dialog .primary { width: calc(100% - 40px); margin: 0 auto; }
.book-entry { display: flex; flex-wrap: wrap; min-width: 0; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 10px 14px; border-radius: 14px; background: #ffffff0c; border: 1px solid var(--line); text-align: left; font-size: 13px; color: var(--ink); }
.book-entry small { display: block; color: var(--muted); font-size: 11px; margin-top: 2px; }
.book-entry > div { flex: 1 1 140px; min-width: 0; }
.book-entry b { font-size: 13.5px; color: var(--cyan); overflow-wrap: anywhere; }
.book-entry.open b { color: var(--muted); }.book-entry.locked { opacity: .5; }
.weekly { display: block; margin: 0 0 14px; padding: 12px 14px; border-radius: 16px; background: linear-gradient(140deg,#2a4a6b55,#1b2f4a55); border: 1px solid #7ce9ff44; }
.weekly b { display: block; margin: 6px 0 8px; font-size: 15px; line-height: 1.3; }
.weekly progress { --bar: var(--cyan); width: 100%; height: 8px; display: block; border-radius: 4px; overflow: hidden; appearance: none; -webkit-appearance: none; border: 0; background: #ffffff18; color: var(--bar); accent-color: var(--cyan); }
.weekly progress::-webkit-progress-bar { background: #ffffff18; border-radius: 4px; }.weekly progress::-webkit-progress-value { background: var(--bar); border-radius: 4px; }.weekly progress::-moz-progress-bar { background: var(--bar); border-radius: 4px; }
.weekly.done progress { --bar: var(--green); }
.weekly small { display: block; margin-top: 6px; color: var(--muted); font-size: 12px; }
.weekly.done { background: linear-gradient(140deg,#2b7c5c55,#1b4a3a55); border-color: #95f4bb99; }.weekly.done small { color: var(--green); }
#trust-card progress { --bar: var(--pink); accent-color: var(--pink); }#trust-card span svg { color: var(--pink); }
.quest i { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; background: #ffb0ff22; color: #ffb0ff; }.quest > div { min-width: 0; }.quest b { display: block; font-size: 13px; }
.quest progress { display: block; width: 100%; height: 5px; margin: 6px 0 2px; accent-color: #ffb0ff; border-radius: 3px; overflow: hidden; }.quest small { color: var(--muted); font-size: 10.5px; }
.quest.done { border-color: #95f4bb88; background: #2b7c5c33; }.quest.done i { background: #6ff0bd33; color: var(--green); }.quest.done progress { accent-color: var(--green); }.quest.done small { color: var(--green); }
.quest-reward { display: inline-flex; align-items: center; gap: 3px; font-weight: 900; color: var(--c); font-size: 13px; }.quest-reward svg { filter: drop-shadow(0 0 6px var(--c)); }
.quest-bonus { margin: 10px 20px 0; font-size: 12px; }.quest-sheet .primary { width: calc(100% - 40px); margin: 10px auto 0; }
.result-progress { margin: 6px 0 0; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }.result-progress .result-xp { flex: 1 1 200px; }.result-xp span, .result-xp b { white-space: nowrap; }
.result-xp { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; align-items: center; padding: 6px 10px; border-radius: 12px; background: #ffffff0c; font-size: 12px; text-align: left; }
.result-xp span { grid-column: 1; grid-row: 1; color: var(--cyan); font-weight: 800; }.result-xp b { grid-column: 2; grid-row: 1 / 3; color: var(--gold); font-size: 15px; }
.result-xp progress { grid-column: 1; grid-row: 2; width: 100%; height: 5px; accent-color: var(--cyan); display: block; border-radius: 3px; overflow: hidden; }
.result-quests { display: grid; gap: 4px; font-size: 12px; color: var(--green); text-align: left; }.result-quests span { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 10px; background: #2b7c5c33; }
/* Die Ausbeute einer Runde, in der Karte statt als Streifen davor: Erfolge, Rang, Vertrauen, Booster,
   Siegesserie, Sternen-Kisten. 🚨 ALS MARKEN, DIE UMBRECHEN, NICHT ALS ZEILEN: Eine gute Runde wirft acht
   Belohnungen auf einmal ab, und acht volle Zeilen schieben auf einem 320-px-Handy die Knöpfe aus dem Bild.
   Nebeneinander passen zwei bis drei je Zeile, und das Symbol sagt, worum es geht. */
.result-news { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: 6px; font-size: 11.5px; }
/* 🚨 EINE MARKE IST EINE ZEILE — IMMER. Gemeldet: unterschiedliche Höhen machen keinen Sinn.
   `white-space: nowrap` ist die Zusicherung: Ein Text, der nicht mehr in die Karte passt, bricht sonst um
   und macht aus einer 18-px-Marke eine mit 30 px. Zusammen mit `max-width` und `text-overflow` wird er
   stattdessen abgeschnitten — Missionstexte und Erfolgsnamen sind Daten, und die Liste kann wachsen.
   Die zweite Ursache lag woanders: Die Klasse hieß `ach` und traf damit die Erfolgsliste (`.ach` mit
   eigener Schriftgröße). Deshalb jetzt `news-ach`. */
.result-news .news { white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; border-radius: 99px; background: #ffffff10; border: 1px solid var(--line); color: var(--ink); font-size: inherit; font-weight: 700; line-height: 1.35; animation: rise .35s ease backwards; }
.result-news .news svg { flex: none; width: 13px; height: 13px; color: var(--gold); }
.result-news .news.news-rank svg { color: var(--cyan); }.result-news .news.news-quest svg { color: #ffb0ff; }
.result-news .news.news-gift svg { color: var(--green); }.result-news .news.news-streak svg { color: #ff9c57; }
/* 🚨 HINTER der Grundregel, nicht im 380-px-Block weiter oben: Bei gleicher Spezifität gewinnt die
   spätere Regel. Auf 320 px bleiben der Marke rund 284 px — eine Nummer kleiner, und zwei passen
   nebeneinander statt einer. */
@media(max-width:380px) {
  .result-news { gap: 3px; font-size: 10.5px; }
  .result-news .news { padding: 3px 7px; gap: 4px; }
  .result-news .news svg { width: 11px; height: 11px; }
}
@media(max-width:380px) { .campaign-bars { gap: 6px; } .chapter { left: 0; right: 0; padding: 8px 10px; } .chapter strong { font-size: 14px; } .chapter small { display: none; } }
@media(orientation:landscape) and (max-height:600px) { .result-progress { margin-top: 4px; } .result-quests { display: none; } }
@media(min-width:1001px) and (orientation:landscape) { #progress-screen .list-scroll { grid-template-columns: minmax(0,600px) minmax(320px,1fr); } .chapter strong { font-size: 18px; } .quest-list { padding: 0 24px; } }
/* Progress bars of the v18 screens: explicit track and fill, since accent-color renders differently per browser. */
.bar-card progress, .ach progress, .quest progress, .result-xp progress { --bar: var(--gold); appearance: none; -webkit-appearance: none; border: 0; background: #ffffff18; color: var(--bar); }
#rank-card progress, .result-xp progress { --bar: var(--cyan); }.quest progress { --bar: #ffb0ff; }.quest.done progress { --bar: var(--green); }.ach.earned progress { --bar: var(--green); }
.bar-card progress::-webkit-progress-bar, .ach progress::-webkit-progress-bar, .quest progress::-webkit-progress-bar, .result-xp progress::-webkit-progress-bar { background: #ffffff18; border-radius: 3px; }
.bar-card progress::-webkit-progress-value, .ach progress::-webkit-progress-value, .quest progress::-webkit-progress-value, .result-xp progress::-webkit-progress-value { background: var(--bar); border-radius: 3px; box-shadow: 0 0 8px color-mix(in srgb, var(--bar) 60%, transparent); transition: width .4s ease; }
.bar-card progress::-moz-progress-bar, .ach progress::-moz-progress-bar, .quest progress::-moz-progress-bar, .result-xp progress::-moz-progress-bar { background: var(--bar); border-radius: 3px; }

/* 🚨 ZWEITER BLOCK MIT DERSELBEN BEDINGUNG — UND ER STEHT SPÄTER, ALSO GEWINNT ER. Genau hier stand noch
   `.game { grid-template-columns: 176px minmax(0,1fr) }` und machte die drei Spalten oben still wieder zu
   zweien: Die Ziele landeten in einer IMPLIZITEN dritten Spalte, deren Breite der Inhalt bestimmte, und die
   linke Spalte war 176 statt 148 px breit. Im Quelltext sah oben alles richtig aus. Die Spaltenaufteilung
   steht deshalb jetzt nur noch an EINER Stelle; hier bleiben nur Feinheiten, die dort nichts überschreiben. */
@media(orientation:landscape) and (max-height:600px) { .goal { font-size: 11px; gap: 4px; padding: 3px 6px 6px 3px; flex-wrap: wrap; } .goal canvas { width: 22px; height: 22px; } }
/* Desktop campaign: map and achievements scroll independently, so jumping to the current level never empties the right column. */
/* 🚨 DIE RECHTE SPALTE ROLLT ALS GANZES. Vom Betreiber am Rechner fotografiert: „auf der rechten Seite nach unten
   scrollen … ich sehe nicht den kompletten Inhalt." Vorher rollten nur die Erfolge in der untersten Rasterzeile —
   Fortschrittskarten und Überschrift standen in festen Zeilen darüber, und sobald die höher wurden als das Fenster,
   blieb für die rollende Zeile nichts mehr übrig und der Rest verschwand hinter `overflow:hidden`. Jetzt ist die
   ganze Spalte EIN Rollbereich (`.list-side`), genau wie die Levelkarte daneben. */
@media(min-width:1001px) and (orientation:landscape) {
  #progress-screen .list-scroll { overflow: hidden; }
  #progress-screen .level-map { overflow-y: auto; max-height: 100%; overscroll-behavior: contain; padding: 4px 8px 12px 4px; }
  #progress-screen .list-side { grid-column: 2; min-height: 0; max-height: 100%; overflow-y: auto; overscroll-behavior: contain; padding: 0 4px 12px 0; }
  #progress-screen .campaign-extra { margin-top: 0; }
  #progress-screen .campaign-extra .list-subhead { margin-top: 0; }
}

/* ── v19: Nova, the companion ──────────────────────────────────────────────────────────────────── */
.nova-small { width: 40px; height: 40px; filter: drop-shadow(0 0 8px #7ce9ff66); }
.nova-line { display: flex; align-items: center; gap: 10px; text-align: left; margin-top: 12px; padding: 8px 12px 8px 8px; border-radius: 16px; background: #7ce9ff14; border: 1px solid #7ce9ff44; font-size: 13px; line-height: 1.45; color: var(--ink); }
.nova-line span { min-width: 0; }.nova-line .bump { animation: rise .3s ease; }
@keyframes nudge { 50% { transform: scale(1.035); box-shadow: 0 0 0 8px #ffd77a33, 0 6px 0 #995335; } }
.list-nova { margin: 0 0 10px; padding: 6px 12px 6px 6px; max-width: 560px; }.sheet-nova { margin: 0 20px 8px; }.reward .nova-line { margin: 0 0 12px; }.pause-objective { margin-top: 12px; }
.level-intro .nova-line { margin-top: 12px; font-size: 12.5px; }
.intro-go { width: 100%; min-height: 48px; margin-top: 14px; }
/* The card must never outgrow the board area it sits in (the button was clipped on small phones): it scrolls inside. */
.level-intro { max-height: calc(100% - 12px); overflow-y: auto; overscroll-behavior: contain; }
@media(max-height:650px) and (orientation:portrait) { .level-intro { padding: 12px 14px; } .level-intro h3 { font-size: 20px; margin: 4px 0 2px; } .level-intro p { font-size: 12px; } .intro-goals { margin-top: 8px; gap: 8px; } .intro-goals canvas { width: 28px; height: 28px; } .intro-wish { margin-top: 8px !important; font-size: 11.5px !important; padding: 4px 10px; } .level-intro .nova-line { margin-top: 8px; } .intro-go { min-height: 40px; margin-top: 8px; } }
.level-sheet .nova-line { margin: 0 0 12px; }
.result-hero { display: grid; grid-template-columns: 64px minmax(0,1fr) auto; column-gap: 12px; row-gap: 0; align-items: center; justify-items: start; text-align: left; }
.result-hero .stamp { margin: 0; transform: none; font-size: 10px; padding: 3px 8px; border-width: 2px; }.result-hero h2 { margin: 3px 0 0; font-size: 21px; line-height: 1.1; }
.result-share { grid-column: 3; grid-row: 1 / 3; width: 44px; height: 44px; align-self: center; }
/* Docks: empty places on a card or sheet that borrow the one live Nova from the HUD. The dock keeps the size,
   the landed mount fills it, so nothing shifts while she is on her way. */
/* Novas Bühne (stage.mjs): EINE Figur für die ganze App, als manuelles Popover im Top-Layer, damit sie über jedem
   Blatt und dessen Backdrop liegt. Die Bühne bekommt je Frame Größe und Transform des aktiven Docks; unterwegs
   skaliert nur der Transform. Die UA-Regeln für [popover] (inset:0, margin:auto, Rahmen, Hintergrund) werden hier
   alle zurückgenommen, sonst stünde sie mittig in einem weißen Kasten. */
.nova-stage { position: fixed; inset: auto; left: 0; top: 0; width: 44px; height: 44px; margin: 0; padding: 0; border: 0; background: transparent; overflow: visible; color: inherit; z-index: 120; pointer-events: none; transform-origin: 0 0; will-change: transform; display: block; }
.nova-stage.nova-hidden { visibility: hidden; }
.nova-figure { display: block; position: relative; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; border-radius: 50%; background: transparent; box-shadow: none; line-height: 0; pointer-events: auto; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent; filter: drop-shadow(0 0 8px #7ce9ff66); }
/* 🚨 IHR RING IST RUND UND LIEGT AUSSEN. Die Grundregel für Knöpfe setzt `outline-offset: -3px` —
   drei Punkte NACH INNEN, quer über ihr Gesicht. Und die Bühne selbst bekommt nie einen Ring:
   Sie ist ein quadratischer Kasten um eine runde Figur, dort sähe jeder Ring wie ein Fehler aus. */
.nova-figure:focus-visible { outline: 3px solid var(--cyan); outline-offset: 4px; border-radius: 50%; }
.nova-stage:focus, .nova-stage:focus-visible, .nova-figure:focus:not(:focus-visible) { outline: none; }
.nova-figure svg { width: 100%; height: 100%; overflow: visible; display: block; }
/* Kein brightness-Filter auf dem Druck: zusammen mit dem drop-shadow malte WebKit nur noch ein dunkles Quadrat (v26). */
.nova-figure.pressed { filter: none; transform: translateY(2px) !important; }
.nova-figure.look-hero { filter: none; }.nova-figure.look-hud { filter: drop-shadow(0 0 8px #7ce9ff55); }
.nova-figure.look-big { filter: drop-shadow(0 0 26px color-mix(in srgb, var(--c) 70%, transparent)); }.nova-figure.look-glow { filter: drop-shadow(0 0 22px #7ce9ff66); }
.nova-dock { display: grid; place-items: center; flex: 0 0 auto; cursor: pointer; }
.nova-dock.nova-big, .nova-dock.nova-small { filter: none; }
.result-nova-dock { width: 64px; height: 64px; grid-row: 1 / 3; display: grid; place-items: center; border-radius: 50%; background: radial-gradient(circle,#7ce9ff1c 0 35%,transparent 68%); }
.result-nova-dock::after { content: ''; width: 42%; height: 42%; border: 1px solid #7ce9ff55; border-radius: 50%; box-shadow: 0 0 20px #7ce9ff66; animation: nova-dock 1.4s ease-in-out infinite; }
@keyframes nova-dock { 50% { transform: scale(1.45); opacity: .3; } }
.nova-travelling .nova-figure { pointer-events: none; }
/* Unterwegs aus eigenem Antrieb (`nova-geist.mjs`): Solange sie sich bewegt, fängt sie keine Klicks ab —
   sie fliegt über Knöpfe hinweg, und ein Klick darauf muss den Knopf treffen, nicht sie. Steht sie, ist
   sie wieder antippbar. Bei einem schnellen Satz bekommt sie denselben Schweif wie im Flug. */
.nova-eilt .nova-figure { pointer-events: none; }
.nova-schnell::after { content: ''; position: absolute; inset: -35%; border-radius: 50%; background: radial-gradient(circle,#fff7 0 8%,#7ce9ff55 26%,transparent 68%); filter: blur(2px); z-index: -1; animation: nova-flight 1s ease-out infinite; }
.nova-travelling::after { content: ''; position: absolute; inset: -35%; border-radius: 50%; background: radial-gradient(circle,#fff7 0 8%,#7ce9ff55 26%,transparent 68%); filter: blur(2px); z-index: -1; animation: nova-flight 1s ease-out infinite; }
@keyframes nova-flight { from { transform: scale(.55); opacity: .95; } to { transform: scale(1.8); opacity: 0; } }
.nova-stage.lose .nova-figure { filter: drop-shadow(0 0 22px #ff718366); }
.result.nova-arriving .result-score-row, .result.nova-arriving .result-side, .result.nova-arriving .result-bubble { opacity: 0; }
.result.nova-arrived .result-score-row, .result.nova-arrived .result-side, .result.nova-arrived .result-bubble:not([hidden]) { animation: rise .38s ease backwards; }
.result.nova-arrived .result-score-row { animation-delay: .02s; }.result.nova-arrived .result-side { animation-delay: .12s; }.result.nova-arrived .result-bubble:not([hidden]) { animation-delay: .2s; }
.result-bubble { position: relative; grid-column: 1 / -1; justify-self: stretch; margin: 8px 0 0; padding: 6px 10px; border-radius: 14px; background: #7ce9ff14; border: 1px solid #7ce9ff44; color: var(--ink); font-size: 12.5px; line-height: 1.4; text-align: left; max-width: none; animation: rise .4s ease .25s backwards; }
.result-bubble::before { content: ""; position: absolute; left: 26px; top: -7px; width: 12px; height: 12px; margin-left: -6px; transform: rotate(45deg); background: #1a3548; border: 1px solid #7ce9ff44; border-right: 0; border-bottom: 0; border-radius: 3px 0 0 0; }
.result-wish { display: flex; align-items: center; gap: 8px; margin: 6px 0 0; padding: 5px 10px; font-size: 12px; border-radius: 12px; background: #ffffff0c; border: 1px solid var(--line); font-size: 12.5px; text-align: left; color: var(--muted); animation: rise .4s ease .3s backwards; }
.result-wish svg { color: #ffffff3a; flex: 0 0 auto; }.result-wish span { flex: 1; min-width: 0; line-height: 1.3; }.result-wish b { color: var(--gold); white-space: nowrap; }
.result-wish.done { background: #ffd77a1c; border-color: #ffd77a66; color: var(--ink); }.result-wish.done svg { color: var(--gold); filter: drop-shadow(0 0 6px var(--gold)); }
.intro-wish { margin: 10px 0 0 !important; padding: 6px 12px; border-radius: 12px; background: #ffd77a14; border: 1px solid #ffd77a44; color: var(--gold) !important; font-size: 12.5px !important; font-weight: 700; }.intro-wish.done { color: var(--green) !important; background: #6ff0bd14; border-color: #6ff0bd44; }
.level-wish { margin: 0 0 10px; padding: 6px 12px; border-radius: 12px; background: #ffd77a14; border: 1px solid #ffd77a44; color: var(--gold); font-size: 12.5px; font-weight: 700; }.level-wish.done { color: var(--green); background: #6ff0bd14; border-color: #6ff0bd44; }
/* ── Die Story-Szene ──────────────────────────────────────────────────────
   🚨 SIE IST KEIN BLATT MEHR, SIE IST EINE SZENE. Gewünscht: „Wenn Nova Dialoge vom
   spielfortschritt erzählt möchte ich das die spielmenus verschwinden bis auf den Sternen
   Hintergrund, Nova soll deutlich größer werden und der Text Dialog soll richtig cool dargestellt
   werden."

   Also: Das Blatt füllt den Schirm, hat keinen eigenen Hintergrund und keinen Rahmen — was man
   sieht, ist der echte Sternenhimmel der Welt (`.ambient`), der dahinter WEITERLÄUFT. Die Menüs
   und das Brett darüber blendet `body.story-an .shell` aus; gelöscht wird nichts, sie stehen nach
   dem letzten „Weiter" unverändert wieder da.

   ⚠️ UND DER HIMMEL MUSS SICHTBAR BLEIBEN. `dialog::backdrop` verdunkelt sonst zu 84 %; hier ist
   er nur ein weicher Schleier am oberen und unteren Rand, damit Kicker und Text lesbar bleiben,
   ohne den Himmel zuzudecken. Dass er dabei weiterzieht, steht in `fx.mjs`: Die Bildsperre für
   offene Blätter nimmt die Story ausdrücklich aus. */
.story { --c: var(--cyan); text-align: center; overflow: hidden;
  width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
  padding: var(--sa-oben) var(--sa-rechts) var(--sa-unten) var(--sa-links);
  border: 0; border-radius: 0; background: transparent; box-shadow: none;
  grid-template-rows: minmax(0,1fr) auto; place-items: center; }
/* 🚨 `display` STEHT AM ZUSTAND, NICHT AN DER KLASSE. Ein `dialog` ist nur deshalb unsichtbar, solange er
   zu ist, weil der Browser selbst `dialog:not([open]) { display: none }` mitbringt. Wer `display: grid`
   an `.story` schreibt, schlaegt diese Regel — und die geschlossene Szene steht mitten im Menue, wo
   ihr „Weiter"-Knopf quer ueber der Fusszeile lag. Darum hier `[open]`, wie bei jedem anderen Blatt im
   Haus auch (`.result[open]`, `.nova-shop[open]`). Die Masse bleiben an `.story`, damit der
   Querformat-Block sie mit seiner niedrigeren Spezifitaet weiter abwandeln kann. */
.story[open] { display: grid; }
.story::backdrop { background: linear-gradient(180deg,#05030fcc 0,#05030f44 26%,#05030f44 58%,#05030fe8 100%); }
body.story-an .shell { opacity: 0; pointer-events: none; transition: opacity .4s ease; }

/* Die Bühne: Nova gross und mittig, ihr Licht dahinter. Der Kasten ist nur noch der Platz, den sie
   bekommt — Sterne malt der Himmel selbst, die vier gemalten Punkte von früher sind weg. */
.story-scene { position: relative; width: 100%; display: grid; place-items: center; align-self: center;
  background: none; border: 0; }
.story-scene::before { content: ""; position: absolute; width: min(86vw,520px); aspect-ratio: 1;
  border-radius: 50%; background: radial-gradient(circle, color-mix(in srgb, var(--c) 34%, transparent) 0,
  color-mix(in srgb, var(--c) 10%, transparent) 42%, transparent 68%); pointer-events: none;
  animation: story-atem 5s ease-in-out infinite; }
.story.signal-sprung .story-scene::after { content: ""; position: absolute; z-index: 0; width: min(78vw,460px); aspect-ratio: 1;
  border: 1px solid color-mix(in srgb,var(--c) 70%,transparent); border-radius: 50%;
  box-shadow: 0 0 22px color-mix(in srgb,var(--c) 50%,transparent),inset 0 0 34px color-mix(in srgb,var(--c) 24%,transparent);
  animation: signal-open .9s cubic-bezier(.16,1,.3,1) both,signal-orbit 18s linear .9s infinite; pointer-events:none; }
@keyframes signal-open { from { opacity: 0; transform: scale(.35); } to { opacity: .8; transform: scale(1); } }
@keyframes signal-orbit { to { rotate: 360deg; } }
body.reduced .story.signal-sprung .story-scene::after { animation:none; opacity:.55; }
@keyframes story-atem { 50% { transform: scale(1.07); opacity: .82; } }
body.reduced .story-scene::before { animation: none; }
/* 🚨 SIE WÄCHST MIT DEM SCHIRM, NICHT AUF EINE FESTE ZAHL. 160 px waren im Blatt richtig; auf dem
   ganzen Schirm sind sie verloren. `min()` gegen BEIDE Achsen, sonst ragt sie quer aus dem Bild. */
.story .nova-big { width: min(54vh,74vw,380px); height: min(54vh,74vw,380px);
  filter: drop-shadow(0 0 40px color-mix(in srgb, var(--c) 75%, transparent)); }

/* Der Text: eine Bildunterschrift, kein Kasten. Eine Linie in der Kapitelfarbe trägt ihn, darunter
   steht er gross genug, um auf Armlänge gelesen zu werden. */
.story-fuss { width: min(100%,620px); padding: 0 20px 18px; }
.story .eyebrow { display: block; margin: 0 0 10px; color: var(--c); font-size: 11px; letter-spacing: .28em;
  text-shadow: 0 0 18px color-mix(in srgb, var(--c) 60%, transparent); }
.story-bubble { position: relative; display: grid; margin: 0; padding: 16px 4px 4px; border: 0; border-radius: 0;
  background: none; min-height: 104px; text-align: center; cursor: pointer; }
.story-bubble > #story-text, .story-bubble > #story-reserve { grid-area: 1 / 1; }
#story-reserve { display: grid; visibility: hidden; pointer-events: none; }
#story-reserve > p { grid-area: 1 / 1; }
.story-bubble::before { content: ""; position: absolute; top: 0; left: 50%; width: min(220px,70%); height: 2px;
  transform: translateX(-50%); border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--c), transparent);
  box-shadow: 0 0 14px color-mix(in srgb, var(--c) 70%, transparent); }
.story-bubble p { margin: 0; color: var(--ink); font-size: clamp(16px,4.4vw,21px); line-height: 1.55;
  font-weight: 600; text-shadow: 0 2px 18px #000a; }
.story-bubble p[data-done="0"]::after { content: "▍"; color: var(--c); animation: twinkle 1s steps(2) infinite; }
.story-dots { display: flex; justify-content: center; gap: 7px; margin: 16px 0 10px; }
.story-dots i { width: 8px; height: 8px; border-radius: 50%; background: #ffffff22; transition: background .2s; }
.story-dots i.on { background: var(--c); box-shadow: 0 0 10px var(--c); }
.story-dots i.done { background: color-mix(in srgb, var(--c) 45%, transparent); }
.story .primary { width: min(100%,340px); margin: 0 auto; }
@media(max-height:650px) and (orientation:portrait) { .level-intro .nova-line { font-size: 11.5px; padding: 6px 10px 6px 6px; } .level-intro .nova-small { width: 30px; height: 30px; } }
@media(orientation:landscape) and (max-height:600px) { .level-intro .nova-line { display: none; } .result-bubble { display: none; }
  /* Quer steht Nova NEBEN dem Text statt darüber — übereinander bliebe für beides zu wenig Höhe.
     Bildfüllend bleibt die Szene auch hier. */
  .story { grid-template-rows: minmax(0,1fr); grid-template-columns: minmax(0,1fr) minmax(0,1.1fr); align-items: center; }
  .story-scene::before { width: min(52vh,42vw); }
  .story .nova-big { width: min(64vh,34vw,300px); height: min(64vh,34vw,300px); }
  .story-fuss { width: min(100%,520px); padding: 0 24px 0 8px; text-align: left; }
  .story-bubble { text-align: left; min-height: 0; }
  .story-bubble::before { left: 0; transform: none; width: min(180px,60%); }
  .story-bubble p { font-size: clamp(14px,2.4vw,18px); }
  .story-dots { justify-content: flex-start; margin: 12px 0 8px; }
  .story .primary { margin: 0; }
}

/* Nova's targeting tools reuse the dock, preserving the full board on small screens. */

.nova-excursion .nova-figure { pointer-events: none; }
.nv-steam { opacity: 0; }
.nova-figure[data-reaction] .nv-steam { opacity: .9; animation: nova-steam .65s ease-in-out infinite alternate; }
.nova-figure[data-reaction="angry"] { filter: drop-shadow(0 0 12px #ff6555aa); }
@keyframes nova-steam { to { transform: translateY(-5px); opacity: .4; } }
body.reduced .nv-steam { animation: none; }
/* Novas Licht: das Schwebelicht unter ihr atmet, ein Funke läuft über die vordere Hälfte ihres Rings, die beiden
   Positionslichter an der Naht blinken versetzt. Reine CSS-Animationen — sie kosten den Rig-Takt nichts. */
.nv-schweb { transform-box: fill-box; transform-origin: center; animation: nova-schweb 2.6s ease-in-out infinite alternate; }
@keyframes nova-schweb { from { opacity: .55; transform: scale(.88, .8); } to { opacity: 1; transform: scale(1.06, 1.08); } }
.nv-funke { animation: nova-funke 2.8s linear infinite; opacity: .9; }
@keyframes nova-funke { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -100; } }
.nv-licht { animation: nova-licht 1.8s steps(2, jump-none) infinite; }
.nv-licht + .nv-licht { animation-delay: -.9s; }
@keyframes nova-licht { from { opacity: 1; } to { opacity: .25; } }
body.reduced .nv-schweb, body.reduced .nv-funke, body.reduced .nv-licht { animation: none; }
body.reduced .nv-funke { opacity: 0; }

/* Only the catalogue scrolls; the header and live preview remain visible. */
.nova-shop[open] { overflow: hidden; display: grid; grid-template-rows: auto auto minmax(0,1fr); width: min(92vw,620px); padding: 18px; }
.nova-shop .sheet-head { position: static; padding: 0 0 8px; background: none; }
.nova-shop .sheet-head h2 { margin: 4px 0 6px; font-size: clamp(25px,7vw,34px); }
.shop-intro { color: var(--muted); font-size: 13px; line-height: 1.5; }
.shop-preview { display: grid; grid-template-columns: 112px minmax(0,1fr); gap: 12px; align-items: center; min-height: 144px; padding: 12px; border-radius: 20px; background: #7ce9ff0a; }
.shop-preview .nova-dock { width: 112px; height: 112px; }
.shop-preview p { min-height: 3em; font-size: 13px; }
.shop-details { container-type: inline-size; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scroll-padding-top: 58px; padding: 0 4px 12px 0; }
.shop-items { display: grid; grid-template-columns: repeat(auto-fit,minmax(min(100%,160px),1fr)); gap: 10px; }
.shop-item { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--line); border-radius: 16px; }
.shop-item b { font-size: 14px; min-height: 2.5em; }
.shop-item button { width: 100%; min-height: 44px; padding: 8px; font-size: 12px; margin: 0; }
.coin-note { color: var(--gold); font-size: 13px; }
/* Garderobe: Seltenheit am Rand der Karte, Tagesangebot, Reiter für Auftritte und Accessoires, Anlässe. */
.shop-item { position: relative; --tier: #9fb6c8; border-color: color-mix(in srgb, var(--tier) 45%, transparent); background: linear-gradient(160deg, color-mix(in srgb, var(--tier) 10%, transparent), transparent 70%); }
.shop-item.tier-1 { --tier: #7ce9ff; }.shop-item.tier-2 { --tier: #b18cff; }.shop-item.tier-3 { --tier: #ffd77a; }
.shop-item.active { box-shadow: inset 0 0 0 2px var(--tier); }
.shop-meta { color: var(--tier); font-size: 11px; font-weight: 700; letter-spacing: .02em; }
.shop-item.deal::after { content: '−30 %'; position: absolute; top: -8px; right: 8px; padding: 2px 7px; border-radius: 99px; background: var(--gold); color: #3a2400; font-size: 10px; font-weight: 900; }
.shop-collection { color: var(--muted); font-weight: 600; }
.shop-deal { margin: 0 0 10px; padding: 9px 12px; border-radius: 12px; background: linear-gradient(90deg,#ffd77a26,#ff8ae81f); border: 1px solid #ffd77a55; color: var(--gold); font-size: 13px; font-weight: 700; }
.shop-tabs { position: sticky; top: 0; z-index: 2; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 4px; margin: 0 0 10px; border-radius: 14px; background: #30294f; }
.shop-tabs button { min-height: 40px; margin: 0; padding: 6px; border: 0; border-radius: 10px; background: transparent; box-shadow: none; font-size: 13px; font-weight: 800; color: var(--muted); }
.shop-tabs button[aria-selected="true"] { background: #7ce9ff24; color: var(--ink); }
.shop-acts { display: grid; gap: 4px; margin: 0 0 8px; }.shop-acts[hidden] { display: none; }
.shop-track { display: block; height: 4px; border-radius: 2px; background: #ffffff14; overflow: hidden; }
.shop-track i { display: block; height: 100%; background: linear-gradient(90deg,var(--cyan),var(--gold)); transform-origin: 0 50%; transform: scale(0,1); }
.shop-acts small { color: var(--muted); font-size: 11px; font-weight: 700; }
.shop-rules { margin: 14px 0 10px; }.shop-rules .eyebrow { margin: 0 0 8px; }.shop-rules .row { min-height: 54px; }
/* Novas Auftritte (nova-show.mjs): zwei Ebenen neben der Figur, jedes Teilchen unsichtbar, bis seine Animation es zeigt. */
.nova-figure svg { transform-origin: 50% 50%; }
.nv-prop-move { transform-box: fill-box; transform-origin: 50% 90%; }
.nova-show { position: absolute; left: 50%; top: 50%; width: 0; height: 0; pointer-events: none; color: #ffffff; }
.nova-show .fx { position: absolute; left: 0; top: 0; display: block; opacity: 0; pointer-events: none; line-height: 0; will-change: transform, opacity; }
.nova-show .fx svg { display: block; width: 100%; height: 100%; overflow: visible; fill: currentColor; }
.fx.pink { color: #ff8ac6; }.fx.gold { color: #ffd77a; }.fx.cyan { color: #7ce9ff; }.fx.mint { color: #82ffd5; }.fx.ice { color: #d9fbff; }.fx.orange { color: #ffb45f; }.fx.violet { color: #b18cff; }.fx.white { color: #ffffff; }
.fx.c1 { color: #ff8ac6; }.fx.c2 { color: #ffd77a; }.fx.c3 { color: #7ce9ff; }.fx.c4 { color: #82ffd5; }.fx.c5 { color: #ffb45f; }
.fx.big { filter: drop-shadow(0 0 10px currentColor); }
.fx.ring { border: 2px solid currentColor; border-radius: 50%; box-shadow: 0 0 12px currentColor, inset 0 0 8px currentColor; }.fx.ring.thin { border-width: 1px; }
.fx.comet, .fx.streak { border-radius: 99px; background: linear-gradient(90deg, transparent, currentColor 72%, #ffffff); }
.fx.conf, .fx.px { background: currentColor; border-radius: 1px; }
.fx.aurora { border-radius: 50%; background: radial-gradient(ellipse at 50% 60%, #82ffd5aa 0, #7ce9ff55 32%, #b18cff33 55%, transparent 70%); }
.fx.aurora.a1 { background: radial-gradient(ellipse at 45% 55%, #b18cffaa 0, #ff8ae844 35%, transparent 68%); }
.fx.aurora.a2 { background: radial-gradient(ellipse at 55% 50%, #7ce9ffaa 0, #82ffd544 38%, transparent 68%); }
.fx.ice-shell { border-radius: 50%; border: 1.5px solid #e9fdffaa; background: radial-gradient(circle at 35% 30%, #ffffffcc 0 7%, #d9fbff55 20%, #9fe8ff33 55%, #d9fbff88 72%, transparent 74%), conic-gradient(from 20deg, #ffffff22, transparent 12%, #ffffff18 30%, transparent 45%, #ffffff22 62%, transparent 80%, #ffffff18); }
.fx.crack path, .fx.constellation path { fill: none; stroke: #ffffff; stroke-width: 1.4; stroke-linejoin: round; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
.fx.constellation path { stroke: #ffe8a0; stroke-width: 1.1; }
.fx.digit { line-height: 1; font-weight: 900; color: #ffd77a; text-shadow: 0 0 12px #ff9c57, 0 2px 0 #7a3a10; font-variant-numeric: tabular-nums; }
.fx.puff { border-radius: 50%; background: radial-gradient(circle, #eef4ffdd 0, #c9d6f080 45%, transparent 70%); }
.fx.flames { display: flex; justify-content: center; align-items: flex-start; gap: 6%; }
.fx.flames i { display: block; width: 28%; height: 100%; border-radius: 50% 50% 45% 45% / 30% 30% 70% 70%; background: linear-gradient(#fff6c0, #ffb45f 40%, #ff5f5f 75%, transparent); transform-origin: 50% 0; animation: nova-flame .12s ease-in-out infinite alternate; }
.fx.flames i:nth-child(2) { height: 130%; animation-delay: -.06s; }
@keyframes nova-flame { to { transform: scaleX(1.12) scaleY(.72); } }
.fx.rays { border-radius: 50%; background: repeating-conic-gradient(#ffe27566 0 6deg, transparent 6deg 20deg); -webkit-mask: radial-gradient(closest-side, transparent 18%, #000 32%, transparent 100%); mask: radial-gradient(closest-side, transparent 18%, #000 32%, transparent 100%); }
.fx.vortex { border-radius: 50%; background: radial-gradient(closest-side, #0b0620 0 16%, transparent 34%), repeating-conic-gradient(from 0deg, #b18cff00 0deg, #b18cffcc 10deg, #7ce9ff00 24deg); -webkit-mask: radial-gradient(closest-side, #000 55%, transparent 100%); mask: radial-gradient(closest-side, #000 55%, transparent 100%); }
.fx.scan { border-radius: 50%; background: repeating-linear-gradient(0deg, #ffffff30 0 1px, transparent 1px 3px), linear-gradient(90deg, #ff4fd822, #3ff0ff22); }
.fx.dot { border-radius: 50%; background: #ffffff; box-shadow: 0 0 10px #ffffff, 0 0 22px #7ce9ff; }
.fx.boot { border: 1px solid #7ce9ff; border-radius: 3px; padding: 1px; }.fx.boot i { display: block; width: 100%; height: 100%; background: #7ce9ff; transform-origin: 0 50%; transform: scaleX(0); }
.fx.bubble { border-radius: 50%; background: radial-gradient(circle at 32% 28%, #ffffffee 0 7%, transparent 15%), radial-gradient(circle, transparent 56%, #7ce9ff40 68%, #ff8ae855 80%, #ffffffaa 92%, transparent 95%); }
body.reduced .fx.flames i { animation: none; }
/* 🚨 SCHMAL: TITEL ÜBER DIE GANZE BREITE, KNÖPFE DARUNTER. Mit Titel und beiden Knöpfen in EINER Zeile blieben
   auf 320 px noch 54 px für den Namen — „Sternschleife" brach mitten im Wort und lief unter die Knöpfe. */
@container (max-width:480px) { .shop-items { grid-template-columns: 1fr; }.shop-item { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); grid-template-areas: "t t" "m m" "p b"; align-items: center; gap: 4px 8px; padding: 10px; }.shop-item b { grid-area: t; min-height: 0; font-size: 13px; }.shop-item .shop-meta { grid-area: m; font-size: 10px; margin-bottom: 4px; }.shop-item button.wide { grid-area: p; min-height: 44px; }.shop-item button.primary { grid-area: b; min-height: 44px; } }
/* Kurze Hochformat-Schirme: Vorschau und Einleitung rücken zusammen, damit der Katalog darunter Platz hat. */
@media(max-height:700px) and (orientation:portrait) {
  .nova-shop[open] { padding: 14px; }.nova-shop .sheet-head h2 { font-size: 24px; margin: 2px 0 2px; }
  .shop-preview { grid-template-columns: 84px minmax(0,1fr); min-height: 0; padding: 8px; gap: 8px; }.shop-preview .nova-dock { width: 84px; height: 84px; }
  .shop-preview p { min-height: 0; font-size: 12px; margin: 4px 0 6px; }.shop-preview .mini { padding: 7px 10px; font-size: 12px; }
  .shop-details .coin-note { margin: 8px 0 6px; font-size: 12px; }.shop-deal { padding: 6px 10px; font-size: 12px; margin-bottom: 6px; }.shop-tabs button { min-height: 36px; }
}

/* Hidden after the third full anger episode: a short target game made from the regular stones. */
.nova-egg { justify-content: center; align-items: center; padding: 10px 16px max(14px,var(--sa-unten)); background: radial-gradient(circle at 50% 20%,#e34e6750,transparent 38%),radial-gradient(circle at 50% 85%,#7ce9ff20,transparent 45%); }
.egg-card { width: min(100%,760px); height: min(100%,900px); display: grid; grid-template-rows: auto auto auto minmax(0,1fr) auto; gap: 8px; padding: 14px; border: 1px solid #ff7c8e66; border-radius: 28px; background: linear-gradient(155deg,#251947ee,#0c2a3bee); box-shadow: 0 24px 80px #0008,inset 0 1px #ffffff18; overflow: hidden; }
.egg-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }.egg-head > div { min-width: 0; }.egg-head h1 { margin: 2px 0 0; font-size: clamp(22px,6vw,40px); line-height: 1; overflow-wrap: anywhere; }.egg-head .eyebrow { color: #ff91a0; }
.egg-hero { display: grid; grid-template-columns: clamp(150px,35vw,250px) minmax(0,1fr); align-items: center; min-height: 180px; padding: 4px 14px; border-radius: 22px; background: radial-gradient(circle at 24% 50%,#ff637c2d,transparent 55%),#ffffff08; }
.egg-nova { width: clamp(150px,35vw,250px); height: clamp(150px,35vw,250px); }
.egg-hero > div { min-width: 0; }.egg-hero p { margin: 0 0 12px; color: white; font-size: clamp(14px,3vw,19px); font-weight: 800; line-height: 1.35; overflow-wrap: anywhere; }
.egg-stats { display: flex; flex-wrap: wrap; gap: 6px; }.egg-stats span { padding: 6px 9px; border-radius: 99px; background: #ffffff0e; color: var(--muted); font-size: 10px; letter-spacing: .08em; }.egg-stats b { color: var(--gold); font-size: 15px; }
.egg-rule { margin: 0; color: var(--muted); text-align: center; font-size: 12px; }
/* 🚨 DAS VERHÄLTNIS KOMMT VON DER KACHEL, NICHT VOM BRETT. Gemeldet: „mobil am handy sieht alles gut aus,
   im browser am pc sind die spielsteine aber verzerrt" — Käfer und Fenster standen in hochkant gezogenen
   Kästen. Derselbe Widerspruch wie damals im Hochformat, nur an einer Stelle, die der damalige Block nicht
   erreicht hat: `height: 100%` (die Zeile des Kartengitters) macht die Höhe fest, `max-width` deckelt die
   Breite — und `aspect-ratio` hat keine Achse mehr, über die es sich durchsetzen könnte. Es verliert
   still, und die Zeilen werden höher als die Spalten breit sind.

   Der Fix von damals stand in `@media(orientation:portrait)` und galt deshalb nur dort. Ein Browserfenster
   am PC ist quer und höher als 600 px, fällt also weder in diesen Block noch in den kurzen Querformat-Block
   darunter — und landete genau auf der widersprüchlichen Grundregel. Darum steht die Lösung jetzt HIER, in
   der Grundregel selbst: Die KACHEL ist quadratisch (`aspect-ratio: 1`), das Brett wird so breit, wie
   Breite UND Höhe es zulassen (`dvh` deckelt gegen die flache Seite), und die Zeilenhöhe ergibt sich
   daraus. Ein Verhältnis aus einer Regel statt zwei, die sich streiten. */
.egg-board { width: min(100%,430px,46dvh); height: auto; max-width: none; min-width: 0; min-height: 0;
  place-self: center; display: grid; grid-template-columns: repeat(5,minmax(0,1fr)); grid-auto-rows: auto;
  align-content: center; gap: clamp(4px,1.5vw,8px); }
.egg-tile { position: relative; aspect-ratio: 1; min-width: 0; min-height: 0; padding: 0; border: 1px solid #ffffff13; border-radius: 15px; background: linear-gradient(145deg,#194052,#0b2434); box-shadow: 0 4px 0 #061722; overflow: hidden; transition: transform .18s ease,filter .18s ease,background .18s ease; }
.egg-tile canvas { width: 100%; height: 100%; display: block; }.egg-tile.hot { background: #ff65792c; border-color: #ff8fa0; filter: drop-shadow(0 0 10px #ff637c); animation: egg-hot .55s ease-in-out infinite alternate; }.egg-tile.hit { animation: egg-hit .32s ease-out; }
/* 🚨 DER WECHSEL INS EASTER EGG IST EINE ÜBERNAHME, KEIN BILDSCHIRMWECHSEL. Gewünscht: „die
   Animation cooler aussehen wenn das Menu verschwindet und das easter egg Spiel beginnt."
   Vorher wurde `display` umgeschaltet — das Menü war in einem Bild weg, die Karte in einem Bild da.

   Jetzt geht die Energie von NOVA aus: Ihre Mitte steht als `--egg-x/--egg-y` bereit (gesetzt in
   `openNovaEgg()`), von dort fährt eine Druckwelle über den Schirm und deckt den harten Schnitt zu.
   Dahinter klappt ihre Karte auf, und die Steine fallen versetzt ein — ihre Steine, ihre Regeln.

   ⚠️ Die Welle liegt UNTER Novas Bühne (die ist im Top-Layer) und über der Hülle, damit sie das
   Menü verschluckt, aber nicht sie selbst. */
.egg-flash { display: none; position: fixed; inset: 0; z-index: 40; pointer-events: none; opacity: 0;
  transform-origin: var(--egg-x,50%) var(--egg-y,50%);
  background: radial-gradient(circle at var(--egg-x,50%) var(--egg-y,50%),
    #ffd9e0 0 6%, #ff6d86 14%, #ff6d8666 34%, #ff6d8600 64%); }
.egg-flash::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(circle at var(--egg-x,50%) var(--egg-y,50%),
    transparent 0 30%, #ffe3e9cc 33%, transparent 38%); opacity: 0; }
/* ⚠️ `display` statt nur `opacity`: Eine ganzflächige Ebene mit `opacity: 0` bleibt eine Ebene —
   der Browser hält sie die ganze Sitzung über bereit, für neunzehn Zwanzigstel Spielzeit, in der
   sie nie zu sehen ist. Eine Animation startet auch aus `display: none` heraus. */
body.egg-start .egg-flash { display: block; animation: egg-welle .9s cubic-bezier(.2,.8,.2,1) both; }
body.egg-start .egg-flash::after { animation: egg-ring .8s cubic-bezier(.15,.85,.25,1) both; }
@keyframes egg-welle { 0% { opacity: 0; transform: scale(.05); } 14% { opacity: 1; } 60% { opacity: .85; } 100% { opacity: 0; transform: scale(2.6); } }
@keyframes egg-ring { 0% { opacity: 0; transform: scale(.1); } 20% { opacity: 1; } 100% { opacity: 0; transform: scale(3.2); } }
body.egg-start .egg-card { animation: egg-karte .68s cubic-bezier(.2,.9,.25,1.05) .14s both; }
@keyframes egg-karte { from { opacity: 0; transform: translateY(20px) scale(.9) rotate(-1.4deg); filter: blur(7px); }
  to { opacity: 1; transform: none; filter: none; } }
body.egg-start .egg-tile { animation: egg-einschlag .42s cubic-bezier(.2,.9,.3,1.25) both;
  animation-delay: calc(var(--i,0) * 22ms + 280ms); }
@keyframes egg-einschlag { from { opacity: 0; transform: scale(.35) rotate(-9deg); } to { opacity: 1; transform: none; } }
.egg-actions { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 10px; align-items: center; }.egg-actions progress { width: 100%; height: 8px; accent-color: #ff758b; }.egg-actions .primary { margin: 0; min-height: 42px; padding: 8px 16px; }
@keyframes egg-hot { to { transform: translateY(-3px) scale(1.05); } }
@keyframes egg-hit { 50% { transform: scale(.72) rotate(12deg); opacity: .35; } }
@media(max-width:480px) { .egg-stats { justify-content: center; }.egg-head .round-button { width: 40px; height: 40px; }.egg-hero { grid-template-columns: 1fr; justify-items: center; min-height: 245px; padding: 0 10px 12px; text-align: center; }.egg-nova { width: 190px; height: 190px; margin-bottom: -20px; } }
/* 🚨 HOCHKANT WAREN DIE KACHELN KEINE QUADRATE. Gemeldet: „Fixe das easter Egg Spiel in Portrait
   wirkt es komisch!" — und genau das war es: Käfer und Fenster standen in hochkant gezogenen
   Kästen mit totem Raum darüber und darunter.

   Die Ursache ist ein Widerspruch in drei Zeilen: Das Brett bekam `height: 100%` (die Zeile des
   Kartengitters), dazu `aspect-ratio: 5/4` — und dann eine Klammer `max-width: 340px`. Die Höhe
   ist damit fest, die Breite gedeckelt, und das Seitenverhältnis hat keine Achse mehr, über die
   es sich durchsetzen könnte: 340 breit bei 411 hoch statt 340 bei 272.

   Quer stimmt es, dort gibt es die Klammer nicht — die Breite folgt der Höhe. Hochkant dreht
   dieser Block die Richtung um: Die KACHEL ist quadratisch (`aspect-ratio: 1`), das Brett wird so
   breit, wie Breite UND Höhe es zulassen (`dvh` deckelt gegen die flache Seite), und die Zeilen
   ergeben sich daraus. Damit ist das Verhältnis nicht mehr zwei Regeln, die sich widersprechen,
   sondern eine, die aus der Kachel folgt. */
@media(orientation:portrait) {
  /* 🚨 DIE KARTE IST SO HOCH WIE IHR INHALT, NICHT WIE DER SCHIRM. Mit `height: min(100%,900px)`
     stand hochkant ein leeres Band über und unter dem Brett: Das Brett kann nicht breiter werden
     als die Karte, seine Höhe folgt daraus — die übrige Höhe war Luft im Inneren. Jetzt schrumpft
     die Karte auf ihren Inhalt und steht mittig im Schirm; die Luft liegt aussen, wo sie hingehört. */
  .egg-card { height: auto; max-height: min(100%,900px); }
    /* Nova und ihr Kasten wachsen mit dem Schirm, damit dem Brett auf kurzen Geräten Platz bleibt. */
  .egg-hero { min-height: min(260px,30dvh); }
  .egg-nova { width: min(210px,24dvh); height: min(210px,24dvh); }
}
@media(orientation:portrait) and (max-width:480px) {
  .egg-board { width: min(100%,340px,44dvh); }
}

@media(max-height:700px) and (orientation:portrait) { .egg-hero { min-height: 150px; grid-template-columns: 120px minmax(0,1fr); justify-items: stretch; padding: 4px 10px; text-align: left; }.egg-nova { width: 120px; height: 120px; margin: 0; }.egg-card { padding: 10px; }.egg-board { max-width: min(100%,340px); width: min(100%,340px,38dvh); } }

/* Both landscape phones and desktops keep the preview beside the scrolling catalogue. */
@media(orientation:landscape) and ((max-height:600px) or (min-width:1001px)) {
  .nova-shop[open] { grid-template-columns: minmax(0,1fr) minmax(0,1.4fr); grid-template-rows: auto minmax(0,1fr); gap: 8px 16px; width: min(94vw,1000px); height: min(820px,calc(var(--vvh,100dvh) - 40px - var(--sa-oben) - var(--sa-unten))); padding: 16px; }
  .nova-shop .sheet-head { position: static; grid-column: 1 / -1; margin: 0; padding: 0; }
  .shop-preview { align-self: start; }
  .shop-details > .coin-note { margin-top: 0; }
}
@media(orientation:landscape) and (min-width:1001px) and (min-height:601px) {
  .shop-preview { grid-template-columns: minmax(0,1fr); justify-items: center; text-align: center; padding: 24px; }
  .shop-preview .nova-dock { width: clamp(112px,18dvh,180px); height: clamp(112px,18dvh,180px); }
  .shop-preview p { min-height: 3em; line-height: 1.5; }
}
@media(orientation:landscape) and (max-height:600px) {
  .nova-shop .sheet-head h2 { font-size: 24px; margin: 2px 0; }
  .shop-details .coin-note { font-size: 12px; }
  .shop-deal { font-size: 12px; padding: 6px 10px; }
  .shop-preview { --preview-size: clamp(48px,16dvh,88px); grid-template-columns: var(--preview-size) minmax(0,1fr); padding: 8px; min-height: 0; height: 100%; max-height: 100%; gap: 8px; }
  .shop-preview .nova-dock { width: var(--preview-size); height: var(--preview-size); }
  .shop-preview > div { display: flex; flex-direction: column; min-height: 0; max-height: 100%; }
  .shop-preview b, .shop-preview .shop-acts, .shop-preview .mini { flex: none; }
  .shop-preview b { overflow-wrap: anywhere; font-size: 13px; }
  .shop-preview p { min-height: 0; overflow-y: auto; overscroll-behavior: contain; font-size: 11px; margin: 6px 0; }
  .shop-preview .mini { font-size: 11px; padding: 8px; min-height: 44px; }
  .shop-item { padding: 8px; }
  .shop-item b { font-size: 11px; }
  .nova-egg { padding: 6px 12px; }.egg-card { width: min(100%,920px); height: 100%; grid-template-columns: minmax(0,.8fr) minmax(0,1.2fr); grid-template-rows: auto auto minmax(0,1fr) auto; gap: 6px 16px; padding: 10px 14px; }.egg-head { grid-column: 1 / -1; }.egg-head h1 { font-size: 25px; }.egg-hero { grid-column: 1; grid-row: 2 / 5; grid-template-columns: 1fr; align-content: center; justify-items: center; min-height: 0; text-align: center; }.egg-nova { width: min(31vh,180px); height: min(31vh,180px); }.egg-rule { grid-column: 2; grid-row: 2; }.egg-board { grid-column: 2; grid-row: 3; width: min(100%,58dvh); }.egg-actions { grid-column: 2; grid-row: 4; }
}

/* ── Große Bildschirme ─────────────────────────────────────────────────────
   Gemeldet: „das spiel sollte für browser, also pc optimiert werden. da nutzen wir den platz noch
   nicht gut! außerdem sollen die scrollbars kleiner dargestellt werden in chrome!"

   🚨 DIESER BLOCK MUSS AM ENDE DER DATEI STEHEN. Die Breiten-Deckel der Bildschirme und Blätter
   (`.screen-list`, `dialog`) stehen weiter oben OHNE Media-Query. Bei gleicher Spezifität gewinnt
   die spätere Regel — deshalb war der Deckel aus `@media(min-width:1001px)` (Zeile ~288)
   wirkungslos: „Novas Reise" und die Rangliste standen auch auf 2560 px als 940-px-Säule in der
   Mitte, links und rechts je 810 px leer. Wer diese Regeln nach oben schiebt, schaltet sie wieder ab.

   Das Spielbrett selbst bleibt unangetastet: Es füllt am Rechner schon die volle Höhe (auf 2560×1440
   sind das 1352 px im Quadrat), und breiter als hoch kann ein quadratisches Brett nicht werden.
   Handygrößen bleiben ebenfalls, wie sie sind — alles hier greift erst ab 1001 px. */

/* Schlanke Rollbalken statt der breiten Standardleiste von Chrome. Beide Schreibweisen stehen da:
   Chrome ab 121 und Firefox nehmen `scrollbar-width`/`scrollbar-color` und ignorieren dann die
   `::-webkit-`-Pseudoelemente; ältere Chrome- und alle Safari-Versionen kennen nur diese. Nur für
   Zeigergeräte — auf dem Handy überlagern sich die Balken ohnehin und würden sonst dauerhaft stehen. */
@media(hover:hover) and (pointer:fine) {
  html { scrollbar-width: thin; scrollbar-color: #ffffff30 transparent; }
  *, *::before, *::after { scrollbar-width: thin; scrollbar-color: #ffffff30 transparent; }
  ::-webkit-scrollbar { width: 9px; height: 9px; }
  ::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: transparent; }
  ::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background: #ffffff30; background-clip: padding-box; }
  ::-webkit-scrollbar-thumb:hover { background: #ffffff55; background-clip: padding-box; }
}

@media(min-width:1001px) and (orientation:landscape) {
  /* Der Deckel von oben, hier endlich wirksam. */
  .screen-list { width: min(100%,1180px); padding: 12px 32px 20px; }
  /* Blätter dürfen breiter werden, sobald der Bildschirm es hergibt: 520 px auf einem 1920er sind eine
     Säule mit 700 px Leere daneben, und der Inhalt rollt trotzdem. */
  dialog { width: min(92vw,560px); }
  dialog.sheet { width: min(92vw,620px); }
  .result-card { width: min(94vw,520px); }
}

/* Ab hier stehen die Blätter zweispaltig: Einstellungen und Spielregeln passen dann ohne Rollen auf
   den Schirm. `columns` statt Raster, weil es die Spalten von selbst gleich hoch macht — ein Raster
   ließe unter „Profil" eine Lücke in der Höhe von „Audio & Haptik" stehen. Der stehende Kopf
   (`.sheet-top`, siehe oben) bleibt außerhalb: In einem Mehrspaltenkasten gibt es kein `sticky`. */
@media(min-width:1280px) and (orientation:landscape) {
  dialog.sheet:has(.sheet-cols) { width: min(92vw,940px); }
  /* 🚨 KEINE SONDERBEHANDLUNG FÜR DAS ERSTE ELEMENT im Kasten. `:first-child` trifft nur das erste im
     HTML, also den Kopf der LINKEN Spalte; die rechte behielte ihren Abstand, und beide Spalten
     begännen auf verschiedener Höhe. Alle Kästen sehen gleich aus, dann fluchten die Spalten. */
  .sheet-cols { columns: 2; column-gap: 26px; margin-top: 10px; }
  .sheet-cols > * { break-inside: avoid; }
  /* Die Baustein-Übersicht darunter darf die volle Breite nutzen statt in drei weiten Spalten zu stehen. */
  .help-modules { grid-template-columns: repeat(auto-fit,minmax(88px,1fr)); }
  .settings .primary { width: calc(100% - 48px); }
}
@media(min-width:1600px) and (orientation:landscape) {
  dialog.sheet:has(.sheet-cols) { width: min(88vw,1060px); }
  .sheet-cols { column-gap: 34px; }
}

/* Novas Reise: die Karte darf mitwachsen (ihre Straße ist in Prozent gezeichnet, siehe
   `renderProgress()`), und die Erfolge daneben stehen zu zweit statt untereinander. */
@media(min-width:1500px) and (orientation:landscape) {
  .screen-list { width: min(100%,1480px); }
  #progress-screen .list-scroll { grid-template-columns: minmax(0,680px) minmax(360px,1fr); column-gap: 48px; }
  #progress-screen .head-books { max-width: 680px; }
  #progress-screen .achievements { grid-template-columns: repeat(2,minmax(0,1fr)); }
  /* Drei Karten nebeneinander brauchen mehr als 168 px, sonst bricht „Novas Vertrauen · Neu hier" um
     und die Reihe steht auf drei verschiedenen Höhen. */
  #progress-screen .campaign-bars { grid-template-columns: repeat(auto-fit,minmax(230px,1fr)); }
  .node { --w: 128px; }
  /* Die Rangliste rollt in zwei Spalten, Platz 1 oben links. `columns` füllt die linke Spalte zuerst,
     ein Raster würde Platz 2 neben Platz 1 setzen und die Reihenfolge zerreißen. Die Klasse setzt
     `loadBoard()` erst ab genug Einträgen — bei drei Namen sähen zwei Spalten albern aus. */
  .leader-list.two-up { columns: 2; column-gap: 20px; }
  .leader-list.two-up .row { break-inside: avoid; }
}
@media(min-width:2000px) and (orientation:landscape) {
  .screen-list { width: min(100%,1680px); }
  #progress-screen .list-scroll { grid-template-columns: minmax(0,760px) minmax(420px,1fr); }
  #progress-screen .head-books { max-width: 760px; }

}

/* ── Weltenauswahl ─────────────────────────────────────────────────────────
   Erscheint erst ab zwei Welten (`renderWorlds()` setzt `hidden`). Eine Zeile, die am Handy rollt statt
   umzubrechen — bei sechs Welten bräche sie sonst in drei Reihen und schöbe die Levelkarte aus dem Bild.
   Eine gesperrte Welt bleibt sichtbar und lesbar: Man soll sehen, dass es weitergeht. */
.world-picker { display: flex; gap: 8px; margin: 0 0 10px; overflow-x: auto; scroll-snap-type: x proximity; padding-bottom: 2px; }
.world-picker[hidden] { display: none; }
.world-chip { flex: 0 0 auto; max-width: 100%; overflow-wrap: anywhere; scroll-snap-align: start; display: grid; gap: 1px; text-align: left; padding: 8px 14px; min-height: 48px; border-radius: 14px; background: var(--panel); border: 1px solid var(--line); color: var(--ink); }
.world-chip b { font-size: 14px; }
.world-chip small { font-size: 11px; color: var(--muted); }
.world-chip.active { background: #7ce9ff1f; border-color: #7ce9ff77; }
.world-chip.active b { color: var(--cyan); }
.world-chip.locked { opacity: .8; }
.world-chip.locked b { color: var(--muted); }
@media(min-width:1001px) and (orientation:landscape) { .world-chip { padding: 10px 18px; } .world-chip b { font-size: 15px; } }

/* Keep the road usable in flat windows instead of stacking every control above it. */
@media(orientation:landscape) and (max-width:1000px) and (max-height:600px) {
  body[data-screen="progress"] #progress-screen, body[data-screen="leaderboard"] #leaderboard-screen { display: grid; grid-template-columns: minmax(150px,.8fr) minmax(0,1.5fr); grid-template-rows: minmax(0,1fr); gap: 14px; padding: 4px 12px 12px; }
  #progress-screen .list-head, .board-controls { min-width: 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding-right: 4px; }
  .screen-list h1 { font-size: 24px; margin-top: 4px; }
  .screen-list .list-nova { font-size: 11px; gap: 6px; padding: 6px; }
  .screen-list .list-nova .nova-small { width: 30px; height: 30px; }
  #progress-screen .head-books { grid-template-columns: minmax(0,1fr); gap: 6px; }
  #progress-screen .list-scroll { min-width: 0; padding-top: 0; }
  body[data-screen="leaderboard"] #leaderboard-screen { grid-template-rows: minmax(0,1fr) auto; gap: 8px 14px; }
  .board-controls { grid-row: 1 / -1; }
  #leaderboard-screen .list-scroll { grid-column: 2; grid-row: 1; padding-top: 0; }
  #leaderboard-screen .board-tabs { grid-template-columns: repeat(2,minmax(0,1fr)); }
  #leaderboard-screen .board-me { grid-column: 2; grid-row: 2; max-height: 120px; overflow-y: auto; margin-top: 0; }
}
@media(orientation:landscape) and (min-width:1001px) {
  #progress-screen .list-head { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); column-gap: 28px; }
  #progress-screen .list-head > .eyebrow, #progress-screen .list-head > h1, #progress-screen .world-picker { grid-column: 1 / -1; }
  #progress-screen .head-books { align-self: start; max-width: none; margin-top: 0; }
}
@media(orientation:landscape) and (min-width:1001px), (orientation:landscape) and (max-height:600px) {
  #progress-screen .head-books .diary-button { display: grid; grid-template-columns: 18px minmax(0,1fr); gap: 2px 8px; min-height: 48px; }
  #progress-screen .head-books .diary-button svg { grid-row: 1 / 3; }
  #progress-screen .head-books .diary-button small { grid-column: 2; margin: 0; white-space: normal; }
}

/* ── Duell: 2 bis 4 Spieler an einem Brett, reihum (js/duell.mjs) ─────────────────────────────────────────
   Der Eingang ist seit v170 die erste Kachel der Spielarten im Menü (siehe „Hauptmenü" am Ende der Datei).
   Im Spiel ersetzt die Spieler-Anzeige Züge, Punkte und Ziele; der Schein hinter dem Brett trägt die Farbe dessen,
   der dran ist (`--duell-schein`). */

.duell-sheet { padding: 0 0 18px; }
.duell-sheet h2 { margin: 2px 0 0; font-size: 24px; }
/* Drei Stufen: `start` (Name, Eröffnen, Code tippen), `einladung` (per Link gekommen: Name, der Raum, EIN Knopf —
   „Eröffnen oder beitreten?" war dort verwirrend, obwohl die Einladung die Antwort schon ist) und `lobby`. */
.duell-sheet[data-stufe="start"] :is(.duell-lobby, .duell-einladung), .duell-sheet[data-stufe="lobby"] :is(.duell-start, .duell-einladung, .duell-wer), .duell-sheet[data-stufe="einladung"] :is(.duell-start, .duell-lobby) { display: none; }
.duell-wer, .duell-start, .duell-einladung, .duell-lobby { display: grid; gap: 10px; padding: 4px 20px 0; }
.duell-wer { padding-bottom: 6px; }
.duell-sheet button.duell-leise { background: transparent; border: 0; color: var(--muted); font-weight: 600; font-size: 13px; min-height: 40px; }
.duell-sheet button.duell-leise.pressed { color: white; }
/* Die Knöpfe unten stehen in einer eigenen Spalte: gleich breit, untereinander, mit festem Abstand. */
.duell-aktionen { display: grid; gap: 8px; margin-top: 4px; }
.duell-sheet > .duell-aktionen { padding: 10px 20px 0; margin: 0; }
.duell-aktionen > button { width: 100%; margin: 0; }
.duell-sheet button:not(.primary):not(.round-button) { min-height: 44px; border-radius: 14px; padding: 10px 14px; font-weight: 700; }
.duell-feld { display: grid; gap: 4px; font-size: 12px; color: var(--muted); }
.duell-feld input, .duell-beitritt input { min-height: 44px; border-radius: 12px; padding: 0 12px; font-size: 16px; }
.duell-oder { margin: 4px 0 -2px; text-align: center; font-size: 12px; color: var(--muted); }
.duell-beitritt { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 8px; }
.duell-beitritt input { font: 800 20px/1 ui-monospace, Menlo, monospace; letter-spacing: .12em; text-transform: uppercase; text-align: center; }
/* Der Code steht allein in seiner Zeile und bricht nie um; „Einladen“ darunter über die ganze Breite. */
.duell-code-box { display: grid; grid-template-columns: minmax(0,1fr); align-items: center; gap: 4px; padding: 12px 14px; border-radius: 16px; background: #ffffff0d; border: 1px solid #ffffff1c; }
.duell-code-box small { font-size: 10px; letter-spacing: .14em; color: var(--muted); }
.duell-code-box b { font: 900 clamp(26px, 9vw, 36px)/1.1 ui-monospace, Menlo, monospace; letter-spacing: .1em; white-space: nowrap; color: #ffe2b8; }
.duell-code-box button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; margin-top: 4px; }
.duell-plaetze { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 8px; }
.duell-plaetze li { display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 44px; padding: 8px 10px; border-radius: 14px; background: #ffffff0a; border: 1px solid color-mix(in srgb, var(--farbe, #fff) 45%, transparent); font-weight: 700; }
.duell-plaetze li.frei { border-style: dashed; border-color: #ffffff26; color: var(--muted); font-weight: 500; }
.duell-plaetze li i { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--farbe, #ffffff33); box-shadow: 0 0 10px var(--farbe, transparent); }
.duell-plaetze li span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.duell-plaetze li small { margin-left: auto; font-size: 11px; color: var(--muted); }
.duell-regel { margin: 0; font-size: 12px; color: var(--muted); }
.duell-fehler { margin: 10px 20px 0; padding: 10px 12px; border-radius: 12px; background: #ff718322; color: #ffc2cb; font-size: 13px; }
.duell-rang { list-style: none; margin: 4px 20px 0; padding: 0; display: grid; gap: 8px; }
.duell-rang li { display: grid; grid-template-columns: 28px minmax(0,1fr) auto; align-items: center; gap: 10px; min-height: 48px; padding: 8px 12px; border-radius: 14px; background: #ffffff0a; border: 1px solid color-mix(in srgb, var(--farbe) 50%, transparent); }
.duell-rang li.eins { background: color-mix(in srgb, var(--farbe) 16%, #ffffff08); box-shadow: 0 0 18px color-mix(in srgb, var(--farbe) 30%, transparent); }
.duell-rang li > b:first-child { font-size: 18px; color: var(--farbe); text-align: center; }
.duell-rang li span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
.duell-rang li strong { font-size: 18px; font-variant-numeric: tabular-nums; }
.duell-bilanz { margin: 10px 20px 0; font-size: 13px; color: var(--muted); }
/* Im Spiel */
.duell-hud { display: grid; gap: 6px; width: 100%; }
body[data-modus="duell"] .hud-stats, body[data-modus="duell"] #goals, body[data-modus="duell"] .run-panel, body[data-modus="duell"] #nova-badge { display: none !important; }
.duell-spieler { display: grid; grid-template-columns: repeat(var(--n, 2), minmax(0,1fr)); gap: 6px; }
/* Name über die ganze Breite (er ist das Wichtigste), darunter Punkte links, übrige Züge rechts — und wenn die Karte
   dafür zu schmal ist (quer liegt sie in der schmalen Seitenspalte), rutschen die Züge unter die Punkte, statt sie
   zu überdecken. Deshalb ein umbrechender Fluss statt eines festen Rasters. */
.duell-chip { position: relative; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; min-width: 0; padding: 6px 10px; border-radius: 14px; background: #ffffff0b; border: 1px solid color-mix(in srgb, var(--farbe) 35%, transparent); transition: border-color .2s, box-shadow .2s, transform .2s; }
.duell-chip b { order: 0; flex: 1 0 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--farbe); }
.duell-chip strong { order: 1; flex: 0 1 auto; font-size: clamp(18px, 5.4vw, 24px); line-height: 1.1; font-variant-numeric: tabular-nums; }
.duell-chip small { order: 2; margin-left: auto; font-size: 10px; color: var(--muted); white-space: nowrap; }
.duell-chip[data-dran] { border-color: var(--farbe); box-shadow: 0 0 0 1px var(--farbe), 0 0 16px color-mix(in srgb, var(--farbe) 45%, transparent); }
.duell-chip[data-weg] { opacity: .45; }
.duell-chip[data-fuehrt]::after { content: '♛'; position: absolute; top: -9px; right: 8px; font-size: 13px; color: var(--gold); text-shadow: 0 0 6px #0008; }
.duell-tau { height: 6px; border-radius: 3px; background: var(--farbe-b, #ff8ae8); overflow: hidden; }
.duell-tau i { display: block; height: 100%; width: 50%; background: var(--farbe-a, #7ce9ff); transition: width .5s cubic-bezier(.2,.9,.3,1); }
.duell-zeile { display: grid; grid-template-columns: minmax(0,1fr) minmax(60px, 30%); align-items: center; gap: 10px; min-height: 22px; }
.duell-zeile b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.duell-uhr { height: 6px; border-radius: 3px; background: #ffffff14; overflow: hidden; }
.duell-uhr i { display: block; height: 100%; width: 100%; background: var(--duell-farbe, #7ce9ff); transform-origin: left; transform: scaleX(var(--rest, 1)); }
.duell-uhr.knapp i { background: #ff7183; }
body[data-modus="duell"] .board-aura { background: radial-gradient(ellipse, var(--duell-schein, #9b7bf042), transparent 70%); transition: background .4s; }
/* 🚨 DIE KARTEN RICHTEN SICH NACH IHRER SPALTE, NICHT NACH DEM FENSTER. Quer steht die Anzeige in einer schmalen
   Seitenspalte (auf 640 × 360 gut 150 px): vier Karten nebeneinander wurden dort zu Streifen mit einem Buchstaben
   Namen, und „8 Züge" ragte aus dem Bild (Geräteprüfung). Zu viert unter 420 px: 2 × 2; unter 260 px alle
   untereinander, und die Statuszeile darf umbrechen. Die Fensterregel bleibt für Browser ohne Container-Abfragen. */
@media(max-width:480px) { .duell-spieler[data-n="4"] { grid-template-columns: repeat(2, minmax(0,1fr)); } }
.duell-hud { container-type: inline-size; }
@container (max-width: 420px) { .duell-spieler[data-n="4"] { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@container (max-width: 260px) {
  .duell-spieler, .duell-spieler[data-n="4"] { grid-template-columns: minmax(0,1fr); }
  .duell-zeile { grid-template-columns: minmax(0,1fr); gap: 4px; }
  .duell-zeile b { white-space: normal; }
}
/* Leben in der Anzeige: Die Karte des Aktiven atmet, die Krone poppt auf, der Zuwachs steigt aus der Karte,
   die letzten Sekunden pulsieren, die Rangliste fährt Zeile für Zeile ein. */
.duell-chip[data-dran] { animation: duell-atmen 1.6s ease-in-out infinite; }
@keyframes duell-atmen { 50% { box-shadow: 0 0 0 1px var(--farbe), 0 0 28px color-mix(in srgb, var(--farbe) 75%, transparent); } }
.duell-chip[data-fuehrt]::after { animation: duell-krone .5s cubic-bezier(.2,.8,.2,1.4); }
@keyframes duell-krone { from { transform: scale(0) rotate(-30deg); opacity: 0; } }
.duell-plus { position: absolute; right: 8px; bottom: calc(100% - 6px); font-size: 14px; font-weight: 900; font-style: normal; color: var(--farbe); text-shadow: 0 0 8px #000, 0 1px 2px #000; pointer-events: none; animation: duell-plus 1s ease-out forwards; }
@keyframes duell-plus { from { opacity: 0; transform: translateY(10px); } 20% { opacity: 1; } to { opacity: 0; transform: translateY(-18px); } }
.duell-uhr.knapp i { animation: duell-knapp .5s ease-in-out infinite alternate; }
@keyframes duell-knapp { to { filter: brightness(1.7); } }
.duell-zeile b.tick { animation: duell-tick .3s ease; }
@keyframes duell-tick { 30% { transform: scale(1.12); color: #ffb3c0; } }
.duell-rang li { animation: rise .5s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i, 0) * 120ms); }
body.reduced .duell-chip, body.reduced .duell-tau i { transition: none; }
body.reduced .duell-chip[data-dran], body.reduced .duell-chip[data-fuehrt]::after, body.reduced .duell-uhr.knapp i, body.reduced .duell-rang li { animation: none; }

/* ── Freunde ───────────────────────────────────────────────────────────────────── */


/* ── Hauptmenü (v170) ──────────────────────────────────────────────────────────────────────────────────────
   Gemeldet: „Da ist teilweise zu viel, was man besser einteilen könnte." Vorher standen Welt, Tagesaufgabe,
   Endlos, Zeitspiel, Missionen und Rangliste als sechs gleich laute Kacheln, der Rang als eigene Leiste, Duell und
   Freunde als schwebende Knöpfe (der Freunde-Knopf lag halb auf dem Duell-Knopf) und Einstellungen, Regeln und Shop
   als kleine Textzeile ganz unten. Jetzt vier Ebenen, von „wer bin ich" bis „nachschlagen":
     1 Kopfleiste   Profil (Rang als Ring, der sich mit den XP füllt) · Münzen → Garderobe · Freunde · Einstellungen
     2 Nova         Figur, Marke, ihr Satz
     3 Spielen      EINE Hauptaktion; direkt darunter die Welt, in der man steht, mit Fortschritt (→ Karte)
     4 Spielarten   Duell (vorn, zeigt, wie viele Freunde online sind), Tagesaufgabe, Endlos, Zeitspiel
     5 Dock         Missionen · Rangliste · Spielregeln
   Hochkant eine Spalte; quer und am PC zwei (`.lobby-links` = Nova und Spielen, `.lobby-rechts` = Spielarten und
   Dock) — hochkant sind die beiden Hüllen `display: contents`, die Reihenfolge bleibt dieselbe. */
.menu { flex-direction: column; align-items: center; padding: 6px 16px 14px; overflow-y: auto; overscroll-behavior: contain; }
.lobby { width: min(100%, 540px); margin: auto; display: flex; flex-direction: column; gap: clamp(10px, 1.7dvh, 16px); }
.lobby-links, .lobby-rechts { display: contents; }
.lobby-kopf, .lobby-held, .lobby-start, .lobby-modi, .lobby-dock { animation: rise .55s cubic-bezier(.2,.8,.2,1) backwards; animation-delay: calc(var(--i,0) * 70ms + 40ms); }
body.reduced :is(.lobby-kopf, .lobby-held, .lobby-start, .lobby-modi, .lobby-dock) { animation: none; }

/* 1 Kopfleiste */
.lobby-kopf { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 48px; }
.profil { display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; gap: 10px; min-width: 0; min-height: 48px; padding: 4px 16px 4px 4px; border-radius: 999px; background: #0b2636b8; border: 1px solid var(--line); color: var(--ink); text-align: left; }
.profil-ring { --p: 0; position: relative; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: conic-gradient(var(--cyan) calc(var(--p) * 1%), #ffffff1f 0); box-shadow: 0 0 14px #7ce9ff33; }
.profil-ring::before { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #22536a, #0a1c2a 70%); }
.profil-ring b { position: relative; font-size: 15px; font-weight: 900; font-variant-numeric: tabular-nums; }
.profil-text { display: grid; min-width: 0; gap: 1px; }
.profil-text b { font-size: 14px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.profil-text small { font-size: 11px; font-weight: 600; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.profil-text progress, .profil-xp { display: none; }
.profil progress { --bar: var(--cyan); width: 100%; height: 4px; margin-top: 3px; appearance: none; -webkit-appearance: none; border: 0; border-radius: 2px; background: #ffffff18; color: var(--bar); overflow: hidden; }
.profil progress::-webkit-progress-bar { background: #ffffff18; }
.profil progress::-webkit-progress-value { background: var(--bar); box-shadow: 0 0 8px #7ce9ff99; }
.profil progress::-moz-progress-bar { background: var(--bar); }
.kopf-knoepfe { display: flex; align-items: center; gap: 8px; flex: none; }
.kopf-rund { position: relative; display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border-radius: 50%; background: #0b2636b8; border: 1px solid var(--line); color: var(--ink); }
.kopf-rund svg { color: var(--cyan); filter: drop-shadow(0 0 6px #7ce9ff66); }
.kopf-muenzen { display: inline-flex; align-items: center; gap: 7px; height: 44px; padding: 0 14px 0 6px; border-radius: 999px; background: #2a1d3fcc; border: 1px solid #ffd77a55; color: #ffe9b0; font-weight: 800; font-size: 14px; font-variant-numeric: tabular-nums; }
.muenze { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #fff3c2, #ffc94d 55%, #c78a17); color: #6b3f00; font-size: 14px; box-shadow: 0 0 12px #ffd77a55, inset 0 -2px 0 #0002; }
.kopf-wort { display: none; }
.zaehler { position: absolute; top: -5px; right: -5px; display: grid; place-items: center; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px; background: var(--pink); color: #2a0f24; font-size: 11px; font-weight: 900; border: 2px solid #0b1a26; animation: zaehler-pop .45s cubic-bezier(.3,1.6,.5,1); }
.online-punkt { position: absolute; top: 1px; right: 1px; width: 12px; height: 12px; border-radius: 50%; background: var(--green); border: 2px solid #0b1a26; box-shadow: 0 0 8px var(--green); }
.zaehler[hidden], .online-punkt[hidden] { display: none; }
@keyframes zaehler-pop { from { transform: scale(0); } }
@media(hover:hover) { :is(.profil, .kopf-rund, .kopf-muenzen):hover { border-color: #7ce9ff77; background: #10324699; } }

/* 2 Nova und die Marke */
.lobby-held { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 4px; }
.held-nova { border-radius: 50%; line-height: 0; }
/* Der Druck ist ein reines Verschieben: ein Helligkeitsfilter auf dem Knopf liess WebKit die Figur verlieren. */
.held-nova.pressed { transform: translateY(3px) !important; filter: none; }
/* `nova-hero` ist mehr als ein Name: Die Bühne liest daraus Novas Aussehen im Menü (`look-hero`, stage.mjs). */
.nova-hero { display: block; width: clamp(84px, 14dvh, 128px); height: clamp(84px, 14dvh, 128px); }
/* 🚨 DER TITEL IST EINE ZWEIZEILIGE MARKE, KEIN SATZ: der Beiname als eigene, kleinere Zeile darunter. */
.logo { margin: 0; font-size: clamp(34px, min(8.6vw, 6.6dvh), 60px); line-height: .95; letter-spacing: -.045em; }
.logo em { display: block; margin-top: .08em; font-size: .5em; font-style: normal; letter-spacing: -.01em; background: linear-gradient(90deg,#7ce9ff,#c8f7ff 40%,#7ce9ff 60%,#b191ff); background-size: 200% auto; -webkit-background-clip: text; background-clip: text; color: transparent; animation: shimmer 4s linear infinite; }
.held-zeile { position: relative; margin: 8px 0 0; padding: 8px 14px; max-width: 420px; border-radius: 16px; background: #7ce9ff14; border: 1px solid #7ce9ff44; color: var(--ink); font-size: 14px; line-height: 1.4; }
.held-zeile::before { content: ""; position: absolute; left: 50%; top: -7px; width: 12px; height: 12px; margin-left: -6px; transform: rotate(45deg); background: #17324a; border: 1px solid #7ce9ff44; border-right: 0; border-bottom: 0; border-radius: 3px 0 0 0; }
.held-zeile .bump { animation: rise .3s ease; }
.held-zeile:has(> span:empty) { display: none; }

/* 3 Spielen und die Welt darunter */
.lobby-start { display: grid; gap: 10px; }
.start-knopf { position: relative; overflow: hidden; display: grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: center; gap: 12px; width: 100%; min-height: 78px; padding: 10px 14px; border-radius: 24px; color: #14283a; background: linear-gradient(160deg,#ffe5a3,#ffae79); border: 2px solid #fff0c5; box-shadow: 0 6px 0 #995335, 0 14px 32px #0004; animation: breathe 3s ease-in-out 1s infinite; }
.start-knopf::after { content: ""; position: absolute; top: -20%; bottom: -20%; width: 34%; background: linear-gradient(90deg,transparent,#ffffff77,transparent); animation: sheen 3.6s ease-in-out infinite; pointer-events: none; }
.start-knopf strong { min-width: 0; font-size: 28px; line-height: 1.05; }
.start-knopf small { display: block; margin-top: 3px; font-size: 12.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.start-icon, .start-pfeil { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: #14283a1c; }
.start-knopf.pressed { transform: translateY(6px) !important; box-shadow: 0 0 0 #995335, 0 4px 14px #0004; filter: brightness(.97); }
.start-knopf.nudge { animation: nudge .7s ease 3; }
@media(hover:hover) { .start-knopf:hover { transform: translateY(-2px); filter: brightness(1.04); } }
.welt-leiste { --a: var(--world-accent, var(--gold)); display: grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: center; gap: 12px; min-height: 58px; padding: 8px 10px 8px 14px; border-radius: 18px; text-align: left; color: var(--ink); background: linear-gradient(120deg, color-mix(in srgb, var(--a) 22%, #0e2a3a), #0b2233cc 72%); border: 1px solid color-mix(in srgb, var(--a) 45%, transparent); box-shadow: 0 3px 0 #061824; }
.welt-icon { color: var(--a); filter: drop-shadow(0 0 8px color-mix(in srgb, var(--a) 70%, transparent)); }
.welt-text { display: grid; min-width: 0; gap: 1px; }
.welt-text b { font-size: 15px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.welt-text small { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.welt-balken { display: block; height: 5px; margin-top: 4px; border-radius: 3px; background: #ffffff1a; overflow: hidden; }
.welt-balken i { display: block; width: 0; height: 100%; border-radius: inherit; background: var(--a); box-shadow: 0 0 8px var(--a); transition: width .6s cubic-bezier(.2,.8,.2,1); }
.welt-karte { display: inline-flex; align-items: center; gap: 4px; min-height: 34px; padding: 0 10px 0 12px; border-radius: 999px; background: #ffffff14; font-size: 12px; font-weight: 800; }
.welt-leiste.pressed { transform: translateY(3px) !important; box-shadow: 0 0 0 #061824; filter: brightness(1.06); }
@media(hover:hover) { .welt-leiste:hover { filter: brightness(1.08); } }
/* Die vier Zahlen gibt es nur am PC (dort ist Platz neben den Kacheln); hochkant und quer fehlen sie. */
.menu-stats { display: none; }

/* 4 Spielarten */
.lobby-modi { display: grid; gap: 8px; }
.lobby-titel { margin: 2px 4px 0; font-size: 11px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.kacheln { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); grid-auto-rows: 1fr; gap: 10px; }
.kachel { --a: var(--cyan); position: relative; overflow: hidden; display: grid; grid-template-columns: 30px minmax(0,1fr); grid-template-rows: auto auto; align-content: center; gap: 2px 10px; align-items: center; min-height: 74px; padding: 12px; border-radius: 20px; text-align: left; color: var(--ink); background: linear-gradient(150deg, color-mix(in srgb, var(--a) 17%, #1d4556), #0f2b3b); box-shadow: 0 4px 0 #061824, inset 0 1px 0 #ffffff18; }
.kachel::before { content: ""; position: absolute; inset: 0; background: radial-gradient(circle at 15% 20%, color-mix(in srgb, var(--a) 32%, transparent), transparent 58%); opacity: .75; transition: opacity .25s; }
.kachel-icon { grid-row: span 2; color: var(--a); filter: drop-shadow(0 0 8px color-mix(in srgb, var(--a) 70%, transparent)); }
.kachel strong, .kachel span { position: relative; display: block; min-width: 0; }
.kachel strong { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kachel span { font-size: 11px; color: var(--muted); overflow-wrap: anywhere; }
.kachel-duell { --a: #ffb86b; border: 1px solid #ffb86b55; }
.kachel-daily { --a: var(--cyan); }
.kachel-endless { --a: var(--pink); }
.kachel-sprint { --a: var(--violet); }
.kachel.done .kachel-icon, .kachel.done span { color: var(--green); }
/* Ist ein Freund online, pulsiert an der Duell-Kachel ein grüner Punkt (die Zeile darunter sagt, wie viele). */
.kachel-duell.live::after { content: ""; position: absolute; top: 10px; right: 10px; width: 9px; height: 9px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 0 #6ff0bd99; animation: live-puls 1.8s ease-out infinite; }
@keyframes live-puls { 70% { box-shadow: 0 0 0 9px #6ff0bd00; } 100% { box-shadow: 0 0 0 0 #6ff0bd00; } }
.kachel.pressed { transform: translateY(4px) !important; box-shadow: 0 0 0 #061824, inset 0 1px 0 #ffffff10; filter: brightness(1.06); }
@media(hover:hover) { .kachel:hover { transform: translateY(-2px); box-shadow: 0 6px 0 #061824, 0 12px 30px #0006; } .kachel:hover::before { opacity: 1; } }

/* 5 Dock */
.lobby-dock { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 8px; }
.dock-knopf { --a: var(--muted); display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; gap: 8px; min-height: 52px; padding: 8px 10px; border-radius: 16px; background: #ffffff0a; border: 1px solid #ffffff14; color: var(--ink); text-align: left; }
.dock-knopf svg { color: var(--a); flex: none; }
.dock-knopf span { display: grid; min-width: 0; }
.dock-knopf b { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dock-knopf small { font-size: 10.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#missions { --a: #ffb0ff; }#leaderboard { --a: var(--green); }#help { --a: var(--cyan); }
.dock-knopf.done small { color: var(--green); }
.dock-knopf.pressed { transform: translateY(2px) !important; background: #ffffff14; filter: none; }
@media(hover:hover) { .dock-knopf:hover { background: #ffffff12; border-color: #ffffff2a; } }

/* Einladung eines Freundes zum Duell: eine Karte oben im Menü, bis man beitritt oder sie wegtippt. */
.einladung-karte { position: fixed; z-index: 30; left: 50%; bottom: calc(var(--sa-unten) + 12px); width: min(calc(100% - 24px), 460px); transform: translateX(-50%); display: grid; grid-template-columns: auto minmax(0,1fr) auto auto; align-items: center; gap: 10px; padding: 10px; border-radius: 20px; background: linear-gradient(135deg, #3a2512f5, #22163af5); border: 1px solid #ffb86b99; box-shadow: 0 16px 40px #000a, 0 0 30px #ffb86b33; animation: einladung-rein .5s cubic-bezier(.2,.9,.3,1.2); }
.einladung-karte[hidden] { display: none; }
.einladung-text { display: grid; min-width: 0; }
.einladung-text b { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.einladung-text small { font-size: 12px; color: #ffd9b3; }
.einladung-bei { min-height: 44px; padding: 0 16px; border-radius: 14px; font-weight: 900; color: #3a1d00; background: linear-gradient(#ffd08a,#ffa45c); border-color: #ffe2bf; box-shadow: 0 3px 0 #8a4a15; }
.einladung-weg { display: grid; place-items: center; width: 40px; height: 40px; padding: 0; border-radius: 50%; background: #ffffff12; color: var(--muted); }
@keyframes einladung-rein { from { opacity: 0; transform: translate(-50%, 28px) scale(.96); } }
body.reduced .einladung-karte { animation: none; }

/* Quer auf dem Handy und flache Fenster: zwei Spalten, nichts rollt — es passt oder es schrumpft. */
@media (orientation: landscape) and (max-height: 600px) {
  .menu { padding: 4px 16px 6px; overflow: hidden; }
  .lobby { width: min(100%, 980px); height: 100%; display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); gap: 8px 22px; }
  .lobby-kopf { grid-column: 1 / -1; min-height: 40px; }
  .lobby-links, .lobby-rechts { display: flex; flex-direction: column; justify-content: center; gap: min(10px, 2.4dvh); min-height: 0; }
  .lobby-held { display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; justify-items: start; text-align: left; gap: 4px 12px; }
  .nova-hero { width: min(64px, 17dvh); height: min(64px, 17dvh); }
  .logo { font-size: min(36px, 9.5dvh); }
  .held-zeile { grid-column: 1 / -1; margin-top: 6px; font-size: clamp(11px, 3dvh, 12.5px); line-height: 1.35; padding: 6px 10px; }
  .held-zeile::before { left: 26px; }
  .held-zeile > span { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
  .start-knopf { min-height: min(64px, 16dvh); padding: 6px 12px; }.start-knopf strong { font-size: min(26px, 7dvh); }
  .start-icon, .start-pfeil { width: min(40px, 11dvh); height: min(40px, 11dvh); }
  .welt-leiste { min-height: min(52px, 14dvh); padding: 4px 8px 4px 12px; }
  .lobby-rechts { justify-content: stretch; }
  .lobby-modi { flex: 1; min-height: 0; grid-template-rows: minmax(0, 1fr); }
  .lobby-titel { display: none; }
  .kacheln { min-height: 0; grid-auto-rows: minmax(0, 1fr); }
  .kachel { min-height: 0; padding: 8px 10px; }
  .dock-knopf { min-height: min(46px, 12dvh); padding: 4px 8px; }
}
/* Sehr flach (iPhone SE quer, 320 hoch) oder sehr schmal quer: Nova-Zeile auf eine Zeile, Kopf enger. */
@media (orientation: landscape) and ((max-height: 380px) or (max-width: 700px)) {
  .lobby-kopf { min-height: 36px; }
  .profil { min-height: 38px; padding-right: 12px; }.profil-ring { width: 32px; height: 32px; }.profil-ring b { font-size: 13px; }
  .kopf-rund, .kopf-muenzen { height: 38px; }.kopf-rund { width: 38px; }.muenze { width: 26px; height: 26px; }
  .held-zeile > span { -webkit-line-clamp: 1; line-clamp: 1; }
  .kachel strong { font-size: 13px; }.kachel span { font-size: 10px; }.kachel { gap: 1px 8px; }
  .dock-knopf small { display: none; }
}

/* Hochkant, niedrige Fenster: erst der Abschnittstitel, dann Nova kleiner, ganz unten auch ihre Zeile. */
@media (orientation: portrait) and (max-height: 740px) {
  .lobby-titel { display: none; }
  .nova-hero { width: 76px; height: 76px; }
  .held-zeile { font-size: 13px; padding: 6px 12px; }
}
@media (orientation: portrait) and (max-height: 650px) {
  .lobby { gap: 9px; }
  .nova-hero { width: 62px; height: 62px; }
  .logo { font-size: 30px; }
  .held-zeile { display: none; }
  .start-knopf { min-height: 64px; }.start-knopf strong { font-size: 24px; }
  .welt-leiste { min-height: 50px; }
  .kachel { min-height: 62px; padding: 9px 10px; }
  .dock-knopf { min-height: 46px; }
}
/* Schmale Handys: Dock-Einträge stehen als Symbol über dem Wort, die Nebenzeile fällt weg. */
@media (max-width: 400px) {
  .dock-knopf { grid-template-columns: minmax(0,1fr); justify-items: center; text-align: center; gap: 2px; padding: 6px 4px; }
  .dock-knopf span { justify-items: center; }
  .dock-knopf small { display: none; }
  .kachel { grid-template-columns: 26px minmax(0,1fr); gap: 2px 8px; padding: 10px; }.kachel-icon { width: 26px; height: 26px; }
  .kachel strong { font-size: 14px; }.kachel span { font-size: 10.5px; }
  .profil-text small { font-size: 10px; }
}
@media (max-width: 340px) {
  .kopf-muenzen { padding-right: 10px; }.lobby-kopf { gap: 6px; }.kopf-knoepfe { gap: 6px; }
  .kachel { grid-template-columns: minmax(0,1fr); }.kachel-icon { display: none; }
}
/* Tablet hochkant: mehr Luft, größere Kacheln. */
@media (orientation: portrait) and (min-width: 700px) and (min-height: 900px) {
  .lobby { width: min(100%, 600px); gap: 18px; }
  .kachel { min-height: 104px; padding: 16px; grid-template-columns: 36px minmax(0,1fr); }.kachel-icon { width: 34px; height: 34px; }
  .kachel strong { font-size: 18px; }.kachel span { font-size: 13px; }
  .dock-knopf { min-height: 60px; }.dock-knopf b { font-size: 14px; }.dock-knopf small { font-size: 12px; }
}

/* PC und Tablet quer: Nova und Spielen links, Spielarten und Dock rechts, die Kopfleiste darüber. */
@media (min-width: 1001px) and (orientation: landscape) and (min-height: 601px) {
  .menu { padding: 18px 40px 24px; }
  .lobby { width: min(100%, 1180px); display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.12fr); grid-template-rows: auto 1fr; gap: 26px 64px; }
  .lobby-kopf { grid-column: 1 / -1; }
  .lobby-links, .lobby-rechts { display: flex; flex-direction: column; justify-content: center; gap: 20px; min-width: 0; }
  .profil { grid-template-columns: auto minmax(0,1fr) auto; min-width: 320px; gap: 12px; padding-right: 18px; }
  .profil-text progress { display: block; }.profil-xp { display: block; font-size: 12px; color: var(--muted); font-weight: 700; font-variant-numeric: tabular-nums; }
  .profil-ring { width: 44px; height: 44px; }
  .kopf-wort { display: inline; font-weight: 700; color: #ffe9b0cc; }.kopf-wort::before { content: "·"; margin-right: 7px; opacity: .6; }
  .lobby-held { display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; justify-items: start; text-align: left; gap: 8px 22px; }
  .nova-hero { width: 150px; height: 150px; }
  .logo { font-size: clamp(52px, 5.4vw, 82px); }
  .held-zeile { grid-column: 1 / -1; font-size: 16px; }.held-zeile::before { left: 60px; }
  .start-knopf { min-height: 92px; padding: 12px 20px; border-radius: 28px; }.start-knopf strong { font-size: 34px; }.start-knopf small { font-size: 14px; }
  .start-icon, .start-pfeil { width: 52px; height: 52px; }
  .welt-leiste { min-height: 66px; padding: 10px 12px 10px 18px; }.welt-text b { font-size: 17px; }.welt-text small { font-size: 13px; }
  .menu-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
  .menu-stats div { padding: 8px 6px; border-radius: 14px; background: #ffffff0c; border: 1px solid #ffffff12; text-align: center; }
  .menu-stats b { display: block; font-size: 20px; line-height: 1.15; font-variant-numeric: tabular-nums; }
  .menu-stats small { display: block; font-size: 10px; letter-spacing: .1em; color: var(--muted); white-space: nowrap; }
  .kacheln { gap: 16px; }
  .kachel { min-height: 132px; padding: 18px 18px 18px 20px; border-radius: 24px; grid-template-columns: 44px minmax(0,1fr); }.kachel-icon { width: 40px; height: 40px; }
  .kachel strong { font-size: 20px; line-height: 1.2; }.kachel span { font-size: 13.5px; margin-top: 4px; }
  .dock-knopf { min-height: 64px; padding: 10px 14px; gap: 12px; }.dock-knopf b { font-size: 15px; }.dock-knopf small { font-size: 12.5px; }
}
@media (min-width: 1001px) and (orientation: landscape) and (min-height: 601px) and (max-height: 760px) {
  .menu-stats { display: none; }.nova-hero { width: 110px; height: 110px; }.kachel { min-height: 108px; }
}
@media (min-width: 1600px) and (orientation: landscape) and (min-height: 601px) {
  .lobby { width: min(100%, 1320px); column-gap: 90px; }
}

/* ── Freunde (v170, js/friends.mjs) ─────────────────────────────────────────────────────────────────────── */
.freunde { width: min(92vw, 540px); padding: 0 0 18px; }
.freunde h2 { margin: 2px 0 0; font-size: 26px; }
/* 🚨 minmax(0,1fr): Eine Rasterspalte weicht sonst nie unter ihren breitesten Inhalt — eine Karte mit langem Namen und
   zwei Knöpfen machte auf 280 px die ganze Spalte breiter als das Blatt, und der Such-Knopf ragte hinaus. */
.freunde-rumpf { display: grid; grid-template-columns: minmax(0,1fr); gap: 12px; padding: 2px 20px 0; }
.freunde-ich { display: grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: center; gap: 12px; padding: 12px; border-radius: 18px; background: linear-gradient(135deg, #7ce9ff1a, #b191ff14); border: 1px solid #7ce9ff33; }
.freunde-ich:empty { display: none; }
.freunde-ich .freund-wer small:first-child { font-size: 10px; font-weight: 800; letter-spacing: .14em; color: var(--cyan); }
.freunde-name { grid-column: 1 / -1; display: grid; gap: 6px; }
.freunde-name b { font-size: 15px; }.freunde-name span { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.freunde-name div { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 8px; }
.freunde-name input { min-height: 44px; border-radius: 12px; font-size: 16px; }
.freunde-suche { position: relative; display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 8px; }
.freunde-suche input { width: 100%; min-height: 48px; padding: 0 12px 0 42px; border-radius: 14px; font-size: 16px; background: #0b2233; border: 1px solid #7ce9ff33; color: var(--ink); }
.freunde-suche input:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 0 3px #7ce9ff33; }
.freunde-suche input::-webkit-search-cancel-button { -webkit-appearance: none; }
.freunde-lupe { position: absolute; left: 14px; top: 15px; color: var(--muted); pointer-events: none; }
.freunde-suche button { display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border-radius: 14px; color: #17263c; background: linear-gradient(#acffd0,#7bd7b6); border-color: #d6ffe8; box-shadow: 0 3px 0 #2b6b5a; }
.freunde-hinweis { margin: -4px 6px 0; font-size: 12px; color: var(--muted); line-height: 1.4; }
.freunde-hinweis:empty { display: none; }
.freunde-treffer, .freunde-liste { display: grid; grid-template-columns: minmax(0,1fr); gap: 8px; }
.freunde-treffer { padding: 10px; border-radius: 18px; background: #ffffff06; border: 1px solid #7ce9ff2e; }
.freunde-treffer[hidden] { display: none; }
.freunde-liste h3, .freunde-treffer h3 { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 6px 4px 0; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
.freunde-treffer h3 { margin-top: 0; }
.freunde-reiter { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 4px; padding: 4px; border-radius: 14px; background: #0b2233; border: 1px solid #ffffff14; }
.freunde-reiter button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 0; min-height: 40px; padding: 0 6px; border: 0; border-radius: 10px; background: transparent; color: var(--muted); font-size: 13px; font-weight: 700; white-space: nowrap; }
.freunde-reiter button[aria-selected="true"] { background: #7ce9ff22; color: var(--ink); box-shadow: inset 0 0 0 1px #7ce9ff55; }
.reiter-zahl { display: grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; background: #ffffff1f; color: var(--ink); font-size: 11px; }
.reiter-zahl:empty { display: none; }
.reiter-zahl.heiss { background: var(--pink); color: #2a0f24; }
.freund { display: grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: center; gap: 12px; min-height: 64px; padding: 10px 10px 10px 12px; border-radius: 18px; background: linear-gradient(135deg, #1a3b52cc, #0d2233cc); border: 1px solid #ffffff14; animation: rise .35s ease backwards; }
body.reduced .freund { animation: none; }
.freund.einladung { border-color: #ffb86b88; background: linear-gradient(135deg, #3a2512cc, #1d1a38cc); box-shadow: 0 0 22px #ffb86b22; }
.freund.anfrage { border-color: #ff8ae866; }
.freund.gesperrt { opacity: .78; }
.freund-avatar { --h: 200; position: relative; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; font-size: 15px; font-weight: 900; color: #081624; background: linear-gradient(145deg, hsl(var(--h) 90% 76%), hsl(calc(var(--h) + 40) 70% 58%)); box-shadow: inset 0 -3px 0 #0003, 0 2px 8px #0005; }
.freund-avatar.gross { width: 52px; height: 52px; font-size: 18px; }
.freund-avatar.online::after { content: ""; position: absolute; right: -1px; bottom: -1px; width: 13px; height: 13px; border-radius: 50%; background: var(--green); border: 2.5px solid #13263a; box-shadow: 0 0 8px var(--green); }
.freund-wer { display: grid; min-width: 0; gap: 2px; }
.freund-wer b { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.freund-wer small { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.freund-tag { font-variant-numeric: tabular-nums; opacity: .85; }
.freund-status.online { color: var(--green); font-weight: 700; }
.freund-aktionen { display: flex; align-items: center; gap: 6px; }
.freund-extra { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; border-top: 1px dashed #ffffff1c; }
.freund-extra[hidden] { display: none; }
.freund-marke { padding: 0 6px; font-size: 12px; font-weight: 800; color: var(--green); white-space: nowrap; }
.fk { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 40px; padding: 0 14px; border-radius: 12px; background: #ffffff12; border: 1px solid #ffffff22; color: var(--ink); font-size: 13px; font-weight: 800; white-space: nowrap; }
.fk-haupt { color: #17263c; background: linear-gradient(#acffd0,#7bd7b6); border-color: #d6ffe8; box-shadow: 0 3px 0 #2b6b5a; }
.fk-duell { color: #ffe2bf; background: #2b1d0fcc; border-color: #ffb86b88; }.fk-duell svg { color: #ffb86b; }
.fk-duell.heiss { color: #3a1d00; background: linear-gradient(#ffd08a,#ffa45c); border-color: #ffe2bf; box-shadow: 0 3px 0 #8a4a15; }.fk-duell.heiss svg { color: #3a1d00; }
.fk-leise { color: var(--muted); background: transparent; border-color: #ffffff26; }
.fk-leise.gefahr { color: #ffb3c0; border-color: #ff718355; }
.fk-rund { width: 40px; padding: 0; }
.fk.scharf { color: #2a0610; background: #ff7183; border-color: #ffb3c0; }
.fk.wartet { opacity: .6; }
.fk.pressed { transform: translateY(2px) !important; filter: brightness(.95); }
.freunde-leer { display: grid; justify-items: center; gap: 6px; padding: 26px 18px; border-radius: 18px; border: 1px dashed #7ce9ff33; background: #ffffff05; text-align: center; color: var(--muted); font-size: 13px; line-height: 1.45; }
.freunde-leer svg { color: var(--cyan); opacity: .85; }
.freunde-leer b { color: var(--ink); font-size: 15px; }
.freunde-leer.klein { padding: 16px; }
.freunde-cta { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin-top: 6px; padding: 0 18px; border-radius: 14px; background: #7ce9ff22; border: 1px solid #7ce9ff66; color: var(--ink); font-weight: 800; }
.freund.platzhalter { animation: none; }
.freund.platzhalter :is(.freund-avatar, b, small) { color: transparent; box-shadow: none; border-radius: 8px; background: linear-gradient(90deg, #ffffff0d, #ffffff1f, #ffffff0d); background-size: 200% 100%; animation: glimmer 1.2s linear infinite; }
.freund.platzhalter .freund-avatar { border-radius: 50%; }
.freund.platzhalter b { width: 60%; height: 14px; }.freund.platzhalter small { width: 38%; height: 11px; }
@keyframes glimmer { to { background-position: -200% 0; } }
body.reduced .freund.platzhalter :is(.freund-avatar, b, small) { animation: none; }
/* Eine Einladung ist die wichtigste Karte im Blatt: Name über die ganze Breite, die Knöpfe in einer eigenen Zeile. */
.freund.einladung { grid-template-columns: auto minmax(0,1fr); }
.freund.einladung .freund-aktionen { grid-column: 1 / -1; }
.freund.einladung .fk-duell { flex: 1; }
@media (max-width: 400px) {
  .freunde-rumpf { padding: 2px 14px 0; }
  .freund { gap: 10px; padding: 8px; }.freund-avatar { width: 38px; height: 38px; font-size: 13px; }
  .fk { padding: 0 10px; }.freunde-reiter button { font-size: 12px; gap: 4px; }.reiter-zahl { min-width: 18px; height: 18px; padding: 0 5px; }
}
/* Hohe Kacheln (quer, Tablet, PC): Symbol als Plakette oben links, Titel und Zeile unten — in einer hohen Kachel
   hing sonst das Symbol mittig und der Text oben, und dazwischen klaffte die Leere. */
@media (orientation: landscape) and (max-height: 600px), (min-width: 1001px) and (orientation: landscape), (orientation: portrait) and (min-width: 700px) and (min-height: 900px) {
  /* Das Symbol steht im Fluss und schiebt mit `margin-bottom: auto` den Text nach unten — es kann ihn nie überdecken. */
  .kachel { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
  .kachel-icon { position: relative; flex: none; margin-bottom: auto; box-sizing: content-box; padding: 7px; border-radius: 14px; background: color-mix(in srgb, var(--a) 16%, transparent); }
  .kachel strong { width: 100%; margin-top: 6px; }
}
@media (min-width: 1001px) and (orientation: landscape) and (min-height: 601px) { .kachel-icon { padding: 9px; } }
@media (orientation: landscape) and (max-height: 600px) { .kachel-icon { padding: 5px; }.kachel strong { margin-top: 2px; } }
@media (orientation: landscape) and ((max-height: 380px) or (max-width: 700px)) {
  .kachel { grid-template-columns: none; }.kachel-icon { width: 20px; height: 20px; }
  .dock-knopf { grid-template-columns: minmax(0,1fr); justify-items: center; gap: 0; padding: 3px 4px; }.dock-knopf span { justify-items: center; }
  .dock-knopf b { font-size: 11px; }.dock-knopf svg { width: 18px; height: 18px; }
}
/* Große Handys hochkant: die Höhe ist da — Kacheln und Dock bekommen sie, statt unten Leere zu lassen. */
@media (orientation: portrait) and (max-width: 699px) and (min-height: 800px) {
  .kachel { min-height: 88px; }.dock-knopf { min-height: 60px; }.nova-hero { width: 132px; height: 132px; }
}
/* Schmale Handys: Münzen ohne Plakette, runde Knöpfe 40 px — so bleibt dem Profil Platz für den Namen. */
@media (max-width: 360px) {
  .kopf-muenzen { gap: 4px; padding: 0 10px; height: 40px; }.muenze { width: auto; height: auto; background: none; box-shadow: none; color: #ffd77a; font-size: 15px; }
  .kopf-rund { width: 40px; height: 40px; }
  .profil { gap: 8px; padding-right: 10px; }.profil-ring { width: 36px; height: 36px; }
}
@media (max-width: 360px) {
  .freund:not(.einladung) .fk-duell { width: 40px; padding: 0; }.freund:not(.einladung) .fk-duell span { display: none; }
  .freunde-ich .fk { width: 40px; padding: 0; }.freunde-ich .fk span { display: none; }
}
/* Ganz schmal (Fold außen): Knöpfe jeder Karte in eine eigene Zeile, rechtsbündig — der Name behält die Breite. */
@media (max-width: 340px) {
  .freund { grid-template-columns: auto minmax(0,1fr); }
  .freund-aktionen { grid-column: 1 / -1; justify-content: flex-end; }
  .freund:not(.einladung) .fk-duell { width: auto; padding: 0 12px; }.freund:not(.einladung) .fk-duell span { display: inline; }
}
/* Hochkant und sehr niedrig (320 × 480): Nova steht links neben der Marke statt darüber, alles eine Stufe kleiner —
   so passen Kopfleiste, Spielen, Welt, vier Spielarten und Dock ohne Rollen. */
@media (orientation: portrait) and (max-height: 540px) {
  .lobby { gap: 7px; }
  .lobby-kopf { min-height: 40px; }.profil { min-height: 40px; }.profil-ring { width: 34px; height: 34px; }
  .kopf-rund { width: 40px; height: 40px; }.kopf-muenzen { height: 40px; }
  .lobby-held { display: grid; grid-template-columns: auto auto; justify-content: center; align-items: center; gap: 0 10px; text-align: left; }
  .nova-hero { width: 48px; height: 48px; }.logo { font-size: 26px; }
  .start-knopf { min-height: 54px; padding: 6px 12px; }.start-knopf strong { font-size: 22px; }.start-icon, .start-pfeil { width: 36px; height: 36px; }
  .welt-leiste { min-height: 44px; padding: 4px 8px 4px 12px; }
  .kachel { min-height: 52px; padding: 7px 10px; }
  .dock-knopf { min-height: 42px; padding: 4px; }.dock-knopf svg { width: 18px; height: 18px; }
}
