/* ─────────────────────────────────────────────────────────────
   UI v3.1 — Stage-Scaling System
   Reference: 1280×720px
   ───────────────────────────────────────────────────────────── */

/* NEW: Viewport-Wrapper — füllt ganzen Bildschirm */
body, html {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #030508;
}

/* Fix BH1 (2026-08-18): globaler Farbschutz fuer ALLE Canvas-Elemente. Fund aus Fix BG1 —
   Chromiums browserseitige automatische Farbanpassung (dark-mode-nahe Heuristik) veraendert
   NUR Canvas-Pixel beim finalen Zusammensetzen des Bildes, unabhaengig vom bereits
   vorhandenen <meta name="color-scheme" content="only light">, das nur DOM-/CSS-Inhalt
   schuetzt. Damals nur am Ladering-Canvas als Inline-Style behoben (dort MUSS es so frueh
   gesetzt sein, dass nur ein Inline-Style vor dem ersten Frame zuverlaessig wirkt — bleibt
   dort zusaetzlich bestehen). Diese Regel ist der Schutz fuer JEDES ANDERE Canvas — auch
   zur Laufzeit per document.createElement('canvas') erzeugte (Wuerfel-Textur, Karten-Canvas
   in game-core.js) sind davon erfasst, weil die Regel schon in der CSSOM steht, bevor
   irgendein Canvas-Element ueberhaupt erzeugt wird — anders als beim Ladering ist hier KEINE
   fruehe Inline-Deklaration noetig. Messung (getImageData vs. Screenshot) am sichtbarsten
   Kandidaten (#space-canvas, Lobby-Sternfeld) zeigte KEINEN messbaren Unterschied — dessen
   Sterne sind reines Weiss (#ffffff, saettigungslos), fuer das eine farbtonbasierte
   Anpassung wirkungslos bleibt. Die Regel steht trotzdem global (vorsorglich, s. Bericht):
   jedes kuenftige Canvas mit gesaettigten Farben (wie der Ladering) waere sonst genauso
   betroffen. Jedes neue Canvas-Feature braucht diesen Schutz nicht mehr einzeln bedenken. */
canvas {
  forced-color-adjust: none;
  color-scheme: light;
}

/* NEW: Stage — fester 1280×720 Canvas, transform-Scaling via JS */
#sq-stage {
  position: absolute;
  width: 1280px;
  height: 720px;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  /* transform: translate(offXpx, offYpx) scale(X) — wird per JS gesetzt */
  overflow: hidden;
}

/* NEW: Layer-Grundstruktur */
#layer-bg,
#layer-field,
#layer-ui,
#layer-overlays {
  position: absolute;
  inset: 0;
  pointer-events: none; /* Layer selbst nicht klickbar */
}

/* Layer-Reihenfolge */
#layer-bg       { z-index: 0; }
#layer-field    { z-index: 10; }
#layer-ui       { z-index: 20; pointer-events: none; } /* Kinder erben pointer-events */
#layer-overlays { z-index: 30; }

/* NEW: Layer-UI Kinder bekommen pointer-events zurück */
#layer-ui > * { pointer-events: auto; }
#layer-overlays > * { pointer-events: auto; }
/* FIX: layer-field Kinder klickbar — Screens (Lobby, Vanguard, Overview, Combat) liegen darin (Session 1.4c) */
#layer-field { pointer-events: auto; }

/* NEW: Background-Layer — Space + Sterne */
#layer-bg {
  background:
    radial-gradient(ellipse at 20% 50%, rgba(10,20,60,0.6) 0%, transparent 55%),
    radial-gradient(ellipse at 80% 20%, rgba(5,10,40,0.5) 0%, transparent 45%),
    radial-gradient(ellipse at 50% 80%, rgba(20,5,40,0.4) 0%, transparent 40%),
    transparent; /* FIX: durchscheinender Stage damit #game-bg sichtbar wird (Session 1.4d) */
}

/*
 * Star Squadrons — game-v3.css
 * Autor: TedShino | Stand: 2026-05-01
 * Basis: 1920x1080px Scale-to-Fit System
 * Farbschema: #070c14 Basis | #33cccc Cyan | #f0a000 Gold | #0d1018 Panel
 *
 * NICHT mit game-v2.css mischen.
 * Laeuft ausschliesslich auf /playtest (play-v3.ejs).
 */

/* ═══════════════════════════════════════════════════
   1. DESIGN TOKENS (CSS Custom Properties)
   Identisch zu game-v2.css :root — alle JS-Dateien
   referenzieren diese Variablen direkt.
   ═══════════════════════════════════════════════════ */

/* NEW: Vollstaendige Design-Tokens fuer game-v3.css (2026-05-01) */
:root {
  /* FIX AU1 (2026-08-18): sichere Bereiche (Notch/Kamera-Aussparung, Gestenleiste) als
     px-Custom-Properties bereitstellen — layout-engine.js liest sie per getComputedStyle()
     aus (env() selbst ist in JS nicht direkt auslesbar) und schiebt die Buehne im
     unskalierten translate()-Anteil davon weg (s. layout-engine.js FIX-AU1-Kommentar).
     Fallback 0px auf Geraeten ohne Notch/env()-Support. */
  --sq-safe-top:    env(safe-area-inset-top, 0px);
  --sq-safe-right:  env(safe-area-inset-right, 0px);
  --sq-safe-bottom: env(safe-area-inset-bottom, 0px);
  --sq-safe-left:   env(safe-area-inset-left, 0px);

  /* Backgrounds */
  --bg-void:    #030508;
  --bg-deep:    #07090f;
  --bg-panel:   #0d1018;
  --bg-card:    #111520;
  --bg-hover:   #161b28;
  --bg-surface: #1a2035;

  /* Faction colors — VS (Voidstalker) */
  --vs:      #e02020;
  --vs-glow: #e0202060;
  --vs-dim:  #7a0f0f;
  /* NEW: --vb alias fuer VS (historischer Name Voidbringer, in game-combat.js + game-core.js) */
  --vb:      #e02020;
  --vb-glow: #e0202060;
  --vb-dim:  #7a0f0f;

  /* Faction colors — UED */
  --ued:      #00c050;
  --ued-glow: #00c05060;
  --ued-dim:  #005525;

  /* Accent */
  --gold:      #f0a000;
  --gold-glow: #f0a00060;
  --gold-dim:  #7a5000;

  /* HP layer */
  --hp-shield: #4090ff;
  --hp-armor:  #e0a020;
  --hp-hull:   #e04040;

  /* Text */
  --text-primary:   #e8eaf0;
  --text-secondary: #8a90a8;
  --text-dim:       #50566a;

  /* Borders */
  --border-subtle: #1e2438;
  --border-mid:    #2a3050;
  --border-bright: #3a4068;

  /* Bevel */
  --bevel-sm: 6px;
  --bevel-md: 10px;
  --bevel-lg: 16px;
  --bevel-xl: 22px;

  /* NEW: v3 Farb-Aliase */
  --sq-cyan: #33cccc;
  --sq-gold: #f0a000;

  /* NEW: Responsive Sizing Tokens — identisch zu play.ejs playtest-overrides.
     Werden von game-overview.js + game-combat.js via var(--sq-*) konsumiert. */
  --sq-bar-h:        clamp(50px, 7vh, 80px);
  --sq-bar-pad:      0 clamp(8px, 1vw, 16px);
  --sq-bar-fs:       clamp(10px, 0.9vw, 14px);
  --sq-av-size:      clamp(20px, 2vw, 28px);
  --sq-name-fs:      clamp(9px, 0.85vw, 13px);
  --sq-fac-fs:       clamp(8px, 0.7vw, 12px);
  --sq-fac-pad:      2px clamp(4px, 0.5vw, 8px);
  --sq-stat-fs:      clamp(9px, 0.85vw, 13px);
  --sq-stat-mr:      clamp(6px, 1vw, 14px);
  --sq-sp-fs:        clamp(11px, 1vw, 16px);
  --sq-btn-size:     clamp(22px, 2.2vw, 32px);
  --sq-btn-fs:       clamp(10px, 0.9vw, 14px);
  --sq-btn-gap:      clamp(4px, 0.5vw, 8px);
  --sq-hud-l:        clamp(4px, 0.5vw, 10px);
  --sq-hud-w:        clamp(160px, 18vw, 380px);
  --sq-hud-hd-pad:   clamp(4px, 0.6vh, 10px) clamp(6px, 0.8vw, 12px);
  --sq-hud-hd-fs:    clamp(8px, 0.75vw, 12px);
  --sq-hud-bc-pad:   clamp(3px, 0.5vh, 8px) clamp(6px, 0.8vw, 12px);
  --sq-hud-bc-fs:    clamp(8px, 0.75vw, 12px);
  --sq-hud-log-pad:  clamp(3px, 0.5vh, 8px) clamp(6px, 0.8vw, 12px);
  --sq-hud-log-fs:   clamp(8px, 0.75vw, 12px);
  --sq-board-gap:    clamp(2px, 0.4vh, 6px);
  --sq-board-pad:    clamp(2px, 0.3vw, 6px);
  --sq-act-r:        clamp(4px, 0.5vw, 10px);
  --sq-act-w:        clamp(110px, 14vw, 280px);
  --sq-act-pad:      clamp(4px, 0.5vw, 10px);
  --sq-act-gap:      clamp(4px, 0.5vh, 8px);
  --sq-act-lbl-fs:   clamp(7px, 0.6vw, 10px);
  --sq-act-btn-pad:  clamp(4px, 0.6vh, 10px);
  --sq-act-btn-fs:   clamp(8px, 0.7vw, 11px);
  --sq-ti-pad:       clamp(3px, 0.4vh, 6px) clamp(4px, 0.5vw, 10px);
  --sq-ti-fs:        clamp(8px, 0.7vw, 11px);
  --sq-dr-size:      clamp(70px, 7vw, 110px);
  --sq-dr-mar:       clamp(2px, 0.3vh, 6px);
  --sq-dr-num-fs:    clamp(24px, 2.5vw, 40px);
  --sq-dr-lbl-fs:    clamp(8px, 0.8vw, 14px);
  --sq-cb-w:         clamp(44px, 4.5vw, 66px);
  --sq-cb-h:         clamp(58px, 7vh, 88px);
  --sq-cb-ml:        clamp(-6px, -0.4vw, -2px);
  --sq-fz-h:         clamp(50px, 7vh, 80px);
  --sq-fz-gap:       clamp(3px, 0.4vw, 8px);
  --sq-fz-lbl-fs:    clamp(6px, 0.6vw, 10px);
  --sq-ship-sz:      clamp(32px, 3vw, 50px);
  --sq-ship-h:       clamp(44px, 4.2vh, 68px);
  --sq-ship-fs:      clamp(5px, 0.5vw, 8px);
  --sq-loc-gap:      clamp(3px, 0.4vw, 8px);
  --sq-loc-rad:      clamp(4px, 0.4vw, 8px);
  --sq-loc-hd-pad:   clamp(2px, 0.3vh, 6px) clamp(4px, 0.5vw, 10px);
  --sq-loc-nm-fs:    clamp(8px, 0.7vw, 11px);
  --sq-loc-sp-fs:    clamp(9px, 0.85vw, 14px);
  --sq-loc-ef-fs:    clamp(7px, 0.6vw, 10px);
  --sq-loc-ef-pad:   1px clamp(3px, 0.4vw, 8px);
  --sq-loc-st-fs:    clamp(8px, 0.7vw, 12px);
  --sq-loc-st-pad:   clamp(1px, 0.2vh, 4px) clamp(6px, 0.8vw, 14px);
  --sq-hand-gap:     clamp(2px, 0.3vw, 6px);
  --sq-hand-pad:     0 clamp(10px, 1.5vw, 24px);
  --sq-card-w:       clamp(38px, 4vw, 60px);
  --sq-card-h:       clamp(52px, 6vh, 82px);
  --sq-card-nm-fs:   clamp(6px, 0.5vw, 9px);
  --sq-card-cost-fs: clamp(7px, 0.6vw, 11px);
  --sq-card-lift:    clamp(-16px, -1.2vh, -8px);
  --sq-gy-w:         clamp(24px, 2.2vw, 36px);
  --sq-gy-en-top:    clamp(30px, 4vh, 60px);
  --sq-gy-my-bot:    clamp(30px, 4vh, 60px);
  --sq-gy-en-r:      calc(-1 * clamp(30px, 3vw, 46px));
  --sq-gy-sz:        clamp(36px, 3.5vw, 56px);
  --sq-gy-h:         clamp(36px, 3.5vw, 56px);
  --sq-gy-num-fs:    clamp(14px, 1.3vw, 22px);
  --sq-gy-fs:        clamp(10px, 0.9vw, 16px);
  /* Ship card sizes — Gross / Mittel / Klein */
  --sq-card-l-w: clamp(150px, 14vw, 200px);
  --sq-card-l-h: clamp(210px, 19.6vw, 280px);
  --sq-card-m-w: clamp(75px, 7vw, 105px);
  --sq-card-m-h: clamp(105px, 9.8vw, 147px);
  --sq-card-s-w: clamp(45px, 4.5vw, 65px);
  --sq-card-s-h: clamp(63px, 6.3vw, 91px);
}

/* NEW: Mobile Landscape — kompaktere Tokens */
@media (max-height: 499px) and (max-width: 1023px) and (orientation: landscape) {
  :root {
    --sq-bar-h: 34px;
    --sq-fz-h:  34px;
    --sq-hud-w: clamp(150px, 22vw, 210px);
    --sq-act-w: clamp(100px, 14vw, 150px);
  }
  button, [data-action] { min-height: 36px !important; min-width: 36px !important; }
}

/* ═══════════════════════════════════════════════════
   2. RESET + BASIS
   ═══════════════════════════════════════════════════ */

/* NEW: Basis-Reset (2026-05-01) */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg-void);
  font-family: 'Rajdhani', sans-serif;
  color: var(--text-primary);
}

::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-mid); border-radius: 2px; }
::-webkit-scrollbar-thumb:hover { background: var(--border-bright); }

/* NEW: Typographie-Helfer (identisch game-v2.css) */
.font-orbitron  { font-family: 'Orbitron', sans-serif; }
.font-rajdhani  { font-family: 'Rajdhani', sans-serif; }
.font-mono-game { font-family: 'Share Tech Mono', monospace; }

/* ═══════════════════════════════════════════════════
   3. SCALE-TO-FIT SYSTEM
   JS setzt transform dynamisch via scaleGame().
   ═══════════════════════════════════════════════════ */

/* NEW: Scale-to-Fit Root (2026-05-01) */
#game-scale-root {
  width: 1920px;
  height: 1080px;
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: top left;
  overflow: hidden;
  /* FIX: transparent damit #game-bg (position:fixed) durchscheint (2026-05-01) */
  background: transparent;
}

/* NEW: Haupt-Container — FIX: position:absolute damit Screens korrekt im Scale-Root bleiben (2026-05-01) */
#game-root {
  width: 100%;
  height: 100%;
  position: absolute;
  inset: 0;
  /* FIX: overflow:visible damit schwebender Hauptbutton nicht abgeschnitten wird (2026-05-01) */
  overflow: visible;
}

/* ═══════════════════════════════════════════════════
   4. HINTERGRUND (ausserhalb Scale-Root, fixed)
   ═══════════════════════════════════════════════════ */

/* FIX: Weltraum-Hintergrund aus game-v2.css uebernommen — bg-space.jpg + Nebula (2026-05-01) */
#game-bg {
  position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  background: url('/bg-space.jpg') center/cover no-repeat,
    radial-gradient(ellipse 120% 80% at 20% 30%, #0a0d1f 0%, #030508 60%, #000 100%);
}

/* Fix BC1 (2026-08-18): Ladebildschirm-Overlay — Basisplatzierung steht bereits inline in
   play-v3.ejs (kein FOUC-Risiko), hier nur der Ausblend-Uebergang. Canvas selbst bleibt bis
   zum Schluss GANZ normal sichtbar/klickblockierend (pointer-events erbt von #preload-overlay,
   Default auto) — erst .preload-overlay-hidden (game-loading-screen.js, nach dem
   Schliess-Impuls) blendet aus und gibt Klicks frei. */
#preload-overlay {
  transition: opacity .45s ease;
}
#preload-overlay.preload-overlay-hidden {
  opacity: 0;
  pointer-events: none;
}

/* Nebula layers */
#game-bg::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 60% 40% at 75% 20%, rgba(100,40,200,0.12) 0%, transparent 60%),
    radial-gradient(ellipse 50% 60% at 10% 70%, rgba(0,60,120,0.15) 0%, transparent 55%),
    radial-gradient(ellipse 40% 30% at 90% 80%, rgba(180,20,20,0.08) 0%, transparent 50%);
  animation: nebulaPulse 18s ease-in-out infinite alternate;
}

#game-bg::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 70% 35% at 50% 50%, rgba(20,30,80,0.2) 0%, transparent 70%);
  animation: nebulaPulse 24s ease-in-out infinite alternate-reverse;
}

@keyframes nebulaPulse {
  0%   { opacity: 0.7; filter: hue-rotate(0deg); }
  50%  { opacity: 1;   filter: hue-rotate(15deg); }
  100% { opacity: 0.8; filter: hue-rotate(-10deg); }
}

#space-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Star field – layer 1 (white) */
.stars-layer {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1px 1px   at 10%  15%, #ffffff88, transparent),
    radial-gradient(1px 1px   at 25%  42%, #ffffff66, transparent),
    radial-gradient(1.5px 1.5px at 38%  8%, #ffffffaa, transparent),
    radial-gradient(1px 1px   at 52%  67%, #ffffff55, transparent),
    radial-gradient(1px 1px   at 63%  31%, #ffffff77, transparent),
    radial-gradient(2px 2px   at 74%  55%, #ffffffcc, transparent),
    radial-gradient(1px 1px   at 82%  12%, #ffffff66, transparent),
    radial-gradient(1px 1px   at 91%  78%, #ffffff88, transparent),
    radial-gradient(1px 1px   at  5%  88%, #ffffff55, transparent),
    radial-gradient(1.5px 1.5px at 47%  92%, #ffffff99, transparent),
    radial-gradient(1px 1px   at 15%  55%, #ffffff44, transparent),
    radial-gradient(1px 1px   at 29%  72%, #ffffff66, transparent),
    radial-gradient(1px 1px   at 58%  18%, #ffffff55, transparent),
    radial-gradient(2px 2px   at 85%  40%, #ffffffaa, transparent),
    radial-gradient(1px 1px   at 70%  88%, #ffffff44, transparent),
    radial-gradient(1px 1px   at 43%  48%, #ffffff33, transparent),
    radial-gradient(1px 1px   at 95%  25%, #ffffff77, transparent),
    radial-gradient(1.5px 1.5px at 20%  35%, #ffffff88, transparent),
    radial-gradient(1px 1px   at 67%  72%, #ffffff55, transparent),
    radial-gradient(1px 1px   at 33%  95%, #ffffff44, transparent);
  opacity: 0.9;
  pointer-events: none;
}

/* Star field – layer 2 (colored tints) */
.stars-layer-2 {
  position: absolute; inset: 0;
  background-image:
    radial-gradient(1px 1px   at  7%  22%, #aaccff66, transparent),
    radial-gradient(1px 1px   at 18%  80%, #ffaaaa44, transparent),
    radial-gradient(1px 1px   at 35%  60%, #aaffcc33, transparent),
    radial-gradient(1.5px 1.5px at 55%  35%, #ffffaa88, transparent),
    radial-gradient(1px 1px   at 77%  65%, #aaaaff55, transparent),
    radial-gradient(1px 1px   at 88%  90%, #ffccaa44, transparent),
    radial-gradient(1px 1px   at 42%  25%, #ccffff33, transparent),
    radial-gradient(2px 2px   at 62%  85%, #ffffcc66, transparent);
  opacity: 0.6;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════
   FIX BU1: Leerlauf-Bewegung (Etappe 2c)
   Belebt das Brett zwischen den Zuegen, ohne beim Spielen abzulenken. NUR transform/
   opacity (Layout-Sicherheit — Karten-FX messen getBoundingClientRect(), s. Bericht).
   Gesteuert per body-Klassen aus game-idle-motion.js:
     sq-idle-on             Hauptschalter (aus DB-Setting idle_motion_enabled)
     sq-idle-breathe-on / sq-idle-halo-on / sq-idle-ring-on / sq-idle-stars-on /
     sq-idle-shimmer-on     je Baustein (aus den 5 idle_motion_*_enabled-Settings)
     sq-idle-suspended      FX aktiv ODER Overlay/Modal offen ODER Gameover-Screen ODER
                             Tab im Hintergrund — ENTFERNT die Animation komplett (kein
                             animation-play-state:paused — das wuerde den Transform-Wert
                             mitten im Zyklus einfrieren, was fuer Karten-Atmen die exakt
                             selbe Messverfaelschung waere, die dieser Bausteinsatz
                             vermeiden soll; nur ein tatsaechliches Entfernen der
                             animation-Deklaration setzt transform sofort synchron auf
                             seinen Basiswert zurueck, s. Bericht Abschnitt "Layout-
                             Sicherheit"/onFxActiveChange() in game-anim-combat.js).
   --sq-idle-strength wird per JS gesetzt (0..2, aus DB-Setting idle_motion_strength/100).
   ═══════════════════════════════════════════════════ */
:root { --sq-idle-strength: 1; }

/* ── Phasen-Bucket je Karte, aus dem LETZTEN Zeichen der instanceId (Base36) —
   bewusst NICHT :nth-child() (haengt von zufaelligen Nicht-Karten-Geschwistern im
   jeweiligen Container ab, je nach Render-Pfad unterschiedlich, s. Bericht), sondern ein
   Attribut-Selektor auf der ohnehin stabilen data-instance-id — unabhaengig von DOM-
   Struktur/Geschwistern. 4 Gruppen aus je 9 Zeichen des 36er-Alphabets. */
.ship-card-v3:not(.ship-tok-combat) { --sq-idle-phase: 0; }
.ship-card-v3:not(.ship-tok-combat):is(
  [data-instance-id$="0"],[data-instance-id$="1"],[data-instance-id$="2"],
  [data-instance-id$="3"],[data-instance-id$="4"],[data-instance-id$="5"],
  [data-instance-id$="6"],[data-instance-id$="7"],[data-instance-id$="8"]
) { --sq-idle-phase: 0; }
.ship-card-v3:not(.ship-tok-combat):is(
  [data-instance-id$="9"],[data-instance-id$="a"],[data-instance-id$="b"],
  [data-instance-id$="c"],[data-instance-id$="d"],[data-instance-id$="e"],
  [data-instance-id$="f"],[data-instance-id$="g"],[data-instance-id$="h"]
) { --sq-idle-phase: 1; }
.ship-card-v3:not(.ship-tok-combat):is(
  [data-instance-id$="i"],[data-instance-id$="j"],[data-instance-id$="k"],
  [data-instance-id$="l"],[data-instance-id$="m"],[data-instance-id$="n"],
  [data-instance-id$="o"],[data-instance-id$="p"],[data-instance-id$="q"]
) { --sq-idle-phase: 2; }
.ship-card-v3:not(.ship-tok-combat):is(
  [data-instance-id$="r"],[data-instance-id$="s"],[data-instance-id$="t"],
  [data-instance-id$="u"],[data-instance-id$="v"],[data-instance-id$="w"],
  [data-instance-id$="x"],[data-instance-id$="y"],[data-instance-id$="z"]
) { --sq-idle-phase: 3; }

/* ── Baustein 1: Karten atmen — NUR ausserhalb der Kampfansicht (:not(.ship-tok-combat)).
   getCombatAnchor()/playDestructionEffect() u.a. messen genau die Kampf-Token-Rects fuer
   FX-Anker/Klon-Startpositionen — ein zeitgleicher Skalierungs-Transform waere dort
   riskant. Auf Uebersicht-Brett/Hand/Fleetzone besteht dieses Risiko nicht (dort misst
   keine FX die Karten-Rects). */
@keyframes sq-idle-breathe-kf {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(calc(1 + var(--sq-fx-idle-breathe-scale-mult) * var(--sq-idle-strength))); }
}
body.sq-idle-on.sq-idle-breathe-on:not(.sq-idle-suspended) .ship-card-v3:not(.ship-tok-combat) {
  animation: sq-idle-breathe-kf var(--sq-fx-idle-breathe-ms) ease-in-out infinite;
  animation-delay: calc(var(--sq-fx-idle-breathe-ms) * -1 * (0.08 + var(--sq-idle-phase) * 0.22));
}

/* ── Baustein 2: Fraktions-Halo — weicher Schein HINTER der Karte (::before, z-index -1,
   braucht position:relative auf der Karte — bereits inline gesetzt). Rot(VS)/Blau(UED),
   ANDERER Takt als das Atmen (5300ms statt 7200ms — kein gemeinsamer Teiler in der Naehe,
   sonst liefen beide irgendwann synchron und wirkten wieder mechanisch). */
.ship-card-v3:not(.ship-tok-combat)::before {
  content: '';
  position: absolute;
  inset: -10px;
  z-index: -1;
  border-radius: 8px;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle, var(--sq-idle-halo-color, rgba(160,170,190,0.5)) 0%, transparent 72%);
}
.ship-card-v3[data-faction="VS"]::before  { --sq-idle-halo-color: rgba(224,32,32,0.65); }
.ship-card-v3[data-faction="UED"]::before { --sq-idle-halo-color: rgba(40,110,240,0.65); }
@keyframes sq-idle-halo-kf {
  0%, 100% { opacity: 0; }
  50%      { opacity: calc(var(--sq-fx-idle-halo-opacity-mult) * var(--sq-idle-strength)); }
}
body.sq-idle-on.sq-idle-halo-on:not(.sq-idle-suspended) .ship-card-v3:not(.ship-tok-combat)::before {
  animation: sq-idle-halo-kf var(--sq-fx-idle-halo-ms) ease-in-out infinite;
  animation-delay: calc(var(--sq-fx-idle-halo-ms) * -1 * (0.08 + var(--sq-idle-phase) * 0.22));
}

/* ── Baustein 5: Lichtschimmer — seltener, schraeger Lichtstreifen (::after, ueber der
   Karte). Zyklus 17s, davon nur ein kurzes Fenster (0–7%) sichtbar (feste Prozent-
   Haltepunkte — Begruendung s. FX_DURATIONS-Kommentar in game-anim-combat.js), Rest des
   Zyklus unsichtbar/bewegungslos — "gelegentlich, selten". Grosser Delay-Streubereich
   (fast der ganze Zyklus) sorgt zusaetzlich dafuer, dass Karten nie gleichzeitig
   schimmern. Bewusst dieselbe :not(.ship-tok-combat)-Ausnahme wie Atmen/Halo — kein
   Layout-Risiko (nur ::after-Transform/-Opacity, ruehrt die Karte selbst nicht an),
   aber konzeptionell bleibt "Leerlauf" auf Nicht-Kampf-Ansichten beschraenkt. */
.ship-card-v3:not(.ship-tok-combat)::after {
  content: '';
  position: absolute;
  top: 0; left: -30%;
  width: 160%; height: 100%;
  pointer-events: none;
  z-index: 5;
  background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,0.9) 50%, transparent 58%);
  opacity: 0;
  transform: translateX(-70%);
}
@keyframes sq-idle-shimmer-kf {
  0%   { transform: translateX(-70%); opacity: 0; }
  2%   { opacity: calc(var(--sq-fx-idle-shimmer-opacity-mult) * var(--sq-idle-strength)); }
  7%   { transform: translateX(70%);  opacity: 0; }
  100% { transform: translateX(70%);  opacity: 0; }
}
body.sq-idle-on.sq-idle-shimmer-on:not(.sq-idle-suspended) .ship-card-v3:not(.ship-tok-combat)::after {
  animation: sq-idle-shimmer-kf var(--sq-fx-idle-shimmer-cycle-ms) linear infinite;
  animation-delay: calc(var(--sq-fx-idle-shimmer-cycle-ms) * -1 * (0.05 + var(--sq-idle-phase) * 0.23));
}

/* ── Baustein 4: Sterne driften — nutzt die BESTEHENDEN zwei Ebenen (.stars-layer/
   .stars-layer-2, s.o.), animiert NUR transform:translate (nicht background-position).
   #game-bg ist position:fixed;inset:0 (views/play-v3.ejs) — kein sichtbarer Rand bei der
   kleinen Auslenkung hier. Unterschiedliches Tempo je Ebene = Parallax-Tiefe. */
@keyframes sq-idle-stars-drift-kf {
  0%   { transform: translate(0, 0); }
  50%  { transform: translate(calc(var(--sq-fx-idle-stars-drift-px) * var(--sq-idle-strength)), calc(var(--sq-fx-idle-stars-drift-px) * var(--sq-idle-strength) * -0.6)); }
  100% { transform: translate(0, 0); }
}
@keyframes sq-idle-stars-drift2-kf {
  0%   { transform: translate(0, 0); }
  50%  { transform: translate(calc(var(--sq-fx-idle-stars-drift2-px) * var(--sq-idle-strength) * -1), calc(var(--sq-fx-idle-stars-drift2-px) * var(--sq-idle-strength) * 0.5)); }
  100% { transform: translate(0, 0); }
}
body.sq-idle-on.sq-idle-stars-on:not(.sq-idle-suspended) .stars-layer {
  animation: sq-idle-stars-drift-kf var(--sq-fx-idle-stars-drift-ms) ease-in-out infinite;
}
body.sq-idle-on.sq-idle-stars-on:not(.sq-idle-suspended) .stars-layer-2 {
  animation: sq-idle-stars-drift2-kf var(--sq-fx-idle-stars-drift2-ms) ease-in-out infinite;
}

/* ═══════════════════════════════════════════════════
   5. SCREENS (Basis)
   game-overview.js + game-combat.js ueberschreiben
   display + position via screen.style.cssText.
   ═══════════════════════════════════════════════════ */

/* NEW: Screen Basis (2026-05-01) */
/* FIX: Screens sind absolute im #game-root — display:none/flex steuert Sichtbarkeit (2026-05-01) */
.screen {
  display: none;
  width: 100%;
  height: 100%;
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}

.screen.active {
  display: flex;
  flex-direction: column;
}

/* NEW: Overview + Combat füllen #game-root vollständig — JS überschreibt display via cssText */
#screen-overview,
#screen-combat {
  width: 100%;
  height: 100%;
}

/* ═══════════════════════════════════════════════════
   6. TURN TIMER (fixed, ausserhalb Scale-Root)
   ═══════════════════════════════════════════════════ */

/* NEW: Turn Timer (2026-05-01) */
#turn-timer-container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 1000;
  background: rgba(51, 204, 204, 0.08);
  align-items: stretch;
}

#turn-timer-bar {
  height: 100%;
  background: #33cccc;
  transition: width 1s linear;
  box-shadow: 0 0 8px #33cccc;
}

#turn-timer-label {
  position: fixed;
  top: 6px;
  left: 8px;
  font-size: 10px;
  color: rgba(51, 204, 204, 0.55);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  z-index: 1001;
}

#turn-timer-seconds {
  position: fixed;
  top: 6px;
  right: 8px;
  font-size: 11px;
  color: rgba(51, 204, 204, 0.7);
  font-family: 'Share Tech Mono', monospace;
  z-index: 1001;
}

/* ═══════════════════════════════════════════════════
   7. LOBBY SCREEN
   ═══════════════════════════════════════════════════ */

/* NEW: Lobby-Layout (2026-05-01) */
#screen-lobby {
  align-items: center;
  justify-content: center;
  position: relative;
  background: transparent;
  z-index: 2;
}

#lobby-ship-container {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.lobby-main {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.lobby-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-bottom: 28px;
}

.lobby-logo { width: 140px; height: auto; }

.lobby-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 24px;
  font-weight: 900;
  color: var(--gold); /* FIX: Gold statt Cyan — Marcel-Korrektur Session 1.4b */
  letter-spacing: 4px;
  text-align: center;
  line-height: 1.3;
}

.version-tag {
  font-size: 10px;
  color: rgba(51, 204, 204, 0.28);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 2px;
  margin-top: 20px;
}

/* Sprach-Schalter */
.lang-switch-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.lang-label {
  font-size: 11px;
  color: rgba(51, 204, 204, 0.4);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 2px;
}

.lang-switch {
  position: relative;
  display: inline-block;
  width: 36px;
  height: 20px;
  cursor: pointer;
}

.lang-switch input { opacity: 0; width: 0; height: 0; }

.lang-slider {
  position: absolute;
  inset: 0;
  background: rgba(51, 204, 204, 0.1);
  border: 1px solid rgba(51, 204, 204, 0.25);
  border-radius: 10px;
  transition: background 0.2s;
}

.lang-slider::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #33cccc;
  transition: transform 0.2s;
}

.lang-switch input:checked + .lang-slider::before { transform: translateX(16px); }

/* Menü-Navigation */
.menu-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 300px;
}

/* FIX I1: .menu-level/.menu-btn/.menu-btn-primary/.menu-btn-sm/.back-btn/.menu-arrow
   waren HIER dupliziert (identische Selektoren nochmal weiter unten im Sci-Fi-Lobby-
   Block, der wegen späterer Cascade-Reihenfolge ohnehin gewann) — restlos entfernt,
   einzige verbleibende Definition + neuer Sci-Fi-Button-Stil (Eckklammer/Energie-Kante/
   Tick) steht jetzt dort. .menu-btn-quit war NICHT dupliziert, dorthin verschoben. */

.menu-row {
  display: flex;
  gap: 7px;
  align-items: center;
  width: 270px;
}

.menu-field {
  width: 270px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.menu-label {
  font-size: 9px;
  color: rgba(51, 204, 204, 0.38);
  letter-spacing: 2px;
  font-family: 'Share Tech Mono', monospace;
}

.menu-value {
  font-size: 13px;
  color: #33cccc;
  font-family: 'Share Tech Mono', monospace;
}

.menu-input {
  background: rgba(51, 204, 204, 0.04);
  border: 1px solid rgba(51, 204, 204, 0.18);
  border-radius: 4px;
  padding: 8px 12px;
  font-size: 13px;
  color: var(--text-primary);
  font-family: 'Rajdhani', sans-serif;
  letter-spacing: 1px;
  outline: none;
  transition: border-color 0.15s;
}

.menu-input:focus { border-color: rgba(51, 204, 204, 0.5); }

.menu-input-sm {
  padding: 7px 9px;
  font-size: 12px;
  text-align: center;
  letter-spacing: 3px;
}

.menu-select {
  background: rgba(51, 204, 204, 0.04);
  border: 1px solid rgba(51, 204, 204, 0.18);
  border-radius: 4px;
  padding: 7px 9px;
  font-size: 12px;
  color: var(--text-secondary);
  font-family: 'Rajdhani', sans-serif;
  outline: none;
  cursor: pointer;
}

.menu-status {
  width: 270px;
  text-align: center;
  font-size: 11px;
  color: rgba(51, 204, 204, 0.45);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
}

.menu-status-info {
  font-size: 10px;
  color: rgba(51, 204, 204, 0.3);
  margin: 3px 0;
}

.menu-link {
  background: none;
  border: none;
  font-size: 10px;
  color: rgba(51, 204, 204, 0.3);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  cursor: pointer;
  text-decoration: none;
  transition: color 0.15s;
}

.menu-link:hover { color: rgba(51, 204, 204, 0.65); }

.lobby-pulse-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.lobby-pulse {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(51, 204, 204, 0.65);
  animation: pulse 1.4s ease infinite;
}

/* Einstellungen */
.setting-row {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 270px;
}

.setting-label {
  font-size: 10px;
  color: rgba(51, 204, 204, 0.4);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  flex: 0 0 72px;
}

.menu-slider {
  flex: 1;
  height: 4px;
  accent-color: #33cccc;
  cursor: pointer;
}

/* Tutorial */
.tutorial-check { width: 14px; height: 14px; flex-shrink: 0; }

/* Uber */
.about-block {
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 14px;
}

.about-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 16px;
  color: #33cccc;
  letter-spacing: 3px;
}

.about-ver {
  font-size: 11px;
  color: rgba(51, 204, 204, 0.32);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 2px;
}

.about-credit {
  font-size: 10px;
  color: rgba(200, 210, 230, 0.3);
  letter-spacing: 1px;
}

.about-links {
  display: flex;
  gap: 14px;
  justify-content: center;
  margin-bottom: 6px;
}

.room-code {
  font-size: 20px;
  color: var(--gold);
  letter-spacing: 5px;
  font-family: 'Share Tech Mono', monospace;
  font-weight: 600;
}

/* Faction Badge + Dot (game-core.js, game-lobby.js) */
.faction-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 1px;
  font-family: 'Share Tech Mono', monospace;
}

.faction-badge.VS  { background: #2a0808; color: var(--vs);  border: 1px solid var(--vs-dim); }
.faction-badge.UED { background: #003015; color: var(--ued); border: 1px solid var(--ued-dim); }

.faction-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.faction-dot.VS  { background: var(--vs);  box-shadow: 0 0 4px var(--vs); }
.faction-dot.UED { background: var(--ued); box-shadow: 0 0 4px var(--ued); }

/* NEW (Fix Lobby-Promo/Discord, 2026-07-17): Promo-Banner links + Discord-Button
   rechts neben der Menüspalte. Position/Größe kommen vom UI-v3.1-Layout-Engine
   (public/js/layout/layout-engine.js + layout-config.js, screens.lobby — dem
   bestehenden Muster folgend, NICHT eigenes Flex-Layout: #lobby-main wird von
   genau diesem Mechanismus bereits absolut positioniert+breitenbegrenzt, siehe
   #lobby-main-Regel weiter unten). Hier nur visuelles Styling — position/left/top/
   width/height setzt LayoutAnchors.applyToElement() per Inline-Style zur Laufzeit.
   Beide Elemente sind standardmäßig ausgeblendet und werden NUR sichtbar, solange
   #menu-main (Level 0, das Hauptmenü) aktiv ist — :has() auf #screen-lobby (gemeinsamer
   Vorfahre von #lobby-main und diesen beiden Geschwister-Elementen) bindet die
   Sichtbarkeit direkt an die bestehende .menu-level.active-Klasse aus game-lobby.js,
   ohne dessen Navigations-Code anzufassen. Electron 43 (Steam-Shell) und alle
   Chromium-basierten Browser unterstützen :has() vollständig. */
.lobby-promo-banner,
.lobby-discord-btn,
.lobby-steam-btn {
  display: none;
}

#screen-lobby:has(#menu-main.active) .lobby-promo-banner {
  display: block;
}
#screen-lobby:has(#menu-main.active) .lobby-discord-btn,
#screen-lobby:has(#menu-main.active) .lobby-steam-btn {
  display: flex;
}

.lobby-promo-banner {
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  /* NEW (Fix Positionen/Transparenz, 2026-07-18): Ruhezustand so transluzent wie der
     Discord-Button — der hat kein eigenes opacity:, sondern mehrere rgba()-Alphas
     (Hintergrund 0.08, Rahmen 0.4, Text 0.85). 0.85 (Textfarbe, die praesenteste
     Flaeche des Buttons) liegt exakt in der vom Prompt vermuteten Spanne (~0.7-0.85)
     und wird hier als EIN einheitlicher opacity-Wert auf den ganzen Banner uebernommen. */
  opacity: 0.85;
  transition: opacity 0.2s ease, filter 0.15s ease, transform 0.15s ease;
}
.lobby-promo-banner img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 8px;
}
.lobby-promo-banner:hover {
  opacity: 1;
  filter: brightness(1.12);
  transform: scale(1.02);
}

.lobby-discord-btn {
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
  border: 1px solid rgba(88, 101, 242, 0.4); /* Discord-Blurple */
  border-radius: 8px;
  background: rgba(88, 101, 242, 0.08);
  color: rgba(210, 214, 255, 0.85);
  font-family: 'Share Tech Mono', monospace;
  font-size: 12px;
  letter-spacing: 1px;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.lobby-discord-btn:hover {
  background: rgba(88, 101, 242, 0.18);
  border-color: rgba(88, 101, 242, 0.8);
  color: #ffffff;
  box-shadow: 0 0 16px rgba(88, 101, 242, 0.5);
}
.lobby-discord-icon { flex-shrink: 0; }

/* NEW (Fix BE1, Steam-Verlinkung Lobby, 2026-08-20): 1:1 nach dem Discord-Knopf-Muster
   oben, eigene Farbe (Steam-Blau statt Discord-Blurple), sonst identische Struktur. */
.lobby-steam-btn {
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
  border: 1px solid rgba(102, 192, 244, 0.4); /* Steam-Blau */
  border-radius: 8px;
  background: rgba(102, 192, 244, 0.08);
  color: rgba(200, 231, 250, 0.85);
  font-family: 'Share Tech Mono', monospace;
  font-size: 12px;
  letter-spacing: 1px;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.lobby-steam-btn:hover {
  background: rgba(102, 192, 244, 0.18);
  border-color: rgba(102, 192, 244, 0.8);
  color: #ffffff;
  box-shadow: 0 0 16px rgba(102, 192, 244, 0.5);
}
.lobby-steam-icon { flex-shrink: 0; }

/* NEW: Portrait-Breakpoint (Layout Engine schaltet #lobby-main dort auf "stretch-both",
   volle Bildschirmbreite, siehe layout-config.js screens.lobby.portrait) — kein Platz
   neben der Menüspalte, deshalb hart ausgeblendet statt mit einer evtl. veralteten
   Anchor-Position aus dem vorherigen Breakpoint stehen zu bleiben (die Layout Engine
   setzt bei fehlendem Config-Eintrag für den aktuellen Breakpoint keine neue Position). */
@media (max-aspect-ratio: 1/1) {
  .lobby-promo-banner,
  .lobby-discord-btn,
  .lobby-steam-btn {
    display: none !important;
  }
}

/* ═══════════════════════════════════════════════════
   8b. BACKBONE-HUB SCREEN (Fix CG1, Spieler-Zentrale)
   ═══════════════════════════════════════════════════ */

/* Umzug von Fix CD1 (Kopfband)/CC1 (Warteschlangen-Ansicht) aus der 270px-Lobby-
   Menuespalte auf einen eigenen Bildschirm — Konzept B (mockups/warteschlange-hub-
   konzepte.html). #bb-hub-panel wird per LayoutEngine (layout-config.js,
   screens['backbone-hub']) gesetzt — dieselbe Technik wie #vanguard-panel/
   #gameover-panel, aber seit CJ1 mit echten Raendern (margins) statt 0/0/0/0.

   ── Fix CJ1 (2026-08-20, reine Gestaltungsrunde) ─────────────────────────────────
   Bis CI1 waren alle Bestandteile da, sahen dem Entwurf aber nicht aehnlich. Vom
   Betreiber am laufenden /playtest beobachtet und per Bildschirmfoto bestaetigt
   (berichte/fix-cj1-zentrale-gestaltung.md):
     1. Flaechen ohne eigenen Hintergrund — die fast durchsichtige Fuellung
        (rgba(10,14,24,.5)) liess die Schrift direkt auf dem Hintergrundbild stehen.
     2. Volle Buehnenbreite statt Spalten — LayoutAnchors.applyToElement() schreibt
        `width` INLINE auf #bb-hub-panel und ueberstimmt damit jedes `width` aus dem
        CSS (das alte `width:min(980px,100%)` war deshalb wirkungslos). Die Rangliste
        lief bis an den Buehnenrand, die Punktespalte klebte am Rand.
     3. Keine Oben/Unten-Aufteilung — Rangliste/Letzte Partien lagen als gestapelte
        rechte Spalte NEBEN dem Kopfband, die Fraktionswahl schwamm im Rest.
   Konsequenz fuer diese Runde: Aussenmasse gehoeren in layout-config.js (margins),
   die INNERE Aufteilung hierher. Kein `width`/`left`/`top` mehr auf #bb-hub-panel im
   CSS — das waere ein Sonderweg an der Layout-Engine vorbei (Drift-Quelle).

   Aufteilung nach Konzept B, Verhaeltnisse aus dem 980px-Entwurf auf die Buehne
   umgerechnet (Entwurf: Inhaltsbreite 944 = 238 / 388 / 290 bei 14px Abstand;
   hier: 1120 = 272 / 480 / 336 bei 16px Abstand — 25/44/31 % gegen 25/41/31 %).
   Bandhoehe: Entwurf 186 von 564 nutzbarer Hoehe (33 %) -> hier 214 von 642 (33 %). */
#screen-backbone-hub {
  /* Farbwerte aus dem Entwurf (--panel:#0a1120, --line:#16203a). Der Rahmen ist
     gegenueber dem Entwurf aufgehellt und die Fuellung minimal durchscheinend: die
     echte Buehne traegt ein fotografisches Hintergrundbild (heller Planet), der
     Entwurf nur ein fast schwarzes Sternenfeld — #16203a waere darauf unsichtbar.
     Einzige bewusste Farbabweichung, s. Bericht. */
  --bb-panel-bg: linear-gradient(168deg, rgba(12, 19, 35, 0.96), rgba(5, 9, 18, 0.975));
  --bb-panel-line: rgba(46, 64, 104, 0.95);
  --bb-row-line: rgba(24, 34, 58, 0.95);
  --bb-content-w: 1120px;
  --bb-col-id: 272px;
  --bb-col-recent: 336px;
  --bb-band-h: 214px;
  align-items: center;
  justify-content: center;
  /* Nur Rueckfallposition, falls applyLayout('backbone-hub') nicht laeuft — die
     wirksamen Raender stehen in layout-config.js (screens['backbone-hub'].margins). */
  padding: 18px 80px 22px;
  overflow: hidden;
}

.bb-hub-panel {
  /* KEIN width hier: LayoutAnchors setzt Breite/Hoehe inline (s. Kommentar oben).
     align-items:center + feste Breite auf den Kindern haelt den Inhalt mittig und
     verhindert, dass er sich auf sehr breiten Buehnen (bis 1920, MAX_STAGE_W)
     auseinanderzieht — "feste Spaltenbreiten, kein Ausdehnen ueber die ganze
     Buehne" (Rundenprompt Abschnitt 1). */
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  overflow-x: hidden;
  overflow-y: auto;
}

/* Die Zeilen des Bildschirms teilen sich EINE Inhaltsbreite — dadurch fluchten Band und
   Handlungszone an derselben linken/rechten Kante. Fix CL1: .bb-hub-back steht nicht mehr
   in dieser Reihe — er sitzt seit dieser Runde INNERHALB der Handlungszone, unter dem
   GEGNER-SUCHEN-Knopf (Betreiber-Vorgabe). */
.bb-hub-top,
.bb-hub-content {
  width: min(var(--bb-content-w), 100%);
}

.bb-hub-back {
  background: none;
  border: none;
  color: #6a7090;
  font-family: 'Orbitron', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  cursor: pointer;
  padding: 4px 2px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  flex-shrink: 0;
}
.bb-hub-back:hover { color: #f0a500; text-shadow: 0 0 10px rgba(240, 165, 0, 0.3); }
.bb-hub-back .menu-arrow { color: #4dd0e1; font-size: 11px; }
.bb-hub-back:hover .menu-arrow { color: #f0a500; }

/* ── Oberes Band: drei Flaechen NEBENEINANDER (Konzept B) ───────────────────────
   .bb-hub-right-col (CI1: Rangliste ueber Letzte Partien in einer rechten Spalte)
   loest im Querformat ihre eigene Box per display:contents auf — dadurch werden
   Rangliste und Letzte Partien direkte Flex-Kinder des Bandes und stehen nebeneinander,
   ohne dass das Markup umgebaut werden muss (Rundenprompt: keine Funktionsaenderung).
   Im Hochformat dient dasselbe display:contents dazu, alle drei Flaechen per `order`
   umsortieren zu koennen (s. Hochformat-Block unten). */
.bb-hub-top {
  display: flex;
  align-items: stretch;
  gap: 16px;
  height: var(--bb-band-h);
  flex: 0 0 auto;
}
.bb-hub-right-col { display: contents; }

/* Gemeinsamer Flaechen-Look — das ist der Kern des CJ1-Befundes: jede Flaeche traegt
   ihren eigenen, gedeckten Hintergrund mit Rahmen, damit die Schrift unabhaengig vom
   Hintergrundbild lesbar bleibt.

   Fix CL1 (2026-08-20): dazu die Science-Fiction-Formensprache, die das Spiel bereits hat,
   statt schlichter Rechtecke (Betreiber-Befund) — und zwar mit den VORHANDENEN Mitteln,
   nicht mit einer zweiten Gestaltungswelt (Rundenprompt Abschnitt 4):
     * abgeschraegte Ecken per clip-path in genau der Form, die .faction-tile/.menu-btn
       schon benutzen (polygon(Npx 0, 100% 0, ...) — oben links/unten rechts angeschnitten),
     * eine goldene Kopfkante wie am Kommando-Kreis/HUD-Rand,
     * eine goldene Eckmarke unten rechts an der Schnittkante.
   Die Fuellung wurde gleichzeitig DEUTLICHER gedeckt (0.93/0.95 -> 0.96/0.97) und die
   Schriftfarben angehoben: "Lesbarkeit hat Vorrang vor Dekoration" (Abschnitt 4). */
.bb-hub-header,
.bb-hub-leaderboard,
.bb-hub-recent {
  --bb-chamfer: 12px;
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 11px 13px 12px;
  border: 1px solid var(--bb-panel-line);
  background: var(--bb-panel-bg);
  overflow: hidden;
  clip-path: polygon(var(--bb-chamfer) 0, 100% 0, 100% calc(100% - var(--bb-chamfer)),
                     calc(100% - var(--bb-chamfer)) 100%, 0 100%, 0 var(--bb-chamfer));
}
/* Kopfkante: kraeftig links (wo die Ueberschrift steht), nach rechts auslaufend — dasselbe
   Prinzip wie die Energie-Kante der .menu-btn, nur waagerecht. */
.bb-hub-header::before,
.bb-hub-leaderboard::before,
.bb-hub-recent::before {
  content: '';
  position: absolute;
  top: 0;
  left: var(--bb-chamfer);
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, rgba(240, 165, 0, 0.85), rgba(240, 165, 0, 0.12) 62%, transparent);
  pointer-events: none;
}
/* Eckmarke an der unteren Schnittkante — reine Dekoration, nie ueber Text (die Flaechen
   haben unten Innenabstand, s. padding oben). */
.bb-hub-header::after,
.bb-hub-leaderboard::after,
.bb-hub-recent::after {
  content: '';
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: calc(var(--bb-chamfer) + 5px);
  height: calc(var(--bb-chamfer) + 5px);
  background: linear-gradient(135deg, transparent 48%, rgba(240, 165, 0, 0.5) 50%, transparent 52%);
  pointer-events: none;
}
.bb-hub-header {
  flex: 0 0 var(--bb-col-id);
  justify-content: center;  /* Entwurf: Identitaet sitzt vertikal mittig in ihrer Flaeche */
  gap: 8px;
}
.bb-hub-leaderboard { flex: 1 1 0; }
.bb-hub-recent      { flex: 0 0 var(--bb-col-recent); }

.bb-hub-id {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.bb-hub-header .bb-hub-stats,
.bb-hub-header .bb-hub-empty {
  margin-top: 0;
}

/* Flaechen-Ueberschrift — im Entwurf gold (.panel h4), nicht grau. Der rechte
   Zusatz des Entwurfs ("SAISON 1" / "5") fehlt bewusst: beides waere erfundener
   Inhalt (die Saison ist nirgends abrufbar), Rundenprompt Abschnitt 4. */
.bb-ladder-title {
  font-family: 'Orbitron', monospace;
  font-size: 10px;
  letter-spacing: 0.18em;
  color: #f0a500;
  text-transform: uppercase;
  margin-bottom: 8px;
  flex-shrink: 0;
  /* Fix CL1: Ueberschrift bekommt eine eigene Grundlinie (Entwurf: die Panels trennen
     Kopf und Inhalt), plus ein leichtes Leuchten wie andere Goldschriften im Spiel. */
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(240, 165, 0, 0.22);
  text-shadow: 0 0 12px rgba(240, 165, 0, 0.28);
}

/* Listen fuellen den Rest ihrer Flaeche. overflow-y:auto statt hidden: eine ungewoehnlich
   lange Liste (oder ein umgebrochener langer Name) scrollt INNERHALB der Flaeche, statt
   ueber den Buehnenrand zu laufen oder abgeschnitten zu werden. min-height:0 ist noetig,
   sonst wuerde das Flex-Item nie unter seine Inhaltshoehe schrumpfen. */
.bb-ladder-list,
.bb-recent-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
}

/* Eine Zeile — .bb-ladder-row wird per JS (backbone-lobby.js#_bbRenderLeaderboard) aus
   drei Kindspans zusammengesetzt (Rang/Name/Score), Name per textContent (nie innerHTML —
   Anzeigenamen sind fremdbestimmt). min-width:0 auf Zeile UND Name-Span, sonst erzwingt
   ein langer, leerzeichenloser Name die MIN-CONTENT-Breite des Flex-Items (derselbe
   Flexbox-Effekt wie beim Kopfband-Namen, s. "Fix CD1: Spieler-Zentrale-Kopfband"-Block
   weiter unten) — "lange Namen duerfen nicht abgeschnitten werden".
   Trennlinie je Zeile nach dem Entwurf (dort `td { border-bottom:1px solid #121a2c }`). */
.bb-ladder-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 12px;
  padding: 3px 2px;
  min-width: 0;
  border-bottom: 1px solid var(--bb-row-line);
}
.bb-ladder-row:last-child { border-bottom: none; }
.bb-ladder-rank {
  color: #6a7090;
  width: 22px;
  flex-shrink: 0;
  text-align: right;
  /* Zahlen fluchten (Rundenprompt Abschnitt 3): feste Laufweite, damit 1 und 12
     dieselbe Breite belegen. */
  font-variant-numeric: tabular-nums;
}
/* Die ersten drei Plaetze tragen ihre Wertigkeit auch ohne die Zahl zu lesen. */
.bb-ladder-row:nth-child(1) .bb-ladder-rank { color: #f0c040; }
.bb-ladder-row:nth-child(2) .bb-ladder-rank { color: #c9d2e4; }
.bb-ladder-row:nth-child(3) .bb-ladder-rank { color: #c98a4b; }
.bb-ladder-name {
  color: #d2d7e6;
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.bb-ladder-score {
  color: #f0a500;
  flex-shrink: 0;
  width: 48px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* Eigene Zeile hervorgehoben — sichtbar unabhaengig davon, ob sie inline in der Spitze
   steckt oder (bb-ladder-row-gap) als Anhang weit ausserhalb liegt.
   Fix CL1: deutlicher als bisher (Betreiber-Befund "die eigene Zeile faellt nicht auf") —
   kraeftigere Fuellung PLUS eine goldene Kante links, die auch bei schwachem Kontrast
   traegt. */
.bb-ladder-row-me {
  background: linear-gradient(90deg, rgba(240, 165, 0, .20), rgba(240, 165, 0, .06));
  border-left: 2px solid #f0a500;
  padding-left: 4px;
  box-shadow: inset 0 0 18px rgba(240, 165, 0, .07);
}
.bb-ladder-row-me .bb-ladder-name  { color: #ffc94d; font-weight: 600; }
.bb-ladder-row-me .bb-ladder-rank  { color: #f0a500; }
.bb-ladder-row-me .bb-ladder-score { color: #ffd873; }
.bb-ladder-row-gap {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px dashed rgba(139, 147, 168, 0.25);
}
/* ── Leerzustaende (Rundenprompt Abschnitt 5) ─────────────────────────────────────
   Bei einer frischen Saison sind sie der NORMALFALL, nicht die Ausnahme — vorher stand
   eine einzelne graue Zeile oben links in einer ansonsten leeren Flaeche, was wie ein
   Fehler aussah (Bildschirmfoto "vorher" im Bericht). Jetzt fuellen sie ihre Flaeche
   mittig aus und tragen dieselbe Formensprache (goldene Zierlinie ueber dem Text,
   gestrichelter Rahmen = "hier kommt noch etwas hin", kein Warnzeichen).
   KEINE erfundenen Zusatztexte — die Saetze sind unveraendert die aus CH1/CI1. */
.bb-ladder-empty,
.bb-ladder-no-own,
.bb-ladder-error,
.bb-hub-empty {
  font-size: 11px;
  color: #8b93a8;
  font-family: 'Rajdhani', sans-serif;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}
/* Nur die "die Flaeche ist leer"-Zustaende fuellen die Flaeche — .bb-ladder-no-own und
   .bb-recent-partial stehen NEBEN einer weiterhin sichtbaren Liste (CH1/CI1) und duerfen
   sie deshalb nicht verdraengen. */
.bb-hub-leaderboard > .bb-ladder-empty,
.bb-hub-leaderboard > .bb-ladder-error,
.bb-hub-recent > .bb-ladder-empty,
.bb-hub-recent > .bb-ladder-error {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  text-align: center;
  padding: 4px 10px;
  border: 1px dashed rgba(240, 165, 0, 0.16);
  background: rgba(240, 165, 0, 0.02);
}
/* (.hidden traegt global display:none !important — kein eigener Ausschluss noetig.) */
.bb-hub-leaderboard > .bb-ladder-empty::before,
.bb-hub-leaderboard > .bb-ladder-error::before,
.bb-hub-recent > .bb-ladder-empty::before,
.bb-hub-recent > .bb-ladder-error::before {
  content: '';
  width: 46px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(240, 165, 0, 0.55), transparent);
}
.bb-ladder-no-own { margin-top: 8px; color: #7d879e; }
.bb-ladder-error { color: rgba(230, 110, 100, 0.9); }
.bb-hub-leaderboard > .bb-ladder-error,
.bb-hub-recent > .bb-ladder-error {
  border-color: rgba(224, 32, 32, 0.28);
  background: rgba(224, 32, 32, 0.04);
}
.bb-hub-leaderboard > .bb-ladder-error::before,
.bb-hub-recent > .bb-ladder-error::before {
  background: linear-gradient(90deg, transparent, rgba(224, 60, 60, 0.6), transparent);
}

/* Letzte Partien (Fix CI1) — eine Zeile: Ausgang | Gegner (flex, min-width:0 gegen
   Ueberlauf, dieselbe Fehlerklasse wie .bb-ladder-name) | Punktveraenderung | Zeitpunkt.
   BEWUSST KEINE Fraktions-Spalte — die Rohdaten liefern keine (s. backbone-client.js#
   getRecentGames-Kommentar). Feste Spaltenbreiten rechts (Entwurf: .rt mit width), damit
   Punktveraenderung und Zeitpunkt untereinander fluchten statt zu zappeln. */
.bb-recent-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 11.5px;
  padding: 3px 2px;
  min-width: 0;
  border-bottom: 1px solid var(--bb-row-line);
}
.bb-recent-row:last-child { border-bottom: none; }
/* Fix CL1: Sieg und Niederlage sind unterscheidbar, OHNE das Wort lesen zu muessen
   (Rundenprompt Abschnitt 3) — farbige Marke vor dem Ausgang plus kraeftigere Farbe.
   Die Marke ist rein dekorativ (::before am Ausgangs-Feld), sie ersetzt keinen Text. */
.bb-recent-result {
  flex-shrink: 0;
  width: 74px;
  color: #c0c4d4;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.bb-recent-result::before {
  content: '';
  width: 3px;
  height: 9px;
  flex-shrink: 0;
  background: currentColor;
  opacity: 0.85;
  transform: translateY(1px);
}
.bb-recent-win  { color: #5ce08a; text-shadow: 0 0 10px rgba(92, 224, 138, 0.25); }
.bb-recent-loss { color: #ff7b5c; text-shadow: 0 0 10px rgba(255, 123, 92, 0.22); }
.bb-recent-opponent {
  flex: 1;
  min-width: 0;
  color: #97a0b6;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.bb-recent-delta {
  flex-shrink: 0;
  width: 36px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.bb-recent-delta-pos { color: #5ce08a; }
.bb-recent-delta-neg { color: #ff7b5c; }
.bb-recent-time {
  flex-shrink: 0;
  width: 72px;
  text-align: right;
  color: #5b667f;
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}

/* ── Handlungszone: "was tue ich jetzt" (Konzept B, unterer Bereich) ────────────
   Deutlich abgesetzt vom Band (Trennlinie wie im Entwurf: `border-top:1px solid
   #131c2e`), nimmt den gesamten Rest der Hoehe ein und zentriert darin Fraktionswahl
   bzw. Suchzustand. Der Wechsel Uebersicht <-> Warteschlange selbst wird NICHT
   angefasst (Rundenprompt Abschnitt 4) — er passiert weiterhin ueber die
   .menu-level.active-Umschaltung in backbone-lobby.js. */
.bb-hub-content {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;   /* Fix CL1: ZURÜCK ZUR LOBBY steht UNTER der Handlung */
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(40, 56, 92, 0.55);
}
.bb-hub-content .menu-level {
  width: 100%;
  max-width: 460px;
}
.bb-hub-content #menu-backbone-searching { max-width: 560px; }

/* ── Fix CL1: Peilring im Wartezustand ────────────────────────────────────────────
   Aufbau nach Konzept B ("only-q"): Ring links, Angaben rechts. Der Ring ist ein
   <canvas>, gezeichnet von window.SqRing (public/js/game-loading-screen.js) — dieselbe
   Formensprache wie der Ladebildschirm. Feste Bauteilgroesse in Buehnen-px: der Ring
   rechnet seinen Massstab selbst aus clientWidth/clientHeight, die Buehnenskalierung
   der LayoutEngine ist dabei bereits eingerechnet. */
.bb-search-zone {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 26px;
  width: 100%;
}
.bb-ring {
  position: relative;
  flex: 0 0 auto;
  width: 200px;
  height: 200px;
}
.bb-ring canvas {
  display: block;
  width: 100%;
  height: 100%;
}
.bb-search-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  width: 248px;
  min-width: 0;
}
.bb-search-kicker {
  font-family: 'Orbitron', monospace;
  font-size: 11px;
  letter-spacing: 0.22em;
  color: #f0a500;
  text-transform: uppercase;
  text-shadow: 0 0 14px rgba(240, 165, 0, 0.3);
}
.bb-search-side .menu-link {
  align-self: flex-start;
  margin-top: 2px;
}

/* ZURÜCK ZUR LOBBY (Betreiber-Vorgabe 2026-08-20: unter dem GEGNER-SUCHEN-Knopf).
   Bis CL1 stand der Knopf ueber dem Band, ganz links auf hellem Planetenhintergrund und
   war dort kaum lesbar (Bildschirmfoto "vorher"). Jetzt mittig unter der Handlung, mit
   eigener gedeckter Flaeche und derselben Anschraegung wie die uebrigen Flaechen. */
.bb-hub-content .bb-hub-back {
  align-self: center;
  justify-content: center;
  width: auto;
  padding: 7px 22px;
  color: #97a0b6;
  background: linear-gradient(180deg, rgba(12, 19, 35, 0.9), rgba(6, 10, 20, 0.94));
  border: 1px solid rgba(46, 64, 104, 0.9);
  clip-path: polygon(9px 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%, 0 9px);
  transition: color 0.15s ease, border-color 0.15s ease;
}
.bb-hub-content .bb-hub-back:hover {
  color: #f0a500;
  border-color: rgba(240, 165, 0, 0.7);
}

/* ── Hochformat ────────────────────────────────────────────────────────────────
   Zwei bis drei Spalten nebeneinander funktionieren im Hochformat nicht (die Buehne
   bleibt zwar 1280 Buehnen-px breit, wird aber auf ~0.6 herunterskaliert — 12px
   Schrift landet real bei ~7px). Deshalb gestapelt, Reihenfolge laut Rundenprompt
   Abschnitt 3: Identitaet, Handlungszone, Rangliste, Letzte Partien.

   display:contents auf .bb-hub-top UND .bb-hub-right-col loest beide Zwischenboxen
   auf — erst dadurch sind Kopfband, Rangliste und Letzte Partien Geschwister des
   Handlungsbereichs und per `order` umsortierbar, OHNE das Markup zu aendern (die
   Handlungszone steht im DOM zwingend nach den Datenflaechen, weil sie dort
   inhaltlich hingehoert und CG1/CH1/CI1 sie so gebaut haben).

   Gleicher Breakpoint wie das bestehende Lobby-Portrait-Verhalten (max-aspect-ratio
   1/1). Achtung: die LayoutEngine schaltet ihren eigenen 'portrait'-Satz erst unter
   ratio 0.9 um — im Zwischenband 0.9–1.0 greift hier bereits die Stapelung, waehrend
   die Raender noch aus 'default' kommen. `min(var(--bb-content-w), 100%)` faengt das
   ab: die Flaechen werden dann einfach so breit wie das Panel, nie breiter. */
@media (max-aspect-ratio: 1/1) {
  #screen-backbone-hub {
    /* Schmaler als die Buehne: eine Rangliste-Zeile ueber die vollen 1200 Buehnen-px
       reisst Name und Punktzahl so weit auseinander, dass die Zeile nicht mehr als
       Zeile gelesen wird. 960 liegt zwischen der Entwurfsbreite (388/290) und der
       vollen Buehne und nutzt im 768px-Hochformat noch ~75 % der Bildbreite. */
    --bb-content-w: 960px;
    padding: 10px 40px;
  }
  .bb-hub-panel { gap: 7px; }
  .bb-hub-top,
  .bb-hub-right-col { display: contents; }

  /* Fix CL1: .bb-hub-back braucht hier kein `order` mehr — er ist kein direktes Kind von
     .bb-hub-panel mehr, sondern sitzt in der Handlungszone (order 2). */
  .bb-hub-header  { order: 1; }
  .bb-hub-content { order: 2; }
  .bb-hub-leaderboard { order: 3; }
  .bb-hub-recent      { order: 4; }

  .bb-hub-header,
  .bb-hub-leaderboard,
  .bb-hub-recent {
    flex: 0 0 auto;
    width: min(var(--bb-content-w), 100%);
    overflow: visible;
  }
  /* Mindesthoehen, damit die Flaechen auch LEER fertig aussehen (frische Saison ist
     der Normalfall) — im Querformat uebernimmt das die feste Bandhoehe. */
  .bb-hub-leaderboard { min-height: 128px; }
  .bb-hub-recent      { min-height: 122px; }

  /* Hoehenbudget: die Buehne bleibt auch im Hochformat 720 Buehnen-px hoch, gestapelt
     braucht der Inhalt aber mehr Platz als nebeneinander. Deshalb hier ueberall etwas
     dichter (Abstaende, Flaechen-Innenabstand, Zeilenhoehe) — gemessen: 676 von 700
     verfuegbaren px bei voll gefuellten Listen, s. Bericht. .bb-hub-panel behaelt
     zusaetzlich sein overflow-y:auto als Rueckfallebene fuer Ausnahmefaelle
     (z. B. mehrfach umgebrochene, sehr lange Anzeigenamen). */
  .bb-hub-header { padding: 8px 12px; gap: 6px; }
  .bb-ladder-row,
  .bb-recent-row { padding: 2px; }

  /* Fix CL1: der Peilring ist im Hochformat kleiner — gestapelt ist die Hoehe knapp
     (gemessenes Budget aus CJ1: 676 von 700 verfuegbaren Buehnen-px bei vollen Listen),
     ein 200px-Ring wuerde sie sprengen. */
  .bb-search-zone { gap: 16px; }
  .bb-ring { width: 132px; height: 132px; }
  .bb-search-side { width: auto; max-width: 220px; gap: 5px; }
  .bb-hub-content .bb-hub-back { padding: 5px 18px; }

  .bb-hub-content {
    order: 2;
    flex: 0 0 auto;
    padding-top: 6px;
  }
  /* Gestapelt wachsen die Listen mit ihrem Inhalt statt eine feste Bandhoehe zu fuellen. */
  .bb-ladder-list,
  .bb-recent-list { flex: 0 0 auto; overflow: visible; }
}

/* ═══════════════════════════════════════════════════
   9. VANGUARD SCREEN
   ═══════════════════════════════════════════════════ */

/* NEW: Vanguard-Layout (2026-05-01) */
#screen-vanguard {
  align-items: center;
  justify-content: flex-start;
  flex-direction: column;
  gap: 14px;
  padding: 28px 36px;
  overflow: hidden;
}

.vanguard-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 20px;
  font-weight: 700;
  color: #33cccc;
  letter-spacing: 5px;
}

.vanguard-info {
  font-size: 12px;
  color: rgba(51, 204, 204, 0.45);
  letter-spacing: 1px;
  font-family: 'Rajdhani', sans-serif;
}

.vanguard-vp-meter {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  max-width: 580px;
}

.vanguard-vp-bar-wrap {
  flex: 1;
  height: 5px;
  background: rgba(51, 204, 204, 0.09);
  border-radius: 3px;
  overflow: hidden;
}

/* NEW: vg-vp-bar hat class vanguard-vp-bar-fill — JS setzt width per style */
.vanguard-vp-bar-fill {
  height: 100%;
  background: #33cccc;
  border-radius: 3px;
  transition: width 0.3s;
  box-shadow: 0 0 5px rgba(51, 204, 204, 0.4);
}

.vanguard-vp-label {
  font-size: 12px;
  color: rgba(51, 204, 204, 0.55);
  font-family: 'Share Tech Mono', monospace;
  flex-shrink: 0;
  min-width: 46px;
  text-align: right;
}

/* FIX: Vanguard-Grid aus game-v2.css — 4-Spalten-Grid statt flex-wrap (2026-05-01) */
.vanguard-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  max-height: 58vh;
  overflow-y: auto;
  padding: 8px;
}

.vanguard-hand-preview { display: flex; gap: 7px; padding: 6px; }

/* Buttons (Vanguard + Gameover) */
.btn-game {
  background: rgba(10, 22, 40, 0.82);
  border: 1px solid rgba(51, 204, 204, 0.27);
  border-radius: 5px;
  padding: 11px 26px;
  font-size: 13px;
  color: rgba(51, 204, 204, 0.75);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 2px;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-game:hover:not(:disabled) {
  background: rgba(51, 204, 204, 0.1);
  border-color: #33cccc;
  color: #33cccc;
}

.btn-game:disabled { opacity: 0.3; cursor: not-allowed; }

.btn-primary {
  background: rgba(18, 55, 18, 0.7);
  border-color: rgba(80, 200, 80, 0.38);
  color: rgba(120, 215, 120, 0.82);
}

.btn-primary:hover:not(:disabled) {
  background: rgba(22, 68, 22, 0.88);
  border-color: rgba(100, 240, 100, 0.58);
  color: #9eff9e;
}

.btn-ghost {
  background: transparent;
  border-color: rgba(51, 204, 204, 0.13);
  color: rgba(51, 204, 204, 0.4);
  font-size: 11px;
}

.btn-sm { padding: 7px 16px; font-size: 11px; }

/* Fix K2 (Section 6): moderner Sci-Fi-Chamfer-Stil (Design-Sprache aus der Lobby, s.
   .menu-btn oben — angeschraegte Ecken via clip-path) + auffaelliges pulsierendes Leuchten,
   SOLANGE eine Eingabe vom Spieler erwartet wird (pa.waitingFor === eigene Fraktion — NIE
   isMyTurn, s. renderCombatActions()/renderInlineDodge() in game-combat.js: diese Buttons
   werden ohnehin nur gerendert, wenn genau das zutrifft, die Klasse braucht daher keine
   eigene Bedingung). Gilt fuer Pass, Got-Ya-/Interrupt-Fenster-Buttons und die Dodge-
   Entscheidungs-Buttons. Groesser als .btn-game (Messe-Tauglichkeit: min-height 44px). */
/* UMBAU Z1 (2026-08-13): .sq-cb-pulse-btn/.sq-cb-pulse-btn.btn-ghost + die
   Ghost-Variante sqCbPulseGlowGhost waren AUSSCHLIESSLICH die grüne Knopfspalte
   (#combat-action-btns, entfernt) — gelöscht. sqCbPulseGlow bleibt: wird weiterhin
   von #cb-phase-status.sq-waiting-glow genutzt (s. unten). */
@keyframes sqCbPulseGlow {
  0%, 100% { box-shadow: 0 0 8px rgba(100, 230, 140, 0.35), inset 0 0 8px rgba(100,230,140,0.08); border-color: rgba(120, 240, 140, 0.5); }
  50%      { box-shadow: 0 0 20px rgba(120, 255, 160, 0.75), inset 0 0 14px rgba(120,255,160,0.18); border-color: rgba(150, 255, 180, 0.95); }
}

/* Fix K2 (Section 6): cb-phase-status bekommt den gleichen modernen Puls-Rahmen, wenn
   "Du bist dran" gilt (pa.waitingFor === myFaction — s. renderCombatPhaseStatus()). Pendant
   zu ov-phase-status in K3 (gleiche Komponente/CSS, hier fuer Combat). */
#cb-phase-status.sq-waiting-glow {
  animation: sqCbPulseGlow 1.6s ease-in-out infinite;
  border-width: 1px;
  border-style: solid;
}

/* FIX K3 (Section 6): ov-phase-status bekommt DIESELBE Puls-Rahmen-Komponente
   (identischer Mechanismus/Klassenname .sq-waiting-glow, identisches Timing 1.6s
   ease-in-out infinite, identische box-shadow/border-color-Puls-Struktur wie
   sqCbPulseGlow oben) — hier aber zusätzlich farbcodiert nach Fraktions-/HUD-Schema
   (game-hud-frame.js self/enemy: #4dd0e1/#ff5c5c), weil die Overview (anders als das
   kurze Combat-Fenster) laengere Zeit sichtbar ist und "wessen Zug/Eingabe gerade
   erwartet wird" durchgehend erkennbar sein soll. Eigener Farbsatz nur ueber die
   ID-spezifische Selektor-Kaskade (#ov-phase-status.sq-waiting-glow) — cb-phase-status
   und .sq-cb-pulse-btn oben bleiben dadurch unveraendert gruen (kein Regressionsrisiko
   für die bereits verifizierten K2-Komponenten). */
#ov-phase-status.sq-waiting-glow {
  animation: sqOvPulseGlowSelf 1.6s ease-in-out infinite;
  border-width: 1px;
  border-style: solid;
}
#ov-phase-status.sq-waiting-glow-enemy {
  animation: sqOvPulseGlowEnemy 1.6s ease-in-out infinite;
  border-width: 1px;
  border-style: solid;
}
@keyframes sqOvPulseGlowSelf {
  0%, 100% { box-shadow: 0 0 8px rgba(77,208,225,0.35), inset 0 0 8px rgba(77,208,225,0.08); border-color: rgba(77,208,225,0.5); }
  50%      { box-shadow: 0 0 20px rgba(120,225,240,0.75), inset 0 0 14px rgba(120,225,240,0.18); border-color: rgba(150,235,245,0.95); }
}
@keyframes sqOvPulseGlowEnemy {
  0%, 100% { box-shadow: 0 0 8px rgba(255,92,92,0.3), inset 0 0 8px rgba(255,92,92,0.08); border-color: rgba(255,92,92,0.45); }
  50%      { box-shadow: 0 0 18px rgba(255,120,120,0.6), inset 0 0 12px rgba(255,120,120,0.16); border-color: rgba(255,140,140,0.8); }
}

/* ═══════════════════════════════════════════════════
   10. OVERVIEW + COMBAT SCREENS
   game-overview.js / game-combat.js setzen
   screen.style.cssText = "position:fixed;display:grid;..."
   CSS hier ist nur Basis fuer den Fall vor dem ersten Render.
   ═══════════════════════════════════════════════════ */

/* NEW: Overview + Combat Basis (2026-05-01) */
/* FIX: screen-overview overflow:visible damit schwebender Hauptbutton sichtbar (2026-05-01) */
#screen-overview {
  overflow: visible;
}
#screen-combat {
  overflow: hidden;
}

/* ═══════════════════════════════════════════════════
   11. GAMEOVER SCREEN
   ═══════════════════════════════════════════════════ */

/* NEW: Gameover-Layout (2026-05-01) */
#screen-gameover {
  align-items: center;
  justify-content: center;
  gap: 16px;
  background: radial-gradient(ellipse at 50% 40%, rgba(18, 28, 55, 0.9) 0%, rgba(4, 7, 14, 0.97) 70%);
}

.gameover-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 56px;
  font-weight: 900;
  letter-spacing: 10px;
  text-transform: uppercase;
}

.gameover-title.victory { color: var(--gold); text-shadow: 0 0 28px rgba(240, 160, 0, 0.38); }
.gameover-title.defeat  { color: var(--vs);   text-shadow: 0 0 28px rgba(224, 32, 32, 0.3); }

.gameover-subtitle {
  font-size: 18px;
  color: rgba(51, 204, 204, 0.6);
  letter-spacing: 3px;
  font-family: 'Share Tech Mono', monospace;
}

.gameover-stats {
  display: flex;
  gap: 26px;
}

.gameover-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.stat-val {
  font-size: 26px;
  color: #33cccc;
  font-weight: 600;
  font-family: 'Share Tech Mono', monospace;
}

.stat-label {
  font-size: 10px;
  color: rgba(51, 204, 204, 0.38);
  letter-spacing: 2px;
  font-family: 'Share Tech Mono', monospace;
}

/* ═══════════════════════════════════════════════════
   12. KARTEN (Hand + Spielfeld)
   ═══════════════════════════════════════════════════ */

/* NEW: Hand-Karten (2026-05-01) */
.hand-card {
  width: var(--sq-card-w, 44px);
  height: var(--sq-card-h, 62px);
  background: linear-gradient(155deg, #0d1e36, #162e50);
  border: 1px solid rgba(51, 204, 204, 0.22);
  border-radius: 4px;
  cursor: pointer;
  transition: transform 0.12s, border-color 0.12s;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
}

.hand-card:hover {
  transform: translateY(var(--sq-card-lift, -10px));
  border-color: rgba(51, 204, 204, 0.55);
}

.hand-card.selected {
  transform: translateY(var(--sq-card-lift, -10px)) scale(1.04);
  border-color: var(--gold);
  box-shadow: 0 0 9px rgba(240, 160, 0, 0.28);
}

/* FIX G2 (2026-07-15): Kampf-Auswahl-Feedback fuer zielbare Aktionskarten (Salvo) —
   dieselben Gold-Werte wie .hand-card.selected oben (Haupt-Phase-Auswahl), aber ueber
   filter:drop-shadow statt border/box-shadow: .combat-hand-card setzt Rotation/Lift bereits
   per Inline-Transform (public/js/game-combat.js renderCombatHand()), eine zweite Quelle für
   dieselbe CSS-Property wuerde die Rotation ueberschreiben statt sie zu ergaenzen. Die
   Border-Farbe der inneren Karten-Box wird dafuer direkt im Template gesetzt (kein Inline-
   Styles-Fight noetig, da dort ohnehin schon Inline-Styles verwendet werden). */
.combat-hand-card.selected {
  filter: drop-shadow(0 0 10px var(--gold-glow));
}

/* Fix AZ1: spielbare Aktionskarte in der Hand waehrend offer_action_card — vorher
   keinerlei Einladungs-Optik auf der Hand-Karte selbst (nur Feldkarten pulsierten,
   s. Bericht Abschnitt 1b). Reuse derselben activeAttackerAnim-Keyframe wie die
   Feldkarten-Pulse-Faelle (box-shadow-only, kollidiert nicht mit dem Inline-Transform
   dieser Karte). .sq-hand-card-playable bleibt als statischer Rahmen stehen, auch wenn
   .sq-hand-card-pulse (Puls-Klasse) nach dem ersten Klick in diesem Zustand entfaellt. */
.combat-hand-card.sq-hand-card-playable {
  outline: 2px solid #f0b429;
  outline-offset: 2px;
  border-radius: 4px;
}
.combat-hand-card.sq-hand-card-pulse {
  animation: activeAttackerAnim 1.6s ease-in-out infinite;
}

/* FIX K6 (2026-07-23): kleines Hinweisdetail auf im Kampf nicht spielbaren
   Schiffskarten der Hand (jetzt volle Deckkraft + grayscale/brightness-Filter statt
   Transparenz, s. renderCombatHand()) — macht "nicht spielbar" eindeutig, ohne wie
   eine Layering-/Transparenz-Verwechslung zu wirken. */
.sq-hand-locked-hint {
  position: absolute;
  bottom: 3px;
  right: 3px;
  font-size: 11px;
  opacity: 0.7;
  z-index: 4;
  pointer-events: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9);
}

.hand-card canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 3px;
}

/* Schiff-Token im Spielfeld */
/* Fix CQ1 (Punkt 5, 2026-08-21): die Basisklasse setzte hier `cursor: pointer` und
   erzwang den Zeigefinger damit fuer JEDES Schiffs-Token — auch ueber Karten, an denen
   makeCombatTok() bewusst KEIN clickFn vergibt (gemeldeter Fall: Unterbrechungsfenster;
   die interrupt_window-Markierung ist absichtlich klicklos, s. Fix BA1). Nicht global
   umgestellt: der Zeigefinger haengt jetzt an der Klasse `.clickable`, die
   makeCombatTok() (game-combat.js, `fullClass`) exakt dann vergibt, wenn auch
   `tok.onclick = clickFn` gesetzt wird — dieselbe Bedingung, eine Quelle. Klickbare
   Token behalten den Zeigefinger unveraendert (zusaetzlich schreibt renderShipCard()
   fuer opts.clickable=true weiterhin ein Inline-`cursor:pointer`, beide Wege stimmen
   ueberein). */
.ship-tok-combat {
  width: var(--sq-ship-sz, 40px);
  height: var(--sq-ship-h, 54px);
  border: 1px solid rgba(51, 204, 204, 0.22);
  border-radius: 4px;
  cursor: default;
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, #0d1e36, #0a1626);
  transition: border-color 0.12s, box-shadow 0.12s;
  display: flex;
  flex-direction: column;
}
.ship-tok-combat.clickable { cursor: pointer; }

.ship-tok-combat.VS  { border-color: rgba(224, 32, 32, 0.38); }
.ship-tok-combat.UED { border-color: rgba(0, 192, 80, 0.38); }

/* FIX (2026-07-08): Wingman-Paar — dezente Kennzeichnung statt Gold-Rahmen.
   Gold ist jetzt exklusiv "am Zug" (.active-attacker); Wingmen bekommen einen
   schmalen silbernen Rahmen + kleines Ketten-Badge an der Ecke. */
.ship-tok-combat.wingman-badge {
  border-color: rgba(200, 205, 215, 0.55);
  box-shadow: none;
}
.ship-tok-combat.wingman-badge::after {
  content: '⛓';
  position: absolute;
  top: 2px;
  right: 2px;
  width: 13px;
  height: 13px;
  line-height: 13px;
  text-align: center;
  font-size: 9px;
  color: rgba(210, 214, 224, 0.9);
  background: rgba(20, 22, 30, 0.65);
  border-radius: 50%;
  pointer-events: none;
}

/* UMBAU Z1 (2026-08-13, Abschnitt 4 "was angeklickt werden muss, zeigt sich als
   anklickbar"): war bisher statischer Rahmen — jetzt pulsierend, reuse der
   bestehenden activeAttackerAnim-Keyframe (s. weiter unten, ".active-attacker" =
   "du bist dran") statt einer neuen Animation. .sq-targetable (Angriffsziel,
   choose_target) bleibt bewusst ROT-pulsierend und eigenständig (spätere Regel,
   gleiche Spezifität, überschreibt border-color/box-shadow/animation vollständig)
   — Rot=Angriffsziel vs. Gold=eigene Auswahl (Wingman/Aktionskarte/Init-Reihenfolge)
   ist eine bereits etablierte, bewusste Farbunterscheidung, hier nicht angetastet. */
.ship-tok-combat.target-selectable {
  border-color: var(--gold);
  box-shadow: 0 0 9px rgba(240, 160, 0, 0.32);
  cursor: crosshair;
  animation: activeAttackerAnim 1.6s ease-in-out infinite;
}

/* Fix K4 (Wingman-Flow, Teil A): "gewaehlt"-Zustand fuer die guided Wingman-Zuweisung.
   Bewusst NEU und optisch von .target-selectable oben (duenner STATISCHER Gold-Rahmen =
   "das hier ist klickbar") UND von .active-attacker weiter unten (PULSIERENDER Gold-
   Outline mit Lift = "du bist dran") unterschieden: dicker durchgehender Gold-Rahmen +
   Innen-Glow, KEINE Animation ("bereits eingerastet/gewaehlt", im Gegensatz zu "wartet
   auf deine Eingabe"). Gilt fuer die lokal (noch unbestaetigt) gewaehlte Wingman-Karte
   (Schritt 2/3) und die lokal gewaehlte Schutzziel-Karte (Schritt 3), s. makeCombatTok(). */
.ship-tok-combat.sq-wingman-chosen {
  border: 2px solid var(--gold);
  box-shadow: inset 0 0 12px rgba(240, 160, 0, 0.35), 0 0 10px rgba(240, 160, 0, 0.55);
  cursor: pointer;
}
.sq-wingman-choice-badge {
  position: absolute;
  top: 2px;
  left: 2px;
  font-family: 'Orbitron', monospace;
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: #1a1200;
  background: var(--gold);
  padding: 2px 4px;
  border-radius: 2px;
  pointer-events: none;
  z-index: 3;
  white-space: nowrap;
}

/* Fix K2 (Bug 1, Gleiche-INI-Gegenschlag-Ausnahme): Karte bleibt trotz currentHp<=0
   sichtbar, bekommt aber einen deutlichen "ZERSTÖRT"-Marker + gedaempften Rahmen, damit
   sie nicht faelschlich lebendig wirkt, bis ihr Konter abgespielt ist. */
.ship-tok-combat.ship-tapped-destroyed {
  border-color: rgba(120, 40, 30, 0.6);
  filter: grayscale(0.4);
}
.ship-tapped-destroyed-badge {
  position: absolute;
  inset: auto 0 0 0;
  text-align: center;
  font-family: 'Orbitron', monospace;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: #ffb3a8;
  background: rgba(120, 20, 10, 0.78);
  padding: 2px 0;
  pointer-events: none;
  z-index: 2;
}

/* FIX (Feature 2026-07-08): Rot-Pulsieren für gültige Angriffsziele während choose_target —
   überschreibt den statischen Gold-Rahmen von .target-selectable oben (gleiche Spezifität,
   spätere Regel gewinnt). Klasse wird bei jedem Render neu vergeben (siehe renderCombatShips),
   kann also nie hängenbleiben. */
@keyframes sqTargetablePulse {
  0%, 100% { border-color: rgba(255, 70, 51, 0.55); box-shadow: 0 0 8px rgba(255, 70, 51, 0.35); }
  50%      { border-color: rgba(255, 70, 51, 0.95); box-shadow: 0 0 16px rgba(255, 70, 51, 0.7); }
}
.ship-tok-combat.sq-targetable {
  animation: sqTargetablePulse 1s ease-in-out infinite;
  cursor: crosshair;
}

/* Fix K2 (Section 2, Angriffs-Ziel markieren): Ziel-Highlight fuer den AKTIVEN Angriff
   (combat.currentAttack), unabhaengig davon ob man selbst gerade waehlt — sichtbar fuer
   BEIDE Seiten, Combat-View UND Overview (game-overview.js renderShipsInto()). Bewusst
   dieselbe Puls-Keyframe-Familie wie .sq-targetable (rote Zielwahl), aber eigene Klasse:
   .sq-targetable ist an Klick-Eligibility/Hover gebunden, dieses hier ist reiner
   Anzeige-State ohne Cursor-/Klick-Semantik.
   Aufraeumen: Klasse wird bei JEDEM Render neu vergeben (nie manuell entfernt), kann also
   nie "stehen bleiben" — s. renderCombatShips()/renderShipsInto(). */
.ship-tok-combat.sq-active-attack-target,
.ship-tok-v2.sq-active-attack-target {
  animation: sqTargetablePulse 0.9s ease-in-out infinite;
  box-shadow: 0 0 10px rgba(255, 70, 51, 0.5);
}

/* FIX J1 (Fleetzone-Burn "Vollversions-Regel"): dezente Puls-Hervorhebung fuer eigene
   Fleetzone-Squads, wenn die Burn-Bedingung erfuellt ist (canFleetzoneBurn(),
   game-combat.js). Bewusst ruhiger/langsamer als sqTargetablePulse (Kampf-Zielwahl) —
   das hier ist eine "du KANNST"-Option in der Main Phase, kein dringliches Angriffsziel. */
@keyframes sqFleetzoneBurnPulse {
  0%, 100% { border-color: var(--gold); box-shadow: 0 0 6px rgba(240, 190, 60, 0.35); }
  50%      { border-color: rgba(255, 215, 110, 0.95); box-shadow: 0 0 14px rgba(255, 215, 110, 0.6); }
}
.ship-tok-v2.fleetzone-burn-eligible {
  animation: sqFleetzoneBurnPulse 1.8s ease-in-out infinite;
  cursor: pointer;
}

/* Fix AZ1 (Betreiber-Vorgabe 2, "pulsiert bis einmal geklickt, danach ruhig"):
   Modifier-Klasse statt eigener Animation — schaltet die jeweils zutreffende Puls-
   Keyframe ab, Rahmen/Glow der Basisklasse (.target-selectable/.fleetzone-burn-eligible)
   bleiben stehen (Markierung verschwindet nicht, s. Betreiber-Vorgabe "nicht
   verschwinden"). Muss NACH allen drei Pulse-Regeln oben stehen (.target-selectable,
   .sq-targetable, .fleetzone-burn-eligible) und pro Kombination eine zusaetzliche Klasse
   mehr tragen als die jeweilige Basisregel, um sie per Spezifitaet sicher zu schlagen,
   unabhaengig von der Dateireihenfolge — kein !important noetig. Gesetzt von
   game-combat.js (_sqPulseCalmed()) und game-overview.js (dieselben Helfer,
   modulweit global). */
.ship-tok-combat.target-selectable.sq-pulse-calmed,
.ship-tok-combat.sq-targetable.sq-pulse-calmed,
.ship-tok-v2.target-selectable.sq-pulse-calmed {
  animation: none;
}
.ship-tok-v2.fleetzone-burn-eligible.sq-pulse-calmed {
  animation: none;
}

/* Targeting-Pfeil-Overlay (Feature 2026-07-08) */
#sq-target-arrow-svg.sq-arrow-flash #sq-target-arrow-path {
  stroke: #ffffff !important;
  filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.95)) !important;
  transition: stroke 80ms ease-out, filter 80ms ease-out;
}

/* NEW (Runde 3, Teil 3.4): VS-Laser — DOM/CSS statt Canvas (fireLaserBeamDOM,
   game-anim-combat.js). Kind von #cb-location, erbt dessen LayoutEngine-Transform.
   Timing: ~120ms Aufleuchten -> ~180ms halten -> ~150ms ausblenden. */
.sq-laser-beam {
  position: absolute;
  height: 4px;
  transform-origin: 0 50%;
  border-radius: 2px;
  pointer-events: none;
  z-index: 102;
  background: linear-gradient(to bottom, #ff4633, #ff8c7a, #ff4633);
  box-shadow: 0 0 10px 2px rgba(255, 70, 51, 0.6);
  opacity: 0;
  transition: opacity 120ms ease-in;
}
.sq-laser-beam-on { opacity: 1; }
.sq-laser-beam-out { opacity: 0; transition: opacity 150ms ease-out; }

/* FIX BL1 (Etappe 2b, Baustein "Schuss zieht vorbei"): Ausweich-Fehlschuss bekommt ein
   eigenes, aus FX_DURATIONS.DODGE_SHOT_PASS_MS abgeleitetes Timing (0.55/0.45-Aufteilung
   Aufleuchten/Ausblenden, identisch zur JS-Berechnung in fireLaserBeamDOM(), game-anim-
   combat.js) statt des kurzen Standard-Treffer-Timings direkt oberhalb. Beschleunigtes
   Aufleuchten (ANSPANNUNG-Kurve) statt des generischen ease-in. NUR aktiv bei .sq-laser-
   beam-dodge-miss — der normale Treffer-Laser bleibt unverändert (s. Audit-Fund BK1/BL1:
   dieser Selektor selbst ist noch nicht Teil der FX_DURATIONS-Konsolidierung, s. Bericht). */
.sq-laser-beam-dodge-miss {
  transition: opacity var(--sq-fx-dodge-shot-pass-ms) var(--sq-fx-ease-anspannung);
}
.sq-laser-beam-dodge-miss.sq-laser-beam-out {
  transition: opacity calc(var(--sq-fx-dodge-shot-pass-ms) * 0.45) ease-out;
}

/* FIX BM1: die vorherigen #sq-combat-bar-top/-bottom-Kinobalken (Fix BL1) standen hier —
   ersatzlos entfernt (CLAUDE.md-Regel "Dead Code immer entfernen"). Root Cause + Ersatz
   (heute: Variante A, "Zoom auf den Ort", beide Richtungen) s. Kommentar bei
   _sqCombatAUebergang() in public/js/game-anim-combat.js — die zugehörigen
   .sq-combat-a-*-Klassen stehen dort (JS-injiziertes Stylesheet, wie schon die Balken es
   waren), nicht hier. */

/* FIX I2 (Mockup 1): Salvo-Doppelstrahl — eigene Farbvariante des VS-Laser-Strahls
   (fireSalvoBeamsDOM, game-anim-combat.js), sonst identische Technik/Timing. Magenta-
   Rot statt reinem VS-Rot, damit Salvo optisch als eigener, top-down kommender Effekt
   erkennbar bleibt und nicht mit einem normalen VS-Schuss verwechselt wird. */
.sq-salvo-beam {
  background: linear-gradient(to bottom, #ff0044, #ff6a3d, #ff0044);
  box-shadow: 0 0 10px 2px rgba(255, 0, 68, 0.6);
}

.tok { width: 100%; height: 100%; position: relative; overflow: hidden; }
.tok-art { width: 100%; height: 100%; object-fit: cover; opacity: 0.82; }

.dodge-arrow     { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.dodge-mini-card { width: var(--sq-cb-w, 50px); height: var(--sq-cb-h, 68px); border-radius: 4px; overflow: hidden; }
.dodge-ships-row { display: flex; gap: 5px; align-items: center; }

/* ═══════════════════════════════════════════════════
   13. GLOBALE OVERLAYS (fixed, ausserhalb Scale-Root)
   ═══════════════════════════════════════════════════ */

/* NEW: Toast (2026-05-01) */
#toast {
  position: fixed;
  bottom: 22px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  pointer-events: none;
}

.toast-msg {
  background: rgba(6, 12, 24, 0.93);
  border: 1px solid rgba(51, 204, 204, 0.26);
  border-radius: 6px;
  padding: 9px 20px;
  font-size: 12px;
  color: var(--text-primary);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  animation: toast-in 0.22s ease;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(7px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Card Reveal (KARTE GEZOGEN): Layout+Animation kommen jetzt vollständig aus dem
   HUD-Frame-System (game-hud-frame.js injectHudFrameStyles(), Fix I1) — hier bewusst
   keine Regeln mehr, um Doppel-/Kollisions-Deklarationen zu vermeiden. */

/* NEW: Card Tooltip (2026-05-01) */
#card-tooltip {
  position: fixed;
  z-index: 800;
  pointer-events: none;
  filter: drop-shadow(0 4px 14px rgba(0, 0, 0, 0.88));
}

#card-tooltip-inner {
  background: rgba(5, 10, 22, 0.97);
  border: 1px solid rgba(51, 204, 204, 0.2);
  border-radius: 7px;
  padding: 9px;
  max-width: 230px;
  font-size: 11px;
  color: var(--text-primary);
  font-family: 'Rajdhani', sans-serif;
  line-height: 1.5;
}

/* NEW: Selection Hint (2026-05-01) */
/* Fix CW1 (2026-08-22): der frueher hier stehende #selection-hint-Block ist entfallen.
   Er hielt die Leiste per position:fixed + translateX(-50%) unten mittig fest und hat als
   ID-Selektor die neue .sq-hint-bar-Klasse still ueberstimmt — gemessen im ersten Lauf von
   scripts/verify-cw1-banner.js: die Leiste sass exakt eine halbe Zonenbreite zu weit links,
   weil translateX(-50%) weiterhin griff. Die Optik der Hinweisleiste steht jetzt
   ausschliesslich in .sq-hint-bar (weiter oben), ihre Position kommt allein aus
   _sqPlaceSelectionHint() (game-combat.js). */

/* NEW: Modals (2026-05-01) */
/* FIX G4 (2026-07-15): #modal-deckviewer aus dieser geteilten Regel entfernt — der
   `> div`-Kind-Selektor traf ungewollt BEIDE direkten Divs (Panel UND den davor
   liegenden Backdrop-Klick-Fänger), das Deckviewer-Modal verwaltet Panel-Optik jetzt
   vollständig über `.deckviewer-panel` + Inline-Style. Fleetzone/Wingman unangetastet. */
#modal-fleetzone {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  z-index: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

#modal-fleetzone > div {
  background: #0a1220;
  border: 1px solid rgba(51, 204, 204, 0.2);
  border-radius: 9px;
  padding: 16px;
  max-width: 640px;
  max-height: 82vh;
  overflow-y: auto;
  width: 90%;
}

/* FIX (Friedhof-Fix 2026-07-08): eigenes, eigenständiges Panel statt geteiltem
   Balken-Layout mit dem Deckviewer/Fleetzone/Wingman-Block oben — der leere Zustand
   kollabierte dort auf eine einzeilige Höhe bei 90%-Breite ("bildschirmbreiter
   flacher Balken", Marcel-Screenshot). min-height + flex-column hält das Panel
   kompakt-quadratisch statt breit-flach, auch wenn der Friedhof leer ist. */
.sq-graveyard-modal {
  position: fixed;
  inset: 0;
  z-index: 9900;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sq-graveyard-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  cursor: pointer;
}
.sq-graveyard-panel {
  position: relative;
  background: rgba(10, 14, 26, 0.95);
  border: 1px solid rgba(139, 147, 168, 0.3);
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  max-width: 520px;
  max-height: 60vh;
  min-height: 160px;
  width: 90vw;
  padding: 20px 24px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.sq-graveyard-close {
  position: absolute;
  top: 8px;
  right: 12px;
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.55);
  font-size: 22px;
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}
.sq-graveyard-header {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  font-family: 'Orbitron', sans-serif;
  font-size: 14px;
  letter-spacing: 2px;
  color: #f0b429;
  margin-bottom: 14px;
  flex-shrink: 0;
}
.sq-graveyard-count {
  font-size: 11px;
  letter-spacing: 1px;
  color: rgba(240, 180, 41, 0.6);
  font-family: 'Share Tech Mono', monospace;
}
#graveyard-content {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  justify-content: center;
  align-content: center;
  flex: 1;
}
.sq-graveyard-empty {
  margin: auto;
  font-size: 12px;
  color: var(--text-dim);
  font-style: italic;
}

/* FIX (Aufgeben/Optionen-Modal, 2026-07-12): mirrors .sq-graveyard-* geometry/z-index,
   eigene Klassen fuer Sound-Sektion + Match/Aufgeben-Sektion. */
.sq-options-modal {
  position: fixed;
  inset: 0;
  z-index: 9900;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sq-options-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  cursor: pointer;
}
.sq-options-panel {
  position: relative;
  background: rgba(10, 14, 26, 0.95);
  border: 1px solid rgba(139, 147, 168, 0.3);
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  max-width: 360px;
  min-height: 160px;
  width: 90vw;
  padding: 20px 24px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.sq-options-close {
  position: absolute;
  top: 8px;
  right: 12px;
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.55);
  font-size: 22px;
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}
.sq-options-header {
  text-align: center;
  font-family: 'Orbitron', sans-serif;
  font-size: 14px;
  letter-spacing: 2px;
  color: #f0b429;
  flex-shrink: 0;
}
.sq-options-section-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 11px;
  letter-spacing: 2px;
  color: rgba(51, 204, 204, 0.75);
  text-transform: uppercase;
  margin-bottom: 8px;
}
.sq-options-surrender-btn {
  width: 100%;
  padding: 10px;
  border-radius: 4px;
  border: 1px solid #e24b4a;
  background: rgba(226, 75, 74, 0.06);
  color: #e24b4a;
  font-family: 'Orbitron', sans-serif;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  text-align: center;
}
.sq-options-surrender-btn:disabled {
  cursor: not-allowed;
}
.sq-options-confirm-text {
  font-size: 12px;
  color: var(--text-dim);
  text-align: center;
  margin-bottom: 10px;
}
.sq-options-confirm-actions {
  display: flex;
  gap: 8px;
}
.sq-options-confirm-yes,
.sq-options-confirm-cancel {
  flex: 1;
  padding: 8px;
  border-radius: 4px;
  font-family: 'Orbitron', sans-serif;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
}
.sq-options-confirm-yes {
  border: 1px solid #e24b4a;
  background: rgba(226, 75, 74, 0.12);
  color: #e24b4a;
}
.sq-options-confirm-cancel {
  border: 1px solid rgba(139, 147, 168, 0.3);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-dim);
}

/* Fix F5 (Steam-Shell v1.0.2): Anzeige-Sektion (Fenstermodi) — nur im Options-Modal
   sichtbar, wenn window.SteamShell.available (s. game-options-modal.js). */
.sq-options-display-modes {
  display: flex;
  gap: 6px;
}
.sq-options-mode-btn {
  flex: 1;
  padding: 8px 4px;
  border-radius: 4px;
  border: 1px solid rgba(51, 204, 204, 0.25);
  background: rgba(51, 204, 204, 0.04);
  color: rgba(51, 204, 204, 0.6);
  font-family: 'Orbitron', sans-serif;
  font-size: 10px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  cursor: pointer;
  text-align: center;
}
.sq-options-mode-btn:hover {
  border-color: rgba(51, 204, 204, 0.5);
  color: #33cccc;
}
.sq-options-mode-btn.active {
  border-color: #33cccc;
  background: rgba(51, 204, 204, 0.18);
  color: #33cccc;
}

/* Fix AT1: Chat-Panel — angedockt statt Vollbild-Modal (Backdrop wie bei Optionen/
   Friedhof wuerde das laufende Match dahinter verdecken, s. views/play-v3.ejs-Kommentar
   ueber #modal-chat). Sitzt unten rechts, oberhalb von Toast/Icon-Leiste. */
.sq-chat-panel {
  position: fixed;
  right: 16px;
  bottom: 20px;
  z-index: 9800;
  width: min(320px, calc(100vw - 32px));
  max-height: min(420px, calc(100vh - 100px));
  /* FIX AU1 (2026-08-18): 100dvh statt 100vh — auf Mobilgeraeten aendert die ein-/
     ausblendende Adressleiste die sichtbare Hoehe, 100vh bleibt dabei auf dem groessten
     Wert stehen (Panel kann unten abgeschnitten wirken). 100dvh folgt der tatsaechlich
     sichtbaren Hoehe. Deklaration bewusst NACH der 100vh-Zeile: Browser ohne dvh-Support
     ignorieren die ungueltige Deklaration und behalten den 100vh-Wert (Rueckfall, keine
     @supports-Abfrage noetig). */
  max-height: min(420px, calc(100dvh - 100px));
  background: rgba(10, 14, 26, 0.95);
  border: 1px solid rgba(139, 147, 168, 0.3);
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.sq-chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  font-family: 'Orbitron', sans-serif;
  font-size: 12px;
  letter-spacing: 1.5px;
  color: #f0b429;
  border-bottom: 1px solid rgba(139, 147, 168, 0.2);
  flex-shrink: 0;
}
.sq-chat-close {
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.55);
  font-size: 18px;
  cursor: pointer;
  line-height: 1;
  padding: 2px 4px;
}
.sq-chat-mute-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  font-size: 11px;
  color: var(--text-dim);
  border-bottom: 1px solid rgba(139, 147, 168, 0.12);
  cursor: pointer;
  flex-shrink: 0;
}
.sq-chat-history {
  flex: 1;
  min-height: 80px;
  overflow-y: auto;
  padding: 8px 10px;
  font-family: 'Rajdhani', sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-dim);
}
.sq-chat-history .chat-line {
  margin-bottom: 4px;
  word-break: break-word;
}
.sq-chat-history .chat-line .chat-line-name {
  font-weight: 700;
  margin-right: 4px;
}
.sq-chat-history .chat-line.chat-own .chat-line-name { color: #33cccc; }
.sq-chat-history .chat-line.chat-enemy .chat-line-name { color: #e24b4a; }
.sq-chat-history .chat-line.chat-pending { opacity: 0.55; }
.sq-chat-history .chat-line.chat-rejected .chat-line-msg {
  color: #e24b4a;
  text-decoration: line-through;
}
.sq-chat-panel.chat-mute-active .chat-line.chat-enemy { display: none; }
.sq-chat-muted-notice {
  padding: 4px 10px;
  font-size: 10px;
  color: rgba(226, 75, 74, 0.75);
  border-top: 1px solid rgba(139, 147, 168, 0.12);
  flex-shrink: 0;
}
.sq-chat-input-row {
  display: flex;
  gap: 6px;
  padding: 8px 10px;
  border-top: 1px solid rgba(139, 147, 168, 0.2);
  flex-shrink: 0;
}
.sq-chat-input {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  border-radius: 4px;
  border: 1px solid rgba(139, 147, 168, 0.3);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text, #e6edf3);
  font-family: 'Rajdhani', sans-serif;
  font-size: 12px;
}
.sq-chat-send-btn {
  padding: 6px 12px;
  border-radius: 4px;
  border: 1px solid #33cccc;
  background: rgba(51, 204, 204, 0.1);
  color: #33cccc;
  font-family: 'Orbitron', sans-serif;
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
}
.sq-chat-limit-hint {
  padding: 0 10px 6px;
  font-size: 10px;
  color: #f0b429;
  flex-shrink: 0;
}
/* Zaehler-Abzeichen am Chat-Icon (ov-chat-btn/cb-chat-btn) — Markup kommt aus
   _chatBadgeHTML() (game-chat.js), bei jedem Icon-Leisten-Render neu erzeugt. */
.chat-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 14px;
  height: 14px;
  padding: 0 3px;
  border-radius: 7px;
  background: #e24b4a;
  color: #fff;
  font-family: 'Share Tech Mono', monospace;
  font-size: 9px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}

#fleetzone-prompt-loc {
  font-size: 12px;
  color: rgba(51, 204, 204, 0.6);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  margin-bottom: 9px;
}

#fleetzone-prompt-ships {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

#wingman-instruction {
  font-size: 12px;
  color: rgba(51, 204, 204, 0.6);
  font-family: 'Rajdhani', sans-serif;
  margin-bottom: 10px;
  text-align: center;
  line-height: 1.5;
}

#wingman-ship-list {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  justify-content: center;
}

/* NEW: Wingman-Stacking V2-Ansatz — Guard oben rechts, Guard-2 oben links (2026-05-11 v3) */
/* Kopiert von game-v2.css, Farben für V3 angepasst (teal/gold statt lila) */
.wingman-stack {
  position: relative;
  display: inline-block;
  flex-shrink: 0;
  overflow: visible;
  vertical-align: top;
}
.wingman-protected {
  position: relative;
  z-index: 1;
  display: inline-block;
  box-shadow: 0 0 8px rgba(51, 204, 204, 0.35) !important;
}
/* Guard (erster Wingman) → oben rechts, überlappt Protected */
.wingman-guard {
  position: absolute;
  top: -50%;
  right: -50%;
  z-index: 2;
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.7));
  border: 2px solid rgba(51, 204, 204, 0.85) !important;
  border-radius: 4px;
}
/* Guard-2 (zweiter Wingman) → oben links, überlappt Protected */
/* FIX (Runde 2, Befund 2): war Gold (rgba(240,160,0,…)) — genau die Quelle des gemeldeten
   Gold-Rahmens auf Schwarm-Paaren (Doppel-Wingman-Pfad gilt auch für swarm+wingman-Schiffe,
   siehe canBeWm2Inline() in game-combat.js). Gold ist jetzt exklusiv "am Zug"
   (.active-attacker); Guard-2 bekommt dieselbe neutrale Farbe wie Guard (erster Wingman). */
.wingman-guard-2 {
  position: absolute;
  top: -50%;
  left: -50%;
  z-index: 3;
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.7));
  border: 2px solid rgba(51, 204, 204, 0.85) !important;
  border-radius: 4px;
}
.wingman-guard .ship-card-v3,
.wingman-guard-2 .ship-card-v3,
.wingman-protected .ship-card-v3 {
  display: block;
}

/* Wuerfel-Popup (Legacy) */
#modal-dice { display: none; }

/* ═══════════════════════════════════════════════════
   14. UTILITY KLASSEN (von JS gesetzt/gelesen)
   ═══════════════════════════════════════════════════ */

/* NEW: Utility-Klassen (2026-05-01) */
.hidden { display: none !important; }

/* NEW (Lobby-Anmelden-Fraktionswahl, 2026-07-12): Anmelden-Button-Teaser bei
   BACKBONE_ENABLED=false — sichtbar, aber ausgegraut ("Bald verfügbar"), kein toter Klick. */
.menu-btn-disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.menu-hint {
  display: block;
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--gold-dim, #a88a3a);
  margin-top: 2px;
}

.scroll-panel {
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-mid) transparent;
}

/* Alte Elemente aus play.ejs playtest-overrides ausblenden */
.gradient-frame-top,
.gradient-frame-bottom { display: none !important; }

#game-hud,
#tr-options,
.tr-options-area,
#speed-btn,
#mute-btn,
#fullscreen-btn { display: none !important; }

/* ═══════════════════════════════════════════════════
   15. ANIMATIONEN
   ═══════════════════════════════════════════════════ */

/* NEW: Animationen (2026-05-01) */
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes slideUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.42; }
}

@keyframes glow-pulse {
  0%, 100% { box-shadow: 0 0 7px rgba(51, 204, 204, 0.28); }
  50%       { box-shadow: 0 0 16px rgba(51, 204, 204, 0.6); }
}

.anim-fade-in  { animation: fadeIn 0.3s ease forwards; }
.anim-slide-up { animation: slideUp 0.28s ease forwards; }
.anim-pulse    { animation: pulse 1.4s ease infinite; }
.anim-dice-roll { animation: pulse 0.1s ease infinite; }
/* FIX F4 (Ausweich-Feedback, 2026-07-15): .anim-dodge (reines Fade-in) entfernt — ersetzt
   durch .sq-dodge-dash + .sq-dodge-ghost (game-anim-combat.js, dort injiziert). */
.anim-glow     { animation: glow-pulse 2s ease infinite; }

/* ═══════════════════════════════════════════════════
   NEW: LOBBY CSS — aus game-v2.css erzwungen (2026-05-01)
   Ueberschreibt fruehre Definitionen aus Phase 3.
   ═══════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════
   LOBBY REDESIGN — Hierarchical Menu
══════════════════════════════════════════════════════════════ */

@keyframes nebula-drift {
    0%   { transform: translate(0, 0) rotate(0deg); }
    25%  { transform: translate(30px, -20px) rotate(90deg); }
    50%  { transform: translate(-20px, 30px) rotate(180deg); }
    75%  { transform: translate(20px, 20px) rotate(270deg); }
    100% { transform: translate(0, 0) rotate(360deg); }
}


#lobby-ship-container {
    position: fixed; inset: 0; pointer-events: none; z-index: 1; overflow: hidden;
}
.flying-ship {
    position: absolute; font-size: 14px; color: rgba(255,255,255,0.4);
    filter: blur(0.5px); animation: ship-fly linear forwards;
}
@keyframes ship-fly {
    0%   { transform: translateX(-40px) translateY(0); opacity: 0; }
    5%   { opacity: 1; }
    95%  { opacity: 1; }
    100% { transform: translateX(calc(100vw + 40px)) translateY(-30px); opacity: 0; }
}

/* FIX: doppelter Lobby-Block entfernt (Session 1.4) — erste Definitionen ab Zeile ~485 gelten.
   Entfernt: .lobby-main (min-height:100vh — Killer), .lobby-header, .lobby-logo,
             .lobby-title (color:#f0a500 — Konflikt), .lobby-subtitle */

/* ─── Menu System ─── */
.menu-container {
    position: relative; width: 100%; max-width: 420px;
}
.menu-level {
    display: none; flex-direction: column; align-items: center; gap: 10px;
    animation: menu-fade-in 0.3s ease-out;
}
.menu-level.active { display: flex; }
@keyframes menu-fade-in {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Menu Buttons — Fix I1: Sci-Fi-Stil, EIN Button-Stil für die ganze Lobby (Hauptmenü +
   alle Untermenüs teilen sich .menu-btn). Angeschrägte Ecken oben-rechts/unten-links
   (clip-path-Chamfer), 3px Energie-Kante links, Tick-Markierung in der unbeschnittenen
   unten-rechts-Ecke, optionale Unterzeile (.menu-btn-sub) via Flex-Wrap+flex-basis:100%
   (kein Markup-Umbau bei Buttons ohne Unterzeile nötig — Pfeil/Text/Tutorial-Häkchen
   bleiben normale Inline-Flex-Items auf derselben Zeile). */
.menu-btn {
    --mb-chamfer: 16px;
    --mb-edge: rgba(139, 147, 168, 0.35);
    background: rgba(10, 13, 22, 0.55);
    border: none; border-left: 3px solid var(--mb-edge);
    clip-path: polygon(0 0, calc(100% - var(--mb-chamfer)) 0, 100% var(--mb-chamfer),
                        100% 100%, var(--mb-chamfer) 100%, 0 calc(100% - var(--mb-chamfer)));
    color: #c0c4d4; font-family: 'Orbitron', monospace; font-size: 13px; font-weight: 600;
    letter-spacing: 0.1em; text-align: center; padding: 14px 20px; cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
    position: relative; width: 100%; max-width: 360px;
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    column-gap: 8px; row-gap: 3px;
}
.menu-btn::after {
    /* Tick-Markierung — kleine diagonale Kerbe in der unbeschnittenen unten-rechts-Ecke */
    content: ''; position: absolute; right: 7px; bottom: 8px;
    width: 9px; height: 2px; background: var(--mb-edge);
    transform: rotate(-45deg); transition: background 0.15s ease;
}
.menu-btn:hover {
    color: #67e8f9; border-left-color: #4dd0e1;
    text-shadow: 0 0 10px rgba(77,208,225,0.35);
    background: rgba(77,208,225,0.07);
}
.menu-btn:hover::after { background: #4dd0e1; }
.menu-btn:active { transform: scale(0.98); }
.menu-btn-sub {
    flex-basis: 100%;
    font-family: 'Rajdhani', sans-serif; font-size: 10px; font-weight: 500;
    letter-spacing: 0.06em; text-transform: none; color: rgba(192,196,212,0.45);
}
.menu-btn:hover .menu-btn-sub { color: rgba(103,232,249,0.6); }
.menu-arrow { color: #4dd0e1; font-size: 11px; }
.menu-btn:hover .menu-arrow { text-shadow: 0 0 8px rgba(77,208,225,0.6); }

/* Steam-Beenden — dezent abgesetzt, roter Energie-Kante/Hover als Gefahren-Hinweis
   (Fix F5, an neue Sci-Fi-Basis angepasst, Fix I1) */
.menu-btn-quit {
    margin-top: 18px; padding: 10px 20px; font-size: 11px;
    --mb-edge: rgba(139, 147, 168, 0.2);
    color: rgba(139, 147, 168, 0.45);
}
.menu-btn-quit:hover {
    color: #e24b4a; --mb-edge: rgba(226, 75, 74, 0.55);
    background: rgba(226, 75, 74, 0.06);
    text-shadow: none;
}
.menu-btn-quit:hover::after { background: #e24b4a; }

.back-btn { color: #6a7090; font-size: 11px; margin-top: 8px; --mb-edge: rgba(139, 147, 168, 0.2); }
.back-btn:hover { color: #f0a500; --mb-edge: rgba(240,165,0,0.5); text-shadow: 0 0 10px rgba(240,165,0,0.3); background: rgba(240,165,0,0.06); }
.back-btn:hover::after { background: #f0a500; }

/* ─── Menu Fields ─── */
.menu-field { margin-bottom: 8px; }
.menu-label {
    display: block; font-family: 'Orbitron', monospace; font-size: 9px;
    letter-spacing: 0.15em; color: #6a7090; text-transform: uppercase; margin-bottom: 6px;
}
.menu-value { font-family: 'Orbitron', monospace; font-size: 13px; font-weight: 700; color: #f0a500; }
.menu-input {
    width: 100%; background: #050810; border: 1px solid #2a2e3a; color: #e8eaf0;
    padding: 8px 12px; font-family: 'Rajdhani', sans-serif; font-size: 15px; font-weight: 600;
    outline: none; transition: border-color 0.15s;
}
.menu-input:focus { border-color: #f0a500; }
.menu-input-sm { padding: 8px 10px; font-family: 'Share Tech Mono', monospace; font-size: 13px; text-transform: uppercase; }
.menu-select {
    background: #050810; border: 1px solid #2a2e3a; color: #e8eaf0;
    padding: 8px 10px; font-family: 'Rajdhani', sans-serif; font-size: 13px; font-weight: 600;
    outline: none; cursor: pointer;
}
.menu-row { display: flex; gap: 6px; align-items: stretch; }

/* ─── Faction Row ─── */
.faction-row {
    display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; margin-bottom: 14px;
}
.faction-btn {
    background: #050810; border: 2px solid #2a2e3a; color: #c0c4d4;
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 12px 8px; cursor: pointer;
    clip-path: polygon(12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%, 0 12px);
    border-radius: 0;
    transition: transform .15s, box-shadow .15s, border-color .15s, background .15s;
}
.faction-btn:hover { transform: translateY(-3px); }
.faction-icon { font-size: 18px; line-height: 1; }
.faction-name { font-family: 'Orbitron', monospace; font-size: 9px; font-weight: 700; letter-spacing: 0.08em; }
.faction-desc { font-size: 10px; color: #6a7090; }

.faction-btn.faction-vs {
    background: linear-gradient(165deg, rgba(120,15,10,.28), rgba(10,6,10,.9));
    border: 1px solid rgba(255,70,51,.55);
}
.faction-btn.faction-vs.selected {
    border-color: #ff4633;
    box-shadow: 0 0 22px rgba(255,60,40,.35), inset 0 0 30px rgba(255,60,40,.08);
}
.faction-btn.faction-ued {
    background: linear-gradient(165deg, rgba(90,110,15,.22), rgba(8,10,6,.9));
    border: 1px solid rgba(216,227,74,.5);
}
.faction-btn.faction-ued.selected {
    border-color: #d8e34a;
    box-shadow: 0 0 22px rgba(216,227,74,.35), inset 0 0 30px rgba(216,227,74,.08);
}
.faction-btn.faction-rng {
    background: linear-gradient(165deg, rgba(120,90,15,.18), rgba(10,8,6,.9));
    border: 1px solid rgba(240,180,41,.4);
}
.faction-btn.faction-rng.selected {
    border-color: #f0b429;
    box-shadow: 0 0 22px rgba(240,180,41,.35), inset 0 0 30px rgba(240,180,41,.08);
}

.faction-emblem { width: 56px; height: auto; display: block; margin: 0 auto; }
.faction-emblem-wide { width: 76px; }
.faction-emblem-dice { width: 36px; }

.faction-btn.faction-vs  .faction-name { color: #ff5a45; }
.faction-btn.faction-ued .faction-name { color: #d8e34a; }
.faction-btn.faction-rng .faction-name { color: #f0b429; }

/* ─── Status / Queue ─── */
.menu-status {
    margin-top: 12px; padding: 14px; background: #050810; border: 1px solid #2a2e3a; text-align: center;
}
.menu-status-info { font-size: 12px; color: #6a7090; font-family: 'Rajdhani', sans-serif; margin: 4px 0; }
.menu-link {
    background: none; border: none; font-size: 11px; color: #6a7090; cursor: pointer;
    font-family: 'Rajdhani', sans-serif; text-decoration: underline; padding: 4px 8px;
}
.menu-link:hover { color: #f0a500; }
.room-code {
    font-family: 'Share Tech Mono', monospace; font-size: 24px; font-weight: 700;
    color: #f0a500; letter-spacing: 0.25em; margin: 8px 0;
}
.lobby-pulse-row {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    font-family: 'Orbitron', monospace; font-size: 11px; color: #f0a500;
}

/* ─── Settings ─── */
.setting-row {
    display: flex; align-items: center; justify-content: space-between; padding: 10px 16px;
}
.setting-label {
    font-family: 'Orbitron', monospace; font-size: 10px; letter-spacing: 0.12em; color: #c0c4d4;
}
.menu-slider {
    width: 140px; height: 4px; -webkit-appearance: none; appearance: none;
    background: #2a2e3a; outline: none; border-radius: 2px;
}
.menu-slider::-webkit-slider-thumb {
    -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%;
    background: #f0a500; cursor: pointer; box-shadow: 0 0 6px rgba(240,165,0,0.4);
}

/* ─── About ─── */
.about-block { text-align: center; padding: 16px; }
.about-title { font-family: 'Orbitron', monospace; font-size: 16px; color: #f0a500; margin: 0 0 4px; }
.about-ver { font-family: 'Share Tech Mono', monospace; font-size: 11px; color: #6a7090; letter-spacing: 0.2em; }
.about-credit { font-family: 'Rajdhani', sans-serif; font-size: 14px; color: #c0c4d4; margin-top: 10px; }
.about-links { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; padding: 8px 0; }

/* ─── Version tag ─── */
/* FIX: Version weiter nach rechts + oben (2026-04-08) */
/* FIX BV1 (2026-08-20): bottom 28px -> 120px. #version-label-lobby ist ein Nachkomme von
   #sq-stage (verschachtelt in #lobby-main) — position:fixed nimmt hier NICHT den echten
   Fenster-Rand als Containing Block, sondern die naechste Vorfahren-Ebene mit transform
   (genau #sq-stage, CSS-Spezifikation: ein transform auf einem Vorfahren erzeugt den
   Containing Block fuer dessen fixed-Nachkommen) — bottom/left sind dadurch bereits
   Buehnen-relative (virtuelle) px, kein zweites Koordinatensystem, empirisch belegt
   (28px * gemessener Buehnen-Scale ergab in allen 5 getesteten Seitenverhaeltnissen inkl.
   3440x1440 und einem echten Jenseits-der-1920-Deckelung-Fall exakt die gerenderte
   Bildschirmposition, s. berichte/fix-bv1-layout-anker.md Abschnitt 2). Die eigentliche
   Ursache der vom Betreiber gemeldeten Überdeckung war NICHT ein Koordinatensystem-Drift,
   sondern schlicht zu wenig vertikaler Abstand zur (seit Fix BE1 gewachsenen) Lobby-Knopf-
   Spalte direkt darüber (Discord+Steam, x=8..228 virtuell) — der Versionstext selbst ist
   mit ~386 virtuellen px (voller Label-Text, z.B. "Star Squadrons v0.7.95-live... · Datum
   Zeit") deutlich breiter als die Knopf-Spalte, ein Ausweichen nach rechts würde stattdessen
   die Menüspalte treffen (#lobby-main links liegt nie unter x=440). Einzige kollisionsfreie
   Richtung: nach OBEN, über die gesamte Knopf-Spalte (Discord+Steam) hinaus — 64px (nur
   Steam ausgewichen) kollidierte noch mit Discord (Messung 1. Versuch, s. Bericht), 120px
   raeumt beide Knoepfe in beiden Breakpoints mit Sicherheitsabstand frei (Rechnung im
   Bericht). Bewusst NUR diesen einen Wert geaendert (Abschnitt 2 im Prompt: "nicht beides
   gleichzeitig aendern") — die Lobby-Knopf-Positionen (Abschnitt 1) bleiben unberuehrt. */
.version-tag {
    position: fixed; bottom: 120px; left: 28px; z-index: 10;
    font-family: 'Share Tech Mono', monospace; font-size: 11px;
    color: #FFD700; letter-spacing: 0.05em;
    opacity: 0.9;
    text-shadow: 0 0 8px rgba(0,0,0,0.8);
}

/* ─── Fade-in animation for header ─── */
.anim-fade-in { animation: anim-fade-in 0.8s ease-out; }
@keyframes anim-fade-in {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ─── Staggered menu entrance ─── */
.menu-level.active .menu-btn:nth-child(1) { animation-delay: 0.1s; }
.menu-level.active .menu-btn:nth-child(2) { animation-delay: 0.25s; }
.menu-level.active .menu-btn:nth-child(3) { animation-delay: 0.4s; }
.menu-level.active .menu-btn:nth-child(4) { animation-delay: 0.55s; }
.menu-level.active .menu-btn {
    animation: menu-fade-in 0.3s ease-out both;
}

/* ── ship-card-v3 als ship-tok-combat: clip-path + overflow-Fix ──────────────
   ship-card-v3 braucht overflow:visible damit Overlays am Rand sichtbar sind.
   clip-path wird durch none überschrieben. hp-overlay/hp-bar-mini ausgeblendet. */
.ship-card-v3.ship-tok-combat {
  clip-path: none !important;
  overflow: visible !important;
}
.ship-card-v3 .hp-overlay,
.ship-card-v3 .hp-bar-mini,
.ship-card-v3 .combat-seg-hp { display: none !important; }

/* NEW: DE/EN Sprach-Slider (2026-04-08) */
.lang-switch-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 16px;
}

.lang-label {
    font-family: 'Orbitron', sans-serif;
    font-size: 10px;
    color: rgba(255, 215, 0, 0.5);
    letter-spacing: 0.1em;
    transition: color 0.3s;
}

.lang-label.active {
    color: #FFD700;
}

.lang-switch {
    position: relative;
    display: inline-block;
    width: 36px;
    height: 18px;
}

.lang-switch input { opacity: 0; width: 0; height: 0; }

.lang-slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background: rgba(255, 215, 0, 0.2);
    border: 1px solid rgba(255, 215, 0, 0.4);
    border-radius: 18px;
    transition: background 0.3s;
}

.lang-slider::before {
    content: '';
    position: absolute;
    height: 12px;
    width: 12px;
    left: 2px;
    bottom: 2px;
    background: #FFD700;
    border-radius: 50%;
    transition: transform 0.3s;
}

.lang-switch input:checked + .lang-slider {
    background: rgba(255, 215, 0, 0.3);
}

.lang-switch input:checked + .lang-slider::before {
    transform: translateX(18px);
}
/* NEW: Lobby-Pulse Animation (2026-05-01) */
.lobby-pulse {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--gold);
  animation: lobbyPulse 1.2s ease-in-out infinite;
}
@keyframes lobbyPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
} /* FIX: fehlendes closing } ergänzt — Session 1.4 */

/* ─── Fix CC1: Warteschlangen-Ansicht + Match-gefunden-Moment ───────────────────
   Erweitert #menu-backbone-searching (.menu-status), kein neuer Layer. Breite/Position
   erben absichtlich von .menu-status (270px, s.o.) statt einen eigenen Sonderweg zu
   nehmen — s. Rundenprompt Abschnitt 6. Kein white-space:nowrap/overflow:hidden auf den
   Textzeilen: der Suchzustand-Text darf umbrechen statt abgeschnitten zu werden
   (Abschnitt 6, "lange Namen duerfen nicht abgeschnitten werden"). */
.bb-queue-view {
  margin-top: 2px;   /* Fix CL1: sitzt jetzt in der rechten Spalte neben dem Peilring */
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  min-width: 0;
}
/* Fix CL1: eigene kleine Flaeche je Angabe (Entwurf .stat) statt nackter Zeilen —
   dieselbe gedeckte Fuellung und Anschraegung wie die grossen Flaechen oben, damit die
   Schrift auch ueber dem hellen Planeten im Hintergrundbild lesbar bleibt. */
.bb-queue-stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  min-width: 0;
  padding: 5px 9px;
  background: linear-gradient(168deg, rgba(12, 19, 35, 0.94), rgba(5, 9, 18, 0.96));
  border: 1px solid rgba(46, 64, 104, 0.8);
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
}
.bb-queue-stat-k {
  font-family: 'Orbitron', monospace;
  font-size: 9px;
  letter-spacing: 0.1em;
  color: #7d879e;
  flex-shrink: 0;
}
.bb-queue-stat-v {
  font-family: 'Share Tech Mono', monospace;
  font-size: 13px;
  color: #f0a500;
  white-space: normal;
  word-break: break-word;
  min-width: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.bb-search-state {
  text-align: left;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  color: rgba(240, 165, 0, 0.85);
  text-transform: uppercase;
}

/* Match-gefunden-Moment — Zeitgefühl-Grammatik (Anspannung -> Stillstand -> Auflösung,
   s. public/js/backbone-lobby.js#_bbPlayMatchFoundTransition + BB_MF_*_MS-Kommentar).
   NUR ausgeloest, wenn QUEUE_VIEW.matchFoundFx aktiv ist — sonst bleiben diese Klassen
   ungenutzt und das bisherige Verhalten (Overlay erscheint sofort) bleibt unveraendert. */
/* Fix CL1: Traeger des Moments ist jetzt der Peilring selbst (#bb-search-ring, gezeichnet
   von window.SqRing — Einrasten, Weissblende, Erschuetterung, Ausbruch). Die drei
   Zeitabschnitte bleiben unveraendert (BB_MF_*_MS in backbone-lobby.js) und steuern hier
   nur noch das, was CSS besser kann als Canvas: die Angaben daneben zuruecknehmen und die
   Flaeche kurz aufblitzen lassen. Der frueher hier angesteuerte #bb-pulse-dot existiert
   nicht mehr (Markup-Umbau dieser Runde, global gegrept — keine weiteren Referenzen). */
#menu-backbone-searching.bb-mf-tension .bb-search-side {
  animation: bbMfTensionKf 220ms cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards;
}
#menu-backbone-searching.bb-mf-freeze .bb-search-side {
  animation: none;
  opacity: 0.5;
  transform: scale(0.985);
}
#menu-backbone-searching.bb-mf-resolve .bb-search-side {
  animation: bbMfResolveKf 260ms cubic-bezier(.36, .07, .19, .97) forwards;
}
#menu-backbone-searching.bb-mf-resolve .bb-search-zone {
  animation: bbMfFlashKf 260ms ease-out;
}
@keyframes bbMfTensionKf {
  0%   { opacity: 1;   transform: scale(1); }
  100% { opacity: 0.5; transform: scale(0.985); }
}
@keyframes bbMfResolveKf {
  0%   { opacity: 0.5; transform: scale(0.985); }
  40%  { opacity: 1;   transform: scale(1.02); }
  100% { opacity: 1;   transform: scale(1); }
}
@keyframes bbMfFlashKf {
  0%   { background: rgba(240, 165, 0, 0); }
  18%  { background: rgba(240, 165, 0, .16); }
  100% { background: rgba(240, 165, 0, 0); }
}

/* ─── Fix CD1: Spieler-Zentrale-Kopfband (Stats-Zeile + Namensumbruch) ─────────────
   Layout (Breite/Ausrichtung) kommt seit Fix CG1 (2026-08-20) NICHT mehr von
   .menu-field (270px-Spalte). Fix CJ1 (2026-08-20) hat den frueher HIER stehenden
   Panel-Look (padding/border/background) entfernt: er ist jetzt Teil des GEMEINSAMEN
   Flaechen-Looks von Kopfband, Rangliste und Letzte Partien im "8b. BACKBONE-HUB
   SCREEN"-Block oben — drei Flaechen, ein Look, eine Stelle. Die alte Fuellung
   (rgba(10,14,24,.5)) war ausserdem zu durchsichtig, um Schrift ueber dem
   Hintergrundbild lesbar zu halten (CJ1-Befund). */
/* Lange, leerzeichenlose Anzeigenamen (z.B. Nakama-Auto-Usernamen "PlayerXXXXX" oder
   Unterstrich-getrennte Wunschnamen) sind sonst EIN unbrechbares "Wort" — Browser
   brechen nur an Leerzeichen/Bindestrichen um, nicht an Unterstrichen. Gleiches Muster
   wie .bb-queue-stat-v (CC1, s.o.) — "lange Namen duerfen nicht abgeschnitten werden"
   (Rundenprompt Abschnitt 5), live als echter Overflow gefunden (verify-backbone-login-
   screen.js, Portrait+Ultrawide, Fix CD1).
   min-width:0 ist HIER der eigentlich wirksame Teil: #backbone-userDisplayName ist ein
   Flex-Item mit default min-width:auto (seit CG1 innerhalb .bb-hub-id, davor direkt in
   .bb-hub-header/.menu-field) — das erzwingt die MIN-CONTENT-Breite des laengsten
   unbrechbaren Textlaufs, overflow-wrap allein greift dagegen NICHT (bekannter Flexbox-
   Min-Groesse-Effekt). Ohne dieses min-width:0 blieb der 200px-Overflow exakt gleich
   gross, unabhaengig vom Viewport — das war der Beweis, dass es kein Zeilenumbruch-,
   sondern ein Flex-Min-Groessen-Problem war (live nachvollzogen, nicht angenommen).
   Fix CG1 ergaenzt denselben min-width:0 zusaetzlich auf .bb-hub-id (s.o.), dem neuen
   Zwischen-Flex-Container. */
.bb-hub-header .menu-value {
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
  /* Entwurf Konzept B: der eigene Name ist das groesste Element der Identitaetsflaeche
     (18px statt der 13px, die .menu-value ueberall sonst hat). */
  font-size: 18px;
  line-height: 1.2;
}
.bb-hub-id .menu-label { letter-spacing: 0.2em; margin-bottom: 0; }
/* HUB.enabled === false (DB-Master-Schalter aus): Panel-Look weg, Identitaetszeile
   bleibt (das ist "wie heute" vor Fix CD1 — keine neue Funktion, nur ihre Position). */
.bb-hub-header.bb-hub-off {
  padding: 0;
  border: none;
  background: none;
  clip-path: none;
}
.bb-hub-header.bb-hub-off::before,
.bb-hub-header.bb-hub-off::after { display: none; }
.bb-hub-stats {
  display: flex;
  gap: 18px;  /* Entwurf Konzept B */
  margin-top: 6px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 12.5px;
}
.bb-hub-stat-k {
  color: #7d879e;
  letter-spacing: 0.08em;
  margin-right: 4px;
}
/* Fix CL1: eigener Stand deutlicher — der Name ist gold, Score/Rang waren es auch, damit
   verschwamm die Hierarchie. Zahlen jetzt heller und mit fester Laufweite. */
.bb-hub-stat-v { color: #ffc94d; font-variant-numeric: tabular-nums; }
.bb-hub-header .menu-label { color: #7d879e; }
.bb-hub-empty {
  margin-top: 6px;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: #6a7090;
  font-family: 'Rajdhani', sans-serif;
}

/* FIX: v3 Hauptbutton Hover/Active Effekte (2026-05-01) */
/* FIX 1.6.1: erste Duplikate von #ov-main-btn:hover/:active/#ov-main-btn-wrap
   entfernt — vollständige Definitionen weiter unten behalten */

/* NEW: UI v3 HoK-Style Overlays (2026-05-01) */

/* screen-overview = Spielfeld, kein Layout-Container mehr */
#screen-overview {
  overflow: visible !important;
  /* FIX: display:block !important entfernt — game-core.js showScreen() setzt display korrekt (Session 1.4e) */
}

/* Locations fuellen Spielfeld */
/* FIX 1.6.1: position/top/left/right/bottom entfernt — werden von applyLayout gesetzt */
#ov-locations {
  display: flex;
  gap: 4px;
}

/* Hauptbutton Hover-Effekte — UMBAU Z1: gilt jetzt für beide Instanzen (Übersicht
   #ov-main-btn UND Kampf #cb-main-btn, EINE Implementierung/game-command-button.js).
   FIX AB1: war gruen (0 0 0 10px rgba(50,180,80,..) / 0 0 40px rgba(50,200,80,..)) —
   Wert stammt bereits 1:1 aus der Vor-Z1-Fassung (game-v3-pre-z1.css, #ov-main-btn:hover),
   ist also KEINE Z1-Regression, sondern eine statische Hover-Regel, die schon vorher
   unabhaengig vom jeweiligen Ring-/Body-Zustand immer gruen aufblitzte. "Kein Zustand
   darf gruen bleiben" gilt laut Auftrag ausdruecklich auch fuer historisch gruene
   Zustaende — auf Gold umgefaerbt, gleiche Ring-/Blur-Aufweitung wie im Original
   beibehalten (nur der Farbton ersetzt, keine neue Struktur erfunden). */
#ov-main-btn:hover, #cb-main-btn:hover {
  transform: translateY(-3px) scale(1.05) !important;
  box-shadow:
    0 0 0 4px rgba(5,15,8,0.7),
    0 0 0 10px rgba(212,168,67,0.55),
    0 0 0 12px rgba(5,10,5,0.5),
    0 8px 28px rgba(0,0,0,0.65),
    0 0 40px rgba(212,168,67,0.45) !important;
}

#ov-main-btn:active, #cb-main-btn:active {
  transform: translateY(2px) scale(0.97) !important;
}

#ov-main-btn-wrap, #cb-main-btn-wrap {
  overflow: visible;
}

/* FIX: UI v3 Hand + Fleetzone Korrekturen (2026-05-01) */

/* Hand-Container overflow:visible damit Faecher sichtbar */


/* FIX 1.6.1: #ov-fz-mine-wrap + #ov-fz-enemy-wrap > div:first-child entfernt
   — nur min-height-Constraints, kein visuelles Styling. Größe kommt aus layout-config.js */

/* FIX (Topbar Variante B, 2026-07-08): eine dunkle angular Leiste statt Einzel-Chips —
   eigener Name+Fraktion links, SP-Duell-Chip mittig, Gegner rechts.
   FIX (Topbar Runde 4, 2026-07-09): Zug-Badge entfernt, Grid → Flexbox. Layout-
   Prinzip statt Pixel-Werten: Embleme + SP-Duell-Chip sind FESTE Elemente
   (flex-shrink:0), die beiden Namens-Blöcke (.sq-topbar-name-col) sind FLEXIBEL
   (flex:1;min-width:0;ellipsis) — bei knapper Breite kürzen sich IMMER zuerst die
   Namen, nie die Chips. Funktioniert mit jeder Designer-Breite, keine feste
   Breite mehr hartkodiert. */
/* FIX K7 (2026-07-23, Mockup 1): Flexbox-Reihe -> 3-Spalten-Grid (1fr auto 1fr).
   Jede Seite ist jetzt ein KOMPAKTER Block (flex:0 1 auto statt 1 1 auto auf
   .sq-topbar-name-col) — die Gruppe [Logo+Name+Chip] wächst nicht mehr auf die volle
   1fr-Spaltenbreite, sondern haengt per justify-content am Aussenrand ihrer Spalte;
   der Rest der Spalte bleibt leerer Raum Richtung Zentrum. Das war noetig, weil das
   Mockup den Handkarten-Chip "deutlich weg vom Zentrum" neben dem Namen will, statt
   an den Innenrand (Zentrum) gedrueckt — mit wachsendem Namen-Block waere der Chip
   sonst immer am Spalten-Innenrand (=Zentrum-nah) gelandet. */
/* ══ Fix CW1 (2026-08-22): HUD-Neuaufbau Etappe 1 — das Banner ════════════════════════
   Zielbild: mockups/hud-neuaufbau-vollversion.html (#hud). EINE Reihe ueber die volle
   Buehnenbreite, fuenf Zonen:
     ganz links       Fraktionswappen, Spielername, Fraktion, Handkarten-Anzahl
     links der Mitte  Phase, "Dein Zug", Timer als kleiner Ring
     Mitte            Siegpunkte (Etappe 3: in der Kampfansicht die Initiative-Reihenfolge)
     rechts der Mitte die Hinweiseinblendung
     ganz rechts      Gegnername, Fraktion, Handkarten-Anzahl, Wappen
   Vorher (K7) war dies ein 3-Spalten-Grid in einem 580 px breiten Kaestchen oben rechts.
   Die Breite kommt jetzt aus layout-config.js (stretch-horizontal ueber die ganze Buehne),
   die Aufteilung darin aus Flexbox: die beiden Spielerzonen und die Siegpunkte sind FEST,
   Phase und Hinweis teilen sich den Rest — so traegt das Banner jede Buehnenbreite von
   1280 bis 1920 (Fix AU1) ohne neue Zahlen. `overflow:hidden` ist die harte Zusage
   "kein Ueberlauf": alles Schrumpfbare kuerzt vorher per Ellipsis. */
.sq-topbar {
  display: flex;
  align-items: stretch;
  /* Die 46px aus layout-config.js sind die AUSSENhoehe — ohne border-box kaeme die
     Unterkante (1px) obendrauf und das Band waere 47px hoch (kein globaler Reset in
     dieser Datei). */
  box-sizing: border-box;
  background: linear-gradient(180deg, rgba(10, 16, 30, 0.97), rgba(6, 10, 20, 0.90));
  border: 0;
  border-bottom: 1px solid rgba(240, 160, 0, 0.30);
  clip-path: none;
  padding: 0;
  overflow: hidden;
  /* FIX (Runde 3, 2026-07-08): die verbreiterte Leiste (Fix 1a) überlappt jetzt
     horizontal/vertikal mit #ov-enemy-hand (z-index:15) und #ov-icons (z-index:30) —
     ohne eigenen z-index (vorher "auto") lag die Gegner-Handkarten-Reihe sichtbar
     ÜBER dem eigenen Namen/Emblem. Reiner Stacking-Fix, keine Positionsänderung. */
  z-index: 35;
}
/* Fix CW1: feste Zonenbreite statt 1fr-Grid-Spalte (Zielbild: .pl{flex:0 0 268px}).
   Fest heisst hier "waechst nicht mit" — schrumpfen darf die Zone sehr wohl, sonst
   koennte sie eine schmale Buehne sprengen. Was in ihr schrumpft, ist ausschliesslich
   die Namensspalte (unten), nie Wappen oder Handkarten-Chip. */
.sq-topbar-player {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  /* 268px stammt aus dem Zielbild. Das Breitenbudget ist gemessen, nicht geraten
     (scripts/cw1-probe4.js, Namensbreiten je Schriftgroesse):
       laengster Bot-Name "Commander Falcon"          136px @12px
       20 Zeichen gemischt "MaximilianWolkenberg"     157px @12px
       20 Zeichen zifferlastig (Testnamen verify-ui)  190px @12px
       20x "M" (theoretisches Maximum von maxlength=20) 230px @12px
     312px geben der Namensspalte rund 207px — genug bis einschliesslich des zifferlastigen
     Falls, den verify-ui.js benutzt. Reine Wiederholungszeichenfolgen (20x "W" = 290px)
     kuerzen weiterhin per Ellipsis; das taten sie vor dieser Runde ebenfalls (damals
     max-width:210px bei 11px Schrift) und der volle Name steht als Kurzhinweis am Element.
     Begruendete Abweichung vom Entwurf. */
  flex: 0 1 312px;
  padding: 0 10px;
}
.sq-topbar-mine  { justify-content: flex-start; }
.sq-topbar-enemy { justify-content: flex-end; }
.sq-topbar-glyph {
  font-size: 14px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
/* FIX (Runde 3, 2026-07-08): Fraktions-Emblem-Klon (ersetzt ◆/⬡-Textglyph)
   FIX K7 (Mockup 1): 30px -> 44px ("Fraktions-Logo 44px"). */
/* Fix CW1: 44px -> 28px. Das Banner ist 46px hoch (Zielbild), ein 44px-Wappen liesse
   darin keinen Rand. Zielbild: .pl .emb{width:28px;height:28px}. */
.sq-topbar-emblem-svg {
  width: 28px;
  height: 28px;
  object-fit: contain;
  flex-shrink: 0;
  display: block;
}
.sq-topbar-name-col {
  display: flex;
  flex-direction: column;
  /* FIX K7: war flex:1 1 auto (wuchs auf volle Spaltenbreite, druckte den Chip an den
     Zentrum-nahen Innenrand) — jetzt nur schrumpfbar, nicht wachsend, damit die
     Gruppe [Logo+Name+Chip] kompakt am Aussenrand bleibt. max-width als Sicherheitsnetz
     fuer sehr lange Namen (Ellipsis greift weiterhin via .sq-topbar-name). */
  /* Fix CW1: die Namensspalte waechst NICHT (sonst schoebe sie den Handkarten-Chip an den
     Zonenrand — im Bildschirmfoto des dritten Laufs deutlich zu sehen, das Zielbild haelt
     Wappen, Name und Chip dagegen als eine enge Gruppe zusammen). Sie ist aber das EINZIGE
     schrumpfbare Teil der Zone: bei knappem Platz kuerzt immer zuerst der Name per Ellipsis,
     nie Wappen oder Chip. Das frueher noetige max-width:210px entfaellt — die Zonenbreite
     (296px, s.o.) deckelt bereits und laesst dem laengsten Namen seine gemessenen 171px. */
  flex: 0 1 auto;
  min-width: 0;
}
.sq-topbar-name-col-enemy { align-items: flex-end; }
.sq-topbar-name {
  font-family: 'Orbitron', sans-serif;
  /* Zielbild: 14px. 12px, weil das Breitenbudget im 1280er Band sonst nicht fuer beides
     reicht — vollstaendige Spielernamen UND einen vollstaendigen Standard-Hinweis (s.
     .sq-topbar-player und .sq-hint-bar). Bei 13px kuerzte der zifferlastige 20-Zeichen-Name
     aus verify-ui.js (207px gegen 191px Platz, im ersten verify-ui-Lauf dieser Runde
     gemessen). Begruendete Abweichung vom Entwurf. */
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  max-width: 100%;
}
.sq-topbar-faction-sub {
  font-size: 7px;
  color: rgba(200, 198, 188, 0.4);
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* FIX K7 (Mockup 1): zweite, kleinere Zeile "BOT · <Schwierigkeit>" beim Gegner. */
.sq-topbar-faction-sub-bot {
  font-size: 6px;
  opacity: 0.75;
}
/* FIX K6 (2026-07-23): "SP" raus, "0:11"-Format + ausgeschriebenes goldenes Label
   darunter statt seitlich — Block jetzt Spalte (Wert-Zeile + Label-Zeile). */
.sq-topbar-sp {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  /* FIX K7 (Mockup 1): "grosszuegiges seitliches Padding" — Grid-Mittelspalte ist
     jetzt "auto"-breit (game-v3.css .sq-topbar), Padding haelt Abstand zu den
     Seitenspalten statt justify-self:center (kein Flex-Item mehr, Grid-Kind).
     FIX K7-Nachschliff: 24px -> 18px — der breitere 44px-Logo (Mockup 1) drueckte
     die Namensspalten messbar enger (Live-Messung analog K6-Nachschliff), 18px
     bleibt weiterhin klar grosszuegiger als das alte 6px-Flex-gap. */
  /* Fix CW1: feste Mittelzone mit den beiden senkrechten Trennlinien aus dem Zielbild
     (.zone.mid{flex:0 0 176px;border-left/right}) statt "auto"-breiter Grid-Spalte. */
  /* Zielbild: 176px. 152px, weil die freiwerdenden Pixel in der Hinweiszone gebraucht
     werden (s. dort); der Inhalt der Mittelzone ("3:11" bei 22px + das ausgeschriebene
     Wort "SIEGPUNKTE"/"VICTORY POINTS" bei 7px) bleibt deutlich darunter. Dass hier nichts
     ueberlaeuft, prueft scripts/verify-cw1-banner.js in allen drei Formaten mit. */
  flex: 0 0 152px;
  justify-content: center;
  padding: 0 10px;
  border-left: 1px solid rgba(240, 160, 0, 0.20);
  border-right: 1px solid rgba(240, 160, 0, 0.20);
}
.sq-topbar-sp-row {
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.sq-topbar-sp-val {
  font-family: 'Orbitron', sans-serif;
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
}
.sq-topbar-sp-colon {
  font-family: 'Orbitron', sans-serif;
  font-size: 16px;
  font-weight: 700;
  line-height: 1;
  color: rgba(230, 228, 220, 0.35);
}
.sq-topbar-sp-label {
  /* FIX K6-Nachschliff: kompakter (8px/1.5px -> 7px/1px, wie .sq-topbar-faction-sub) —
     "SIEGPUNKTE"/"VICTORY POINTS" ist strukturell breiter als das alte "SP"-Kürzel und
     drängte die Namensspalten (flex:1;min-width:0) messbar enger (Live-Messung: 1920px
     Breite, ~14px Ellipsis-Überschuss bei einem 20-Zeichen-Testnamen). Kein Verlust an
     Lesbarkeit (gleiche Groesse wie die Fraktions-Unterzeile), gibt den Namen Platz zurueck. */
  font-size: 7px;
  color: var(--gold);
  font-family: 'Orbitron', sans-serif;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
}
/* ══ Fix CY1 (2026-08-22): HUD-Neuaufbau Etappe 3 — Zone 3 in der Kampfansicht ═══════
   Zielbild (mockups/hud-neuaufbau-vollversion.html): `.zone.mid` traegt in der Uebersicht
   `#vpbox` (Siegpunkte) und im Kampf `#inibox` (Initiative-Reihenfolge). Die ZONE ist in
   beiden Ansichten dieselbe — ihre Geometrie steht vollstaendig in `.sq-topbar-sp` oben
   (feste 152px, die beiden Trennlinien, senkrecht mittig). Hier steht ausschliesslich,
   was die Kampf-Fassung an INHALT anders macht. Damit ist "gleiche Stelle, gleiche
   Groesse" strukturell zugesichert statt zweimal bemasst. */
/* ══ Fix DE1 (Punkt 3, 2026-08-23): Initiative nach Zone 2, Phase in die Mitte ═══════
   Der Tausch gilt NUR fuer die Kampfansicht; die Uebersicht behaelt Phase links und
   Siegpunkte mittig. Grund ist Breite: Zone 2 ist elastisch (gemessen 250 Buehnen-px bei
   1280 Buehnenbreite), die Mittelzone fest 152. Die Initiative braucht die Breite, weil
   sie seit dieser Runde wieder Schiffsnamen traegt; das Phasen-Panel braucht sie nicht
   (gemessen 85 px Inhaltsbreite, scripts/de1-probe1.js). Bewusste Abweichung vom Zielbild,
   vom Betreiber so entschieden. */
.sq-banner-ini {
  /* Wie .sq-banner-phase, nur linksbuendig: die Reihe beginnt am linken Zonenrand und
     waechst nach rechts — so steht der erste (= schnellste) Angreifer immer an derselben
     Stelle, unabhaengig davon, wie viele Schiffe im Kampf sind.
     Fix EB1: basis 224 statt 0 — das ist die Breite, die die Zone im Bezugsformat heute
     schon hat (gemessen 224,2 mit Ring). Ohne ausgeschriebene basis wuerde die Zone beim
     Deckeln der Phasenzone auf 201 zurueckfallen, also im Bezugsformat SCHRUMPFEN. */
  flex: 1 1 224px;
  /* Fix EG1 (2026-08-25): derselbe Deckel-Gedanke wie bei .sq-banner-phase, s. dort.
     251 statt 224, weil die Zone laut CY1 breiter bleiben muss als die Kampf-Phasenzone
     (deren Deckel steht bei 250) — 251 ist damit der kleinstmoegliche Wert und laesst der
     Hinweiszone den groesstmoeglichen Rest. Die Initiative-LEISTE selbst ist davon
     unberuehrt: sie ist bei realistischen Flotten inhaltsbreit (gemessen 187,6 Buehnen-px
     bei 2..6 Schiffen, passt in die 231 px Innenbreite), nur der Leerraum RECHTS von ihr
     schrumpft. Erst bei 12 Schiffen scrollt sie — das tut sie im Bezugsformat heute schon
     (gemessen: braucht 605, Platz 204). */
  max-width: 251px;
  justify-content: flex-start;
}
/* Reihe + Beschriftung untereinander, wie bei den Siegpunkten in der Uebersicht. */
.sq-banner-ini-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  /* Ohne min-width:0 wuerde die scrollbare Reihe ihre Zone aufblaehen statt zu scrollen. */
  min-width: 0;
  max-width: 100%;
}
/* Das Phasen-Panel in der Mittelzone.
   Zwei Dinge muessen hier gedreht werden, beide gemessen und nicht geraten:
   1. RICHTUNG. `.sq-topbar-sp` ist eine Spalte (Siegpunktzahl ueber Beschriftung). Das
      Phasen-Panel steht aber NEBEN seinem Timer-Ring, nicht darueber — in der Spalte
      stapelten sich beide und ragten zusammen 19 Buehnen-px aus dem 46px-Band heraus
      (gemessen von scripts/verify-cw1-banner.js, erster Lauf dieser Runde: cb-phase-status
      bei top -19, der Ring bei bottom 64). Deshalb `row`.
   2. BREITE. Gemessen brauchen Panel (85) + Abstand (6) + Ring (40) + Zonenpolster (20)
      zusammen 151 Buehnen-px — die 152 der Uebersichts-Mittelzone waeren auf den Pixel
      genau aufgebraucht, jedes laengere Phasenwort kuerzte sofort. 176 ist die Breite,
      die das Zielbild fuer `.zone.mid` vorsieht, und laesst 25 px Luft. Die beiden
      elastischen Nachbarzonen geben die 24 px je zur Haelfte ab (gemessen 250 -> 238).
   Ausserdem richtet `.sq-banner-phase-panel` seinen Inhalt rechtsbuendig aus (im Zielbild
   haengt es am Innenrand seiner Zone) — zwischen zwei Trennlinien gehoert er mittig. */
/* ══ Fix EB1 (2026-08-24): die Phasenzone nutzt die vorhandene Breite ═══════════════
   GEMESSEN (scripts/eb1-probe3.js, verify-shots/eb1-probe3/bericht-vorher.md), Kampf-
   ansicht, 4 Schiffe, Timer-Ring sichtbar, alle Zahlen in BUEHNEN-px:

     Fenster        Buehne   Phasenzone   Ini-Zone   Ini-Leiste braucht   ungenutzt rechts
     1280x720       1280        203,6       224,2           188                 16,6
     1920x937       1475,3      203,6       321,9           144,5              116,6
     1920x1080      1280        203,6       224,2           125,3               19,9
     2880x1080      1920        203,6       544,2           125,3              339,9

   Zwei Befunde stehen darin:

   1. DIE PHASENZONE WAR DIE EINZIGE, DIE NICHT MITWAECHST. `flex: 0 0 176px` haelt sie
      bei JEDER Buehnenbreite auf denselben ~204 px (die 176 werden nur deshalb
      ueberschritten, weil der Timer-Ring die Zone per min-content aufdrueckt — sie nimmt
      sich die Differenz still von beiden Nachbarn). Ini- und Hinweiszone (`flex: 1 1 0`)
      teilen sich dagegen den GESAMTEN Zuwachs. Bei 1475 px Buehne liegen dadurch 116,6 px
      ungenutzt rechts der Initiative-Leiste und die komplette, immer leere Hinweiszone
      daneben — waehrend die Phase auf ihren 204 klemmt. Das ist der "Platz in beide
      Richtungen", den der Betreiber gesehen hat.

   2. EIN FENSTER VON 1920x1080 IST NICHT DER NORMALFALL. Bei EXAKT 16:9 klemmt
      layout-engine.js die Buehne auf 1280 (`effRefW = clamp(720*ratio, 1280, 1920)`) —
      dort gibt es keinen Spielraum, und die Zeile 1920x1080 oben ist mit 1280x720
      identisch. Ein reales Browserfenster auf demselben Monitor hat durch Tab-/
      Adressleiste ~1920x937 und damit 1475 px Buehne. Nur diese Zeile beschreibt den
      Betreiber (Fehlerklasse feedback_desktop_exact_ratio_test_blindspot, Fund AY1).

   DAS MITTEL: alle drei mittleren Zonen bekommen eine AUSGESCHRIEBENE flex-basis, die im
   Bezugsformat exakt die heute gemessene Aufteilung ergibt (204 + 224 + 224 = 652 = die
   Breite, die nach den beiden 312er Spielerzonen uebrig bleibt). Bei 1280 aendert sich
   dadurch NICHTS — die harte Grenze aus dem Prompt. Erst der Zuwachs DARUEBER wird zu
   dritt geteilt statt zu zweit.

   DER DECKEL: `max-width: 250px` auf der Kampf-Phasenzone. 250 ist kein gegriffener Wert,
   sondern die Breite der Uebersichts-Phasenzone im Bezugsformat — die Kampfphase darf bis
   dorthin wachsen, nicht weiter. Ohne Deckel bekaeme sie bei 1920 px Buehne 417 px, die
   das Panel gar nicht fuellen kann, und der Initiative-Leiste fehlten 128. Mit Deckel
   gewinnt die Phase hoechstens +46 px und Ini/Hinweis geben hoechstens je ~23 px ab —
   und zwar ausschliesslich Leerraum: die Initiative-LEISTE selbst braucht bei 1475 nur
   144,5 px und behaelt bei jeder realistischen Flottengroesse ihre Breite.

   KEIN min-width:0 auf der Phasenzone. Die Zone darf sich weiterhin per min-content
   aufdruecken, wenn eine Beschriftung laenger ist als die basis — genau das haelt den
   englischen Fall ("Wingman counter", gemessen 209 statt 203,6) unveraendert, statt ihn
   auf 204 zu kuerzen. Das ist bewusst KEINE Breitenzusage per CSS-width (Fehlerklassen
   CJ1/DC1): die Zonen sind Flex-Kinder, keine layout-config.js-gefuehrten Elemente. */
.sq-topbar-phase-mid {
  /* Fix EB1: war `flex: 0 0 176px`. Die 176 sind als basis geblieben? Nein — 204, weil
     das der Wert ist, den die Zone MIT Ring heute real einnimmt (gemessen). Als basis
     ausgeschrieben nimmt sie ihn sich nicht mehr still von den Nachbarn. */
  flex: 1 1 204px;
  max-width: 250px;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.sq-topbar-phase-mid .sq-banner-phase-panel { align-items: center; }
.sq-topbar-phase-mid .sq-banner-phase-action { text-align: center; }

.sq-topbar-ini-row {
  /* NICHT kosmetisch: der Autoscroll in renderInitiativeBar() (Fix K8) rechnet mit
     `_activeItemEl.offsetLeft`, und offsetLeft misst gegen den naechsten POSITIONIERTEN
     Vorfahren. Bis Fix CY1 war das die Leiste selbst (die Layout-Engine setzte
     position:absolute auf #initiative-bar). Als Flow-Kind des Banners waere es jetzt das
     Banner — offsetLeft lieferte dann die Position im ganzen Band statt in der Leiste, der
     Zielwert liefe ueber das Maximum und die Leiste stuende immer am ENDE. Gemessen im
     Bildschirmfoto: bei 12 Schiffen und aktivem Eintrag 3 standen die letzten fuenf Kreise
     im Bild, der aktive gar nicht. position:relative macht die Leiste wieder zum
     Bezugsrahmen. */
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  max-width: 100%;
  /* Das Polster ist gemessen, nicht geschmueckt: .sq-ini-bar-scroll (Fix K8) bringt
     overflow-y:hidden mit — ohne Polster schneidet die Leiste den Goldrahmen und den
     Puls des aktiven Kreises oben und unten ab (im ersten Lauf dieser Runde mit 1.3 bis
     2.0 px gemessen, in allen drei Formaten). 5px geben dem 2px-Rahmen und dem inneren
     Teil des Pulses Platz; die Zone bleibt mit 22+10 px Reihe, 1 px Abstand und der
     rund 9 px hohen Beschriftung unter den 46 px des Bands. */
  /* Fix DE1: 5px -> 4px. Das Hoehenbudget der Zone ist 45 Buehnen-px und wird jetzt von
     drei Dingen geteilt: Reihe (26 + 2x4 Polster = 34), Abstand (1) und die Beschriftung
     "INITIATIVE" (9) = 44. Bei 5px waeren es 46 und die Zone liefe ueber. Der Zweck des
     Polsters bleibt gewahrt: der 2px-Goldrahmen des aktiven Eintrags steckt seit dieser
     Runde in der festen Chip-Hoehe (border-box), zu polstern ist nur noch der innere Teil
     des Goldpulses — der aeussere Schein reicht ohnehin 40px weit und wird von
     overflow-y:hidden beschnitten, in jeder Polsterung. */
  padding: 4px 3px;
  box-sizing: border-box;
  /* overflow-x:auto + versteckter Scrollbalken kommen unveraendert aus
     .sq-ini-bar-scroll (Fix K8), die #initiative-bar zusaetzlich traegt. */
}
/* Fix DE1 (Punkt 3): der Eintrag ist kein 22px-Kreis mit blosser Zahl mehr, sondern
   wieder Name ueber Initiative-Zahl — die Fassung von vor Fix CY1, nur in der Bandhoehe
   des Banners statt in der alten 56px-Leiste. Der Kreis war eine Folge der 152px-Zone,
   nicht eine Entscheidung fuer sich; mit dem Zonentausch faellt sein Grund weg. */
.sq-ini-chip {
  /* Der aktive Eintrag traegt einen 2px-Goldrahmen (.ini-bar-active, weiter unten, mit
     !important) — ohne border-box waere genau dieser Eintrag 2px groesser als alle
     anderen und die Reihe wuerde beim Weiterruecken des Angreifers sichtbar zucken.
     border-box allein reicht dafuer aber NICHT: es deckelt nur eine VORGEGEBENE Groesse.
     Ohne feste Hoehe waechst der Kasten mit seinem Rahmen, der aktive Eintrag wurde 28
     statt 26 Buehnen-px hoch, riss die ganze Reihe auf 37.98 und das Banner lief um 2 px
     ueber (gemessen scripts/de1-probe3.js; verify-cy1 hat es als scrollHeight-Ueberlauf
     gemeldet). Die feste Hoehe ist deshalb funktional, nicht kosmetisch — sie ist genau
     das, was der Kreis vor DE1 mit seinem `height:22px` mitgebracht hat.
     26 = 2 Rahmen + 2 Polster + 9.9 Namenszeile + 12.1 Zahlenzeile. */
  box-sizing: border-box;
  height: 26px;
  flex: 0 0 auto;
  /* Die Breite kommt vom Namen, nicht von einer festen Zahl — kurze Namen ("Alpha")
     brauchen weniger Platz als lange ("Chosenling"), und in der scrollbaren Reihe ist
     jeder gesparte Pixel ein Schiff mehr im Bild. Der Deckel haelt sehr lange kuenftige
     Namen davon ab, die Reihe allein auszufuellen. */
  max-width: 78px;
  border-radius: 4px;
  padding: 1px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1;
  border: 1px solid rgba(240, 160, 0, 0.20);
  background: #0b1424;
  color: rgba(230, 228, 220, 0.60);
  transition: box-shadow 0.15s, opacity 0.15s, filter 0.15s;
}
/* Der Name kuerzt per Ellipsis; vollstaendig steht er im `title` des Eintrags
   (renderInitiativeBar(), game-combat.js). */
.sq-ini-chip-name {
  font-family: 'Rajdhani', sans-serif;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.2px;
  line-height: 1.1;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sq-ini-chip-ini {
  font-family: 'Share Tech Mono', monospace;
  font-size: 11px;
  line-height: 1.1;
}
.sq-ini-chip-vs  { border-color: rgba(226, 75, 74, 0.75);  color: #ff8a8a; }
.sq-ini-chip-ued { border-color: rgba(59, 139, 212, 0.75); color: #a9cdf5; }
/* Fix DE1: der Name erbt die Fraktionsfarbe (er ist die Zuordnung, die diese Runde
   zurueckholt), die Initiative-Zahl steht etwas zurueckgenommen darunter. */
.sq-ini-chip-name { color: inherit; }
.sq-ini-chip-ini  { opacity: 0.75; }
/* Aktiv: Gold und leicht groesser — Farbe und Puls (.ini-bar-active) unveraendert aus
   Fix 2 (2026-07-08), nur die Form ist jetzt der Kreis aus dem Zielbild. */
.sq-ini-chip-aktiv {
  color: #f0b429;
  background: rgba(240, 180, 41, 0.16);
  /* Kein `transform: scale()` — der alte, rechteckige Eintrag wurde um 1.12 vergroessert.
     In der 22px-Reihe des Banners ragte der vergroesserte Kreis aus dem overflow-y:hidden
     der Leiste heraus und wurde oben/unten abgeschnitten. Das Zielbild loest "aktiv"
     ohnehin ueber Farbe und Rahmen, nicht ueber Groesse (.ini .c.now). */
}
/* Gefeuert / Vorschau: dieselben Blass-Stufen wie bisher (0.35 + saturate(.3) bzw. 0.55). */
.sq-ini-chip-gefeuert { opacity: 0.35; filter: saturate(0.3); }
.sq-ini-chip-vorschau { opacity: 0.55; }

/* ── Fix CY1: die Ortskarte in der Mitte der Kampfansicht (Zielbild `.cbloc`) ─────────
   Ein kompaktes, senkrecht mittiges Kaestchen zwischen den beiden Schiffsspalten. Vorher
   war das eine dunkle Spalte ueber die volle Feldhoehe — die haette das seit dieser Etappe
   vollflaechige Ortsartwork (#cb-loc-backdrop) in zwei Haelften geschnitten. */
.sq-cbloc-col {
  position: relative;
  z-index: 1;
  flex: 0 0 196px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 10px;
  min-width: 0;
}
.sq-cbloc {
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 10px 10px 11px;
  text-align: center;
  border: 1px solid rgba(240, 160, 0, 0.32);
  border-radius: 5px;
  background: rgba(8, 14, 26, 0.86);
}
.sq-cbloc-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 12.4px;
  font-weight: 600;
  letter-spacing: 1.4px;
  color: #dfe5f2;
  text-transform: uppercase;
  line-height: 1.2;
  max-width: 100%;
  /* Ortsnamen kommen aus der Datenbank — der laengste heute ("Redwood Nebula") passt in
     eine Zeile, ein laengerer bricht um, statt die Karte zu sprengen. */
  overflow-wrap: anywhere;
}
.sq-cbloc-vp {
  font-family: 'Share Tech Mono', monospace;
  font-size: 19px;
  font-weight: 700;
  color: var(--gold);
  line-height: 1;
}
.sq-cbloc-vplbl {
  font-family: 'Orbitron', sans-serif;
  font-size: 7.6px;
  letter-spacing: 1.6px;
  color: rgba(255, 200, 50, 0.45);
  white-space: nowrap;
}
.sq-cbloc-owner {
  display: inline-block;
  box-sizing: border-box;
  margin-top: 2px;
  font-family: 'Orbitron', sans-serif;
  font-size: 9px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 4px;
  padding: 3px 8px;
  color: rgba(255, 255, 255, 0.5);
  line-height: 1.2;
  max-width: 100%;
  overflow-wrap: anywhere;
}
/* "Keine Schilde" (FIX G5) — Sichtbarkeit schaltet weiterhin JS ueber style.display. */
.sq-cbloc-effect {
  display: inline-block;
  box-sizing: border-box;
  font-family: 'Orbitron', sans-serif;
  font-size: 7px;
  letter-spacing: 1px;
  text-transform: uppercase;
  border: 1px solid rgba(226, 75, 74, 0.85);
  border-radius: 4px;
  padding: 3px 4px;
  color: #ff8a89;
  background: rgba(226, 75, 74, 0.28);
  max-width: 100%;
}

/* FIX J1 (Fleetzone-Burn-Prompt, Änderung 2): Handkarten-Chip, nur Kampf-Topbar
   ('cb') — s. _renderSqTopbarHTML()/_updateSqTopbar() (game-overview.js).
   FIX K6 (2026-07-23): Rahmen/Kachel-Hintergrund entfernt (wirkte deplatziert neben
   Namen/Untertitel) — Symbol+Zahl jetzt bare Geschwister als EINE visuelle Einheit.
   FIX K7 (2026-07-23, Mockup 1): Icon 15x21 -&gt; 40x52, Zahl 12px -&gt; 22px. Der
   18px-Abstand zum Namen-Block kommt als inline margin direkt aus
   _renderSqTopbarHTML() (seitenabhaengig links/rechts), nicht aus dieser Klasse. */
.sq-hand-chip {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}
.sq-hand-chip-icon {
  /* FIX K8 (2026-07-24): cover -&gt; contain — die echten handchip-Assets sind quer
     (~1.6:1, 3 gefaecherte Kartenruecken), object-fit:cover zeigte in der 40x52-
     Box nur einen zentrierten Ausschnitt (sah aus wie ein einzelner Kartenruecken).
     Box-Groesse 40x52 bleibt unveraendert (Layout-Engine-Box), das Symbol selbst
     wird jetzt unverzerrt eingepasst statt beschnitten. */
  /* Fix CW1: 40x52 -> 26x26. Die alten Masse stammen aus der 80px hohen Kampf-Topbar
     (K7); im 46px-Band des Banners passt kein 52px hohes Symbol. Zielbild:
     .chip img{width:26px;height:26px}. object-fit:contain bleibt (K8): die echten
     handchip-Assets sind quer (~1.6:1) und wuerden bei cover beschnitten. */
  width: 26px;
  height: 26px;
  object-fit: contain;
  border-radius: 2px;
  display: block;
  flex-shrink: 0;
}
.sq-hand-chip-count {
  font-family: 'Orbitron', sans-serif;
  font-size: 19px;
  font-weight: 700;
  color: rgba(230, 228, 220, 0.9);
  line-height: 1;
}
/* FIX (Topbar Runde 4, 2026-07-09): .sq-topbar-turn-badge/-mine/-waiting +
   @keyframes sqTopbarTurnPulse entfernt — Zug-Badge ersatzlos raus (Marcel-
   Entscheidung, Phasen-Panel zeigt den Zugbesitzer bereits). */

/* FIX (Teil 2, 2026-07-08): #ov-deploy-ring-Regeln entfernt — Widget komplett weg,
   Zähler lebt jetzt als Segmentbalken im Phasen-Panel (siehe .sq-phase-panel-deploy unten). */

/* FIX (Teil 2, 2026-07-08): Phasen-Panel — teal angular (Serien-Grundfarbe des Panels),
   plus neuer Deploy-Segmentbalken darunter (nur main_phase, JS toggelt display). */
.sq-phase-panel {
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
}
/* Fix CW1: der Balken sass als eigener Block UNTER dem Panel — im 46px-Band ist dafuer
   kein Platz. Er steht jetzt inline neben "Dein Zug" (Zeile 2 der Phasenzone). Nur die
   Achse dreht sich, Inhalt und Schreiber (renderOvPhaseStatus()) bleiben unveraendert;
   dessen `display:flex` beim Einblenden greift weiterhin. */
.sq-phase-panel-deploy {
  flex-direction: row;
  align-items: center;
  gap: 4px;
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.sq-phase-panel-deploy-label {
  font-family: 'Orbitron', sans-serif;
  font-size: 7px;
  letter-spacing: 1px;
  color: rgba(212,168,67,0.6);
}
.sq-phase-panel-deploy-segments {
  display: flex;
  gap: 3px;
}

/* ── Fix DE1 (Punkt 2, 2026-08-23): das gedrueckte Werkzeugsymbol ────────────────────
   Zielbild (mockups/hud-neuaufbau-vollversion.html): `.tool.act` — Rahmen und Glyphe
   wechseln auf Gold, solange die zugehoerige Schublade offen ist. Gesetzt/entfernt wird
   die Klasse ausschliesslich von _sqApplyDrawer() (game-chat.js), nach jedem Render neu.
   Die Grundmasse der Knoepfe stehen weiterhin inline im Markup beider Icon-Leisten —
   hier steht nur, was der aktive Zustand aendert. */
.sq-tool-active {
  border-color: var(--gold) !important;
  color: var(--gold) !important;
  background: rgba(240, 180, 41, 0.14) !important;
}

/* ── Fix CW1 (2026-08-22): Zone 2 (Phase + Timer-Ring) und Zone 4 (Hinweis) ──────────── */
.sq-banner-zone {
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 0 10px;
}
/* Zielbild: .zone.phase{flex:1;justify-content:flex-end} — der Phasenblock haengt am
   INNENRAND seiner Zone, also direkt links neben den Siegpunkten. */
.sq-banner-phase {
  /* Fix EB1: basis 250 = die heute gemessene Breite im Bezugsformat. Sie MUSS mit der
     basis der Hinweiszone uebereinstimmen, sonst teilen sich die beiden den Zuwachs nicht
     mehr haelftig — die Uebersicht bleibt dadurch bei JEDER Buehnenbreite exakt wie
     bisher (nachgerechnet: 1475 -> 347,65 gegen gemessene 347,7). */
  flex: 1 1 250px;
  /* ══ Fix EG1 (2026-08-25): der Deckel, ab dem die Hinweiszone den Zuwachs bekommt ═══
     Die basis bleibt unangetastet — im Bezugsformat (Buehne 1280) gibt es gar keinen
     Zuwachs zu verteilen (312+250+152+250+312 = 1276 = Bannerbreite, gemessen: alle vier
     Zonenluecken 0). Der Deckel wirkt deshalb ERST oberhalb von 1280; dort faellt alles,
     was diese Zone nicht mehr nimmt, an die Hinweiszone, weil sie die einzige Zone ohne
     Deckel ist.
     WARUM 300 UND NICHT 250 (= gar kein Zuwachs mehr): die Mittelzone muss in BEIDEN
     Ansichten am selben Fleck sitzen (Zusage CY1, geprueft mit 1px Toleranz). Ihre Mitte
     liegt bei 2 + 312 + Zone2 + Mittelzone/2 — in der Uebersicht also 2+312+Z2+76, im
     Kampf 2+312+Z2+125 (Mittelzone dort 250 statt 152). Beide Ansichten wandern nur dann
     gleich weit, wenn die Uebersichts-Phasenzone genau 23 px MEHR Zuwachs behaelt als die
     Initiativezone: 300 = 250 + (27 + 46/2). Die 27 stammen aus dem Deckel der
     Initiativezone (251, s. .sq-banner-ini), die 46 sind der EB1-Zuwachs der
     Kampf-Phasenzone (204 -> 250), der nicht zurueckgenommen wird.
     Das ist zugleich das MAXIMUM: jeder px weniger Deckel hier zwingt die Initiativezone
     unter die 250 der Kampf-Phasenzone und bricht die zweite CY1-Zusage
     ("die Initiativezone ist breiter als die Mittelzone").
     Gemessen (scripts/eg1-probe1.js): Buehne 1475 -> Phasenzone 300 statt 347,6,
     Hinweiszone 395 statt 347,6. Ihr Inhalt braucht dort 175..190 px, der Deckel laesst
     ihr also weiterhin ueber 100 px Luft. */
  max-width: 300px;
  justify-content: flex-end;
  gap: 10px;
}
/* Zielbild: .zone.hint{flex:1;justify-content:flex-start}. Die Zone bleibt LEER — sie ist
   nur das Mass, nach dem _sqPlaceSelectionHint() (game-combat.js) die eine, ausserhalb der
   Bildschirme lebende Hinweisleiste ausrichtet. */
.sq-banner-hint {
  /* Fix EB1: basis = die im Bezugsformat gemessene Breite, damit dort nichts wandert.
     Die Zone steht in BEIDEN Bannern, ist aber unterschiedlich breit (Uebersicht 250,
     Kampf 224,2) — deshalb der Kampf-Wert praefixgenau darunter statt eines Mittelwerts.
     Die Zusage "die Hinweiszone wird nicht schmaler" gilt damit im Bezugsformat exakt. */
  flex: 1 1 250px;
  justify-content: flex-start;
}
#cb-bar-top .sq-banner-hint { flex-basis: 224px; }

/* Das Phasen-Panel im Banner: kein Kaestchen mehr (kein Hintergrund, kein clip-path,
   kein Rahmen-Padding), sondern ein rechtsbuendiger Mikro-Block aus zwei bis drei Zeilen.
   renderOvPhaseStatus()/renderCombatPhaseStatus() setzen weiterhin ps.style.borderColor —
   ohne border-style laeuft das ins Leere und aendert nichts; die Puls-Regeln
   #ov-phase-status.sq-waiting-glow / #cb-phase-status.sq-waiting-glow (weiter oben)
   bringen ihre eigene border-width/-style mit und wirken unveraendert. */
.sq-banner-phase-panel {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  min-width: 0;
  clip-path: none;
  background: none;
  padding: 0 2px;
  pointer-events: none;
}
.sq-banner-phase-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 13px;
  font-weight: 700;
  color: #33cccc;
  letter-spacing: 0.4px;
  line-height: 1.05;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.sq-banner-phase-line2 {
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-width: 0;
}
.sq-banner-phase-turn {
  font-family: 'Rajdhani', sans-serif;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--gold);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Dritte Mikro-Zeile: die Aktionszeile aus dem alten Panel. Das Zielbild kennt sie nicht,
   sie traegt aber Information, die sonst ersatzlos verschwaende (Abweichung im Bericht
   begruendet). Klein und einzeilig, damit die Zone im 46px-Band bleibt. */
.sq-banner-phase-action {
  font-family: 'Rajdhani', sans-serif;
  font-size: 8.5px;
  color: rgba(255, 255, 255, 0.45);
  font-style: italic;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  text-align: right;
}

/* ── Fix CW1: die Hinweisleiste (Zone 4) ──────────────────────────────────────────────
   Optik 1:1 aus dem Zielbild (.hintbox): angular beschnittener Goldrahmen, warmes Gold auf
   dunklem Verlauf. Position/Groesse kommen ausschliesslich inline von
   _sqPlaceSelectionHint() — hier bewusst KEIN left/top/width (Fehlerklasse aus CJ1:
   zwei Quellen fuer dieselbe Zahl). */
.sq-hint-bar {
  position: absolute;
  z-index: 40;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  /* Zielbild: padding 6px 13px, Schrift 12.6px. Gemessen (scripts/cw1-probe2.js ueber ALLE
     44 HINT_-Texte in beiden Sprachen) braucht der laengste Hinweis 496px, der haeufigste
     ("Handkarte anklicken, um sie einzusetzen") 252px — die Hinweiszone bietet bei 1280px
     Buehnenbreite rund 236px. Der laengste Fall wird also IMMER gekuerzt; das sieht auch
     das Zielbild so vor (.hintbox traegt dort text-overflow:ellipsis). Enger gesetzt ist
     die Leiste nur so weit, dass der HAEUFIGSTE Hinweis bei 1280x720 vollstaendig steht:
     11.5px statt 12.6px und 10px statt 13px seitliches Polster. Begruendete Abweichung. */
  padding: 5px 10px;
  border: 1px solid rgba(240, 160, 0, 0.55);
  background: linear-gradient(180deg, rgba(240, 160, 0, 0.15), rgba(240, 160, 0, 0.04));
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  font-family: 'Rajdhani', sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  color: #ffd98a;
  letter-spacing: 0.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.sq-deploy-seg {
  width: 16px;
  height: 5px;
  background: rgba(212,168,67,0.15);
  border: 1px solid rgba(212,168,67,0.3);
  border-radius: 1px;
}
.sq-deploy-seg-filled {
  background: #d4a843;
  border-color: #d4a843;
  box-shadow: 0 0 4px rgba(212,168,67,0.5);
}

/* FIX (Teil 2, 2026-07-08): HOLD-Ghost-Stil — nur der neutrale "kein Controller"-
   Zustand (fraktionsfarbene Pille bei kontrollierten Locations bleibt unverändert). */
.sq-hold-badge {
  font-family: 'Orbitron', sans-serif;
  font-size: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: rgba(139, 147, 168, 0.7);
  border: 1px solid rgba(139, 147, 168, 0.4);
  background: transparent;
  padding: 2px 8px;
  clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px);
  white-space: nowrap;
  transition: border-color 0.2s, color 0.2s;
}
.sq-hold-badge:hover {
  border-color: #f0b429;
  color: #f0b429;
}

/* ══════════════════════════════════════════════════════════════════════════
   Teil 3 (2026-07-08): Kommando-Button — V7 "Orbit-Ring" (Standard) /
   V6 "Zielmarke" (Kampfphase) + Kommando-Flyout.
   ══════════════════════════════════════════════════════════════════════════ */

/* --ov-ring-color wird von _renderPhasePanelV3() je Zustand gesetzt (Teal/Grau).
   Alle Ring-Elemente nur transform/opacity-Animationen (GPU-Compositing, keine
   Repaints großer Flächen — Performance-Vorgabe aus dem Prompt).
   FIX (Teil 3, Smoke-Test): display:flex hier statt inline im Template — inline
   position:relative auf #ov-main-btn-wrap hatte LayoutEngines eigene
   position:absolute-Zuweisung verhindert (applyLayout() setzt position/top/left/
   width/height inline; ein externes display:flex/align-items kollidiert damit
   NICHT, weil es andere CSS-Properties betrifft). position bleibt unangetastet. */
#ov-main-btn-wrap, #cb-main-btn-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  --ov-ring-color: #2dd4bf;
}
/* FIX AI1 (2026-08-16): war top:50%/left:50%/width:172px/height:172px/margin:-86px —
   fixe Pixelwerte, unabhaengig von der tatsaechlichen Groesse von #ov-main-btn-wrap.
   inset:0 fuellt stattdessen IMMER die volle (jetzt wieder ganz normal per LayoutEngine
   gesetzte, feste) Box von #ov-main-btn-wrap — Ring und Button bleiben
   dadurch bei jeder Groesse konzentrisch. */
.ov-orbit-outer,
.ov-orbit-dashed,
.ov-orbit-inner,
.ov-zielmarke-frame {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  transition: opacity 0.3s ease, border-color 0.3s ease, inset 0.2s ease;
}
.ov-orbit-outer {
  border: 1px solid var(--ov-ring-color);
  opacity: 0.25;
}
.ov-orbit-dashed {
  border: 2px dashed var(--ov-ring-color);
  opacity: 0.7;
  animation: ovOrbitSpin 24s linear infinite;
}
.ov-orbit-inner {
  inset: 7px;
  border: 1px solid transparent;
  border-top-color: var(--ov-ring-color);
  border-right-color: var(--ov-ring-color);
  animation: ovOrbitSpinReverse 10s linear infinite;
}
@keyframes ovOrbitSpin        { from { transform: rotate(0deg); }  to { transform: rotate(360deg); } }
@keyframes ovOrbitSpinReverse { from { transform: rotate(0deg); }  to { transform: rotate(-360deg); } }

/* "Warten"-Zustand: Rotation komplett gestoppt (Akku/CPU — Prompt-Vorgabe:
   "Stillstand = nichts zu tun"). */
#ov-main-btn-wrap[data-anim-paused="1"] .ov-orbit-dashed,
#ov-main-btn-wrap[data-anim-paused="1"] .ov-orbit-inner,
#cb-main-btn-wrap[data-anim-paused="1"] .ov-orbit-dashed,
#cb-main-btn-wrap[data-anim-paused="1"] .ov-orbit-inner {
  animation-play-state: paused;
}

/* FIX BU1 (Leerlauf-Bewegung, Baustein "Warte-Ring"): genau EIN "Warten"-Zustand aus den
   obigen — "Gegner ist am Zug" (data-idle-wait="1", s. game-command-button.js) — laesst
   den ohnehin vorhandenen, langsamen Orbit-Ring (24s/10s) bei aktivem Baustein weiter-
   laufen statt ihn zu stoppen. Reine Rotation (transform), kein Layout-Risiko fuer FX-
   Anker (der Button ist nie ein getBoundingClientRect()-Ziel von Kampf-FX) — deshalb
   genuegt hier animation-play-state (anders als beim Karten-Atmen). sq-idle-suspended
   pausiert wieder, falls waehrend der Wartezeit z.B. ein Modal geoeffnet wird. */
body.sq-idle-on.sq-idle-ring-on:not(.sq-idle-suspended) #ov-main-btn-wrap[data-idle-wait="1"] .ov-orbit-dashed,
body.sq-idle-on.sq-idle-ring-on:not(.sq-idle-suspended) #ov-main-btn-wrap[data-idle-wait="1"] .ov-orbit-inner,
body.sq-idle-on.sq-idle-ring-on:not(.sq-idle-suspended) #cb-main-btn-wrap[data-idle-wait="1"] .ov-orbit-dashed,
body.sq-idle-on.sq-idle-ring-on:not(.sq-idle-suspended) #cb-main-btn-wrap[data-idle-wait="1"] .ov-orbit-inner {
  animation-play-state: running;
}

/* V6 "Zielmarke" — geschlossener Gold-Ring + 4 Kardinal-Kerben + der (jetzt statische,
   gold eingefärbte) gestrichelte Ring aus V7 als "innerer gestrichelter Ring". */
.ov-zielmarke-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid #f0b429;
}
.ov-zielmarke-notch {
  position: absolute;
  background: #f0b429;
}
.ov-zn-top    { top: 0;    left: calc(50% - 1.5px); width: 3px;  height: 16px; }
.ov-zn-bottom { bottom: 0; left: calc(50% - 1.5px); width: 3px;  height: 16px; }
.ov-zn-left   { left: 0;   top: calc(50% - 1.5px);  width: 16px; height: 3px; }
.ov-zn-right  { right: 0;  top: calc(50% - 1.5px);  width: 16px; height: 3px; }
.ov-zielmarke-frame { opacity: 0; }

#ov-main-btn-wrap[data-look="v6"] .ov-orbit-outer,
#ov-main-btn-wrap[data-look="v6"] .ov-orbit-inner,
#cb-main-btn-wrap[data-look="v6"] .ov-orbit-outer,
#cb-main-btn-wrap[data-look="v6"] .ov-orbit-inner {
  opacity: 0;
}
#ov-main-btn-wrap[data-look="v6"] .ov-orbit-dashed,
#cb-main-btn-wrap[data-look="v6"] .ov-orbit-dashed {
  opacity: 0.5;
  animation-play-state: paused;
  border-color: #f0b429;
}
#ov-main-btn-wrap[data-look="v6"] .ov-zielmarke-frame,
#cb-main-btn-wrap[data-look="v6"] .ov-zielmarke-frame {
  opacity: 1;
}

/* Puls (drop-shadow-Glow) NUR wenn klickbar (Prompt-Vorgabe) — data-pulse wird von
   game-command-button.js nur bei aktionsfähigem Zustand gesetzt. */
@keyframes ovMainPulseGlow {
  0%, 100% { box-shadow: 0 0 6px 1px var(--ov-ring-color); }
  50%      { box-shadow: 0 0 16px 4px var(--ov-ring-color); }
}
#ov-main-btn-wrap[data-pulse="1"] .ov-orbit-outer,
#cb-main-btn-wrap[data-pulse="1"] .ov-orbit-outer {
  animation: ovMainPulseGlow 1.8s ease-in-out infinite;
}
#ov-main-btn-wrap[data-look="v6"][data-pulse="1"] .ov-zielmarke-ring,
#cb-main-btn-wrap[data-look="v6"][data-pulse="1"] .ov-zielmarke-ring {
  animation: ovMainPulseGlow 1.8s ease-in-out infinite;
  --ov-ring-color: #f0b429;
}

/* UMBAU Z1 (2026-08-13): Options-Liste IM Kommando-Button — ersetzt sowohl die
   alte Ortswahl-Flyout-Struktur (`.sq-circle-choice`/`-open`/`-header`/`-rows`/
   `-cancel`, Cross-Fade-Toggle per Klick, s. Git-History) ALS AUCH die grüne
   Knopfspalte (`#combat-action-btns`). `.sq-cmd-opts` liegt IMMER direkt sichtbar
   im Button (kein Klick-zum-Öffnen mehr, s. Aufgabe "Kein Doppelklick-Umweg") —
   der Entrance-Fade beim Zustandswechsel läuft jetzt über `#ov-main-btn-normal`/
   `#cb-main-btn-normal` selbst (_paintCmdButton() in game-command-button.js).
   `.sq-circle-choice-row`/`.sq-circle-row-name`/`.sq-circle-row-sp` bleiben (Name
   historisch von der Ortswahl, jetzt generisch für JEDE Options-Zeile: Orte,
   Aktionskarten, Schiffe, Dodge/Got-Ya-Optionen). */
/* FIX AE1 (2026-08-16): Hierarchie der Hauptaktion — .sq-cmd-primary umschliesst
   lbl/sub/arrow (Markup: game-overview.js/game-combat.js). Ungefuellt (kein .filled)
   = bisheriges Verhalten (reiner Text, fuer dim-Zustaende UND fuer reine
   Auswahl-Zustaende ohne Hauptaktion — dort bleibt .sq-cmd-primary leer, s.
   _buildCmdSpec()-Zweige ohne spec.big). .filled = die einzige Hauptaktion im
   Zustand: gefuellte goldene Flaeche, dunkle Schrift, Pfeil — das auffaelligste
   Element im Kreis (Betreiber-Vorgabe Abschnitt 2), klar abgesetzt von den
   flacheren Listenzeilen darunter. */
.sq-cmd-primary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 100%;
}
.sq-cmd-primary.filled {
  background: linear-gradient(180deg, #f3c968 0%, #d4a843 55%, #b8860b 100%);
  border-radius: 12px;
  padding: 7px 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.35), inset 0 1px 0 rgba(255,255,255,0.35);
}
.sq-cmd-primary-lbl {
  font-family: 'Orbitron', sans-serif;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 1.5px;
  line-height: 1.3;
  text-align: center;
  color: #d4a843;
  text-shadow: 0 0 12px rgba(212,168,67,0.4);
}
.sq-cmd-primary.filled .sq-cmd-primary-lbl {
  color: #241a08;
  text-shadow: none;
}
.sq-cmd-primary-sub {
  font-size: 7px;
  letter-spacing: 1px;
  color: rgba(140,150,170,0.4);
}
.sq-cmd-primary.filled .sq-cmd-primary-sub {
  color: rgba(36,26,8,0.65);
}
.sq-cmd-primary-arrow {
  display: none;
  font-size: 11px;
  line-height: 1;
  color: #241a08;
}
.sq-cmd-primary.filled .sq-cmd-primary-arrow {
  display: block;
}
/* FIX AI1 (2026-08-16): der Kreis hat jetzt eine feste Groesse (kein Wachstum mehr,
   s. game-command-button.js) — max-height+overflow-y:auto gelten deshalb IMMER,
   nicht mehr bedingt ueber eine JS-gesetzte .scroll-Klasse (die Stufenlogik samt
   Schwellwerten ist komplett entfallen). overflow-y:auto zeigt eine Scrollleiste nur,
   wenn der Inhalt tatsaechlich ueberläuft — passt der Inhalt (z. B. "Kopf + 3
   Eintraege"), bleibt die Regel wirkungslos, kein Sonderfall noetig. */
.sq-cmd-opts {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  width: 100%;
  margin-top: 2px;
  max-height: 130px;
  overflow-y: auto;
  padding-right: 2px;
}
.sq-cmd-opts:empty { margin-top: 0; }
.sq-cmd-opts::-webkit-scrollbar { width: 4px; }
.sq-cmd-opts::-webkit-scrollbar-thumb { background: rgba(240,180,41,0.4); border-radius: 2px; }
/* FIX AI1: dezenter Hinweis "weitere Eintraege" — sichtbar/unsichtbar wird per JS
   ueber tatsaechlichen DOM-Overflow entschieden (game-command-button.js), keine
   Stufe/Schwellwert. Sitzt als eigene Zeile UNTER .sq-cmd-opts (also selbst nicht
   Teil des scrollenden Bereichs) — bleibt dadurch immer sichtbar, wenn aktiv. */
.sq-cmd-more {
  display: none;
  text-align: center;
  font-size: 9px;
  letter-spacing: 1px;
  color: rgba(240,180,41,0.7);
  margin-top: 2px;
}
/* FIX AE1 (2026-08-16, Hierarchie): war ein umrandeter, eckenbeschnittener Kasten
   pro Zeile (border+clip-path) — sah dadurch selbst wie ein Knopf aus und
   konkurrierte optisch mit der eigentlichen Hauptaktion (Betreiber-Befund:
   "die Listeneinträge haben Rahmen und sehen nach Knopf aus"). Jetzt nur noch eine
   Trennlinie zur vorigen Zeile, zurückhaltender Grund — bleibt klickbar, hebt sich
   beim Hover weiterhin deutlich ab, tritt aber nicht mehr gegen die Hauptaktion an. */
.sq-circle-choice-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 5px 6px;
  border: none;
  border-top: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.02);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
  flex-shrink: 0;
}
.sq-cmd-opts > .sq-circle-choice-row:first-child {
  border-top: none;
}
.sq-circle-choice-row:hover {
  border-top-color: rgba(240, 180, 41, 0.4);
  background: rgba(240, 180, 41, 0.14);
}
.sq-circle-choice-row.ghost {
  background: transparent;
  justify-content: center;
}
.sq-circle-choice-row.ghost .sq-circle-row-name {
  color: rgba(255,255,255,0.4);
  font-size: 10px;
  letter-spacing: 1.2px;
  max-width: none;
}
.sq-circle-choice-row.ghost:hover {
  background: rgba(240, 180, 41, 0.08);
}
.sq-circle-choice-row.disabled {
  cursor: default;
  pointer-events: none;
}
.sq-circle-row-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 12px;
  font-weight: 700;
  color: #e8e6df;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}
.sq-circle-row-sp {
  font-family: 'Orbitron', sans-serif;
  font-weight: 700;
  font-size: 11px;
  color: #f0c040;
  flex-shrink: 0;
}

/* NEU (Runde 7): Schiffe-Bilanz am Ort-Banner, nur während Hover einer Ort-Wahl-Zeile
   sichtbar (toggleCombatChoice() setzt textContent + display). */
.sq-loc-balance-hover {
  font-family: 'Share Tech Mono', monospace;
  font-size: 8px;
  color: rgba(240, 180, 41, 0.85);
  margin-top: 1px;
}

/* Angreifen-Button an umkämpften Orten (Runde 5) — ersetzt an genau diesen Orten
   die HOLD/Controller-Anzeige, gleicher Platz, angular wie die Ortswahl-Chips. */
.sq-loc-attack-btn {
  font-family: 'Orbitron', sans-serif;
  font-size: var(--sq-loc-st-fs, clamp(8px, 0.7vw, 12px));
  padding: clamp(1px, 0.2vh, 4px) clamp(6px, 0.8vw, 14px);
  letter-spacing: 1px;
  text-transform: uppercase;
  color: #f0b429;
  background: rgba(240, 180, 41, 0.12);
  border: 1px solid #f0b429;
  clip-path: polygon(4px 0, 100% 0, 100% calc(100% - 4px), calc(100% - 4px) 100%, 0 100%, 0 4px);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s, box-shadow 0.15s;
}
.sq-loc-attack-btn:hover {
  background: rgba(240, 180, 41, 0.28);
  box-shadow: 0 0 8px rgba(240, 180, 41, 0.4);
}

/* Brett-Highlight (Kombi) — Hover auf eine Ort-Zeile pulsiert die zugehörige
   Location gold, gleiche Keyframes-Familie wie .sq-targetable (rote Zielwahl). */
@keyframes sqBoardHighlightPulse {
  0%, 100% { box-shadow: inset 0 0 0 2px rgba(240,180,41,0.55), 0 0 8px rgba(240,180,41,0.35); }
  50%      { box-shadow: inset 0 0 0 2px rgba(240,180,41,0.95), 0 0 16px rgba(240,180,41,0.7); }
}
.ov-loc.sq-board-highlight {
  animation: sqBoardHighlightPulse 1s ease-in-out infinite;
}

/* FIX 1.6.1: #ov-locations zweite Def. mit !important entfernt
   — top/left/right/bottom sind Layout-Properties, werden von applyLayout gesetzt */

/* FIX 1.6.1: orphaned CSS-Block entfernt (kein Selektor, vermutlich Rest von #ov-hand)
   — enthielt einen spurious closing } der zur pre-existing Brace-Imbalance beitrug */


/* ACHTUNG (Fix DC1, 2026-08-22): width/height/min-width hier sind nur der Zustand VOR
   dem ersten fitHandCards()-Lauf (game-card-layout.js) — die echte Groesse kommt von dort
   als Inline-Style. Die `min-width` unten hat genau deshalb bis DC1 stillschweigend
   gewonnen: eine Inline-BREITE schlaegt jede CSS-Breite, aber KEINE CSS-`min-width`.
   Bei 19 Handkarten rechnete fitHandCards() 58 px und bekam 90 px — die Reihe war dadurch
   924 px breit in einer 320-px-Zone. fitHandCards() setzt min-/max-width jetzt selbst mit;
   wer hier etwas aendert, aendert nur noch den Vorzustand. */
.hand-card {
  width:  clamp(82px, 10vw, 124px);
  height: clamp(112px, 15.5vh, 166px);
  /* FIX 2: Allow shrinking when many cards */
  flex-shrink: 1; min-width: clamp(58px, 7vw, 90px);
  cursor: pointer;
  position: relative;
  transition: transform 0.15s, z-index 0s;
  user-select: none;
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  clip-path: polygon(8px 0, calc(100% - 8px) 0, 100% 8px, 100% calc(100% - 8px), calc(100% - 8px) 100%, 8px 100%, 0 calc(100% - 8px), 0 8px);
  overflow: hidden;
  display: flex; flex-direction: column;
}
.hand-card:hover {
  transform: translateY(-20px) scale(1.15);
  z-index: 50;
  /* FIX 2: Full size on hover */
  flex-shrink: 0; min-width: clamp(90px, 10vw, 124px);
  border-color: var(--gold);
  box-shadow: 0 16px 40px rgba(0,0,0,0.7), 0 0 16px var(--gold-glow);
}
.hand-card.selected {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold-glow);
  transform: translateY(-10px) scale(1.05);
  z-index: 10;
}
.hand-card.disabled { opacity: 0.3; cursor: not-allowed; pointer-events: none; }
.hand-card img,
.hand-card-img,
.ecard,
.card-canvas,
.loc-art,
.ship-tok-v2 img,
.ship-tok-combat img,
[class*="card"] img,
[class*="tok"] img {
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
  -moz-user-drag: none;
  draggable: false;
}
/* NEW: UI v3 Hand — endgueltige Loesung (2026-05-01) */
/* Wrapper-Groesse kommt aus JS (wrapper.style.width/height = 115px/161px) */

/* FIX 1.6.1: position/bottom/left/right/height entfernt — Layout-Properties,
   werden von applyLayout gesetzt (ov-hand ist in layout-config.js) */
/* FIX 1.6.4: display/flex-direction/align-items/justify-content/overflow entfernt
   — werden vom 1.6.3-Block (#ov-hand, #ov-enemy-hand) übernommen.
   Übrig bleiben nur z-index + pointer-events (Interaction, kein Layout). */
#screen-overview #ov-hand {
  z-index: 25 !important;
  pointer-events: auto !important;
}

/* FIX K3 (Section 4): waehrend der Starthand-Reveal-Sequenz (playStartingHandRevealIfNeeded(),
   game-overlays.js) ist die Hand sichtbar, aber nicht anklickbar — verhindert Deploy-Klicks
   auf Karten, die der Spieler in der Sequenz noch nicht "gesehen" hat. */
#screen-overview #ov-hand.sq-hand-reveal-blocking {
  pointer-events: none !important;
}

#screen-overview .hand-card {
  overflow: visible !important;
  cursor: pointer;
  position: relative;
}
#screen-overview .hand-card:hover {
  z-index: 100 !important;
}


/* ═══════════════════════════════════════════════════════════════
   NEW: Match-Found + Würfelwurf Overlays — portiert aus game-v2.css
   Zeilen 2896-3136 (Session 1.4f, 2026-05-05)
   showMatchFoundOverlay / showStartRollOverlay erzeugen DOM-Elemente
   mit diesen Klassen am document.body.
   ═══════════════════════════════════════════════════════════════ */
.sq-overlay {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #030508;
  animation: sqOverlayIn 0.35s ease-out;
  font-family: 'Orbitron', sans-serif;
}
.sq-overlay.sq-overlay-out {
  animation: sqOverlayOut 0.4s ease-in forwards;
}
@keyframes sqOverlayIn {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes sqOverlayOut {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.02); }
}

.sq-overlay-inner {
  width: 100%;
  max-width: 580px;
  padding: 40px 24px;
  text-align: center;
  background: rgba(3, 5, 8, 0.65);
  border-radius: 12px;
}

/* Match-Found */
.sq-mf-label {
  font-size: 9px;
  color: rgba(51, 204, 204, 0.5);
  letter-spacing: 3px;
  margin-bottom: 24px;
}
.sq-mf-players {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  margin-bottom: 28px;
}
.sq-mf-player {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 20px 16px;
}
.sq-mf-icon {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid;
}
.sq-mf-icon.vs {
  background: rgba(220, 80, 80, 0.12);
  border-color: rgba(220, 80, 80, 0.5);
}
.sq-mf-icon.ued {
  background: rgba(51, 204, 204, 0.1);
  border-color: rgba(51, 204, 204, 0.4);
}
/* FIX K1 (2026-07-23): .sq-mf-icon-dot/-sq (Punkt/Quadrat-Platzhalter) ersetzt durch
   echtes Fraktionslogo — global gegrept, keine weiteren Referenzen. */
.sq-mf-icon-logo {
  width: 40px;
  height: auto;
  display: block;
}
.sq-mf-faction {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 1px;
}
.sq-mf-faction.vs  { color: rgba(220, 100, 100, 0.95); }
.sq-mf-faction.ued { color: rgba(51, 204, 204, 0.95); }
.sq-mf-name {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.75);
  letter-spacing: 1px;
}
.sq-mf-role {
  font-size: 8px;
  letter-spacing: 1px;
  opacity: 0.45;
}
.sq-mf-role.vs  { color: rgba(220, 80, 80, 1); }
.sq-mf-role.ued { color: rgba(51, 204, 204, 1); }
.sq-mf-divider {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
}
.sq-mf-vs-txt {
  font-size: 22px;
  font-weight: 700;
  color: rgba(212, 168, 67, 0.9);
  letter-spacing: 4px;
}
.sq-mf-vline {
  width: 1px;
  height: 56px;
  background: rgba(212, 168, 67, 0.2);
}
.sq-mf-countdown-label {
  font-size: 9px;
  color: rgba(255, 255, 255, 0.22);
  letter-spacing: 2px;
  margin-bottom: 10px;
}
.sq-mf-countdown {
  font-size: 36px;
  font-weight: 700;
  color: #d4a843;
  letter-spacing: 2px;
}

/* Würfelwurf */
.sq-dr-label {
  font-size: 9px;
  color: rgba(212, 168, 67, 0.5);
  letter-spacing: 3px;
  margin-bottom: 28px;
}
/* FIX K7 (2026-07-23, Mockup 2): Flexbox (content-getriebene Breite, "vs" nur
   rechnerisch mittig) -> 3-Spalten-Grid (1fr | 60px | 1fr). Beide Seiten sind jetzt
   IMMER gleich breit, unabhängig davon wie lang der Fraktions-/Spielername auf einer
   Seite ist — die feste 60px-Mittelspalte ("VS") bleibt dadurch optisch zentriert. */
.sq-dr-grid {
  display: grid;
  grid-template-columns: 1fr 60px 1fr;
  align-items: center;
  margin-bottom: 24px;
}
.sq-dr-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.sq-dr-faction {
  font-size: 10px;
  letter-spacing: 1px;
}
.sq-dr-faction.vs  { color: rgba(220, 100, 100, 0.65); }
.sq-dr-faction.ued { color: rgba(51, 204, 204, 0.65); }
.sq-dr-name {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.45);
  letter-spacing: 1px;
}
/* FIX K7 (Mockup 2): 76px -> 64px ("Würfel-Box 64px"). */
.sq-dr-die {
  width: 64px;
  height: 64px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  font-weight: 700;
  transition: transform 0.05s;
  border: 2px solid;
}
.sq-dr-die.vs {
  background: rgba(220, 80, 80, 0.1);
  border-color: rgba(220, 80, 80, 0.4);
  color: rgba(220, 100, 100, 0.9);
}
.sq-dr-die.ued {
  background: rgba(51, 204, 204, 0.08);
  border-color: rgba(51, 204, 204, 0.3);
  color: rgba(51, 204, 204, 0.9);
}
.sq-dr-die.winner {
  border-width: 3px;
  transform: scale(1.08);
}
.sq-dr-die.vs.winner  { border-color: rgba(220, 80, 80, 0.9); }
.sq-dr-die.ued.winner { border-color: rgba(51, 204, 204, 0.9); }
.sq-dr-vs-txt {
  font-size: 18px;
  color: rgba(255, 255, 255, 0.18);
  font-weight: 700;
  text-align: center;
}
.sq-dr-result {
  font-size: 13px;
  color: rgba(255, 255, 255, 0.35);
  letter-spacing: 2px;
  min-height: 22px;
  margin-bottom: 6px;
}
.sq-dr-winner {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 2px;
  min-height: 28px;
  transition: opacity 0.3s;
}

/* Würfelwurf Countdown Timer */
.sq-dr-timer {
  margin-top: 16px;
  font-size: 11px;
  color: rgba(255, 255, 255, 0.25);
  letter-spacing: 2px;
}
.sq-dr-timer-bar-wrap {
  width: 200px;
  height: 3px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 2px;
  margin: 6px auto 0;
  overflow: hidden;
}
.sq-dr-timer-bar {
  height: 100%;
  background: rgba(212, 168, 67, 0.6);
  border-radius: 2px;
  transition: width 1s linear;
}

/* ═══════════════════════════════════════════════════════════════════════════
   FIX 1.6.3 / 1.6.6: Hand-Container — minimales CSS, JS-basiertes Card-Sizing
   ─────────────────────────────────────────────────────────────────────────
   Card-Größen werden in fitHandCards() (game-overview.js) berechnet und als
   inline-style auf .hand-card / .enemy-hand-card gesetzt. CSS macht nur:
   - Container-Layout (flex, center)
   - Rotation für Enemy-Hand (180°)
   - Visuelle Properties (Border, Border-Radius)
   ═══════════════════════════════════════════════════════════════════════════ */

#ov-hand,
#ov-enemy-hand {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
}

/* z-index + pointer-events für ov-enemy-hand (waren vorher inline, seit 1.6.3) */
#ov-enemy-hand {
  z-index: 15;
  pointer-events: none;
}

/* FIX 1.6.8: .enemy-hand-rotated Wrapper komplett entfernt — Cards liegen jetzt direkt
   in #ov-enemy-hand (1:1 symmetrisch zur eigenen Hand in #ov-hand) */

/* Visuelle Eigenschaften für Cards (Größe kommt aus fitHandCards in JS) */
.hand-card {
  position: relative;
  flex-shrink: 0;
}

.enemy-hand-card {
  position: relative;
  flex-shrink: 0;
  transform-origin: bottom center;
  border-radius: 4px;
  overflow: hidden;
}

#ov-enemy-hand .enemy-hand-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}

/* ─── field-highlight — Hover-Markierung für Kampf-Buttons (2026-05-11) ─── */
/* Wird von highlightFieldCard(instanceId, true/false) gesetzt */
.field-highlight {
  box-shadow: 0 0 20px rgba(255, 170, 0, 0.85),
              0 0 40px rgba(255, 170, 0, 0.4) !important;
  border-color: #ffaa00 !important;
  z-index: 10;
  position: relative;
  transition: box-shadow 0.2s, border-color 0.2s;
}

/* ═══════════════════════════════════════════════════════════
   LOBBY BUTTONS — sync von game-v2.css (2026-05-01)
   ═══════════════════════════════════════════════════════════ */

.play-actions-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  width: 100%;
  margin-bottom: 10px;
}

.private-panel {
  min-height: 72px;
}

.play-action-btn {
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  border-radius: 0;
  padding: 16px 10px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  font-family: 'Orbitron', sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
  transition: transform .15s, box-shadow .15s, opacity .15s;
}
.play-action-btn:hover { opacity: 1; transform: translateY(-2px); }
.play-action-btn:active { transform: scale(0.97); }

.play-action-primary {
  background: linear-gradient(165deg, rgba(212,168,67,.16), rgba(12,9,4,.9));
  border: 1px solid rgba(212,168,67,0.45);
  color: #d4a843;
}
.play-action-primary:hover { box-shadow: 0 0 24px rgba(212,168,67,.35); }

.play-action-secondary {
  background: linear-gradient(165deg, rgba(51,204,204,.12), rgba(4,12,11,.9));
  border: 1px solid rgba(51,204,204,0.25);
  color: rgba(51,204,204,0.85);
  padding: 14px 12px;
}
.play-action-secondary:hover { box-shadow: 0 0 24px rgba(51,204,204,.3); }

/* Fix CD1: RANKED-Platzhalter (Backbone-Login-Screen Angleichung, 2026-08-08) entfernt —
   der Anmelde-Weg IST jetzt der gewertete Weg, ein zweiter "bald verfuegbar"-Knopf
   daneben wuerde der Assertion "genau ein Startknopf" widersprechen. .play-action-grid-
   single (unten) zentriert den verbliebenen Knopf statt der Zwei-Spalten-Aufteilung. */
.play-actions-grid-single {
  grid-template-columns: minmax(0, 260px);
  justify-content: center;
}

.play-action-sub {
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 1.5px;
  opacity: 0.5;
}

.play-action-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
}

.play-select {
  font-size: 12px !important;
  padding: 6px 8px !important;
  background: rgba(0,0,0,0.7) !important;
  border: 1px solid rgba(51,204,204,0.35) !important;
  color: rgba(51,204,204,0.95) !important;
  border-radius: 4px !important;
  cursor: pointer;
  min-width: 80px !important;
}
.play-select option {
  background: #0a1020 !important;
  color: rgba(51,204,204,0.95) !important;
  font-size: 12px !important;
  padding: 6px !important;
}

/* Privater Raum Box */
.private-room-box {
  width: 100%;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 6px;
  margin-bottom: 10px;
  overflow: hidden;
}

.private-room-label {
  font-family: 'Orbitron', sans-serif;
  font-size: 9px;
  color: rgba(255,255,255,0.25);
  letter-spacing: 2px;
  padding: 10px 14px 0;
}

.private-room-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid rgba(255,255,255,0.08);
  margin-top: 6px;
}

.private-tab {
  padding: 10px;
  font-family: 'Orbitron', sans-serif;
  font-size: 10px;
  letter-spacing: 1px;
  cursor: pointer;
  border: none;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: rgba(255,255,255,0.3);
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.private-tab.active#tab-join {
  border-bottom-color: #33cccc;
  background: rgba(51,204,204,0.08);
  color: rgba(51,204,204,0.9);
}

.private-tab.active#tab-create {
  border-bottom-color: #d4a843;
  background: rgba(212,168,67,0.08);
  color: #d4a843;
}

.private-panel {
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}

#panel-create {
  flex-direction: column;
  align-items: stretch;
}

.private-code-input {
  flex: 1 !important;
  letter-spacing: 2px;
  text-transform: uppercase;
  font-size: 11px !important;
}

.private-action-btn {
  background: rgba(51,204,204,0.1);
  border: 1px solid rgba(51,204,204,0.3);
  border-radius: 4px;
  padding: 10px 16px;
  cursor: pointer;
  font-family: 'Orbitron', sans-serif;
  font-size: 10px;
  color: rgba(51,204,204,0.85);
  letter-spacing: 1px;
  white-space: nowrap;
  transition: opacity 0.15s;
}
.private-action-btn:hover { opacity: 0.8; }

.private-action-gold {
  width: 100%;
  background: rgba(212,168,67,0.1);
  border-color: rgba(212,168,67,0.35);
  color: #d4a843;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
}

.private-hint {
  font-size: 11px;
  color: rgba(255,255,255,0.3);
  margin: 0 0 8px;
  line-height: 1.4;
  font-family: 'Rajdhani', sans-serif;
}

/* ═══════════════════════════════════════════════════════════════
   LAYOUT ENGINE MIGRATION — Screen-Panels (2026-05-12)
   lobby-main, vanguard-panel, gameover-panel werden per
   Layout Engine absolut positioniert — Screens selbst kein Flex mehr.
   ═══════════════════════════════════════════════════════════════ */

/* Lobby: Screen ist jetzt transparenter Backdrop — Layout Engine positioniert lobby-main */
#screen-lobby {
  align-items: unset;
  justify-content: unset;
  overflow: visible;
}

/* lobby-main: overflow-y für lange Menu-Level (z.B. menu-play mit private-room-box) */
#lobby-main {
  overflow-y: auto !important;
  overflow-x: hidden !important;
  padding-top: 20px;
  box-sizing: border-box;
}

/* Vanguard: Screen ist jetzt transparenter Backdrop — vanguard-panel übernimmt Layout */
#screen-vanguard {
  align-items: unset;
  justify-content: unset;
  padding: 0;
  gap: 0;
  overflow: visible;
}

/* vanguard-panel: behält das alte Flex-Layout des Screens */
.vanguard-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  padding: 28px 36px;
  overflow: hidden;
  overflow-x: hidden;
  position: absolute; /* wird von Layout Engine überschrieben */
  box-sizing: border-box;
}

/* Gameover: Screen ist jetzt transparenter Backdrop — gameover-panel übernimmt Layout */
#screen-gameover {
  align-items: unset;
  justify-content: unset;
  gap: 0;
}

/* gameover-panel: behält das alte Flex-Layout des Screens */
.gameover-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  position: absolute; /* wird von Layout Engine überschrieben */
  box-sizing: border-box;
}

/* ── Flip-Karte: eigene verdeckte Schiffe (Hover → Artwork) ─────────────────── */
.sq-flip-card { perspective: 600px; }
.sq-flip-inner {
  position: relative;
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.35s ease;
}
.sq-flip-card:hover .sq-flip-inner {
  transform: rotateY(180deg);
}
.sq-flip-back,
.sq-flip-front {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: 4px;
  overflow: hidden;
}
.sq-flip-front {
  transform: rotateY(180deg);
}



/* ── Combat: Aktiver Angreifer Highlight ──────────────────────────────────── */
/* FIX (2026-07-08): Puls war definiert aber nie per `animation` angewendet
   (rein statischer Rahmen). Jetzt aktiv + Farbe auf #f0b429 vereinheitlicht —
   dieselbe Keyframe-Definition wird von der Ini-Leiste (.ini-bar-active)
   zweitgenutzt, damit Feld und Leiste exakt gleich pulsen. */
@keyframes activeAttackerAnim {
  0%   { box-shadow: 0 0 10px rgba(240,180,41,0.5), 0 0 20px rgba(240,180,41,0.2); }
  50%  { box-shadow: 0 0 22px rgba(240,180,41,0.9), 0 0 40px rgba(240,180,41,0.5); }
  100% { box-shadow: 0 0 10px rgba(240,180,41,0.5), 0 0 20px rgba(240,180,41,0.2); }
}
.ship-tok-combat.active-attacker {
  outline: 2px solid #f0b429;
  outline-offset: 2px;
  transform: translateY(-3px);
  transition: outline 0.15s, transform 0.15s;
  animation: activeAttackerAnim 1.6s ease-in-out infinite;
  z-index: 5;
  position: relative;
}

.ini-bar-active {
  border: 2px solid #f0b429 !important;
  animation: activeAttackerAnim 1.6s ease-in-out infinite;
}

/* FIX K8 (2026-07-24): Autoscroll bei Platzmangel — #initiative-bar (game-combat.js
   HTML) bekommt diese Klasse zusaetzlich zum bestehenden Inline-Style. overflow-x:auto
   ersetzt das bisherige overflow:hidden (Ueberlauf wurde bisher stumm abgeschnitten,
   nicht sichtbar/scrollbar). Scrollbar bewusst versteckt (dezentes HUD, s. Prompt) —
   Scroll bleibt trotzdem per Maus/Touch/Wheel bedienbar, nur die Leiste selbst wird
   nicht angezeigt. scroll-behavior:smooth traegt sowohl den manuellen Scroll als auch
   das programmatische scrollTo() in renderInitiativeBar(). */
.sq-ini-bar-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scrollbar-width: none;      /* Firefox */
  -ms-overflow-style: none;   /* alte Edge/IE-Faelle */
}
.sq-ini-bar-scroll::-webkit-scrollbar {
  display: none;              /* Chrome/Safari/Edge (Chromium) */
}

/* ── Phase-Status Box (Overview + Combat) ─────────────────────────────────────
   Fix CW1 (2026-08-22): dieser Block ist ersatzlos entfallen. Er schrieb die alte,
   frei schwebende Kaestchen-Fassung fest — `min-height:110px !important`,
   `padding:14px 16px !important` und feste Schriftgroessen mit !important. Im Banner
   (46px hohes Band) hat das Panel diese Masse gemessen um 65px ueberschritten (belegt
   per scripts/verify-cw1-banner.js, erster Lauf: h=110 in einem 45px hohen Band).
   Zustaendig sind ab jetzt ausschliesslich die .sq-banner-phase-*-Klassen weiter oben —
   EINE Quelle statt zweier, und ohne !important, weil das Markup keine Inline-Masse mehr
   mitbringt (game-overview.js _renderPhasePanelHTML()). Die Puls-Regeln
   #ov-phase-status.sq-waiting-glow / #cb-phase-status.sq-waiting-glow (weiter oben)
   bleiben unangetastet. */


/* ── Private Room Modal (2026-05-22) ─────────────────────────────────────── */
#private-room-modal {
  display: none;
  align-items: center;
  justify-content: center;
}
#private-room-modal.open {
  display: flex;
}

/* ── Squad Stack Counter (2026-05-22) ────────────────────────────────────── */
.squad-stack {
  position: relative;
  overflow: visible;
  display: inline-block;
}
.squad-stack-ghost {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  pointer-events: none;
}
.squad-counter-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  background: var(--gold, #f0c040);
  color: #0a0e1a;
  font-family: 'Orbitron', sans-serif;
  font-size: 10px;
  font-weight: 900;
  padding: 1px 5px;
  border-radius: 8px;
  z-index: 10;
  box-shadow: 0 0 6px rgba(0,0,0,0.6);
  pointer-events: none;
  line-height: 1.4;
}

/* ── Fleetzone-Hover-Fächer (Fix I1, Richtung+Clipping-Fix K3 Section 1) ──────────
   FIX K3: position/left/bottom/transform kommen jetzt aus game-overview.js
   (_showSquadFanOut()) als Inline-Styles — der Fächer haengt im position:fixed
   #squad-fanout-layer (views/play-v3.ejs, AUSSERHALB von #sq-stage, das
   overflow:hidden hat), nicht mehr im .squad-stack-Wrapper. Öffnungsrichtung
   (oben/unten) ist dadurch je Zone unterschiedlich (eigene Zone → oben, Gegner-Zone →
   unten) statt hier hart auf "immer nach oben" verdrahtet. flex-wrap ergänzt, damit
   sehr große Stacks umbrechen statt über den Viewport-Rand hinauszuragen (Prompt-
   Vorgabe "wrap/shrink instead of overflowing"). Die Fade-in-Animation ist auf reines
   Opacity reduziert — ein Transform in den Keyframes würde sonst das per JS gesetzte
   Clamp-Transform (Viewport-Rand-Korrektur) am Ende der Animation wieder überschreiben. */
.squad-fanout {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
  padding: 6px;
  background: rgba(6, 9, 16, 0.9);
  border: 1px solid rgba(120, 140, 180, 0.35);
  border-radius: 6px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.6);
  animation: squad-fanout-in 0.15s ease-out forwards;
}
@keyframes squad-fanout-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.squad-fanout-card { flex-shrink: 0; }

/* ── Lobby Scrollbar: versteckt (Scroll-Funktion bleibt erhalten) ────────── */
#lobby-main { scrollbar-width: none; -ms-overflow-style: none; }
#lobby-main::-webkit-scrollbar { display: none; }


/* ── Lobby Ghost-Buttons (Privater Raum, Zurück) — scoped auf #menu-play ── */
#menu-play .menu-btn {
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  background: transparent;
  border: 1px solid rgba(139,147,168,.3);
  border-left: none;
  transition: border-color .15s, color .15s, box-shadow .15s;
}
#menu-play .menu-btn:hover {
  border-color: rgba(240,180,41,.5);
  color: #f0b429;
  background: transparent;
  box-shadow: none;
  text-shadow: 0 0 8px rgba(240,180,41,.3);
}

/* NEW (2026-05-23): Match-Found Overlay Background — zwei Faktionen, Galaxie zentral */
/* FIX (2026-05-24): Background-Image als direkter Layer, Overlay-Tönung über ::after */
#match-proposed-overlay {
  background-image: url('/backgrounds/match-found-bg.webp') !important;
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
  background-color: #080c1c !important;
}
#match-proposed-overlay::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(8,12,28,0.50), rgba(8,12,28,0.65));
  pointer-events: none;
  z-index: 1;
}
#match-proposed-overlay > * {
  position: relative;
  z-index: 2;
}

/* ── Fix CL1 (2026-08-20): der Moment, wenn ein Gegner gefunden wird ──────────────
   Bis hierhin: ein Kasten mit Inline-Styles und einer nackten Countdown-Zahl. Jetzt der
   Duell-Aufbau des Entwurfs (mockups/warteschlange-matchmaking.html) mit den BEREITS
   vorhandenen .sq-mf-*-Bausteinen des Spielstart-Overlays (Wappen, Fraktionsname,
   VS-Trenner) — keine zweite Gestaltungswelt.
   Zeitgefuehl: Wappen und Namen fahren VERSETZT ein (mp-d1..mp-d5), nicht gleichzeitig.
   Der Countdown ist derselbe Ring wie Ladebildschirm und Peilring, nur rueckwaerts
   (window.SqRing, public/js/game-loading-screen.js).
   Die Verdeckung ist davon voellig unberuehrt: was angezeigt werden DARF, entscheidet
   weiterhin allein der Server (plugins/game.js#_proposeBackboneMatch — Nachricht ohne
   Name/userId/Rating). */
.mp-box {
  --mp-chamfer: 16px;
  position: relative;
  min-width: 340px;
  max-width: 500px;
  padding: 22px 30px 24px;
  text-align: center;
  font-family: 'Orbitron', sans-serif;
  background: linear-gradient(168deg, rgba(10, 16, 32, 0.965), rgba(5, 8, 17, 0.98));
  border: 1px solid rgba(46, 64, 104, 0.95);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.7);
  clip-path: polygon(var(--mp-chamfer) 0, 100% 0, 100% calc(100% - var(--mp-chamfer)),
                     calc(100% - var(--mp-chamfer)) 100%, 0 100%, 0 var(--mp-chamfer));
  animation: mpBoxIn 340ms cubic-bezier(.2, .9, .25, 1.15) both;
}
.mp-box::before {
  content: '';
  position: absolute;
  top: 0;
  left: var(--mp-chamfer);
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, rgba(240, 165, 0, 0.9), rgba(240, 165, 0, 0.12) 65%, transparent);
  pointer-events: none;
}
@keyframes mpBoxIn {
  from { opacity: 0; transform: scale(0.62); }
  to   { opacity: 1; transform: scale(1); }
}
.mp-title {
  font-size: 11px;
  letter-spacing: 0.26em;
  color: #f0a500;
  text-shadow: 0 0 14px rgba(240, 165, 0, 0.35);
  padding-bottom: 11px;
  margin-bottom: 4px;
  border-bottom: 1px solid rgba(46, 64, 104, 0.8);
}
.mp-duel { margin-bottom: 12px; align-items: flex-start; }
.mp-side { padding: 14px 8px 6px; gap: 7px; }
/* Beide Seiten fluchten, auch wenn ein Fraktionsname zweizeilig umbricht
   ("United Earth Defense") und der andere nicht ("Voidstalker"). */
.mp-box .sq-mf-faction { line-height: 1.25; min-height: 2.5em; display: flex; align-items: center; }
.mp-icon-unknown {
  border-color: rgba(139, 147, 168, 0.35);
  background: rgba(139, 147, 168, 0.06);
  color: #6a7090;
  font-size: 24px;
  font-weight: 700;
}
/* Fraktionsfarben NUR innerhalb dieses Fensters auf die kanonischen Spielfarben
   (--vs/--ued, Block "Farben" oben) gezogen. Das Spielstart-Overlay
   (showMatchFoundOverlay, .sq-mf-faction.ued) faerbt UED seit jeher cyan statt gruen —
   eine vorbestehende Abweichung, die diese Runde bewusst NICHT global anfasst (sie
   gehoert zu einem anderen Bildschirm, s. Bericht). Innerhalb des Annehmen-Fensters
   waere sie aber ein Widerspruch zur Fraktionskachel direkt davor. */
.mp-box .sq-mf-faction.vs  { color: var(--vs); }
.mp-box .sq-mf-faction.ued { color: var(--ued); }
.mp-box .sq-mf-icon.vs  { border-color: rgba(224, 32, 32, 0.55); background: rgba(224, 32, 32, 0.1); }
.mp-box .sq-mf-icon.ued { border-color: rgba(0, 192, 80, 0.5);  background: rgba(0, 192, 80, 0.09); }
/* Der Gegnername bleibt vor der Annahme verdeckt (Server sendet ihn nicht) — die Zeile
   traegt dann den Hinweistext und wird optisch als "noch unbekannt" gelesen. */
.mp-side-en .sq-mf-name { color: rgba(255, 255, 255, 0.5); letter-spacing: 1.4px; }
.mp-vs { padding: 0 6px; }

/* Countdown-Ring. #match-proposed-countdown bleibt als Textknoten bestehen (fuer
   bestehende Pruefungen auslesbar), ist aber visuell verborgen — die Zahl zeichnet der
   Ring selbst in seine Mitte. Nicht display:none: das wuerde textContent zwar erhalten,
   aber sichtbar-Pruefungen kippen; clip+0-Groesse ist das im Projekt uebliche Muster. */
.mp-cd {
  position: relative;
  width: 124px;
  height: 124px;
  margin: 2px auto 6px;
}
.mp-cd canvas { display: block; width: 100%; height: 100%; }
.mp-cd-value {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.mp-hint {
  font-family: 'Rajdhani', sans-serif;
  font-size: 11px;
  color: #7d879e;
  letter-spacing: 0.04em;
  margin-bottom: 12px;
}
.mp-btns { display: flex; gap: 10px; justify-content: center; }
.mp-btn {
  flex: 1;
  padding: 11px 10px;
  border: 1px solid;
  cursor: pointer;
  font-family: 'Orbitron', sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
  transition: filter 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.mp-btn-yes {
  background: linear-gradient(180deg, rgba(240, 165, 0, 0.22), rgba(240, 165, 0, 0.06));
  border-color: rgba(240, 165, 0, 0.85);
  color: #ffc94d;
}
.mp-btn-yes:hover { filter: brightness(1.25); }
.mp-btn-no {
  background: rgba(10, 17, 32, 0.7);
  border-color: rgba(46, 64, 104, 0.9);
  color: #8b93a8;
}
.mp-btn-no:hover { color: #d2d7e6; border-color: rgba(139, 147, 168, 0.7); }

/* Versetztes Einfahren — erst der Gegner, dann man selbst, dann Trenner/Ring/Knoepfe.
   "Versetzt statt gleichzeitig" (Entwurf Abschnitt 2). */
.mp-d1, .mp-d2, .mp-d3, .mp-d4, .mp-d5 { animation: mpRise 300ms cubic-bezier(.2, .9, .25, 1.15) both; }
.mp-d1 { animation-delay: 180ms; animation-name: mpRiseRight; }
.mp-d2 { animation-delay: 270ms; animation-name: mpRiseLeft; }
.mp-d3 { animation-delay: 400ms; animation-name: mpPop; }
.mp-d4 { animation-delay: 520ms; }
.mp-d5 { animation-delay: 640ms; }
@keyframes mpRise      { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes mpRiseRight { from { opacity: 0; transform: translateX(46px); } to { opacity: 1; transform: none; } }
@keyframes mpRiseLeft  { from { opacity: 0; transform: translateX(-46px); } to { opacity: 1; transform: none; } }
@keyframes mpPop       { from { opacity: 0; transform: scale(2.2); } to { opacity: 1; transform: scale(1); } }

/* NEW (2026-05-23): Startspieler-Wurf (Roll-Off) Background — Crossroads, diagonale Nebel */
#sq-start-roll-overlay {
  background-image:
    linear-gradient(rgba(8,12,28,0.45), rgba(8,12,28,0.60)),
    url('/backgrounds/roll-bg.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* NEW (Fix K1, 2026-07-23): Own-Connection Disconnect-Banner — eigenständig von
   #disconnect-banner (Gegner-Disconnect, game-lobby.js showDisconnectBanner()), siehe
   Kommentar dort. Sitzt über den HUD-Bannern (z-index 9000), damit ein eigener
   Verbindungsverlust immer sichtbar bleibt, auch während gerade ein Phasen-Banner läuft. */
.own-dc-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 9500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 10px 16px;
  font-family: 'Rajdhani', sans-serif;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  box-shadow: 0 2px 12px rgba(0,0,0,0.4);
}
.own-dc-banner.own-dc-lost     { background: #7a1414; }
.own-dc-banner.own-dc-restored { background: #0d5c3c; }
.own-dc-banner.own-dc-failed   { background: #4a4a4a; }
.own-dc-spinner {
  width: 14px; height: 14px;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: #fff;
  border-radius: 50%;
  animation: own-dc-spin 0.8s linear infinite;
  flex-shrink: 0;
}
@keyframes own-dc-spin { to { transform: rotate(360deg); } }
.own-dc-reload-btn {
  padding: 4px 14px;
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: 4px;
  background: rgba(255,255,255,0.1);
  color: #fff;
  font-family: 'Rajdhani', sans-serif;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
.own-dc-reload-btn:hover { background: rgba(255,255,255,0.2); }


/* ══ Fix CX1 (2026-08-22): HUD-Neuaufbau Etappe 2 — Baender, Fleetzone, Ortsleiste ═════
   Zielbild: mockups/hud-neuaufbau-vollversion.html (#field). Die AUSSENMASSE aller hier
   gestylten Kaesten stehen in layout-config.js, NICHT hier — applyToElement() schreibt
   width/height inline, eine Breite an dieser Stelle waere wirkungslos (Fehlerklasse CJ1).
   Dieser Block macht ausschliesslich Optik und Innenaufteilung.

   Bewusst NICHT unter #screen-overview eingehaengt: bis Fix EJ1 klonte der Kampfuebergang
   die Ortskachel an #sq-stage — ausserhalb der Bildschirme; der Klon verlor seinen eigenen
   className, behielt aber den seiner Kinder, und nur mit ungebundenen Selektoren sah er
   waehrend des Flugs noch so aus wie die Kachel, von der er stammte. Der Klonflug ist
   entfallen (beide Richtungen zoomen jetzt die Ortsleiste an Ort und Stelle); die
   ungebundenen Selektoren bleiben trotzdem, weil sie unabhaengig davon korrekt sind und
   ein Umhaengen nur neues Risiko ohne Nutzen waere.
   ═════════════════════════════════════════════════════════════════════════════════════ */

/* ── Fleetzone: ein Regal im Band, links, kein Kaestchen mehr ───────────────── */
.sq-fleetzone {
  box-sizing: border-box;
  display: flex;
  align-items: stretch;
  padding: 4px 8px;
  border: 1px solid rgba(40, 55, 85, 0.75);
  border-radius: 4px;
  background: rgba(6, 11, 20, 0.50);
  overflow: hidden;
}
.sq-fleetzone-mine  { border-color: rgba(50, 160, 80, 0.42); }
.sq-fleetzone-enemy { border-color: rgba(200, 60, 60, 0.42); }

/* Beschriftung liegt UEBER dem Regal (Zielbild .fzlabel) statt darueber zu stehen —
   sie darf die nutzbare Hoehe nicht schmaelern, weil genau die die Kartengroesse und
   damit die Lesbarkeit der Kartenzahlen bestimmt. */
.sq-fleetzone-label {
  position: absolute;
  right: 7px;
  top: 3px;
  font-family: 'Orbitron', sans-serif;
  font-size: 7.4px;
  letter-spacing: 1.6px;
  color: rgba(122, 134, 166, 0.8);
  pointer-events: none;
  z-index: 2;
  white-space: nowrap;
}
.sq-fleetzone-row {
  flex: 1 1 0;
  min-width: 0;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Friedhof — Kartenformat statt Kaestchen; Groesse aus layout-config.js. */
.sq-graveyard {
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
}

/* ── Ortskachel: Schleier + zwei Schiffsreihen + Ortsleiste ─────────────────── */
.sq-loc-veil {
  position: absolute;
  inset: 0;
  background: rgba(6, 10, 20, 0.42);
  pointer-events: none;
  z-index: 0;
}
/* Beide Reihen teilen sich exakt gleich, was die Ortsleiste uebrig laesst. Vorher:
   feste 42.5 % je Reihe und 15 % fuer die Leiste — die Leiste war dadurch zu klein
   fuer ihren eigenen Inhalt. */
.sq-loc-row {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
  padding: 3px;
}

.sq-locbar {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  padding: 5px 6px 6px;
  text-align: center;
  background: linear-gradient(180deg, rgba(12, 20, 36, 0.94), rgba(8, 14, 26, 0.92));
  border-top: 1px solid rgba(240, 160, 0, 0.24);
  border-bottom: 1px solid rgba(240, 160, 0, 0.24);
}
.sq-locbar-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: #dfe5f2;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sq-locbar-vprow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 2px;
  flex-wrap: wrap;
}
.sq-locbar-vp {
  font-family: 'Share Tech Mono', monospace;
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  color: #f0c040;
}
.sq-locbar-vplbl {
  font-family: 'Orbitron', sans-serif;
  font-size: 8.5px;
  letter-spacing: 1.5px;
  color: rgba(139, 147, 168, 0.75);
  white-space: nowrap;
}
.sq-locbar-owner {
  display: inline-block;
  margin-top: 3px;
  max-width: 100%;
  padding: 1px 8px;
  border: 1px solid currentColor;
  border-radius: 3px;
  font-family: 'Orbitron', sans-serif;
  font-size: 9px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sq-locbar-effrow {
  display: flex;
  gap: 4px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 3px;
}
.sq-locbar-eff {
  font-family: 'Orbitron', sans-serif;
  font-size: 8.5px;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  padding: 2px 8px;
  border: 1px solid rgba(226, 75, 74, 0.70);
  border-radius: 3px;
  color: #ff8a89;
  background: rgba(226, 75, 74, 0.12);
  white-space: nowrap;
}

/* HOLD und "Angreifen" teilen sich denselben Platz in der Siegpunkt-Zeile. Die
   Grundregeln stehen weiter oben (.sq-hold-badge, .sq-loc-attack-btn) und sind
   fuer ein frei stehendes Kaestchen bemasst (12px Schrift, 3px Sperrung) — in der
   Leiste wuerden sie die Zeile umbrechen. Hier deshalb NUR Groessen, keine zweite
   Farbdefinition. */
.sq-locbar-vprow .sq-hold-badge {
  font-size: 8.5px;
  letter-spacing: 2px;
  padding: 2px 7px;
}
.sq-locbar-vprow .sq-loc-attack-btn {
  font-size: 9px;
  letter-spacing: 1.5px;
  padding: 2px 8px;
}
/* Aktiv heisst hier: es haelt sie noch niemand. Sobald ein Controller gesetzt ist,
   tritt die Marke zurueck und die Besitzer-Pille uebernimmt die Aussage. */
.sq-hold-badge.sq-hold-on {
  color: #f0b429;
  border-color: rgba(240, 180, 41, 0.80);
  background: rgba(240, 180, 41, 0.10);
}
