.play-page {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.companion-column {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  min-width: 160px;
  max-width: 230px;
  flex-shrink: 0;
}

.streak-badge {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: fit-content;
  flex-shrink: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  text-decoration: none;
  color: var(--text-primary);
  font-weight: 700;
  font-size: 1.3rem;
  transition: border-color 0.15s;
}

.streak-badge:hover {
  border-color: var(--accent);
}

/* Unlit by default — filter: grayscale() rather than just low opacity, so
   an unlit flame reads as "off" (dull gray) instead of just "a faint orange
   flame", which read as lit-but-faded rather than not-yet-earned. */
.streak-flame {
  display: inline-block;
  filter: grayscale(1);
  opacity: 0.35;
}

.streak-flame.lit {
  filter: none;
  opacity: 1;
}

.streak-flame-sm,
.streak-flame-md,
.streak-flame-lg {
  font-size: 1.2rem;
}

#streak-count {
  margin-left: 0.2rem;
}

.sparrow-companion-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

.sparrow-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--surface-2);
  padding: 3px;
  border: 1px solid var(--border);
  transition: border-color 0.6s ease, box-shadow 0.6s ease, transform 0.6s ease;
}

/* Sparrow's "tell" — a subtle, non-numeric read on how the game is going
   for Sparrow (see board.js's setSparrowMood / game.py's
   _mood_from_win_prob). Deliberately quiet: a glow shift and a slow
   ambient animation, not a badge or a number. */
.sparrow-avatar.mood-confident {
  border-color: #f0b429;
  box-shadow: 0 0 8px 1px rgba(240, 180, 41, 0.55);
  animation: sparrow-mood-confident-pulse 2.4s ease-in-out infinite;
}

.sparrow-avatar.mood-worried {
  border-color: #60a5fa;
  box-shadow: 0 0 6px 1px rgba(96, 165, 250, 0.45);
  transform: scale(0.94);
}

@keyframes sparrow-mood-confident-pulse {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.06);
  }
}

@media (prefers-reduced-motion: reduce) {
  .sparrow-avatar {
    transition: none;
  }
  .sparrow-avatar.mood-confident {
    animation: none;
  }
}

.sparrow-bubble {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.35rem 0.7rem;
  font-size: 0.8rem;
  color: var(--text-secondary);
  animation: sparrow-bubble-in 0.2s ease;
}

@keyframes sparrow-bubble-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.ask-sparrow-btn {
  font-size: 0.82rem;
  padding: 0.4rem 0.8rem;
  width: 100%;
}

/* A normal column member now (not an absolute overlay). Height is set from
   JS (sizeAskSparrowPanel in board.js) to line up its bottom edge with the
   board's own bottom, since that varies with whatever banners/bars are
   showing above the board — a fixed CSS height can't track that. The
   left margin nudges it clear of the flip-board icon, which pokes out past
   the board's right edge (see .flip-icon-btn's own negative offset) and
   would otherwise sit right where this panel starts. */
.ask-sparrow-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: min(74vh, 620px);
  margin-left: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  overflow: hidden;
  transform-origin: top;
  animation: ask-sparrow-fall 0.22s ease;
}

@keyframes ask-sparrow-fall {
  from {
    opacity: 0;
    transform: scaleY(0.9);
  }
  to {
    opacity: 1;
    transform: scaleY(1);
  }
}

.ask-sparrow-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  font-size: 0.9rem;
  flex-shrink: 0;
}

.ask-sparrow-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0.7rem 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.chat-message {
  max-width: 85%;
  padding: 0.5rem 0.75rem;
  border-radius: 14px;
  font-size: 0.85rem;
  line-height: 1.4;
  word-wrap: break-word;
}

.chat-message.sparrow {
  align-self: flex-start;
  background: var(--surface-2);
  color: var(--text-primary);
  border-bottom-left-radius: 4px;
}

.chat-message.user {
  align-self: flex-end;
  background: var(--accent);
  color: var(--accent-on);
  border-bottom-right-radius: 4px;
}

.chat-message.pending {
  opacity: 0.6;
}

.ask-sparrow-error {
  color: #ffb4b4;
  font-size: 0.8rem;
  padding: 0 0.9rem 0.5rem;
}

.ask-sparrow-input-row {
  display: flex;
  gap: 0.4rem;
  padding: 0.6rem;
  border-top: 1px solid var(--border);
}

.ask-sparrow-input-row input {
  flex: 1;
  min-width: 0;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  font-family: inherit;
  font-size: 0.85rem;
}

.ask-sparrow-input-row .btn {
  padding: 0.5rem 0.9rem;
  font-size: 0.85rem;
}

.resign-confirm-card {
  max-width: 360px;
}

.streak-badge.renewed {
  animation: streak-pop 0.5s ease;
}

@keyframes streak-pop {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.35);
  }
  60% {
    transform: scale(0.95);
  }
  100% {
    transform: scale(1);
  }
}

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(8, 5, 14, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  animation: modal-overlay-in 0.18s ease;
}

/* Added by closeModal() in board.js just before the .hidden class lands —
   .hidden is display:none!important (see theme.css), which can't be
   animated, so this is what actually plays the close transition in the
   brief window before the JS-side setTimeout hides the element for real. */
.modal-overlay.closing {
  animation: modal-overlay-out 0.16s ease forwards;
}

.modal-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.6rem 1.8rem;
  min-width: 320px;
  max-width: 90vw;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
  animation: modal-card-in 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}

.modal-overlay.closing .modal-card {
  animation: modal-card-out 0.16s ease forwards;
}

@keyframes modal-overlay-in {
  from {
    opacity: 0;
  }
}

@keyframes modal-overlay-out {
  to {
    opacity: 0;
  }
}

@keyframes modal-card-in {
  from {
    opacity: 0;
    transform: scale(0.92) translateY(8px);
  }
}

@keyframes modal-card-out {
  to {
    opacity: 0;
    transform: scale(0.95) translateY(4px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .modal-overlay,
  .modal-overlay.closing,
  .modal-card,
  .modal-overlay.closing .modal-card {
    animation: none;
  }
}

.modal-card h2 {
  margin: 0 0 1rem;
  font-size: 1.25rem;
  padding-right: 1.5rem;
}

.modal-close {
  position: absolute;
  top: 0.8rem;
  right: 0.9rem;
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem;
}

.modal-close:hover {
  color: var(--text-primary);
}

.modal-meta {
  margin-bottom: 1.3rem;
}

.modal-actions {
  display: flex;
  gap: 0.7rem;
}

.game-end-classifications {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.game-end-classifications .tag {
  font-size: 0.78rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
}

.game-end-achievements {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.3rem;
}

.achievement-toast {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  background: var(--now-bg, rgba(168, 85, 247, 0.15));
  border: 1px solid var(--accent);
  border-radius: 8px;
  padding: 0.55rem 0.8rem;
  animation: achievement-toast-in 0.3s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}

.achievement-toast:nth-child(2) {
  animation-delay: 0.08s;
}

.achievement-toast:nth-child(3) {
  animation-delay: 0.16s;
}

@keyframes achievement-toast-in {
  from {
    opacity: 0;
    transform: translateY(6px) scale(0.96);
  }
}

@media (prefers-reduced-motion: reduce) {
  .achievement-toast {
    animation: none;
  }
}

.achievement-toast strong {
  font-size: 0.88rem;
  color: var(--accent-soft);
}

.achievement-toast span {
  font-size: 0.78rem;
  color: var(--text-secondary);
}

.onboarding-card {
  max-width: 420px;
}

.onboarding-levels {
  margin: 1rem 0;
}

.onboarding-level-btn {
  flex: 1;
}

.onboarding-divider {
  text-align: center;
  font-size: 0.78rem;
  color: var(--text-muted);
  margin: 0.8rem 0;
}

.onboarding-rating-row {
  display: flex;
  gap: 0.6rem;
}

.onboarding-rating-row input {
  flex: 1;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem 0.7rem;
  color: var(--text-primary);
  font-size: 0.9rem;
  font-family: inherit;
}

.onboarding-hint {
  margin-top: 1rem;
  font-size: 0.78rem;
  line-height: 1.4;
}

.onboarding-chesscom-status {
  margin-top: 0.5rem;
  font-size: 0.78rem;
  text-align: center;
}

.placement-banner {
  /* No horizontal margin: auto here — .board-panel (the flex parent)
     already centers this via align-items: center, and margin: auto
     resolves to 0 (not negative) once the box is wider than its actual
     container, which shoved this flush against the left edge with all
     the overflow bleeding out the right. 100% is the real safety cap:
     .board-panel's padded content area is narrower than the viewport,
     so a vw-only cap (copied from .board, whose immediate parent
     happens to run nearly edge-to-edge) isn't reliable here. Capped
     noticeably narrower than the board itself (480px vs .board's
     620px) since a status banner doesn't need to span the full board. */
  width: min(74vh, 480px, 92vw, 100%);
  margin: 0 0 0.6rem;
  text-align: center;
  background: var(--now-bg, rgba(168, 85, 247, 0.15));
  border: 1px solid var(--accent);
  color: var(--accent-soft);
  border-radius: 8px;
  padding: 0.5rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.page-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-shrink: 0;
}

.onboarding-tutorial-link {
  display: block;
  text-align: center;
  margin-top: 0.6rem;
}

.streak-badge-wrap {
  position: relative;
  width: fit-content;
}

.shield-toast {
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 50%;
  transform: translateX(-50%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.5rem 0.9rem;
  font-size: 0.78rem;
  font-weight: 600;
  text-align: center;
  width: max-content;
  max-width: 200px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  animation: sparrow-bubble-in 0.2s ease;
  z-index: 5;
}

.play-page .page-header {
  flex-shrink: 0;
  margin-bottom: 0.7rem;
  font-size: 1.8rem;
}

.layout {
  flex: 1;
  min-height: 0;
  display: flex;
  gap: 1.6rem;
  align-items: flex-start;
  margin-top: 1.1rem;
}

.board-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

.status-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.status-bar {
  font-size: 1rem;
  min-height: 1.4rem;
}

.board-clock {
  font-size: 0.76rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}

.opening-bar {
  font-size: 1.05rem;
  min-height: 1.4rem;
  color: var(--accent-soft);
  font-weight: 600;
}

.tactics-bar {
  font-size: 0.82rem;
  min-height: 1.1rem;
  color: var(--accent-soft);
  font-weight: 600;
}

.tactic-tag {
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.tactic-popover {
  position: fixed;
  z-index: 50;
  max-width: 260px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.7rem 0.9rem;
  font-size: 0.82rem;
  color: var(--text-secondary);
  animation: info-popover-in 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  .tactic-popover {
    animation: none;
  }
}

.tactic-popover strong {
  display: block;
  margin-bottom: 0.3rem;
  color: var(--text-primary);
  font-size: 0.85rem;
}

.tactic-popover p {
  margin: 0;
}

.captured-row {
  display: flex;
  align-items: center;
  gap: 2px;
  min-height: 1.8rem;
  flex-wrap: wrap;
  /* 100% caps it to .board-panel's actual padded content width — the vh/vw
     terms alone (copied from .board) don't account for that padding, which
     is what let .placement-banner overflow its real container. */
  width: min(74vh, 620px, 94vw, 100%);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.2rem 0.4rem;
}

.captured-row .captured-piece {
  width: 1.5rem;
  height: 1.5rem;
  background: var(--square-light);
  border-radius: 3px;
  padding: 1px;
}

.board-row {
  position: relative;
}

.flip-icon-btn {
  position: absolute;
  top: 50%;
  right: -44px;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-secondary);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}

.flip-icon-btn svg {
  width: 18px;
  height: 18px;
}

.flip-icon-btn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on);
}

.promotion-picker {
  position: absolute;
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

.promotion-choice {
  width: calc(min(74vh, 620px, 94vw) / 8);
  height: calc(min(74vh, 620px, 94vw) / 8);
  padding: 4px;
  border: none;
  background: var(--surface-2);
  cursor: pointer;
}

.promotion-choice:hover {
  background: var(--accent);
}

.promotion-choice img {
  width: 100%;
  height: 100%;
}

.move-confirm {
  position: absolute;
  z-index: 20;
  display: flex;
  gap: 0.3rem;
  transform: translate(-50%, -100%);
}

.move-confirm-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border);
  cursor: pointer;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}

.move-confirm-yes {
  background: #16a34a;
  color: #fff;
  border-color: #16a34a;
}

.move-confirm-no {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
}

.confetti-canvas {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;
}

.board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(8, 1fr);
  width: min(74vh, 620px, 94vw);
  height: min(74vh, 620px, 94vw);
  border: 2px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
}

.square {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
  user-select: none;
}

.piece-img {
  width: 78%;
  height: 78%;
  pointer-events: none;
  user-select: none;
}

.piece-img.draggable-piece {
  pointer-events: auto;
  cursor: grab;
}

.piece-img.draggable-piece:active {
  cursor: grabbing;
}

@keyframes captureFlash {
  0% {
    box-shadow: inset 0 0 0 5px rgba(220, 38, 38, 0.85);
  }
  100% {
    box-shadow: inset 0 0 0 5px rgba(220, 38, 38, 0);
  }
}

.square.capture-flash {
  animation: captureFlash 350ms ease-out;
}

@keyframes checkPulse {
  0%,
  100% {
    box-shadow: inset 0 0 0 4px rgba(220, 38, 38, 0);
  }
  50% {
    box-shadow: inset 0 0 0 6px rgba(220, 38, 38, 0.9);
  }
}

.square.check-pulse {
  animation: checkPulse 900ms ease-in-out;
}

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

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

.square.selected {
  outline: 3px solid var(--square-highlight);
  outline-offset: -3px;
}

.square.last-move {
  background-image: linear-gradient(rgba(246, 215, 107, 0.32), rgba(246, 215, 107, 0.32));
}

.square .move-dot {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(20, 10, 30, 0.35);
  pointer-events: none;
}

.square .capture-ring {
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  border: 4px solid rgba(20, 10, 30, 0.35);
  pointer-events: none;
}

.square .coord-label {
  position: absolute;
  font-size: 0.62rem;
  font-weight: 700;
  pointer-events: none;
  line-height: 1;
}

.square .coord-rank {
  top: 3px;
  left: 4px;
}

.square .coord-file {
  bottom: 3px;
  right: 4px;
}

.coord-label {
  color: #726a82;
}

.board-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.3rem;
}

/* On desktop these two are invisible to layout — their buttons act as
   plain direct children of .board-actions, same flat row as always.
   Mobile (see media query) turns them into a real boxed group. */
.board-actions-primary,
.board-actions-secondary,
.board-actions-row-1 {
  display: contents;
}

.personality-select {
  padding: 0.5rem 0.9rem;
  font-size: 0.92rem;
  cursor: pointer;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  font-family: inherit;
  margin-left: auto;
}

.fen-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
  width: min(74vh, 620px, 94vw, 100%);
}

.fen-input-row {
  display: flex;
  gap: 0.5rem;
}

.fen-form input {
  flex: 1;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.45rem 0.7rem;
  color: var(--text-primary);
  font-size: 0.85rem;
  font-family: "Cascadia Code", Consolas, monospace;
}

.famous-positions-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.famous-positions-label {
  font-size: 0.78rem;
  margin-right: 0.1rem;
}

.famous-position-btn {
  font-size: 0.76rem;
  padding: 0.3rem 0.6rem;
}

.fen-error {
  color: var(--danger);
  font-size: 0.82rem;
  min-height: 1.1rem;
  margin-top: 0.3rem;
}

.side-panel {
  min-width: 160px;
  max-width: 230px;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.1rem;
}

.side-panel h2 {
  flex-shrink: 0;
  font-size: 0.95rem;
  margin: 0 0 0.5rem;
}

.move-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  padding-left: 0.2rem;
  font-family: "Cascadia Code", Consolas, monospace;
  font-size: 0.88rem;
  line-height: 1.55;
}

.review-panel {
  margin-top: 0.6rem;
  font-size: 0.85rem;
  overflow-y: auto;
  min-height: 0;
}

.review-summary {
  color: var(--text-secondary);
  margin-bottom: 0.6rem;
  line-height: 1.5;
  font-size: 0.9rem;
}

.review-summary p {
  margin: 0 0 0.7rem;
}

.review-summary p:last-child {
  margin-bottom: 0;
}

.review-accuracy {
  font-weight: 600;
  margin-bottom: 0.6rem;
}

.review-moves {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: "Cascadia Code", Consolas, monospace;
  max-height: 220px;
  overflow-y: auto;
}

.review-moves li {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.15rem 0.3rem;
  border-radius: 3px;
}

.tag {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0 0.35rem;
  border-radius: 3px;
}

.tag-brilliant {
  background: #1a6b6b;
  color: #d2fffa;
}

.tag-great {
  background: #1f5f8a;
  color: #d6efff;
}

.tag-best, .tag-excellent {
  background: #2f6b3a;
  color: #d7ffdd;
}

.tag-good {
  background: #2c5a63;
  color: #d6f5fa;
}

.tag-book {
  background: #4a4058;
  color: #e9e2f5;
}

.tag-inaccuracy {
  background: #8a7a1f;
  color: #fff6cf;
}

.tag-miss {
  background: #8a5a1f;
  color: #ffe9cf;
}

.tag-mistake {
  background: #8a4f1f;
  color: #ffe6cf;
}

.tag-blunder {
  background: #8a1f1f;
  color: #ffd6d6;
}

.mini-dashboard {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 160px;
  max-width: 230px;
  margin-left: 28px;
}

.ad-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 120px;
  border-style: dashed;
  text-align: center;
}

.ad-slot-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.ad-slot-placeholder {
  font-size: 0.78rem;
  color: var(--text-muted);
  line-height: 1.4;
}

.mini-card h3 {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
}

.mini-stats {
  margin: 0;
}

.mini-stats > div {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.22rem 0;
  font-size: 0.85rem;
}

.mini-stats dt {
  color: var(--text-muted);
}

.mini-stats dd {
  margin: 0;
  font-weight: 600;
  color: var(--text-primary);
  text-align: right;
}

.mini-link {
  display: block;
  margin-top: 0.7rem;
  font-size: 0.8rem;
  color: var(--accent-soft);
  text-decoration: none;
}

.mini-link:hover {
  text-decoration: underline;
}

/* Phone layout: board-panel and companion-column stack into one column,
   board first since it's the actual game. The moves box and mini-dashboard
   are desktop-only — mobile was deliberately kept without them (user's
   call after trying both), so don't just reflow them into the mobile
   stack if either ever comes back into this media query by accident. */
@media (max-width: 700px) {
  /* A touch larger than desktop's 78% — easier to make out on a phone-sized
     board. Applies wherever .piece-img renders (Play, Puzzles, Game Review
     all load this stylesheet), since it's the same board rendering code
     and the same "small screen" reasoning on every one of them. */
  .piece-img {
    width: 84%;
    height: 84%;
  }

  .layout {
    flex-direction: column;
    align-items: stretch;
    gap: 1rem;
  }

  /* Scoped to .layout (Play page only) — .side-panel is also game_detail's
     class for its summary/accuracy/moves panel, which must stay visible on
     mobile. A bare .side-panel rule here hid Game Review's panel entirely,
     since style.css is loaded by both pages and this class name is shared. */
  .layout .side-panel,
  .layout .mini-dashboard {
    display: none;
  }

  .layout .board-panel {
    order: 1;
    align-items: center;
  }

  .layout .companion-column {
    order: 3;
    max-width: none;
  }

  .page-header-row {
    flex-wrap: wrap;
  }

  /* Ask Sparrow's button+avatar physically relocate here via JS
     (relocateForMobile in board.js) so it renders just above the taken-
     pieces row instead of down in the companion column. */
  .mobile-ask-sparrow-slot {
    width: 100%;
  }

  .mobile-ask-sparrow-slot .sparrow-companion-row {
    justify-content: center;
  }

  /* Streak badge relocates into the header row (same spot/spirit as
     desktop's "inline with the header" — see alignStreakBadgeWithHeader,
     which no-ops under this same breakpoint so it doesn't fight this). */
  .mobile-streak-slot .streak-badge {
    font-size: 0.85rem;
    padding: 0.3rem 0.6rem;
  }

  /* Reserved empty space for the tactics tag even when there's nothing to
     show (deliberate on desktop, to avoid layout shift when one appears) —
     on a much tighter mobile screen this read as dead space above the
     opening indicator; a small shift when a tactic does appear is an
     acceptable trade here. */
  .tactics-bar {
    min-height: 0;
  }

  /* Flip-orientation always available now (relocated here via JS instead
     of living beside the board, which is what made the board itself
     narrow) — bottom-left of the New game/Undo/Resign group. */
  .board-actions-row-1 {
    display: flex;
    align-items: stretch;
    gap: 0.4rem;
  }

  .mobile-flip-slot {
    flex-shrink: 0;
  }

  .mobile-flip-slot .flip-icon-btn {
    position: static;
    top: auto;
    right: auto;
    transform: none;
    height: 100%;
  }

  .board-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
  }

  .board-actions-primary {
    display: flex;
    flex: 1;
    gap: 0.4rem;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.4rem;
  }

  .board-actions-secondary {
    display: flex;
    gap: 0.4rem;
  }

  .board-actions-primary .btn,
  .board-actions-secondary .btn,
  .board-actions-secondary .personality-select {
    flex: 1;
    min-width: 0;
  }

  .board-actions .btn,
  .board-actions .personality-select {
    padding: 0.3rem 0.4rem;
    font-size: 0.72rem;
  }

  /* Ask Sparrow becomes a large popup on mobile instead of an in-column
     panel — inset (not edge-to-edge) so it reads as a popup with a visible
     border/margin around it (base .ask-sparrow-panel already has a real
     border + border-radius, kept here rather than zeroed out), and stops
     well short of the bottom so it never covers the fixed bottom nav bar
     (60px tall). board.js's sizeAskSparrowPanel already skips its
     desktop-only inline height calc under this same breakpoint. */
  .ask-sparrow-panel {
    position: fixed;
    top: 14px;
    left: 14px;
    right: 14px;
    bottom: 78px;
    width: auto;
    height: auto !important;
    margin-left: 0;
    z-index: 90;
  }

  /* Onboarding stacks a lot more content than other modal-cards (heading,
     description, 3 level buttons, two labeled input rows, hint text,
     tutorial link), so it reads as oversized on a phone even within
     modal-card's normal 90vw cap. Tighten padding and vertical rhythm
     here specifically rather than shrinking modal-card everywhere.
     max-width uses a fixed pixel margin rather than modal-card's 90vw:
     .onboarding-card's own max-width:420px (needed on desktop) replaces
     rather than intersects with modal-card's 90vw cap, so on a phone
     narrower than 420px nothing was actually constraining the card —
     its shrink-to-fit width (driven by the button row's natural width)
     was hitting the viewport edge with zero margin either side. */
  .onboarding-card {
    padding: 1.1rem 1.2rem;
    max-width: calc(100vw - 48px);
  }

  .onboarding-card h2 {
    font-size: 1.05rem;
    margin-bottom: 0.6rem;
  }

  .onboarding-card > .muted {
    font-size: 0.82rem;
  }

  .onboarding-divider {
    margin: 0.55rem 0;
  }

  .onboarding-hint {
    margin-top: 0.6rem;
  }

  /* Beginner/Intermediate/Advanced at .btn's normal padding+font-size
     wanted ~353px total — wider than the now-properly-capped card can
     offer. Shrunk specifically for this row rather than .btn globally. */
  .onboarding-levels {
    gap: 0.4rem;
  }

  .onboarding-level-btn {
    padding: 0.5rem 0.4rem;
    font-size: 0.8rem;
  }

}
