/* static/css/chess.css — Chess board page.
   Board palette is deliberately theme-constant (the classic green/ivory): a board that
   flips shade with the site theme reads as a bug, and the piece fills are fixed
   black/white anyway. Everything around the board uses site tokens and flips normally.
   Text on a brand-gradient fill uses a literal #fff, never a theme-flipping token. */

.ch-page {
  --ch-light: #ebecd0;
  --ch-dark: #739552;
  --ch-move: rgba(255, 255, 51, 0.45);
  --ch-check: #e5484d;
  --ch-coord-on-light: #739552;
  --ch-coord-on-dark: #ebecd0;
  /* One knob drives every board-relative size, so the board and its labels scale together. */
  --ch-sq: 1;
}

.ch-layout {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 900px) {
  .ch-layout {
    grid-template-columns: minmax(0, 1fr) 16rem;
    align-items: start;
  }
}

/* ── Board ─────────────────────────────────────────────────────────────────── */

/* The board is capped by the viewport height as well as the column width, so on a
   short laptop window it stays fully visible instead of running off the fold. `dvh`
   keeps that honest on mobile, where the browser chrome shrinks the viewport. */
.ch-board-wrap {
  position: relative;
  width: 100%;
  max-width: min(100%, calc(100dvh - 15rem));
  margin-inline: auto;
}
@media (max-width: 899px) {
  .ch-board-wrap { max-width: min(100%, calc(100dvh - 17rem)); }
}

.ch-board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  /* Rows must be explicit: with `auto` rows the squares holding a piece grow to the
     piece's intrinsic height while empty ones collapse, so the board re-proportions
     itself on every capture. */
  grid-template-rows: repeat(8, 1fr);
  aspect-ratio: 1;
  width: 100%;
  border-radius: 0.35rem;
  overflow: hidden;
  box-shadow: 0 8px 28px rgba(2, 6, 23, 0.35);
  touch-action: manipulation;
  user-select: none;
  /* Coordinate labels size off the board itself (cqw), not the viewport, so they
     stay proportional whether the board is capped by width or by height. */
  container-type: inline-size;
}

.ch-sq {
  position: relative;
  min-width: 0;
  min-height: 0;
  border: 0;
  padding: 0;
  cursor: pointer;
  background: var(--ch-light);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 120ms ease;
}
.ch-sq.ch-odd { background: var(--ch-dark); }
.ch-sq:disabled { cursor: default; }
.ch-sq:focus-visible { outline: 3px solid #fff; outline-offset: -3px; z-index: 3; }

/* Coordinates, chess.com style: rank down the left edge, file along the bottom,
   each tinted against the square it sits on. JS marks the edge squares. */
.ch-sq[data-rank-label]::before,
.ch-sq[data-file-label]::after {
  position: absolute;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: clamp(0.5rem, 1.6cqw, 0.8rem);
  line-height: 1;
  pointer-events: none;
}
.ch-sq[data-rank-label]::before {
  content: attr(data-rank-label);
  top: 3%;
  left: 5%;
  color: var(--ch-coord-on-light);
}
.ch-sq[data-file-label]::after {
  content: attr(data-file-label);
  bottom: 3%;
  right: 5%;
  color: var(--ch-coord-on-light);
}
.ch-sq.ch-odd[data-rank-label]::before,
.ch-sq.ch-odd[data-file-label]::after { color: var(--ch-coord-on-dark); }
/* A square can carry both labels (the bottom-left corner); the ::after still reads. */

.ch-sq.ch-from,
.ch-sq.ch-last { box-shadow: inset 0 0 0 100px var(--ch-move); }

/* An empty legal target gets a dot; a capturable one gets a ring around the piece. */
.ch-sq.ch-target::after {
  content: '';
  position: absolute;
  width: 30%;
  height: 30%;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.22);
  transition: transform 110ms ease;
}
.ch-sq.ch-target.ch-occupied::after {
  width: 88%;
  height: 88%;
  background: transparent;
  border: 6px solid rgba(15, 23, 42, 0.22);
}
.ch-sq.ch-target:hover::after { transform: scale(1.18); }
/* The dot must not be eaten by the file letter on the bottom rank. */
.ch-sq.ch-target[data-file-label]::after { content: ''; bottom: auto; right: auto; }

.ch-sq.ch-check {
  background: radial-gradient(circle, #ff6b6b 12%, rgba(229, 72, 77, 0.55) 55%, transparent 72%);
}

.ch-piece {
  width: 92%;
  height: 92%;
  display: block;
  pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
}
.ch-piece.ch-white { fill: #fafafa; stroke: #2c2c2c; stroke-width: 1.1; }
.ch-piece.ch-black { fill: #3a3a38; stroke: #101010; stroke-width: 1.1; }

/* Move animation: the piece is drawn on its destination square, then offset back to
   where it came from and released. One transition, no sprite layer to keep in sync.
   Skipped for anyone who asked for less motion. */
.ch-piece.ch-sliding { transition: transform 170ms cubic-bezier(0.2, 0.7, 0.3, 1); }
.ch-sq.ch-moving { z-index: 2; }

@keyframes ch-pop { from { transform: scale(0.72); opacity: 0.4; } to { transform: scale(1); opacity: 1; } }
.ch-piece.ch-popping { animation: ch-pop 150ms ease-out; }

@media (prefers-reduced-motion: reduce) {
  .ch-piece.ch-sliding { transition: none; }
  .ch-piece.ch-popping { animation: none; }
  .ch-sq, .ch-sq.ch-target::after { transition: none; }
}

/* ── Promotion ─────────────────────────────────────────────────────────────── */

.ch-promo {
  position: absolute;
  inset: 0;
  margin: auto;
  width: max-content;
  height: max-content;
  display: flex;
  gap: 0.35rem;
  padding: 0.5rem;
  border-radius: 0.6rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  box-shadow: 0 10px 30px rgba(2, 6, 23, 0.5);
  animation: ch-pop 140ms ease-out;
  z-index: 4;
}
.ch-promo button {
  width: clamp(2.5rem, 11vw, 3.25rem);
  height: clamp(2.5rem, 11vw, 3.25rem);
  border-radius: 0.4rem;
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  background: var(--ch-light);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 110ms ease, border-color 110ms ease;
}
.ch-promo button:hover { border-color: var(--brand-primary); transform: translateY(-2px); }

/* chess.css loads after tailwind, so `display: flex` here would otherwise beat
   tailwind's equal-specificity `.hidden { display: none }` and leave the promotion
   dialog and the draw-offer box permanently on screen. */
.ch-promo.hidden,
.ch-offer.hidden { display: none; }

/* ── Players, clocks, move list ────────────────────────────────────────────── */

.ch-player {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  min-width: 0;
}
.ch-player-name { flex: 1 1 auto; min-width: 0; }

.ch-avatar {
  width: 2rem;
  height: 2rem;
  flex: 0 0 auto;
  border-radius: 0.35rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
  color: #fff;
  background: var(--grad-primary);
}

.ch-taken {
  flex: 0 1 auto;
  font-size: 0.95rem;
  line-height: 1;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
}

.ch-clock {
  flex: 0 0 auto;
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
  padding: 0.15rem 0.7rem;
  border-radius: 0.35rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  color: var(--text-muted);
  transition: color 150ms ease, background-color 150ms ease, border-color 150ms ease;
}
.ch-clock.ch-active {
  color: var(--text-primary);
  border-color: var(--brand-primary);
  box-shadow: 0 0 0 1px var(--brand-primary) inset;
}
.ch-clock.ch-low { color: #f87171; border-color: #f87171; }
.ch-clock.ch-active.ch-low { animation: ch-tick 1s steps(2, jump-none) infinite; }
@keyframes ch-tick { 50% { opacity: 0.55; } }

.ch-banner {
  padding: 0.55rem 0.9rem;
  border-radius: 0.5rem;
  text-align: center;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  color: var(--text-secondary);
}
.ch-banner.ch-yours {
  background: var(--grad-primary);
  border-color: transparent;
  color: #fff;
}

.ch-moves {
  margin-top: 0.75rem;
  height: 14rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.5rem;
  border-radius: 0.5rem;
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
  color: var(--text-secondary);
}
.ch-moves .ch-ply { display: grid; grid-template-columns: 2rem 1fr 1fr; gap: 0.25rem; padding: 0.1rem 0; }
.ch-moves .ch-ply:nth-child(odd) { background: rgba(127, 127, 127, 0.07); }
.ch-moves .ch-no { color: var(--text-muted); }

.ch-offer {
  margin-top: 0.75rem;
  padding: 0.5rem;
  border-radius: 0.5rem;
  border: 1px solid var(--brand-primary);
  font-size: 0.85rem;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  animation: ch-pop 150ms ease-out;
}

.ch-mini {
  padding: 0.5rem 0.6rem;
  border-radius: 0.4rem;
  font-family: 'Rajdhani', sans-serif;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--text-secondary);
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  cursor: pointer;
  transition: border-color 120ms ease, color 120ms ease;
}
.ch-mini:hover { border-color: var(--brand-primary); color: var(--text-primary); }
.ch-mini:disabled { opacity: 0.45; cursor: default; }

/* The lobby/arena/result panels are static containers, not clickable cards, so the
   sitewide .card-border:hover lift is neutralized. */
#ch-app > .card-border:hover,
#ch-app .card-border:not(button):hover {
  transform: none;
  box-shadow: none;
}

/* ── Phone ─────────────────────────────────────────────────────────────────── */

@media (max-width: 899px) {
  /* Board first, then the controls; the move list is secondary on a phone. */
  .ch-layout { gap: 0.6rem; }
  .ch-moves { height: 7rem; margin-top: 0.5rem; }
  .ch-clock { font-size: 1.25rem; padding: 0.1rem 0.5rem; }
  .ch-avatar { width: 1.75rem; height: 1.75rem; }
  .ch-player { padding: 0.35rem 0; }
  .ch-taken { font-size: 0.8rem; }
  /* Full-bleed board: on a phone the card padding is wasted width. */
  #ch-arena > .card-border { padding: 0.5rem; }
}

/* Lobby mode picker. Selected pill sits on the brand fill, so its text is literal white. */
.ch-modes { display: flex; flex-direction: column; gap: .75rem; align-items: center; }
.ch-mode-row { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; align-items: center; }
.ch-mode-label { width: 100%; text-align: center; font-size: .8rem; color: var(--text-secondary); }
.ch-mode-label small, .ch-fast-toggle small { color: var(--text-muted); margin-left: .25rem; }
.ch-mode {
  min-width: 4.5rem; padding: .45rem .9rem; border-radius: .5rem; font-weight: 600;
  border: 1px solid var(--border-color, rgba(127,127,127,.35)); color: var(--text-secondary); background: transparent;
}
.ch-mode:hover { color: var(--text-primary); border-color: var(--brand-primary); }
.ch-mode[aria-pressed="true"] { background: var(--brand-primary); border-color: var(--brand-primary); color: #fff; }
.ch-fast-toggle { display: inline-flex; align-items: center; gap: .35rem; font-size: .85rem; color: var(--text-secondary); cursor: pointer; }
.ch-slow {
  display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; justify-content: center;
  padding: .75rem 1rem; border-radius: .5rem; border: 1px solid var(--brand-primary); color: var(--text-primary);
}
.ch-slow.hidden { display: none; }

/* ── Lobby extras, challenge and watch panels ──────────────────────────────── */
.ch-extra { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.ch-practice-group { display: inline-flex; align-items: stretch; gap: 0.4rem; }
.ch-select,
.ch-input {
  padding: 0.5rem 0.6rem;
  border-radius: 0.4rem;
  font-size: 0.85rem;
  color: var(--text-primary);
  background: var(--bg-card);
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  min-width: 0;
}
.ch-select:focus,
.ch-input:focus { outline: 2px solid var(--brand-primary); outline-offset: 1px; }
.ch-share { display: flex; gap: 0.4rem; max-width: 32rem; margin-inline: auto; }
.ch-share .ch-input { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.75rem; }
a.ch-mini { display: inline-block; text-decoration: none; }

.ch-list { display: flex; flex-direction: column; gap: 0.5rem; }
.ch-list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.6rem;
  border-radius: 0.5rem;
  border: 1px solid var(--border-color, rgba(148, 163, 184, 0.35));
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.ch-list-row > span { min-width: 0; }
.ch-list-row .ch-mini { flex-shrink: 0; }

.ch-tools { padding-top: 0.75rem; border-top: 1px solid var(--border-color, rgba(148, 163, 184, 0.35)); }

/* A spectator gets a read-only board: no game controls, just the flip button. */
.ch-spectator { display: none; }
#ch-app.ch-spectating .ch-spectator { display: block; }
#ch-app.ch-spectating .ch-actions { display: none; }