/* SubSloth Dashboard — Modern MudBlazor styling */

/* ── Design-Tokens (STYLE.md §3) ──────────────────────────────────────────────
   Alle Tokens leiten sich aus den --mud-palette-*-Variablen ab, die der
   MudThemeProvider (SubSlothTheme) generiert — sie flippen daher automatisch
   mit dem Light/Dark-Toggle. Keine festen Hex-Werte für Flächen/Text/Borders! */
:root {
    /* Flächen */
    --app-surface-card:   var(--mud-palette-surface);
    --app-surface-inner:  var(--mud-palette-background);
    --app-surface-raised: var(--mud-palette-drawer-background);
    --app-border:         var(--mud-palette-lines-default);
    --app-text-muted:     var(--mud-palette-text-secondary);
    /* Dezentes "Anheben" Richtung Textfarbe — hellt im Dark Mode auf, dunkelt im Light Mode ab */
    --app-hover-bg:       color-mix(in srgb, var(--mud-palette-text-primary) 5%, transparent);

    /* Semantische Status-Farben (Case-Workflow) */
    --app-status-open:          var(--mud-palette-error);
    --app-status-investigating: var(--mud-palette-warning);
    --app-status-resolved:      var(--mud-palette-primary);
    --app-status-closed:        var(--mud-palette-success);

    /* Bewusst modus-unabhängige Akzente (funktionieren auf hell & dunkel).
       Werte kommen aus dem Heroes-Lounge-DS, wo es ein Äquivalent gibt (Kommentar nennt
       das DS-Token); der Rest ist als DS-Lücke markiert und wird im Rework geklärt. */
    --app-on-dark:       var(--fg-on-dark);        /* Text auf dauerhaft dunklen Flächen (Map-Banner, Tooltips) */
    --app-on-dark-muted: var(--fg-on-dark-muted);  /* gedämpfter Text auf dauerhaft dunklen Bannern/Overlays */
    --app-team-home:     var(--hl-team-a);         /* Team-Akzent home (Ban-/Pick-Tiles) */
    --app-team-away:     var(--hl-team-b);         /* Team-Akzent away */
    --app-blacklisted:   var(--hl-violet-600);     /* Blacklist-Chip */
    --app-banned:        var(--hl-red-600);        /* Gebannte Spieler */
    /* DS-Lücke: kein Gold-/Critical-Äquivalent im DS. Bewusst beibehalten, bis das DS
       einen Winner- bzw. Critical-Ton definiert (siehe docs/plans/2026-07-28-ui-rework-design-system-plan.md). */
    --app-gold: #ffd700;          /* Winner/MVP-Highlight — DS-Lücke */
    --app-critical: #9b1c31;      /* Critical-Chip — DS-Lücke */

    /* Skeleton pulse — richtet sich nach MudBlazors Skeleton-Default, darf aber nicht
       hardcoded übernommen werden; nutzt Overlay aus Text-Farbe für Theme-Flip. */
    --app-skeleton-bg: color-mix(in srgb, var(--mud-palette-text-primary) 8%, transparent);

    /* Case-Tracking-Status-Marker (Violation-Banner + Legende).
       Waren vier Rohfarben aus der Zeit vor dem DS. Der Rework-Plan §6.2 hielt fest, dass
       das DS für vier Stufen zu wenig Töne hat — „late" und „deadline" wären beide gelblich.
       Die Auflösung liegt im Bestand selbst: jeder der sechs Zustände trägt bereits ein
       eigenes Icon (CheckCircle, AccessTime, Timer, Gavel, Warning, Report). Die Farbe
       unterscheidet also nichts, was das Icon nicht schon unterscheidet, und kann auf die
       semantischen Palette-Rollen fallen — die zudem mit dem Theme flippen.
       „late" und „deadline" teilen sich bewusst das Amber; getrennt bleiben die Namen, weil
       die Zustände getrennt sind. */
    --app-track-resolved: var(--mud-palette-success);   /* rechtzeitig registriert */
    --app-track-late:     var(--mud-palette-warning);   /* Late Registration */
    --app-track-deadline: var(--mud-palette-warning);   /* Deadline läuft */
    --app-track-case:     var(--hl-violet-500);         /* Case existiert — DS-Violett */

    /* Case-Nummer-Akzent in .detail-stats-table (z.B. Cases.razor) */
    --app-case-number: var(--mud-palette-primary);

    /* Alt-Aliase — nur für Bestandscode, in neuem Code die --app-*-Tokens nutzen */
    --card-bg: var(--app-surface-card);
    --card-border: var(--app-border);
    --table-bg: var(--app-surface-inner);
    --inner-card-bg: var(--app-surface-inner);
    --color-open: var(--app-status-open);
    --color-investigating: var(--app-status-investigating);
    --color-resolved: var(--app-status-resolved);
    --color-closed: var(--app-status-closed);
    --color-case-number: var(--mud-palette-primary-lighten);
    --color-muted: var(--app-text-muted);
    --color-critical: var(--app-critical);
    --color-blacklisted: var(--app-blacklisted);
}

/* ── Layout-Chrome (AppBar/Drawer) — Hintergrund kommt aus der Palette ── */
.app-appbar {
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--app-border);
}

.app-drawer {
    border-right: 1px solid var(--app-border);
}

/* Marke in der AppBar: HL-Symbol + SubSloth-Wortmarke (BrandMark.razor).
   Die DS-Lücke aus Rework-Plan §6.6 ist geschlossen — die ursprünglich gelieferten Logos
   waren deckende JPGs ohne Alpha; die jetzigen PNGs sind echt freigestellt.
   Display-Font/Uppercase/Tracking der Wortmarke kommen aus dem Theme (Typo.h6). */
.brand-mark {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

/* Das Symbol ist reines Markenblau und braucht deshalb keine Modus-Variante.
   Höhe an der Wortmarke ausgerichtet, Breite folgt dem Seitenverhältnis (654×752). */
.brand-mark__symbol {
    height: 24px;
    width: auto;
    display: block;
}

.app-wordmark {
    color: var(--mud-palette-appbar-text);
}

/* Volles HL-Lockup auf der Login-Fläche (§5.1). Zwei Tinten, in Markup umgeschaltet —
   MudBlazor schreibt seine Palette in :root und lässt keinen CSS-Hook für einen
   Bildwechsel. Breite gedeckelt, damit es auf der 420px-Karte Luft behält. */
.brand-lockup {
    width: 100%;
    max-width: 240px;
    height: auto;
    display: block;
}

/* ── Sidebar-Navigation (DS: ui_kits/subsloth Sidebar.jsx) ──────────────────────
   Das DS zeichnet die Sidebar mit uppercase Display-Sektionslabels und einem
   aktiven Eintrag, der als abgesetzte Akzentfläche mit Seitenluft sitzt — nicht
   als randlose Vollbreiten-Markierung. */
.nav-section-label {
    display: block;
    font-family: var(--font-display);
    font-size: var(--app-fs-micro);
    font-weight: var(--app-fw-medium);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--app-text-muted);
}

.app-drawer .mud-nav-link.active:not(.mud-nav-link-disabled) {
    background: var(--surface-accent-active);
    color: var(--fg-on-dark);
    border-radius: var(--app-radius-sm);
    /* Seitenluft, damit die Fläche als Kachel und nicht als Vollbreiten-Balken liest */
    margin-inline: var(--space-2);
}

.app-drawer .mud-nav-link.active:not(.mud-nav-link-disabled) .mud-nav-link-icon {
    color: var(--fg-on-dark);
}

/* ── Font-Weight-Utilities (STYLE.md §3.2) ── */
.fw-medium   { font-weight: 500; }
.fw-semibold { font-weight: 600; }
.fw-bold     { font-weight: 700; }
.fw-black    { font-weight: 800; }

/* Stat-number status colors (Moderation pages) — map to the canonical --app-status-* tokens. */
.text-status-open          { color: var(--app-status-open); }
.text-status-investigating { color: var(--app-status-investigating); }
.text-status-resolved      { color: var(--app-status-resolved); }
.text-status-closed        { color: var(--app-status-closed); }
.text-status-blacklisted   { color: var(--app-blacklisted); }

/* ── Standard-Karten (STYLE.md §4.1) ── */
.app-card {
    background: var(--app-surface-card) !important; /* Mud-Elevation-Hintergrund überschreiben */
    border: 1px solid var(--app-border);
}

.app-card--inner {
    background: var(--app-surface-inner) !important; /* Mud-Elevation-Hintergrund überschreiben */
}

/* ProfileFilterBar popover width — must be GLOBAL, not scoped: MudPopover portals its panel to
   MudPopoverProvider at the app root, outside the component's DOM subtree, so a scoped selector
   (or ::deep) can't reach it. The panel carries this class via MudPopover Class=. Gives the
   three-column season grid room. */
.profile-filter-bar__popover {
    min-width: 320px;
    max-width: 90vw;
}

html, body {
    font-family: var(--font-body); /* DS --font-body (Inter) */
    margin: 0;
    padding: 0;
}

/* Hide number input spinners globally */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

h1:focus {
    outline: none;
}

/* ── Season Selector in AppBar ── */
.mud-appbar .mud-select {
    color: inherit !important;
}

.mud-appbar .mud-input-outlined .mud-input-outlined-border {
    border-color: var(--app-border) !important;
}

.mud-appbar .mud-input-outlined:hover .mud-input-outlined-border {
    border-color: var(--app-text-muted) !important;
}

.mud-appbar .mud-select .mud-input {
    font-size: 13px;
    color: inherit;
}

/* ── Season Selector in Drawer ── */
.season-selector-drawer {
    padding: 12px 12px 8px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--app-border);
}

.season-selector-drawer .mud-button-root {
    border-radius: 8px;
    padding: 6px 12px;
    min-height: 36px;
}

/* ── Status cards with left accent bar ── */
.status-card {
    position: relative;
    overflow: hidden;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    border: 1px solid var(--app-border);
    background: var(--app-surface-card) !important;
}

/* The DS is explicit that hover is "opacity or color shift only, no bounce/spring" and that
   elevation stays flat — the previous translateY(-2px) plus a raw 0 8px 24px shadow was both
   the bounce and the shadow-pop it rules out. A border shift carries the affordance instead. */
.status-card:hover {
    border-color: var(--border-accent);
}

.status-card::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    border-radius: 4px 0 0 4px;
}

.status-card.status-active::before { background: var(--mud-palette-success); }
.status-card.status-inactive::before { background: var(--mud-palette-error); }
.status-card.status-info::before { background: var(--mud-palette-primary); }
.status-card.status-warning::before { background: var(--mud-palette-warning); }

/* ── Map Banner ── */
.replay-map-banner {
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    background-color: var(--app-surface-card);
    min-height: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.replay-map-banner__overlay {
    position: relative;
    z-index: 1;
    text-align: center;
    padding: 32px 16px;
}

.replay-map-banner::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.6) 100%);
}

.replay-map-banner__build {
    position: absolute;
    bottom: 8px;
    right: 12px;
    z-index: 1;
}

/* ── Match Card ── */

/* ── Draft Order Strip ──
   Used on MatchDetail between GameDetailCard and GameStatsTabs. One horizontal row of compact
   hero tiles grouped by draft phase (ban-burst / pick-burst / ban-burst / pick-burst).
   Border colour encodes the HL team side (already resolved to home/away by GameStatMerge,
   so blue/red here is always = HL home/away, NOT raw in-game Blue/Red). Border style encodes
   ban (dashed, dimmed) vs pick (solid, vivid). Swaps get a small ↻ overlay. */
.draft-strip {
    gap: 0.5rem;
    justify-content: center; /* draft row centred horizontally */
}

.draft-strip__caption { justify-content: center; }

.draft-strip__title { letter-spacing: 0.3px; }

.draft-strip__phase {
    gap: 0.3rem;
}

.draft-strip__phase-sep {
    width: 1px;
    height: 52px;
    background: var(--app-border);
    flex-shrink: 0;
    margin: 0 0.35rem;
}

.draft-strip__tile {
    width: 56px;
    height: 56px;
    border-radius: 50%; /* round, follows the circular hero portrait instead of a box */
    border: 2px solid transparent;
    overflow: hidden;
    position: relative;
    flex-shrink: 0;
    background: var(--app-surface-card);
}

.draft-strip__tile--home { border-color: var(--app-team-home); }
.draft-strip__tile--away { border-color: var(--app-team-away); }

.draft-strip__tile--ban {
    border-style: dashed;
    opacity: 0.85;
}

/* Banned heroes shown de-saturated to read as "removed". */
.draft-strip__tile--ban .draft-strip__tile-img {
    filter: grayscale(1);
}

.draft-strip__tile--pick {
    border-style: solid;
}

.draft-strip__tile-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.draft-strip__tile-fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--app-text-muted);
    font-size: 12px;
    font-weight: var(--app-fw-semibold);
}

.draft-strip__tile-overlay {
    position: absolute;
    bottom: 0;
    right: 0;
    background: var(--mud-palette-warning);
    color: var(--mud-palette-background);
    font-size: 10px;
    line-height: 1;
    padding: 1px 2px;
    border-top-left-radius: 4px;
}

.draft-strip__label { font-size: var(--text-body-xs); font-weight: var(--app-fw-semibold); }
.draft-strip__label--home { color: var(--app-team-home); }
.draft-strip__label--away { color: var(--app-team-away); }

.draft-strip__source-chip {
    height: 20px;
    font-size: var(--text-body-xs);
    text-transform: none;
    letter-spacing: 0;
}
/* DS Card (readme "Borders & shadows" / "Corners"): 1px --border-subtle, small radius, very
   soft low-elevation shadow — separation comes from the border, not from the shadow. The
   previous 0 4px 20px rgba(0,0,0,.4) was a raw colour and far heavier than the DS allows. */
.match-card {
    position: relative;
    isolation: isolate;
    background: var(--app-surface-card);
    border-radius: var(--app-radius-lg);
    overflow: hidden;
    border: 1px solid var(--app-border);
    box-shadow: var(--app-shadow-card);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

/* Full-card click target that navigates to the match details. Sits above passive content but
   below interactive elements (player tags, footer buttons) which are lifted with higher z-index. */
.match-card__click {
    position: absolute;
    inset: 0;
    z-index: 2;
    cursor: pointer;
}

/* DS: hover is "opacity or color shift only, no bounce/spring" and "no shadow-pop". */
.match-card:hover {
    border-color: var(--border-accent);
    box-shadow: var(--app-shadow-hover);
}

.match-card--played {
    border-left: 4px solid var(--mud-palette-success);
}

/* Header Banner — bewusst dunkles Marken-Band in beiden Themes (weißer Text darauf ok).
   DS: "flat solid colors only, no gradients" + --surface-dark als Marken-Dunkelfläche. */
.match-card__header {
    background: var(--surface-dark);
    padding: 10px 16px;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 6px;
    border-bottom: 2px solid var(--mud-palette-success);
}

.match-card__header--played {
    border-bottom-color: var(--mud-palette-success);
    /* Leicht angehobene Marken-Dunkelfläche; den "played"-Status trägt die Success-Border. */
    background: var(--surface-dark-raised);
}

.match-card__header--warning {
    border-bottom-color: var(--mud-palette-error);
}

.match-card__header--ingame {
    border-bottom-color: var(--mud-palette-info);
}

/* Season badge on match cards — the DS Tag (components/core/Badge.jsx): a tinted pill in the
   display face. The two rgba() literals were the old Discord blurple and stayed put through the
   palette flip; 0.65rem (10.4px) was below the DS's 11px floor. */
.season-badge {
    padding: 3px 10px;
    border-radius: var(--app-radius-sm);
    font-family: var(--font-display);
    font-size: var(--text-body-xs);
    font-weight: var(--app-fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
    background: color-mix(in srgb, var(--mud-palette-primary) 25%, transparent);
    color: var(--mud-palette-primary-lighten);
    border: 1px solid color-mix(in srgb, var(--mud-palette-primary) 50%, transparent);
    white-space: nowrap;
    flex-shrink: 0;
}

.match-card__meta {
    font-size: var(--text-body-xs);
    color: var(--app-text-muted);
    letter-spacing: var(--tracking-caps);
}

/* Match ID — the DS reserves the mono face for IDs alongside scores and MMR. */
.match-card__id {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--app-text-muted);
    font-weight: var(--app-fw-medium);
    font-size: var(--text-body-sm);
}

/* VS Section — the core layout */
.match-card__body {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 0;
    padding: 16px;
    align-items: center;
}

.team {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.team--home { text-align: left; }
.team--away { text-align: right; }

/* Team names are the DS's display treatment (readme: the wordmark face is used for
   headings/CTAs/labels), so they move from Inter 800 onto Oswald. The weight drops to 700:
   Oswald ships nothing above it, and --app-fw-black (800) is reserved for the body face —
   see the rework plan §6.5. --tracking-display replaces the hardcoded 0.5px. */
.team__name {
    position: relative;
    z-index: 1;
    font-family: var(--font-display);
    font-size: var(--text-body-md);
    font-weight: var(--app-fw-bold);
    color: var(--mud-palette-text-primary);
    text-transform: uppercase;
    letter-spacing: var(--tracking-display);
    line-height: var(--leading-snug);
}

/* Team logo watermark — fills the full block height (top-to-bottom) behind the team's data and
   fades out toward the center. Deliberately over-scaled past the container height and centered, so
   the visible emblem reaches the top/bottom edges even though the source PNGs carry transparent
   padding; the container's overflow:hidden clips the excess. Width follows the logo's aspect ratio. */
.team__logo-bg {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 155%;
    width: auto;
    opacity: 0.24;
    z-index: 0;
    pointer-events: none;
    user-select: none;
}

.team--home .team__logo-bg,
.match-detail-team--home .team__logo-bg {
    left: 0;
    -webkit-mask-image: linear-gradient(to right, #000 20%, transparent 92%);
            mask-image: linear-gradient(to right, #000 20%, transparent 92%);
}

.team--away .team__logo-bg,
.match-detail-team--away .team__logo-bg {
    right: 0;
    -webkit-mask-image: linear-gradient(to left, #000 20%, transparent 92%);
            mask-image: linear-gradient(to left, #000 20%, transparent 92%);
}

/* Match-detail team columns get the same watermark treatment (no click overlay there). */
.match-detail-team {
    position: relative;
    overflow: hidden;
}

.match-detail-team > *:not(.team__logo-bg) {
    position: relative;
    z-index: 1;
}

.team__name--winner {
    color: var(--mud-palette-warning);
}

/* VS Divider */
.vs-divider {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 16px;
    gap: 2px;
}

/* Display face; weight 900 was unreachable (Oswald tops out at 700, Inter at 800) and so
   already rendered as the nearest available weight. The glow is gone with it — the DS has no
   text-shadow anywhere and the raw amber it used was left over from the old palette. */
.vs-divider__text {
    font-family: var(--font-display);
    font-size: var(--text-display-sm);
    font-weight: var(--app-fw-bold);
    color: var(--mud-palette-warning);
}

/* A score is a number: DS mono, tabular, so 1:0 and 3:2 occupy the same width. */
.vs-divider__score {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-body-sm);
    font-weight: var(--app-fw-semibold);
    color: var(--mud-palette-text-primary);
}

.vs-divider__time {
    font-size: 11px;
    color: var(--app-text-muted);
    white-space: nowrap;
}

.vs-divider__takedowns {
    font-size: 11px;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    white-space: nowrap;
    letter-spacing: 0.5px;
}

.vs-divider__takedowns-icon {
    color: var(--mud-palette-error-lighten);
    margin-right: 1px;
}

.team-logo {
    object-fit: contain;
    border-radius: 4px;
    vertical-align: middle;
    flex-shrink: 0;
}

/* Player Roster */
.team__roster {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.team--away .team__roster {
    justify-content: flex-end;
}

.player-tag {
    position: relative;
    z-index: 3;
    background: var(--app-hover-bg);
    border: 1px solid var(--app-border);
    border-radius: 6px;
    padding: 6px 10px;
    font-size: 11px;
    color: var(--mud-palette-text-primary);
    transition: all 0.2s;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    min-height: 32px;
}

/* Every tint below used to be a literal rgba() of the *pre-DS* palette (neon green #00ff88,
   Discord blurple #5865F2, #ED4245, #be1e2d) paired with a var() text colour. After the palette
   flip the tint and the text it sits behind were no longer the same hue. Mixing from the same
   variable the text uses keeps them in step, in both modes and through any future palette edit. */
.player-tag:hover {
    background: color-mix(in srgb, var(--mud-palette-success) 10%, transparent);
    border-color: var(--mud-palette-success);
    color: var(--mud-palette-success);
}

.player-tag--warning {
    border-color: color-mix(in srgb, var(--mud-palette-error) 50%, transparent);
    color: var(--mud-palette-error);
}

.player-tag--warning:hover {
    background: color-mix(in srgb, var(--mud-palette-error) 10%, transparent);
    border-color: var(--mud-palette-error);
    color: var(--mud-palette-error);
}

.player-tag--sub {
    border-color: color-mix(in srgb, var(--mud-palette-primary) 50%, transparent);
    color: var(--mud-palette-primary);
}

.player-tag--sub:hover {
    background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
    border-color: var(--mud-palette-primary);
    color: var(--mud-palette-primary);
}

.player-tag--banned {
    border-color: color-mix(in srgb, var(--app-banned) 70%, transparent);
    color: var(--app-banned);
    background: color-mix(in srgb, var(--app-banned) 8%, transparent);
}

.player-tag--banned:hover {
    background: color-mix(in srgb, var(--app-banned) 15%, transparent);
    border-color: var(--app-banned);
    color: var(--app-banned);
}

/* Status Badge — the DS StatusPill (components/core/Badge.jsx): a pill in the display face with
   a tint mixed from its own accent. The comment here used to claim the rgba() tints were alpha
   variants of the palette accents; that stopped being true at the palette flip — they were the
   old accents (#ffaa00, #00ff88, #7289DA, #ED4245) sitting behind the new ones. */
.status-badge {
    padding: 3px 10px;
    border-radius: var(--app-radius-pill);
    font-family: var(--font-display);
    font-size: var(--text-body-xs);
    font-weight: var(--app-fw-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.status-badge--pending {
    background: color-mix(in srgb, var(--mud-palette-warning) 15%, transparent);
    color: var(--mud-palette-warning);
    border: 1px solid color-mix(in srgb, var(--mud-palette-warning) 40%, transparent);
}

/* The one badge that reads as the card's headline result, so it stays a step larger. Weight
   stays at the display face's ceiling — 800 is body-face only (plan §6.5). */
.status-badge--played {
    background: color-mix(in srgb, var(--mud-palette-success) 20%, transparent);
    color: var(--mud-palette-success);
    border: 1px solid color-mix(in srgb, var(--mud-palette-success) 60%, transparent);
    font-size: var(--text-body-sm);
    padding: 4px 12px;
    font-weight: var(--app-fw-bold);
}

.status-badge--ingame {
    background: color-mix(in srgb, var(--mud-palette-info) 15%, transparent);
    color: var(--mud-palette-info);
    border: 1px solid color-mix(in srgb, var(--mud-palette-info) 40%, transparent);
    animation: pulse-badge 1.5s infinite;
}

.status-badge--warning {
    background: color-mix(in srgb, var(--mud-palette-error) 15%, transparent);
    color: var(--mud-palette-error);
    border: 1px solid color-mix(in srgb, var(--mud-palette-error) 40%, transparent);
    animation: pulse-badge 1.5s infinite;
}

/* The DS allows "opacity or color shift only" — a pulse qualifies, but it is the one animation
   in the app that never stops, so it yields to the reduced-motion preference. */
@keyframes pulse-badge {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
    .status-badge--ingame,
    .status-badge--warning {
        animation: none;
    }
}

/* Match Card Footer */
.match-card__footer {
    position: relative;
    z-index: 3;
    background: var(--app-hover-bg);
    border-top: 1px solid var(--app-border);
    padding: 10px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

/* Footer action row: Details on the left, "View on HL" pushed to the right (via ms-auto). */
.match-card--skeleton {
    /* Amarant-leaner Skeleton-Hintergrund statt Echt-Daten; kein Hover-Lift */
    pointer-events: none;
}

/* A skeleton is not clickable, so it keeps the resting card chrome on hover. */
.match-card--skeleton:hover {
    border-color: var(--app-border);
    box-shadow: var(--app-shadow-card);
}

.match-card--skeleton .mud-skeleton {
    background-color: var(--app-skeleton-bg);
}

.match-card__footer-actions {
    width: 100%;
}

.match-card__maps {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.match-card__games {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
}

.game-card {
    display: flex;
    align-items: stretch;
    border-radius: 6px;
    overflow: hidden;
    border: 1px solid var(--app-border);
    background: var(--app-hover-bg);
}

/* Which side won a map. These carried the old blurple/neon-green literals; the two roles have
   DS team tokens, and using them also makes the pair read as "home vs away" rather than as
   "brand vs success". */
.game-card--home-win {
    border-color: color-mix(in srgb, var(--app-team-home) 40%, transparent);
}

.game-card--away-win {
    border-color: color-mix(in srgb, var(--app-team-away) 40%, transparent);
}

.game-card__img {
    width: 80px;
    min-height: 48px;
    background-size: cover;
    background-position: center;
    flex-shrink: 0;
    /* The new full-res map art is vivid — tone the small thumbnail down. */
    filter: brightness(0.7);
}

.game-card__info {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    min-height: 40px;
}

.game-card__map {
    font-size: 11px;
    font-weight: 600;
    color: var(--mud-palette-text-primary);
}

.game-card__duration {
    font-size: 10px;
    color: var(--app-text-muted);
}

.game-card__winner {
    font-size: 10px;
    font-weight: 600;
    color: var(--app-gold);
}

/* ── Game Stats (expandable per-game player stats table) ── */
.game-stats-container {
    padding: 8px 12px 10px;
    border-top: 1px solid var(--app-border);
}

.game-stats-bans {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 8px;
    font-size: 10px;
    color: var(--app-text-muted);
}

.game-stats-ban-label {
    font-weight: 500;
}

.game-stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 10px;
}

.game-stats-table th {
    text-align: left;
    padding: 3px 6px;
    color: var(--app-text-muted);
    font-weight: 600;
    font-size: 9px;
    text-transform: uppercase;
    border-bottom: 1px solid var(--app-border);
}

.game-stats-table td {
    padding: 2px 6px;
    color: var(--mud-palette-text-primary);
    white-space: nowrap;
}

.game-stats-row--home td {
    color: var(--mud-palette-primary-lighten);
}

.game-stats-row--away td {
    color: var(--mud-palette-success-lighten);
}

.map-tag {
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 11px;
    font-weight: 600;
    border: 1px solid var(--app-border);
    background: var(--app-hover-bg);
    color: var(--app-text-muted);
}

.map-tag--home-win {
    border-color: rgba(88, 101, 242, 0.5);
    color: var(--mud-palette-primary);
}

.map-tag--away-win {
    border-color: rgba(0, 255, 136, 0.5);
    color: var(--mud-palette-success);
}

.view-btn {
    background: transparent;
    border: 1px solid var(--mud-palette-primary);
    color: var(--mud-palette-primary);
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
    text-decoration: none;
    display: inline-block;
}

.view-btn:hover {
    background: rgba(85, 136, 255, 0.15);
    color: var(--mud-palette-primary-lighten);
}

/* ── Unregistered Sub Banner ── */
.unreg-sub-banner {
    background: rgba(237, 66, 69, 0.08);
    border-top: 1px solid rgba(237, 66, 69, 0.3);
    padding: 8px 16px;
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 11px;
    color: var(--mud-palette-error);
}

.unreg-sub-entry {
    margin-bottom: 2px;
}

/* ── Page headers (DS Topbar; PageHeader.razor, plan §2.5) ──
   The class existed but nothing used it — all 22 headers were hand-rolled copies of the
   same flex markup. It now backs the shared component. Alignment follows the DS Topbar:
   flex-start, so a two-line subtitle does not drag the action buttons down with it. */
.page-header {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 24px;
}

.page-header--with-actions {
    justify-content: space-between;
}

.page-header__lead {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.page-header__actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

/* Section divider */
.section-title {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 8px;
    margin-bottom: 16px;
}

.section-title::after {
    content: '';
    flex: 1;
    height: 1px;
    background: currentColor;
    opacity: 0.12;
}

/* Drag handle */
.drag-handle {
    cursor: grab;
    opacity: 0.4;
    transition: opacity 0.15s;
}

.drag-handle:hover {
    opacity: 1;
}

/* Card hover effects */
.hover-card {
    transition: transform 0.15s ease, box-shadow 0.15s ease;
    border: 1px solid var(--app-border);
}

.hover-card:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

/* Quick action buttons */
.quick-action {
    transition: transform 0.15s ease;
}

.quick-action:hover {
    transform: translateY(-2px);
}

/* Smooth page transitions */
.mud-main-content {
    animation: fadeIn 0.2s ease-in;
}

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

/* Expansion panel refinements */
.mud-expand-panel {
    border-radius: var(--app-radius-lg) !important; /* DS --radius-lg; Mud-Default überschreiben */
    margin-bottom: 8px !important;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA9NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--hl-red-600);
    padding: 1rem 1rem 1rem 3.7rem;
    color: var(--fg-on-dark);
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

/* ── Pulse dot animation (Bot Status) ── */
.pulse-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    animation: pulse 2s ease-in-out infinite;
}

.pulse-green {
    background: var(--mud-palette-success);
    box-shadow: 0 0 0 0 rgba(0, 255, 136, 0.6);
}

.pulse-red {
    background: var(--mud-palette-error);
    box-shadow: 0 0 0 0 rgba(237, 66, 69, 0.6);
    animation-name: pulseRed;
}

@keyframes pulse {
    0% { box-shadow: 0 0 0 0 rgba(0, 255, 136, 0.6); }
    70% { box-shadow: 0 0 0 8px rgba(0, 255, 136, 0); }
    100% { box-shadow: 0 0 0 0 rgba(0, 255, 136, 0); }
}

@keyframes pulseRed {
    0% { box-shadow: 0 0 0 0 rgba(237, 66, 69, 0.6); }
    70% { box-shadow: 0 0 0 8px rgba(237, 66, 69, 0); }
    100% { box-shadow: 0 0 0 0 rgba(237, 66, 69, 0); }
}

/* Next match countdown card */
.next-match-card {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--app-border);
    background: var(--app-surface-card) !important;
}

.next-match-card::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 4px;
    border-radius: 4px 0 0 4px;
    background: var(--mud-palette-warning);
}

/* ── Division Toggle ── */
.division-toggle {
    cursor: pointer;
    user-select: none;
    padding: 4px 8px;
    border-radius: 8px;
    transition: background 0.15s ease;
}

.division-toggle:hover {
    background: var(--app-hover-bg);
}

/* Fallback-Banner für Games ohne Map-Bild — bewusst dunkles Marken-Band in beiden Themes. */
.detail-map-fallback {
    background: var(--surface-dark);
}

/* ── Replay Analyzer ── */
/* Bewusst dunkles Marken-Banner in beiden Themes (weißer Text darauf ok). */
.replay-match-banner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    background: var(--surface-dark);
    border-bottom: 1px solid var(--app-border);
}

.replay-team {
    padding: 20px 24px;
    text-align: center;
}

.replay-team--winner {
    background: rgba(0, 255, 136, 0.06);
}

.replay-team--loser {
    background: rgba(237, 66, 69, 0.04);
    opacity: 0.7;
}

.replay-vs {
    font-size: 22px;
    font-weight: 900;
    color: var(--mud-palette-warning);
    text-shadow: 0 0 20px rgba(255, 170, 0, 0.5);
    padding: 0 16px;
}

.replay-teams-grid {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
}

.replay-player-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-radius: 8px;
    margin-bottom: 4px;
    transition: background 0.15s;
}

.replay-player-row:hover {
    background: var(--app-hover-bg);
}

.replay-player-hero {
    display: flex;
    align-items: center;
    gap: 10px;
}

@media (max-width: 960px) {
    .replay-match-banner,
    .replay-teams-grid {
        grid-template-columns: 1fr;
    }

    .replay-vs {
        text-align: center;
        padding: 8px 0;
    }
}

/* ── Replay Stats Table ── */
.replay-tabs .mud-tabs-toolbar {
    background: rgba(0, 0, 0, 0.2) !important;
    border-bottom: 1px solid var(--app-border);
}

/* ── Substitutes page tabs ── */
.sub-tabs .mud-tabs-toolbar {
    background: rgba(0, 0, 0, 0.2) !important;
    border-bottom: 1px solid var(--app-border);
}

.replay-stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    table-layout: auto;
}

.replay-stats-table th {
    padding: 6px 8px;
    text-align: left;
    font-weight: 600;
    color: var(--app-text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--app-border);
    white-space: nowrap;
}

.replay-stats-th-hero {
    width: 40px;
}

.replay-stats-th-num {
    text-align: right !important;
}

.replay-stats-th-talent {
    text-align: center !important;
    width: 44px;
}

.replay-stats-row td {
    padding: 4px 8px;
    border-bottom: 1px solid var(--mud-palette-table-lines);
    vertical-align: middle;
}

.replay-stats-row:hover td {
    background: var(--app-hover-bg);
}

.replay-stats-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    color: var(--mud-palette-text-primary);
    white-space: nowrap;
}

.replay-stats-team-header td {
    padding: 6px 8px;
    font-size: 11px;
    border-bottom: 2px solid var(--app-border);
    background: rgba(0, 0, 0, 0.15);
}

.replay-stats-totals td {
    padding: 8px 10px;
    border-top: 2px solid var(--app-border);
    background: rgba(0, 0, 0, 0.1);
    color: var(--mud-palette-text-primary);
    font-weight: 700;
}

.replay-stats-spacer td {
    padding: 3px 0;
    border: none;
}

.replay-stats-hero-cell {
    width: 40px;
    padding: 4px 6px !important;
}

.replay-hero-icon {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    object-fit: cover;
    background: var(--app-hover-bg);
    border: 1px solid var(--app-border);
}

/* MatchDetail: small role badge overlaid on the hero icon in the per-game stats table. */
.mdx-hero-role { position: relative; display: inline-block; line-height: 0; }
.mdx-role-icon {
    position: absolute; right: -4px; bottom: -4px;
    width: 14px; height: 14px; border-radius: 50%;
    background: var(--app-surface-card); padding: 1px;
    box-shadow: 0 0 0 1px var(--app-border);
}
/* MatchDetail: GameStatsTabs cell styling — replaces inline color/font-weight/font-size (STYLE.md §4.4/§3.2/§5.4). */
.mdx-team-home { color: var(--mud-palette-primary); }
.mdx-team-away { color: var(--mud-palette-error); }
.mdx-stat-best { font-weight: 700; color: var(--app-gold); }
.mdx-kda-k { color: var(--mud-palette-success); }
.mdx-kda-d { color: var(--mud-palette-error); }
.mdx-kda-a { color: var(--mud-palette-primary-lighten); }
.mdx-subtext { font-size: var(--text-body-xs); color: var(--app-text-muted); }
.mdx-tooltip-title { font-weight: 700; color: var(--app-on-dark); }
.mdx-tooltip-desc { font-size: var(--text-body-xs); color: var(--app-text-muted); line-height: 1.4; }

/* ── Replay stats tables: merged Hero+Player lead cell ──
   Wide partyframe banner (128×56) anchored left, flush with the row's top/bottom edges, fading
   out to the right; player/hero names overlay it. Falls back to the small hero icon
   (left-anchored) when no partyframe art exists for the hero. Row height target ~44px. */
.replay-pf-cell {
    position: relative;
    min-width: 150px;
    height: 44px;
    /* !important (STYLE.md §8): overrides the generic `.replay-stats-row td { padding: 4px 8px }`
       rule, which otherwise wins on specificity and would inset the banner from the cell edge. */
    padding: 0 8px 0 0 !important;
}
/* Clips the banner + fade to the cell bounds. Kept separate from .replay-pf-cell so callers that
   also render an overflowing child (e.g. ReplayAnalyzer's hover popover) can place it as a sibling
   outside this wrapper instead of inside — it would otherwise be clipped by overflow:hidden. */
.replay-pf-inner {
    position: relative;
    height: 100%;
    overflow: hidden;
}
.replay-pf-img {
    position: absolute; inset: 0 auto 0 0; height: 100%; width: auto;
    /* fade the banner out to the right so the overlaid text stays legible; rgba() here is a
       documented mask-alpha exception per STYLE.md §2.4 (black-based, not a color value). */
    -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 55%, rgba(0, 0, 0, 0) 100%);
    mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 55%, rgba(0, 0, 0, 0) 100%);
}
.replay-pf-text {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    padding-left: 8px;
    /* subtle shadow keeps player/hero text legible over the banner artwork; rgba() here is a
       documented overlay-alpha exception per STYLE.md §2.4 (black-based, not a color value). */
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}
.replay-pf-fallback {
    position: absolute;
    left: 6px;
    top: 50%;
    transform: translateY(-50%);
}
.replay-pf-text--icon {
    padding-left: 44px;
}

/* ── Replay Talent Cells ── */
.replay-talent-cell {
    text-align: center;
    vertical-align: middle;
    padding: 2px !important;
}

.replay-talent-pick {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 6px;
    background: rgba(88, 101, 242, 0.1);
    border: 1px solid rgba(88, 101, 242, 0.3);
    cursor: pointer;
    transition: all 0.15s ease;
}

.replay-talent-pick:hover {
    border-color: var(--mud-palette-primary);
    background: rgba(88, 101, 242, 0.2);
    transform: scale(1.1);
}

.replay-talent-icon {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    object-fit: cover;
}

.replay-talent-fallback {
    font-size: 9px;
    font-weight: 700;
    color: var(--app-text-muted);
    text-overflow: ellipsis;
    overflow: hidden;
    max-width: 36px;
    display: block;
}

.replay-talent-empty {
    color: var(--mud-palette-text-disabled);
    font-size: 14px;
}

/* ── Team Search Filter ── */
.match-filter-bar {
    background: var(--app-surface-card);
    border: 1px solid var(--app-border);
    border-radius: 12px;
    padding: 12px 16px;
    margin-bottom: 16px;
}

/* ── Legend Card ── */
.legend-card {
    background: var(--app-surface-card) !important;
    border: 1px solid var(--app-border);
    border-radius: 12px;
    padding: 12px 16px;
}

/* ── Severity/Risk chip overrides for dark theme visibility ── */
.chip-critical {
    background: var(--color-critical) !important;
    color: white !important; /* fester Akzent-Hintergrund — bewusst weiß in beiden Themes */
}

.chip-blacklisted {
    background: var(--color-blacklisted) !important;
    color: white !important; /* fester Akzent-Hintergrund — bewusst weiß in beiden Themes */
}

/* ── Responsive ── */

/* Responsive tables: horizontal scroll with fade indicator */
.mud-table {
    overflow: visible;
}

.mud-table .mud-table-container {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--mud-palette-text-disabled) transparent;
}

.mud-table .mud-table-container::-webkit-scrollbar {
    height: 6px;
}

.mud-table .mud-table-container::-webkit-scrollbar-thumb {
    background: var(--mud-palette-text-disabled);
    border-radius: 3px;
}

.mud-table .mud-table-container::-webkit-scrollbar-track {
    background: transparent;
}

/* Ensure table doesn't shrink columns too aggressively */
.mud-table .mud-table-root {
    min-width: 700px;
}

/* Truncated text in table cells */
.mud-td {
    max-width: 250px;
}

.cell-truncate {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Page headers: stack on mobile */
@media (max-width: 600px) {
    .d-flex.align-center.justify-space-between {
        flex-direction: column;
        align-items: flex-start !important;
        gap: 12px;
    }
}

/* ── Player Name Popover ── */
.replay-player-name {
    font-weight: 600;
    color: var(--mud-palette-text-primary);
    cursor: pointer;
    display: inline-block;
}

.replay-player-name:hover {
    color: var(--mud-palette-primary);
    text-decoration: underline;
}

.replay-player-popover {
    position: absolute;
    left: 0;
    top: 100%;
    z-index: 100;
    background: var(--app-surface-card);
    border: 1px solid var(--app-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.5);
    white-space: nowrap;
}

/* Stats cards: 2-col on very small screens */
@media (max-width: 400px) {
    .mud-grid > .mud-grid-item {
        flex-basis: 50% !important;
        max-width: 50% !important;
    }
}

@media (max-width: 960px) {
    .match-card__body {
        grid-template-columns: 1fr;
        gap: 12px;
        text-align: center;
    }

    .team--home, .team--away {
        text-align: center;
    }

    .team__roster, .team--away .team__roster {
        justify-content: center;
    }

    .vs-divider {
        padding: 4px 0;
    }

    .vs-divider__text {
        font-size: 18px;
    }

    /* Tighter filter bars on tablet */
    .d-flex.align-center.gap-4.flex-wrap {
        gap: 8px !important;
    }
}

@media (max-width: 600px) {
    .mud-main-content {
        padding: 8px !important;
    }

    .mud-container {
        padding-left: 8px !important;
        padding-right: 8px !important;
    }


    /* Compact stat cards. Targets the KPI value itself now that the tiles render through
       StatCard's .stat-card__value rather than a heading typo. */
    .status-card,
    .stat-card {
        padding: 8px 12px !important;
    }

    .stat-card__value {
        font-size: var(--text-display-sm);
    }

    /* Dialog full-width on mobile */
    .mud-dialog {
        margin: 8px !important;
        max-height: calc(100vh - 16px) !important;
    }

    .hero-card {
        width: 56px;
    }

    .hero-portrait {
        width: 48px;
        height: 48px;
    }

    .hero-name {
        font-size: var(--text-body-xs);
    }

    .map-grid {
        grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    }

    /* Table: hide less important columns on mobile */
    .hide-on-mobile {
        display: none !important;
    }

    /* Full width filter inputs */
    .d-flex.align-center.gap-4.flex-wrap > * {
        flex: 1 1 100% !important;
        max-width: 100% !important;
    }
}

/* ── Hero Grid (Nexus Rumble) ── */
.hero-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.hero-card {
    position: relative;
    width: 72px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    cursor: pointer;
    transition: transform 0.15s ease;
}

.hero-card:hover {
    transform: translateY(-3px);
}

.hero-portrait {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: 10px;
    overflow: hidden;
    border: 2px solid var(--app-border);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    flex-shrink: 0;
}

.hero-card:hover .hero-portrait {
    border-color: var(--app-text-muted);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}

.hero-portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: filter 0.2s ease;
}

.hero-card.banned .hero-portrait {
    border-color: var(--mud-palette-error);
}

.hero-card.banned .hero-portrait img {
    filter: grayscale(100%) brightness(0.4);
}

.hero-ban-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(237, 66, 69, 0.25);
}

.hero-name {
    display: block;
    font-size: var(--text-body-xs);
    margin-top: 4px;
    color: var(--app-text-muted);
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hero-card.banned .hero-name {
    color: var(--mud-palette-error);
    font-weight: 600;
}

/* ── Map Cards (Map Pool) ── */
.map-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 12px;
}

.map-card {
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.2s ease, filter 0.2s ease;
    border: 2px solid transparent;
}

.map-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}

.map-card.active {
    border-color: var(--mud-palette-success);
}

.map-card:not(.active) {
    opacity: 0.45;
    filter: grayscale(50%);
}

.map-card:not(.active):hover {
    opacity: 0.85;
    filter: none;
}

.map-card-img {
    width: 100%;
    height: 110px;
    object-fit: cover;
    display: block;
}

.map-card-label {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 8px 10px;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.85));
    font-size: var(--text-body-sm);
    font-weight: 600;
    color: white; /* liegt auf abgedunkeltem Map-Bild — bewusst weiß */
}

.map-card-badge {
    position: absolute;
    top: 6px;
    right: 6px;
    /* Liegt auf dem Map-Bild — bewusst feste Akzentfarben, unabhängig vom Theme. */
    background: var(--hl-green-500);
    color: var(--hl-ink-950);
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-body-xs);
    font-weight: 700;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* Sortable stats table headers */
.replay-stats-sortable {
    cursor: pointer;
    user-select: none;
    transition: color 0.15s;
}

.replay-stats-sortable:hover {
    color: var(--mud-palette-primary);
}

.replay-sort-icon {
    font-size: 10px;
    margin-left: 2px;
    opacity: 0.6;
}

/* ── Match Detail Page ── */

.match-detail-game {
    transition: box-shadow 0.2s ease;
}

.match-detail-game:hover {
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}

.match-detail-map {
    position: relative;
    width: 100%;
    height: 300px;
    border-radius: 12px 12px 0 0;
    overflow: hidden;
}

/* Blurred + darkened map art on its own layer so the sharp content above is unaffected. */
.match-detail-map::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--map-bg);
    background-size: cover;
    background-position: center;
    filter: blur(3px) brightness(0.55);
    transform: scale(1.06); /* absorb blur edge bleed */
    z-index: 0;
}

.match-detail-map__overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 16px 20px;
    /* Lighter than before — the background layer is already darkened. */
    background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.25) 55%, rgba(0, 0, 0, 0.05) 100%);
    border-radius: 12px 12px 0 0;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.85);
}

.match-detail-map__overlay .w-100 {
    width: 100%;
}

.match-detail-level-badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 6px;
    background: rgba(0, 0, 0, 0.5);
    color: var(--mud-palette-text-primary);
    font-size: 12px;
    font-weight: 500;
    border: 1px solid var(--app-border);
}

.match-detail-winner-badge {
    display: inline-block;
    padding: 3px 12px;
    border-radius: 6px;
    background: rgba(0, 255, 136, 0.15);
    color: var(--mud-palette-success);
    font-size: 13px;
    font-weight: 700;
    border: 1px solid rgba(0, 255, 136, 0.3);
}

.detail-ban-label {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border-radius: 6px;
    background: var(--app-hover-bg);
    color: var(--app-text-muted);
    font-size: 12px;
    font-weight: 500;
    border: 1px solid var(--app-border);
}

/* ── Ban Tiles (Map & Hero) ──
   Die rgba(85,136,255,…)/rgba(255,85,85,…)-Töne sind die festen Team-Akzente
   (--app-team-home/--app-team-away) als Alpha-Varianten — bewusst theme-unabhängig. */

.ban-map-tile {
    display: flex;
    flex: 1;
    min-width: 80px;
    flex-direction: column;
    align-items: center;
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid var(--app-border);
    background: var(--app-surface-inner);
    transition: transform 0.15s ease;
}
.ban-map-tile:hover {
    transform: translateY(-2px);
}

.ban-map-tile--home {
    border-color: rgba(85, 136, 255, 0.5);
    box-shadow: 0 0 8px rgba(85, 136, 255, 0.15);
}
.ban-map-tile--away {
    border-color: rgba(255, 85, 85, 0.5);
    box-shadow: 0 0 8px rgba(255, 85, 85, 0.15);
}

.ban-map-tile__img {
    width: 100%;
    height: 56px;
    background-size: cover;
    background-position: center;
    filter: grayscale(60%) brightness(0.8);
    transition: filter 0.2s ease;
}
.ban-map-tile:hover .ban-map-tile__img {
    filter: grayscale(20%) brightness(1);
}
.ban-map-tile__img--fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--app-surface-raised);
}
.ban-map-tile__name {
    padding: 3px 6px;
    font-size: 9px;
    font-weight: 600;
    color: var(--app-text-muted);
    text-align: center;
    max-width: 96px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ban-hero-tile {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid var(--app-border);
    background: var(--app-surface-inner);
    transition: transform 0.15s ease;
    flex-shrink: 0;
}
.ban-hero-tile:hover {
    transform: translateY(-2px);
}

.ban-hero-tile--home {
    border-color: rgba(85, 136, 255, 0.5);
    box-shadow: 0 0 8px rgba(85, 136, 255, 0.15);
}
.ban-hero-tile--away {
    border-color: rgba(255, 85, 85, 0.5);
    box-shadow: 0 0 8px rgba(255, 85, 85, 0.15);
}

.ban-hero-tile__img {
    width: 48px;
    height: 48px;
    object-fit: cover;
    filter: grayscale(40%);
    transition: filter 0.2s ease;
}
.ban-hero-tile:hover .ban-hero-tile__img {
    filter: grayscale(0%);
}
.ban-hero-tile__img--fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    background: var(--app-surface-raised);
    color: var(--mud-palette-text-disabled);
    font-size: 10px;
}
.ban-hero-tile__name {
    padding: 2px 6px;
    font-size: 9px;
    font-weight: 600;
    color: var(--app-text-muted);
    text-align: center;
    max-width: 72px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Compact variant for MatchCard games section */
.ban-hero-tile--compact .ban-hero-tile__img {
    width: 32px;
    height: 32px;
}
.ban-hero-tile--compact .ban-hero-tile__img--fallback {
    width: 32px;
    height: 32px;
}
.ban-hero-tile--compact .ban-hero-tile__name {
    font-size: 8px;
    max-width: 56px;
}

.ban-map-tile--compact .ban-map-tile__img {
    width: 64px;
    height: 36px;
}
.ban-map-tile--compact .ban-map-tile__name {
    font-size: 8px;
    max-width: 60px;
}

/* ── Ban Layout Helpers ── */

.ban-team-separator {
    width: 2px;
    background: var(--app-border);
    align-self: stretch;
    margin: 0 12px;
    border-radius: 1px;
}

/* Team label under the map ban / pick tiles (home left, away right). */
.draft-team-label {
    font-weight: var(--app-fw-semibold, 600);
}

.ban-vs-divider {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    font-weight: 900;
    color: var(--mud-palette-warning);
    text-shadow: 0 0 14px rgba(255, 170, 0, 0.5);
    padding: 0 12px;
    letter-spacing: 3px;
    gap: 4px;
}

/* ── Overlay hero tile (compact, for map overlay) ── */

.ban-hero-tile--overlay {
    border-width: 1px;
    border-radius: 6px;
}
.ban-hero-tile--overlay .ban-hero-tile__img {
    width: 64px;
    height: 64px;
    filter: grayscale(45%);
}
.ban-hero-tile--overlay .ban-hero-tile__img--fallback {
    width: 64px;
    height: 64px;
    font-size: 12px;
}
.ban-hero-tile--overlay .ban-hero-tile__name {
    font-size: 10px;
    max-width: 58px;
    padding: 1px 3px;
}

/* ── Pick vs Ban states (placed after --overlay so they win on source order) ── */

/* Picks: full-colour, vivid, stronger team-coloured glow. */
.ban-hero-tile--pick .ban-hero-tile__img {
    filter: none;
}
.ban-hero-tile--pick.ban-hero-tile--home {
    border-color: rgba(85, 136, 255, 0.85);
    box-shadow: 0 0 12px rgba(85, 136, 255, 0.35);
}
.ban-hero-tile--pick.ban-hero-tile--away {
    border-color: rgba(255, 85, 85, 0.85);
    box-shadow: 0 0 12px rgba(255, 85, 85, 0.35);
}

/* Bans: greyscale + dimmed, with a subtle "banned" marker. */
.ban-hero-tile--banned {
    position: relative;
    border-color: var(--app-border);
    box-shadow: none;
    opacity: 0.85;
}
.ban-hero-tile--banned .ban-hero-tile__img {
    filter: grayscale(100%) brightness(0.5);
}
.ban-hero-tile--banned:hover .ban-hero-tile__img {
    filter: grayscale(100%) brightness(0.65);
}
.ban-hero-tile--banned::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    /* only over the image area, not the name label */
    height: 64px;
    background: repeating-linear-gradient(135deg, rgba(237, 66, 69, 0.0) 0 6px, rgba(237, 66, 69, 0.18) 6px 8px);
    pointer-events: none;
}
.ban-hero-tile--banned .ban-hero-tile__name {
    color: var(--app-text-muted);
}

.hero-col-teamname {
    font-size: 12px;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    text-align: center;
}
.hero-col-teamname--winner {
    color: var(--app-gold);
    text-shadow: 0 0 12px rgba(255, 215, 0, 0.6);
}
.hero-col-level {
    font-size: 13px;
    font-weight: 700;
    color: var(--app-text-muted);
    text-align: center;
}
.game-duration-badge {
    font-size: 11px;
    font-weight: 600;
    color: var(--app-text-muted);
    text-align: center;
}

.detail-stats-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

/* Column heads carry the DS's recurring micro-label treatment — the same rule as .hl-label
   (hl-theme.css) and as the DS's own DataTable/StandingsTable column heads. Previously this
   was a hand-rolled near-miss: body face instead of the display face, weight 600 instead of
   500, and a hardcoded 0.5px letter-spacing instead of --tracking-caps. */
.detail-stats-table th {
    padding: 8px 10px;
    text-align: left;
    font-family: var(--font-display);
    font-size: var(--text-body-xs);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--fg-muted);
    border-bottom: 1px solid var(--app-border);
    user-select: none;
    white-space: nowrap;
}
.detail-stats-table th.sortable {
    cursor: pointer;
    transition: color 0.15s;
}
.detail-stats-table th.sortable:hover {
    color: var(--app-text-muted);
}
.detail-stats-table th .sort-arrow {
    display: inline-block;
    margin-left: 2px;
    font-size: 9px;
    opacity: 0.5;
}
.detail-stats-table th.sort-active {
    color: var(--mud-palette-warning);
}
.detail-stats-table th.sort-active .sort-arrow {
    opacity: 1;
}

.hero-role-chip-icon { width: 16px; height: 16px; vertical-align: middle; margin-right: 4px; }

.detail-stats-table td {
    padding: 8px 10px;
    color: var(--mud-palette-text-primary);
    border-bottom: 1px solid var(--app-border);
    vertical-align: middle;
}

/* Bulk-action toolbar above a table, shown once rows are selected (TeamChanges,
   MatchChanges, PlayerChanges). Was three copies of the same inline
   Style="background: rgba(88,101,242,.1); border: 1px solid rgba(88,101,242,.3)" — the old
   Discord blurple, left behind by the palette flip. Now one class, mixed from the palette. */
.bulk-toolbar {
    background: color-mix(in srgb, var(--mud-palette-primary) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--mud-palette-primary) 30%, transparent);
}

/* Shared pager for .detail-stats-table (STYLE.md §4.4). */
.table-pager {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 4px 0;
    font-size: var(--text-body-sm);
    color: var(--app-text-muted);
}
.table-pager__label { font-size: var(--text-body-xs); }
.table-pager__range { font-variant-numeric: tabular-nums; }
.table-pager__size { max-width: 96px; }

.detail-stat--max {
    color: var(--app-gold);
    font-weight: 800;
    text-shadow: 0 0 10px rgba(255, 215, 0, 0.5);
}

/* Home/away row tints. These were raw rgba() of the old Discord blurple and red — the same
   two roles already have DS tokens (--app-team-home/away → --hl-team-a/b), so they now tint
   from those and follow the theme. */
.detail-stats-row--home td {
    background: color-mix(in srgb, var(--app-team-home) 8%, transparent);
}

.detail-stats-row--away td {
    background: color-mix(in srgb, var(--app-team-away) 8%, transparent);
}

/* Horizontal-scroll wrapper for wide .detail-stats-table on narrow viewports. */
.detail-stats-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Match/series result colouring — the winning side green, the losing side red. Reused wherever a
   result/score is shown (standings, recent results, match tables) so results always read the same. */
.result-win { color: var(--mud-palette-success); }
.result-loss { color: var(--mud-palette-error); }

/* Selection checkbox column in .detail-stats-table (e.g. TeamChanges.razor). */
.dst-check { width: 36px; }

/* Clickable-row affordance (STYLE.md §4.4): hover tint + primary left accent bar so it
   reads as clickable. Tint uses the theme-safe --app-hover-bg (works light+dark). */
.detail-stats-table tbody tr.row-clickable { cursor: pointer; transition: background 0.12s ease; }
.detail-stats-table tbody tr.row-clickable:hover td { background: var(--app-hover-bg); }
.detail-stats-table tbody tr.row-clickable:hover td:first-child {
    box-shadow: inset 3px 0 0 var(--mud-palette-primary);
}
@media (prefers-reduced-motion: reduce) {
    .detail-stats-table tbody tr.row-clickable { transition: none; }
}

/* Case-# cell accent (Cases.razor) — the DS mono face (was a literal 'Courier New' stack),
   which is what the DS reserves for IDs, scores and MMR. */
.case-number {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: var(--app-fw-semibold);
    color: var(--app-case-number);
}

/* Game-history rows are shaded per MATCH (all games of a match share a tone), so it's easy to
   see which rows belong together. A left accent reinforces the grouping. */
.game-history-row--a td {
    background: var(--app-hover-bg);
}

/* Alternate match group. The tone only has to differ from --a's --app-hover-bg, so it is
   mixed from the palette primary instead of the raw violet-grey it used to hardcode. */
.game-history-row--b td {
    background: color-mix(in srgb, var(--mud-palette-primary) 7%, transparent);
}

.game-history-row--a td:first-child {
    box-shadow: inset 3px 0 0 color-mix(in srgb, var(--mud-palette-primary) 35%, transparent);
}

.game-history-row--b td:first-child {
    box-shadow: inset 3px 0 0 rgba(120, 130, 200, 0.6);
}

.stat-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

.stat-card {
    background: var(--app-surface-raised);
    border: 1px solid var(--app-border);
    border-radius: var(--app-radius-md);
    padding: 12px;
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* KPI value (DS StatCard, components/data/DataTable.jsx): the mono face with tabular
   figures, so the numbers in a tile grid line up column-wise instead of drifting. The
   display face is deliberately not used here — it is for titles, and it is uppercase. */
.stat-card__value {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: var(--text-display-md);
    font-weight: var(--app-fw-semibold);
    line-height: var(--leading-tight);
    color: var(--mud-palette-text-primary);
}

/* Denser secondary grids (role distribution, per-map tiles) — the DS's smaller step. */
.stat-card__value--sm {
    font-size: var(--text-display-sm);
}

.stat-card__sub {
    font-size: var(--text-body-xs);
    line-height: var(--leading-snug);
    color: var(--fg-muted);
    margin-top: 2px;
}

/* Tonal values — the DS StatCard's `tone` prop. Pass the class via StatCard's ValueClass so
   call sites never carry a colour of their own. */
.stat-card__value--accent  { color: var(--mud-palette-primary); }
.stat-card__value--success { color: var(--mud-palette-success); }
.stat-card__value--warning { color: var(--mud-palette-warning); }
.stat-card__value--error   { color: var(--mud-palette-error); }

.stat-card--center {
    text-align: center;
    align-items: center;
    justify-content: center;
}

.stat-card--clickable {
    cursor: pointer;
}

/* Was a no-op — it re-set the border to the value the base rule already has. */
.stat-card--clickable:hover {
    border-color: var(--border-accent);
}

.detail-hero-cell {
    padding: 4px !important;
    width: 40px;
}

.detail-hero-icon {
    width: 36px;
    height: 36px;
    border-radius: 6px;
    object-fit: cover;
    background: var(--app-hover-bg);
    border: 1px solid var(--app-border);
}

/* MatchDetail XP-momentum chart (signature element). */
.mdx-xp-chart { padding: 4px 2px; }
.mdx-xp-title { font-weight: 600; }
.mdx-xp-plot {
    position: relative; height: 240px; border-radius: 8px;
    border: 1px solid var(--app-border); background: var(--app-surface-inner); padding: 12px;
}
.mdx-xp-svg { width: 100%; height: 100%; overflow: visible; }
.mdx-xp-ymax {
    position: absolute; top: 8px; left: 8px; font-size: 10px;
    font-variant-numeric: tabular-nums; color: var(--app-text-muted);
}
.mdx-xp-legend { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; }
.mdx-xp-swatch { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.mdx-xp-swatch-home { background: var(--mud-palette-primary); }
.mdx-xp-swatch-away { background: var(--mud-palette-error); }
.mdx-xp-milestone { font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; }
.mdx-xp-axis-time { font-size: var(--text-body-xs); color: var(--app-text-muted); font-variant-numeric: tabular-nums; }
.mdx-xp-line { stroke-dasharray: 1; stroke-dashoffset: 1; animation: mdx-xp-draw 900ms ease-out forwards; }
@keyframes mdx-xp-draw { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
    .mdx-xp-line { animation: none; stroke-dashoffset: 0; }
}

/* MatchDetail XP-source breakdown chart (per-team stacked area). */
.mdx-xpb-chart { padding: 4px 2px; }
.mdx-xpb-title { font-weight: 600; }
.mdx-xpb-empty { color: var(--app-text-muted); padding: 4px 2px; }
.mdx-xpb-charts { display: flex; flex-wrap: wrap; gap: 16px; }
.mdx-xpb-team { flex: 1 1 260px; min-width: 220px; }
.mdx-xpb-team-title { font-weight: 600; margin-bottom: 2px; }
.mdx-xpb-plot {
    position: relative; height: 160px; border-radius: 8px;
    border: 1px solid var(--app-border); background: var(--app-surface-inner); padding: 8px;
}
.mdx-xpb-svg { width: 100%; height: 100%; overflow: visible; }
.mdx-xpb-legend { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; }
.mdx-xpb-swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.mdx-xpb-swatch-minion { background: var(--mud-palette-primary); }
.mdx-xpb-swatch-hero { background: var(--mud-palette-error); }
.mdx-xpb-swatch-structure { background: var(--mud-palette-warning); }
.mdx-xpb-swatch-creep { background: var(--mud-palette-success); }
.mdx-xpb-swatch-trickle { background: var(--app-text-muted); }
.mdx-xpb-axis-time { font-size: var(--text-body-xs); color: var(--app-text-muted); font-variant-numeric: tabular-nums; }
.mdx-xpb-layer { opacity: 0; animation: mdx-xpb-fade 700ms ease-out forwards; }
@keyframes mdx-xpb-fade { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
    .mdx-xpb-layer { animation: none; opacity: 1; }
}

/* MatchDetail XP-source donut charts (final cumulative totals, per team). */
.mdx-xpd-charts { display: flex; flex-wrap: wrap; gap: 24px; justify-content: center; }
.mdx-xpd-team { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.mdx-xpd-team-title { color: var(--app-text-muted); }
.mdx-xpd-plot { width: 160px; max-width: 100%; }
.mdx-xpd-svg { width: 100%; height: auto; }
.mdx-xpd-center { fill: var(--mud-palette-text-primary); font-size: 6px; font-weight: 700; }

/* MatchDetail advanced section. */
.mdx-advanced-divider { display: flex; align-items: center; gap: 12px; margin: 8px 0 12px; }
.mdx-advanced-divider::before, .mdx-advanced-divider::after {
    content: ""; flex: 1; height: 1px; background: var(--app-border);
}
.mdx-advanced-divider span { font-size: 11px; letter-spacing: 2px; color: var(--app-text-muted); font-weight: 700; }
.mdx-awards { display: flex; flex-wrap: wrap; gap: 12px; }
.mdx-award-badge {
    display: flex; align-items: center; gap: 8px; padding: 8px 12px;
    border-radius: 8px; border: 1px solid var(--app-border); background: var(--app-surface-inner);
}
.mdx-award-badge--home { border-color: var(--mud-palette-primary); }
.mdx-award-badge--away { border-color: var(--mud-palette-error); }
/* MVP always wins the border treatment, even for home/away award-holders. */
.mdx-award-badge--mvp { border-color: var(--app-gold); box-shadow: 0 0 0 1px var(--app-gold) inset; }
.mdx-award-icon { width: 48px; height: 48px; }
.mdx-award-hero { width: 28px; height: 28px; border-radius: 4px; }
.mdx-award-label { font-size: 12px; font-weight: 700; color: var(--mud-palette-text-primary); }
.mdx-award-badge--mvp .mdx-award-label { color: var(--app-gold); }
.mdx-award-player { font-size: 11px; color: var(--app-text-muted); }

/* MatchDetail teamfight timeline (signature element). */
.mdx-timeline-title { font-weight: 600; }
.mdx-timeline-fb-time { font-weight: 700; font-variant-numeric: tabular-nums; }
.mdx-timeline-plot {
    position: relative; height: 56px; border-radius: 8px;
    border: 1px solid var(--app-border); background: var(--app-surface-inner); padding: 8px 12px;
}
.mdx-timeline-svg { width: 100%; height: 100%; overflow: visible; }
.mdx-timeline-axis-time { font-size: var(--text-body-xs); color: var(--app-text-muted); font-variant-numeric: tabular-nums; }
.mdx-timeline-time { font-variant-numeric: tabular-nums; }
.mdx-timeline-table-wrap { overflow-x: auto; }

.mdx-fight-rect { cursor: pointer; transition: opacity .12s ease; }
.mdx-fight-rect:hover { opacity: .8; }
.mdx-fight-rect--sel { stroke: var(--mud-palette-text-primary); stroke-width: 0.6; }
.mdx-fight-card {
    background: var(--app-surface-card); border: 1px solid var(--app-border);
    border-radius: var(--app-radius-md, 8px); padding: 12px;
}
.mdx-fight-card-head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.mdx-fight-card-title { font-weight: var(--app-fw-semibold, 600); }
.mdx-fight-score { font-variant-numeric: tabular-nums; font-weight: var(--app-fw-semibold, 600); }
.mdx-kill-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.mdx-kill-time { font-variant-numeric: tabular-nums; color: var(--app-text-muted); min-width: 44px; font-size: var(--text-body-sm); }
.mdx-kill-side { display: inline-flex; align-items: center; gap: 6px; }
.mdx-kill-hero { width: 22px; height: 22px; border-radius: var(--app-radius-sm, 6px); }
.mdx-kill-arrow { color: var(--app-text-muted); }

/* MatchDetail objective timeline (mirrors the teamfight timeline). */
.mdx-obj-details { display: flex; flex-wrap: wrap; gap: 8px; }
.mdx-obj-detail {
    display: flex; flex-direction: column; background: var(--app-surface-inner);
    border: 1px solid var(--app-border); border-radius: var(--app-radius-sm, 6px); padding: 6px 10px;
}
.mdx-obj-detail-label { font-size: var(--text-body-xs); color: var(--app-text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.mdx-obj-detail-val { font-variant-numeric: tabular-nums; font-weight: var(--app-fw-semibold, 600); }

/* MatchDetail unified event timeline (replaces the separate teamfight/objective timelines) —
   Stats-of-the-Storm-style category lanes: one row per event category, markers positioned by
   time inside each lane's track. The lane labels double as the legend (no emoji glyph key). */
.mdx-lanes-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.mdx-lanes { min-width: 640px; }
.mdx-lane { display: flex; align-items: stretch; border-bottom: 1px solid var(--app-border); }
.mdx-lane-label {
    flex: 0 0 110px; font-size: var(--text-body-xs); text-transform: uppercase; letter-spacing: 0.5px;
    color: var(--app-text-muted); padding: 6px 8px; display: flex; align-items: center;
}
/* Track height is set inline per lane from the number of stacked sub-rows the layout needed. */
.mdx-lane-track { position: relative; flex: 1; min-height: 34px; }
/* Dashed vertical gridline every 5 minutes of game time, spanning the full lane track. */
.mdx-lane-gridline { position: absolute; top: 0; bottom: 0; border-left: 1px dashed var(--app-border); }
.mdx-ev-chip {
    position: absolute; transform: translateX(-50%); display: inline-flex; align-items: center; gap: 3px;
    padding: 2px 6px; border-radius: var(--app-radius-sm, 6px); background: var(--app-surface-inner);
    border: 1px solid var(--app-border); font-size: var(--text-body-xs); cursor: pointer; white-space: nowrap;
}
/* Teamfight chips span a time range (anchored at the fight's start), so they must not be re-centered. */
.mdx-ev-chip--span { transform: none; }
.mdx-ev-chip--home { border-color: var(--mud-palette-primary); }
.mdx-ev-chip--away { border-color: var(--mud-palette-error); }
.mdx-ev-chip--sel { outline: 2px solid var(--mud-palette-text-primary); }
.mdx-ev-chip:hover { background: var(--app-hover-bg); }
.mdx-ev-hero { width: 20px; height: 20px; border-radius: var(--app-radius-sm, 6px); }
.mdx-ev-obj { width: 20px; height: 24px; object-fit: contain; }
.mdx-et-line { padding: 4px 0; }
/* Members of a clustered ("N×") chip stack in the pinned card, separated by a hairline. */
.mdx-et-cluster-item + .mdx-et-cluster-item { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--app-border); }

.detail-hero-name {
    font-size: 11px;
    color: var(--app-text-muted);
    display: block;
    margin-top: 1px;
}

/* ── SeasonMultiSelect: searchable season picker (search + selected chips + scrollable list) ── */
.season-ms {
    width: 100%;
}
/* Three-column season grid: Regular / Events / Offseason. Collapses to fewer columns when narrow. */
.season-ms__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
}
.season-ms__col {
    border: 1px solid var(--app-border);
    border-radius: 8px;
    background: var(--app-surface-card);
    padding: 4px;
    max-height: 340px;
    overflow-y: auto;
}
.season-ms__col-head {
    position: sticky;
    top: 0;
    background: var(--app-surface-card);
    padding: 6px 8px 4px;
    font-size: var(--text-body-xs);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-weight: 600;
    color: var(--app-text-muted);
}
.season-ms__col-empty {
    padding: 8px;
    font-size: var(--text-body-sm);
    color: var(--app-text-muted);
}
/* Selected-chips bar: always visible when ≥1 selected; wraps and caps its height for many picks. */
.season-ms__selected {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    max-height: 96px;
    overflow-y: auto;
    padding: 6px 8px;
    border: 1px solid var(--app-border);
    border-radius: 8px;
    background: var(--app-surface-inner);
}
.season-ms__count {
    font-size: var(--text-body-xs);
    font-weight: 600;
    color: var(--app-text-muted);
    margin-right: 2px;
}
.season-ms__clear {
    margin-left: auto;
}
/* Scrollable list with a fixed max height — replaces the ~800px badge grid. */
.season-ms__list {
    max-height: 320px;
    overflow-y: auto;
    border: 1px solid var(--app-border);
    border-radius: 8px;
    background: var(--app-surface-card);
    padding: 4px;
}
.season-ms__row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 6px;
    cursor: pointer;
    user-select: none;
}
.season-ms__row:hover {
    background: var(--mud-palette-action-default-hover);
}
.season-ms__row:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}
.season-ms__row--selected {
    background: var(--mud-palette-primary-hover);
}
.season-ms__label {
    font-size: var(--text-body-sm);
    color: var(--mud-palette-text-primary);
}
.season-ms__empty {
    padding: 16px 8px;
    text-align: center;
    font-size: var(--text-body-sm);
    color: var(--app-text-muted);
}

/* PlayerProfile substitutes mini-cards. */
.sub-mini-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 8px;
}
.sub-mini-card {
    border: 1px solid var(--app-border);
    background: var(--app-surface-inner);
    border-radius: 8px;
    padding: 8px 10px;
}
.sub-mini-card__meta {
    font-size: var(--text-body-xs);
    color: var(--app-text-muted);
}

/* PlayerProfile season-limit rows. */
.limit-row { margin-bottom: 10px; font-size: var(--text-body-sm); color: var(--mud-palette-text-primary); }
.limit-row__count { font-variant-numeric: tabular-nums; color: var(--app-text-muted); }

/* HeroicTickets — channel names read as Discord identifiers, so give them the monospace treatment.
   Shared by the ticket list and the detail page (scoped CSS cannot span both). */
.ticket-channel {
    font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;
    font-size: 0.85em;
    color: var(--app-text-muted);
}


/* ═══════════════════════════════════════════════════════════════════════════════════════
   Settings page (DS SettingsControls — components/forms/SettingsControls.jsx)

   These live here and not in Settings.razor.css on purpose. Blazor's CSS isolation stamps
   its b-<hash> attribute only onto markup authored in the .razor file; MudBlazor components
   render their own DOM and never receive it. Every rule below targets a MudBlazor element
   (MudExpansionPanel, MudText, MudChip, MudTextField, MudPaper), so as scoped CSS they
   matched nothing at all — the panel borders, the inline-input width and the save bar had
   been silently dead since they were moved out of inline styles. ::deep is no way out
   either: the page renders MudExpansionPanels at its root, so there is no own element for
   the scope attribute to sit on.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* ── DS SettingsSection (components/forms/SettingsControls.jsx) ────────────────────────
   The DS built this group from screenshots of this very page, so the structure already
   matched; what follows is the treatment it prescribes. */

.settings-panel {
    border: 1px solid var(--app-border);
}

/* Section title in the display face. Deliberately NOT uppercased: the DS's own
   SettingsSection sets font-family only, and these titles run long
   ("Draft / Match-Format / Map-Pool") — uppercase Oswald would dominate the panel. */
.settings-panel__title {
    font-family: var(--font-display);
    font-weight: var(--app-fw-semibold);
    letter-spacing: var(--tracking-display);
}

/* Status badges next to the title. The DS draws these as flat blue pills; the colour here
   still carries state (green = active, blue = tournament), which the DS's monochrome
   version would throw away — so only its shape and type scale are adopted. */
/* .mud-chip is repeated in the selector so the DS's 11px wins over MudChip's own 12px —
   without it the font-size is the one rule of these that silently loses. */
.settings-panel__badge.mud-chip {
    font-family: var(--font-display);
    font-size: var(--text-body-xs);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
}

/* ── DS FormField hint ────────────────────────────────────────────────────────────────
   The slash command that changes a setting from Discord. It used to hide inside a tooltip
   on an info icon, which meant it was invisible unless you knew to hover. The DS FormField
   puts the hint on the page, under the control. Mono, because it is a command to type. */
.settings-hint {
    display: block;
    margin-top: 4px;
    font-family: var(--font-mono);
    font-size: var(--text-body-xs);
    color: var(--fg-muted);
}

/* ── DS Chip ──────────────────────────────────────────────────────────────────────────
   Removable tag for list values (case categories, map pool). The DS gives the chip itself
   a neutral surface and reserves the loss colour for the remove control alone — the old
   fully-red/blue outlined chips read as a status, which a category name is not. */
.settings-chip.mud-chip {
    background: var(--app-surface-inner);
    border: 1px solid var(--app-border);
    color: var(--mud-palette-text-primary);
    border-radius: var(--app-radius-pill);
    font-size: var(--text-body-sm);
}

.settings-chip.mud-chip .mud-chip-close-button {
    color: var(--mud-palette-error);
}

/* Shared width for the small inline "add" text fields (new category / new map). */
.settings-inline-input {
    max-width: 280px;
}

/* Floating "unsaved changes" bar. Translucent raised surface + primary-tinted border, both
   built from color-mix() over theme variables so they flip automatically with Light/Dark
   (STYLE.md §2.4 — overlay effect, not a flat hardcoded color). */
.settings-savebar {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1300;
    border-radius: var(--app-radius-md, 8px);
    min-width: 480px;
    max-width: 700px;
    /* Opaque, not translucent-with-blur: the DS records "Transparency/blur: none observed"
       and asks for flat surfaces. The bar floats over content, so it has to be readable —
       a solid surface does that without the blur the DS rules out (STYLE.md §4.5). */
    background: var(--app-surface-raised);
    border: 1px solid color-mix(in srgb, var(--mud-palette-primary) 30%, transparent);
    box-shadow: var(--app-shadow-hover);
}

