/* Chat Tower Companion -- pages/collection.css
 * P6-Kette Glied 6/8 (web-241). Reine Verschiebung aus web/public/style.css.
 * Scope: Dashboard-Tab "Karten & Sockel" -- Sockel, Draws,
 * Free-Draws-Kampagne-Banner, Draw-Karte-Flip-Wrapper, das ui-007-
 * Panel-Grundgeruest, die ui-111-Upgrade-Leiste + Merge-Animation. Deckt sich
 * mit dem JS-Modul web/client/companion/collection/cards.js (web-237).
 * ui-612 (AK6): die vormalige "Cards/Pills"/"Merge"-Sektion (.card-pill/
 * .card-group/.merge-btn/-hints) ist entfallen — sie stylte AUSSCHLIESSLICH
 * den toten Legacy-Renderer dashboard.js renderInventory()/effectPill()/
 * weaponPill() (Fallback fuer ein laengst nicht mehr existentes `?tab=
 * inventory`, ohne Aufrufer). Die ui-111-Upgrade-Leiste + Merge-Animation
 * (Karten-MERGEN im echten Sockel-/Inventar-Grid, ein ANDERES Konzept als
 * die geloeschten Merge-Buttons) bleibt unveraendert weiter unten.
 *
 * Kaskaden-Lock: MUSS vor pages/dashboard.css UND pages/shared-mobile.css
 * laden -- mehrere hier definierte Basisregeln (.cs-draw-bar/.cs-draw-
 * counter/.draw-result/.cs-subtoggle/.cs-panel/.cs-sort-btn/.cs-card-remove/
 * .hexa-table/.cs-drop-odds-link u.a.) werden von spaeteren Mobile-/Touch-
 * Overrides in genau diesen zwei Dateien ueberschrieben (gleiche
 * Spezifitaet, spaetere Datei-Position gewinnt) -- s. web-241-Ticket
 * Cross-File-Sweep fuer die volle Belegliste. */


/* ===== Sockel ===== */

.socket-list { display: flex; flex-direction: column; gap: 0.5em; }
.socket-row {
  display: grid;
  grid-template-columns: 2em 3em 1fr auto;
  align-items: center;
  gap: 0.6em;
  padding: 0.6em 0.8em;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 4px;
}
.socket-icon { color: var(--cyan); font-size: 1.2em; }
.socket-slot-index { color: var(--muted); font-family: ui-monospace, monospace; font-size: 0.9em; }
.socket-select {
  font-family: inherit;
  font-size: 0.9em;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line-2);
  border-radius: 3px;
  padding: 0.3em 0.5em;
  width: 100%;
}
.socket-select:focus { outline: none; border-color: var(--cyan); }
.socket-status {
  font-size: 0.85em;
  color: var(--green);
  min-width: 8em;
  text-align: right;
}
.socket-status.muted { color: var(--muted); font-style: italic; }
.socket-preview {
  margin-top: 1em;
  padding-top: 1em;
  border-top: 1px dashed var(--line);
}
.socket-preview h3 { color: var(--magenta); font-size: 0.95em; margin: 0 0 0.4em; }
.preview-list { margin: 0; padding-left: 1.3em; color: var(--text); }
.preview-list li { padding: 0.15em 0; }

/* ===== Draws (web-100) ===== */
/* .draws-panel / .draw-zone / .draw-counter / .draw-counter-label entfernt (web-100):
   Draw-Zone lebt jetzt als kompakte .cs-draw-bar in renderCardsAndSockets.
   .draw-btn und .draw-result bleiben, da IDs #draw-btn/#draw-result unverändert sind. */

/* web-100: Kompakte Draw-Leiste (Design-Lock DL-1) */
.cs-draw-bar {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 14px 18px;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  background: linear-gradient(120deg, rgba(255, 69, 181, 0.05), rgba(56, 225, 255, 0.04)), var(--panel);
  margin-bottom: 0;
}

/* Zähler: Magenta, ~2em (DL-2).
   ui-380: align-items center statt baseline — baseline hängte die Zahl-Grundlinie
   an die ERSTE Zeile des zweizeiligen Labels ("DRAWS"), "VERFÜGBAR" ragte darunter
   raus → Zahl und Label ~15px diagonal gegeneinander verschoben (Zahl-Mitte über,
   Label-Mitte unter der Button-Achse). center legt Zahl-Box (2em) und Label-Block
   (2×0.7em×1.3, fast gleich hoch) auf EINE Mittelachse mit Button + Hint. */
.cs-draw-counter {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.cs-draw-counter #draws-remaining-big {
  font-size: 2em;
  font-weight: 700;
  /* ui-623: --cur-draw statt Magenta (Fifty-Bug-Report "Hexa sind mal pink,
     mal gelb" — dieser Zähler teilte sich bis dahin Hexas Farbe). */
  color: var(--cur-draw);
  text-shadow: 0 0 16px rgba(255, 179, 71, 0.35);
  line-height: 1;
}
.cs-draw-counter-label {
  color: var(--muted);
  text-transform: uppercase;
  font-size: var(--fs-caption); /* ui-505 (M3): 0.7em (~10.5px) -> --fs-caption (K1) */
  letter-spacing: 0.07em;
  line-height: 1.3;
}

/* Dezenter Hint-Text (DL-1) */
.cs-draw-hint {
  color: var(--text-dim, var(--muted));
  font-size: 0.78em;
  line-height: 1.4;
  max-width: 240px;
}

/* Cyan-Button (DL-2) — mindestens 44px Tap-Höhe via Padding */
.draw-btn {
  font-size: 1.05em;
  padding: 0.65em 1.6em;
  background: var(--cyan);
  color: var(--bg);
  border: none;
  border-radius: 8px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  flex-shrink: 0;
  box-shadow: 0 0 22px rgba(56, 225, 255, 0.35);
  transition: transform 0.1s, box-shadow 0.15s;
  min-height: 44px;
}
.draw-btn:hover:not(:disabled) {
  transform: scale(1.02);
  box-shadow: 0 0 30px rgba(56, 225, 255, 0.55);
  color: var(--bg);
}
.draw-btn:disabled { background: var(--line-2); color: var(--muted); box-shadow: none; cursor: default; }

/* Inline-Result-Slot rechts (DL-3, ui-487: FESTER Draw-Stapel-Slot).
   width/height reservieren eine Mindest-Stapel-Flaeche IMMER (0..20 Karten,
   Design-Lock "keine Layout-Spruenge der Draw-Leiste") -- vormals nur
   min-height=180 fuers Leerzustand (Fifty-Wunsch 2026-06-12), jetzt zusaetzlich
   eine feste Breite, weil die Karten (.draw-flip-wrapper unten) seit ui-487
   ABSOLUT positioniert sind und dadurch KEINE eigene Breite/Hoehe mehr an
   dieses Element weiterreichen (position:absolute-Kinder tragen nicht zur
   Groesse eines auto-groessen Elternelements bei). Breite bleibt bei 288px
   (Kartenbreite 120px + 4x 42px, historischer DL-2=5-Wert) -- ui-598 (20 statt
   5 Karten, geometrisch abklingender Versatz statt linear, s. draw-stack.js)
   AENDERT DIESEN WERT BEWUSST NICHT: der volle Tiefen-Versatz bei 20 Karten
   erreicht bis zu ~319px (computeDrawStackLayout(20)[0].tx) und ueberragt den
   288px-Slot damit sichtbar -- das ist HIER (Desktop, reichlich Platz in
   .cs-draw-bar) beabsichtigt und live verifiziert (kein overflow:hidden auf
   Desktop): die hinteren, ohnehin stark gedimmten/verkleinerten Karten laufen
   optisch frei in den Panel-Hintergrund aus, exakt der von Fifty gewuenschte
   Effekt ("weiter ausfaden"). Das MOBILE-Gegenstueck (dashboard.css
   ≤480px-Block) schneidet den ueberlaufenden Rest stattdessen per
   overflow:hidden + Kanten-Maske sauber ab (schmaler Viewport, kein Platz
   fuer freien Overflow ohne Kollisionsrisiko mit Nachbar-Inhalt). Hoehe
   bleibt bei 180px (= Kartenhoehe, keine vertikale Staffelung).
   isolation:isolate haelt die Stapel-z-Index-Werte (1..20, s. draw-stack.js)
   lokal -- kollidiert nicht mit Modal-/Toast-Stapelkontexten anderswo auf der
   Seite. display:flex/align-items/justify-content gelten nur noch fuers
   :empty::after-Platzhalter-Label unten (absolut positionierte Kinder
   ignorieren Flex-Alignment). */
.draw-result {
  margin-left: auto;
  position: relative;
  isolation: isolate;
  width: 288px;
  height: 180px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: opacity 0.3s;
}
.draw-result:empty::after {
  content: "dein letzter Zug erscheint hier";
  color: var(--muted);
  font-size: var(--fs-caption); /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
  text-align: center;
  max-width: 90px;
  opacity: 0.6;
}

/* ===== Free-Draws-Kampagne-Banner (ui-330, Datenquelle web-212) =====
   Sitzt in #cs-root direkt ÜBER .cs-draw-bar (Design-Lock: Sockel-Tab, über
   "Karten ziehen", NICHT Dashboard-Header). Vier Zustände: verfügbar /
   .claimed (eingesammelt) / Gast (.link-btn statt .draw-btn) / unsichtbar (kein
   Markup — renderFreeDrawsBanner() liefert '' wenn !active, kein Platzhalter
   hier nötig). border-radius 8px = --card-radius, die kanonische Box-Stufe
   (ui-098) — hier als Literal, da .fd-banner kein --card-accent-Slot braucht. */
.fd-banner {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 16px;
  background: linear-gradient(120deg, rgba(56, 225, 255, 0.10), rgba(255, 69, 181, 0.08));
  border: 1px solid color-mix(in srgb, var(--cyan) 40%, var(--line));
  border-radius: 8px;
  padding: 16px 18px;
  margin-bottom: 14px;
  box-shadow: 0 0 26px rgba(56, 225, 255, 0.14);
}
.fd-icon {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: radial-gradient(circle at 40% 30%, rgba(56, 225, 255, 0.22), rgba(255, 69, 181, 0.10));
  border: 1px solid var(--line-2);
  font-size: 24px;
  /* ui-623: --cur-draw statt Cyan — der Banner bewirbt Draws, nicht die
     UI-Interaktionsfarbe (DL-4). Der Verlaufs-Hintergrund/-Rand oben bleibt
     unverändert (Marken-Gradient, keine Währungsrolle). */
  color: var(--cur-draw);
}
.fd-icon svg { width: 27px; height: 27px; display: block; }
.fd-main { flex: 1; min-width: 0; }
.fd-title { font-size: 1.12em; font-weight: 800; line-height: 1.15; }
/* ui-623: --cur-draw statt Magenta-Light — dieselbe Fifty-Bug-Report-Familie
   ("Hexa sind mal pink, mal gelb"), der Banner bewirbt ausschließlich Draws. */
.fd-title .amt { color: var(--cur-draw); }
.fd-sub {
  font-size: 0.82em;
  color: var(--text-dim);
  margin-top: 3px;
  display: flex;
  align-items: center;
  gap: 0.5em;
  flex-wrap: wrap;
}
.fd-countdown { color: var(--cyan); font-weight: 600; font-variant-numeric: tabular-nums; }
.fd-cta { flex: 0 0 auto; }

/* Zustand "eingesammelt" — grün-good, gedämpft, kein CTA. */
.fd-banner.claimed {
  background: linear-gradient(120deg, rgba(94, 255, 138, 0.10), rgba(94, 255, 138, 0.03));
  border-color: color-mix(in srgb, var(--green) 40%, var(--line));
  box-shadow: none;
}
.fd-banner.claimed .fd-icon { background: rgba(94, 255, 138, 0.12); color: var(--green); }
.fd-banner.claimed .fd-title .amt { color: var(--green); }
.fd-check { color: var(--green); }

/* Zustand "Gast" — twitch-lila CTA statt Claim. .tw-glyph ist bereits geteilt
   (Landing-Login-Button, pages/entry.css) — hier nur eine zweite Nutzung, kein
   neuer Glyph. Anders als .cta-secondary (neutral bis :hover) ist .link-btn
   schon im Ruhezustand twitch-lila umrandet — die Hürde soll im Banner sofort
   erkennbar sein, nicht erst beim Hover. */
.link-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  font-size: 0.98em;
  font-weight: 700;
  padding: 0.6em 1.3em;
  min-height: 44px;
  background: transparent;
  color: #c9b8ff;
  border: 1px solid color-mix(in srgb, var(--twitch) 55%, transparent);
  border-radius: 6px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color 0.15s, background 0.15s;
}
.link-btn:hover { border-color: var(--twitch); background: rgba(145, 70, 255, 0.12); }
.link-btn .tw-glyph { fill: var(--twitch); width: 1.1em; height: 1.1em; }

/* ui-330 Design-Lock "Responsive @≤560px: Banner umbrechen, CTA volle
   Breite" — eigener Breakpoint-Wert (560px, nicht der 480px-Stack-Punkt von
   .cs-draw-bar weiter unten), abgenommener Designer-Wert aus dem Prototyp. */
@media (max-width: 560px) {
  .fd-banner { flex-wrap: wrap; }
  .fd-cta { flex-basis: 100%; }
  .fd-cta .draw-btn,
  .fd-cta .link-btn { width: 100%; }
}

/* ===== Happy-Draw-Hour-Banner (web-320, Datenquelle services/draw-tier-event.js) =====
   Sitzt in #cs-root DIREKT NACH .fd-banner (AK9-Reihenfolge-Lock) — Design-
   Lock DL-2: dieselbe Bausprache wie .fd-banner oben, aber in TIER-Farbe statt
   fixem Cyan. Kein CTA (DL-1: der Draw-Button steht direkt darunter). Markup/
   Klassen 1:1 aus dem abgenommenen Prototyp (.claude/sprint/prototypes/web-320.html
   Abschnitt 2/3) übernommen. Kein eigener Mobile-Breakpoint nötig (AK9: bleibt
   bei jeder Breite einzeilig, Text bricht innerhalb der bestehenden Flex-/
   overflow-wrap-Regeln um — anders als .fd-banner oben, dessen ≤560px-Regel
   NICHT gebraucht wird). */
.hdh-banner {
  --hdh-color: var(--cyan);
  --hdh-glow: rgba(56, 225, 255, 0.5);
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  margin-bottom: 14px;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--hdh-color) 55%, var(--line));
  background: linear-gradient(120deg, color-mix(in srgb, var(--hdh-color) 14%, transparent), rgba(56, 225, 255, 0.04)), var(--panel);
  box-shadow: 0 0 26px color-mix(in srgb, var(--hdh-color) 22%, transparent);
}
/* AK13: der reload-freie Poll (app.js hdhTickAndPoll()) setzt das native
   `hidden`-Attribut, wenn das Event ausläuft/beendet wird — OHNE diese Regel
   würde die `display:flex`-Basisregel oben die UA-Default-Regel `[hidden]{display:none}`
   überstimmen (gleiche Selektor-Spezifität, Autor-Stylesheet schlägt UA-Stylesheet). */
.hdh-banner[hidden] { display: none; }
/* Lock 4: dieselben Tokens wie .cs-card[data-tier="N"] --card-color/--card-glow
   (components.css) — Default (fehlt/T1) bleibt Cyan (Basisregel oben). Ein
   Paritätstest (web-320-css-parity.test.js) vergleicht T2–T9 gegen den
   Karten-Kanon. */
.hdh-banner[data-tier="2"] { --hdh-color: var(--magenta); --hdh-glow: rgba(255, 69, 181, 0.5); }
.hdh-banner[data-tier="3"] { --hdh-color: var(--yellow);  --hdh-glow: rgba(255, 216, 74, 0.55); }
.hdh-banner[data-tier="4"] { --hdh-color: var(--green);   --hdh-glow: rgba(94, 255, 138, 0.5); }
.hdh-banner[data-tier="5"] { --hdh-color: var(--card-color-t5); --hdh-glow: var(--card-glow-t5); }
.hdh-banner[data-tier="6"] { --hdh-color: var(--card-color-t6); --hdh-glow: var(--card-glow-t6); }
.hdh-banner[data-tier="7"] { --hdh-color: var(--card-color-t7); --hdh-glow: var(--card-glow-t7); }
.hdh-banner[data-tier="8"] { --hdh-color: var(--card-color-t8); --hdh-glow: var(--card-glow-t8); }
.hdh-banner[data-tier="9"] { --hdh-color: var(--card-color-t9); --hdh-glow: var(--card-glow-t9); }
.hdh-badge {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: var(--hdh-color);
  color: var(--text-on-accent);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.08em;
  box-shadow: 0 0 18px var(--hdh-glow);
}
.hdh-main { flex: 1; min-width: 0; }
.hdh-title {
  font-size: 1.12em;
  font-weight: 800;
  line-height: 1.15;
  display: flex;
  align-items: center;
  gap: 0.55em;
  flex-wrap: wrap;
}
.hdh-pill {
  font-size: 0.68em;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid var(--hdh-color);
  color: var(--hdh-color);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.5;
}
.hdh-msg { font-size: 0.92em; color: var(--text); margin-top: 3px; overflow-wrap: anywhere; }
.hdh-sub { font-size: 0.82em; color: var(--text-dim); margin-top: 3px; }
.hdh-countdown { color: var(--hdh-color); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Trenner zwischen Draw-Leiste und Inventar (DL-1) */
.cs-section-sep {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 18px 0;
}

/* Empty-State des Inventars (DL-6). ui-470: .cs-filter-empty-state (0 Treffer unter
   aktivem Effekt-Filter) teilt sich denselben Look ueber einen kombinierten Selektor —
   server-seitig immer gerendert, client-seitig per .cs-filter-hidden ein-/ausgeblendet
   (dashboard.js renderInvGrid + cards.js applyFilterVisibility). */
.cs-inv-empty-state,
.cs-filter-empty-state {
  padding: 16px;
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.85em;
  margin-bottom: 12px;
}
.cs-draw-jump {
  background: none;
  border: none;
  color: var(--cyan);
  cursor: pointer;
  font-size: inherit;
  padding: 0;
  text-decoration: underline;
  font-family: inherit;
}
.cs-draw-jump:focus { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* just-drawn: Tier-farbiger Ring auf frisch eingefügtem/aktualisiertem Tile (DL-5) —
   ui-625 AK5: liest --card-color/--card-glow statt fixem Cyan, damit Tier >= 2 den
   Ring in der jeweiligen Tier-Farbe zeigt (T5-T9-Folienfarben, ui-611, kommen
   automatisch mit). T1 bleibt fuer die Ring-Farbe/-Border pixelidentisch
   (--card-color IST fuer data-tier="1" var(--cyan), components.css Tier-Farben-Map). */
.cs-card.just-drawn {
  box-shadow: 0 0 0 2px var(--card-color, var(--cyan)), 0 0 18px var(--card-glow, rgba(56, 225, 255, 0.4));
}

/* ===== Draw-Karte Flip-Wrapper (web-043, 2026-06-07) ===== */
/* Dreistufige Hierarchie: perspective-Container → preserve-3d-Inner → Vor-/Rückseite.
   Flip via CSS-transition (nicht @keyframes): Cross-Browser-robust (Chrome + Firefox).
   Der frühere @keyframes-Restart (animation:none → rAF → animation) lief in Chrome,
   blieb aber in Firefox aus (Karte sprang sofort auf die Vorderseite). */

/* ui-487: Stapel-Position (Tiefen-Versatz/Skalierung/Dimmung, DL-1/DL-2) lebt
   auf DIESER Ebene (Wrapper) -- getrennt vom Flip-Transform auf
   .draw-flip-inner (rotateY) darunter; beide Transitionen laufen unabhaengig
   auf verschiedenen Elementen, keine Kollision. right:0/top:0 verankert an
   der rechten Kante des .draw-result-Slots (position:relative, s.o.) -- die
   neueste Karte sitzt unveraendert dort (tx 0), jede aeltere schiebt sich per
   inline --tx (JS, companion/app.js applyDrawStackLayout(), Formel in
   draw-stack.js computeDrawStackLayout()) weiter nach links. ui-513:
   opacity-Transition bleibt fuer die Fly-in-Reveal-Fade (0 -> 1, DL-3)
   erhalten -- die Tiefenstaffelung selbst laeuft jetzt zusaetzlich ueber
   filter (Brightness-Dim statt Alpha-Falloff, s. draw-stack.js). ui-598
   (Perf-Blick AK4, 20 statt 5 Karten): KEIN `will-change: transform;` mehr
   HIER als dauerhafte Basisregel -- bei 20 absolut positionierten
   `filter`-Karten wuerde das permanent 20 eigene Compositing-Layer
   offenhalten, auch ausserhalb jeder Bewegung. companion/app.js setzt
   `will-change` seither NUR waehrend der aktiven Reposition-Transition
   selbst (applyDrawStackLayout()) und loescht es per Timer wieder --
   s. dortiger Kommentar. */
.draw-flip-wrapper {
  position: absolute;
  top: 0;
  right: 0;
  perspective: 600px;
  width: 120px;
  height: 180px;
  transition: transform 0.28s ease, opacity 0.28s ease, filter 0.28s ease;
}

/* Hover hebt eine gestapelte Karte kurz hervor (DL-5) -- KEIN Klick-Verhalten
   (kein neues Interaktions-Fass, Design-Lock). --tx haelt die aktuelle
   X-Position (von applyDrawStackLayout() gesetzt), Scale/Brightness/z-index
   heben die Karte zusaetzlich hervor. !important noetig: app.js setzt
   transform/opacity/filter/z-index PRO LAYOUT-PASS als Inline-Style -- die
   Hover-Regel muss darueber gewinnen. ui-513: filter:brightness(1) hebt eine
   gedimmte (tiefere) Karte beim Hover auf volle Helligkeit -- Analogie zum
   opacity:1-Override, der vor ui-513 denselben Zweck fuer den (inzwischen
   entfernten) Alpha-Falloff erfuellte; opacity:1 bleibt zusaetzlich stehen
   (weiterhin korrekt, auch wenn der Alpha-Kanal inzwischen konstant ist).
   ui-598: z-index-Override 6 -> 21 (DRAW_STACK_MAX_VISIBLE ist jetzt 20, der
   hoechste reguläre zIndex-Wert also 20 statt vormals 5 -- ohne diese
   Anpassung haette eine gehoverte TIEFE Karte mit dem alten Wert 6 hinter
   fast dem gesamten uebrigen Stapel gelegen, statt davor). */
.draw-flip-wrapper:hover {
  z-index: 21 !important;
  transform: translateX(var(--tx, 0px)) scale(1.04) !important;
  opacity: 1 !important;
  filter: brightness(1) !important;
}

/* ui-598 AK2: weiches Verschwinden der aeltesten Karte beim Herausfallen aus
   dem Stapel (21. Draw) -- companion/app.js handleDrawStackExit() fuegt
   diese Klasse hinzu STATT das Element sofort per .remove() zu entfernen,
   setzt danach Ziel-Transform/-Opacity inline (loest die Transition aus,
   analog applyDrawStackLayout() oben). Laengere/eigene Transition (450ms
   ease-out statt der 0.28s-Reposition-Transition der Basisregel) NUR fuer
   Transform/Opacity. ABSICHTLICH ein PLAIN Single-Class-Selektor (KEIN
   `.draw-flip-wrapper.ds-exit`-Compound): haelt dieselbe Spezifitaet (0,1,0)
   wie die Basisregel oben UND wie die reduced-motion-Ueberschreibung weiter
   unten (DL-4-Sammel-Block) -- Cascade-REIHENFOLGE statt !important
   entscheidet dann, welche Regel gewinnt (bei gleicher Spezifitaet gewinnt
   die spaetere Regel im Dokument). Deshalb MUSS diese Regel NACH der
   .draw-flip-wrapper-Basisregel stehen (s.o., fuer den Normalfall) -- und die
   bereits bestehende reduced-motion-Regel weiter unten
   (`.draw-flip-wrapper { transition: none; }`, noch spaeter im Dokument)
   ueberschreibt sie automatisch mit, OHNE dass es dafuer einen eigenen
   .ds-exit-Eintrag im reduced-motion-Block braucht (DL-4: kein JS-Zweig).
   will-change hier ist unkritisch (anders als die Basisregel, AK4): die
   Karte wird spaetestens nach DRAW_STACK_EXIT_FALLBACK_MS aus dem DOM
   entfernt, haelt also nie dauerhaft einen Compositing-Layer offen. */
.ds-exit {
  transition: transform 0.45s ease-out, opacity 0.45s ease-out;
  will-change: transform, opacity;
}

.draw-flip-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform: rotateY(180deg);
  transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);
}

/* KEIN overflow:hidden auf den Faces! Firefox behandelt ein backface-visibility:hidden-
   Face mit overflow!=visible als geflättet (eigener Flattening-Context) → Backface-
   Culling bricht, Vorderseite rendert durch, Rückseite unsichtbar (DL-2 Cross-Browser). */
.draw-flip-front,
.draw-flip-back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: 10px;
}

/* Explizites rotateY(0deg) auf Vorderseite ist PFLICHT für Firefox-Culling.
   Firefox cullt ein backface-visibility:hidden-Face nur zuverlässig, wenn es ein
   eigenes rotateY-Transform hat. Mit transform:none cullt FF die Vorderseite beim
   Flip-Start nicht — sie überdeckt die Rückseite (DL-1). */
.draw-flip-front {
  transform: rotateY(0deg);
}

.draw-flip-back {
  transform: rotateY(180deg);
  background: linear-gradient(155deg, #131a44 0%, #0c1230 100%);
  border: 1px solid var(--line-2);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 8px;
}

/* Hexagon-Rücken-Motiv: inline-SVG (robuster als clip-path bei preserve-3d,
   bekannter Safari-Bug: clip-path erzeugt eigenen Stacking-Context) — DL-3. */
.draw-flip-back-hexagon {
  width: 64px;
  height: 72px;
  opacity: 0.18;
  flex-shrink: 0;
}
.draw-flip-back-hexagon svg {
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 8px var(--cyan));
}

.draw-flip-back-label {
  /* ui-503 (M1): 9px -> 11px-Boden (K1) — 120x180px-Flip-Wrapper hat reichlich
     Raum fuer "Chat Tower" (kurzes Brand-Wort, kein Umbruchrisiko). */
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  opacity: 0.6;
}

/* Glow-Shadow erscheint nach Flip-Ende (DL-7): .flipped via transitionend-Event in JS */
.draw-flip-inner.flipped .cs-card {
  box-shadow:
    0 0 0 1px var(--card-color, var(--cyan)),
    0 6px 24px rgba(0, 0, 0, 0.4),
    0 0 32px var(--card-glow, rgba(56, 225, 255, 0.4));
}

/* ===== ui-625: Special-Reveal für Tier-2+-Draws (immer, unabhängig von einer
   Happy Draw Hour — Lock 3; web-320 bleibt der reine Event-/Banner-Layer,
   Split aus dessen Prototyp-Abschnitt 2). --special-color/--special-glow
   setzt companion/app.js applyDrawSpecialReveal() inline auf den Wrapper —
   kopiert 1:1 aus den BERECHNETEN --card-color/--card-glow des gerenderten
   .cs-card (Lock 1: eine Farbquelle, kein zweites Register — T5-T9-
   Folienfarben, ui-611, kommen automatisch mit). Läuft NACH dem Flip-Ende
   (transitionend → .flipped, DL-7-Glow oben ist zu diesem Zeitpunkt bereits
   aktiv), rein additiv — kein Eingriff in Button-Re-Enable/Stapel-Layout/
   Exit/Inventar-Einfügen (Lock 2). Wrapper-`transform` bleibt dem
   Stapel-Layout vorbehalten (Lock 4) — Pop/Ring laufen auf dem `.cs-card`-
   Kind bzw. auf den Pseudo-Elementen des Wrappers, nie auf dem
   Wrapper-transform selbst. Gesamtdauer <= 700ms (Klasse `draw-special`
   fällt nach 800ms/1400ms-Reduced-Motion wieder ab, s. Hook). Werte 1:1 aus
   dem Prototyp (.claude/sprint/prototypes/web-320.html Abschnitt 2), OHNE
   dessen `--tempo`-Review-Variable (Zeitlupe, nur für die Prototyp-Review). */
.draw-flip-wrapper.draw-special {
  --special-color: var(--cyan);
  --special-glow: rgba(56, 225, 255, 0.5);
}
.draw-flip-wrapper.draw-special .draw-flip-front .cs-card {
  animation:
    hdh-pop 420ms cubic-bezier(0.2, 0.9, 0.3, 1.2) both,
    hdh-cardring 700ms ease-out both;
}
@keyframes hdh-pop {
  0%   { transform: scale(1);    filter: brightness(1); }
  30%  { transform: scale(1.07); filter: brightness(1.45); }
  100% { transform: scale(1);    filter: brightness(1); }
}
@keyframes hdh-cardring {
  0%   { box-shadow: 0 0 0 2px var(--special-color), 0 0 26px var(--special-glow); }
  70%  { box-shadow: 0 0 0 2px var(--special-color), 0 0 26px var(--special-glow); }
  100% { box-shadow: 0 0 0 0 transparent, 0 0 0 transparent; }
}
/* Burst-Ring — z-index über .draw-flip-inner (das keinen eigenen z-index
   setzt), pointer-events:none (rein dekorativ, kein Klick-/Hover-Ziel). */
.draw-flip-wrapper.draw-special::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 14px;
  pointer-events: none;
  z-index: 3;
  border: 2px solid var(--special-color);
  box-shadow: 0 0 18px var(--special-glow);
  animation: hdh-ring 620ms ease-out both;
}
@keyframes hdh-ring {
  0%   { transform: scale(0.96); opacity: 1; }
  100% { transform: scale(1.28); opacity: 0; }
}
/* Funkenkranz — repeating-conic-gradient radial maskiert auf einen Ring. */
.draw-flip-wrapper.draw-special::before {
  content: "";
  position: absolute;
  inset: -16px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 3;
  background: repeating-conic-gradient(from 0deg, var(--special-color) 0 4deg, transparent 4deg 30deg);
  -webkit-mask: radial-gradient(circle, transparent 56%, #000 58%, #000 66%, transparent 68%);
          mask: radial-gradient(circle, transparent 56%, #000 58%, #000 66%, transparent 68%);
  animation: hdh-sparks 560ms ease-out both;
}
@keyframes hdh-sparks {
  0%   { transform: scale(0.7) rotate(0deg);   opacity: 0; }
  25%  { opacity: 1; }
  100% { transform: scale(1.25) rotate(25deg); opacity: 0; }
}
/* Variante B (AK3): schwebendes Label "TIER N" — vorbereitet über die
   html.variant-b-Klasse, aber NICHT aktiv (Fifty-Wahl Q1 steht aus, Default
   ist Variante A ohne Label). companion/app.js erzeugt das Element NUR, wenn
   `variant-b` am html-Element gesetzt ist — kein toter DOM-Knoten im Default. */
.draw-special-label {
  display: none;
  position: absolute;
  left: 50%;
  top: -14px;
  transform: translateX(-50%);
  z-index: 4;
  pointer-events: none;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--special-color);
  text-shadow: 0 0 10px var(--special-glow);
  white-space: nowrap;
}
html.variant-b .draw-flip-wrapper.draw-special .draw-special-label {
  display: block;
  animation: hdh-label 700ms ease-out both;
}
@keyframes hdh-label {
  0%   { transform: translate(-50%, 6px);   opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: translate(-50%, -18px); opacity: 0; }
}

/* Waffen-Karte: Yellow-Override via .is-weapon-Klasse (additiv, kein .cs-card-Override) — DL-6, DL-9 */
.cs-card.is-weapon {
  --card-color: var(--yellow);
  --card-glow: rgba(255, 216, 74, 0.55);
}

/* Waffen-Badge ("WAFFE") und Waffen-Bonus-Label für Draw-Karte */
.cs-card-tier-badge.weapon-badge {
  background: var(--yellow);
  color: var(--text-on-accent);
  letter-spacing: 0.06em;
}
.cs-card-bonus.is-weapon-label {
  font-size: 12px;
  font-weight: 600;
}

/* Mobile: Vollbild (DL-2) -- ui-602 AK4: `.cs-modal-backdrop`/`.cs-drop-odds`/
   `.cs-do-close` waren hier BARE (Top-Level, kein Eltern-Scope) -- da
   `.cs-modal-backdrop` der GETEILTE Backdrop-Baustein fuer JEDES Modal ist
   (components.css, inzwischen auch Club-/Season-Pass-Kauf-Popins und das
   kommende Geschenk-Popup ui-601), machte diese Regel bei <=520px JEDES
   offene Modal randlos/vollflaechig -- nicht nur das hier gemeinte Drop-
   Chancen-Modal (belegter Kollisionsfall, s. ui-602-Ticket "Was & Warum";
   Backdrop traegt `id="drop-odds-backdrop"`, s.
   web/client/companion/util.js createDropOddsModal()). Fix: Scope auf die
   Drop-Chancen-Modal-Instanz per ID -- kein Markup-Wechsel, keine
   Verhaltensaenderung fuer das Drop-Chancen-Modal selbst (die ID sitzt
   bereits IMMER auf demselben Element wie die Klasse), aber die Regel
   trifft jetzt NIE mehr ein anderes `.cs-modal-backdrop`. `.cs-do-grid`
   bleibt bewusst BARE: dieselbe Klasse traegt zusaetzlich das Shop-
   Karten-Reveal-Grid (views/shop.js, ui-557/ui-575 "kein Fork der Karten-
   Optik") -- eine Scope-Aenderung haette dessen Mobile-Layout
   mitverschoben (Regressionsrisiko, Lock "keine visuelle Aenderung").
   `.cs-drop-odds-link` bleibt ebenfalls BARE: reiner Touch-Ziel-Groessen-
   Fix (min-height) auf dem ausserhalb des Backdrops liegenden Trigger-
   Button, kein weiterer Klassen-Konsument existiert (kein Kollisionsrisiko,
   s. Baseline-Eintrag mit reason). */
@media (max-width: 520px) {
  #drop-odds-backdrop.cs-modal-backdrop {
    padding: 0;
    align-items: stretch;
  }
  #drop-odds-backdrop .cs-drop-odds {
    width: 100%;
    max-height: 100svh;
    border-radius: 0;
    border-left: none;
    border-right: none;
  }
  .cs-do-grid {
    grid-template-columns: repeat(auto-fill, minmax(102px, 1fr));
    gap: 10px;
  }
  #drop-odds-backdrop .cs-do-close {
    padding: 12px 14px;
  }
  .cs-drop-odds-link {
    min-height: 44px;
  }
}

.hexa-totals {
  display: flex;
  gap: 1em;
  margin: 1em 0 1.5em;
  flex-wrap: wrap;
}
.hexa-totals .stat-pill.big .stat-num {
  color: var(--cur-hexa); /* ui-623: SSOT-Token-Alias, Wert unverändert (Hexa bleibt Magenta) */
  text-shadow: 0 0 16px rgba(255, 69, 181, 0.5);
  font-size: 2.2em;
}

.hexa-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.5em;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.92em;
}
.hexa-table th {
  color: var(--muted);
  font-size: 0.82em; /* ui-344: 0.75em→0.82em, war ~10.35px (0.75em x 0.92em-Tabellenkontext) */
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
  text-align: left;
  padding: 0.4em 0.8em;
  border-bottom: 1px solid var(--line);
}
.hexa-table th.num { text-align: right; }
.hexa-table td {
  padding: 0.55em 0.8em;
  border-bottom: 1px solid var(--line);
}
.hexa-table td.num { text-align: right; }

/* ui-214 Breakpoint-Kanon -- volle Doku in pages/shared-mobile.css. */
@media (max-width: 600px) {
  .socket-row {
    grid-template-columns: 2em 1fr;
    grid-template-rows: auto auto;
  }
  .socket-icon, .socket-slot-index { grid-row: 1; }
  .socket-select { grid-column: 1 / -1; grid-row: 2; }
  .socket-status { grid-column: 1 / -1; text-align: left; }
}

/* ===== Karten & Sockel Tab (ui-007, 2026-05-29) ===== */
/* Tier-Farb-Variablen: gesetzt via data-tier am .cs-card Element.          */
/* T1 cyan → T2 magenta → T3 gold → T4 green → T5 white (alle ≥T5 = white) */

/* ui-255: Query-Container für den fluiden Spalten-Mechanismus.
   #cs-root hat kein horizontales Padding → 100cqw == .cs-layout-Breite. */
#cs-root {
  container-type: inline-size;
}

.cs-layout {
  /* ui-255: Fluider, geteilter Spaltenwert via Container-Query (DL-1/DL-2).
     --col: ein Spaltenwert für BEIDE Grids (5 Inv-Spalten + 2 Sockel-Spalten = 7 Gesamt).
     100cqw = #cs-root-Breite; alle Gaps + Panel-Chrome (Padding+Border) + Layout-Gap abziehen,
     durch 7 teilen → exakte Kartenbreite die den Container lückenlos füllt.
     min(200px,…) cappt bei großen Viewports (≥~1560px) → Layout zentriert (Außenränder). */
  --gap: 10px;
  --lgap: 24px;
  --chrome: 42px; /* 2*20px Panel-Padding + 2*1px Border je Panel */
  --col: min(200px, calc((100cqw - 5 * var(--gap) - 2 * var(--chrome) - var(--lgap)) / 7));
  display: grid;
  /* Panel-Breite = exakt das Karten-Grid des jeweiligen Panels (DL-2).
     justify-content:center hält Mittel-Gap fix; Restfläche geht nach außen → nie leere Mitte. */
  grid-template-columns:
    calc(5 * var(--col) + 4 * var(--gap) + var(--chrome))
    calc(2 * var(--col) + 1 * var(--gap) + var(--chrome));
  justify-content: center;
  gap: var(--lgap);
  align-items: start;
}
@media (max-width: 1100px) {
  .cs-layout { grid-template-columns: 1fr; }
  /* ui-244 DL-7: Grids auf fluid — feste --cs-card-col würde auf schmalen Viewports
     überlaufen; repeat(N,1fr) passt sich dem Panel an. */
  .cs-inv-grid { grid-template-columns: repeat(5, 1fr); }
  .cs-socket-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ui-318: Mobil-Sub-Umschalter "◇ Sockel ⇄ ◆ Inventar" — Desktop-Basis
   display:none (Toggle ist ohne Mobile-Layout ueberfluessig, Inv+Sockel
   stehen nebeneinander). ≤600px-Block weiter unten (web-085-Mobile-Fallback-
   Sektion) schaltet auf display:flex + fuegt die Show/Hide-Regeln fuer die
   beiden .cs-panel-Sections hinzu (data-mobile-sub-Attribut auf dem stabilen
   #cs-root, s. dashboard.js renderCardsAndSockets-Kommentar). */
.cs-subtoggle {
  display: none;
}

.cs-panel {
  background: rgba(17, 22, 42, 0.6);
  border: 1px solid rgba(120, 180, 255, 0.18);
  border-radius: 14px;
  padding: 20px;
  backdrop-filter: blur(8px);
}
.cs-panel.cs-drop-zone-active {
  border-color: var(--magenta);
  box-shadow: 0 0 12px rgba(255, 69, 181, 0.4);
}

.cs-panel-title {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  margin: 0 0 4px;
  color: var(--magenta);
  text-shadow: 0 0 8px rgba(255, 69, 181, 0.45);
}
.cs-panel-sub {
  font-size: 12px;
  color: var(--muted);
  margin: 0 0 16px;
}

/* =====================================================================
   ui-111: Upgrade-Leiste + vereinheitlichtes Control + Merge-Animation
   ===================================================================== */

/* Leiste: horizontale Gruppe direkt unter .cs-panel-sub, über Sort-Bar */
.cs-upgrade-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin: 0 0 14px;
}

/* Pill-Group-Control: Button links + Auto-Toggle rechts (DL-1 "Checkbox im Button") */
.cs-upgrade-ctl {
  display: inline-flex;
  align-items: stretch;
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid var(--cyan);
  background: var(--bg-2);
  box-shadow: 0 0 0 1px rgba(56, 225, 255, 0.10), 0 0 18px rgba(56, 225, 255, 0.12);
  transition: border-color 0.2s, box-shadow 0.2s, opacity 0.2s;
}

/* Manueller Trigger (Button-Seite) */
.cs-upgrade-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font: inherit;
  font-size: 0.92em;
  font-weight: 600;
  padding: 0.6em 1.15em;
  min-height: 44px;
  cursor: pointer;
  border: none;
  background: var(--cyan);
  color: var(--bg);
  letter-spacing: 0.01em;
  transition: background 0.15s, color 0.15s, transform 0.1s;
}
.cs-upgrade-btn:hover:not(:disabled) {
  transform: translateY(-1px);
}
.cs-upgrade-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.cs-upgrade-btn-icon {
  font-size: 1.05em;
  line-height: 1;
}
.cs-upgrade-btn-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5em;
  height: 1.5em;
  padding: 0 0.4em;
  border-radius: 999px;
  background: rgba(6, 8, 15, 0.28);
  color: var(--bg);
  font-size: 0.8em;
  font-weight: 700;
}

/* ui-192: Lade-/Berechnungs-State des Badges — dezenter Puls, kein Zahl-Flip */
.cs-upgrade-btn-badge.is-calc {
  color: rgba(6, 8, 15, 0.55);
  letter-spacing: 0.05em;
  animation: badgePulse 1s ease-in-out infinite;
}
@keyframes badgePulse {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.95; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-upgrade-btn-badge.is-calc {
    animation: none;
    opacity: 0.7;
  }
}

/* Zustand: nichts upgradebar (DL-3, ui-180) — ganzes Control gedimmt */
.cs-upgrade-ctl.is-empty {
  border-color: var(--line-2);
  box-shadow: none;
}
.cs-upgrade-ctl.is-empty .cs-upgrade-btn {
  background: var(--line-2);
  color: var(--muted);
  cursor: default;
}
.cs-upgrade-ctl.is-empty .cs-upgrade-btn-badge {
  display: none;
}

/* Status-Text neben dem Control */
.cs-upgrade-status {
  font-size: 0.8em;
  color: var(--muted);
}
.cs-upgrade-status b {
  color: var(--cyan);
}

/* -----------------------------------------------------------------------
   ui-142: Vorschau-Toggle (dritter Pill-Abschnitt) + Vorschau-Panel
   ----------------------------------------------------------------------- */

/* Vorschau-Toggle: dritter Pill-Abschnitt (DL-1) */
.cs-upgrade-preview-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: inherit;
  font-size: 0.82em;
  font-weight: 600;
  padding: 0.6em 0.9em;
  cursor: pointer;
  border: none;
  border-left: 1px solid rgba(6, 8, 15, 0.25);
  background: var(--cyan);
  color: var(--bg);
  min-height: 44px;
  transition: background 0.15s, color 0.15s;
}
.cs-upgrade-preview-toggle:hover:not(:disabled) {
  filter: brightness(1.05);
}
.cs-upgrade-preview-toggle:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.cs-upgrade-preview-toggle .chev {
  transition: transform 0.15s;
  font-size: 0.9em;
  line-height: 1;
}
.cs-upgrade-ctl.preview-open .cs-upgrade-preview-toggle .chev {
  transform: rotate(180deg);
}

/* Vorschau-Panel (DL-2, ui-142): Popover unter .cs-upgrade-bar */
.cs-upgrade-preview {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  min-width: 270px;
  max-width: 360px;
  background: var(--panel);
  border: 1px solid var(--cyan);
  border-radius: 10px;
  padding: 10px 12px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5), 0 0 22px rgba(56, 225, 255, 0.15);
}
.cs-upgrade-preview.open {
  display: block;
}
/* .cs-upgrade-bar braucht position:relative für absolutes Popover */
.cs-upgrade-bar {
  position: relative;
}

/* Panel-Kopfzeile */
.cs-upgrade-preview-head {
  font-size: 0.74em;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  margin: 0 0 8px;
  display: flex;
  justify-content: space-between;
}

/* Zeile pro Effekt (DL-2): Symbol · Name · T-Sprung */
.cs-prev-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 0;
  border-top: 1px solid var(--line);
}
.cs-prev-row:first-of-type {
  border-top: none;
}
.cs-prev-sym {
  font-size: 1.25em;
  width: 1.4em;
  text-align: center;
  filter: drop-shadow(0 0 6px currentColor);
}
.cs-prev-name {
  flex: 1;
  font-size: 0.9em;
}
.cs-prev-jump {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.82em;
  font-weight: 600;
}
.cs-prev-tier {
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid;
  font-size: 0.85em;
}
.cs-prev-arrow {
  color: var(--text-dim);
}
.cs-prev-count {
  font-size: var(--fs-caption); /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
  color: var(--muted);
}

/* Fuß-Zeile mit Gesamt */
.cs-upgrade-preview-foot {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 0.78em;
  color: var(--text-dim);
}

/* Lade-Placeholder */
.cs-prev-loading {
  font-size: 0.9em;
  color: var(--muted);
  padding: 4px 0;
}

/* -----------------------------------------------------------------------
   ui-142: Narrations-Spans in der Statuszeile (DL-3)
   ----------------------------------------------------------------------- */
.cs-upgrade-status .narrate-sym {
  font-size: 1.15em;
  vertical-align: -1px;
}
.cs-narrate-tier {
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid;
  font-size: 0.85em;
  font-weight: 600;
}
.cs-narrate-arrow {
  color: var(--text-dim);
}

/* -----------------------------------------------------------------------
   ui-142: Floating-Label am mergenden Tile (DL-3 Sekundärkanal)
   ----------------------------------------------------------------------- */
.cs-merge-label {
  position: absolute;
  left: 50%;
  bottom: 8px;
  transform: translateX(-50%);
  white-space: nowrap;
  z-index: 7;
  font-size: var(--fs-caption); /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  pointer-events: none;
  background: rgba(6, 8, 15, 0.82);
  border: 1px solid var(--upgrade-color, var(--cyan));
  color: var(--upgrade-color, var(--cyan));
  box-shadow: 0 0 12px var(--upgrade-color, var(--cyan));
  animation: cs-merge-label-in 0.42s ease forwards;
}
@keyframes cs-merge-label-in {
  0%   { opacity: 0; transform: translate(-50%, 6px); }
  100% { opacity: 1; transform: translate(-50%, 0); }
}

/* -----------------------------------------------------------------------
   Merge-Animation (DL-5): reload-frei, gestaffelt, Tier-Farb-Sprache
   1) Quell-Tile sackt zusammen + Upgrade-Farb-Blitz
   2) Aufsteigendes ▲ (Spark)
   3) Ergebnis-Tile pulst im neuen Tier-Ring
   ----------------------------------------------------------------------- */

/* 1) Quell-Tile: sackt zusammen + Box-Shadow-Blitz */
.cs-card.cs-upgrading {
  animation: cs-upgrade-collapse 0.28s ease forwards;
  box-shadow: 0 0 0 2px var(--upgrade-color), 0 0 26px var(--upgrade-color);
  z-index: 5;
}
@keyframes cs-upgrade-collapse {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.06); }
  100% { transform: scale(0.82); opacity: 0.15; }
}

/* 2) Aufsteigendes ▲ (Spark) */
.cs-upgrade-spark {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6em;
  color: var(--upgrade-color);
  pointer-events: none;
  z-index: 6;
  animation: cs-spark-rise 0.42s ease forwards;
  text-shadow: 0 0 14px var(--upgrade-color);
}
@keyframes cs-spark-rise {
  0%   { opacity: 0; transform: translateY(8px) scale(0.7); }
  35%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-22px) scale(1.25); }
}

/* 3) Ergebnis-Tile: pulst kurz im neuen Tier-Ring */
.cs-card.just-upgraded {
  animation: cs-just-upgraded 1s ease;
}
@keyframes cs-just-upgraded {
  0%   { box-shadow: 0 0 0 3px var(--card-color), 0 0 26px var(--card-glow); transform: scale(1.04); }
  100% { box-shadow: 0 0 0 0 transparent; transform: scale(1); }
}

/* prefers-reduced-motion: alle Upgrade-Animationen deaktivieren (DL-6) */
/* ui-142: auch cs-merge-label + .cs-upgrade-preview-toggle .chev deaktivieren */
@media (prefers-reduced-motion: reduce) {
  .cs-card.cs-upgrading,
  .cs-upgrade-spark,
  .cs-card.just-upgraded,
  .cs-merge-label {
    animation: none !important;
  }
  .cs-card.cs-upgrading {
    opacity: 0.4;
  }
  .cs-upgrade-preview-toggle .chev {
    transition: none;
  }
  /* ui-625 AK4: Burst-Ring/Funkenkranz/Label aus, Karten-Pop-Animation aus,
     statischer Tier-Ring (16px Blur statt 26px, 1400ms — wie .just-drawn). */
  .draw-flip-wrapper.draw-special::before,
  .draw-flip-wrapper.draw-special::after,
  .draw-special-label {
    display: none !important;
    animation: none !important;
  }
  .draw-flip-wrapper.draw-special .draw-flip-front .cs-card {
    animation: none !important;
    box-shadow: 0 0 0 2px var(--special-color), 0 0 16px var(--special-glow);
  }
}

/* --- Sort Toolbar (web-036) + Filter-Disclosure (ui-470 → ui-479) ---
   ui-470 Design-Lock "Muster = Sortierleiste": .cs-filter-btn teilt sich JEDE
   Basisregel mit .cs-sort-btn ueber kombinierte Selektoren (garantiert Pixel-
   Paritaet statt einer separat gepflegten Kopie) — die Chips leben seit ui-479
   INNERHALB der Disclosure (.cs-filter-body); die frühere flache Leiste
   #cs-filter-bar/.cs-filter-bar/.cs-filter-label gibt es nicht mehr (ersetzt durch
   .cs-filter/.cs-filter-head/.cs-filter-group-label weiter unten). */
.cs-sort-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 16px;
}
.cs-sort-label {
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: 2px;
}
/* Segment-Buttons = Pill-Toggles, Radius 999 (Styleguide) */
/* ui-124: Ruhe-color = --text (statt --muted) — alle Sort-Buttons gleichwertig
   klickbar; ui-470/ui-479: identische Regel fuer die Filter-Chips (Muster-Lock). */
.cs-sort-btn,
.cs-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 6px 14px;
  background: var(--bg-2);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.cs-sort-btn:hover,
.cs-filter-btn:hover {
  border-color: var(--cyan);
  color: var(--text);
}
.cs-sort-btn:focus-visible,
.cs-filter-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
/* Aktiver Zustand = Cyan (primär/interaktiv) + dezenter Glow (DL-3) — unverändert;
   ui-470/ui-479: gilt identisch fuer .cs-filter-btn.is-active. */
.cs-sort-btn.is-active,
.cs-filter-btn.is-active {
  border-color: var(--cyan);
  color: var(--cyan);
  background: rgba(56, 225, 255, 0.10);
  box-shadow: 0 0 10px rgba(56, 225, 255, 0.18);
}
/* ui-124: .cs-sort-btn.is-default entfernt — gestrichelter Lazy-Default entfällt */
.cs-sort-arrow {
  font-size: 11px;
  line-height: 1;
  display: inline-block;
  min-width: 8px;
}
/* ui-124: .cs-sort-state + @media-Regel entfernt — State-Narration entfällt */

/* ui-479 (DL-3): Zähler-Kapsel auf Filter-Chips — .cs-sort-btn hat keine .n-Kinder,
   deshalb kein kombinierter Selektor noetig. */
.cs-filter-btn .n {
  font-size: 11px;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.06);
  border-radius: 999px;
  padding: 1px 6px;
  line-height: 1.5;
}
.cs-filter-btn.is-active .n {
  color: var(--cyan);
  background: rgba(56, 225, 255, 0.16);
}
/* AK3/DL-3: 0-Treffer-Chips bleiben klickbar, aber gedimmt. */
.cs-filter-btn.is-zero {
  opacity: 0.5;
}

/* -----------------------------------------------------------------------
   ui-479: Filter-Disclosure — Kopf (immer sichtbar, Toggle + aktive Chips) +
   ausklappbarer Body (zwei Achsen: Nutzung, Effekt). Ersetzt die flache
   ui-470-Leiste. Struktur/Klassen/Abstände 1:1 aus dem Prototyp übernommen:
   .claude/sprint/prototypes/ui-479.html.
   ui-480: dritte, unabhängige Achse "upgradebar" als Toggle in der Nutzungs-Zeile
   (.cs-filter-sep/.cs-filter-sub-label weiter unten) — kein eigener Prototyp-Lauf,
   Muster/Klassen von ui-479 uebernommen (Dev-Ticket, s. dortige Design-Locks).
   ----------------------------------------------------------------------- */
.cs-filter {
  margin: 0 0 16px;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  /* AK7-Lock "kein neues Farb-Token": der Prototyp definierte ein eigenes lokales
     --bg-3, das im Companion-Token-Set (public/tokens.css) nicht existiert.
     --panel ist der etablierte Token für verschachtelte Sub-Panels (identisches
     Muster wie .cs-upgrade-preview weiter oben). */
  background: var(--panel);
}
.cs-filter-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  min-height: 50px;
}
.cs-filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 6px 12px 6px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cs-filter-toggle .lbl {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 12px;
  color: var(--muted);
}
.cs-filter-toggle .chev {
  display: inline-block;
  transition: transform 0.18s ease;
  color: var(--muted);
}
.cs-filter.is-open .cs-filter-toggle .chev {
  transform: rotate(180deg);
}
.cs-filter.is-open .cs-filter-toggle {
  border-color: var(--cyan);
}
.cs-filter-toggle:hover {
  border-color: var(--cyan);
}
.cs-filter-toggle:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.cs-filter-current-mount {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.cs-filter-current {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 6px 8px 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--bg-2);
  color: var(--text);
  font-size: 13px;
}
.cs-filter-current.is-set {
  border-color: var(--cyan);
  color: var(--cyan);
  background: rgba(56, 225, 255, 0.10);
}
.cs-filter-current.neutral {
  padding-right: 12px;
}
.cs-filter-count {
  font-size: 12px;
  color: var(--muted);
}
.cs-filter-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  border: 1px solid transparent;
  background: rgba(56, 225, 255, 0.16);
  color: var(--cyan);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}
.cs-filter-clear:hover {
  background: rgba(56, 225, 255, 0.30);
}
.cs-filter-clear:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.cs-filter-body {
  display: none;
  padding: 2px 10px 12px;
  border-top: 1px solid var(--line);
}
.cs-filter.is-open .cs-filter-body {
  display: block;
}
.cs-filter-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
}
.cs-filter-group-label {
  flex: 0 0 100%;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 2px 0 -2px;
}
.cs-filter-group.usage {
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
/* ui-480 (DL-1): Trenner + Mini-Label der dritten, unabhaengigen Achse "upgradebar" —
   INNERHALB der Nutzungs-Zeile (.cs-filter-group.usage), rechts hinter den drei
   Nutzungs-Chips. .cs-filter-sub-label teilt die Typografie von .cs-filter-group-label
   (11px uppercase, Farbe muted), aber OHNE flex 0 0 100 Prozent - bleibt auf Desktop
   inline in derselben umbrechenden Zeile wie die Chips; die Mobile-Media-Query weiter
   unten erzwingt bei knappem Platz die eigene Zeile. */
.cs-filter-sep {
  width: 1px;
  height: 22px;
  background: var(--line);
  margin: 0 4px;
}
.cs-filter-sub-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.cs-filter-legend {
  margin: 12px 0 0;
  font-size: 11px;
  color: var(--muted);
}
/* DL-6: Mobile-Kompaktion (≤600px) — nur Größe/Padding, KEIN Auto-Collapse (JS-Seite,
   cards.js). min-height:32px hier ist NICHT die letzte Instanz: auf echten Touch-
   Geräten (narrow WEIT UND coarse Pointer gleichzeitig) gewinnt die spätere, generische
   .cs-filter-btn-Touch-Regel weiter unten (@media (hover:none),(pointer:coarse),
   min-height:44px, WCAG-2.5.5-Floor aus ui-470) per Source-Order bei gleicher
   Spezifität (0,1,0) — Padding/min-height dort überschreiben diese Zeilen, font-size
   bleibt bei 12.5px unangetastet (die Touch-Regel setzt keine font-size). Absicht:
   volle DL-6-Kompaktion auf schmalen Nicht-Touch-Viewports (z.B. verkleinertes
   Desktop-Fenster), aber nie unter den etablierten 44px-Touch-Floor auf echten Handys. */
@media (max-width: 600px) {
  .cs-filter-head {
    gap: 6px;
    padding: 8px;
  }
  .cs-filter-btn {
    min-height: 32px;
    padding: 5px 11px;
    font-size: 12.5px;
  }
  /* ui-480 (DL-1 Mobile-Klausel): Trenner ausblenden statt als Zeilen-Waise am Anfang
     einer umgebrochenen Zeile zu haengen; Mini-Label bekommt stattdessen dieselbe
     flex-basis-100-Regel wie .cs-filter-group-label, das schiebt Label + Toggle-Chip
     zusammen auf eine eigene Zeile (identisches Muster, nur ohne den vollen Uppercase-
     Achsen-Block darueber). */
  .cs-filter-sep {
    display: none;
  }
  .cs-filter-sub-label {
    flex: 0 0 100%;
    margin-top: 4px;
  }
}

/* ===== ui-488: Upgrade-Kontext-Hinweis "Drei gleiche Karten!" (DL-1..DL-5) =====
   Sitzt in #cs-inv-panel zwischen der Filter-Leiste und .cs-inv-grid (DL-1
   "unterhalb der Filter-Leiste, ueber dem Karten-Grid"). Struktureller Server-Gate
   ist upgradeableInvCount>0 (dashboard.js renderInvGrid) — ob das Banner
   TATSAECHLICH sichtbar ist, entscheidet ausschließlich cards.js
   syncUpgradeHintBanner() per .is-dismissed (localStorage-getrieben, NICHT das
   native [hidden]-Attribut — s. dortiger Kommentar zur Spezifitäts-Falle, analog
   .cs-filter-hidden weiter unten). Optik: gedämpfter Rahmen + cyan Akzent
   (Bausprache wie .fd-banner oben), aber EIN Akzentton (kein Magenta-Gradient —
   .fd-banner ist ein Belohnungs-Banner, dies ist ein reiner Hinweis). */
.cs-upgrade-hint {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  background: rgba(56, 225, 255, 0.06);
  border: 1px solid color-mix(in srgb, var(--cyan) 35%, var(--line));
  border-radius: var(--card-radius);
  padding: 14px 48px 14px 16px;
  margin-bottom: 14px;
  animation: cs-upgrade-hint-in 0.3s ease-out;
}
.cs-upgrade-hint.is-dismissed {
  display: none;
}
@keyframes cs-upgrade-hint-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-upgrade-hint { animation: none; }
}
.cs-upgrade-hint-icon {
  flex: 0 0 auto;
  margin-top: 2px;
  font-size: 20px;
  line-height: 1;
  color: var(--cyan);
}
.cs-upgrade-hint-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cs-upgrade-hint-text {
  margin: 0;
  font-size: 0.86em;
  line-height: 1.45;
  color: var(--text-dim);
}
.cs-upgrade-hint-text strong {
  color: var(--text);
}
.cs-upgrade-hint-cta {
  align-self: flex-start;
  font: inherit;
  font-size: 0.85em;
  font-weight: 700;
  padding: 0.55em 1.1em;
  min-height: 36px;
  background: transparent;
  color: var(--cyan);
  border: 1px solid var(--cyan);
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.cs-upgrade-hint-cta:hover {
  background: var(--cyan);
  color: var(--bg);
}
.cs-upgrade-hint-close {
  position: absolute;
  top: 4px;
  right: 4px;
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 1em;
  cursor: pointer;
  border-radius: 6px;
  transition: color 0.15s;
}
.cs-upgrade-hint-close:hover {
  color: var(--cyan);
}

/* --- Inventory Grid --- */
.cs-inv-grid {
  display: grid;
  /* ui-255: Spaltenbreite aus dem fluiden --col-Token auf .cs-layout → pixelgleich mit Sockel-Grid */
  grid-template-columns: repeat(5, var(--col));
  gap: var(--gap);
}
.cs-inv-slot {
  position: relative;
  aspect-ratio: 3 / 4;
  min-height: 0;
}
/* ui-470: Effekt-Filter — Skeleton+Patch (kein Grid-Struktur-Re-Render, nur ein
   Sichtbarkeits-Toggle; Grid-Auto-Flow schließt die entstehende Lücke automatisch,
   keine manuelle Re-Kompaktierung nötig). Greift auf .cs-inv-slot (Karten + leere
   Slots, cards.js applyFilterVisibility) UND .cs-filter-empty-state (dashboard.js).
   BUG-BELEG (Browser-Smoke ui-470): eine einfache `.cs-filter-hidden{display:none}`
   verlor bei .cs-slot-empty-Elementen (leere Grid-Platzhalter, ZWEI Klassen:
   "cs-inv-slot cs-slot-empty cs-filter-hidden") den Kaskaden-Tiebreak GEGEN
   .cs-slot-empty{display:flex} weiter unten — gleiche Spezifität (0,1,0), spätere
   Regel gewinnt per Source-Order. classList.contains('cs-filter-hidden') meldete
   dadurch fälschlich "korrekt", während computed display trotzdem 'flex' blieb
   (nur per echtem Screenshot sichtbar, nicht per DOM-Property-Check — s.
   dom-property-check-is-no-layout-proof-Lehre). Fix: verkettete Selektoren
   (Spezifität (0,2,0)) schlagen JEDE (0,1,0)-Regel unabhängig von der Datei-
   Position — kein Source-Order-Wettrennen mehr. */
.cs-inv-slot.cs-filter-hidden,
.cs-filter-empty-state.cs-filter-hidden {
  display: none;
}
.cs-slot-empty {
  border: 1px dashed rgba(120, 180, 255, 0.15);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(142, 162, 200, 0.25);
  font-size: 22px;
  transition: all 0.15s ease;
}
.cs-slot-empty:hover,
.cs-slot-empty.cs-drag-over {
  border-color: var(--cyan);
  background: rgba(56, 225, 255, 0.08);
  color: var(--cyan);
}
.cs-inv-slot.cs-drag-over {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
  border-radius: 10px;
  box-shadow: 0 0 12px rgba(56, 225, 255, 0.5);
}

/* ui-228: Inventar-Karte mit ungenutztem Bonus-Typ (kein Sockel belegt für diesen effect_key,
   mindestens ein Sockel frei — Gate). Variante B aus Prototyp ui-228.html.
   Statisch (kein @keyframes) — grenzt sich ab von merge-bereit (Magenta-Rotation)
   und just-drawn (Tier-farbiger Ring seit ui-625, transient). Badge via ::before auf .cs-inv-slot (position:relative
   bereits gesetzt). is_weapon-Karten werden nie markiert (server-seitig ausgefiltert). */
.cs-slot--unsocketed {
  box-shadow: inset 0 0 0 1px rgba(94, 255, 138, 0.55);
  border-radius: 10px;
}
.cs-slot--unsocketed::before {
  content: "ungenutzt";
  position: absolute;
  top: -1px;
  left: -1px;
  z-index: 2;
  /* ui-503 (M1): 0.55rem (~8.25px effektiv) -> 11px-Boden (K1), direkter
     px-Wert. Echte Info (Karte belegt keinen Sockel-Bonus), kein Deko-
     Kandidat — Live-CDP-Fit-Check bei 390px s. Ticket ## Notes. */
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #06080f;
  background: var(--green);
  padding: 2px 6px;
  border-radius: 8px 0 8px 0;
  pointer-events: none;
}

/* --- Socket Grid --- */
/* ui-623 (Review-Runde 1, 2026-09-09): --cur-socket statt Cyan — der
   "N / Cap gesockelt"-Zähler im Panel-Kopf (renderSocketGrid()) ist ein
   echter Sockel-Betrag, der erste AK4-Sweep hatte ihn übersehen (must-fix).
   Border+Text-Paar-Muster wie .kw-pill/.fd-icon; Text-Shadow-RGB-Werte wie
   #draws-remaining-big analog von --cyan auf die neue Farbe umgerechnet. */
.cs-socket-info {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 14px;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 8px;
  border-left: 3px solid var(--cur-socket);
}
.cs-socket-count {
  font-size: 20px;
  font-weight: 700;
  color: var(--cur-socket);
  text-shadow: 0 0 10px rgba(47, 224, 168, 0.7);
}
.cs-socket-label {
  font-size: 12px;
  color: var(--muted);
}

.cs-socket-grid {
  display: grid;
  /* ui-255: Spaltenbreite aus dem fluiden --col-Token auf .cs-layout → pixelgleich mit Inventar-Grid */
  grid-template-columns: repeat(2, var(--col));
  gap: var(--gap);
}

/* ui-244: Sockel-Zelle = vertikaler Stack: schlanke Kopfzeile (◇ #N) + Karten-Box.
   .cs-socket bleibt Drop-Target für cards.js — .cs-socket:not(.cs-socket-locked) greift weiterhin.
   .cs-socket-locked bleibt am äußeren .cs-socket, damit closest()-Filter in cards.js
   weiter korrekt matcht. */
.cs-socket {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Kopfzeile ◇ #N — schlankes Label über der Karten-Box, nie Overlay */
.cs-socket-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 14px;
  padding: 0 2px;
}

.cs-socket-number {
  font-size: var(--fs-caption); /* ui-505 (M3): 10px -> --fs-caption (K1) — Sockel-Kopfzeile "#N", M1 (ui-503) hat diese Klasse bewusst dem M3-Scope ueberlassen */
  color: var(--muted);
  letter-spacing: 0.1em;
  font-weight: 600;
}

/* Karten-Box: aspect-ratio 3/4 wie .cs-inv-slot → identische Tile-Höhe */
.cs-socket-box {
  position: relative;
  aspect-ratio: 3 / 4;
  min-height: 0;
}

/* Leerer Sockel: gestrichelter Puls-Rahmen + + Hint (Affordance) */
.cs-socket-box.is-empty {
  background: rgba(0, 0, 0, 0.35);
  border: 2px dashed rgba(56, 225, 255, 0.35);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
  animation: cs-socket-pulse 2.4s ease-in-out infinite;
}
.cs-socket-box.is-empty::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(56, 225, 255, 0.08) 0%, transparent 70%);
  opacity: 0;
  transition: opacity 0.2s ease;
  pointer-events: none;
}
.cs-socket-box.is-empty:hover::before { opacity: 1; }
@keyframes cs-socket-pulse {
  0%, 100% { border-color: rgba(56, 225, 255, 0.3); }
  50%       { border-color: rgba(56, 225, 255, 0.7); box-shadow: inset 0 0 20px rgba(56, 225, 255, 0.15); }
}

/* Drag-over-Highlight — auf .cs-socket-box damit nur die Box leuchtet, nicht die Kopfzeile */
.cs-socket.cs-drag-over .cs-socket-box {
  border-color: var(--cyan);
  border-style: solid;
  background: rgba(56, 225, 255, 0.08);
  box-shadow: 0 0 12px rgba(56, 225, 255, 0.7), 0 0 32px rgba(56, 225, 255, 0.25);
  transform: scale(1.04);
}

/* Gesperrter Sockel: Hatch + gelbe Border */
.cs-socket-box.is-locked {
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 8px,
    rgba(255, 200, 50, 0.06) 8px,
    rgba(255, 200, 50, 0.06) 16px
  );
  border: 2px dashed rgba(255, 200, 50, 0.3);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: not-allowed;
}

/* Next-to-unlock Slot: Magenta Hatch + Puls */
.cs-socket-box.is-next-unlock {
  background: repeating-linear-gradient(
    45deg, transparent, transparent 8px,
    rgba(255, 69, 181, 0.06) 8px, rgba(255, 69, 181, 0.06) 16px
  );
  border: 2px dashed rgba(255, 69, 181, 0.5);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: cs-next-pulse 2.2s ease-in-out infinite;
}
@keyframes cs-next-pulse {
  0%, 100% { box-shadow: inset 0 0 8px rgba(255, 69, 181, 0.1); }
  50%       { box-shadow: inset 0 0 24px rgba(255, 69, 181, 0.3); border-color: rgba(255, 69, 181, 0.8); }
}

/* Gefüllter Sockel: rahmenlos/transparent → Karte füllt Box wie .cs-inv-slot (DL-3) */
.cs-socket-box.is-filled {
  border: 0;
  background: none;
}
.cs-socket-box.is-filled .cs-card {
  position: absolute;
  inset: 0;
}

.cs-socket-empty-hint {
  font-size: 24px;
  color: rgba(56, 225, 255, 0.4);
  pointer-events: none;
}
.cs-socket-locked-hint {
  font-size: var(--fs-caption); /* ui-505 (M3): 10px -> --fs-caption (K1) — M1 (ui-503) hat die Basis-Regel bewusst dem M3-Scope ueberlassen, .small-Kind ist bereits seit M1 11px */
  text-align: center;
  color: rgba(255, 124, 203, 0.9);
  padding: 8px;
  letter-spacing: 0.05em;
  line-height: 1.4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.cs-socket-locked-badge { font-size: 16px; margin-bottom: 4px; }
.cs-socket-locked-hint strong {
  font-size: 13px;
  color: var(--magenta);
  text-shadow: 0 0 8px rgba(255, 69, 181, 0.5);
}
.cs-socket-locked-hint small {
  /* ui-503 (M1): 9px -> 11px-Boden (K1) — "bis zum naechsten" traegt echte
     Info (erklaert die Zahl darueber), kein Deko-Kandidat. */
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.04em;
}

/* ui-038: Herkunfts-Chip-Reihe (DL-2) */
.cs-socket-origin {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.cs-origin-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--line);
  font-size: 12px;
}
.cs-origin-chip.is-zero { opacity: 0.45; }
.cs-origin-chip .cs-origin-num  { font-weight: 700; font-size: 13px; }
.cs-origin-chip .cs-origin-lbl  { color: var(--muted); font-size: 11px; }
.cs-origin-sub  .cs-origin-glyph,
.cs-origin-sub  .cs-origin-num  { color: var(--cyan); }
.cs-origin-ach  .cs-origin-glyph,
.cs-origin-ach  .cs-origin-num  { color: var(--yellow); }
.cs-origin-hexa .cs-origin-glyph,
.cs-origin-hexa .cs-origin-num  { color: var(--magenta); }

/* ui-038: Hexa-Schwellen-Fortschritts-Meter (DL-4) */
.cs-hexa-progress {
  margin-bottom: 16px;
  padding: 0.6em 0.75em;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-2);
}
.cs-hexa-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6em;
  flex-wrap: wrap;
}
.cs-hexa-lbl  { font-size: 0.8em; color: var(--text); font-weight: 600; }
.cs-hexa-nums { font-size: 0.82em; color: var(--muted); }
.cs-hexa-nums b { color: var(--magenta); }
.cs-hexa-meter {
  position: relative;
  height: 9px;
  margin-top: 0.55em;
  border-radius: 5px;
  background: var(--line);
  overflow: hidden;
}
.cs-hexa-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: linear-gradient(90deg, var(--magenta), var(--magenta-light));
  border-radius: 5px;
  transition: width 0.25s ease;
  box-shadow: 0 0 10px rgba(255, 69, 181, 0.5);
}
.cs-hexa-hint { font-size: var(--fs-caption); color: var(--muted); margin-top: 0.5em; line-height: 1.4; } /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
.cs-hexa-hint b { color: var(--magenta); }

/* prefers-reduced-motion: Hexa-Fill-Transition deaktivieren */
@media (prefers-reduced-motion: reduce) {
  .cs-hexa-fill { transition: none; }
}

/* ui-244 DL-4: Shrink-Satz entfernt — .cs-socket-filled .cs-card-* Overrides gelöscht.
   Karte erbt 1:1 die Basis-.cs-card-Styles (Icon 54px, Name 11px, Bonus 16px, Effect 13px).
   Die Karte füllt .cs-socket-box.is-filled via position:absolute inset:0 (s. oben). */

/* Remove button in socket (✕, appears on hover) */
.cs-card-remove {
  position: absolute;
  bottom: 4px;
  left: 4px;
  width: 18px;
  height: 18px;
  border-radius: 9px;
  background: rgba(255, 77, 110, 0.2);
  color: var(--red);
  border: 1px solid rgba(255, 77, 110, 0.4);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.15s ease;
  z-index: 4;
  padding: 0;
}
/* ui-244: Reveal-Hook auf .cs-socket-box.is-filled (DL-6) statt .cs-socket.
   ui-546 (Re-Spawn must-fix, s. components.css .cs-card-surface-Kommentar):
   Bei Pakt-Karten ueberlappt die eigene 17px-Box des (i)-Details-Triggers
   (bottom:7px/left:7px) den ✕-Button (bottom:4px/left:4px) bereits OHNE jede
   Hitbox-Erweiterung — beide sitzen faktisch in derselben Ecke. Default
   gewinnt jetzt der (i)-Trigger (.cs-card-surface z-index:5 > 4, s. dort) —
   korrekt, denn ausserhalb von :hover ist der ✕-Button unsichtbar
   (opacity:0), ein Klick auf das Sichtbare muss treffen. Genau WENN der
   ✕-Button sichtbar wird (hier), dreht sich das Blatt bewusst um: z-index:6
   schlaegt die 5 der Karten-Oberflaeche, der jetzt SICHTBARE ✕-Button
   bekommt in diesem Moment die Ueberlappung zurueck — live verifiziert
   (Desktop-Hover-Zustand), kein Fehlklick-Rueckschritt gegenueber vor
   ui-546. */
.cs-socket-box.is-filled:hover .cs-card-remove { opacity: 1; z-index: 6; }
.cs-card-remove:hover { background: var(--red); color: var(--text-on-accent); border-color: var(--red); }

/* ui-184: Sim-only-Fußnote unter der Stat-Vorschau im Waffe-Tab (Build-Sektion).
   Erscheint nur wenn mind. eine Gruppen-Karte gesockelt ist (conditional render).
   border-top:dashed folgt der .info-foot-Fußnoten-Konvention. */
.build-bonus-note {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}
.build-bonus-note .nm {
  color: var(--text-dim);
  flex: 0 0 auto;
  font-style: normal;
}
.build-bonus-note b {
  color: var(--white);
  font-weight: 600;
}

/* ========================================= */

/* prefers-reduced-motion: alle CS-Animationen deaktivieren */
@media (prefers-reduced-motion: reduce) {
  .cs-card.cs-can-upgrade { animation: none; }
  .cs-upgrade-chevron { animation: none; }
  .cs-socket-box.is-empty { animation: none; }
  .cs-socket-box.is-next-unlock { animation: none; }
  .cs-card-surface { transition: none; }
  .cs-card { transition: none; }
  /* ui-487 (DL-4): Draw-Stapel-Fly-in/Tiefen-Verschiebung instant statt
     animiert -- Karten erscheinen sofort an ihrer Endposition. app.js setzt
     dieselben Zielwerte unveraendert (kein JS-Zweig); nur diese Regel
     entscheidet ueber animiert vs. instant. */
  .draw-flip-wrapper { transition: none; }
}

/* ui-204: Touch-Affordance-Parität
 * Greift nur auf Touch-Geräten (hover:none = kein echter Hover-Zeiger,
 * pointer:coarse = Finger-Input). Desktop mit Maus bleibt byte-gleich.
 * REIHENFOLGE: .cs-card-touch-preview-Basis-Regel steht OBEN (display:none),
 * dieser Block folgt danach → display:flex hier gewinnt auf Touch (gleiche Spezifizität, später).
 */
@media (hover: none), (pointer: coarse) {
  /* Karten-Upgrade-Vorschau: Hover-Flip neutralisieren (sonst bleibt langer-Touch "hängen").
   * Rest-Surface bleibt sichtbar, Preview-Surface bleibt aus.
   * Die persistente Touch-Leiste (.cs-card-touch-preview) übernimmt die Info-Rolle. */
  .cs-card.cs-can-upgrade:hover .cs-card-surface-rest {
    opacity: 1;
    transform: none;
  }
  .cs-card.cs-can-upgrade:hover .cs-card-surface-preview {
    opacity: 0;
  }

  /* Rest-CTA weicht der persistenten Touch-Leiste (sonst doppelt) */
  .cs-card.cs-can-upgrade .cs-upgrade-cta {
    display: none;
  }

  /* ui-511: Pakt-Karten-Details-Trigger weicht der persistenten Touch-Leiste
   * nach oben aus — dieselbe bottom:0/z-index:4-Fläche wie .cs-card-touch-
   * preview unten. Ohne den Abstand deckt die Leiste den Trigger ab und ein
   * Tap darauf würde (über die Karte darunter, .tipwrap-Klick-Guard greift
   * nicht mehr) versehentlich das Upgrade statt den Detail-Tooltip auslösen.
   * ui-546: der Trigger ist seither position:absolute (components.css, Basis
   * bottom:7px, s. dortiger Kommentar) statt eines in-flow-Elements mit
   * Top-Margin — die Ausweich-Distanz lebt jetzt als bottom-Override, nicht
   * mehr als margin-bottom (auf einem position:absolute-Element wirkungslos).
   * 46px statt der rechnerisch aequivalenten 33px (7px Basis + altes 26px):
   * die Touch-Leiste ist bei laengerem Vorschau-Text ("▲ Upgrade → T2 · +15 %")
   * auf Kachel-Breite ZWEIZEILIG und damit ~43px hoch (Live-CDP-Messung, nicht
   * die angenommenen ~24px eines einzeiligen Textes) — 33px ueberlappte die
   * Leiste noch messbar. 46px raeumt 43px + 3px Puffer frei (Ticket ## Notes). */
  .cs-card.is-pact.cs-can-upgrade .cs-pact-det.tipwrap {
    bottom: 46px;
  }

  /* ui-585 (AK5): genereller Fall (Normal-/Gruppen-/Köder-Karten — Pakt hat
   * seit ui-511/546 die eigene Ausweichregel oben, Jagd-Karten haben nie
   * cs-can-upgrade/eine Touch-Leiste, s. renderHuntCardTile()). Dieselbe
   * 46px-Leistenhöhe (2-zeiliger Vorschautext, ui-546-Messung) wie beim
   * Pakt-Fall — EIN Konstantwert für beide Ausweichregeln.
   * (1) .cs-card-sub (Fusszeile, IN-FLOW letztes Kind von .cs-card-body
   *     innerhalb .cs-card-surface-rest, dessen display:flex;
   *     justify-content:space-between den Body an den Boden DES CONTENT-
   *     BEREICHS drückt) weicht über zusätzliches Bottom-Padding auf der
   *     Surface selbst aus — die Basis-Regel behält ihr 12px 10px 10px
   *     (components.css), hier wird NUR padding-bottom ueberschrieben.
   * (2) .cs-card-tier-badge ist position:absolute (bottom:7px, Basisregel
   *     components.css) und dadurch NICHT vom Padding der Surface betroffen
   *     (absolut positionierte Kinder richten sich am Padding-BOX-Rand aus,
   *     nicht an dessen eigenem padding-bottom-Wert) — braucht deshalb einen
   *     EIGENEN bottom-Override, exakt wie der Pakt-Trigger oben: 46px FLACH
   *     ersetzt die 7px-Basis (nicht additiv, s. Kommentar dort "46px statt
   *     der rechnerisch aequivalenten 33px"). */
  .cs-card.cs-can-upgrade .cs-card-surface-rest {
    padding-bottom: 46px;
  }
  .cs-card.cs-can-upgrade .cs-card-tier-badge {
    bottom: 46px;
  }

  /* Persistente Touch-Vorschau-Leiste einblenden */
  .cs-card-touch-preview {
    display: flex;
  }

  /* ui-470: Filter-Chips ≥44px auf Touch (ui-461-Kanon, WCAG 2.5.5). .cs-filter-btn ist
   * eine NEUE Klasse ohne konkurrierende Basis-Deklaration außerhalb dieser Datei — anders
   * als .cs-sort-btn (dessen eigener 44px-Touch-Fix historisch über die ÄLTERE,
   * datei-übergreifende max-width:600px-Kaskaden-Route in dashboard.css läuft, s. dortiger
   * KASKADEN-LOCK-Kommentar) braucht .cs-filter-btn diesen Umweg nicht — die Anhebung lebt
   * vollständig hier, im selben, bereits vorhandenen (hover:none)/(pointer:coarse)-Block
   * (Dev-Entscheid ui-470, s. Ticket ## Notes). Desktop/Maus bleibt bei 34px unverändert.
   * ui-479: gewinnt auf echten Touch-Geräten bewusst GEGEN die frühere, schmalere
   * @media (max-width:600px)-Kompaktion der Filter-Disclosure (DL-6, 32px/12.5px) —
   * beide Regeln haben dieselbe Spezifität (0,1,0), diese hier steht textuell SPÄTER
   * → min-height/padding aus DIESEM Block gewinnen, font-size (dort gesetzt, hier
   * nicht) bleibt unangetastet bei 12.5px. Siehe Kommentar an der DL-6-Regel selbst.
   */
  .cs-filter-btn {
    min-height: 44px;
    padding: 10px 14px;
  }
}
