/* The board is the widest surface in the app — N teams side by side — so it
   takes the full page measure rather than the 1000px the match pages use.
   At 1240 the teams grid below fits four across. */
.mix-page {
  max-width: var(--page-max);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

/* A <turbo-frame> is an inline custom element with no layout of its own, so
   without this every block inside the board stacked with no gap at all. */
.mix-board {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

/* The copy-link component carries its own top margin for pages that don't
   space their children; here the flex gap already does that job. */
.mix-board > .copy-link {
  margin-top: 0;
}

/* Labelled sections get a little extra air above them, so the page reads as
   groups rather than one evenly-spaced stack. */
.mix-board > .mix-section,
.mix-board > .mix-columns {
  margin-top: var(--space-sm);
}

.mix-page__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-md);
}

.mix-page__title {
  margin: 0;
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
}

/* The night's name and what kind of night it is, on one line. */
.mix-page__title-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.mix-page__meta {
  margin: var(--space-xs) 0 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* Quiet text action, matching the destructive controls elsewhere. */
.mix-page__delete {
  background: none;
  border: none;
  padding: 0;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  cursor: pointer;
  transition: color var(--dur) var(--ease-out);
}

.mix-page__delete:hover {
  color: var(--action-destructive-fg);
}

.mix-page__header form {
  margin: 0;
}

.mix-empty {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--text-base);
}

.mix-banner {
  margin: 0;
  padding: 11px var(--space-md);
  border-radius: var(--radius);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  box-shadow: var(--shadow-xs);
  font-size: var(--text-base);
}

.mix-banner--done {
  background: var(--surface-win);
  border-color: var(--border-win);
  color: var(--text-win);
}

/* ---------------------------------------------------------------- listing */

/* **The list owns the columns, and the rows subgrid them**, so the mode, the
   status and the count read down three straight edges. Each row was its own
   grid, which sized its tracks to its own contents: "Shuffled" and "Drafted"
   are not the same width, nor are "Finished" and "Gathering players", so every
   row sat a few pixels off the one above it. */
.mix-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: var(--space-sm);
}

.mix-list__item {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
}

.mix-list__link {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  transition: var(--transition-control);
}

.mix-list__link:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
  border-color: var(--border-strong);
}

.mix-list__status {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-loud);
  color: var(--text-tertiary);
}

.mix-list__status--drafting {
  color: var(--text-win);
}

/* Over, so it recedes — mint is for what is still happening. */
.mix-list__status--finished {
  color: var(--text-tertiary);
}

.mix-list__count {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* A phone has no room for four columns: the date wrapped onto three lines to
   make space for them. Two lines of two instead — when and what kind of night
   above, how far through and how many below — which is the order somebody
   reads them in anyway. */
@media (max-width: 640px) {
  .mix-list {
    grid-template-columns: 1fr auto;
  }

  .mix-list__link {
    row-gap: var(--space-xs);
    column-gap: var(--space-sm);
  }

  .mix-list__when {
    grid-column: 1;
    grid-row: 1;
  }

  .mix-list__mode {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }

  .mix-list__status {
    grid-column: 1;
    grid-row: 2;
  }

  .mix-list__count {
    grid-column: 2;
    grid-row: 2;
    justify-self: end;
  }
}

/* ---------------------------------------------------------------- sections */

.mix-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.mix-section__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-sm);
}

.mix-section__title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

.mix-section__hint {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* Two lists side by side when there are two, and one list across the whole
   page when there is one. A fixed `1fr 1fr` left the pool in the left half
   with the right half empty on every night nobody missed out — which is most
   of them. */
.mix-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
  gap: var(--space-xl);
}

.mix-actions {
  display: flex;
  gap: var(--space-sm);
}

/* ----------------------------------------------------------------- roster */

.mix-roster {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.mix-roster__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-smd);
  padding: 10px var(--space-md);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  font-size: var(--text-base);
  transition: var(--transition-control);
}

.mix-roster__item:hover {
  border-color: var(--border-strong);
}

.mix-roster__number {
  flex: 0 0 22px;
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
}

.mix-roster__nickname {
  flex: 0 1 auto;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The row carries a name, the roles, a record and two ranks, so something has
   to give when it is tight. The roles go first: they are the one part that
   still reads when it is cut short, and a truncated nickname is useless. */
.mix-roster__positions {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.mix-roster__elo {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}

.mix-roster__remove-form {
  margin: 0;
  flex: 0 0 auto;
}

.mix-roster__remove {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
}

.mix-roster__remove:hover {
  color: var(--action-destructive-fg);
}

.mix-roster--out .mix-roster__item {
  opacity: 0.55;
}

/* On a phone the roster row has far more in it than a line will hold: a
   number, a name, the roles, a claim, four labelled figures and a remove
   button. Side by side the name ran straight under the claim tag and the
   button fell off the right-hand edge. So the row becomes three lines — who
   they are, what they play, what they are worth — which is the order somebody
   reads it in anyway. Same treatment as `.mix-rsvps__item`, because once
   sign-ups open this is the list that one becomes. */
@media (max-width: 640px) {
  .mix-roster__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    column-gap: var(--space-smd);
    row-gap: var(--space-sm);
    align-items: center;
  }

  .mix-roster__number {
    grid-area: 1 / 1;
  }

  .mix-roster__player {
    grid-area: 1 / 2;
  }

  .mix-roster__item .mix-claim {
    grid-area: 1 / 3;
    justify-self: end;
  }

  .mix-roster__remove-form {
    grid-area: 1 / 4;
    justify-self: end;
  }

  .mix-roster__positions {
    grid-area: 2 / 1 / auto / -1;
  }

  /* Stats, Riot rank, solo queue and the rating, in that order across the
     last line — the same order they sit in on a wide screen. */
  .mix-roster__item .rank-cell {
    grid-row: 3;
    align-items: flex-start;
  }

  .mix-roster__item .rank-cell--league {
    grid-column: 4;
    align-items: flex-end;
  }
}

/* ------------------------------------------------------------------ teams */

/* Four across on a full-width page: the 1240 cap leaves 1176 of content, and
   4 x 240 + 3 x 24 = 1032 fits where a fifth (1296) would not. Degrades to
   three, two and one as the window narrows. */
.mix-teams {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-lg);
}

.mix-team {
  display: flex;
  flex-direction: column;
  gap: var(--space-smd);
  padding: var(--card-pad-sm);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
}

.mix-team__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.mix-team__name {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

.mix-team__elo {
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  border: var(--border-width) solid transparent;
}

/* The side that picks next — the one mint on the board. */
.mix-team__elo--lowest {
  background: linear-gradient(135deg, #effbf7, #cdf2e5);
  border-color: var(--mint-300);
  color: var(--mint-800);
}

.mix-team__roster {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.mix-team__member {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-sm);
  padding: var(--space-sm) var(--space-smd);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
}

/* Second line, first column: the Riot tier sits beside it on the right. */
.mix-team__positions {
  grid-column: 1;
  grid-row: 2;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.mix-team__member-elo {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}

/* The card is a narrow two-column grid, so the two labelled figures get an
   explicit place each rather than being auto-flowed into whatever is left:
   the league rating beside the name, the Riot tier beside the positions. */
.mix-team__member .rank-cell--league {
  grid-column: 2;
  grid-row: 1;
}

.mix-team__member .rank-cell--riot {
  grid-column: 2;
  grid-row: 2;
}

/* A third row rather than a third column: the card is narrow, and squeezing
   three figures across it would wrap every nickname. */
.mix-team__member .rank-cell--record {
  grid-column: 2;
  grid-row: 3;
}

/* A fourth row for the measured standing. It sits under the reported one
   deliberately: the claim and the check read as a pair that way. */
.mix-team__member .rank-cell--solo {
  grid-column: 2;
  grid-row: 4;
}

.mix-team__empty {
  padding: var(--space-smd);
  border: var(--border-width) dashed var(--border-default);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.mix-team__add {
  width: 100%;
}

/* ------------------------------------------------------------------ modal */

.mix-modal {
  width: min(480px, calc(100vw - 2 * var(--space-md)));
  padding: 0;
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  background: var(--surface-card);
  color: var(--text-primary);
}

.mix-modal::backdrop {
  background: var(--scrim);
}

.mix-modal__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  padding: var(--space-lg);
  max-height: 70vh;
}

/* The sign-up form is far taller than the pick list this modal was built for,
   so it scrolls inside the box while the header stays put. */
.mix-modal__inner > .mix-join__form {
  overflow-y: auto;
  min-height: 0;
}

.mix-modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
}

.mix-modal__title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

.mix-modal__close {
  border: none;
  background: none;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  color: var(--text-secondary);
  transition: color var(--dur) var(--ease-out);
}

.mix-modal__close:hover {
  color: var(--text-primary);
}

.mix-modal__list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.mix-modal__pick {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 var(--space-sm);
  width: 100%;
  text-align: left;
  padding: 10px var(--space-smd);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: inherit;
  cursor: pointer;
  transition: var(--transition-control);
}

.mix-modal__pick:hover {
  border-color: var(--border-selected);
  box-shadow: var(--shadow-xs);
}

.mix-modal__positions {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.mix-modal__elo {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-semibold);
}

/* ------------------------------------------------------------------- join */

.mix-join {
  max-width: 560px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
}

.mix-join__title {
  margin: 0;
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
}

.mix-join__meta {
  margin: var(--space-xs) 0 0;
  color: var(--text-secondary);
  font-size: 14px;
}

.mix-join__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

.mix-join__nomatch {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
}

.mix-join__already {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
}

/* `display: flex` from this rule would otherwise beat the user agent's
   `[hidden] { display: none }`, leaving the panel on screen before a player
   has been picked. */
.mix-join__panel[hidden] {
  display: none;
}

.mix-join__panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  padding: var(--card-pad);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.mix-join__summary {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-sm) var(--space-md);
}

.mix-join__name {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

.mix-join__elo {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-base);
  color: var(--text-secondary);
}

.mix-join__positions {
  font-size: 13px;
  color: var(--text-secondary);
}

/* "Can't find yourself" opens a modal rather than unfolding in place: the form
   underneath is long — name, Riot ID, rank and five role preferences — and
   pushing it into the page shoved the picker most people actually want off the
   top of the screen. */
.mix-join__new {
  display: flex;
}

.mix-join__new-trigger {
  /* Secondary: the picker above is what almost everyone needs. */
  align-self: flex-start;
}

.combobox__option {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
}

.combobox__option-elo {
  font-family: var(--font-mono);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
}

@media (max-width: 640px) {
  .mix-columns {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------- matches */

.mix-team__rank {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  margin-right: var(--space-xs);
}

.mix-team__delta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

.mix-team__delta--up {
  color: var(--text-win);
}

.mix-team__delta--down {
  color: var(--text-loss);
}

.mix-matches {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.mix-matches__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-smd);
  padding: 10px var(--space-md);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  font-size: var(--text-base);
}

.mix-matches__result {
  flex: 1 1 auto;
}

.mix-matches__winner {
  font-weight: var(--weight-semibold);
}

.mix-matches__loser {
  color: var(--text-secondary);
}

/* A played fixture goes through to its league match. */
.mix-matches__result--link {
  text-decoration: none;
  transition: color var(--dur) var(--ease-out);
}

.mix-matches__result--link:hover {
  text-decoration: underline;
}

.mix-matches__when {
  font-family: var(--font-mono);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-2xs);
}

.mix-matches__delete-form {
  margin: 0;
  flex: 0 0 auto;
}

.mix-matches__delete {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
}

.mix-matches__delete:hover {
  color: var(--action-destructive-fg);
}

/* --------------------------------------------------------------- pairings */

.mix-pairings {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.mix-pairing {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
}

.mix-pairing__teams {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  font-size: 15px;
}

.mix-pairing__name {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

.mix-pairing__elo {
  margin-left: var(--space-xs);
  font-family: var(--font-mono);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

.mix-pairing__vs {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.mix-pairing__actions {
  display: flex;
  gap: var(--space-sm);
  flex-wrap: wrap;
}

.mix-pairing__actions form {
  margin: 0;
}

@media (max-width: 640px) {
  .mix-pairing {
    flex-direction: column;
    align-items: stretch;
  }
}

.mix-list__when {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--text-tertiary);
}

.mix-pairing__win {
  flex-shrink: 0;
}

.mix-team__nickname,
.mix-modal__nickname {
  font-weight: var(--weight-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------------------------ pool filter */

/* Links rather than buttons: the board re-fetches itself every few seconds, so
   a filter held in the DOM would be wiped on the next tick. Each chip re-loads
   the frame with its role toggled. */
/* The pool filter: a toggle that opens a panel anchored under it. Anchored in
   normal flow rather than the top layer, so it scrolls with the section. */
.mix-filter {
  position: relative;
}

.mix-filter__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-smd);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-pill);
  background: var(--surface-card);
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

/* Safari still draws its own marker without this. */
.mix-filter__toggle::-webkit-details-marker {
  display: none;
}

.mix-filter__toggle:hover {
  background: var(--surface-sunk);
  border-color: var(--border-strong);
}

.mix-filter[open] > .mix-filter__toggle {
  background: var(--surface-sunk);
  border-color: var(--border-strong);
}

.mix-filter__icon {
  flex: none;
  color: var(--text-secondary);
}

.mix-filter__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--action-primary-bg);
  color: var(--action-primary-fg);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
}

.mix-filter__panel {
  position: absolute;
  top: calc(100% + var(--space-xs));
  right: 0;
  z-index: 20;
  width: max-content;
  min-width: 220px;
  padding: var(--space-md);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--surface-card);
  box-shadow: var(--shadow-lg);
}

.mix-filter__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  margin: 0;
}

.mix-filter__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  border: 0;
}

.mix-filter__legend {
  padding: 0;
  margin-bottom: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.mix-filter__roles {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.mix-filter__option {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  font-size: var(--text-sm);
  cursor: pointer;
}

.mix-filter__option input {
  margin: 0;
  flex: none;
}

.mix-filter__actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  padding-top: var(--space-2xs);
  border-top: var(--border-width) solid var(--border-default);
}

.mix-filter__actions .button {
  flex: 1;
}

.mix-filter__clear {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
}

.mix-filter__clear:hover {
  color: var(--text-primary);
}

/* Narrow screens have no room to hang a panel off the right edge. */
@media (max-width: 520px) {
  .mix-filter__panel {
    right: auto;
    left: 0;
  }
}


/* Stage switcher — an admin looking back at what an earlier stage looked like.
   Sits above the board because it changes what the whole board is showing. */
.mix-stages {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  padding: 3px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-sunk);
  align-self: flex-start;
}

.mix-stages__stage {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: var(--space-xs) var(--space-smd);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-secondary);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.mix-stages__stage:hover {
  background: var(--surface-card);
  color: var(--text-primary);
}

.mix-stages__stage--on {
  background: var(--surface-card);
  color: var(--text-primary);
  box-shadow: var(--shadow-xs);
}

/* Mint means live, the way it does everywhere else. */
.mix-stages__live {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-win);
}

.mix-preview {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
  padding: var(--space-sm) var(--space-md);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface-sunk);
}

.mix-preview__text {
  margin: 0;
  color: var(--text-secondary);
}

.mix-preview__back {
  font-weight: 500;
  white-space: nowrap;
}

/* This round's draw. Read-only on the board — settling happens on the results
   page — so it stays a plain list rather than a row of controls. */
.mix-fixtures {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* A grid, not a flex row: with `space-between` the state and the link sat
   wherever the team names left them, so no two rows lined up. Fixed columns
   mean the eye can run straight down each one. */
.mix-fixtures__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7rem auto;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-md);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-card);
}

.mix-fixtures__item--settled {
  background: var(--surface-sunk);
  color: var(--text-secondary);
}

.mix-fixtures__teams {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  font-weight: 500;
}

.mix-fixtures__vs {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}

.mix-fixtures__state {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  /* Its own column, so "To play" and "Team x won" start in the same place. */
  grid-column: 2;
}

/* Always the last column, whether or not there is a link after it. */
.mix-fixtures__draft {
  grid-column: 3;
  justify-self: end;
}

@media (max-width: 640px) {
  .mix-fixtures__item {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .mix-fixtures__state,
  .mix-fixtures__draft {
    grid-column: auto;
    justify-self: end;
  }
}

.mix-pairing--settled {
  background: var(--surface-sunk);
}

.mix-pairing__outcome {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin-right: var(--space-sm);
}

/* Not open yet: recedes like a finished mix, because neither is happening now. */
.mix-list__status--scheduled {
  color: var(--text-tertiary);
}

.mix-page__actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

.mix-page__edit {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  white-space: nowrap;
}

.mix-page__edit:hover {
  color: var(--text-primary);
}

/* Whose turn it is, on the admin's board. */
.mix-team--on-the-clock {
  border-color: var(--border-win);
  box-shadow: var(--shadow-sm);
}

.mix-team__clock {
  margin-left: var(--space-sm);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-win);
}

/* The night's log. Timestamps line up on the left so it scans as a column. */
.mix-log {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

.mix-log__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  flex-wrap: wrap;
  padding: var(--space-xs) 0;
  border-bottom: var(--border-width) solid var(--border-default);
}

.mix-log__when {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

.mix-log__kind {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* Signing up is the thing we're hoping for, so it gets the mint. */
.mix-log__kind--joined {
  color: var(--text-win);
}

/* The lines asking for something to be done about them: a captain who never
   got their link cannot pick, and a night nobody was told about is empty. */
.mix-log__kind--captain_unreachable,
.mix-log__kind--announce_failed {
  color: var(--text-loss);
}

.mix-log__subject {
  font-weight: 500;
}

.mix-log__detail {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.form__row {
  display: flex;
  gap: var(--space-md);
}

.form__row > * {
  flex: 1;
}

.mix-rsvp {
  margin-top: var(--space-md);
}

.mix-rsvp__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.mix-rsvp__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  list-style: none;
  margin: 0;
  padding: 0;
}

.mix-rsvp__list li {
  padding: var(--space-2xs) var(--space-sm);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
}

/* Fixing a round by hand — its own page, because the board re-fetches itself
   and would close the form under you. */

.mix-swap__link {
  display: inline-block;
  margin-top: var(--space-smd);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.mix-swap__link:hover {
  color: var(--text-primary);
}

.mix-swap__form {
  display: grid;
  gap: var(--space-smd);
  align-items: end;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .mix-swap__form {
    grid-template-columns: 1fr 1fr auto;
  }
}

.mix-swap__hint {
  margin: var(--space-2xs) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

/* Fixing the draft by hand: who leads each team, and putting a wrong pick back. */
.fix-leads {
  list-style: none;
  margin: 0 0 var(--space-md);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.fix-leads__row {
  display: flex;
  align-items: center;
  gap: var(--space-smd);
  padding: var(--space-sm) var(--space-md);
  background: var(--surface-card);
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-md);
}

.fix-leads__team {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-tertiary);
}

.fix-leads__lead {
  flex: 1 1 auto;
  font-weight: var(--weight-medium);
}

.fix-leads__form {
  margin: 0;
  flex: 0 0 auto;
}

.fix-leads__tag {
  margin-left: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-win);
}

/* Name and its op.gg link share the roster's name column. */
.mix-roster__player {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  min-width: 0;
}

/* The name must never be the thing that disappears. It shrinks with an ellipsis
   like it always did, but the op.gg link beside it refuses to shrink at all, so
   without a floor the name absorbs the whole squeeze and collapses to nothing. */
.mix-roster__player .mix-roster__nickname {
  min-width: 7ch;
}

/* The name is what the row is for; everything after it can shrink first. */
.mix-roster__player {
  flex: 0 1 auto;
}

/* One tab with the whole team's solo queue side by side. Sits under the team's
   heading, quiet — it's a way off the page, not part of the standings. */
.op-gg--multi {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: var(--space-xs);
}

/* Name and its op.gg link share the first cell of a team member's row. */
.mix-team__player {
  display: flex;
  align-items: baseline;
  gap: var(--space-sm);
  min-width: 0;
}

/* The names are links now. They should read as the name they already were —
   a row of blue underlines down a draft pool is noise — so the affordance is
   the hover, not the resting state. */
a.mix-roster__nickname,
a.mix-team__nickname {
  color: inherit;
  text-decoration: none;
}

a.mix-roster__nickname:hover,
a.mix-team__nickname:hover {
  text-decoration: underline;
}

/* Where the night stops. Drawn only when somebody is below it. The label is a
   sentence, so it is not uppercased — that treatment belongs to mono captions
   and makes a sentence read as shouting. */
.mix-cut__label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.mix-cut {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: var(--space-sm) 0;
  color: var(--text-tertiary);
}

.mix-cut::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-strong);
}

/* Below the line they are still listed — they turned up — but the row says it
   is not counting on them. */
.mix-roster__item--benched {
  opacity: 0.65;
}

/* What their claim on a place was. A tag rather than a column: on most nights
   nobody is benched and this is only worth a glance. */
.mix-claim {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-tertiary);
}

.mix-claim--going { color: var(--text-win); }
.mix-claim--out { color: var(--text-loss); }

/* The two halves of a night's roster, each keeping its own count. */
.mix-group {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: var(--space-md) 0 var(--space-sm);
}

.mix-group:first-of-type {
  margin-top: 0;
}

.mix-group__title {
  color: var(--text-secondary);
}

.mix-group__hint {
  font-size: var(--text-sm);
  color: var(--text-tertiary);
}

/* Something the admin has to read before using the tool under it. */
.mix-notice {
  margin-bottom: var(--space-lg);
  padding: var(--space-smd) var(--space-md);
  border: var(--border-width) solid var(--border-default);
  border-left: 3px solid var(--amber-300);
  border-radius: var(--radius-md);
  background: var(--surface-card);
}

.mix-notice p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.mix-notice__title {
  font-weight: var(--weight-medium);
  color: var(--text-primary) !important;
  margin-bottom: var(--space-2xs) !important;
}

/* A run of upcoming nights on the schedule page. The one in front is the one
   people are asking about; the rest are there to answer "and the week after?" */
.sched-night {
  padding: var(--space-smd) 0;
  border-top: var(--border-width) solid var(--border-default);
}

.sched-night--next {
  border-top: none;
}

.sched-night__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-bottom: var(--space-2xs);
}

.sched-night__when {
  font-weight: var(--weight-medium);
}

.sched-night--next .sched-night__when {
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

.sched-night__state {
  color: var(--text-tertiary);
}

/* Reading the scoreboard at the end of a game, which is what people have in
   front of them. The ordinary buttons stay: this reads, it does not record. */
.mix-pairing__shot {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  flex-basis: 100%;
  margin-top: var(--space-xs);
}

.mix-pairing__shot-file {
  font-size: var(--text-2xs);
  max-width: 14rem;
}

/* What it read, as a thing to agree with. Nothing is written until the
   button under it is pressed. */
.mix-reading {
  flex-basis: 100%;
  padding: var(--space-smd);
  border: var(--border-width) solid var(--border-default);
  border-left: 3px solid var(--amber-300);
  border-radius: var(--radius-md);
  background: var(--surface-card);
}

.mix-reading__title {
  margin: 0 0 var(--space-xs);
  font-weight: var(--weight-medium);
}

.mix-reading__champs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-bottom: var(--space-sm);
}

.mix-reading__champ {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: 2px var(--space-xs) 2px 2px;
  border: var(--border-width) solid var(--border-default);
  border-radius: var(--radius-sm);
  font-size: var(--text-2xs);
  color: var(--text-secondary);
}

.mix-reading__unmatched {
  margin: 0 0 var(--space-sm);
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.mix-reading__actions {
  display: flex;
  gap: var(--space-sm);
}

/* One fixture's own page: who won, the scoreboard, or an undo. The round page
   is a list for settling four in a row; this is for the thing people actually
   do, which is finish one game and report it. */
.mix-result__title {
  margin: 0 0 var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
}

.mix-result__subtitle {
  margin: 0 0 var(--space-2xs);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.mix-result__hint {
  margin: 0 0 var(--space-md);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.mix-result__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.mix-result__win-form {
  flex: 1 1 14rem;
}

.mix-result__win {
  width: 100%;
}

.mix-result__shot {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: var(--border-width) solid var(--border-default);
}

.mix-result__shot-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm);
}

.mix-result__scout {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-md);
}

.mix-fixtures__report {
  font-size: var(--text-2xs);
  white-space: nowrap;
}

/* Who answered ✅ and is not here yet — the gap between the claim and the
   confirmation, on the page where somebody is deciding whether to wait. */
.mix-join__expected {
  margin-top: var(--space-md);
  padding: var(--space-sm);
  border: var(--border-width) solid var(--border-default);
  border-left: 3px solid var(--mint-500);
  border-radius: var(--radius-md);
  background: var(--surface-card);
}

.mix-join__expected-label {
  display: block;
  margin-bottom: var(--space-2xs);
  color: var(--text-tertiary);
}

.mix-join__expected-names {
  margin: 0;
  font-size: var(--text-sm);
}

.mix-join__expected-hint {
  margin: var(--space-2xs) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-2xs);
}
