/*
 * Farboard styles.
 *
 * The board is a square CSS grid sized against both viewport dimensions so it
 * always fits without scrolling, on a phone held in either orientation.
 */

:root {
  --bg: #302e2b;
  --panel: #262421;
  --panel-raised: #3a3835;
  --border: #46443f;
  --text: #f1f0ee;
  --text-dim: #a7a29a;
  --accent: #81b64c;
  --accent-dark: #6a9a3c;
  --warn: #e0a03c;
  --danger: #d4593f;

  --sq-light: #eeeed2;
  --sq-dark: #769656;
  --sq-highlight: rgba(247, 236, 91, 0.55);
  --sq-select: rgba(247, 236, 91, 0.7);
  --sq-preview: rgba(224, 160, 60, 0.75);

  --radius: 10px;
  --board-size: min(92vw, calc(100vh - 320px), 560px);
}

* {
  box-sizing: border-box;
}

/* Components below set their own `display`, which would otherwise outrank
   the browser's rule for the hidden attribute. */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    sans-serif;
  font-size: 15px;
  line-height: 1.45;
  padding: 0 16px 24px;
  -webkit-text-size-adjust: 100%;
}

h1,
h2 {
  margin: 0;
  font-weight: 600;
}

/* ------------------------------------------------------------------ header */

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  max-width: 1040px;
  margin: 0 auto;
  padding: 16px 0;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand-mark {
  font-size: 34px;
  line-height: 1;
  color: var(--accent);
}

.app-header h1 {
  font-size: 20px;
  letter-spacing: 0.2px;
}

.tagline {
  margin: 2px 0 0;
  color: var(--text-dim);
  font-size: 13px;
}

.header-actions {
  display: flex;
  gap: 8px;
}

/* ------------------------------------------------------------------ layout */

.layout {
  max-width: 1040px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: auto minmax(240px, 300px);
  gap: 20px;
  align-items: start;
  justify-content: center;
}

.board-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: var(--board-size);
}

/* ------------------------------------------------------------ player strip */

.player-strip {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 34px;
  padding: 4px 10px;
  background: var(--panel);
  border: 1px solid transparent;
  border-radius: var(--radius);
}

.player-strip.to-move {
  border-color: var(--accent);
}

.player-id {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  font-size: 14px;
  white-space: nowrap;
}

.dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid #15140f;
}

.dot.white {
  background: #f7f6f3;
}

.dot.black {
  background: #3f3d39;
  border-color: #6e6b64;
}

.captured {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  flex: 1;
  min-width: 0;
  min-height: 24px;
  overflow: hidden;
}

/* Every glyph gets the same fixed box, centred, so the differing widths and
   baselines of the fallback chess fonts (Safari especially) cannot make the
   row look ragged. The narrow box overlaps the glyphs a little so a full set
   still fits on a phone. */
.taken {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 24px;
  font-size: 19px;
  line-height: 1;
  font-family: 'Segoe UI Symbol', 'Apple Symbols', 'DejaVu Sans', sans-serif;
  overflow: visible;
}

.taken.white {
  color: #f7f6f3;
  text-shadow: 0 0 1px #14130f, 0 0 1px #14130f;
}

.taken.black {
  color: #6f6b64;
}

.lead {
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  white-space: nowrap;
}

/* ------------------------------------------------------------------- board */

.board-wrap {
  position: relative;
  width: var(--board-size);
  height: var(--board-size);
}

/* With no game in progress the board is only a backdrop to the home card. */
.board-panel.idle .board-wrap,
.board-panel.idle .player-strip {
  opacity: 0.45;
  pointer-events: none;
}

/* Cards that only mean something during a game. */
body:not(.in-game) .game-only {
  display: none;
}

/* Game events, over the player's own strip so the board stays clear. Pinned
   to the strip's top, so a message that wraps grows down, away from the board. */
.board-toast {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-height: 100%;
  margin: 0;
  padding: 4px 10px;
  border-radius: var(--radius);
  background: var(--panel-raised);
  border: 1px solid var(--accent);
  color: var(--text);
  font-size: 14px;
  text-align: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.board-toast.fading {
  opacity: 0;
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  width: 100%;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.45);
  touch-action: manipulation;
}

.sq {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.sq.light {
  background: var(--sq-light);
}

.sq.dark {
  background: var(--sq-dark);
}

.sq:focus-visible {
  outline: 3px solid #4a9de0;
  outline-offset: -3px;
  z-index: 3;
}

.piece {
  font-size: calc(var(--board-size) / 8 * 0.82);
  line-height: 1;
  pointer-events: none;
  position: relative;
  z-index: 2;
  /* Nudge the glyphs onto the visual centre of the square. */
  transform: translateY(-2%);
}

.piece.white {
  color: #fff;
  text-shadow: 0 0 1px #1d1c19, 0 1px 1px #1d1c19, 1px 0 1px #1d1c19, 0 -1px 1px #1d1c19,
    -1px 0 1px #1d1c19, 0 2px 3px rgba(0, 0, 0, 0.35);
}

.piece.black {
  color: #2b2926;
  text-shadow: 0 0 1px rgba(255, 255, 255, 0.35), 0 2px 3px rgba(0, 0, 0, 0.3);
}

/* Backstop for the pawn glyph alongside the U+FE0E text-presentation
   selector in app.js: naming a font with real chess-symbol coverage keeps
   WebKit from substituting its colour emoji pawn, which ignores the
   colour/text-shadow above. */
.piece-p {
  font-family: 'Apple Symbols', -apple-system, BlinkMacSystemFont, 'Segoe UI Symbol', 'Segoe UI',
    Roboto, 'Helvetica Neue', Arial, sans-serif;
}

/* Rank numbers go top-left, file letters bottom-right, so the corner square
   can carry both without them colliding. */
.coord {
  position: absolute;
  font-size: 10px;
  font-weight: 700;
  opacity: 0.7;
  pointer-events: none;
  z-index: 1;
}

.coord-rank {
  inset: 2px auto auto 3px;
}

.coord-file {
  inset: auto 3px 1px auto;
}

.sq.light .coord {
  color: var(--sq-dark);
}

.sq.dark .coord {
  color: var(--sq-light);
}

body.hide-coords .coord {
  display: none;
}

/* Highlights ---------------------------------------------------------- */

.sq.last-from::before,
.sq.last-to::before,
.sq.selected::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--sq-highlight);
  z-index: 0;
}

.sq.selected::before {
  background: var(--sq-select);
}

.sq.in-check::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    circle at center,
    rgba(212, 89, 63, 0.95) 12%,
    rgba(212, 89, 63, 0.55) 48%,
    transparent 72%
  );
  z-index: 0;
}

/* A dot for a quiet move, a ring for a capture — the chess.com convention. */
.sq.target::after {
  content: '';
  position: absolute;
  width: 30%;
  height: 30%;
  border-radius: 50%;
  background: rgba(20, 20, 18, 0.28);
  z-index: 1;
}

.sq.target-capture::after {
  content: '';
  position: absolute;
  inset: 0;
  border: 6px solid rgba(20, 20, 18, 0.28);
  border-radius: 50%;
  z-index: 1;
}

.sq.target.preview::after,
.sq.target-capture.preview::after {
  background: rgba(224, 160, 60, 0.55);
}

.sq.target-capture.preview::after {
  background: none;
  border-color: var(--sq-preview);
}

.sq.target:hover::after,
.sq.target-capture:hover::after {
  background: rgba(20, 20, 18, 0.4);
}

.sq.target-capture:hover::after {
  background: none;
  border-color: rgba(20, 20, 18, 0.45);
}

/* Game-over overlay ---------------------------------------------------- */

.board-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 19, 16, 0.72);
  border-radius: 6px;
  z-index: 5;
}

/* `display: flex` above outranks the browser's [hidden] rule, so restate it. */
.board-overlay[hidden] {
  display: none;
}

.overlay-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px 24px;
  text-align: center;
  max-width: 80%;
}

.overlay-text {
  margin: 0 0 14px;
  font-size: 17px;
  font-weight: 600;
}

/* -------------------------------------------------------------- side panel */

.side-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.status-card,
.moves-card,
.nav-card,
.tools-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.status-line {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.status-line.check {
  color: var(--warn);
}

.status-line.over {
  color: var(--accent);
}

.hint {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--text-dim);
}

.hint.preview {
  color: var(--warn);
}

.moves-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
}

.moves-head h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--text-dim);
}

.move-count {
  font-size: 12px;
  color: var(--text-dim);
}

.move-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
  font-variant-numeric: tabular-nums;
}

.move-row {
  display: grid;
  grid-template-columns: 34px 1fr 1fr;
  align-items: center;
  gap: 2px;
  border-radius: 5px;
}

.move-row:nth-child(odd) {
  background: rgba(255, 255, 255, 0.03);
}

.move-number {
  color: var(--text-dim);
  font-size: 13px;
  padding-left: 4px;
}

.move {
  appearance: none;
  background: none;
  border: 0;
  border-radius: 5px;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  text-align: left;
  padding: 4px 6px;
  cursor: pointer;
}

.move:hover {
  background: var(--panel-raised);
}

.move.current {
  background: var(--accent-dark);
  color: #fff;
  font-weight: 600;
}

.move.future {
  color: var(--text-dim);
  font-style: italic;
}

.empty-moves {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--text-dim);
}

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

.nav-card {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}

.btn {
  appearance: none;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: 7px;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  padding: 8px 12px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.btn:hover:not(:disabled) {
  background: #4a4744;
}

.btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent-dark);
  color: #1b2a10;
  font-weight: 600;
}

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

.btn.nav {
  padding: 8px 0;
  text-align: center;
}

.btn.nav.wide {
  grid-column: 1 / -1;
}

.btn.small {
  font-size: 13px;
  padding: 6px 10px;
}

.tools-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
}

.toggle input {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.tool-buttons {
  display: flex;
  gap: 6px;
}

.tool-buttons .btn {
  flex: 1;
}

.tool-feedback {
  margin: 0;
  min-height: 16px;
  font-size: 12px;
  color: var(--accent);
}

/* --------------------------------------------------------------- promotion */

.promotion-backdrop {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 14, 12, 0.7);
  z-index: 20;
}

.promotion-backdrop[hidden] {
  display: none;
}

.promotion-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px 20px;
  text-align: center;
}

.promotion-card p {
  margin: 0 0 12px;
  font-weight: 600;
}

.promotion-choices {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.promotion-choice {
  appearance: none;
  width: 62px;
  height: 62px;
  background: var(--sq-light);
  border: 2px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.promotion-choice:hover,
.promotion-choice:focus-visible {
  border-color: var(--accent);
  outline: none;
}

.promotion-choice .piece {
  font-size: 44px;
}

/* ------------------------------------------------------------------ online */

.online-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.online-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.net-dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--text-dim);
}

.net-dot.ok {
  background: var(--accent);
}

.net-dot.wait {
  background: var(--warn);
}

.net-dot.bad {
  background: var(--danger);
}

.net-status {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}

.online-detail {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
  overflow-wrap: anywhere;
}

.request-banner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--warn);
  border-radius: 8px;
  background: rgba(224, 160, 60, 0.1);
}

.request-banner p {
  margin: 0;
  font-size: 13px;
}

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

.modal-backdrop {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(15, 14, 12, 0.7);
  z-index: 30;
}

.modal-card {
  width: min(460px, 100%);
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px 18px;
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.modal-head h2 {
  font-size: 18px;
}

.modal-panel,
.home-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.modal-panel p,
.home-card p {
  margin: 0;
}

.modal-panel .tool-buttons,
.home-card .tool-buttons {
  flex-wrap: wrap;
}

.modal-panel .tool-buttons .btn,
.home-card .tool-buttons .btn {
  flex: 1 1 auto;
}

.modal-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
}

/* On the page itself the sections sit on the page background, so raise them. */
.home-card .modal-section {
  background: var(--panel);
  padding: 14px;
}

.modal-panel h3,
.home-card h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
}

.modal-note {
  font-size: 13px;
  color: var(--text-dim);
}

.modal-note.warn {
  color: var(--warn);
}

.modal-panel code {
  font-size: 12px;
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--panel-raised);
  overflow-wrap: anywhere;
}

.inline-form {
  display: flex;
  gap: 6px;
}

.inline-form input,
.modal-panel .field {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 14px;
  padding: 7px 9px;
  color: var(--text);
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: 7px;
}

.inline-form input:focus,
.modal-panel .field:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

.form-message {
  font-size: 13px;
  min-height: 0;
}

.form-message:empty {
  display: none;
}

.form-message.good {
  color: var(--accent);
}

.form-message.bad {
  color: var(--danger);
}

.setup-steps {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 0;
  padding-left: 22px;
}

.setup-steps li {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.setup-steps li::marker {
  font-weight: 600;
  color: var(--accent);
}

.setup-steps .btn {
  align-self: flex-start;
  text-decoration: none;
}

.color-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 14px;
}

.color-choice legend {
  width: 100%;
  margin-bottom: 4px;
  padding: 0;
  font-size: 13px;
  color: var(--text-dim);
}

.color-choice label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.color-choice input {
  accent-color: var(--accent);
}

#hostReady {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.host-notes {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.stats-line {
  display: block;
}

.relay-what {
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--panel-raised);
}

.link-btn {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

/* QR codes stay dark-on-white whatever the theme: scanners expect that. */
.qr {
  align-self: center;
  width: min(260px, 100%);
  border-radius: 8px;
  overflow: hidden;
  line-height: 0;
}

.qr svg {
  width: 100%;
  height: auto;
}

.qr-light {
  fill: #fff;
}

.qr-dark {
  fill: #000;
}

/* ------------------------------------------------------------------ footer */

.app-footer {
  max-width: 1040px;
  margin: 24px auto 0;
  text-align: center;
}

.app-footer .footer-links {
  justify-content: center;
}

/* -------------------------------------------------------------------- chat */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.name-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0 0 10px;
  font-size: 14px;
  color: var(--text-dim);
}

.join-who {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 8px;
}

.chat-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
}

.chat-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.chat-head h2 {
  margin: 0;
  font-size: 16px;
  flex: 1;
}

.chat-badge {
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--accent);
  color: #10140b;
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}

.chat-log {
  list-style: none;
  margin: 0;
  padding: 0;
  height: 190px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 15px;
  overflow-wrap: anywhere;
}

.chat-line .chat-name {
  font-weight: 600;
  color: var(--text-dim);
}

.chat-line.mine .chat-name {
  color: var(--accent);
}

.chat-line.sys {
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
}

.chat-empty {
  margin: auto;
  color: var(--text-dim);
  font-size: 14px;
}

.chat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.chat-chips .btn {
  min-height: 36px;
}

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

.chat-form input {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  padding: 8px 10px;
  background: var(--bg, #1f1d1a);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font: inherit;
}

.chat-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.chat-form .btn {
  min-height: 44px;
}

.chat-note {
  margin: 0;
  min-height: 1.2em;
  font-size: 13px;
  color: var(--text-dim);
}

/* On phones the chat sits below the board, out of sight: this bar under the
   board shows the latest message and jumps to the chat. */
.chat-peek {
  display: none;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 6px 10px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.chat-peek-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 860px) {
  .chat-peek:not([hidden]) {
    display: flex;
  }
}

.chat-log-wrap {
  position: relative;
}

.chat-new {
  position: absolute;
  right: 8px;
  bottom: 8px;
  min-height: 32px;
  padding: 4px 12px;
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: #10140b;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}

.chat-tick {
  color: var(--accent);
  font-size: 13px;
}

.chat-close {
  display: none;
}

/* On phones the chat is a sheet that rises from the bottom when the bar under
   the board is tapped. It sits above the on-screen keyboard (--kb), and the
   board shrinks to stay in view above it (--vvh and --sheet-h come from the
   visual viewport, see online.js). */
@media (max-width: 860px) {
  .chat-close {
    display: inline-flex;
  }

  .chat-card {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--kb, 0px);
    z-index: 30;
    box-sizing: border-box;
    width: min(100vw, 560px);
    margin: 0 auto;
    border-radius: 14px 14px 0 0;
    padding-bottom: calc(12px + env(safe-area-inset-bottom));
    box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.5);
    transform: translateY(110%);
    visibility: hidden;
    transition: transform 0.2s ease, visibility 0s linear 0.2s;
  }

  .chat-card[hidden] {
    display: none;
  }

  body.chat-open .chat-card {
    transform: none;
    visibility: visible;
    transition: transform 0.2s ease;
  }

  .chat-log {
    height: 96px;
  }

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

  /* Chatting: the board, its two strips and the sheet are all that is needed. */
  body.chat-open {
    --board-size: max(140px, min(94vw, calc(var(--vvh, 100svh) - var(--sheet-h, 300px) - 130px), 520px));
  }

  body.chat-open .app-header,
  body.chat-open .app-footer,
  body.chat-open .chat-peek {
    display: none;
  }

  /* With the keyboard up, quick replies make way for the box. */
  body.chat-open.keyboard-up .chat-chips,
  body.chat-open.keyboard-up .chat-note {
    display: none;
  }

  body.chat-open.keyboard-up .chat-log {
    height: 64px;
  }
}

/* ------------------------------------------------------------- responsive */

@media (max-width: 860px) {
  :root {
    --board-size: min(94vw, calc(100vh - 260px), 520px);
  }

  .layout {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
  }

  .side-panel {
    width: min(94vw, 520px);
  }

  /* With no game yet, starting one matters more than the idle board. */
  body:not(.in-game) .side-panel {
    order: -1;
  }

  .move-list {
    max-height: 200px;
  }
}

@media (max-width: 420px) {
  body {
    padding: 0 10px 20px;
  }

  :root {
    --board-size: min(96vw, calc(100vh - 250px));
  }

  .app-header {
    padding: 12px 0;
  }
}

/* On phones, 100vh includes the space behind the browser's toolbars, so a
   board sized from it can run off the bottom of the screen. svh is the height
   that is actually visible; browsers without it keep the vh sizes above. */
@supports (height: 100svh) {
  :root {
    --board-size: min(92vw, calc(100svh - 320px), 560px);
  }

  .modal-card {
    max-height: calc(100svh - 32px);
  }

  @media (max-width: 860px) {
    :root {
      --board-size: min(94vw, calc(100svh - 260px), 520px);
    }
  }

  @media (max-width: 420px) {
    :root {
      --board-size: min(96vw, calc(100svh - 250px));
    }
  }
}

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