*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  background: #1a1a2e;
  color: #e0e0e0;
  font-family: 'Segoe UI', system-ui, sans-serif;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  padding: 1rem;
}

.container {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.main-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: 1rem;
  width: 100%;
}

.tabs-panel {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  background: #16213e;
  border: 1px solid #2a2a4a;
  border-radius: 12px;
  padding: 0.8rem;
  max-height: var(--tabs-max-h, none);
}

.tabs-header {
  font-size: 0.85rem;
  font-weight: 600;
  color: #c0c0d0;
  padding-bottom: 0.3rem;
  border-bottom: 1px solid #2a2a4a;
}

.replay-tabs {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: none;
}
.replay-tabs::-webkit-scrollbar { display: none; }

.replay-tab {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: #0f3460;
  border: 1px solid #2a2a5a;
  border-radius: 6px;
  padding: 0.4rem 0.5rem;
  font-size: 0.8rem;
  color: #e0e0e0;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
  user-select: none;
}

.replay-tab:hover {
  background: #173a6b;
}

.replay-tab:focus-visible {
  outline: 2px solid #e879a0;
  outline-offset: -2px;
}

.replay-tab.active {
  background: #2a2a5a;
  border-color: #e879a0;
}

.replay-tab-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.replay-tab-remove {
  background: transparent;
  color: #a0a0b0;
  border: none;
  border-radius: 3px;
  width: 1.4rem;
  height: 1.4rem;
  flex-shrink: 0;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.replay-tab-remove:hover {
  background: #3a3a6a;
  color: #ff6b6b;
}

.canvas-column {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 1280px;
}

.sidebar {
  grid-column: 3;
  justify-self: start;
  width: 280px;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}

.left-panel {
  grid-column: 1;
  justify-self: end;
  width: 280px;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
  min-height: 0;
}

.input-panel-wrap {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.input-panel {
  background: #16213e;
  border: 1px solid #2a2a4a;
  border-radius: 12px;
  padding: 1.2rem;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.tab-content {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.tab-content.hidden {
  visibility: hidden;
}

.panel-tabs {
  display: flex;
  justify-content: center;
  margin-top: -1px;
}

.panel-tab {
  background: #0f1c35;
  border: 1px solid #2a2a4a;
  border-radius: 0;
  color: #a0a0b0;
  padding: 0.4rem 1.3rem;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
  position: relative;
  z-index: 1;
}

.panel-tab + .panel-tab {
  margin-left: -1px;
}

.panel-tab:hover:not(.active) {
  background: #16213e;
  color: #c0c0d0;
}

.panel-tab.active {
  background: #2a2a5a;
  color: #e879a0;
  border-color: #e879a0;
  cursor: default;
  z-index: 2;
}

.auth-row {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.auth-state {
  font-size: 0.85rem;
  color: #c0c0d0;
  word-break: break-word;
}

.auth-btn {
  background: #e879a0;
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 0.45rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease;
}

.auth-btn:hover {
  background: #d4609a;
}

.auth-btn.hidden {
  display: none;
}

.input-panel input[type="text"] {
  background: #0f3460;
  border: 1px solid #2a2a5a;
  border-radius: 6px;
  color: #e0e0e0;
  padding: 0.5rem 0.8rem;
  font-size: 0.85rem;
  width: 100%;
  font-family: inherit;
}

.input-panel input[type="text"]::placeholder {
  color: #707080;
}

/* Mobile Safari/Chrome auto-zoom the viewport when focusing an input whose
   font-size is below 16px, which leaves the page zoomed-in after the keyboard
   closes. Bump to 16px on touch devices to suppress that. Desktop (hover-
   capable pointer) keeps the original 0.85rem size. */
@media (hover: none) and (pointer: coarse) {
  .input-panel input[type="text"] {
    font-size: 16px;
  }
  /* Match-view dual-canvas layout isn't mobile-optimized yet — grey out the
     tab on touch devices so desktop users can still test the feature. */
  .panel-tab[data-target="match"] {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
  }
  .panel-tab[data-target="match"]::after {
    content: "desktop only";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 3px;
    font-size: 0.6rem;
    font-weight: 500;
    font-style: italic;
    letter-spacing: 0.02em;
    color: #8a8aa0;
    white-space: nowrap;
    pointer-events: none;
  }
}

#fetch-btn,
#match-fetch-btn {
  background: #e879a0;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 0.6rem 1.5rem;
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  align-self: center;
  transition: background 0.15s ease;
  letter-spacing: 0.03em;
}

#fetch-btn:hover:not(:disabled),
#match-fetch-btn:hover:not(:disabled) {
  background: #d4609a;
}

#fetch-btn:disabled,
#match-fetch-btn:disabled {
  background: #7a4060;
  cursor: not-allowed;
  opacity: 0.6;
}

.file-row {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.file-row label {
  font-size: 0.9rem;
  font-weight: 600;
  color: #c0c0d0;
}

.file-row .required {
  color: #e879a0;
}

.file-row .optional {
  color: #808090;
}

.file-drop {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 2.3rem;
  padding: 0.45rem 0.8rem;
  background: #0f3460;
  border: 1px dashed #2a2a5a;
  border-radius: 6px;
  color: #7a7a90;
  font-size: 0.85rem;
  cursor: pointer;
  text-align: center;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.file-drop:hover {
  background: #143a6b;
  border-color: #3a3a6a;
  color: #b0b0c0;
}

.file-drop.dragover {
  background: #2a2a5a;
  border-style: solid;
  border-color: #e879a0;
  color: #e879a0;
}

.file-drop.has-file {
  border-style: solid;
  color: #e0e0e0;
}

.file-drop input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.file-drop-text {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}

.file-row .skin-select {
  background: #0f3460;
  border: 1px solid #2a2a5a;
  border-radius: 6px;
  color: #e0e0e0;
  font-size: 0.85rem;
  padding: 0.4rem 0.6rem;
  width: 100%;
}

#load-btn {
  background: #e879a0;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 0.6rem 1.5rem;
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  align-self: center;
  margin-top: 0.2rem;
  transition: background 0.15s ease;
  letter-spacing: 0.03em;
}

#load-btn:hover {
  background: #d4609a;
}

#load-btn:disabled {
  background: #7a4060;
  cursor: not-allowed;
}

.status {
  min-height: 1.5rem;
  font-size: 0.85rem;
  color: #e0e0e0;
  text-align: center;
}

.load-progress {
  align-self: center;
  width: 70%;
  max-width: 260px;
  height: 4px;
  margin-top: 0.55rem;
  background: rgba(232, 121, 160, 0.15);
  border-radius: 2px;
  overflow: hidden;
  display: none;
}

.load-progress.active {
  display: block;
}

.load-progress-bar {
  width: 40%;
  height: 100%;
  background: linear-gradient(90deg, transparent 0%, #e879a0 50%, transparent 100%);
  animation: load-progress-slide 1.2s ease-in-out infinite;
}

@keyframes load-progress-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

.player-controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
}

.player-controls.hidden {
  display: none;
}

.play-pause-btn {
  background: #e879a0;
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 0.45rem 0;
  font-size: 1.1rem;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s ease;
  line-height: 1;
  width: 2.4rem;
  text-align: center;
}

.play-pause-btn:hover {
  background: #d4609a;
}

.scrub-bar-wrap {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  height: 16px;
}

.scrub-bar {
  width: 100%;
  cursor: pointer;
  height: 4px;
  margin: 0;
  position: relative;
  z-index: 1;
}

.scrub-markers {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 12px;
  pointer-events: none;
  z-index: 2;
}

.scrub-marker {
  position: absolute;
  top: 0;
  width: 2px;
  height: 12px;
  transform: translateX(-50%);
  border-radius: 1px;
}

.scrub-marker.miss {
  background: #ff4d4d;
}

.scrub-marker.sliderbreak {
  background: #ffdd33;
}

.scrub-marker.miss.partner {
  background: #3d9bff;
}

.scrub-marker.sliderbreak.partner {
  background: #8fd2ff;
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  background: #2a2a4a;
  border-radius: 2px;
}

input[type="range"]::-moz-range-track {
  height: 4px;
  background: #2a2a4a;
  border-radius: 2px;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 3px;
  height: 16px;
  background: #e879a0;
  border: none;
  border-radius: 1px;
  margin-top: -6px;
  cursor: pointer;
}

input[type="range"]::-moz-range-thumb {
  width: 3px;
  height: 16px;
  background: #e879a0;
  border: none;
  border-radius: 1px;
  cursor: pointer;
}

.time-display {
  font-size: 0.85rem;
  color: #a0a0b0;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  min-width: 7ch;
  text-align: right;
}

.render-options {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
  background: #16213e;
  border: 1px solid #2a2a4a;
  border-radius: 8px;
  padding: 0.6rem 1rem;
}

.render-options.hidden {
  display: none;
}

.opts-left,
.opts-right {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  min-width: 0;
}
.opts-left  { justify-self: start; justify-content: flex-start; }
.opts-right { justify-self: end;   justify-content: flex-end;   }

.option-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: #c0c0d0;
  cursor: pointer;
  user-select: none;
}

.option-toggle input[type="checkbox"] {
  accent-color: #e879a0;
  width: 15px;
  height: 15px;
  cursor: pointer;
}

.option-dim {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: #c0c0d0;
}

.option-dim input[type="range"] {
  accent-color: #e879a0;
  width: 110px;
  cursor: pointer;
}

.option-dim span {
  font-size: 0.8rem;
  color: #a0a0b0;
  font-variant-numeric: tabular-nums;
  min-width: 3.5ch;
  text-align: right;
}

.volume-stack {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.volume-stack .option-dim {
  margin-left: 0;
}

.vol-label {
  width: 4.5rem;
  display: inline-block;
}

.option-offset {
  gap: 0.35rem;
}

.option-offset span {
  min-width: 5ch;
}

.offset-btn {
  background: transparent;
  border: 1px solid #2a2a4a;
  border-radius: 5px;
  color: #c0c0d0;
  font-size: 0.85rem;
  line-height: 1;
  padding: 0.2rem 0.4rem;
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.offset-btn:hover {
  background: #2a2a5a;
  color: #e879a0;
  border-color: #e879a0;
}

.offset-btn:active {
  background: #3a3a6a;
}

.offset-reset {
  font-size: 0.95rem;
  padding: 0.15rem 0.35rem;
}

.sync-btn {
  background: transparent;
  border: 1px solid #2a2a4a;
  border-radius: 6px;
  color: #c0c0d0;
  font-size: 0.95rem;
  line-height: 1;
  padding: 0.25rem 0.45rem;
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}

.sync-btn:hover {
  background: #2a2a5a;
  color: #e879a0;
  border-color: #e879a0;
}

.sync-btn:active {
  background: #3a3a6a;
}

/* Audio swap — two musical-note buttons flanking a swap arrow. Lives in
   the middle `auto` column of the render-options grid (`1fr auto 1fr`),
   which centers it within the panel. The INNER layout uses another
   `1fr auto 1fr` grid so the swap button sits at the element's exact
   center regardless of how wide each note's username runs — and since
   the element itself is horizontally centered in the panel (which is
   centered in the canvas column, same as the canvas stack), that center
   lines up with the vertical gap between the two canvases. */
.audio-swap {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.5rem;
  justify-self: center;
}
.audio-swap.hidden { display: none; }

.audio-swap > .audio-swap-note:first-of-type { justify-self: end; }
.audio-swap > .audio-swap-note:last-of-type  { justify-self: start; }

.audio-swap-note {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.6rem;
  background: transparent;
  border: 1px solid #2a2a4a;
  border-radius: 6px;
  color: #a0a0b0;
  font-size: 0.85rem;
  font-family: inherit;
  cursor: pointer;
  max-width: 11rem;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.audio-swap-note:hover {
  background: #2a2a5a;
  color: #e879a0;
  border-color: #e879a0;
}
.audio-swap-note.active {
  background: rgba(232, 121, 160, 0.18);
  color: #e879a0;
  border-color: #e879a0;
  box-shadow: 0 0 0 1px rgba(232, 121, 160, 0.5) inset;
}

.audio-swap-icon {
  font-size: 1.05rem;
  line-height: 1;
  flex-shrink: 0;
}

.audio-swap-name {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-style: italic;
  font-weight: 600;
}

.audio-swap-btn {
  background: transparent;
  border: 1px solid #2a2a4a;
  border-radius: 6px;
  color: #c0c0d0;
  font-size: 1.05rem;
  line-height: 1;
  padding: 0.3rem 0.55rem;
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.audio-swap-btn:hover {
  background: #2a2a5a;
  color: #e879a0;
  border-color: #e879a0;
}
.audio-swap-btn:active {
  background: #3a3a6a;
}

.info-panel {
  position: relative;
  background: #16213e;
  border: 1px solid #2a2a4a;
  border-radius: 12px;
  padding: 1rem 1.1rem 1.1rem;
  overflow: hidden;
  flex: 0 1 auto;
  min-height: 0;
}

.info-header {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  border-bottom: 1px solid #2a2a4a;
  padding-bottom: 0.55rem;
  margin-bottom: 0.7rem;
}

.info-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: #e879a0;
  letter-spacing: 0.02em;
  line-height: 1;
}

.info-version {
  font-size: 0.7rem;
  color: #808095;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.info-body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  font-size: 0.78rem;
  color: #c0c0d0;
  line-height: 1.4;
}

.info-body p {
  margin: 0;
}

.info-author {
  color: #a0a0b0;
}

.info-author strong {
  color: #e0e0e0;
  font-weight: 600;
}

.info-notes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  color: #a0a0b0;
  font-size: 0.75rem;
}

.info-notes li {
  position: relative;
  padding-left: 0.8rem;
}

.info-notes li::before {
  content: "•";
  position: absolute;
  left: 0.1rem;
  color: #e879a0;
}

.info-unsupported {
  color: #a0a0b0;
  font-size: 0.75rem;
}

.info-unsupported-label {
  color: #e879a0;
  font-weight: 600;
}

.info-contact {
  margin-top: 0.15rem;
  color: #c0c0d0;
}

.info-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.1rem;
}

.info-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.35rem;
  background: #0f3460;
  border: 1px solid #2a2a5a;
  border-radius: 6px;
  color: #e0e0e0;
  text-decoration: none;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.info-link:hover {
  background: #2a2a5a;
  border-color: #e879a0;
  color: #e879a0;
}

.info-link-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.info-horse {
  position: absolute;
  right: 24px;
  bottom: -4px;
  width: 70px;
  height: auto;
  opacity: 0.18;
  pointer-events: none;
  filter: saturate(0.9);
}

#replay-canvas,
#replay-canvas-2 {
  border: 2px solid #2a2a4a;
  border-radius: 8px;
  background: #0a0a1a;
  display: block;
}

#replay-canvas.hidden,
#replay-canvas-2.hidden {
  display: none;
}

/* ─── Responsive: stack layout + scale canvas on narrow viewports ──────────────
   The native desktop layout needs ≈1872px (1280 canvas + 2×280 side panels +
   gaps). Below that we collapse the 3-column grid into a single stack and let
   the canvas scale down to viewport width via CSS (backing store stays
   1280×720 — browser downscales the bitmap). */
@media (max-width: 1880px) {
  body { padding: 0.6rem; }

  .main-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.8rem;
  }

  .canvas-column,
  .left-panel,
  .sidebar {
    grid-column: auto;
    justify-self: center;
    width: 100%;
    max-width: 1280px;
  }

  /* Stack order: canvas first (primary content), loaded-replay tabs, then
     input + info panels. */
  .canvas-column { order: 1; }
  .sidebar       { order: 2; }
  .left-panel    { order: 3; }

  #replay-canvas,
  #replay-canvas-2 {
    width: 100%;
    height: auto;
    max-width: 1280px;
  }

  /* JS ties the tabs-panel cap to canvas-column height — meaningful only in
     the 3-column layout. Release it when stacked. */
  .tabs-panel { max-height: none; }
}

/* Small phones: tighten padding and wrap controls onto multiple rows. */
@media (max-width: 600px) {
  body { padding: 0.4rem; }
  .main-row { gap: 0.6rem; }
  .input-panel { padding: 0.9rem; }
  .tabs-panel { padding: 0.6rem; }
  .render-options { padding: 0.5rem 0.7rem; gap: 0.8rem; }
  .player-controls { gap: 0.6rem; }
  .time-display { min-width: 6ch; font-size: 0.8rem; }
  .info-panel { padding: 0.9rem 0.9rem 2.8rem; }
  .info-horse { width: 56px; right: 14px; }
}

/* Prototype — dual-canvas match replay viewing.
   In single mode each canvas renders at its native 1280×720. In dual mode the
   stack goes side-by-side and each canvas is visually halved (backing store
   unchanged — the browser downscales the bitmap). */
.canvas-stack { display: flex; justify-content: center; gap: 8px; }
.canvas-frame { position: relative; display: block; line-height: 0; }
.canvas-frame.hidden { display: none; }
.canvas-stack.dual #replay-canvas,
.canvas-stack.dual #replay-canvas-2 {
  width: 640px;
  height: 360px;
}

/* Player-name label — bottom-right corner of each canvas. Mimics the osu!
   tournament client's player-name plate: Exo bold italic, off-white with a
   subtle blue tint, soft drop-shadow so it stays readable against the bg. */
.player-label {
  position: absolute;
  bottom: 14px;
  right: 20px;
  color: #dce2ee;
  font-family: 'Exo', 'Segoe UI', sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 26px;
  letter-spacing: 0.03em;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.85), 0 0 10px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  line-height: 1;
}
.player-label.hidden { display: none; }
.canvas-stack.dual .player-label { font-size: 18px; bottom: 10px; right: 14px; }
/* Dual mode: tint labels so they match the scrub-bar marker colors —
   soft off-white red for canvas1 (red misses), soft off-white blue for canvas2. */
.canvas-stack.dual #player-label-1 { color: #f3cfd1; }
.canvas-stack.dual #player-label-2 { color: #ccdcf5; }

/* Tournament-client-style dual score readout — appears below the scrub bar
   when a real match pair is active. Left canvas right-aligns to center, right
   canvas left-aligns; the leading side bumps 2px + bold italic. */
.match-score-strip {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 28px;
  align-items: flex-end;
  width: 100%;
  padding: 0 4px;
  pointer-events: none;
}
.match-score-strip.hidden { display: none; }

.match-score-side {
  display: flex;
  flex-direction: column;
  line-height: 1;
}
.match-score-side-left  { align-items: flex-end;  }
.match-score-side-right { align-items: flex-start; }

.match-score-diff {
  font-family: 'Exo', 'Segoe UI', sans-serif;
  font-style: italic;
  font-weight: 600;
  font-size: 13px;
  color: #ff9bb3;
  letter-spacing: 0.04em;
  line-height: 1;
  margin-bottom: 4px;
  min-height: 13px;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
  font-variant-numeric: tabular-nums;
}

.match-score {
  font-family: 'Exo', 'Segoe UI', sans-serif;
  font-style: italic;
  font-weight: 500;
  font-size: 32px;
  color: #dce2ee;
  letter-spacing: 0.02em;
  line-height: 1;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.75);
  font-variant-numeric: tabular-nums;
  transition: font-size 0.12s ease, font-weight 0.12s ease, color 0.12s ease;
}
.match-score.leading {
  font-weight: 800;
  font-size: 34px;
  color: #ffffff;
}

/* Fail overlay — centered over the partner canvas when that player has no
   replay. We still paint the beatmap background underneath so the pair stays
   visually balanced. */
.fail-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #ffd8d8;
  font-family: 'Exo', 'Segoe UI', sans-serif;
  font-style: italic;
  font-weight: 700;
  font-size: 44px;
  letter-spacing: 0.05em;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.9);
  background: rgba(20, 10, 20, 0.55);
  padding: 0.8rem 1.6rem;
  border-radius: 10px;
  pointer-events: none;
  white-space: nowrap;
  line-height: 1;
}
.fail-overlay.hidden { display: none; }
.canvas-stack.dual .fail-overlay { font-size: 30px; padding: 0.5rem 1rem; }

/* ─── Match-view mode ────────────────────────────────────────────────────────
   When a match pair is loaded the single-replay shell (input panel, loaded-
   replays sidebar, info panel) becomes dead weight. Adding `.match-view` to
   <body> collapses the 3-column grid down to a single column dedicated to
   the two canvases, with a slim top strip carrying the match title + pair
   switcher. Each dual canvas stretches toward ≈50vw (capped at its 1280px
   backing store) so the replays dominate the viewport instead of occupying
   the centre third. */
body.match-view .left-panel,
body.match-view .sidebar {
  display: none;
}
body.match-view .main-row {
  grid-template-columns: minmax(0, 1fr);
}
body.match-view .canvas-column {
  grid-column: 1;
  justify-self: center;
  width: 100%;
  max-width: none;
}
body.match-view .canvas-stack.dual {
  gap: 12px;
}
body.match-view .canvas-stack.dual #replay-canvas,
body.match-view .canvas-stack.dual #replay-canvas-2 {
  width: min(calc(50vw - 24px), 1280px);
  height: auto;
  aspect-ratio: 16 / 9;
}
body.match-view .canvas-stack.dual .player-label {
  font-size: clamp(18px, 1.6vw, 28px);
  bottom: clamp(10px, 1vw, 16px);
  right:  clamp(14px, 1.4vw, 22px);
}
body.match-view .canvas-stack.dual .fail-overlay {
  font-size: clamp(30px, 3vw, 54px);
}

/* Slim strip above the canvases — room title, current pair, change-pair
   toggle, exit match view. The drawer drops from the strip with the match
   playlist so users can switch maps without leaving the mode. */
.match-strip {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
  background: #16213e;
  border: 1px solid #2a2a4a;
  border-radius: 8px;
  padding: 0.5rem 0.8rem;
  width: 100%;
  position: relative;
}
.match-strip.hidden { display: none; }

.match-strip-info {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.9rem;
  color: #c0c0d0;
  overflow: hidden;
}

.match-strip-room {
  color: #e879a0;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 0;
  max-width: 30ch;
}

.match-strip-sep { color: #5a5a75; flex-shrink: 0; }

.match-strip-current {
  color: #e0e0e0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.match-strip-actions {
  display: flex;
  gap: 0.4rem;
  flex-shrink: 0;
}

.match-strip-btn {
  background: #0f3460;
  border: 1px solid #2a2a5a;
  border-radius: 6px;
  color: #e0e0e0;
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0.35rem 0.8rem;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
  line-height: 1;
}
.match-strip-btn:hover {
  background: #2a2a5a;
  border-color: #e879a0;
  color: #e879a0;
}

.match-strip-back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.match-strip-back-arrow { font-size: 0.95rem; line-height: 1; }

/* ─── Match overview ────────────────────────────────────────────────────────
   Overlaid on top of canvas1 when a MatchSession is active (before a pair is
   loaded). The canvas below is already painted with the first-picked map's
   gameplay background at 55% dim; this overlay layers the match metadata on
   top with a subtle gradient scrim for consistent text contrast. */
.match-overview {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 1.4rem 1.8rem;
  color: #e8e8f0;
  font-size: 0.95rem;
  line-height: 1.3;
  overflow: hidden;
  border-radius: 8px;
  background: linear-gradient(
    180deg,
    rgba(10, 10, 20, 0.55) 0%,
    rgba(10, 10, 20, 0.25) 35%,
    rgba(10, 10, 20, 0.55) 100%
  );
}
.match-overview.hidden { display: none; }

.match-overview-header {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.match-overview-title {
  font-size: 1.4rem;
  font-weight: 700;
  color: #ffffff;
  letter-spacing: 0.01em;
  margin: 0;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.85), 0 0 16px rgba(0, 0, 0, 0.55);
}

.match-overview-meta {
  font-size: 0.85rem;
  color: #c8c8dc;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

.match-overview-players {
  display: flex;
  align-items: stretch;
  gap: 1rem;
  font-size: 0.9rem;
}

.match-overview-player {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 0.85rem;
  background: rgba(15, 52, 96, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid rgba(42, 42, 90, 0.85);
  border-radius: 10px;
  min-width: 16rem;
  flex: 0 0 auto;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.match-overview-player.leader { border-color: #e879a0; }

.match-overview-player-avatar {
  width: 52px;
  height: 52px;
  border-radius: 8px;
  object-fit: cover;
  flex-shrink: 0;
  background: rgba(0, 0, 0, 0.4);
}
.match-overview-player-avatar-placeholder {
  background: rgba(30, 30, 60, 0.7);
  border: 1px dashed rgba(180, 180, 220, 0.3);
}

.match-overview-player-body {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  flex: 1 1 auto;
}

.match-overview-player-topline {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
}

.match-overview-player-flag {
  width: 22px;
  height: auto;
  border-radius: 2px;
  flex-shrink: 0;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

.match-overview-player-name {
  color: #ffffff;
  font-weight: 700;
  font-size: 1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.match-overview-player-stats {
  color: #c4c8e0;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}

.match-overview-player-ranks {
  color: #9fa8c8;
  font-size: 0.78rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* Scoreboard between the two player cards in a 1v1 overview. Expands to
   fill the gap and stays centered; the winner of each stat gets `.leading`
   (bold + brighter) to echo the live dual-score strip. */
.match-overview-summary {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.5rem 0.85rem;
  min-width: 10rem;
  font-variant-numeric: tabular-nums;
  color: #dce2ee;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

.match-overview-summary-score {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  column-gap: 0.8rem;
  font-family: 'Exo', 'Segoe UI', sans-serif;
  font-style: italic;
  font-size: 2.2rem;
  font-weight: 600;
  line-height: 1;
}
.match-overview-summary-wins {
  color: #c8cede;
  transition: color 0.12s ease, font-weight 0.12s ease;
}
.match-overview-summary-wins:first-child { text-align: right; }
.match-overview-summary-wins:last-child  { text-align: left;  }
.match-overview-summary-wins.leading {
  color: #ffffff;
  font-weight: 800;
}
.match-overview-summary-dash {
  color: #9fa8c8;
  font-weight: 500;
}

.match-overview-summary-stat {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  column-gap: 0.8rem;
  font-size: 0.85rem;
}
.match-overview-summary-stat-label {
  color: #8d93ad;
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.match-overview-summary-stat-val {
  color: #c8cede;
  font-style: italic;
  transition: color 0.12s ease, font-weight 0.12s ease;
}
.match-overview-summary-stat-val.left  { text-align: right; }
.match-overview-summary-stat-val.right { text-align: left;  }
.match-overview-summary-stat-val.leading {
  color: #ffffff;
  font-weight: 700;
}

.match-overview-maps {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  /* grow 0 so the panel only extends as far as the maps themselves — the
     translucent scrim stops at the last map rather than reaching the bottom
     of the overview. Still shrinkable + scrollable when a long match pushes
     past the available height. */
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0.55rem;
  background: rgba(10, 10, 20, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  border: 1px solid rgba(42, 42, 74, 0.55);
  border-radius: 8px;
  scrollbar-width: none;
}
.match-overview-maps::-webkit-scrollbar { display: none; }

.match-overview-map {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.75rem;
  background: rgba(26, 26, 46, 0.82);
  border: 1px solid rgba(42, 42, 74, 0.7);
  border-radius: 5px;
  font-size: 0.85rem;
}
.match-overview-map.current {
  border-color: #e879a0;
  background: rgba(52, 22, 48, 0.85);
}

.match-overview-map-index {
  color: #a0a0c0;
  font-variant-numeric: tabular-nums;
  min-width: 1.5rem;
  text-align: right;
  flex-shrink: 0;
}

.match-overview-map-title {
  color: #e8e8f0;
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.match-overview-map-scores {
  color: #b4b4cc;
  font-variant-numeric: tabular-nums;
  font-size: 0.8rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.match-overview-map-score.leading {
  color: #ffffff;
  font-weight: 700;
}

.match-overview-map-load {
  background: rgba(42, 42, 90, 0.9);
  color: #e8e8f0;
  border: 1px solid rgba(58, 58, 106, 0.9);
  border-radius: 4px;
  padding: 0.3rem 0.85rem;
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.match-overview-map-load:hover:not(:disabled) {
  background: rgba(58, 58, 106, 1);
  border-color: #e879a0;
}
.match-overview-map-load:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Match tab (prototype) */
.match-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 300px;
  overflow-y: auto;
  margin-top: 0.5rem;
}
.match-header {
  font-size: 0.85rem;
  color: #a0a0c0;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid #2a2a4a;
}
.match-item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.4rem 0.5rem;
  background: #1a1a2e;
  border: 1px solid #2a2a4a;
  border-radius: 4px;
  font-size: 0.8rem;
}
.match-item-title { color: #e0e0e0; font-weight: 600; }
.match-item-score { color: #c0c0d0; padding-left: 0.5rem; }
.match-item-load {
  align-self: flex-start;
  margin-top: 0.2rem;
  padding: 0.2rem 0.6rem;
  background: #2a2a5a;
  color: #e0e0e0;
  border: 1px solid #3a3a6a;
  border-radius: 3px;
  cursor: pointer;
  font-size: 0.75rem;
}
.match-item-load:hover:not(:disabled) { background: #3a3a6a; }
.match-item-load:disabled { opacity: 0.4; cursor: not-allowed; }
/* ── 2v2 quad layout ── */
#replay-canvas-3,
#replay-canvas-4 {
  border: 2px solid #2a2a4a;
  border-radius: 8px;
  background: #0a0a1a;
  display: block;
}
#replay-canvas-3.hidden,
#replay-canvas-4.hidden { display: none; }

.canvas-stack.quad {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto;
  gap: 8px;
  justify-content: center;
}
.canvas-stack.quad #replay-canvas,
.canvas-stack.quad #replay-canvas-2,
.canvas-stack.quad #replay-canvas-3,
.canvas-stack.quad #replay-canvas-4 {
  width: 960px;
  height: 360px;
}
.canvas-stack.quad .player-label {
  font-size: 18px;
  bottom: 10px;
  right: 14px;
}
.canvas-stack.quad .fail-overlay { font-size: 28px; padding: 0.4rem 0.9rem; }

body.match-view .canvas-stack.quad {
  gap: 6px;
}
body.match-view .canvas-stack.quad #replay-canvas,
body.match-view .canvas-stack.quad #replay-canvas-2,
body.match-view .canvas-stack.quad #replay-canvas-3,
body.match-view .canvas-stack.quad #replay-canvas-4 {
  width: min(calc(50vw - 16px), 960px);
  height: auto;
  aspect-ratio: 8 / 3;
}
