/* Host screen — read from three metres away.
 *
 * Every size below is in vmin so the layout holds from a 24" monitor to a 65" TV
 * without breakpoints. Nothing here is sized in px except borders, which must stay
 * hairline-crisp rather than scale into slabs. */

#grid {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}

.host {
  overflow: hidden;
}

/* ------------------------------------------------------------------- topbar */

/* One document, two views. `/` and `/host` are the same page so that clicking Host
   is a gesture in THIS document — fullscreen is granted and, because nothing
   navigates, it is never dropped. */
.host[data-view='landing'] .topbar,
.host[data-view='landing'] #stage {
  display: none;
}

/* The game owns the whole frame, clock and standings included. Leaving the shell's
   chrome on top of it collides two HUDs in the same corner. */
.host[data-screen='playing'] .topbar {
  display: none;
}

.topbar {
  position: fixed;
  z-index: 3;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: 2.2vmin 3vmin;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

/* Four hard squares: the mark is the grid, at 1:1. */
.brand-mark {
  width: 2.2vmin;
  height: 2.2vmin;
  background:
    linear-gradient(var(--live), var(--live)) 0 0 / 45% 45% no-repeat,
    linear-gradient(var(--chalk), var(--chalk)) 100% 0 / 45% 45% no-repeat,
    linear-gradient(var(--chalk), var(--chalk)) 0 100% / 45% 45% no-repeat,
    linear-gradient(var(--dim), var(--dim)) 100% 100% / 45% 45% no-repeat;
}

.brand-name {
  font-family: var(--label);
  font-size: 1.5vmin;
  letter-spacing: 0.22em;
  color: var(--dim);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-left: auto;
}

/* Square, quiet, and the same height as the chip beside it. */
.icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.6vmin;
  height: 3.6vmin;
  padding: 0.7vmin;
  color: var(--dim);
  background: var(--panel);
  border: var(--border);
  border-radius: 0;
  cursor: pointer;
}

.icon-btn:hover {
  color: var(--live);
  border-color: var(--live);
}

.icon-btn svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

/* One button, two states — the icon says what the click will do next. */
.icon-btn .ic-compress,
.host[data-full='true'] .icon-btn .ic-expand {
  display: none;
}

.host[data-full='true'] .icon-btn .ic-compress {
  display: block;
}

.code-chip {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  padding: 0.6vmin 1.4vmin;
  border: var(--border);
  background: var(--panel);
}

.code-chip b {
  font-family: var(--display);
  font-size: 2.4vmin;
  letter-spacing: 0.12em;
}

.link-state {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--label);
  font-size: 1.2vmin;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}

.link-state i {
  width: 1.1vmin;
  height: 1.1vmin;
  background: var(--dim);
}

.link-state[data-state='open'] {
  color: var(--live);
}
.link-state[data-state='open'] i {
  background: var(--live);
}
.link-state[data-state='reconnecting'],
.link-state[data-state='connecting'] {
  color: var(--warn);
}
.link-state[data-state='reconnecting'] i,
.link-state[data-state='connecting'] i {
  background: var(--warn);
  animation: blink 0.9s steps(1, end) infinite;
}
.link-state[data-state='refused'],
.link-state[data-state='closed'] {
  color: var(--dead);
}
.link-state[data-state='refused'] i,
.link-state[data-state='closed'] i {
  background: var(--dead);
}

/* -------------------------------------------------------------------- stage */

#stage {
  position: relative;
  z-index: 2;
  height: 100%;
  display: grid;
}

.screen {
  grid-area: 1 / 1;
  min-height: 0;
  padding: 9vmin 5vmin 4vmin;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3vmin;
}

/* ------------------------------------------------------------------ pairing */

.pair-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: 3.4vmin;
  letter-spacing: 0.01em;
  color: var(--chalk);
  text-align: center;
}

.pair-foot {
  margin: 0;
  font-size: 1.6vmin;
  color: var(--dim);
}

.pair-grid {
  display: flex;
  align-items: stretch;
  gap: 3vmin;
}

/* space-between, not center: it puts both eyebrows on one line and both captions on
   another, so the two panels read as a pair rather than two unrelated boxes. */
.pair-code,
.pair-qr {
  padding: 3vmin 4vmin;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 2.4vmin;
  box-shadow: var(--drop-lg);
}

/* The thesis of the whole product, at the size it deserves. */
.code {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 15vmin;
  line-height: 0.92;
  letter-spacing: 0.1em;
  text-indent: 0.1em; /* balance the trailing letter-space */
  color: var(--chalk);
  text-shadow: 0.6vmin 0.6vmin 0 rgba(0, 0, 0, 0.6);
}

.code-where {
  margin: 0;
  font-size: 1.5vmin;
  color: var(--dim);
}

.code-where b {
  color: var(--chalk);
  font-weight: 500;
}

.pair-or {
  display: flex;
  align-items: center;
  font-family: var(--label);
  font-size: 1.4vmin;
  color: var(--dimmer);
  text-transform: uppercase;
  letter-spacing: 0.2em;
}

.qr-frame {
  padding: 1.2vmin;
  background: var(--chalk);
  line-height: 0;
}

.qr-frame img {
  display: block;
  width: 22vmin;
  height: 22vmin;
}


/* -------------------------------------------------------------------- lobby */

/* Sized to its content and centred over the floor, rather than stretched to the
   viewport. A full-height panel next to two short cards reads as a broken layout;
   a centred block reads as a HUD sitting on the grid, which is the intent. */
.lobby {
  display: grid;
  grid-template-columns: minmax(28vmin, 34vmin) 1fr;
  gap: 3vmin;
  align-items: start;
  width: 100%;
  max-width: 170vmin;
  max-height: 100%;
  margin: 0 auto;
}

.lobby-left {
  padding: 2.4vmin;
  display: flex;
  flex-direction: column;
  gap: 2vmin;
  max-height: 78vmin;
  min-height: 0;
}

.lobby-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: var(--border);
  padding-bottom: 1.2vmin;
}

.lobby-head .eyebrow {
  font-size: 1.3vmin;
}

.count {
  font-family: var(--display);
  font-size: 2vmin;
  color: var(--chalk);
}

.players {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.2vmin;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.player {
  display: grid;
  grid-template-columns: 6vmin 1fr auto;
  align-items: center;
  gap: 1.4vmin;
  padding: 1vmin;
  border: 2px solid var(--line);
  background: var(--panel-2);
  /* The player's hue is carried on one hard edge, not a wash. */
  border-left-width: 0.8vmin;
}

.player[data-off='true'] {
  opacity: 0.42;
}

.player-face {
  width: 6vmin;
  height: 6vmin;
  border: 2px solid var(--void);
}

.player-name {
  font-family: var(--display);
  font-size: 2.2vmin;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.player-tag {
  font-family: var(--label);
  font-size: 1vmin;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
}

.player-badge {
  font-family: var(--label);
  font-size: 0.95vmin;
  letter-spacing: 0.1em;
  padding: 0.4vmin 0.7vmin;
  border: 2px solid currentColor;
  text-transform: uppercase;
}

.players-empty {
  margin: 0;
  padding: 2vmin 0;
  font-size: 1.5vmin;
  color: var(--dim);
  text-align: center;
}

.join-chip {
  display: flex;
  gap: 1.4vmin;
  align-items: center;
  padding-top: 1.6vmin;
  border-top: var(--border);
}

.join-chip img {
  width: 9vmin;
  height: 9vmin;
  background: var(--chalk);
  padding: 0.4vmin;
}

.join-chip .eyebrow {
  font-size: 1vmin;
}

.join-code {
  margin: 0.3vmin 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 3.4vmin;
  letter-spacing: 0.1em;
  line-height: 1;
}

.join-url {
  margin: 0;
  font-size: 1.1vmin;
  color: var(--dim);
}

/* ------------------------------------------------------------------- picker */

.lobby-right {
  display: flex;
  flex-direction: column;
  gap: 2vmin;
  min-height: 0;
}

.picker-head {
  display: flex;
  align-items: baseline;
  gap: 2vmin;
}

.pick-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 3.2vmin;
}

.pick-sub {
  margin: 0;
  font-size: 1.5vmin;
  color: var(--dim);
}

/* auto-fit, not auto-fill: with two games the cards claim the whole column instead of
   huddling top-left beside two phantom empty tracks. */
.games {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(44vmin, 100%), 1fr));
  gap: 2.4vmin;
  align-content: start;
  overflow-y: auto;
  min-height: 0;
}

.game {
  display: flex;
  flex-direction: column;
  gap: 1.6vmin;
  min-height: 34vmin;
  padding: 3vmin;
  background: var(--panel);
  border: var(--border);
  box-shadow: var(--drop);
  transition: transform 80ms steps(2), border-color 80ms steps(2);
}

.game[data-picked='true'] {
  border-color: var(--live);
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.55);
}

.game[data-ready='false'] {
  opacity: 0.5;
}

.game-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1vmin;
}

.game-name {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 3.6vmin;
}

.game-cap {
  font-family: var(--label);
  font-size: 1.1vmin;
  letter-spacing: 0.08em;
  color: var(--live);
  white-space: nowrap;
}

.game-blurb {
  margin: 0;
  font-size: 1.75vmin;
  line-height: 1.6;
  color: var(--dim);
}

.game-meta {
  display: flex;
  align-items: center;
  gap: 1vmin;
  margin-top: auto;
  padding-top: 1.2vmin;
  border-top: 2px solid var(--line);
}

/* Control difficulty as three cells, filled. Faster to read than a word. */
.pips {
  display: flex;
  gap: 0.4vmin;
}

.pips i {
  width: 1.2vmin;
  height: 1.2vmin;
  border: 2px solid var(--line-bright);
}

.pips i[data-on='true'] {
  background: var(--warn);
  border-color: var(--warn);
}

.game-diff {
  font-family: var(--label);
  font-size: 1.05vmin;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
}

.game-gate {
  margin-left: auto;
  font-size: 1.2vmin;
  color: var(--warn);
  text-align: right;
}

/* --------------------------------------------------------------------- play */

.play {
  padding: 0;
  display: block;
}

#game-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* ------------------------------------------------------------------ results */

.results-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 5vmin;
}

.standings {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.2vmin;
  width: min(80vmin, 90%);
}

.standing {
  display: grid;
  grid-template-columns: 4vmin 7vmin 1fr auto;
  align-items: center;
  gap: 1.6vmin;
  padding: 1.2vmin 2vmin;
  background: var(--panel);
  border: var(--border);
  border-left-width: 0.8vmin;
}

.standing-rank {
  font-family: var(--label);
  font-size: 1.6vmin;
  color: var(--dim);
}

.standing img {
  width: 7vmin;
  height: 7vmin;
  border: 2px solid var(--void);
}

.standing-name {
  font-family: var(--display);
  font-size: 2.6vmin;
  font-weight: 600;
}

.standing-score {
  font-family: var(--display);
  font-size: 3.2vmin;
  font-weight: 700;
}

.results-foot {
  margin: 0;
  font-size: 1.6vmin;
  color: var(--dim);
}

/* Narrow screens: someone will open /host on a laptop to test. */
@media (max-aspect-ratio: 1/1) {
  .lobby {
    grid-template-columns: 1fr;
  }
  .pair-grid {
    flex-direction: column;
    align-items: center;
  }
  .code {
    font-size: 20vmin;
  }
}


/* ------------------------------------------------------- now playing (shell) */

/* Bottom-left, above everything including a running game: the room should always be
   able to see what is playing and silence it without leaving the game. */
.nowplaying {
  position: fixed;
  z-index: 6;
  left: 2vmin;
  bottom: 2vmin;
  display: flex;
  align-items: center;
  gap: 1.2vmin;
  padding: 1vmin 1.6vmin 1vmin 1vmin;
  background: var(--panel);
  border: var(--border);
  box-shadow: var(--drop);
  max-width: 40vmin;
}

.np-toggle {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 0.3vmin;
  width: 3.4vmin;
  height: 3.4vmin;
  padding: 0.6vmin;
  background: var(--void);
  border: 2px solid var(--line);
  border-radius: 0;
  cursor: pointer;
}

.np-bars {
  display: flex;
  align-items: flex-end;
  gap: 0.3vmin;
  height: 100%;
}

.np-bars i {
  width: 0.45vmin;
  height: 30%;
  background: var(--dimmer);
}

/* The bars move only while sound is actually coming out — it is a readout, not decor. */
.nowplaying[data-state='playing'] .np-bars i {
  background: var(--live);
  animation: eq 0.9s steps(4, end) infinite;
}
.nowplaying[data-state='playing'] .np-bars i:nth-child(2) { animation-delay: 0.15s; }
.nowplaying[data-state='playing'] .np-bars i:nth-child(3) { animation-delay: 0.3s; }
.nowplaying[data-state='playing'] .np-bars i:nth-child(4) { animation-delay: 0.45s; }

.nowplaying[data-state='muted'] .np-bars i {
  background: var(--dead);
  height: 30%;
}

@keyframes eq {
  0%, 100% { height: 25%; }
  25% { height: 100%; }
  50% { height: 55%; }
  75% { height: 80%; }
}

.np-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.np-label {
  font-family: var(--label);
  font-size: 0.95vmin;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

.nowplaying[data-state='idle'] .np-label::after {
  content: ' — tap to start';
  color: var(--warn);
}

.nowplaying[data-state='muted'] .np-label::after {
  content: ' — muted';
  color: var(--dead);
}

.np-title {
  font-family: var(--display);
  font-size: 1.7vmin;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --------------------------------------------------------- end-round dialog */

/* Sits over the frozen game rather than replacing it, so everyone can see the round
   is paused and exactly what they are about to lose. */
.exitask {
  position: fixed;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2vmin;
  background: rgba(10, 12, 18, 0.86);
}

.exitask-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.6vmin;
  padding: 5vmin 7vmin;
  background: var(--panel);
  border: var(--border-bright);
  box-shadow: var(--drop-lg);
}

.exitask-title {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 4.4vmin;
  text-align: center;
}

.exitask-sub {
  margin: 0;
  font-size: 1.7vmin;
  color: var(--dim);
  text-align: center;
}

.exitask-keys {
  font-family: var(--label);
  font-size: 1.1vmin;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dimmer);
}


/* The address someone needs to type on the TV instead. Big, and the only thing on the
   card that looks like something to act on. */
.fatal-url {
  margin: 1vmin 0 0;
  padding: 1.2vmin 2vmin;
  font-family: var(--display);
  font-weight: 700;
  font-size: 3vmin;
  color: var(--live);
  background: var(--void);
  border: 2px solid var(--live);
  word-break: break-all;
  text-align: center;
}
