/* LWShell — Drawer-UI (Game-Shell, §S5). Nutzt Tokens aus style.css. */

/* Etappe 51 (Issue #6): EIN Flex-Container für alle Top-Right-Buttons — löst die
   frühere Offset-Kollision (Uhr lag auf ❓). Neue Buttons einfach anhängen. */
.shell-topbar {
    position: fixed; z-index: 50;
    top: max(14px, env(safe-area-inset-top)); right: max(14px, env(safe-area-inset-right));
    display: flex; gap: 10px;
}
.shell-topbar > button {
    width: 44px; height: 44px; border-radius: 12px; font-size: 20px; cursor: pointer;
    background: var(--panel); border: 1px solid var(--panel-border); color: var(--text);
    backdrop-filter: blur(14px); position: relative; flex: 0 0 auto;
}
.shell-topbar > button:hover { background: rgba(255, 255, 255, .12); }

.shell-help[hidden] { display: none; }
/* Erstnutzer-Anstupser: kurzer Puls */
.shell-help.pulse { animation: shell-help-pulse 1.1s ease-in-out infinite; border-color: var(--accent); }
@keyframes shell-help-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(79, 140, 255, .0); }
    50% { box-shadow: 0 0 0 7px rgba(79, 140, 255, .28); }
}
@media (prefers-reduced-motion: reduce) { .shell-help.pulse { animation: none; border-color: var(--accent); } }

/* Etappe 49: „💬 Chat" — Position/Größe kommt jetzt vom .shell-topbar-Container */
.shell-chat-btn[hidden] { display: none; }
.shell-chat-btn .chat-badge {
    position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px;
    border-radius: 999px; background: var(--red); color: #fff;
    font-size: 11px; font-weight: 800; line-height: 18px; padding: 0 4px;
}
.shell-chat-btn .chat-badge[hidden] { display: none; }

/* ── Etappe 76: Emotes (S24 — flüchtig, nichts davon liegt im State) ── */
.shell-emote-btn[hidden] { display: none; }
.shell-emote-btn:disabled { opacity: .45; cursor: default; }

/* Die Auswahl hängt unter der Topbar. Zwei Reihen zu vier: Acht Stück passen
   so auf jedes Handy, ohne dass eine Reihe abschneidet. */
.shell-emote-pick {
    position: fixed; z-index: 60;
    top: calc(max(14px, env(safe-area-inset-top)) + 54px);
    right: max(14px, env(safe-area-inset-right));
    display: grid; grid-template-columns: repeat(4, 44px); gap: 6px;
    padding: 8px; border-radius: 14px;
    background: var(--panel); border: 1px solid var(--panel-border);
    backdrop-filter: blur(14px);
}
.shell-emote-pick[hidden] { display: none; }
.shell-emote-pick button {
    width: 44px; height: 44px; border-radius: 10px; font-size: 22px; cursor: pointer;
    background: transparent; border: 1px solid transparent; color: var(--text);
}
.shell-emote-pick button:hover { background: rgba(255, 255, 255, .12); }

/* Die Blasen-Ebene fängt KEINE Klicks — sie liegt über dem ganzen Spielfeld.
   Der Flex-Aufbau gilt nur den gestapelten Blasen; verankerte sind `fixed`
   und stehen ohnehin außerhalb des Flusses. */
.shell-emote-layer {
    position: fixed; inset: 0; z-index: 58; pointer-events: none;
    display: flex; flex-direction: column; justify-content: flex-end;
    align-items: center; padding-bottom: 84px;
}
.shell-emote-bub {
    position: fixed; transform: translate(-50%, -115%);
    font-size: 26px; line-height: 1;
    padding: 5px 8px; border-radius: 999px;
    background: var(--panel); border: 1px solid var(--panel-border);
    white-space: nowrap;
    animation: shell-emote-pop 2.5s ease-out forwards;
}
/* Ohne Anker (eigener Sitz, eingeklappte Liste, Spiel ohne Avatare):
   gestapelt am unteren Rand. „Nichts passiert" wäre die schlechteste
   Antwort auf einen Klick. */
.shell-emote-bub.stacked {
    position: static; transform: none;
    margin: 6px auto 0; width: max-content; max-width: 90vw;
    font-size: 18px; overflow: hidden; text-overflow: ellipsis;
    animation: shell-emote-fade 2.5s ease-out forwards;
}
@keyframes shell-emote-pop {
    0% { opacity: 0; transform: translate(-50%, -95%) scale(.7); }
    12% { opacity: 1; transform: translate(-50%, -115%) scale(1); }
    80% { opacity: 1; transform: translate(-50%, -125%) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -140%) scale(.95); }
}
@keyframes shell-emote-fade {
    0% { opacity: 0; } 12%, 80% { opacity: 1; } 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    /* Sichtbar BLEIBEN, nur nicht wandern — sonst wäre „Bewegung aus" ein
       „Emotes aus", und das ist ein anderer Schalter. */
    .shell-emote-bub, .shell-emote-bub.stacked { animation: none; opacity: 1; }
}

/* Chat-Overlay (über dem Drawer) */
.shell-chat { z-index: 65; }
.shell-chat .sc-panel { width: min(520px, 100%); max-height: 82vh; display: flex; flex-direction: column; gap: 12px; }
.shell-chat .sc-head { display: flex; align-items: center; gap: 10px; }
.shell-chat .sc-head h2 { margin-right: auto; font-size: 20px; }
.shell-chat .sc-log { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; min-height: 30vh; }
.shell-chat .sc-msg { display: flex; flex-direction: column; gap: 2px; padding: 8px 11px; border-radius: 12px;
    background: rgba(255, 255, 255, .05); border: 1px solid var(--panel-border); max-width: 88%; }
.shell-chat .sc-msg.mine { align-self: flex-end; background: rgba(88, 101, 242, .18); border-color: rgba(88, 101, 242, .4); }
.shell-chat .sc-who { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); font-weight: 600; }
.shell-chat .sc-who .av { width: 20px; height: 20px; font-size: 12px; }
.shell-chat .sc-at { margin-left: 4px; font-weight: 400; opacity: .75; }
.shell-chat .sc-text { font-size: 15px; line-height: 1.4; overflow-wrap: anywhere; }
.shell-chat .sc-form { display: grid; grid-template-columns: 1fr auto; gap: 8px; }
.shell-chat .sc-input { min-height: 44px; }
.shell-chat .sc-send { min-height: 44px; padding: 0 16px; }

/* Regel-Overlay (über dem Drawer, z-index 60) */
.shell-rules { z-index: 65; }
.shell-rules .sr-panel { width: min(520px, 100%); max-height: 82vh; display: flex; flex-direction: column; gap: 14px; }
.shell-rules .sr-head { display: flex; align-items: center; gap: 10px; }
.shell-rules .sr-head h2 { margin-right: auto; font-size: 20px; }
.shell-rules .sr-body { overflow-y: auto; line-height: 1.5; }
.shell-rules .sr-body p { margin: 0 0 10px; }
.shell-rules .sr-body p:last-child { margin-bottom: 0; }
.shell-rules .sr-ok { align-self: flex-end; }

.shell-scrim { position: fixed; inset: 0; z-index: 55; background: rgba(5, 8, 14, .55); backdrop-filter: blur(3px); }
.shell-scrim[hidden] { display: none; }

.shell-drawer {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 60;
    width: min(340px, 88vw);
    padding: max(18px, env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right)) calc(18px + env(safe-area-inset-bottom)) 18px;
    background: #10141d; border-left: 1px solid var(--panel-border);
    display: flex; flex-direction: column; gap: 14px; overflow-y: auto;
    box-shadow: -20px 0 60px rgba(0, 0, 0, .5);
}
.shell-drawer[hidden] { display: none; }

.shell-head { display: flex; align-items: center; gap: 10px; font-weight: 700; }
.shell-head span { margin-right: auto; }
.shell-close { background: none; border: 0; color: var(--muted); font-size: 18px; cursor: pointer; }
.shell-close:hover { color: var(--text); }
.shell-sound { background: none; border: 0; font-size: 18px; cursor: pointer; padding: 2px; }

.shell-code { display: flex; flex-direction: column; gap: 8px; }
/* Etappe 33 (#7): Der Code-Chip IST der Kopierknopf (S12: Klickbares sieht
   klickbar aus — und tut es dann auch) */
.shell-codeval { font: inherit; font-size: 26px; font-weight: 800; letter-spacing: .22em; text-align: center;
    background: rgba(255, 255, 255, .05); border: 1px dashed var(--panel-border); border-radius: 10px;
    padding: 8px; color: var(--text); cursor: pointer; }
.shell-codeval:hover { background: rgba(255, 255, 255, .1); }
.shell-copy { display: grid; gap: 8px; }
.shell-copy .btn { padding: 9px; font-size: 13.5px; }

.shell-crew {
    font-size: 13.5px; color: var(--text);
    background: rgba(88, 101, 242, .18); border: 1px solid rgba(88, 101, 242, .4);
    border-radius: 8px; padding: 7px 11px;
}

.shell-players-h { font-size: 12.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.shell-players { list-style: none; padding: 0; margin: 0; display: grid; gap: 6px; }
.shell-players li { display: flex; align-items: center; gap: 8px; padding: 6px 10px;
    background: rgba(255, 255, 255, .05); border-radius: 9px; }
/* Issue #7: nur der Name gibt nach (schrumpft/ellipsiert) — Badges & Mod-Buttons
   behalten ihre Form, damit die Zeile nicht umbricht/höher wird. */
.shell-players .pnm { font-size: 14px; min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shell-players .pnm.turn { color: var(--gold); font-weight: 700; }
.shell-players .ptag { font-size: 11px; border: 1px solid var(--gold); color: var(--gold); border-radius: 999px; padding: 0 7px;
    flex: 0 0 auto; white-space: nowrap; }
.shell-players .ptag.host { border-color: var(--accent); color: var(--accent); }
.shell-players .ptag.fed { border-color: var(--muted); color: var(--muted);   /* S18 v2: föderiert */
    max-width: 96px; overflow: hidden; text-overflow: ellipsis; }
.shell-players .pmod, .lobby-roster .pmod { margin-left: auto; display: flex; gap: 5px; flex: 0 0 auto; }
.pmodbtn { font: inherit; font-size: 12px; cursor: pointer; color: var(--muted);
    background: rgba(255, 255, 255, .06); border: 1px solid var(--panel-border); border-radius: 7px; padding: 3px 8px; }
.pmodbtn:hover:not(:disabled) { color: var(--red); border-color: var(--red); }
.pmodbtn:disabled { opacity: .35; cursor: default; }

/* ── S3 (Etappe 27): Account-Box (Discord-Login, optional) ── */
.shell-account {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 10px 12px; background: rgba(255, 255, 255, .04);
    border: 1px solid var(--panel-border); border-radius: 10px; font-size: 14px;
}
.shell-account[hidden] { display: none; }
.sa-img { width: 30px; height: 30px; border-radius: 50%; flex: none; }
.sa-fallback { display: inline-grid; place-items: center; background: rgba(255, 255, 255, .08); font-size: 16px; }
.sa-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; }
.sa-logout { margin-left: auto; padding: 8px 14px; font-size: 13px; min-height: 44px; }   /* 29b: Touch-Ziel */
.sa-login {
    flex: 1 1 100%; text-align: center; text-decoration: none; min-height: 44px;
    display: grid; place-items: center;
    background: rgba(88, 101, 242, .22); border-color: rgba(88, 101, 242, .5);
}
.sa-hint { flex: 1 1 100%; font-size: 12px; color: var(--muted); text-align: center; }
/* Etappe 46D: Link zur persönlichen Statistik (nur eingeloggt) */
.sa-stats { flex: 1 1 100%; text-align: center; text-decoration: none; min-height: 44px;
    display: grid; place-items: center; font-size: 13.5px; }

.shell-switch { margin-top: auto; min-height: 44px; }
.shell-switch[hidden] { display: none; }
.shell-switch:not([hidden]) + .shell-leave { margin-top: 10px; }
.shell-leave { margin-top: auto; border-color: rgba(229, 72, 77, .5); color: #ff8a8d; }
.shell-leave:hover { background: rgba(229, 72, 77, .15); }

/* Vote-Kick-Banner (fix, spielunabhängig) — Etappe 35: unterhalb der
   Raum-Leiste, damit er Code/Brand nicht verdeckt */
.shell-vote {
    position: fixed; top: calc(max(12px, env(safe-area-inset-top)) + 56px); left: 50%; transform: translateX(-50%); z-index: 45;
    display: flex; align-items: center; gap: 14px; max-width: min(560px, 92vw);
    padding: 10px 16px; border-radius: 12px; font-size: 14.5px;
    background: rgba(30, 22, 10, .95); border: 1px solid rgba(242, 193, 78, .5);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .5);
}
.shell-vote[hidden] { display: none; }
.sv-btns { display: flex; gap: 8px; }
.sv-btns .btn { padding: 6px 14px; font-size: 13.5px; }
.sv-yes { border-color: rgba(229, 72, 77, .5); }
.sv-clock { color: var(--gold); font-weight: 700; }

/* ── S12: Avatare (Index vom Kernel, Pools in shell.js) ── */
.av {
    width: 30px; height: 30px; flex: none; border-radius: 50%;
    aspect-ratio: 1 / 1;   /* Härtung gegen Streck-Layouts (oval, Etappe 35) */
    display: inline-grid; place-items: center; font-size: 16px;
    background: color-mix(in srgb, var(--avc, #4f8cff) 30%, transparent);
    box-shadow: inset 0 0 0 2px var(--avc, #4f8cff);
}
/* Etappe 33 (#6): Bild schrumpft IN den Ring, statt ihn zu verdecken —
   die Kernel-Farbe bleibt als Identitäts-Ring um Discord-Avatare sichtbar */
.av img { width: calc(100% - 6px); height: calc(100% - 6px); margin: 3px;
    border-radius: 50%; object-fit: cover; display: block; }
.av.off { filter: grayscale(.9) brightness(.6); }
.av.empty { box-shadow: inset 0 0 0 2px var(--panel-border); color: var(--muted); font-size: 14px; background: none; border-style: dashed; }
.av.bot { box-shadow: inset 0 0 0 2px var(--muted); background: rgba(151, 160, 179, .18); }
.av.big { width: 44px; height: 44px; font-size: 24px; }
.av.mini { width: 22px; height: 22px; font-size: 12px; }

/* ── S12: Konfetti-Overlay ── */
.shell-confetti { position: fixed; inset: 0; z-index: 70; pointer-events: none; }

/* ── Etappe 13: großer Countdown — Etappe 51 (Issue #6): oben MITTIG, damit er
   nie mehr mit der Button-Reihe (❓/💬/☰) oben rechts kollidiert ── */
.shell-clock {
    position: fixed; top: max(14px, env(safe-area-inset-top));
    left: 50%; transform: translateX(-50%); z-index: 44;
    padding: 8px 16px; border-radius: 999px; font-size: 19px; font-weight: 800;
    font-variant-numeric: tabular-nums; color: var(--text);
    background: rgba(20, 26, 40, .95); border: 1px solid rgba(242, 193, 78, .35);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .45); pointer-events: none;
}
.shell-clock.urgent { color: var(--red); border-color: rgba(229, 72, 77, .6); animation: clock-pulse 1s infinite; }
/* translateX(-50%) beibehalten (Zentrierung), nur zusätzlich pulsen */
@keyframes clock-pulse { 0%, 100% { transform: translateX(-50%) scale(1); } 50% { transform: translateX(-50%) scale(1.08); } }
.shell-clock[hidden] { display: none; }

/* E59: Auf dem Handy ging die Rechnung aus E51 nicht mehr auf. Gemessen bei
   390 px: Uhr 152–238 px, Button-Reihe ab 224 px — die Uhr lag also WIEDER
   unter ☰, und der Code-Chip (80–198) lag unter der Uhr. Die Mitte ist bei
   390 px schlicht kein freier Platz mehr, seit die Reihe drei Knöpfe hat.
   Also links andocken; die Raum-Leiste rückt darunter (siehe style.css). */
@media (max-width: 560px) {
    .shell-clock { left: max(14px, env(safe-area-inset-left)); transform: none; }
    .shell-clock.urgent { animation-name: clock-pulse-left; }
}
@keyframes clock-pulse-left { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }

/* ── Etappe 35: Zuschauer-Modus (Nach-Joiner ohne Sitz) ── */
.shell-spec-chip {
    position: fixed; bottom: max(14px, env(safe-area-inset-bottom)); left: 50%; transform: translateX(-50%);
    z-index: 44; padding: 8px 18px; border-radius: 999px; font-size: 14px; font-weight: 700;
    background: rgba(20, 26, 40, .95); border: 1px solid var(--panel-border); color: var(--muted);
    pointer-events: none;
}
.shell-spec-chip[hidden] { display: none; }
.shell-specs { font-size: 13px; color: var(--muted); padding: 2px 2px 0; }
.shell-specs[hidden] { display: none; }

/* ── Etappe 13: Revanche-Box (Endscreens) ── */
.rm-row { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.rm-count { font-size: 13.5px; color: var(--muted); margin-left: 4px; }

/* ── Etappe 37: Abend-Stand (Session-Scoreboard über Spiele hinweg) ── */
.rm-standings {
    display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap;
    margin-bottom: 14px; padding: 10px 14px; border-radius: 12px; font-size: 14px;
    background: rgba(242, 193, 78, .08); border: 1px solid rgba(242, 193, 78, .3);
}
.rm-st-h { font-weight: 800; color: var(--gold); }
.rm-st { display: inline-flex; align-items: center; gap: 6px; }
.rm-st b { color: var(--gold); }

/* Etappe 37: Solo-Schnellstart */
.solo-start { margin-left: 8px; }

/* ── Etappe 33 (#11): Verlassen sichtbar (Lobby + Endscreen) ── */
.ls-leave, .rm-leave {
    margin-top: 12px; min-height: 44px; font-size: 14px;
    color: var(--muted); border-color: var(--panel-border); background: none;
}
.ls-leave:hover, .rm-leave:hover { color: #ff8a8d; border-color: rgba(229, 72, 77, .5); }

/* ── S13 (Etappe 36): Spiel wechseln — Button + Picker-Overlay ── */
.ls-switch, .rm-switch { margin-top: 12px; min-height: 44px; font-size: 14.5px; width: 100%; }
.gp-panel { width: min(420px, 94vw); max-height: min(80dvh, 640px); display: flex; flex-direction: column; }
.gp-hint { margin-top: 2px; }
.gp-list { display: grid; gap: 8px; margin: 14px 0; overflow-y: auto; }
.gp-item {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    min-height: 48px; text-align: left; font-size: 15px;
}
.gp-item .gp-meta { color: var(--muted); font-size: 12.5px; white-space: nowrap; }
.gp-item.cur { border-color: var(--accent); opacity: .7; }
.gp-item:disabled { opacity: .4; }
.gp-item.wished { border-color: var(--gold); }
.gp-wish { color: var(--gold); font-size: 13px; margin-left: 4px; }

/* Etappe 40: Wunsch-Zeile (Lobby + Endscreen) */
.ls-wishes {
    margin: 12px 0 0; padding: 9px 13px; border-radius: 10px; font-size: 13.5px;
    background: rgba(242, 193, 78, .08); border: 1px solid rgba(242, 193, 78, .3);
    color: var(--text);
}
.ls-wishes b { color: var(--gold); }
.ls-wishes .lw-names { color: var(--muted); }
.gp-close { min-height: 44px; }
#shell-gamepick[hidden] { display: none; }

/* ── Etappe 33 (#1): Runden-Banner — der Rundenausgang wird erzählt ── */
.shell-round {
    position: fixed; top: 38%; left: 50%; transform: translate(-50%, -50%); z-index: 65;
    display: flex; align-items: center; gap: 12px;
    /* fixed + left:50% lässt shrink-to-fit sonst nur die halbe Viewport-Breite */
    width: max-content; max-width: min(560px, 92vw);
    padding: 16px 26px; border-radius: 16px; font-size: 19px; font-weight: 700;
    text-align: center; pointer-events: none;
    background: rgba(20, 26, 40, .97); border: 1px solid rgba(242, 193, 78, .55);
    box-shadow: 0 18px 60px rgba(0, 0, 0, .6);
}
.shell-round[hidden] { display: none; }
.shell-round small { display: block; font-weight: 500; font-size: 13px; color: var(--muted); margin-top: 3px; }
.shell-round.pop { animation: shell-round-pop .35s cubic-bezier(.2, 1.4, .4, 1); }
@keyframes shell-round-pop {
    from { opacity: 0; transform: translate(-50%, -50%) scale(.7); }
    to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* ── Etappe 13: Avatar-Picker (§4.9) ── */
.ap-label { display: block; font-size: 13px; color: var(--muted); margin: 14px 0 6px; }
.ap-grid { display: flex; flex-wrap: wrap; gap: 7px; }
/* padding:0 + aspect-ratio: UA-Button-Padding machte die Kreise sonst OVAL (Etappe 35) */
.ap-btn { border: 0; padding: 0; cursor: pointer; font: inherit; opacity: .55; transition: transform .08s, opacity .15s; }
.ap-btn:hover { opacity: 1; transform: scale(1.12); }
.ap-btn.sel { opacity: 1; outline: 2px solid var(--accent); outline-offset: 2px; transform: scale(1.12); }

/* ── S12: gemeinsame Lobby ── */
.lobby-roster li.free { opacity: .55; }
.lobby-roster .tag.bot { color: var(--muted); }
.add-bot { margin-top: 4px; font-size: 14px; padding: 9px 14px; }
.lobby-roster .waiting { color: var(--muted); font-style: italic; font-size: 14px; }
.lobby-share {
    display: flex; align-items: center; gap: 14px; margin-top: 14px;
    padding: 12px; background: rgba(255, 255, 255, .04); border-radius: 12px;
}
.lobby-share-btns { display: grid; gap: 8px; flex: 1; min-width: 0; }
/* E54B: `min-width:0` + Umbruch — sonst sprengt ein langer Code (CODE@server)
   das Grid und die Seite scrollt quer (Mobile-Gate bei 360px). */
.lobby-share-btns .btn { min-height: 44px; min-width: 0; overflow-wrap: anywhere; }
.lobby-qr { width: 96px; height: 96px; flex: none; border-radius: 8px; overflow: hidden; background: #fff; padding: 2px; }
.lobby-qr svg { display: block; width: 100%; height: 100%; }
.lobby-box { margin-top: 12px; text-align: left; }
.lobby-box summary { cursor: pointer; color: var(--muted); font-size: 14px; }
.lobby-settings, .lobby-rules { margin-top: 10px; font-size: 14px; color: var(--text); display: grid; gap: 5px; }

/* ── E52: Einstellungen — gruppiert, erklärt, live gespeichert ── */
.lobby-settings { gap: 14px; }
.ls-group { display: grid; gap: 8px; }
.ls-group-h { font-size: 11.5px; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .07em; }
.ls-lbl { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ls-hint { font-size: 12px; color: var(--muted); line-height: 1.35; }
.ls-field.ls-check { align-items: flex-start; gap: 10px; padding: 2px 0; }
.ls-field.ls-check input { margin-top: 3px; width: 18px; height: 18px; flex: 0 0 auto; }
.ls-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    border-top: 1px solid var(--panel-border); padding-top: 10px; }
.ls-saved { font-size: 12.5px; color: var(--muted); }
.ls-saved.on { color: var(--green); }
.ls-reset { margin-left: auto; font-size: 12.5px; padding: 5px 10px; }
/* Nicht-Host: kompakte Lesefassung statt ausgegrauter Felder */
.ls-read { list-style: none; padding: 0; margin: 0; display: grid; gap: 4px; }
.ls-read li { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.ls-read li span { color: var(--muted); }
.lobby-rules p { margin: 0 0 6px; }
.lobby-settings .kv { display: flex; justify-content: space-between; gap: 12px; }
.lobby-settings .kv span:last-child { color: var(--muted); }
.ls-field { display: flex; align-items: center; gap: 9px; font-size: 14px; }
.ls-field.kv { justify-content: space-between; }
.ls-field select, .ls-field input[type="number"] { width: 130px; padding: 6px 10px; }
/* E74: WebKit macht ein `<select>` mindestens so breit wie seine LÄNGSTE
   Option — die 130px oben greifen dort nicht, und eine lange Beschriftung
   schob die Lobby quer (gemessen: 537px bei 390px Viewport).
   ZWEI Irrwege, beide gemessen und beide verworfen:
     - `flex: 0 1 130px` auch auf `input[type=number]` zog Blackjack mit in
       den Querlauf — ein Feld, das mit der Sache nichts zu tun hatte.
     - `min-width: 0` MACHTE ES SCHLIMMER, nicht besser (Bunt 72 → 147px).
       Das ist der übliche Griff gegen Flex-Überläufe und hier genau falsch.
   Was hilft, ist `max-width` allein — und kurze Optionstexte. */
.ls-field select { max-width: 100%; }
.ls-field input[type="checkbox"] { width: auto; accent-color: var(--accent); }
.ls-field :disabled { opacity: .7; }
.ls-apply { margin-top: 10px; font-size: 14px; padding: 8px 16px; }

/* ── S12: A11y-Basics ── */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ── Etappe 21: Geld-/Punkte-Floater (LWShell.floatDelta) ── */
.shell-float {
    position: fixed; z-index: 60; transform: translateX(-50%);
    font-weight: 800; font-size: 17px; pointer-events: none;
    text-shadow: 0 2px 8px rgba(0, 0, 0, .6);
    animation: shell-float-up 1.35s ease-out forwards;
}
.shell-float.plus { color: var(--green); }
.shell-float.minus { color: var(--red); }
@keyframes shell-float-up {
    from { opacity: 0; transform: translate(-50%, 6px) scale(.8); }
    15% { opacity: 1; transform: translate(-50%, 0) scale(1.15); }
    to { opacity: 0; transform: translate(-50%, -34px) scale(1); }
}

/* S18 (E44) + E54B: der föderierte Code ist ein Teilen-Knopf wie die anderen —
   er stand vorher als Kleingedrucktes darunter und wurde nicht gefunden. */
.shell-fedval b, .ls-fed b { letter-spacing: .08em; }
.shell-fed-hint { margin: 2px 0 0; font-size: 11.5px; line-height: 1.35; color: var(--muted); }
.shell-fedval[hidden], .shell-fed-hint[hidden] { display: none; }

/* ── E54D: Einstellungen im Drawer (mitten im Spiel) ── */
.shell-set { margin: 4px 0 2px; }
.shell-set > summary { cursor: pointer; color: var(--muted); font-size: 13.5px; padding: 6px 0; }
.shell-set[open] > summary { color: var(--text); font-weight: 700; }
.shell-set-body { display: grid; gap: 14px; font-size: 13.5px; margin-top: 6px; }
.shell-set[hidden] { display: none; }
.ls-pending { margin: 0 0 2px; font-size: 12.5px; color: var(--gold); }

/* ── Issue #8: „⛔ Gebannt" im Drawer (nur der Host sieht die Liste) ── */
.shell-bans { margin-top: 10px; display: grid; gap: 6px; }
.shell-bans[hidden] { display: none; }
.shell-bans-h { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.shell-ban { display: flex; align-items: center; gap: 8px; padding: 7px 10px;
    background: rgba(229, 72, 77, .08); border: 1px solid rgba(229, 72, 77, .25); border-radius: 9px; }
.shell-ban .sb-name { font-size: 14px; font-weight: 600; }
.shell-ban .sb-when { font-size: 11.5px; color: var(--muted); }
.shell-ban .sb-undo { margin-left: auto; font-size: 12px; padding: 4px 9px; white-space: nowrap; }

/* ── Issue #5: Platzierung im Endscreen (wenn weitergespielt wurde) ── */
.rm-rank { display: grid; gap: 6px; padding: 12px 14px; border-radius: 12px;
    background: rgba(242, 193, 78, .08); border: 1px solid rgba(242, 193, 78, .3); }
.rm-rank-h { font-size: 11.5px; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .07em; }
.rm-place { display: flex; align-items: center; gap: 8px; font-size: 15px; }
.rm-place.me { font-weight: 800; color: var(--gold); }
.rm-medal { width: 26px; text-align: center; font-size: 15px; }

/* ── E56B: Mitspieler-Aktionen sichtbar machen ──
   Hier stand bis E59 „bewusst klein gehalten: keine fliegenden Karten quer über
   den Tisch". Das gilt nicht mehr — siehe `.lw-fly` weiter unten. Die kleinen
   Hervorhebungen bleiben trotzdem: Sie greifen auch dort, wo ein Flug keinen
   eindeutigen Weg hätte (z. B. Skippo, Handkarte in die Mitte). */
@keyframes lwFlashPop {
    0% { transform: scale(1); }
    35% { transform: scale(1.16); filter: brightness(1.25); }
    100% { transform: scale(1); }
}
@keyframes lwFlashUp {
    0% { transform: translateY(0); }
    35% { transform: translateY(-6px); filter: brightness(1.3); }
    100% { transform: translateY(0); }
}
.lw-flash-pop { animation: lwFlashPop .55s cubic-bezier(.2, 1.4, .4, 1); }
.lw-flash-up { animation: lwFlashUp .55s ease-out; }
@media (prefers-reduced-motion: reduce) {
    .lw-flash-pop, .lw-flash-up { animation: none; }
}

/* ── E59: Ein Gegner hat eine HAND (LWShell.handFan) ──
   Vorher: „🂠 7 Karten" in 12,5 px Grau — die spielentscheidende Zahl war das
   kleinste Element auf dem Schirm. Jetzt Kartenfächer + große Zahl. Die Breite
   folgt --n, damit man das Wachsen und Schrumpfen SIEHT. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.lw-fan {
    --fw: 28px;          /* Breite eines Rückens (×1.45 = 41px hoch — das
                            Lesbarkeits-Gate aus opp-view.mjs verlangt ≥ 40) */
    --step: 11px;        /* Versatz je weiterer Karte */
    display: inline-flex; align-items: center; gap: 8px;
}
.lw-fan-cards {
    position: relative; display: block; flex: none;
    width: calc(var(--fw) + (var(--n) - 1) * var(--step));
    height: calc(var(--fw) * 1.45);
    transition: width .25s cubic-bezier(.2, .9, .3, 1);
}
.lw-fanc {
    position: absolute; top: 0; left: calc(var(--i, 0) * var(--step));
    width: var(--fw); height: calc(var(--fw) * 1.45); border-radius: 4px;
    background: linear-gradient(150deg, #34406b, #202844 60%, #2b3558);
    border: 1px solid rgba(255, 255, 255, .22);
    box-shadow: 0 2px 6px rgba(0, 0, 0, .45);
    transform: rotate(calc((var(--i, 0) - 1.5) * 2.5deg));
    transform-origin: 50% 120%;
}
.lw-fanc.gone { background: none; border-style: dashed; border-color: rgba(255, 255, 255, .14); box-shadow: none; }
.lw-fan-n { font-size: 19px; font-weight: 800; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; }
.lw-fan.low .lw-fanc { border-color: rgba(242, 193, 78, .8); box-shadow: 0 0 10px rgba(242, 193, 78, .45); }
.lw-fan.low .lw-fan-n { color: var(--gold); animation: lwFanLow 1.5s infinite; }
.lw-fan.out .lw-fan-n { color: var(--muted); }
@keyframes lwFanLow { 50% { transform: scale(1.16); } }

/* ── E59: fliegende Karte (LWShell.flyCard) ──
   Nimmt die E56B-Entscheidung („bewusst KEINE fliegenden Karten") zurück — auf
   ausdrücklichen Betreiber-Wunsch. Die damalige Sorge um schwache Handys steckt
   jetzt in den Riegeln im JS (max 6 gleichzeitig, kein Hintergrund-Tab) und
   hier: ausschließlich transform/opacity, also kein Layout pro Bild. */
.lw-fly {
    position: fixed; left: 0; top: 0; z-index: 70; pointer-events: none;
    border-radius: 6px; will-change: transform, opacity;
    background: linear-gradient(150deg, #34406b, #202844 60%, #2b3558);
    border: 1px solid rgba(255, 255, 255, .28);
    box-shadow: 0 8px 22px rgba(0, 0, 0, .55);
    display: grid; place-items: center; font-size: 17px; font-weight: 800; color: #fff;
}
@media (prefers-reduced-motion: reduce) { .lw-fly { display: none; } }

/* ── E57: Spielwünsche sind für den Host Knöpfe ──
   Vorher las er den Wunsch, öffnete den Spielwechsel und suchte dasselbe Spiel
   dort noch einmal. Jetzt ein Griff. */
.lw-pick {
    font: inherit; font-size: 13.5px; color: var(--text); cursor: pointer;
    background: rgba(88, 101, 242, .16); border: 1px solid rgba(88, 101, 242, .45);
    border-radius: 999px; padding: 5px 12px; min-height: 34px; margin: 2px 2px 0 0;
}
.lw-pick:hover { background: rgba(88, 101, 242, .3); border-color: var(--accent); }
.lw-hint { color: var(--muted); font-size: 12px; margin-left: 6px; }

/* ── E64: Zeichen-Fundament (LWDraw) ──
   Gehört keinem Spiel (S5) — Klecks ist das erste, das es benutzt. Die Fläche
   ist PAPIER in einer dunklen App: der einzige helle Block auf dem Schirm, und
   damit unübersehbar das, worum es gerade geht (S21). */
.lwd-paper {
    display: block; width: 100%; aspect-ratio: 4 / 3; max-height: 62vh;
    background: #fdfdfa; border-radius: 12px; border: 1px solid var(--panel-border);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .45); touch-action: none; cursor: default;
}
.lwd-paper.drawing { cursor: crosshair; }

.lwd-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 10px; }
/* `display: flex` schlägt sonst das hidden-Attribut — gemessen: der Ratende
   bekam die Werkzeuge des Zeichners zu sehen. */
.lwd-tools[hidden] { display: none; }
.lwd-colors { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.lwd-color {
    width: 30px; height: 30px; border-radius: 8px; cursor: pointer; padding: 0;
    border: 2px solid rgba(255, 255, 255, .18);
}
.lwd-color.on { border-color: var(--accent); transform: scale(1.08); }
.lwd-sizes { display: flex; gap: 6px; }
.lwd-size {
    width: 34px; height: 34px; border-radius: 9px; cursor: pointer; padding: 0;
    display: grid; place-items: center;
    background: var(--panel); border: 1px solid var(--panel-border);
}
.lwd-size i { display: block; background: var(--text); border-radius: 50%; }
.lwd-size.on { border-color: var(--accent); background: rgba(79, 140, 255, .16); }
.lwd-act {
    min-width: 40px; height: 34px; border-radius: 9px; cursor: pointer; font-size: 16px;
    color: var(--text); background: var(--panel); border: 1px solid var(--panel-border);
}
.lwd-act:hover { border-color: var(--accent); }
/* Auf schmalen Geräten bekommt die Palette eine EIGENE Zeile über die volle
   Breite. Erster Versuch war „alle zehn in die Werkzeugzeile quetschen" — die
   Messung ergab 4 px breite Farbfelder, also unbenutzbar. */
@media (max-width: 560px) {
    .lwd-colors { flex: 1 0 100%; grid-template-columns: repeat(10, 1fr); gap: 5px; }
    .lwd-color { width: 100%; height: 32px; }
    .lwd-tools { gap: 8px; }
}

/* ── S26 (E66): der Inhalts-Editor („Eigene Edition") ──
   Gehört der Shell, nicht den Spielen — sonst baut ihn jedes Spiel neu (S5). */
.lwc { margin-top: 14px; border: 1px solid var(--panel-border); border-radius: 12px; background: rgba(255, 255, 255, .03); }
.lwc > summary { padding: 11px 14px; cursor: pointer; font-size: 14px; font-weight: 600; list-style: none; }
.lwc > summary::-webkit-details-marker { display: none; }
.lwc > summary::before { content: '✎ '; opacity: .6; }
.lwc-body { padding: 0 14px 14px; display: grid; gap: 10px; }
.lwc-note { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.lwc-text {
    width: 100%; resize: vertical; min-height: 120px;
    font: 15px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
    padding: 10px 12px; border-radius: 10px;
    background: rgba(0, 0, 0, .25); color: var(--fg);
    border: 1px solid var(--panel-border);
}
.lwc-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.lwc-row input { flex: 1 1 9em; min-width: 0; min-height: 40px; font-size: 16px; }
.lwc-row .btn { flex: 0 0 auto; }
.lwc-pick { width: 100%; min-height: 40px; }
.lwc-msg { margin: 0; font-size: 12.5px; min-height: 1.2em; }
.lwc-msg.ok { color: var(--green); }
.lwc-msg.err { color: var(--red); }

/* ── S27 (E67): Abstimmung über einen strittigen Wert ──
   Gehört der Shell, nicht dem Spiel — „gilt das?" ist keine SLF-Frage. */
.lwv {
    width: 100%; margin: 0 0 12px; padding: 12px 14px;
    border-radius: 12px; border: 1px solid var(--panel-border); background: var(--panel);
}
.lwv.open { border-color: rgba(242, 193, 78, .6); background: rgba(242, 193, 78, .09); }
.lwv.done.kept { border-color: rgba(63, 191, 111, .5); }
.lwv.done.struck { border-color: rgba(229, 72, 77, .5); }
.lwv-head { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-bottom: 4px; }
.lwv.done.kept .lwv-head { color: var(--green); }
.lwv.done.struck .lwv-head { color: var(--red); }
/* Worüber abgestimmt wird, ist das Wichtigste im Kasten (S21). */
.lwv-what { font-size: 17px; font-weight: 700; overflow-wrap: anywhere; margin-bottom: 10px; }
.lwv-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.lwv-btn { flex: 1 1 8em; min-height: 44px; }
.lwv-btn.yes { border-color: rgba(63, 191, 111, .55); }
.lwv-btn.no { border-color: rgba(229, 72, 77, .55); }
.lwv-note { margin: 0; font-size: 13px; color: var(--muted); }
.lwv-foot { display: flex; justify-content: space-between; gap: 10px; margin-top: 9px; font-size: 12.5px; color: var(--muted); }
.lwv-time { font-variant-numeric: tabular-nums; }
.lwv-time.urgent { color: var(--red); font-weight: 800; }
.lwv-tally { font-size: 12.5px; color: var(--muted); }
.lwv-queue { margin-top: 6px; font-size: 12px; color: var(--muted); }
/* E69: Was ohne Mehrheit passiert. Wer abstimmt, soll wissen, was sein
   Schweigen bewirkt — die Richtung ist je Spiel eine andere. */
.lwv-stays { margin-top: 6px; font-size: 12px; color: var(--muted); font-style: italic; }
/* Das ⚑ an einer fremden Antwort — klein, bis man es braucht. */
/* E69: Der Anzweifel-Knopf gehört der Shell, nicht Stadt Land Fluss — seit
   E69 benutzen ihn auch Klecks und Stille Post (S5). */
.flag {
    border: 1px solid transparent; background: transparent; color: var(--muted);
    border-radius: 999px; padding: 2px 7px; font-size: 12px; cursor: pointer; line-height: 1.4;
}
.flag:hover:not(:disabled) { border-color: rgba(242, 193, 78, .6); color: var(--gold); }
.flag:disabled { opacity: .25; cursor: default; }
.rvi.gestrichen { opacity: .45; }
.rvi.gestrichen .ans { text-decoration: line-through; }

/* ── Issue #14: klebende Kopfleisten ──
   Der Hintergrund erscheint NUR, wenn die Leiste wirklich klebt. Vorher lag
   dort immer ein deckender Verlauf — im Ruhezustand ein harter dunkler Block
   quer über die Seite, der nichts verdeckte, weil nichts darunter lag. */
.lw-stickyguard { height: 1px; margin: 0; padding: 0; }
.lw-stickybar {
    position: sticky; top: 0; z-index: 20;
    border-radius: 0 0 14px 14px;
    transition: background-color .18s ease, box-shadow .18s ease;
    background: transparent;
}
.lw-stickybar.stuck {
    /* Durchscheinend statt deckend, weich statt hart, und die Rundung wird
       mitgenommen — kein Rechteck mit Kanten mehr. */
    background: color-mix(in srgb, var(--bg) 82%, transparent);
    box-shadow: 0 8px 18px -12px rgba(0, 0, 0, .8);
}
@supports (backdrop-filter: blur(1px)) {
    .lw-stickybar.stuck { background: color-mix(in srgb, var(--bg) 62%, transparent); backdrop-filter: blur(10px); }
}
@media (prefers-reduced-motion: reduce) { .lw-stickybar { transition: none; } }

/* E70: Klartext neben einer Edition mit Grammatik (Kontrakt-Rommé). */
.lwc-echo { display: grid; gap: 3px; margin-top: 7px; }
.lwc-echo-row { display: flex; gap: 8px; align-items: baseline; font-size: 12.5px; }
.lwc-echo-row .n { color: var(--muted); min-width: 1.4em; text-align: right; font-variant-numeric: tabular-nums; }
.lwc-echo-row code { color: var(--gold); font-size: 12.5px; min-width: 5.5em; }
.lwc-echo-row .t { color: var(--muted); overflow-wrap: anywhere; }
.lwc-echo-row.bad .t { color: var(--red); }
.lwc-echo-row.bad code { text-decoration: line-through; }

/* ── E73: die Gegner-Reihe — eine Regel statt drei Kopien ──
   Gemeldet an Spite & Malice mit drei Gegnern: Die Kästen waren
   unterschiedlich breit, und bei mittlerer Fensterbreite brach die Reihe auf
   „zwei oben, einer zentriert darunter" um.

   GEMESSEN, nicht geraten: Beim Rundenstart sind alle 348 px — der Unterschied
   entsteht erst IM SPIEL, weil der Handfächer den Kasten aufzieht. Die Breite
   hing also am Inhalt, und damit sprang das Layout bei jedem gezogenen Blatt.

   Die Regel lag dreimal identisch im Code (Spite, Mau+, Bunt!) — nach dem
   S29-Gegentest gehört sie hierher: Eine Änderung wäre in allen dreien nötig
   gewesen, es ist wirklich dieselbe Sache. Die Spiele setzen nur noch ihre
   eigenen Abstände. */
.opponents {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: 12px; margin: 6px 0 14px;
}
.opp {
    /* Gleiche Grundbreite für alle, Wachstum gedeckelt: Der Kasten richtet
       sich nach der REIHE, nicht nach seiner Hand. `min-width: 0` ist nötig,
       damit ein breiter Fächer die Box nicht doch wieder aufdrückt. */
    flex: 1 1 200px;
    min-width: 0;
    max-width: 340px;
}
/* Und nichts darin darf breiter sein als der Kasten. In Spite kann das nicht
   passieren (Hand max. 5), in Bunt! schon — dort wächst die Gegner-Hand ohne
   Deckel, und ein langer Fächer schöbe sonst die ganze Seite quer (S12). */
.opp > * { max-width: 100%; }
/* Der Fächer selbst ist der letzte, der noch schieben kann: Er ist absichtlich
   breiter als seine Karten (Überlappung per `--step`), und `transform: scale()`
   verkleinert nur die Optik, nicht die Fläche. Deshalb hier hart deckeln. */
.opp .opp-hand-wrap, .opp .lw-fan, .opp .lw-fan-cards { max-width: 100%; min-width: 0; overflow: hidden; }
