html, body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, Roboto, 'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Reserve the scrollbar gutter so pages that toggle a vertical scrollbar
   (e.g. opening a detail view) don't shift horizontally. */
html {
  scrollbar-gutter: stable;
}

/* MudBlazor's dialog scroll-lock pads the body by the scrollbar width to make up for the
   scrollbar it hides. The reserved gutter above means the scrollbar never goes away, so that
   padding is a second compensation and visibly jerks the page sideways on every dialog open.
   Its overflow:hidden still does the real work (body's overflow propagates to the viewport). */
body.scroll-locked {
  padding-right: 0;
}

h1:focus {
  outline: none;
}

/* ── Elevation shadow color ──────────────────────────────────────────────
   Pure-black shadows vanish on dark surfaces, so cards/popovers lose their
   lift in dark mode. Drive every elevation off these vars; the body.uma-dark
   class (set by MainLayout) swaps in a much deeper shadow that actually reads
   on a dark background. Light values keep the original soft look. */
:root {
  --uma-shadow-soft: rgba(0, 0, 0, 0.12);
  --uma-shadow-strong: rgba(0, 0, 0, 0.22);
}

body.uma-dark {
  --uma-shadow-soft: rgba(0, 0, 0, 0.5);
  --uma-shadow-strong: rgba(0, 0, 0, 0.66);
}

/* ── Global MudBlazor overrides ─────────────────────────────────────────── */

/* Defined border on all papers/cards (MudBlazor default is borderless) */
.mud-paper, .mud-card {
  border: 1px solid var(--mud-palette-lines-default);
}

/* Dialogs sit on the theme background rather than MudBlazor's surface colour, so a modal reads as
   the page continuing rather than as a lighter sheet floating over it. The panels inside keep their
   own surface, which is what gives them separation from this.
   Written as a descendant selector on purpose: MudBlazor.min.css is linked after app.css in
   _Host.cshtml, so a bare .mud-dialog ties on specificity and loses to its own
   background-color: var(--mud-palette-surface). */
.mud-dialog-container > .mud-dialog {
  background-color: var(--mud-palette-background);
}

/* Race-search autocomplete dropdown: clip the popover so only the inner list scrolls
   (otherwise the popover and the list each show a scrollbar - a double scrollbar). */
.planner-search-popover {
  overflow: hidden;
}

.planner-search-popover .mud-list {
  overflow-y: auto;
}

/* Planner day-race popover: match the sidebar/main tint (.uma-sidebar/.uma-main) instead of the
   lighter default popover surface. Keep this in sync with MainLayout.razor.css. */
.planner-day-popover {
  background-color: color-mix(in srgb, var(--mud-palette-primary) 5%, var(--mud-palette-surface)) !important;
}

/* Aptitude uma search: lay the results out as a 3-column grid of portrait tiles instead of a
   vertical list. The popover is widened past the (narrow) search box so three tiles fit.

   MudAutocomplete's MaxHeight lands as an inline max-height + overflow-y:auto on the popover, and
   MudBlazor's own `.mud-list { max-height: inherit; overflow-y: auto }` makes the list inside scroll
   too - two nested scrollbars side by side. `!important` beats the inline rule so only the list
   scrolls; dropping the list's padding keeps its last row inside the popover's clipped box. */
.apt-uma-popover {
  overflow: hidden !important;
  /* 30rem on desktop, but never wider than the viewport or it runs off-screen on a phone. */
  min-width: min(30rem, 92vw);
  max-width: 92vw;
}

.apt-uma-popover .mud-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
  max-height: inherit;
  overflow-y: auto;
  padding-top: 0;
  padding-bottom: 0;
}

.apt-uma-popover .mud-list-item {
  display: block;
  padding: 6px 4px;
}

.apt-uma-tile {
  width: 100%;
}

.apt-uma-icon {
  object-fit: cover;
  object-position: top;
  border-radius: 6px;
}

.apt-uma-name {
  width: 100%;
  line-height: 1.15;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* On a phone MudBlazor anchors the popover's left edge to the (nearly full-width) search box,
   so a 92vw popover runs off the right and clips the third tile column. The v9 popover is
   position:fixed with a JS-set inline left/top, so pin its horizontal placement to the viewport
   here (our !important beats MudBlazor's non-important inline left); top stays untouched, so it
   still opens anchored under the search box. */
@media (max-width: 900px) {
  .apt-uma-popover {
    left: 2vw !important;
    width: 96vw !important;
    min-width: 0 !important;
    max-width: 96vw !important;
  }

  .apt-uma-popover .mud-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Support-card debug picker (Training Debug): same 3-column grid-of-tiles popover as the aptitude uma
   search, sized for a card icon instead of a portrait. Same single-scrollbar handling - see above. */
.support-ac-popover {
  overflow: hidden !important;
  min-width: min(30rem, 92vw);
  max-width: 92vw;
}

.support-ac-popover .mud-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
  max-height: inherit;
  overflow-y: auto;
  padding-top: 0;
  padding-bottom: 0;
}

.support-ac-popover .mud-list-item {
  display: block;
  padding: 6px 4px;
}

.support-ac-tile {
  width: 100%;
}

.support-ac-icon {
  object-fit: cover;
  object-position: top;
  border-radius: 6px;
}

.support-ac-name {
  width: 100%;
  line-height: 1.15;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

@media (max-width: 900px) {
  .support-ac-popover {
    left: 2vw !important;
    width: 96vw !important;
    min-width: 0 !important;
    max-width: 96vw !important;
  }

  .support-ac-popover .mud-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Accent border utilities - opt-in colored edge on any element.
   Color via --uma-accent inline var (defaults to primary). */
.accent-top {
  border-top: 3px solid var(--uma-accent, var(--mud-palette-primary)) !important;
}

.accent-right {
  border-right: 4px solid var(--uma-accent, var(--mud-palette-primary)) !important;
}

.accent-bottom {
  border-bottom: 4px solid var(--uma-accent, var(--mud-palette-primary)) !important;
}

.accent-left {
  border-left: 4px solid var(--uma-accent, var(--mud-palette-primary)) !important;
}

/* Auto-fill tile grid for the detail-page "other versions" / support-card panels.
   Fixed-size cells that pack tightly and wrap, so short lists don't leave big centered
   gaps and long lists stay dense. Shared by CharacterOtherVersionsPanel,
   CharacterSupportsPanel and SupportOtherCardsPanel. */
.uma-link-tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 8px;
}

/* RelatedCardsPanel: match the outline other detail cards get from MudPaper Outlined.
   Global (not scoped) because Blazor won't stamp the scope attr onto MudExpansionPanels' DOM. */
.related-outlined {
  border: 1px solid var(--mud-palette-lines-default);
  border-radius: var(--mud-default-borderradius);
}

/* Section title color */
.mud-paper .mud-typography-h6 {
  color: var(--mud-palette-primary);
}

/* Hover lift on clickable cards */
.mud-card.cursor-pointer {
  transition: transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease;
}

/* Only on real-pointer devices: on touchscreens :hover sticks after a tap, so skip it. */
@media (hover: hover) {
  .mud-card.cursor-pointer:hover {
    transform: translateY(-2px);
    border-color: var(--mud-palette-primary);
    box-shadow: 0 6px 20px var(--uma-shadow-soft);
  }
}

/* Support card tiles (browser grid + deck picker) - see SupportCardTile.razor. These live
   here because scoped CSS can't reach a MudCard's / MudText's root element. */
.support-tile {
  border-radius: 10px;
  overflow: hidden;
}

/* Browse / picker tiles: the card art already has its own framed edge, so drop the outline and
   keep only a subtle bottom divider under the label, like the app's other cards. */
.support-tile.cursor-pointer {
  border: none;
  border-bottom: 1px solid var(--mud-palette-lines-default);
}

/* Hover is just the lift + elevation (from .mud-card.cursor-pointer:hover); pin the bottom
   divider so the generic border-color:primary doesn't recolor it. */
@media (hover: hover) {
  .support-tile.cursor-pointer:hover {
    border-bottom-color: var(--mud-palette-lines-default);
  }
}

/* Deck-picker variant: no card border, just a pointer cursor over the art. */
.support-tile-plain {
  border: none;
  cursor: pointer;
}

/* Unavailable picker card: inert (the art greys via SupportCardArt's Dimmed flag). */
.support-tile-disabled {
  cursor: default;
  pointer-events: none;
}

/* Keep tiles a uniform height: a long title or name truncates instead of wrapping.
   These target MudText, a child component, so the rule must live here (global) rather than in
   a tile's scoped .razor.css - Blazor does not stamp the scope attribute onto child-component
   markup, so a scoped selector would never match and long names would overflow the grid track
   (which on mobile widens the page and breaks the fixed bottom nav's positioning). */
.support-tile-title,
.support-tile-name,
.char-tile-title,
.char-tile-name {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* AccountMenu's activator, restyled from a Material button into something that sits flush with the
   sidebar's nav links above it. Global for the same reason as the tile titles: every element here is
   rendered by a child component (MudMenu's activator wrapper, MudButton, MudText), so a scoped
   selector would never match. */
.uma-account,
.uma-account .mud-menu-activator {
  width: 100%;
}

.uma-account-row {
  justify-content: flex-start;
  min-height: 42px;
  padding: 0 12px;
  border-radius: 9px;
  text-transform: none;
  font-weight: 500;
  color: var(--mud-palette-text-primary);
}

.uma-account-row .mud-button-label {
  width: 100%;
}

/* Long usernames truncate rather than widen the sidebar. */
.uma-account-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-align: left;
}

/* Belt-and-braces for phones: never let a stray over-wide child scroll the page sideways. A
   horizontally overflowing page widens the layout viewport, which detaches position:fixed
   elements (the bottom nav bar) so they drift on scroll and become hard to tap. */
@media (max-width: 900px) {
  html,
  body {
    overflow-x: hidden;
  }
}

/* Status band across the bottom of the art (e.g. "In deck" / "Uma in deck"). */
.support-tile-status {
  position: absolute;
  inset: auto 0 0 0;
  padding: 3px 0;
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  color: #fff;
}

/* Active nav link weight (MudBlazor default omits this) */
.mud-nav-link.active:not(.mud-nav-link-disabled) {
  font-weight: 600;
}

/* Grade badge base - color set via inline style per component */
.uma-planner-grade-badge {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  padding: 1px 6px;
  border-radius: 4px;
  flex-shrink: 0;
  color: #fff;
  background: #757575;
}

/* ── Blazor runtime hooks (keep global - rendered outside any component) ── */

#blazor-error-ui {
  background: lightyellow;
  bottom: 0;
  box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem 1.25rem;
  position: fixed;
  width: 100%;
  z-index: 1000;
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

/* Circuit-reconnect overlay. Hidden until Blazor adds components-reconnect-{show,failed,
   rejected} to #components-reconnect-modal; each state reveals its matching message. */
#components-reconnect-modal {
  display: none;
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 3000;
  align-items: center;
  justify-content: center;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(2px);
}

.uma-reconnect-card {
  background: var(--mud-palette-surface, #fff);
  color: var(--mud-palette-text-primary, #1a1a1a);
  border-radius: 12px;
  padding: 28px 32px;
  max-width: 360px;
  text-align: center;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
}

.uma-reconnect-spinner {
  width: 36px;
  height: 36px;
  margin: 0 auto 16px;
  border: 3px solid var(--mud-palette-primary, #1565c0);
  border-right-color: transparent;
  border-radius: 50%;
  animation: uma-reconnect-spin 0.8s linear infinite;
}

@keyframes uma-reconnect-spin {
  to {
    transform: rotate(360deg);
  }
}

.uma-reconnect-text {
  margin: 0;
  font-size: 0.95rem;
  color: var(--mud-palette-text-secondary, #555);
}

.uma-reconnect-text a {
  color: var(--mud-palette-primary, #1565c0);
  font-weight: 600;
}

/* Show only the message matching the current reconnect state. */
.uma-reconnect-when-show,
.uma-reconnect-when-failed,
.uma-reconnect-when-rejected {
  display: none;
}

.components-reconnect-show .uma-reconnect-when-show {
  display: block;
}

.components-reconnect-failed .uma-reconnect-when-failed,
.components-reconnect-rejected .uma-reconnect-when-rejected {
  display: block;
}

/* The spinner only makes sense while actively retrying (show); hide it once terminal. */
.components-reconnect-failed .uma-reconnect-spinner,
.components-reconnect-rejected .uma-reconnect-spinner {
  display: none;
}

.blazor-error-boundary {
  background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjY2LjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
  padding: 1rem 1rem 1rem 3.7rem;
  color: white;
}

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

/* ── Umamusume-themed boot loader: runner circling a random race track ───── */

/* Brand wordmark above the track */
.uma-brand {
  text-align: center;
  margin: 9vh 0 0.75rem 0;
  font-weight: 800;
  letter-spacing: 0.05em;
  font-size: 2rem;
  color: #2F62D4;
}

.uma-loader {
  position: relative;
  width: 448px;
  height: 244px;
  max-width: 92vw;
  margin: 0 auto 0.5rem auto;
}

.uma-loader-track {
  position: absolute;
  inset: 0;
  overflow: visible;
}

/* Infield (PeakJoy background-gray) */
.uma-track-grass {
  fill: #DCE6F6;
}

/* Running lane - soft blue-gray dirt with a primary-blue outer rail */
.uma-track-base {
  fill: none;
  stroke: #C6D5EF;
  stroke-width: 14;
  stroke-linejoin: round;
}

/* Outer rail: same stadium path, thin primary-blue stroke on top */
.uma-track-rail {
  fill: none;
  stroke: #2F62D4;
  stroke-width: 1.5;
  stroke-linejoin: round;
  opacity: 0.55;
}

/* ── Track markers ──────────────────────────────────────────────────────── */

.uma-mk-text {
  fill: #161E2C;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.03em;
}

/* Start/finish: dark line + white dashes = checkered band */
.uma-mk-finish-bg {
  stroke: #161E2C;
  stroke-width: 8;
}

.uma-mk-finish {
  stroke: #FFFFFF;
  stroke-width: 8;
  stroke-dasharray: 4 4;
}

/* Landmark arcs follow the curved lane, so they must not fill. */
.uma-mk-uphill,
.uma-mk-corner,
.uma-mk-spurt {
  fill: none;
  stroke-width: 8;
  stroke-linecap: butt;
  opacity: 0.9;
}

/* Slope / uphill - warm orange */
.uma-mk-uphill {
  stroke: #E0843C;
}

/* Final corner - gold (secondary) */
.uma-mk-corner {
  stroke: #D99B1F;
}

/* Last spurt - tertiary red */
.uma-mk-spurt {
  stroke: #D64550;
}

/* Start gate line - green (separate from the finish line) */
.uma-mk-startline {
  stroke: #2E9D5B;
  stroke-width: 4;
}

.uma-mk-start-text {
  fill: #2E9D5B;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.03em;
}

/* Runner laps the oval; offset-distance = real Blazor load %, so it advances as
   assets download. offset-path matches the lane (1 SVG unit = 1px). */
.uma-loader-runner {
  position: absolute;
  top: 0;
  left: 0;
  offset-path: path("M230,210 L340,210 A80,80 0 0 0 340,50 L120,50 A80,80 0 0 0 120,210 Z");
  offset-distance: var(--blazor-load-percentage, 0%);
  offset-rotate: 0deg;
  offset-anchor: 50% 50%;
  transition: offset-distance 0.15s linear;
  animation: uma-gallop 0.45s ease-in-out infinite;
  filter: drop-shadow(0 2px 2px rgba(22, 30, 44, 0.3));
}

.uma-loader-runner img {
  display: block;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 3px solid #2F62D4;
  background: #FFFFFF;
  object-fit: cover;
}

/* Race name + distance, stacked in the centre of the oval */
.uma-loader-label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 90px;
  pointer-events: none;
}

.uma-loader-label .uma-loader-race {
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #2F62D4;
  font-size: 1.25rem;
  line-height: 1.2;
}

.uma-loader-label .uma-loader-dist {
  margin-top: 0.15rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #3D4759;
  font-size: 0.8rem;
}

.uma-loader-label .uma-loader-route {
  margin-top: 0.1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #2F62D4;
  font-size: 0.72rem;
  opacity: 0.85;
}

/* Subtle gallop bob */
@keyframes uma-gallop {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-3px);
  }
}

.loading-progress-text {
  text-align: center;
  font-weight: bold;
  margin-top: 0.25rem;
  color: #555;
}

code {
  color: #c02d76;
}

/* ── Deck Builder full-height panels ─────────────────────────────────────────
   These target MudPaper / MudTabs *component roots*, which Blazor scoped CSS
   cannot reach (the scope attribute isn't applied to child-component roots).
   The picker fills its column and scrolls its inner results (.card-search-results);
   the deck side (slots + Stats/Skills) is natural height and the *whole left column*
   scrolls as one (see .deck-col-left), so a short viewport reaches the skills instead
   of clipping them. */
.deck-title {
  flex: 0 0 auto;
  margin-bottom: 12px;
}

.deck-col-left > .mud-paper:first-child {
  flex: 0 0 auto;
}

.deck-aux {
  /* grow to fill spare height (so the panel reaches the column bottom) but never shrink
     below its content - when the viewport is too short the left column scrolls instead. */
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* Stats / Skills switch: two equal-width MudButtons acting as a tab control. */
.deck-aux-switch {
  flex: 0 0 auto;
  margin-bottom: 12px;
}

.deck-aux-body {
  flex: 0 0 auto;
}

.deck-pick-panel {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Stacked layout (narrow screens / zoom): drop every internal scroll region and let the
   deck builder flow naturally down the page. Critically, nothing here may shrink below
   its content - every panel is flex: 0 0 auto with min-height: auto. A shrinkable,
   min-height:0 flex item (the columns, .deck-aux-body, and the picker's .card-search all
   were) collapses below its content, and with overflow visible it then spills and paints
   over the next panel - that was the picker overlapping the skills list. */
@media (max-width: 900px) {
  .deck-aux,
  .deck-aux-body,
  .deck-pick-panel,
  .deck-pick-panel .card-search,
  .deck-pick-panel .card-search-results {
    flex: 0 0 auto;
    min-height: auto;
    overflow: visible;
  }
}

/* ── Compare page panels ─────────────────────────────────────────────────────
   These style MudPaper / MudStack component roots that scoped CSS can't reach. The page flows with
   the main scroll; the simulator card (left) is content-sized and its matrix scrolls horizontally on
   its own, while the picker card (right) fills the sticky sidebar box and scrolls its inner results. */
.compare-title {
  margin-bottom: 12px;
}

/* Centre the empty-state hint in the left column until cards are added. */
.compare-view-empty {
  max-width: 28rem;
  margin: 0 auto;
  padding: 24px 0;
}

/* The picker fills its column (see .compare-col-right) and scrolls its own results. It fills the
   column height via flex so the inner .card-search / .card-search-results (flex:1 1 0 min-height:0)
   get a resolved height instead of collapsing to a sliver. */
.compare-pick-panel {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Mobile picker dialog: on phones the picker moves out of the right column into a full-screen dialog
   (matching the Options dialog). This body wrapper fills the dialog content and is a flex column so the
   reused .compare-pick-panel keeps filling the height and scrolling its own results, exactly as it does
   in the desktop sidebar (its search box stays put while the grid scrolls under it). */
.compare-picker-dialog-body {
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ── Roster builder layout ───────────────────────────────────────────────────
   Centre each row and keep it its natural size (these target component root elements like
   .roster-current that scoped CSS can't reach). The card art is capped to a slice of the viewport
   in the component's own CSS so the whole tool fits a phone screen without the controls below it
   being pushed off. */
.roster-ingest > * {
  width: 100%;
  max-width: 52rem;
  margin-left: auto;
  margin-right: auto;
  flex: 0 0 auto;
}

/* ── Browse lists: pinned header + scrolling results ─────────────────────────
   Opt-in (the page's root .browse-page makes .uma-main a non-scrolling flex column,
   see MainLayout.razor.css). The header (title + search + sort + filters + count)
   stays put; only .browse-results scrolls. Shared by the Characters / Supports /
   Skills pages, so it lives here rather than in scoped CSS. */
.browse-page {
  height: 100%;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.browse-head {
  flex: 0 0 auto;
}

.browse-results {
  padding-top: 4px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* On narrow screens the shell already lets the page scroll; restore natural flow. */
@media (max-width: 900px) {
  .browse-page {
    height: auto;
    flex: 0 1 auto;
    overflow: visible;
  }

  .browse-results {
    overflow: visible;
  }
}

.mud-input-control.mud-input-control-margin-dense.mud-input-outlined-with-label {
  margin-top: 0 !important;
  margin-bottom: 0 !important;
}

/* ── Mobile touch polish ─────────────────────────────────────────────────────
   Removes the 300ms tap delay on interactive surfaces and gives standard buttons a
   comfortable touch height on phones. Icon buttons are intentionally left alone: some
   live in dense layouts (e.g. the planner cell's quick-delete) where a forced 44px would
   cover their content - those need per-component handling, not a blanket rule. */
.mud-button-root,
.mud-icon-button,
.mud-nav-link,
.mud-chip,
.mud-menu-item,
.mud-card.cursor-pointer,
.support-tile.cursor-pointer {
  touch-action: manipulation;
}

@media (max-width: 900px) {
  .mud-button-root.mud-button {
    min-height: 44px;
  }
}


/* ── CM planner (/cm). GLOBAL ONLY BY NECESSITY ──────────────────────────────
   Everything here is applied through a `Class=` on a MudBlazor component, so Blazor
   never stamps the owning component's scope attribute onto the rendered DOM and a
   scoped .razor.css rule would silently do nothing. Per-component layout that sits on
   plain HTML lives in each component's scoped .razor.css instead. ── */

/* On MudSelect (CmMeetHeader). Width lives inline on the component so it hits the input
   root reliably; this is only a safety cap on very narrow viewports. */
.cm-meet-select {
  max-width: 100%;
}

/* On MudPaper / MudIcon. The section card shell, shared by the summary and track panels. */
.cm-card {
  height: 100%;
}

.cm-card-icon {
  vertical-align: -4px;
  margin-right: 4px;
  color: var(--mud-palette-text-secondary);
}

/* On MudText, across the summary + greens/stats/decks modals. */
.cm-muted {
  color: var(--mud-palette-text-secondary);
}

/* On MudTextField / MudSelect / MudNumericField, across the detail, deck-row, stat-row,
   edit-bar and schedule-instant editors. */
.cm-edit-grow {
  flex: 1 1 220px;
  min-width: 180px;
}

.cm-edit-narrow {
  flex: 0 1 150px;
  min-width: 120px;
}

/* On MudNumericField (CmStatRow): centred value with the stat's identity colour underlined.
   The inner selectors reach MudBlazor's own input DOM. */
.cm-stat-edit-field {
  width: 100%;
}

.cm-stat-edit-field .mud-input-slot {
  text-align: center;
  font-weight: 600;
}

.cm-stat-edit-field .mud-input.mud-input-outlined::after {
  content: "";
}

.cm-stat-edit-field .mud-input-outlined-border {
  border-bottom: 2px solid var(--cm-stat-color);
}

/* On MudNumericField (CmStatSkillRow): the "how many of this skill" box. */
.cm-stat-need-count-field {
  flex: 0 0 90px;
}

/* On MudTextField (CmGridRowLabel). */
.cm-gridboard-label-field {
  margin-top: 0;
}

/* On MudImage inside CmDeckTile, so it cannot be scoped: Blazor stamps its scope attribute onto
   this component's own elements, never onto a child component's rendered DOM. Kept under
   .cm-deck-cards on purpose: filling the column only makes sense inside that six-column grid, and
   an unqualified rule stretched the same image to full width in the editor modal. */
.cm-deck-cards .cm-deck-card {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  border-radius: 5px;
}

/* The editor's thumbs are a compact reminder of what was imported, not the deck's presentation. */
.cm-deck-card-mini {
  width: 36px;
  height: 48px;
  border-radius: 4px;
}

/* On MudDropZone. The drop targets of both drag boards. .cm-drop-can is the containers'
   CanDropClass (see CmDragGridBoard, CmDragTierBoard): with ApplyDropClassesOnDragStarted every
   zone that can take the dragged uma lights up as soon as the drag starts. MudBlazor has no
   per-zone hover class, so the stronger "you are over this one" state is plain :hover, which the
   zone still receives mid-drag because mud-drop-zone-drag-block kills pointer events on its
   children. */
.cm-tier-drop {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-content: flex-start;
  min-height: 92px;
  padding: 6px;
  margin-top: 6px;
  border: 2px dashed var(--mud-palette-lines-default);
  border-radius: 6px;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.cm-tier-drop:empty::after {
  content: "drop umas here";
  align-self: center;
  padding: 0 6px;
  font-size: 0.75rem;
  color: var(--mud-palette-text-disabled);
}

.cm-tier-drop.cm-drop-can {
  border-color: color-mix(in srgb, var(--mud-palette-primary) 55%, transparent);
  background: color-mix(in srgb, var(--mud-palette-primary) 6%, transparent);
}

.cm-tier-drop.cm-drop-can:hover {
  border-color: var(--mud-palette-primary);
  background: color-mix(in srgb, var(--mud-palette-primary) 16%, transparent);
}

/* Cells look like the view's grid cells (solid rounded border), turning dashed on drag-over. */
.cm-gridboard-drop {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  gap: 6px;
  align-content: center;
  justify-content: center;
  align-items: center;
  min-height: 92px;
  height: 100%;
  padding: 6px;
  border: 1px solid var(--mud-palette-lines-default);
  border-radius: 6px;
  transition: border-color 120ms ease, background-color 120ms ease;
}

/* An empty cell says so, rather than reading as a rendering gap. */
.cm-gridboard-drop:empty::after {
  content: "+";
  font-size: 1.25rem;
  line-height: 1;
  color: var(--mud-palette-text-disabled);
}

.cm-gridboard-drop.cm-drop-can {
  border: 2px dashed color-mix(in srgb, var(--mud-palette-primary) 55%, transparent);
  background: color-mix(in srgb, var(--mud-palette-primary) 6%, transparent);
}

.cm-gridboard-drop.cm-drop-can:hover {
  border: 2px dashed var(--mud-palette-primary);
  background: color-mix(in srgb, var(--mud-palette-primary) 16%, transparent);
}

/* The uma pool's drop zone (CmUmaPool): an auto-filling icon grid so it collapses on phones. It is
   also where a placed uma goes to be removed, so during a drag it reads as the discard target -
   error-coloured, not primary, to say "this takes it off the board". */
.cm-pool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
  gap: 6px;
  align-content: start;
  min-height: 60px;
  padding: 6px;
  border: 2px dashed var(--mud-palette-lines-default);
  border-radius: 6px;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.cm-pool-grid.cm-drop-can {
  border-color: color-mix(in srgb, var(--mud-palette-error) 55%, transparent);
  background: color-mix(in srgb, var(--mud-palette-error) 6%, transparent);
}

.cm-pool-grid.cm-drop-can:hover {
  border-color: var(--mud-palette-error);
  background: color-mix(in srgb, var(--mud-palette-error) 14%, transparent);
}
