/* KJ console — desktop-first.
 *
 * This screen is operated from a laptop at the booth during a show, in a dark
 * room, often at a glance between songs. Priorities: wide layout, large hit
 * targets on the row actions, and a rotation list that stays readable from a
 * few feet away. It degrades acceptably on a tablet but is not phone-optimised.
 */

.console-body {
  background-color: var(--rb-bg);
}

/* Left-aligned rather than centred: on the booth's wide monitor, centring
 * pushed the rotation into the middle of the screen and left the KJ tracking
 * it away from the edge they're already looking at. The width cap stays so the
 * row grid doesn't stretch past readable. */
.console-main {
  max-width: 1500px;
  margin: 0;
  padding: 1.5rem;
}

/* Quiet by design — it's reference information for a support conversation, not
 * something to compete with the rotation for attention in a dark booth. */
.console-footer {
  max-width: 1500px;
  margin: 0;
  padding: 0.75rem 1.5rem 1.5rem;
  border-top: 1px solid var(--rb-border);
  color: var(--rb-muted);
  font-size: 0.8rem;
}

.console-footer__version {
  font-variant-numeric: tabular-nums;
}

/* ---------- Messages ---------- */

/* Banners fade rather than vanish: on a screen the KJ is only half-watching, a
 * line of text disappearing between glances is easier to mistake for something
 * they imagined than one they can see going. Timing lives in console-alerts.js
 * and has to match. */
.console-messages .alert {
  transition: opacity 300ms ease;
}

.console-messages .alert--dismissing {
  opacity: 0;
}

/* ---------- Nav ---------- */

.console-nav {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  background-color: var(--rb-panel);
  border-bottom: 2px solid var(--rb-accent);
  padding: 0.5rem 1.5rem;
}

.console-nav__brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 700;
  white-space: nowrap;
}

.console-nav__links {
  display: flex;
  gap: 0.25rem;
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
  flex-wrap: wrap;
}

.console-nav__links a {
  display: block;
  padding: 0.6rem 0.9rem;
  color: var(--rb-text);
  text-decoration: none;
  border-radius: 4px;
}

.console-nav__links a:hover {
  background-color: var(--rb-panel-2);
}

.console-nav__links a.active {
  background-color: var(--rb-accent);
  color: #000;
  font-weight: 700;
}

.console-nav__user {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  white-space: nowrap;
}

/* ---------- Panels & headings ---------- */

.console-panel {
  background-color: var(--rb-panel);
  border: 1px solid var(--rb-border);
  border-radius: 6px;
  padding: 1rem 1.25rem;
  margin-bottom: 1.25rem;
}

.console-panel__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.console-panel__header h2 {
  margin: 0;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--rb-muted);
}

/* The waiting rotation, drawn quieter than the running one above it.
 *
 * Same rows, same controls — but nobody in it is going on stage this rotation,
 * so it must not compete for the glance between songs. A dashed edge says
 * "not yet" at a distance where no label would be readable; the rows themselves
 * keep their own colours, since a song the KJ still has to find matters just as
 * much a rotation early.
 *
 * scroll-margin is for the focus buttons in the two headers: landing the panel
 * hard against the top of the viewport hides the fact that a list continues
 * above it. */
.console-panel,
.console-panel--waiting {
  scroll-margin-top: 1rem;
}

.console-panel--waiting {
  border-style: dashed;
  background-color: transparent;
}

.console-panel--waiting .queue-row {
  opacity: 0.88;
}

/* ---------- Now singing ---------- */

.now-singing {
  background: linear-gradient(90deg, rgba(225, 0, 165, 0.22), var(--rb-panel) 60%);
  border: 2px solid var(--rb-accent);
  border-radius: 6px;
  padding: 1.25rem;
  margin-bottom: 1.25rem;
}

.now-singing__name {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
}

.now-singing__song {
  font-size: 1.15rem;
  color: var(--rb-text);
  opacity: 0.9;
}

/* ---------- Rotation list ---------- */

.queue-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.queue-row {
  display: grid;
  grid-template-columns: 44px 1fr minmax(260px, 1.2fr) auto;
  align-items: center;
  gap: 1rem;
  background-color: var(--rb-panel-2);
  border: 1px solid var(--rb-border);
  border-radius: 4px;
  padding: 0.7rem 0.9rem;
  margin-bottom: 0.5rem;
}

.queue-row.is-next {
  border-color: var(--rb-accent);
  box-shadow: inset 3px 0 0 var(--rb-accent);
}

/* Orange means "sort this out before this singer reaches the mic" — a song we
 * don't own yet, or a duet partner who looks to be in the rotation twice. One
 * colour for both on purpose: the KJ scans the list from across a dark room and
 * needs to know a row wants attention, not yet which kind. The note and badge
 * on the row say which, once they're looking.
 *
 * The marker sits on the right edge so it never has to compete with the accent
 * bar is-next paints on the left — the top of the rotation is often exactly the
 * row that still needs something done to it. */
.queue-row.is-needs-song,
.queue-row.is-double-booked {
  border-color: #ff7a18;
  background-color: rgba(255, 122, 24, 0.1);
  box-shadow: inset -4px 0 0 #ff7a18;
}

.queue-row.is-needs-song.is-next,
.queue-row.is-double-booked.is-next {
  box-shadow: inset 3px 0 0 var(--rb-accent), inset -4px 0 0 #ff7a18;
}

/* Told they can't have it, waiting on a replacement.
 *
 * Must stay below the orange rules above: a row can be both unavailable and a
 * possible double-booking, the two selectors carry the same specificity, and
 * red is the one to show — it's a promise already made to the singer, where
 * orange is only something for the KJ to check. */
.queue-row.is-unavailable {
  border-color: #d92b2b;
  background-color: rgba(217, 43, 43, 0.12);
  box-shadow: inset -4px 0 0 #d92b2b;
}

.queue-row.is-unavailable.is-next {
  box-shadow: inset 3px 0 0 var(--rb-accent), inset -4px 0 0 #d92b2b;
}

/* Standing instruction under the song on a flagged row. */
.queue-row__note {
  font-size: 0.8rem;
  margin-top: 0.25rem;
  opacity: 0.9;
}

/* A guess rather than a fact — the possible double-booking. Muted on purpose:
 * it's a prompt to look, and first-name matching means it will sometimes be
 * wrong. Anything louder would train the KJ to ignore it. */
.queue-row__note--check {
  color: var(--rb-warning);
  opacity: 0.85;
}

.queue-row__handle {
  cursor: grab;
  text-align: center;
  font-size: 1.3rem;
  color: var(--rb-muted);
  user-select: none;
}

.queue-row__handle:active {
  cursor: grabbing;
}

.queue-row__pos {
  font-weight: 700;
  color: var(--rb-accent);
}

.queue-row__singer {
  font-size: 1.15rem;
  font-weight: 700;
}

/* A secondary line hung under something else — the singer behind a message,
   the retry count. Caption-sized on purpose. */
.queue-row__with {
  font-size: 0.85rem;
  color: var(--rb-text);
  opacity: 0.75;
}

/* The people sharing the turn, inline after the name that booked it. These are
   names the KJ reads off the screen and says into a mic, so they sit at the
   size of the name itself; only the weight drops, which keeps whose turn it is
   readable at a glance. The slash divides the two — the accompanist field is
   free text and regularly contains its own "and" or "&". */
.singer-with {
  font-weight: 400;
  opacity: 0.85;
}

/* The Now singing name is 2rem; proportional keeps the guests legible across
   the room without the line outgrowing the card. */
.now-singing__name .singer-with {
  font-size: 0.6em;
}

.queue-row__song {
  font-size: 1rem;
}

.queue-row__artist {
  font-size: 0.85rem;
  font-style: italic;
  opacity: 0.8;
}

.queue-row__actions {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.queue-row__actions .btn {
  min-width: 76px;
}

/* The three ordering controls, stacked into one column: the ▲/▼ nudges sit as a
   pair directly above Top. Grouping them costs the row no extra width — the
   column is as wide as Top alone, and the arrows split that width between them. */
.queue-row__move {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Centred, never stretched: an off-catalog row carries two extra buttons and
     wraps to a second line, which would otherwise pull this group apart. */
  align-self: center;
}

.queue-row__nudge {
  display: flex;
  gap: 2px;
}

.queue-row__nudge form {
  display: flex;
  flex: 1;
}

/* Arrows big enough to hit without aiming, paid for by trimming Top rather than
   by making every row taller — Top is the rarer press of the two. */
.queue-row__nudge .btn {
  min-width: 0;
  flex: 1;
  padding: 0.3rem 0;
  font-size: 0.7rem;
  line-height: 1;
}

.queue-row__top {
  padding: 0.15rem 0.5rem;
  font-size: 0.8rem;
}

/* SortableJS states */
.queue-row.sortable-ghost {
  opacity: 0.35;
  border-style: dashed;
}

.queue-row.sortable-chosen {
  background-color: #5c5c5c;
}

/* ---------- Badges ---------- */

.rb-badge {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.15rem 0.45rem;
  border-radius: 3px;
  vertical-align: middle;
}

.rb-badge--dupe {
  background-color: var(--rb-warning);
  color: #000;
}

.rb-badge--manual {
  background-color: var(--rb-panel);
  color: var(--rb-muted);
  border: 1px solid var(--rb-border);
}

.rb-badge--notified {
  background-color: var(--rb-success);
  color: #000;
}

.rb-badge--nophone {
  background-color: transparent;
  color: var(--rb-muted);
  border: 1px solid var(--rb-border);
}

/* Off-catalog songs. These three are the loudest badges on the board on
 * purpose: every other badge describes the rotation, while these mean the KJ
 * has something to go and do before the singer reaches the mic. */
.rb-badge--needed {
  background-color: #ff7a18;
  color: #000;
}

.rb-badge--unavailable {
  background-color: #d92b2b;
  color: #fff;
}

.rb-badge--acquired {
  background-color: var(--rb-success);
  color: #000;
}

/* More than one person on this turn — cue to have a second mic ready. Cool
 * blue on purpose: it sits outside the orange/red/green run above, which all
 * mean the KJ owes the singer something, and this one is only a fact about the
 * turn. */
.rb-badge--group {
  background-color: #2fa8d8;
  color: #000;
}

/* ---------- Tables ---------- */

.console-table {
  width: 100%;
  border-collapse: collapse;
}

.console-table th,
.console-table td {
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--rb-border);
  text-align: left;
  vertical-align: middle;
}

.console-table th {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--rb-muted);
}

.console-table tbody tr:hover {
  background-color: rgba(255, 255, 255, 0.03);
}

/* ---------- Show history ---------- */

/* The history table is read a rotation at a time, so each one is its own tbody
 * with a heading row. The rule above the heading is heavier than the row borders
 * inside it: the boundary between rotations is the thing being looked for, and at
 * a glance from a few feet away a same-weight line reads as just another row. */
.show-history__divider th {
  border-top: 3px solid var(--rb-border);
  border-bottom: 1px solid var(--rb-border);
  padding-top: 0.9rem;
  font-size: 0.95rem;
  text-transform: none;
  letter-spacing: 0;
  color: var(--rb-text);
}

.show-history__divider th > span {
  margin-left: 0.4rem;
  font-weight: 400;
  font-size: 0.8rem;
}

/* Alternating bands, one per rotation rather than one per row: the question the
 * page answers is which round a turn belonged to, so the block is what should
 * read as a unit from a few feet away. nth-of-type counts tbody elements, and
 * there is exactly one per rotation, so the bands alternate even if a rotation
 * number was skipped. The heavier rule above each heading stays — the tint says
 * these rows go together, the rule says where the seam is.
 *
 * Tinted rows get their own hover, a touch stronger than the untinted one: the
 * stock hover sits at the same weight as the band and would vanish on top of it.
 */
.show-history tbody:nth-of-type(even) tr {
  background-color: rgba(255, 255, 255, 0.04);
}

.show-history tbody:nth-of-type(even) tr:hover {
  background-color: rgba(255, 255, 255, 0.09);
}

/* The rotation being sung right now, on a show still open. An edge marker rather
 * than a colour of its own: background already carries which rotation a row
 * belongs to, and a third background in the same table would compete with both
 * the bands and the hover state. */
.show-history__rotation--running th,
.show-history__rotation--running td:first-child {
  box-shadow: inset 3px 0 0 var(--rb-accent);
}

.show-history__outcome {
  font-weight: 600;
}

.show-history__outcome--sang {
  color: var(--rb-success);
}

/* A turn nobody took. Muted rather than red: it's ordinary bookkeeping on any
 * given night, not something that went wrong. */
.show-history__outcome--missed {
  color: var(--rb-muted);
}

.show-history__outcome--live {
  color: var(--rb-text);
}

/* ---------- Misc ---------- */

.console-empty {
  padding: 2.5rem 1rem;
  text-align: center;
  color: var(--rb-muted);
}

/* Drops the 1500px cap so the card's `auto` margins below centre against the
 * window rather than against a left-aligned 1500px column. */
.console-main--centred {
  max-width: none;
}

.console-login {
  max-width: 380px;
  margin: 8vh auto;
}

@media (max-width: 900px) {
  .queue-row {
    grid-template-columns: 36px 1fr;
    row-gap: 0.5rem;
  }

  .queue-row__song,
  .queue-row__actions {
    grid-column: 2;
    justify-content: flex-start;
  }
}
