/* The player tray (left) and the action tray (right): cream panels beside the monitor.
   docs/ui-spec.md § Visuals: Player tray, Action tray. */
.tray {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  /* Beside the monitor a tray is at least as tall as the monitor (the grid row stretches it; the
     stage reserves the cloud's margin above and below the monitor, so the tray takes the same
     margin) and never shorter than its own content: if the content is taller the row grows and
     the PAGE scrolls. There is no inner scroller to hide anything in. */
  margin-block: var(--cloud-margin);
  padding: 14px 14px 12px;
  border: 2px solid var(--paper-edge);
  border-radius: 14px;
  background: linear-gradient(to bottom, #fbf6e6, var(--paper));
  box-shadow: 0 4px 0 var(--paper-edge), 0 10px 18px rgba(20, 50, 80, 0.22);
  color: var(--ink);
  position: relative;
  z-index: 1;
}

.tray-head {
  margin: 0 0 10px;
  font-size: 15px;
}

/* The title is a button so it can collapse the tray on narrow screens; beside the monitor
   trays.js makes it inert plain text (disabled, role none, no aria-expanded). */
.tray-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin: 0;
  padding: 0 0 8px;
  border: 0;
  border-bottom: 2px dotted var(--paper-edge);
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-align: left;
  cursor: default;
}

.tray-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

/* Below 1100 px the trays stack under the monitor and their titles become the toggles. */
@media (max-width: 1099px) {
  .tray {
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    box-shadow: 0 3px 0 var(--paper-edge), 0 8px 14px rgba(20, 50, 80, 0.2);
  }

  .tray-title {
    cursor: pointer;
  }

  .tray-title::after {
    content: "";
    width: 8px;
    height: 8px;
    margin-right: 4px;
    border-right: 2px solid var(--ink-dim);
    border-bottom: 2px solid var(--ink-dim);
    transform: rotate(45deg);
    transition: transform 0.15s;
  }

  .tray[data-collapsed] .tray-head {
    margin-bottom: 0;
  }

  .tray[data-collapsed] .tray-title {
    padding-bottom: 0;
    border-bottom: 0;
  }

  .tray[data-collapsed] .tray-title::after {
    transform: rotate(-45deg);
  }

  .tray[data-collapsed] .tray-body {
    display: none;
  }
}

/* ---- Player tray ---- */
.player-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.player {
  border-bottom: 1px solid var(--paper-shade);
}

.player:last-child {
  border-bottom: 0;
}

/* Each player is a button that opens the Real Name dialog (trays/real-name.js). */
.player-item {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr);
  column-gap: 10px;
  align-items: center;
  width: 100%;
  margin: 0;
  padding: 6px 4px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.player-item:hover,
.player-item:focus-visible {
  background: var(--paper-shade);
}

.player-dot {
  grid-row: 1 / span 2;
  justify-self: center;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--online);
  box-shadow: 0 0 0 2px rgba(47, 209, 88, 0.25), 0 0 6px var(--online);
}

/* Hovered or focused, the green light becomes a pencil: "edit". A mask over the ink colour, so no
   image file (the SVG is a data: URI, which the CSP's img-src allows). */
.player-item:hover .player-dot,
.player-item:focus-visible .player-dot {
  width: 12px;
  height: 12px;
  border-radius: 0;
  background: var(--ink);
  box-shadow: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M11.3 1.3a1 1 0 0 1 1.4 0l2 2a1 1 0 0 1 0 1.4L5.4 14H2v-3.4z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M11.3 1.3a1 1 0 0 1 1.4 0l2 2a1 1 0 0 1 0 1.4L5.4 14H2v-3.4z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.player-name {
  overflow: hidden;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.player-user {
  overflow: hidden;
  color: var(--ink-dim);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A real name is user input: isolated, so right-to-left text cannot reorder the "(username)" after it. */
.player-real {
  unicode-bidi: isolate;
}

.player-empty {
  margin: 8px 4px;
  color: var(--ink-dim);
  font-style: italic;
}

.tray-foot {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 2px dotted var(--paper-edge);
  color: var(--ink-dim);
  font-size: 12px;
}

.tray-foot p {
  margin: 0 0 6px;
}

/* The list flashes once when it changes; the script adds and removes .is-updated. */
.player-list.is-updated {
  animation: tray-flash 0.9s ease-out;
}

@keyframes tray-flash {
  0% {
    background: rgba(255, 204, 0, 0.45);
  }
  100% {
    background: transparent;
  }
}

.dns-warn {
  margin: 8px 0 0;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--warn-bg);
  color: var(--warn-ink);
  font-size: 12px;
  font-weight: 600;
}

/* Once DNS points at the server and nobody is online yet, the notice is good news: the same panel in green
   (trays/players.js adds .is-ok; the text and the rule are in docs/ui-spec.md § Visuals). */
.dns-warn.is-ok {
  background: var(--ok-bg);
  color: var(--ok-ink);
}

/* ---- Action tray ---- */
.actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 2px 0 6px;
  list-style: none;
}

.action {
  position: relative;
}

/* A line between two groups of keys, and one after the last key so the notices always sit below a line (trays/actions.js,
   from the server's `group`). It is the tray title's dotted rule. Not a key: no text, no hover, not focusable. */
.action-sep {
  height: 0;
  margin: 0;
  border-top: 2px dotted var(--paper-edge);
  list-style: none;
}

/* The last line closes the keys, and the list's own bottom padding (room for the last key's shadow) is not needed under it. */
.action-sep:last-child {
  margin-bottom: -6px;
}

/* Chunky keycap: raised top, a hard shadow underneath that flattens when pressed. */
.keycap {
  display: block;
  width: 100%;
  padding: 11px 12px 12px;
  border: 1px solid var(--key-edge);
  border-radius: 10px;
  background: linear-gradient(to bottom, var(--key-top), var(--key-bottom));
  box-shadow: 0 4px 0 var(--key-edge), 0 6px 8px rgba(60, 45, 20, 0.22), inset 0 1px 0 #fff;
  color: var(--ink);
  font-size: 14px;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
  transition: transform 0.05s, box-shadow 0.05s;
}

.keycap:hover {
  background: linear-gradient(to bottom, #fffaea, #ebe2c8);
}

.keycap:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--key-edge), 0 2px 3px rgba(60, 45, 20, 0.2), inset 0 1px 0 #fff;
}

/* The danger keycap (Force Shutdown) is red. */
.keycap--danger {
  border-color: var(--key-danger-edge);
  background: linear-gradient(to bottom, var(--key-danger-top), var(--key-danger-bottom));
  box-shadow: 0 4px 0 var(--key-danger-edge), 0 6px 8px rgba(120, 20, 10, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.45);
  color: #fff;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
}

.keycap--danger:hover {
  background: linear-gradient(to bottom, #ff6a5e, #d42d22);
}

.keycap--danger:active {
  box-shadow: 0 1px 0 var(--key-danger-edge), 0 2px 3px rgba(120, 20, 10, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.45);
}

/* Disabled (aria-disabled so it can still be hovered and focused to read the reason): greyed. */
.keycap:disabled,
.keycap[aria-disabled="true"] {
  border-color: #c4bda9;
  background: linear-gradient(to bottom, #e6e2d6, #d6d1c2);
  box-shadow: 0 1px 0 #bdb6a1, inset 0 1px 0 rgba(255, 255, 255, 0.6);
  color: #8f8977;
  text-shadow: none;
  cursor: not-allowed;
  transform: translateY(3px);
}

.keycap--danger:disabled,
.keycap--danger[aria-disabled="true"] {
  border-color: #c7aaa5;
  background: linear-gradient(to bottom, #e3cdc9, #d4bcb7);
  color: #987f7b;
}

/* The reason a button is disabled, referenced from it by aria-describedby. It opens IN THE FLOW
   directly under its own button, inside the same .action row: the keys below move down, and it never
   lies over another keycap, so it can never take that keycap's clicks. Shown on hover, on KEYBOARD
   focus (:focus-visible, so a mouse click that leaves focus on a keycap which then turns disabled
   does not pin it open), and while reason-tips.js has marked the row .is-showing-reason (a click or
   tap on a disabled button). Being part of the row, it stays open while the pointer is over it
   (WCAG 1.4.13); Esc dismisses it (.is-dismissed) until the pointer or focus leaves the row.
   Showing a reason moves only the rows below the one that shows it, never that row, so hovering
   cannot make it flicker. */
.keycap-reason {
  display: none;
  margin-top: 6px;
  padding: 6px 9px;
  border-radius: 6px;
  background: #2a2417;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
  color: #f7f0dc;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.3;
}

.action:hover .keycap-reason,
.keycap:focus-visible + .keycap-reason,
.action.is-showing-reason .keycap-reason {
  display: block;
}

.action.is-dismissed .keycap-reason {
  display: none;
}

.status-lines {
  margin: 12px 0 0;
}

.status-line {
  margin: 0 0 6px;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--paper-shade);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.35;
}

.tray-actions .tray-foot {
  margin-top: auto;
}

.tray-foot .link-button {
  padding: 0;
  border: 0;
  background: none;
  color: #1a5fb4;
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* A keycap that shows a state with a light (the EC2 auto-shutdown key, owner ruling 2026-10-01): the light sits
   before the text, centred on it also when the text wraps to two lines. The light is the player tray's dot (10 px,
   the same glow) in green or red, and dims with the rest of a disabled key. */
.keycap--lit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
}

.key-light {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.key-light--green {
  background: var(--online);
  box-shadow: 0 0 0 2px rgba(47, 209, 88, 0.25), 0 0 6px var(--online);
}

.key-light--red {
  background: var(--led-red);
  box-shadow: 0 0 0 2px rgba(255, 59, 48, 0.25), 0 0 6px var(--led-red);
}

.keycap[aria-disabled="true"] .key-light {
  opacity: 0.45;
  box-shadow: none;
}

/* A keycap whose action has been sent and is waiting for the server's answer. */
.keycap[aria-busy="true"] {
  opacity: 0.7;
  cursor: progress;
}
