/* ---------- theme ---------- */

:root {
  color-scheme: light;
  --wall: #e9f2ee;
  --wall-2: #dcebe4;
  --ink: #22303e;
  --paper: #fff;
  --panel: #fff;
  --line: #cfdfd7;
  --hover: #dcebe4;
  --couch: #e9ad63;
  --couch-dark: #cd8845;
  --you: #2fa66a;
  --pawn-1: #3b7dd8;
  --pawn-2: #8e6fd8;
  --pawn-3: #e2698f;
  --pawn-4: #a978bd;
  --pawn-5: #2fa8a0;
  --pawn-6: #559bb7;
  --pawn-7: #4e9c74;
  --pawn-8: #5f7dd8;
  --action: #2f6fed;
  --action-deep: #2058c9;
  --live: #2fa66a;
  --warn: #d98e04;
  --danger: #d64541;
  --lcd: #1d2b22;
  --lcd-digits: #9de8bf;
  --stage: #101a2c;
  --frame: #22303e;
  --radius: 16px;
  --edge: color-mix(in srgb, var(--ink) 62%, var(--paper));
  --muted: color-mix(in srgb, var(--ink) 70%, var(--paper));
  --shadow: 0 3px 0 color-mix(in srgb, var(--ink) 13%, transparent);
  --spring: cubic-bezier(.3, 1.45, .45, 1);
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "Cascadia Mono", SFMono-Regular, Consolas, monospace;
}

html[data-theme=dark] {
  color-scheme: dark;
  --wall: #141e29;
  --wall-2: #0e1620;
  --ink: #dde8f3;
  --paper: #22303e;
  --panel: #1a2634;
  --line: #2b3d4f;
  --hover: #2b3d4f;
  --frame: #0a111a;
  --action: #4a84f2;
  --action-deep: #3a70d8;
  --live: #3fb97a;
  --warn: #e8a33d;
  --danger: #e25a52;
  --lcd: #0d1611;
}

html[data-theme=dark] .when-light,
html[data-theme=light] .when-dark {
  display: none;
}

/* ---------- base ---------- */

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

[hidden] {
  display: none !important;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--wall);
  color: var(--ink);
  font: 15px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
  transition: background-color .3s, color .3s;
}

main {
  display: grid;
  justify-items: center;
  padding: 8px 20px 64px;
}

h1 {
  margin: 0;
  font-size: 26px;
  line-height: 1.2;
}

p {
  margin: 0;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 3px solid var(--action);
  outline-offset: 2px;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
}

.i {
  flex: none;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.spacer {
  flex: 1;
}

.muted {
  color: var(--muted);
}

.cap {
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn);
}

/* ---------- controls ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 2px solid var(--edge);
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--shadow);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
  transition: transform .18s var(--spring), background-color .14s ease;
}

.btn:hover:not(:disabled) {
  background: var(--hover);
}

.btn:active:not(:disabled) {
  transform: translateY(2px);
}

.btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

.btn.is-primary {
  border-color: var(--action-deep);
  background: var(--action);
  color: #fff;
}

.btn.is-primary:hover:not(:disabled) {
  background: var(--action-deep);
}

.btn.is-danger {
  border-color: var(--danger);
  background: var(--danger);
  color: #fff;
}

.btn.is-big {
  padding: 12px 24px;
  font-size: 15px;
}

.btn[aria-expanded=true] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--wall);
}

.btn.select select {
  border: 0;
  background: transparent;
  font-weight: 700;
  cursor: pointer;
}

.btn.select option {
  background: var(--paper);
  color: var(--ink);
}

.icon-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(0 0 0 / .55);
  color: #fff;
  cursor: pointer;
  transition: background-color .14s ease;
}

.icon-btn:hover {
  background: rgb(255 255 255 / .25);
}

.seg {
  display: inline-flex;
  padding: 3px;
  border: 2px solid var(--edge);
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--shadow);
}

.seg button {
  padding: 4px 10px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.seg button[aria-pressed=true] {
  background: var(--ink);
  color: var(--wall);
}

.field {
  flex: 1;
  min-width: 0;
  padding: 9px 14px;
  border: 2px solid var(--edge);
  border-radius: 999px;
  background: var(--wall);
}

.btn.name::before {
  content: "";
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--c, var(--pawn-1));
}

.btn.name span {
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.badge {
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--action);
  color: #fff;
  font-size: 11px;
  line-height: 18px;
  text-align: center;
}

.spinner {
  width: 28px;
  height: 28px;
  border: 3px solid rgb(255 255 255 / .25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .9s linear infinite;
}

@keyframes spin {
  to {
    rotate: 1turn;
  }
}

.pill {
  padding: 2px 10px;
  border: 1.5px solid var(--edge);
  border-radius: 999px;
  font: 700 11px var(--mono);
}

.pill.is-bad {
  padding: 8px 14px;
  border-color: var(--danger);
  color: var(--danger);
  font: 700 13px var(--font);
}

.pill[data-route=p2p] {
  border-color: var(--live);
  color: var(--live);
}

.pill[data-route=relay] {
  border-color: var(--warn);
  color: var(--warn);
}

.lcd {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 3px solid var(--ink);
  border-radius: 12px;
  background: var(--lcd);
  color: var(--lcd-digits);
  font: 700 24px var(--mono);
  letter-spacing: .3em;
  text-indent: .15em;
  text-transform: uppercase;
}

button.lcd {
  cursor: pointer;
}

input.lcd {
  width: 13.1em;
  max-width: 100%;
  text-align: center;
}

input.lcd::placeholder {
  color: color-mix(in srgb, var(--lcd-digits) 30%, transparent);
}

.panel {
  width: min(100%, 880px);
  padding: 14px 18px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}

.toast {
  position: fixed;
  top: 72px;
  left: 50%;
  z-index: 30;
  max-width: 90vw;
  padding: 10px 18px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--wall);
  font-size: 13px;
  font-weight: 700;
  opacity: 0;
  translate: -50% -16px;
  pointer-events: none;
  transition: opacity .2s, translate .2s var(--spring);
}

.toast.is-on {
  opacity: 1;
  translate: -50% 0;
}

/* ---------- top bar ---------- */

.topbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 22px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--ink);
  font-size: 18px;
  text-decoration: none;
}

.brand .i {
  width: 30px;
  height: 30px;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
}

.status[data-state=online] .dot {
  background: var(--live);
}

.status[data-state=offline] .dot {
  background: var(--danger);
}

@media (max-width: 560px) {
  .topbar {
    gap: 8px;
    padding: 12px 14px;
  }

  /* Still read out, just not drawn: the dot's colour and the icon carry it. */
  .status span,
  #themeToggle span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  #themeToggle {
    padding: 8px 10px;
  }
}

/* ---------- home ---------- */

.door {
  display: grid;
  justify-items: center;
  gap: 18px;
  width: min(100%, 520px);
  margin-top: 8vh;
  padding: 36px 28px;
  text-align: center;
}

.door-logo {
  width: 56px;
  height: 56px;
  color: var(--action);
}

.join {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
}

/* ---------- room: stage ---------- */

.room {
  display: grid;
  justify-items: center;
  gap: 18px;
  width: min(100%, 1400px);
}

.stage {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
  gap: 10px;
  /* As wide as the columns want, but never so wide that the rows stop fitting the window height. */
  width: min(100%, calc(var(--cols, 1) * 480px + 480px),
    max(360px, calc((100vh - 280px) * 16 / 9 * var(--cols, 1) / var(--rows, 1))));
  padding: 12px;
  border-radius: 22px;
  background: var(--frame);
  box-shadow: 0 12px 30px rgb(0 0 0 / .25);
}

.stage[data-mode=spotlight] {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  width: min(100%, 1100px, max(360px, calc((100vh - 380px) * 16 / 9)));
}

.stage[data-mode=spotlight] .tile.is-focused {
  grid-column: 1 / -1;
  order: -1;
}

.stage-empty,
.tile {
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  background: var(--stage);
}

.stage-empty {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  padding: 20px;
  color: #9bb0c5;
  text-align: center;
}

.stage-empty .i {
  width: 48px;
  height: 48px;
}

.stage-empty .btn .i {
  width: 18px;
  height: 18px;
}

.stage-empty .btn {
  color: var(--ink);
}

/* Chat bubbles and flying reactions; never in the way of a click. */
.stage-overlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  overflow: hidden;
  border-radius: inherit;
  pointer-events: none;
}

.stage-chat {
  position: absolute;
  bottom: 60px;
  left: 20px;
  display: grid;
  justify-items: start;
  gap: 6px;
  max-width: min(420px, calc(100% - 40px));
  margin: 0;
  padding: 0;
  list-style: none;
}

.bubble {
  padding: 5px 12px;
  border-radius: 14px;
  background: rgb(0 0 0 / .72);
  color: #fff;
  font-size: 14px;
  overflow-wrap: anywhere;
  animation: bubble 6s both;
}

.bubble b {
  margin-right: 8px;
  color: color-mix(in srgb, var(--c) 60%, #fff);
}

@keyframes bubble {
  0% {
    opacity: 0;
    translate: 0 8px;
  }

  4%,
  88% {
    opacity: 1;
    translate: 0;
  }

  100% {
    opacity: 0;
  }
}

.fly {
  position: absolute;
  bottom: 12%;
  font-size: 40px;
  line-height: 1;
  animation: fly 2.4s ease-out both;
}

@keyframes fly {
  0% {
    opacity: 0;
    scale: .5;
  }

  12% {
    opacity: 1;
    scale: 1.15;
  }

  100% {
    opacity: 0;
    translate: 0 -260px;
  }
}

.stage-exit {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 4;
  display: none;
  width: 36px;
  height: 36px;
}

/* Theater mode: the streams take the whole window and nothing else is in the way. */
.is-theater {
  overflow: hidden;
}

.is-theater .stage {
  position: fixed;
  inset: 0;
  z-index: 20;
  grid-template-rows: repeat(var(--rows, 1), minmax(0, 1fr));
  width: auto;
  padding: 8px;
  border-radius: 0;
}

.is-theater .stage[data-mode=spotlight] {
  grid-template-rows: minmax(0, 1fr);
  grid-auto-rows: 104px;
  width: auto;
}

.is-theater .tile {
  aspect-ratio: auto;
  min-height: 0;
}

.is-theater .stage-exit {
  display: grid;
}

.tile {
  position: relative;
  margin: 0;
  overflow: hidden;
  container-type: inline-size;
}

.tile:fullscreen {
  aspect-ratio: auto;
  border-radius: 0;
}

.tile video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  cursor: pointer;
}

.tile-name {
  position: absolute;
  top: 8px;
  left: 8px;
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: calc(100% - 16px);
  padding: 2px 9px;
  border-radius: 999px;
  background: rgb(0 0 0 / .55);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}

.tile-name::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--c);
}

/* Why there is no picture: still connecting, or the connection to its sender dropped. */
.tile-status {
  position: absolute;
  inset: 0;
  display: none;
  place-content: center;
  justify-items: center;
  gap: 12px;
  padding: 16px;
  color: #c9d6e3;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  pointer-events: none;
}

.tile[data-state=waiting] .tile-status,
.tile[data-state=lost] .tile-status {
  display: grid;
}

.tile[data-state=lost] .tile-status {
  background: rgb(0 0 0 / .6);
  color: #fff;
}

.tile[data-state=lost] .spinner {
  border-top-color: var(--warn);
}

/* The browser refused to play sound before the first click on the page. */
.tile-unblock {
  position: absolute;
  top: 50%;
  left: 50%;
  display: none;
  translate: -50% -50%;
  white-space: nowrap;
}

.tile.is-blocked .tile-unblock {
  display: inline-flex;
}

.tile-controls {
  position: absolute;
  inset: auto 0 0;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 30px 10px 8px;
  background: linear-gradient(transparent, rgb(0 0 0 / .7));
  opacity: 0;
  transition: opacity .15s;
}

.tile:hover .tile-controls,
.tile:focus-within .tile-controls,
.tile.is-muted:not(.is-self) .tile-controls {
  opacity: 1;
}

/* Nothing to hover with on a touch screen. */
@media (hover: none) {
  .tile-controls {
    opacity: 1;
  }
}

.tile-controls .icon-btn {
  background: transparent;
}

.tile-controls .icon-btn:hover {
  background: rgb(255 255 255 / .25);
}

.vol {
  width: 84px;
  accent-color: #fff;
  cursor: pointer;
}

.tile.is-muted .when-on,
.tile:not(.is-muted) .when-muted,
.tile.is-self [data-act=mute],
.tile.is-self [data-act=pip],
.tile.is-self .vol,
.no-pip [data-act=pip] {
  display: none;
}

/* A thumbnail has no room for the slider. */
@container (max-width: 260px) {
  .vol {
    display: none;
  }
}

.tile.is-muted [data-act=mute] {
  background: var(--danger);
}

.stage-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.stage-note {
  font-size: 13px;
  text-align: center;
}

/* ---------- room: couch ---------- */

.lounge {
  display: grid;
  justify-items: center;
  gap: 12px;
  margin-top: 22px;
}

.lounge-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

/* Drawn back to front: two legs, the dark frame with its arms, the lighter cushions. Members sit on top. */
.couch {
  position: relative;
  padding: 0 34px 20px;
  background:
    linear-gradient(var(--frame) 0 0) 30px 100% / 6px 12px no-repeat,
    linear-gradient(var(--frame) 0 0) calc(100% - 30px) 100% / 6px 12px no-repeat;
}

.couch::before,
.couch::after {
  content: "";
  position: absolute;
}

.couch::before {
  inset: 34px 0 7px;
  border-radius: 20px 20px 14px 14px;
  background: var(--couch-dark);
}

.couch::after {
  inset: 22px 20px 14px;
  border-radius: 22px 22px 10px 10px;
  background: var(--couch);
}

.couch-seats {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: center;
  gap: 4px;
  min-width: 140px;
}

.pawn {
  position: relative;
  display: grid;
  justify-items: center;
  width: 70px;
  transition: opacity .2s;
}

/* No connection to this member right now. */
.pawn.is-lost {
  opacity: .45;
}

.pawn-head {
  position: relative;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--c);
}

/* two eyes */
.pawn-head::after {
  content: "";
  position: absolute;
  inset: 8px 5px auto;
  height: 4px;
  background: radial-gradient(circle, #16202b 1.5px, transparent 1.9px) 0 0 / 50% 100%;
}

.pawn-body {
  width: 36px;
  height: 27px;
  margin: 2px 0 4px;
  border-radius: 18px 18px 6px 6px;
  background: var(--c);
}

.pawn-name {
  max-width: 100%;
  padding: 1px 7px;
  border-radius: 7px;
  background: var(--ink);
  color: var(--wall);
  font-size: 11px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* the first one in is the host */
.pawn:first-child .pawn-head::before {
  content: "\1F451";
  position: absolute;
  bottom: 100%;
  left: 50%;
  translate: -50%;
  font-size: 12px;
  line-height: 1;
}

.pawn.is-you::before {
  content: "";
  position: absolute;
  top: -24px;
  border: 6px solid transparent;
  border-top-color: var(--you);
}

.pawn.is-live .pawn-head {
  box-shadow: 0 0 0 2px var(--wall), 0 0 0 4px var(--danger);
}

/* A reaction rising from whoever sent it. */
.pawn-pop {
  position: absolute;
  bottom: 100%;
  z-index: 2;
  font-size: 26px;
  line-height: 1;
  pointer-events: none;
  animation: pop 1.8s ease-out both;
}

@keyframes pop {
  0% {
    opacity: 0;
    scale: .4;
  }

  15% {
    opacity: 1;
    scale: 1.2;
  }

  100% {
    opacity: 0;
    translate: 0 -34px;
  }
}

@keyframes blink {
  0%,
  96%,
  100% {
    scale: 1;
  }

  98% {
    scale: 1 .1;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .pawn-head::after {
    animation: blink 5.2s infinite;
  }

  /* not everybody at once */
  .pawn:nth-child(2n) .pawn-head::after {
    animation-delay: -1.7s;
  }

  .pawn:nth-child(3n) .pawn-head::after {
    animation-delay: -3.3s;
  }
}

.couch-count .divider {
  width: 1.5px;
  height: 14px;
  background: var(--edge);
}

.reactions {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 2px solid var(--edge);
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--shadow);
  transition: opacity .15s;
}

.reactions[inert] {
  opacity: .55;
}

.reactions button {
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  transition: transform .18s var(--spring), background-color .14s ease;
}

.reactions button:hover {
  background: var(--hover);
  transform: scale(1.2);
}

/* ---------- room: panels ---------- */

.room-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.role {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}

.chat-log {
  display: grid;
  gap: 4px;
  max-height: 240px;
  margin: 0 0 12px;
  padding: 0;
  overflow-y: auto;
  list-style: none;
  font-size: 14px;
  overflow-wrap: anywhere;
}

.chat-log:empty {
  display: none;
}

.chat-log b {
  margin-right: 8px;
  color: var(--c);
}

.chat-form {
  display: flex;
  gap: 10px;
}

.stats {
  display: grid;
  gap: 12px;
  width: min(100%, 880px);
}

.meter {
  display: grid;
  gap: 12px;
}

.meter header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 13px;
}

.meter summary {
  width: fit-content;
  list-style: none;
}

.meter details[open] summary {
  margin-bottom: 12px;
}

.cells {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px 18px;
}

.cell b {
  display: block;
  font: 700 13px var(--mono);
  overflow-wrap: anywhere;
}

.cell small {
  color: var(--muted);
  font-size: 11px;
}

dialog.panel {
  width: min(92vw, 360px);
  color: var(--ink);
}

dialog::backdrop {
  background: rgb(0 0 0 / .5);
}

dialog form {
  display: grid;
  gap: 12px;
}

dialog menu {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-start;
  gap: 10px;
  margin: 0;
  padding: 0;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }

  /* Bubbles and reactions still show up and go away, they just stand still meanwhile. */
  .bubble,
  .fly,
  .pawn-pop {
    animation: none;
  }

  .spinner {
    animation-duration: 3s;
  }
}
