/* Chat Tower Companion -- pages/profile.css
 * P6-Kette Glied 6/8 (web-241). Reine Verschiebung aus web/public/style.css.
 * Scope: /u/:login (Player-Profil, ui-326) -- Identitaets-Hero, Konto-
 * Pillen-Leiste, Achievement-/Runs-/Sammlung-/Build-/Passkey-Panels,
 * web-227 Push-Benachrichtigungen, web-226 Passkey-Verwaltung, ui-399
 * Profil-Run-Listen mobil als Karten. Keine Kaskaden-Abhaengigkeit zu
 * anderen pages/*.css-Dateien bekannt. */


/* =====================================================================
   Player-Profil (ui-326) — öffentliche Profil-Seite /u/:login.
   Reuse: .stat-pill/.stat-num/.stat-label, .panel/.panel-title/.panel-empty,
   .achievement-weapon-tab* (Tab-Strip, unverändert), .build-invest-cell*,
   .build-stage/.build-spine/.build-dot/.build-step-no/-name/-sub, .draw-btn,
   ui-361: .achievement-tier-badge (Dashboard-Komponente, pages/achievements.css,
   für die Tier-Pille der Achievement-Kachel — keine vierte eigene Pille).
   NEU (Guide-Proposal .claude/sprint/prototypes/ui-042-proposals/ui-player-profile.html,
   bei nächster ui-042-Konsolidierung einzufalten): .id-hero, Rang-Badge auf
   .stat-pill, .rank (bislang nirgends real, nur Guide-Proposal).
   web-240-Re-Spawn (Review cd1cd70f): .chip/.chip.sub/.tchip standen hier
   ursprünglich fälschlich MIT unter der bislang-nirgends-real-Einstufung
   oben — diese Zeile selbst war stale, beide haben ECHTE Konsumenten
   unten (Sub-Monate-/Dabei-seit-/Runden-Chip, Fokus-Stat-Chips via
   .chip.sub, Tier-Chips via .tchip) und liegen seither in
   client/css/companion/components.css.
   [Hinweis: der Rest dieses Kommentarblocks unten (ab .pf-ach-card-
   Familie) ist wegen eines VORBESTEHENDEN, separaten Bugs (Wildcard
   .wb-*-Zitat schließt den Block vorzeitig, s. eigenes Kurz-Ticket) real
   nicht mehr Teil DIESES Kommentars — neuer Text ab hier bewusst NICHT
   mehr angehängt, um die Landmine nicht versehentlich zu erweitern.]
   .pf-ach-card-Familie (ui-361: umbenannt aus .ac-card* — stand hier
   fälschlich als "Reuse", war aber von Anfang an profil-eigen und kollidierte
   mit der ECHTEN Endscreen-Achievement-Karte, s. Kommentar bei .pf-ach-card
   unten), .pager, .wb-focus + restliche .wb-* + .wbuild.
   ===================================================================== */

.profile-page { display: flex; flex-direction: column; gap: 15px; }
/* ui-465: Gegen-Fix zur reaktivierten Regel oben (der frühere vorzeitige
   Kommentar-Schließer [Stern gefolgt von Slash] ist gefixt, `display:flex`
   greift jetzt wirklich) — 15px statt 1.5em, dazu `margin-bottom:0` auf
   jedes direkte `.panel`-Kind (die geteilte components.css-Panel-Regel
   [margin-bottom:1em] würde sonst zum Gap ADDIEREN statt zu kollabieren,
   Flex kollabiert keine Margins). Volle Herleitung + der dritte Baustein
   (`.heroes` verliert seine Margins) beim `.heroes`-Kommentar unten (ui-356). */
.profile-page > .panel { margin-bottom: 0; }

/* ---- ui-371: Konto-Pillen-Leiste (geteilt mit dem Dashboard, dash-account-bar.js) ----
   Der Wrapper reust .dash-header (border-bottom/padding/flex → Header-Optik-
   Kontinuität beim Dashboard↔Profil-Wechsel). justify-content: flex-end setzt
   die .dash-stats rechts wie im Dashboard (dort schiebt die .dash-id sie via
   space-between nach rechts — auf dem Profil gehört der Identitäts-Platz dem
   Subjekt-Hero darunter, AK ui-371). Bewusst .profile-page-gescoped (Leak-Lock
   ui-361/367: /styleguide demot .stat-pill/.dash-*-Klassen ohne Seiten-Wrapper).
   ≤600px: derselbe Kompakt-Strip wie das Mobile-Dashboard (row-Pillen, Labels
   aus, quer-scrollend — Komma-Selektoren am .dashboard-Strip-Block im ui-318-
   Mobil-Layout-Abschnitt). Volle Pillen fräßen auf Phone-Höhen den Subjekt-Hero
   unter die Falte (gemessen 95px @568px-Viewport). */
.profile-page .pf-account-bar { justify-content: flex-end; }
/* ≤600px-Override DIREKT nach der Basis (gewinnt die Kaskade bei gleicher
   Spezifität durch spätere Datei-Position — im ui-318-Block stünde es davor):
   row gegen die ungescopte .dash-header-Column-Regel (≤600px-Basis-Block),
   flex-start gegen die flex-end-Basis darüber — im Strip starten die Pillen
   links wie im Dashboard-Strip. WICHTIG bei Überlauf: flex-end + overflow-x
   wäre ein echter Bug (Überlauf entsteht dann LINKS und ist bei LTR nicht
   erscrollbar — abgeschnittene Draws-Pille ohne Ausweg). */
@media (max-width: 600px) {
  .profile-page .pf-account-bar { flex-direction: row; justify-content: flex-start; }
}

/* ---- ui-372: Header-Vertikal-Paritaet zum Dashboard ----
   section.dashboard traegt `padding: 0.5em 0` (s. "===== Dashboard ====="-Block)
   — ohne Gegenstueck sass die Konto-Leiste im Profil 0.5em (7.5px) hoeher am
   site-header als im Dashboard (computed-Messung 2026-07-25: Leisten-Top
   253.8px vs. 261.3px @390px bzw. 187.3px vs. 194.8px @800px bei identischem
   site-header — die uebrigen Header-Masse waren bereits paritaetisch:
   Header-Hoehe, Pillen-Rects, Abstand Leiste-zu-Tabs 22.5px). Nur der
   padding-TOP-Anteil wird gespiegelt; der Bottom-Anteil des Dashboards haengt
   hinter .dash-footer und ist kein Header-Belang. Bewusst auf --with-nav
   gescoped: ausgeloggt gibt es keinen Dashboard-Header und keinen
   Vergleichspunkt — dort bleibt das Layout unveraendert (kein totes Padding).
   Seit ui-389 ist dies die EINZIGE Regel des Modifiers: die fruehere
   padding-bottom-Reservierung fuer die fixed Bottom-Nav (ui-368, ui-318-
   Block) ist mit dem Sticky-Top-Umbau entfallen — die globale Reservierung
   traegt jetzt body.has-app-botnav (App-Bottom-Nav-Block am Datei-Ende).
   Kein /styleguide-Leak: der Guide rendert keine .profile-page-Huelle. */
.profile-page--with-nav { padding-top: 0.5em; }

/* ---- Identity-Hero-Header ---- */
.id-hero {
  position: relative;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 20px 22px;
}
.id-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 12% -20%, rgba(56, 225, 255, .14), transparent 55%);
}
.id-top { display: flex; gap: 16px; align-items: center; position: relative; }
/* ui-359: Inhalt ist jetzt das Tower-Signatur-SVG (identityBadgeSvg(34),
   src/render/identity-badge-icon.js) statt eines 30px-Unicode-Glyphs — die
   Glyph-font-size entfällt (Größe kommt aus den SVG-Attributen, Mobile-
   Override unten). Radius 12px stand auf keiner Guide-Sprosse → 10px
   (Guide-Stufe "Container", Ticket-AK C1). */
.id-badge {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  background: linear-gradient(140deg, rgba(56, 225, 255, .12), rgba(255, 69, 181, .10));
  border: 1px solid var(--line-2);
  color: var(--cyan);
  box-shadow: 0 0 18px rgba(56, 225, 255, .18);
}
/* ui-362: war ein <div> (kein UA-Margin), jetzt <h1> (Outline-Fix) — margin:0
   neutralisiert explizit die UA-Default-Bloeckmargin von h1 (gemessen 18.09px
   oben+unten, sonst haette der Tag-Tausch die .id-hero-Karte sichtbar
   vergroessert, entgegen "optisch aendert sich nichts" AK). Analog zum
   bestehenden .panel-title-Muster, das margin explizit selbst setzt. */
.id-name { margin: 0; font-size: 1.8em; font-weight: 800; line-height: 1.05; overflow-wrap: anywhere; }
.id-login { color: var(--muted); font-size: .95em; margin-top: 2px; }
.id-meta { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 11px; position: relative; }

/* ---- Hero-Stats (4 stat-pill, 4→2 Spalten @≤640px) ---- */
/* ui-356: Vertikalrhythmus vereinheitlicht auf 15px (Fifty: "das spacing ist
   aus der hölle"/"total dran gequetscht"). Vorher 4px .id-hero->.heroes,
   12px Kachel-gap, 0px .heroes->erstes .panel — drei verschiedene Werte in
   einer Spalte neben dem korrekten 15px .panel->.panel-Rhythmus.
   ui-465: die damalige `.profile-page`-Kommentar-Landmine (vorzeitiger
   Kommentar-Schließer, Stern gefolgt von Slash, s. eigenes Ticket) ist
   gefixt — `display:flex; gap:15px` greift jetzt wirklich (nicht mehr
   `display:block`). Flex kollabiert KEINE Margins (anders als der vorherige
   Block-Fluss): `.heroes` verliert deshalb seine eigenen margin-top/-bottom,
   der 15px-Abstand kommt jetzt aus dem Gap. Zweiter Baustein (`.profile-page
   > .panel`, s.o., margin-bottom auf 0) verhindert, dass die geteilte
   components.css-Panel-Regel zum Gap addiert. Ergebnis erneut einheitlich
   15px auf allen drei Abständen (.id-hero->.heroes, .heroes->1. Panel,
   Panel->Panel) — live gemessen, s. Ticket. */
.heroes { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; }
.heroes .stat-pill { position: relative; }
.heroes .stat-pill .glyph { font-size: 16px; line-height: 1; }
.hx-magenta { color: var(--cur-hexa) !important; } /* ui-623: SSOT-Token-Alias, Wert unverändert (Hexa bleibt Magenta) */
.hx-green   { color: var(--green) !important; }

/* ---- Rang-Badge (NEU) — auf .stat-pill oben-rechts, sonst als generisches
   Rang-Badge (z.B. künftig ui-327/ui-328 Hero-Karten-Kontext). rank-1/2/3
   spiegeln dieselben Glow-rgba-Werte wie .ct-rank-1/2/3 (components.css) —
   unterschiedliche Rolle (Badge/Pill statt reiner Text-Akzent), gleiche Farbe. */
.rank {
  font-size: var(--fs-caption); /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
  font-weight: 800;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  color: var(--text-dim);
  white-space: nowrap;
}
.rank.rank-1 { color: var(--rank-1); border-color: color-mix(in srgb, var(--rank-1) 50%, transparent); text-shadow: 0 0 10px rgba(94, 184, 255, .7); }
.rank.rank-2 { color: var(--rank-2); border-color: color-mix(in srgb, var(--rank-2) 50%, transparent); text-shadow: 0 0 8px rgba(192, 200, 212, .6); }
.rank.rank-3 { color: var(--rank-3); border-color: color-mix(in srgb, var(--rank-3) 50%, transparent); text-shadow: 0 0 8px rgba(205, 127, 50, .6); }
.heroes .stat-pill .rank { position: absolute; top: 7px; right: 7px; }

/* ---- Standings-Footer (ui-366) — Live „Top X %" (Heat) + Distanz zum
   nächsten Rang unter jeder Hero-Stat-Pille (views/profile.js
   standingsFooter(), Zustände dort im Docblock; Prototyp ui-366.html).
   Reiner Status, kein Reward, keine Interaktion — bewusst KEIN Hover-/
   Fokus-State. Alles aus tokens.css-Tokens komponiert; 11px = erlaubter
   Font-Boden (ui-341/342). Heat nach der GEZEIGTEN Zahl X: X==1 → .c1
   (gold), X<=10 → .c10 (cyan), sonst neutral. --gold ist hier LEGITIMES
   Eigentum des Spitzenreiter-/X==1-Status (Design-Lock ui-366) — nicht zu
   verwechseln mit dem ui-357-entfernten toten ★-Fallback. */
.pf-standings { margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--line-2); width: 100%; display: flex; flex-direction: column; align-items: center; gap: 5px; }
.pf-pct { font-size: 11px; font-weight: 600; letter-spacing: .03em; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--line-2); color: var(--muted); white-space: nowrap; }
.pf-pct.c10 { color: var(--cyan); border-color: color-mix(in srgb, var(--cyan) 45%, transparent); }
.pf-pct.c1 { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 55%, transparent); }
.pf-lead { color: var(--gold); font-weight: 600; font-size: 11px; letter-spacing: .03em; white-space: nowrap; }
.pf-small { font-size: 11px; color: var(--muted); white-space: nowrap; }
.pf-dist { font-size: 11px; color: var(--muted); white-space: nowrap; }
.pf-dist b { color: var(--text); font-weight: 600; }
.pf-dist .a { color: var(--green); }

/* ---- Achievement-Showcase-Card (ui-361: .pf-ach-*-Familie — vormals als
   .ac-card/.ac-name/.ac-sub benannt. Das war NIE bloß Guide-Proposal, sondern
   von Anfang an real (dieses Markup, profile.js achievementCard()) — es
   kollidierte aber mit der ECHTEN Endscreen-Achievement-Karte (Eigentümer:
   desktop.css + src/endscreen.js; im Guide nur demonstriert über
   styleguide.js/styleguide.css, dort bleibt .ac-card korrekt). Vor dem
   web-240/241-Split (als beides noch im selben Companion-Stylesheet lag),
   leakte die additive Kollision in die Style-Guide-Live-Demo unter
   /styleguide (s. Ticket ui-361). completed=cyan spiegelt weiterhin die
   .achievement-weapon-tab--active-Cyan-Konvention) ---- */
/* ui-352: festes 3-Spalten-Grid statt ragged Auto-Fill (Fifty-Entscheid
   2026-07-17) — 3x2 = 6 Kacheln/Seite deckungsgleich mit ACH_PAGE_SIZE
   (profile.js:46, unveraendert). Mobile-Fallback s. @media-Block unten. */
.ach-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; }
/* ui-355: [hidden] von der UA-Default-Regel `[hidden]{display:none}` wird
   von der Autoren-Regel oben ueberstimmt (gleiche Selektor-Spezifitaet,
   spaeter im Stylesheet) -> Paginator (profile.js ctPagerNav/ctPagerReset)
   toggelt hidden korrekt, aber es blieb wirkungslos. Scoped Fix (derselbe
   Selektor-Spezifitaets-Kniff wie an anderen Stellen im Companion-CSS) --
   KEIN globales [hidden]-Override. */
.ach-grid[hidden] { display: none; }
.pf-ach-card {
  display: flex;
  flex-direction: column;
  gap: 3px;
  background: rgba(13, 19, 34, .92);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 9px 11px;
  position: relative;
  overflow: hidden;
}
.pf-ach-card.completed { border-color: var(--cyan); box-shadow: 0 0 12px rgba(56, 225, 255, .28); }
.pf-ach-card.completed::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--cyan), rgba(56, 225, 255, .3));
}
.pf-ach-top { display: flex; align-items: center; gap: 8px; }
.pf-ach-ico { color: var(--cyan); font-size: 16px; display: inline-flex; align-items: center; }
.pf-ach-ico svg { display: block; }
.pf-ach-name { font-weight: 700; font-size: .9em; }
/* ui-361: die Tier-Pille war eine eigene .ac-sub-Pille (radius 999px, eigener
   Rahmen/Hintergrund/Padding) — jetzt wiederverwendet sie .achievement-tier-badge
   (pages/achievements.css, Dashboard-Komponente) statt einer vierten eigenen Pille
   (Ticket-Lock — "es gibt bereits drei Badge-Varianten"). Nur die Positionierung
   innerhalb von .pf-ach-top (rechtsbündig neben Icon+Name) bleibt surface-eigen —
   das ist Layout des Aufrufkontexts, keine Neudeklaration der Pille selbst. */
.pf-ach-top .achievement-tier-badge { margin-left: auto; }
/* .pf-ach-desc: NEU (Guide-Proposal) — "erreichte Beschreibung", kein Progress */
.pf-ach-desc { font-size: .8em; color: var(--text-dim); line-height: 1.35; margin-top: 4px; }

/* ---- Paginator (NEU) — cyan=interaktiv, Enden disabled/gedimmt, auto-hidden
   bei 1 Seite (Server rendert .pager gar nicht erst, s. views/profile.js) ---- */
.pager { display: flex; align-items: center; justify-content: center; gap: .9em; margin-top: 1em; }
.pager button {
  font: inherit;
  cursor: pointer;
  background: transparent;
  color: var(--cyan);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  padding: .2em .8em;
  font-size: 1.05em;
  font-weight: 800;
  line-height: 1;
  min-height: 44px;
  min-width: 44px;
}
.pager button:hover:not(:disabled) { border-color: var(--cyan); background: rgba(56, 225, 255, .08); }
.pager button:disabled { opacity: .3; cursor: default; color: var(--muted); }
.pager .pg-info { font-size: .8em; color: var(--muted); min-width: 6.5em; text-align: center; }

/* ui-352: Mobile-Fallback fuers feste 3-Spalten-.ach-grid (Lock D3) — auf
   schmalen Breiten wuerde repeat(3,1fr) quetschen/overflowen. 6/Seite (Pager,
   profile.js) bleibt unveraendert, verteilt sich nur auf 2x3 bzw. 6x1. */
@media (max-width: 600px) {
  .ach-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 380px) {
  .ach-grid { grid-template-columns: repeat(1, 1fr); }
}

/* ---- Sammlung: Tier-Chips-Layout (NEU) — Grid-Wrapper für die
   .tchip-Kacheln. Farbkonvention + Kachel-Regeln selbst (.tchip+Varianten)
   liegen seit web-240-Re-Spawn (Review cd1cd70f) in
   client/css/companion/components.css, s. dortiger Kopfkommentar
   "Tier-Chip" — .tiers/.maxtier bleiben seiten-spezifisches Layout hier.
   Bucket T6 fasst Tier ≥6 zusammen (s. profile-stats.js getCollectionSummary). ---- */
.tiers { display: flex; gap: 7px; flex-wrap: wrap; }
.maxtier { color: var(--text-dim); font-size: .8em; margin-top: 9px; }
.maxtier b { color: var(--group); }

/* ---- Builds pro Waffe (NEU) — Hexa-GESAMTZAHL/Currency-Summe bewusst NICHT
   gezeigt (Design-Lock: "aussagelos, gleicher Pool"); nur Invest-Level je Stat +
   read-only Template + Fokus (s. profile-stats.js getWeaponBuilds()). Die
   ui-353-Collapse-Summary ("N Attribute · Template" im <summary>, ui-363) ist
   davon unbenommen — sie zeigt einen Slot-COUNT (w.invest.length), keine Summe. ----
   ui-353: `.wbuild` ist jetzt ein natives `<details>` (Lock D1, kein JS-Toggle),
   `.wb-head` dessen `<summary>`. Nativer Marker versteckt, eigener `.wb-chevron`
   dreht per `[open]`-Selektor. */
.wbuild {
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 12px 14px;
  margin-top: 12px;
  background: var(--bg-2);
}
.wbuild.equip { border-color: color-mix(in srgb, var(--yellow) 28%, transparent); }
.wbuild > summary { list-style: none; }
.wbuild > summary::-webkit-details-marker { display: none; }
.wbuild > summary::marker { content: ''; }
.wb-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  min-height: 44px;
  margin: -4px -6px;
  padding: 4px 6px;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color .12s ease;
}
.wb-head:hover, .wb-head:focus-visible { background: rgba(255, 255, 255, .05); }
.wb-head:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.wb-head .wg { display: inline-flex; align-items: center; justify-content: center; width: 26px; }
.wb-head b { font-size: 1.02em; }
.wb-chevron {
  display: inline-flex;
  flex: 0 0 auto;
  font-size: .8em;
  color: var(--muted);
  transform: rotate(-90deg);
  transition: transform .15s ease;
}
.wbuild[open] > summary .wb-chevron { transform: rotate(0deg); }
.wb-eq {
  /* ui-360: .66em→.75em, war ~9.90px (15px-Root, keine em-skalierten Vorfahren) — 15px x
     .75em = 11.25px. Kein letter-spacing hier (anders als die Achievement-Tier-Pille — seit
     ui-361 .achievement-tier-badge, vormals die eigene .ac-sub-Pille, trägt letter-spacing
     .05em — .wb-eq hatte nie eins, AK verlangt keine Neueinführung). */
  font-size: .75em;
  color: var(--yellow);
  border: 1px solid color-mix(in srgb, var(--yellow) 40%, transparent);
  border-radius: 999px;
  padding: 1px 8px;
}
.wb-summary {
  margin-left: auto;
  font-size: .78em;
  color: var(--muted);
  white-space: nowrap;
}
.wb-label { font-size: var(--fs-caption); color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin: 12px 0 7px; display: flex; align-items: center; gap: 8px; } /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
/* ui-597 DL-6: Zähler-Suffix ("10 Attribute" / "Template") neben dem Label —
   bricht bewusst aus dessen uppercase/muted-Optik aus (normal-case, Text-
   Farbe, 600), analog .wb-summary im Kopf der Karte. */
.wb-label .cnt { color: var(--text); font-weight: 600; letter-spacing: 0; text-transform: none; }
/* ui-597 (DL-1): 196px statt vormals 150px — 10 Attribute passen bei ~1108px
   Panel-Breite in <=2 Reihen (Ticket-Zielmaß). Mobile-Override (DL-7) im
   @media-Block unten. */
.wb-invest { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 6px; }

/* ---- ui-597 (DL-1/DL-2): Invest-Kachel `.wi` — dichte Lese-Fassung der
   interaktiven `.build-invest-cell` (pages/build.css), OHNE deren Höhen-
   budget für +/-Buttons/Tooltip (dort ui-300-Lock, hier ungenutzt). Grid
   22px 1fr auto / auto 4px: Glyph, Label (ellipsis), "Lv N", darunter ein
   4px-Balken relativ zum höchsten investierten Level dieser Waffe (DL-2,
   Fifty-Entscheid: kein fester Cap, "Schaden dominiert" ist die Info). ---- */
.wi {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  grid-template-rows: auto 4px;
  column-gap: 8px;
  row-gap: 5px;
  align-items: center;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg-2);
}
.wi-g { color: var(--magenta); display: inline-flex; grid-row: 1; }
.wi-l { grid-row: 1; font-size: .93em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wi-lv { grid-row: 1; font-size: var(--fs-caption); font-weight: 700; color: var(--magenta); font-variant-numeric: tabular-nums; }
.wi-bar { grid-column: 1 / -1; grid-row: 2; height: 4px; border-radius: 3px; background: var(--line); overflow: hidden; }
.wi-bar i { display: block; height: 100%; background: var(--magenta); opacity: .85; }

/* ---- ui-597 (DL-3/DL-4): Build-Pfad — Profil-scoped Overrides auf die
   geteilten Stepper-Klassen aus pages/build.css (1:1 wiederverwendet, KEINE
   Kopie). Scope IMMER unter `.wb-tpl`, sonst leaken die Regeln auf den
   interaktiven Setup-Stepper (build.css lädt global auf jeder Seite, s.
   views/layout.js) — Präzedenz: die style.css-Klassen-Kollision, s. Kommentar
   am Dateikopf oben. ---- */
/* DL-3: keine Hover-Skalierung der Dots — der Profil-Build-Pfad ist reine
   Lese-Ansicht, die Interaktions-Affordanz (Reorder/Klick) existiert hier nicht. */
.wb-tpl .build-stage--step.lift:hover .build-dot { transform: none; }
/* DL-4: "to"-Wert immer Text-Farbe/600 — anders als der Setup-Stepper (dort
   cyan bzw. bei skip gelb, weil die Farbe dort Teil der Live-Editier-Sprache
   ist); im Profil trägt bereits Dot/Spine/Step-Nummer die Zustandsfarbe, der
   Wert selbst bleibt neutral. */
.wb-tpl .build-step-sub .to { color: var(--text); font-weight: 600; }
/* DL-4: Kosten-Spalte bei skip/off gedimmt (Setup zeigt dort "0 [Icon]" im
   selben Gelb wie ein echter Lift-Kostenwert — im Profil ist "0 ⓒ ·
   übersprungen"/"inaktiv" ein reiner Info-Text, keine Kosten-Aussage mehr). */
.wb-tpl .build-stage--step.skip .build-step-cost,
.wb-tpl .build-stage--step.off .build-step-cost { color: var(--muted); }

/* .wb-focus: NEU (Guide-Proposal) — Schwanz des Templates (endmode_json), Fokus=cyan (Viewer-Kanon) */
.wb-focus { display: flex; align-items: center; gap: .5em; flex-wrap: wrap; margin-top: .55em; padding-top: .75em; border-top: 1px dashed var(--line); }
.wb-focus-lbl { font-size: var(--fs-caption); color: var(--muted); text-transform: uppercase; letter-spacing: .05em; } /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
.wb-focus .chip.sub { font-size: .76em; }

/* ui-597 (DL-7): Mobile ≤480px — Invest-Grid schrumpft auf 150px-Kacheln,
   Stepper-Stages bekommen weniger Padding, Kosten-Spalte + Titel-Chip des
   Build-Pfads brechen als eigene Zeile um (keine horizontale Scrollung).
   Alle geteilten build.css-Klassen bleiben unter `.wb-tpl` gescoped (s.
   Overrides oben). */
@media (max-width: 480px) {
  .wb-invest { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .wb-tpl .build-stage { padding: .7em .7em; gap: .6em; }
  .wb-tpl .build-step-cost { margin-left: 0; flex-basis: 100%; }
  .wb-tpl .bp-title { flex-basis: 100%; }
}

/* ---- Share-CTA ---- */
.share { margin-top: 22px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.share .hint { font-size: .78em; color: var(--muted); }

@media (max-width: 640px) {
  .heroes { grid-template-columns: repeat(2, 1fr); }
  .id-name { font-size: 1.5em; }
  .id-top { gap: 12px; }
  /* ui-359: SVG-Downscale statt Glyph-font-size (Desktop 34px via Attribut,
     hier 27px im 52px-Badge — CSS überschreibt die SVG-width/height-Attribute). */
  .id-badge { width: 52px; height: 52px; }
  .id-badge svg { width: 27px; height: 27px; }
}


/* =====================================================================
   web-227: Push-Benachrichtigungen — Typen-Schalter (Profil, isOwn-Panel)
   DL-8: keine neuen Farben/Tokens — Schalter var(--cyan), Warnhinweise
   var(--gold) (Tint-Werte unten sind rgba()-Literale DERIVIERT aus den
   bestehenden --cyan/--gold-Hex-Werten, Muster der bereits vorhandenen
   rgba(240,179,80,…)-Pulse-Animation weiter oben — kein neuer :root-Eintrag).
   Tap-Fläche ≥44px (ui-394-Kanon): ::before-Hitbox-Inset, Muster .tip-i::after.
   ===================================================================== */
.push-settings .px-row {
  display: flex;
  align-items: center;
  gap: 0.8em;
  padding: 0.7em 0;
  border-bottom: 1px solid var(--line);
}
.push-settings .px-row:last-of-type { border-bottom: 0; }
.px-meta { flex: 1; min-width: 0; }
.px-name { display: block; font-size: 0.92em; }
.px-desc { display: block; font-size: 0.76em; color: var(--muted); line-height: 1.4; margin-top: 2px; }

.px-switch {
  flex: 0 0 auto;
  width: 52px;
  height: 32px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: transparent;
  cursor: pointer;
  position: relative;
  padding: 0;
}
/* Unsichtbare Hitbox-Erweiterung auf ≥44px (ui-394) — Muster .tip-i::after
   (style.css ~9900): negatives inset wächst NUR über die Box hinaus, ohne
   die sichtbare 32px-Track-Optik selbst aufzublasen. */
.px-switch::before {
  content: '';
  position: absolute;
  inset: -6px 0;
}
.px-switch::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 4px;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--muted);
  transition: left .15s ease, background .15s ease;
}
.px-switch[aria-checked="true"] {
  border-color: var(--cyan);
  background: rgba(56, 225, 255, 0.12); /* == var(--cyan) @ 12% */
}
.px-switch[aria-checked="true"]::after { left: 26px; background: var(--cyan); }
/* ui-552: dritter "wird geladen/unbekannt"-Zustand (SSR-Default + Hydration-
   Fehlschlag mit 401/technischem Fehler, s. public/push-settings.js
   applyOutcomeUI()) — Knopf mittig zwischen AUS (4px) und AN (26px) statt an
   einer der beiden Seiten, DL-8: kein neuer Farbwert (bleibt var(--muted),
   die bestehende ::after-Default-Farbe). Die Dimm-Optik selbst kommt gratis
   aus .px-switch:disabled unten (SSR/Fehlschlag-Zustand ist immer disabled). */
.px-switch[aria-checked="mixed"]::after { left: 15px; }
.px-switch:disabled { opacity: .5; cursor: not-allowed; }

.px-hint {
  border-left: 3px solid var(--gold);
  background: rgba(240, 179, 80, 0.07); /* == var(--gold) @ 7%, s. Pulse-Animation oben für denselben Literal */
  padding: 0.6em 0.8em;
  font-size: 0.82em;
  color: var(--text-dim);
  line-height: 1.5;
  border-radius: 0 6px 6px 0;
  margin-top: 0.6em;
}

/* =====================================================================
   web-226: Passkey-Verwaltung (Profil, isOwn-Panel, DL-6/DL-7)
   Klassennamen 1:1 aus dem abgenommenen Prototyp
   (.claude/sprint/prototypes/web-226.html) übernommen — Optik dort
   verbindlich verifiziert. DL-7: keine neuen Farben/Tokens — nur
   var(--cyan)/var(--gold)/var(--green)/var(--red)/var(--line*)/var(--muted).
   Tap-Flächen ≥44px (ui-394): .pk-revoke/.pk-add sind min-height:44px.
   ===================================================================== */
.pk-panel .pk-row {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.65em 0;
  border-bottom: 1px solid var(--line);
}
.pk-panel .pk-row:last-of-type { border-bottom: 0; }
.pk-ic { font-size: 1.2em; flex: 0 0 auto; }
.pk-meta { flex: 1; min-width: 0; }
.pk-name { display: block; font-size: 0.9em; }
.pk-when { display: block; font-size: 0.75em; color: var(--muted); }
.pk-this { color: var(--green); font-size: var(--fs-caption); } /* ui-505 (M3): 0.72em (~10.8px, 0.72em-Treppe) -> --fs-caption (K1) */
.pk-revoke {
  background: none;
  border: 1px solid var(--line-2);
  color: var(--muted);
  border-radius: 999px;
  padding: 0.3em 0.8em;
  font: inherit;
  font-size: 0.78em;
  cursor: pointer;
  min-height: 44px; /* ui-394-Lock — 36px war im Klick-Test des Prototyps zu klein */
}
.pk-revoke:hover { border-color: var(--red); color: var(--red); }
.pk-revoke:disabled { opacity: .5; cursor: not-allowed; }
.pk-empty { font-size: 0.85em; color: var(--muted); line-height: 1.5; margin: 0; }
.pk-add {
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 0.6em;
  background: transparent;
  border: 1px dashed var(--line-2);
  border-radius: 8px;
  color: var(--text-dim);
  font: inherit;
  font-size: 0.85em;
  cursor: pointer;
}
.pk-add:hover { border-color: var(--cyan); color: var(--cyan); }
.pk-add:disabled { opacity: .5; cursor: not-allowed; }

.pk-reach {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.5em 0.7em;
  font-size: 0.82em;
  margin-top: 1em;
}
.pk-reach dt { color: var(--muted); white-space: nowrap; }
.pk-reach dd { margin: 0; color: var(--text-dim); line-height: 1.45; }
.pk-reach .yes { color: var(--green); }
.pk-reach .no { color: var(--red); }

.pk-warn {
  border-left: 3px solid var(--gold);
  background: rgba(240, 179, 80, 0.07); /* == var(--gold) @ 7%, s. .px-hint oben für denselben Literal */
  padding: 0.7em 0.9em;
  font-size: 0.82em;
  color: var(--text-dim);
  line-height: 1.5;
  border-radius: 0 6px 6px 0;
  margin-top: 0.7em;
}
.pk-warn b { color: var(--gold); }

/* =====================================================================
   web-268: Kaufhistorie + Monatslimit (Profil, isOwn-Panel, ENABLE_SHOP)
   Kein eigener Prototyp fuer dieses Ticket — Zeilen-/Input-Optik bewusst
   1:1 aus den Nachbar-Panels (.pk-row oben, .build-step-target input in
   build.css) uebernommen statt neu erfunden. Keine neuen Farben/Tokens.
   ===================================================================== */
.pu-row {
  display: flex;
  align-items: center;
  gap: 0.7em;
  padding: 0.55em 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.85em;
}
.pu-row:last-of-type { border-bottom: 0; }
.pu-date { flex: 0 0 auto; color: var(--muted); font-size: 0.9em; }
.pu-product { flex: 1; min-width: 0; }
.pu-amount { flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* web-309 (Refund-/Dispute-Sperre): Status-Badge fuer refunded/disputed/
   settled-Kaufzeilen. Unter dem stabilen #purchase-history-panel-Anker
   gescoped (2-Compound, strukturell kollisionssicher) — NEU registrierten
   Praefix bewusst vermieden, weil die restliche `.pu-*`-Familie oben bereits
   bare/vor-ui-602 ist (s. Kommentar an der Panel-Sektion oben). */
#purchase-history-panel .pu-badge {
  display: inline-block; font-size: var(--fs-caption); font-weight: 800; border-radius: 999px;
  padding: .15em .55em; margin-left: .4em; vertical-align: middle;
  color: var(--text); background: rgba(255,255,255,.08); border: 1px solid var(--line-2);
}
#purchase-history-panel .pu-badge--dispute { color: #201502; background: linear-gradient(135deg, var(--gold), #ffcf7d); border-color: transparent; }
#purchase-history-panel .pu-badge--settled { color: #06110a; background: var(--green); border-color: transparent; }

.pu-limit-status { font-size: 0.85em; color: var(--text-dim); margin: 0 0 0.6em; }
.pu-limit-pending {
  border-left: 3px solid var(--gold);
  background: rgba(240, 179, 80, 0.07); /* == var(--gold) @ 7%, s. .px-hint/.pk-warn oben fuer denselben Literal */
  padding: 0.6em 0.8em;
  font-size: 0.82em;
  color: var(--text-dim);
  line-height: 1.5;
  border-radius: 0 6px 6px 0;
  margin: 0 0 0.6em;
}
.pu-limit-form { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; }
.pu-limit-form input[type="number"] {
  width: 110px;
  min-height: 44px; /* ui-394-Lock, s. .pk-revoke/.pk-add oben */
  background: var(--bg);
  border: 1px solid var(--line-2);
  color: var(--text);
  border-radius: 8px;
  padding: 0.4em 0.6em;
  font-size: 0.9em;
  font-family: inherit;
}
.pu-limit-form button {
  min-height: 44px;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  color: var(--text-dim);
  padding: 0.3em 1.1em;
  font: inherit;
  font-size: 0.85em;
  cursor: pointer;
}
.pu-limit-form button:hover { border-color: var(--cyan); color: var(--cyan); }

/* ui-611 AK9: Karten-Effekte-Panel (#karten-effekte-panel) — Radio-Wahl
   "Immer"/"Nur bei Hover". Nutzt .pu-limit-form (oben) unveraendert als
   Layout-Container (gleiches Flex-Wrap-Muster). .pf-shiny-opt ist NUR das
   Label-Padding fuer eine >=44px Tap-Flaeche (ui-394-Konvention dieser
   Seite, s. .pu-limit-form button oben) -- keine Custom-Radio-Optik, kein
   neuer Farb-Token (Cyan-Akzent via accent-color, nativer Browser-Radio). */
.pf-shiny-opt {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-height: 44px;
  padding: 0.3em 0.2em;
  cursor: pointer;
  font-size: 0.9em;
  color: var(--text);
}
.pf-shiny-opt input[type="radio"] {
  width: 18px;
  height: 18px;
  accent-color: var(--cyan);
  cursor: pointer;
}

/* =====================================================================
   ui-399: Profil-Run-Listen mobil als Karten (Konsistenz zu ui-396)

   Additive Erweiterung des ui-396-Karten-Blocks weiter oben (DL-3, Ticket
   ui-399): renderPersonalTable()/renderPersonalRunRow() (highscore.js, von
   profile.js reused, Lock 2) rendern seit ui-399 dieselbe .hs-cardrow-
   Zusatzzeile wie die zwei globalen Boards (renderRunCardRow(), jetzt mit
   colspan=10-Parameter statt dem globalen Default 9). Die .highscore-
   Selektoren des ui-396-Blocks bleiben UNVERÄNDERT — hier nur ein zweiter
   .profile-page-Selektor DANEBEN (Prefix im Original streichen würde die
   Karten in die /styleguide-Demo lecken, dokumentierte Kollisionsfalle
   dieses Projekts).

   Kopiert wird NUR die "Karten"-Kette (Tabelle verstecken/Karte zeigen,
   Kopfzeile, Rang-Badge, DMG/Meta, Caret, Top-Tower-Zeile, Fuß, Detail-
   Andocken) — bewusst NICHT dupliziert (Ticket-Scope):
   - .hs-boardbar/.hs-board-tab/.hs-group-label (Wisch-Strip, ui-396/DL-6):
     eigene Board-Switcher-Optik, keine "Karten"-Regel im engeren Sinn;
     die Profil-Boardbar bricht ohne sie nicht um (Basis flex-wrap,
     pages/highscore.css, nur zwei Tabs "Top Runs"/"Letzte Runs" — kein
     Overflow-Risiko).
   - .hs-participant-table-Grid + .hs-dmg-short/.hs-dmg-full-Toggle
     (ui-396/DL-4): renderPersonalParticipantsCell bleibt BEWUSST ohne
     Mobile-Varianten (kein .hs-dmg-short-Markup vorhanden, s. Kommentar
     dort) — die Teilnehmer-Tabelle im aufgeklappten Detail bleibt eine
     normale <table> in ihrem eigenen .hs-scroll.hs-scroll--part-Container
     (lokal scrollbar, kein Page-Level-Overflow — AK "ohne horizontales
     Scrollen" bezieht sich auf die Run-LISTE, nicht auf diesen bewusst
     unveränderten Detail-Container).
   - .dps-graph-wrap{display:none}/.dps-graph-m/.dps-legend-m/.dgm-*
     (ui-396/DL-5): renderDpsRunGraph() läuft für Personal OHNE withMobile
     (kein .dps-graph-m-Markup existiert dort, s. renderPersonalParticipantsCell-
     Kommentar in highscore.js) — .dps-graph-wrap AUSBLENDEN würde den
     einzigen vorhandenen Graph ersatzlos verschwinden lassen.

   Die "Detail-Zeile dockt als Block an"-Regeln WERDEN dupliziert (keine
   reine Optik-Frage): ohne sie bliebe .hs-details-row.is-open (Basis-Regel
   in pages/highscore.css, display:table-row) unter dem hier blockifizierten
   <tbody> ein verwaistes table-row-Element (Table-Fixup-Anonymous-Box-Risiko) — die
   Docking-Regel gibt ihm denselben display:block-Kontext wie beim
   globalen Board, das Aufklappen bleibt dadurch sauber. */

@media (max-width: 600px) {
  /* Review-Fix (ui-399, Re-Spawn): die vier Regeln in diesem Block, die
     verschachtelte Elemente treffen könnten, nutzen bewusst den Kind-
     Kombinator (>) statt eines unbegrenzten Nachfahren-Selektors. Grund:
     die Teilnehmer-Tabelle im Detail sitzt SELBST als Nachfahre von
     .hs-board/.hs-table/.hs-details-row (.hs-board > .hs-scroll > .hs-table
     > tbody > tr.hs-details-row > td.hs-details-cell > div.hs-scroll--part
     > table.hs-participant-table > thead/tbody/td) — ein ungescopter
     Nachfahren-Selektor reicht deshalb bis in sie hinein (thead versteckt,
     tbody/td blockifiziert → Tabelle rendert als unbeschrifteter Boxen-
     Stapel). ">" trifft nur die direkten Kinder der ÄUSSEREN Run-Tabelle,
     nicht die der inneren .hs-participant-table (bleibt dadurch die
     "normale <table>" aus dem Kommentar oben). NICHT versehentlich auf
     Nachfahren-Selektoren zurückbauen. */
  .profile-page .hs-board > .hs-scroll {
    overflow-x: visible;
    background: none;
  }
  .profile-page .hs-board .hs-table,
  .profile-page .hs-board .hs-table > tbody { display: block; }
  .profile-page .hs-board .hs-table > thead { display: none; }
  .profile-page .hs-board .hs-table tr.hs-row { display: none; }

  .profile-page .hs-board .hs-cardrow { display: block; }
  .profile-page .hs-board .hs-cardrow td {
    display: block;
    position: static;
    box-shadow: none;
    padding: 0;
    background: var(--panel);
    border: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    border-radius: 8px;
    margin-bottom: 8px;
    overflow: hidden;
  }

  .profile-page .hs-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 56px;
    padding: 10px 12px;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }
  .profile-page .hs-card-rank {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 700;
    background: var(--bg-2);
    color: var(--text-dim);
  }
  .profile-page .hs-card-rank.p1 { background: var(--rank-1); color: var(--text-on-accent); }
  .profile-page .hs-card-rank.p2 { background: var(--rank-2); color: var(--text-on-accent); }
  .profile-page .hs-card-rank.p3 { background: var(--rank-3); color: var(--text-on-accent); }

  .profile-page .hs-card-mid { flex: 1 1 auto; min-width: 0; }
  .profile-page .hs-card-dmg {
    display: block;
    font-size: 19px;
    font-weight: 700;
    line-height: 1.15;
    color: var(--text);
    font-variant-numeric: tabular-nums;
  }
  .profile-page .hs-card-dmg small {
    font-size: 11px;
    font-weight: 400;
    color: var(--muted);
    margin-left: 4px;
    letter-spacing: 0.04em;
  }
  .profile-page .hs-card-meta {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-dim);
  }
  .profile-page .hs-card-meta .sep { color: var(--line-2); margin: 0 4px; }
  .profile-page .hs-card-caret {
    flex: 0 0 auto;
    width: 24px;
    text-align: center;
    color: var(--muted);
    font-size: 12px;
    transition: transform 0.18s;
  }
  .profile-page .hs-cardrow--open .hs-card-caret { transform: rotate(180deg); }

  .profile-page .hs-card-sub {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 12px 9px;
    font-size: 12.5px;
    color: var(--text-dim);
  }
  .profile-page .hs-card-sub svg { flex: 0 0 auto; }
  .profile-page .hs-card-top {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text);
  }
  .profile-page .hs-card-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 0 12px 10px;
    font-size: 11px;
    color: var(--muted);
  }

  /* Detail-Zeile dockt als Block unter der offenen Karte an — s. Block-
     Kommentar oben ("Table-Fixup-Anonymous-Box-Risiko"), keine reine Optik. */
  .profile-page .hs-board .hs-cardrow--open td {
    margin-bottom: 0;
    border-bottom: none;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }
  [data-hs-js] .profile-page .hs-board .hs-details-row.is-open { display: block; }
  .profile-page .hs-board .hs-details-row > td,
  .profile-page .hs-board .hs-details-row > td.hs-details-cell {
    display: block;
    position: static;
    box-shadow: none;
    background: rgba(0, 0, 0, 0.18);
    border: 1px solid var(--line);
    border-top: none;
    border-radius: 0 0 8px 8px;
    margin-bottom: 8px;
    padding: 10px 12px 12px;
  }
  .profile-page .hs-board .hs-details-meta { overflow-wrap: anywhere; }
}
