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

body {
  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
  background: #1a1a2e;
  color: #e0e0e0;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 1rem;
}

#game-container {
  /* Wide enough for the two boards and the move-history panel side by side.
     On narrower screens #play-area wraps the panel below the boards. */
  max-width: 1240px;
  width: 100%;
}

header {
  text-align: center;
  margin-bottom: 1rem;
}

header h1 {
  font-size: 1.8rem;
  color: #e0e0e0;
  letter-spacing: 0.05em;
  margin-bottom: 0.4rem;
}

#turn-indicator {
  font-size: 1.1rem;
  font-weight: 600;
  padding: 0.3rem 1rem;
  border-radius: 4px;
  display: inline-block;
}

#turn-indicator.white {
  background: #f0f0f0;
  color: #1a1a2e;
}

#turn-indicator.black {
  background: #333;
  color: #f0f0f0;
}

#game-status {
  font-size: 1rem;
  margin-top: 0.3rem;
  min-height: 1.4em;
}

.status-check { color: #ffa726; font-weight: 700; }
.status-checkmate { color: #ef5350; font-weight: 700; }
.status-stalemate { color: #78909c; font-weight: 700; }

/* ---- play area (boards + move history) ---- */

#play-area {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 1.2rem;
  flex-wrap: wrap;
}

#move-history {
  width: 190px;
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  background: #20203a;
  border: 1px solid #2f2f4a;
  border-radius: 8px;
  overflow: hidden;
}

.mh-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.4rem 0.5rem 0.4rem 0.8rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #90a4ae;
  border-bottom: 1px solid #2f2f4a;
}

.mh-copy {
  font-family: inherit;
  font-size: 0.7rem;
  text-transform: none;
  letter-spacing: normal;
  padding: 0.18rem 0.55rem;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.mh-copy:hover { background: #546e7a; color: #fff; }

.mh-list {
  overflow-y: auto;
  padding: 0.3rem 0.35rem;
  font-family: 'Courier New', monospace;
  font-size: 0.9rem;
}

.mh-row {
  display: grid;
  grid-template-columns: 2.2em 1fr 1fr;
  gap: 0.3rem;
  padding: 0.14rem 0.35rem;
  border-radius: 3px;
}

.mh-row:nth-child(odd) { background: rgba(255, 255, 255, 0.03); }
.mh-num { color: #6b7a8a; }
.mh-move { color: #e0e0e0; }
.mh-empty { color: #6b7a8a; padding: 0.4rem; font-style: italic; }

/* Once the game is over the log becomes a way to navigate it: each move jumps
   the board to the position right after it. */
.mh-list.mh-clickable .mh-move[data-ply] {
  cursor: pointer;
  border-radius: 3px;
  padding: 0 0.2rem;
  margin: 0 -0.2rem;
}
.mh-list.mh-clickable .mh-move[data-ply]:hover { background: rgba(186, 104, 200, 0.22); }
.mh-move.mh-current {
  background: #8e24aa;
  color: #fff;
  font-weight: bold;
}

/* ---- replay controls (shown under the boards once a game has finished) ---- */

#review-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.9rem;
  width: 100%;   /* always its own row inside #play-area, never beside the boards */
}

#review-bar.hidden { display: none; }

/* When the layout stacks — a narrow screen, or phone mode on a big one — the
   move log drops below the boards, and the controls would end up below that:
   a whole scoresheet of scrolling away from the board they drive. Reorder so
   they sit directly under the board instead. */
@media (max-width: 700px) {
  #review-bar { order: 1; }
  #move-history { order: 2; }
}
#play-area:has(#boards-container.phone-mode) #review-bar { order: 1; }
#play-area:has(#boards-container.phone-mode) #move-history { order: 2; }

#review-bar button {
  min-width: 2.6rem;
  padding: 0.4rem 0.6rem;
  font-size: 1rem;
  line-height: 1;
  background: #37474f;
  color: #eceff1;
  border: 1px solid #546e7a;
  border-radius: 5px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
#review-bar button:hover:not(:disabled) { background: #546e7a; color: #fff; }
#review-bar button:disabled { opacity: 0.35; cursor: default; }

#review-bar .rv-play {
  min-width: 6rem;
  font-weight: bold;
  background: #6a1b9a;
  border-color: #8e24aa;
}
#review-bar .rv-play:hover:not(:disabled) { background: #8e24aa; }

.rv-status {
  margin-left: 0.5rem;
  color: #90a4ae;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  min-width: 8em;
}

#review-bar .rv-save {
  min-width: 7rem;
  font-size: 0.85rem;
  border-color: #ab47bc;
  color: #f3e5f5;
}
#review-bar .rv-save:hover:not(:disabled) { background: #6a1b9a; }
#review-bar .rv-save.hidden { display: none; }

/* The outcome of a shared game, which its final position often can't show. */
.status-saved { color: #ce93d8; font-weight: 700; }

/* Share link + Copy, side by side in the save dialog. */
.share-row {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
  margin-bottom: 0.9rem;
}
.share-row .share-input {
  flex: 1 1 auto;
  margin-bottom: 0;
  font-size: 0.85rem;
}
.share-row .share-copy {
  flex: 0 0 auto;
  margin: 0;
  width: auto;
}

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

#boards-container {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 0;
  flex-wrap: wrap;
}

.board-wrapper {
  --board-size: clamp(260px, 40vw, 440px);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.board-label {
  font-size: 0.85rem;
  color: #90a4ae;
  margin-bottom: 0.3rem;
  letter-spacing: 0.03em;
}

.board {
  display: grid;
  /* minmax(0, …) rather than a bare 1fr: a plain 1fr track refuses to shrink
     below its content, so on a narrow board the piece glyphs held the columns
     open, the grid overflowed its own width, and `overflow: hidden` quietly
     ate the h-file. */
  grid-template-columns: repeat(8, minmax(0, 1fr));
  grid-template-rows: repeat(8, minmax(0, 1fr));
  width: var(--board-size);
  height: var(--board-size);
  border: 2px solid #546e7a;
  border-radius: 4px;
  overflow: hidden;
}

/* ---- Möbius "peek" strips (optional display mode) ---- */

/* A 3-rank silhouette of what lies across each seam: near + mid at full height,
   then a half-height far rank that fades out. Hidden unless the reflection
   toggle (#boards-container.reflections-on) is active. */
/* --peek-rows (0–2.5, set at runtime by the slider) controls how many ranks
   are revealed. The grid always holds 3 full-height ranks, but the strip's
   visible height is peek-rows × cell; align-content anchors the near rank to
   the board edge so the outer ranks clip and fade. */
:root { --peek-rows: 1.5; }

.board-peek {
  /* Match the board's inner grid (its 2px border insets the content each side)
     so peek columns line up with the board columns. */
  --cell: calc((var(--board-size) - 4px) / 8);
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(3, var(--cell));
  width: calc(var(--board-size) - 4px);
  height: 0;            /* collapsed until reflection is on — grows/fades in */
  opacity: 0;
  overflow: hidden;
  transition: height 0.2s ease, opacity 0.18s ease;
}

.board-peek.peek-top {
  align-content: end;   /* near rank at the bottom (touching the board), clip the top */
  -webkit-mask-image: linear-gradient(to top, #000 52%, transparent 100%);
          mask-image: linear-gradient(to top, #000 52%, transparent 100%);
}
.board-peek.peek-bottom {
  align-content: start; /* near rank at the top (touching the board), clip the bottom */
  -webkit-mask-image: linear-gradient(to bottom, #000 52%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 52%, transparent 100%);
}

#boards-container.reflections-on .board-peek {
  height: calc(var(--peek-rows) * var(--cell));
  opacity: 1;
}

/* Interactive: peeked squares are real squares across the seam — clicking one
   selects/moves the piece there. A cool purple tint marks it as the reflection
   (the "other side"), distinct from the brown board but still fully playable. */
.board-peek .cell { cursor: pointer; overflow: hidden; }
.board-peek .cell.light { background: #cdc2dc; }
.board-peek .cell.dark  { background: #9b8db3; }
.board-peek .cell.peek-near { opacity: 0.62; }
.board-peek .cell.peek-mid  { opacity: 0.4; }
.board-peek .cell.peek-far  { opacity: 0.22; }

/* Mirror the labels so the strip reads like the reverse side of the board. */
.peek-label { display: inline-block; transform: scaleX(-1); }

.refl-piece {
  font-size: clamp(1.6rem, 3.5vw, 3rem);
  line-height: 1;
  pointer-events: none;
}

.refl-piece.white { color: #f5f5f5; }
.refl-piece.black { color: #2a2a2a; }

/* Reflection view keeps the boards full size; the clocks and captured piles
   move into side gutters (White left, Black right) and the container widens so
   nothing has to shrink or wrap. */
#game-container.reflection-layout { max-width: 1320px; }

.side-gutter { display: none; }

#boards-container.reflections-on .side-gutter {
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: center;
  gap: 0.8rem;
  padding: 0 0.3rem;
  min-width: 150px;
}

.gutter-clock { display: flex; justify-content: center; width: 100%; }
.gutter-clock .clock-box { margin-bottom: 0; }

.captured-side { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; }
.captured-side .captured-label { font-size: 0.72rem; }
.captured-side .captured-pieces {
  font-size: 1.45rem;
  line-height: 1.2;
  max-width: 3.4ch;
  text-align: center;
  word-break: break-all;
}

/* In the split reflection view the gutters replace the bottom info-panel. The
   unified layout keeps the info-panel (reflection-layout is set only for the
   desktop split view — see buildDOM). */
#game-container.reflection-layout #info-panel { display: none; }

/* Reflection mode is ~320px wider than the plain view (a gutter either side), so
   the normal 1240px cap left no room for the move log beside the boards on any
   screen, however large. Give this layout its own cap so a big monitor can
   actually show boards, gutters and log on one row. */
#game-container.reflection-layout { max-width: 1600px; }

/* Keep everything on one row and vertically centered (desktop). The mobile
   layout below stacks into a column instead. */
@media (min-width: 701px) {
  #boards-container.reflections-on { flex-wrap: nowrap; align-items: center; }

  /* Reflection mode adds a ~185px gutter either side, which made the boards
     wider than the play area on their own — so the move log wrapped underneath
     them instead of sitting on the right. The page width is fixed, so the boards
     take what's left after the gutters, the twist column and the log: full size
     wherever there's room (roughly 1590px and up, i.e. no change on a large
     screen), shrinking only as far as it must below that.

     The reserve counts a gutter at its FULL width — the clock in it is now a
     fixed size that already fits the tenths (see .clock-time), so this number
     covers the last ten seconds as well as the rest of the game. Reserving the
     narrower figure is what let the log jump below the boards mid-game. */
  #boards-container.reflections-on .board-wrapper {
    --board-size: clamp(260px, calc((min(100vw - 32px, 1600px) - 662px) / 2), 440px);
  }
}

#flip-btn {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.6rem;
  font-size: 0.95rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  transition: background 0.15s;
}

#flip-btn:hover { background: #546e7a; }

#display-btn {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.9rem;
  font-size: 0.85rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

#display-btn:hover { background: #546e7a; color: #fff; }

#display-btn.active {
  border-color: #ab47bc;
  background: rgba(171, 71, 188, 0.2);
  color: #ce93d8;
}

#peek-range {
  vertical-align: middle;
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  width: 110px;
  accent-color: #ab47bc;
  cursor: pointer;
}

#peek-range[hidden] { display: none; }

/* ---- display tray ----
   The look-and-feel controls used to sit loose in the header, where seven of
   them wrapped into rows above the board. They now fold away behind ⚙ Display;
   the tray is the last child of <header>, so as a block in that centered inline
   row it lands on its own line directly beneath the button. */

#customize-btn {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.9rem;
  font-size: 0.85rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

#customize-btn:hover { background: #546e7a; color: #fff; }

#customize-btn.active {
  border-color: #ab47bc;
  background: rgba(171, 71, 188, 0.2);
  color: #ce93d8;
}

#customize-btn .caret {
  display: inline-block;
  font-size: 0.7em;
  transition: transform 0.15s;
}

#customize-btn[aria-expanded="true"] .caret { transform: rotate(180deg); }

#display-panel {
  /* Block, so it breaks the header's inline row and starts a line of its own;
     fit-content + auto margins keep it wrapped around its controls and centred
     rather than spanning the page. */
  display: block;
  width: fit-content;
  margin: 0.7rem auto 0;
  padding: 0.35rem 0.9rem 0.7rem;
  border: 1px solid #3a3a5a;
  border-radius: 8px;
  background: rgba(171, 71, 188, 0.06);
  max-width: 100%;
}

#display-panel[hidden] { display: none; }

/* Inside the tray the controls keep their own spacing rules; they just don't
   need the top margin that separated them from the title row out in the open. */
#display-panel #display-btn,
#display-panel #unify-btn,
#display-panel #peek-range,
#display-panel .autodecline-opt { margin-top: 0.35rem; }

/* ---- twist connector ---- */

#twist-connector {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 0.6rem;
  min-width: 60px;
}

.twist-label {
  font-size: 0.8rem;
  color: #ab47bc;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 0.4rem;
}

.twist-arrows {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.twist-map {
  font-size: 0.7rem;
  color: #ce93d8;
  text-align: center;
  font-family: monospace;
}

/* ---- cells ---- */

.cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background 0.12s;
}

.cell.light { background: #e8d5b5; }
.cell.dark  { background: #b58863; }

.cell.selected        { background: #f6d94e !important; }
.cell.last-move-from  { background: #c8e6a0 !important; }
.cell.last-move-to    { background: #aad576 !important; }
.cell.in-check        { background: #ef5350 !important; }

.cell.legal-move::after {
  content: '';
  position: absolute;
  width: 28%;
  height: 28%;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.25);
  pointer-events: none;
}

.cell.legal-capture {
  box-shadow: inset 0 0 0 4px rgba(239, 83, 80, 0.7);
}

/* Move preview (look-only): a piece that isn't yours to move right now. Blue,
   and marked with an X rather than the solid dot/ring of a playable move, so it
   reads unmistakably as "you cannot move here yet". */
.cell.preview-from { background: #d98a99 !important; }

.cell.preview-move::after {
  content: '';
  position: absolute;
  width: 38%;
  height: 38%;
  pointer-events: none;
  /* Thicker bands with a soft feathered ramp on each edge, plus a gentle blur,
     so the X reads as a soft marker rather than a crisp glyph. */
  background:
    linear-gradient(45deg,  transparent 34%, rgba(214, 48, 49, 0.75) 44%, rgba(214, 48, 49, 0.75) 56%, transparent 66%),
    linear-gradient(-45deg, transparent 34%, rgba(214, 48, 49, 0.75) 44%, rgba(214, 48, 49, 0.75) 56%, transparent 66%);
  filter: blur(0.6px);
}

/* On a capturable piece, ring the square too so the target piece stays readable. */
.cell.preview-capture {
  box-shadow: inset 0 0 0 4px rgba(200, 95, 120, 0.8);
}

.cell:hover {
  filter: brightness(1.08);
}

/* ---- pieces ---- */

/* Belt and braces with the U+FE0E in js/pieces.js: every surface that draws a
   piece glyph asks for the text presentation explicitly, so the black pawn
   (the one chess codepoint that is also an emoji) cannot be hijacked by the
   colour emoji font and rendered as an oversized square. Ignored by browsers
   that don't know the property — the variation selector still covers those. */
.piece,
.refl-piece,
.captured-pieces,
.promo-btn,
.mode-preview,
.bg-glyph {
  font-variant-emoji: text;
}

.piece {
  /* Sized against the viewport, but never bigger than the square it sits in.
     The viewport clamp alone assumed the board grows with the window, which
     stops being true once --board-size hits its cap or has to shrink to make
     room (reflection mode) — and an oversized glyph then spills out of its
     cell. The 0.88 leaves the normal view exactly as it was; it only bites
     when the square is the smaller constraint. --board-size is inherited from
     .board-wrapper / .unified-wrapper, so this follows whichever is in use. */
  font-size: min(clamp(1.6rem, 3.5vw, 3rem), calc((var(--board-size) - 4px) / 8 * 0.88));
  line-height: 1;
  pointer-events: none;
  text-shadow: 0 1px 3px rgba(0,0,0,0.3);
  z-index: 1;
}

.piece.white { color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,0.5); }
.piece.black { color: #222; text-shadow: 0 1px 2px rgba(255,255,255,0.2); }

/* Reverse-side orientation ("Reverse pieces" in the header). The negative ranks
   are the far side of the strip, reached by crossing a seam — which turns
   everything through 180°. `data-rank` starts with '-' on exactly those squares
   in every layout, so one selector covers board 2, the phone extension rows and
   the reflection peeks alike. The glyphs are inline spans, and transforms don't
   apply to inline boxes, hence inline-block. */
#boards-container.flip-all .cell[data-rank^="-"] .piece,
#boards-container.flip-all .cell[data-rank^="-"] .refl-piece,
#boards-container.flip-pawns .cell[data-rank^="-"] .piece.pc-pawn,
#boards-container.flip-pawns .cell[data-rank^="-"] .refl-piece.pc-pawn {
  display: inline-block;
  transform: rotate(180deg);
}

/* ---- labels ---- */

.rank-label {
  position: absolute;
  top: 2px;
  left: 3px;
  font-size: clamp(0.5rem, 1vw, 0.7rem);
  color: rgba(0, 0, 0, 0.45);
  pointer-events: none;
  font-weight: 600;
  z-index: 2;
}

.file-label {
  position: absolute;
  bottom: 2px;
  right: 3px;
  font-size: clamp(0.5rem, 1vw, 0.7rem);
  color: rgba(0, 0, 0, 0.45);
  pointer-events: none;
  font-weight: 600;
  z-index: 2;
}

/* ---- info panel ---- */

#info-panel {
  display: flex;
  justify-content: center;
  gap: 2rem;
  margin-top: 1rem;
  flex-wrap: wrap;
}

.captured-group {
  text-align: center;
}

.captured-label {
  font-size: 0.8rem;
  color: #90a4ae;
  display: block;
  margin-bottom: 0.2rem;
}

.captured-pieces {
  font-size: 1.3rem;
  min-height: 1.5em;
  letter-spacing: 0.1em;
}

/* ---- modals ---- */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.modal.hidden { display: none; }

.modal-content {
  position: relative;
  background: #263238;
  padding: 2rem;
  border-radius: 8px;
  text-align: center;
  min-width: 200px;
}

.modal-close {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  border: none;
  background: transparent;
  color: #90a4ae;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.1rem 0.35rem;
}

.modal-close:hover { color: #fff; }

.modal-actions {
  display: flex;
  gap: 0.8rem;
  justify-content: center;
  flex-wrap: wrap;
}

.modal-btn-secondary {
  padding: 0.6rem 1.4rem;
  font-size: 1.1rem;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  cursor: pointer;
  background: transparent;
  color: #cfd8dc;
  transition: background 0.15s, color 0.15s;
}

.modal-btn-secondary:hover { background: #546e7a; color: #fff; }

/* Resign confirm — destructive, so it reads as a warning. */
#resign-confirm {
  padding: 0.6rem 1.4rem;
  font-size: 1.1rem;
  font-family: inherit;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background: #b3413a;
  color: #fff;
  transition: background 0.15s;
}

#resign-confirm:hover { background: #c85a52; }

.modal-content p {
  margin-bottom: 1rem;
  font-size: 1.1rem;
}

.promo-btn, #new-game-btn, #request-accept, #resume-btn {
  padding: 0.6rem 1.4rem;
  font-size: 1.1rem;
  font-family: inherit;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  background: #546e7a;
  color: #fff;
  transition: background 0.15s;
}

.promo-btn:hover, #new-game-btn:hover, #request-accept:hover, #resume-btn:hover {
  background: #78909c;
}

/* ---- unified single board (phone layout, or the Single-board toggle) ---- */

.unified-wrapper { --board-size: min(94vw, 360px); }

/* Explicit square cells (8 wide × 16 tall) — deterministic, no aspect-ratio or
   1fr rounding that could clip the last column/row. */
.board-unified {
  --ucell: calc((var(--board-size) - 4px) / 8);  /* minus the 2px border each side */
  grid-template-columns: repeat(8, var(--ucell));
  grid-template-rows: repeat(16, var(--ucell));
  width: var(--board-size);
  height: auto;
}

/* Mark the two internal twist seams so the mirrored rows are legible. */
.board-unified .cell.seam-edge { box-shadow: inset 0 2px 0 0 rgba(206, 147, 216, 0.9); }

/* Extension = the wrapped-around (negative-rank) rows. "Mirrored extension"
   (on by default) flips their labels like reflection mode's peek labels;
   "Purple extension" (off by default) tints those rows the same purple as the
   reflection peeks. The selectors out-specify .cell.light / .cell.dark. */
.board-unified.mirror-ext .ext-label { transform: scaleX(-1); }
.board-unified.purple-ext .cell.ext-cell.light { background: #cdc2dc; }
.board-unified.purple-ext .cell.ext-cell.dark  { background: #9b8db3; }

/* Rainbow mode: give each wrapped-around (negative-rank) row its own hue so the
   eight "other side" ranks are easy to tell apart. Works for both the reflection
   peeks and the phone extension rows — both carry data-rank + .light/.dark. The
   light/dark pair per rank keeps the checkerboard readable; the #boards-container
   id keeps these ahead of the base shade and purple-ext rules. Red → violet. */
#boards-container.rainbow-on .cell[data-rank="-1"].light { background: hsl(2 70% 80%); }
#boards-container.rainbow-on .cell[data-rank="-1"].dark  { background: hsl(2 58% 67%); }
#boards-container.rainbow-on .cell[data-rank="-2"].light { background: hsl(28 74% 78%); }
#boards-container.rainbow-on .cell[data-rank="-2"].dark  { background: hsl(28 62% 64%); }
#boards-container.rainbow-on .cell[data-rank="-3"].light { background: hsl(48 72% 75%); }
#boards-container.rainbow-on .cell[data-rank="-3"].dark  { background: hsl(46 60% 61%); }
#boards-container.rainbow-on .cell[data-rank="-4"].light { background: hsl(135 42% 76%); }
#boards-container.rainbow-on .cell[data-rank="-4"].dark  { background: hsl(138 36% 59%); }
#boards-container.rainbow-on .cell[data-rank="-5"].light { background: hsl(188 50% 76%); }
#boards-container.rainbow-on .cell[data-rank="-5"].dark  { background: hsl(190 44% 59%); }
#boards-container.rainbow-on .cell[data-rank="-6"].light { background: hsl(214 62% 81%); }
#boards-container.rainbow-on .cell[data-rank="-6"].dark  { background: hsl(214 50% 66%); }
#boards-container.rainbow-on .cell[data-rank="-7"].light { background: hsl(258 50% 82%); }
#boards-container.rainbow-on .cell[data-rank="-7"].dark  { background: hsl(258 42% 70%); }
#boards-container.rainbow-on .cell[data-rank="-8"].light { background: hsl(300 46% 82%); }
#boards-container.rainbow-on .cell[data-rank="-8"].dark  { background: hsl(300 38% 70%); }

/* Peeks on the unified board must size their columns exactly like the board
   (explicit cell width, not 1fr) or fractional-pixel rounding drifts them out of
   line with the board columns on the small phone cells. */
.board-peek.unified-peek {
  grid-template-columns: repeat(8, calc((var(--board-size) - 4px) / 8));
}

/* The unified layout stacks vertically (clock, board, clock) — that's the phone
   arrangement, and the fallback everywhere too narrow for the flanking rule below. */
#boards-container.phone-mode {
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
}

.phone-mode .clock-box { margin: 0; min-width: 130px; }

/* Unified board on a screen with room beside it (i.e. the Single-board toggle on
   a desktop, not an actual phone). The 8×16 board is ~715px tall, so bracketing
   it above and below pushes the lower clock off the bottom of a laptop screen —
   you simply never see your own clock. Here the clocks move into the empty side
   margins instead and stick to the top of the viewport while you scroll.

   They live in their own grid columns, so "floating" can never put a clock over
   the board: column 2 is the board's and nothing else is ever placed in it. */
@media (min-width: 760px) {
  #boards-container.phone-mode {
    display: grid;
    grid-template-columns: 1fr auto 1fr; /* equal margins keep the board centred */
    align-items: start;
    column-gap: 1rem;
  }
  .phone-mode > .clock-top,
  .phone-mode > .clock-bottom {
    grid-row: 1;
    position: sticky;
    top: 0.75rem;
    margin: 0;
  }
  .phone-mode > .clock-top       { grid-column: 1; justify-self: end; }
  .phone-mode > .unified-wrapper { grid-column: 2; grid-row: 1; }
  .phone-mode > .clock-bottom    { grid-column: 3; justify-self: start; }
}

#unify-btn {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.9rem;
  font-size: 0.85rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

#unify-btn:hover { background: #546e7a; color: #fff; }

#unify-btn.active {
  border-color: #ab47bc;
  background: rgba(171, 71, 188, 0.2);
  color: #ce93d8;
}

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

@media (max-width: 700px) {
  #boards-container {
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
  }

  .board-wrapper {
    --board-size: clamp(280px, 85vw, 440px);
  }

  /* The unified board is 8 wide but SIXTEEN tall, so sizing it by width alone
     makes it about two viewport-widths tall — taller than the phone screen. With
     reflection mode on it grows by a peek strip at each end (peek-rows × cell
     apiece, 1.5 by default → 19 rows in all), and then the board cannot be seen
     in one piece at any scroll position. So cap it by the viewport height too.

     dvh, not vh: on phones vh is the height with the URL bar *hidden*, which is
     exactly the overestimate that let this overflow in the first place. The vh
     line is the fallback for browsers without dvh. The 240px floor keeps a very
     short screen (landscape) from shrinking the board into uselessness — that
     case scrolls, as before. */
  #boards-container.phone-mode .unified-wrapper {
    --unified-rows: 16;
    --board-size: max(240px, min(85vw, calc((100vh - 110px) / var(--unified-rows) * 8)));
    --board-size: max(240px, min(85vw, calc((100dvh - 110px) / var(--unified-rows) * 8)));
  }
  #boards-container.phone-mode.reflections-on .unified-wrapper {
    --unified-rows: calc(16 + 2 * var(--peek-rows, 0));
  }
}

/* ---- setup / mode-selection screen ---- */

#setup-screen {
  max-width: 760px;
  margin: 3rem auto 0;
  text-align: center;
  padding: 1rem;
  animation: setup-fade 0.4s ease;
}

@keyframes setup-fade {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}

#setup-title {
  font-size: clamp(2rem, 6vw, 3.2rem);
  letter-spacing: 0.06em;
  color: #f0f0f0;
  margin-bottom: 0.3rem;
}

#setup-subtitle {
  color: #ab47bc;
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-bottom: 2rem;
}

#mode-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

@media (max-width: 600px) {
  #mode-grid { grid-template-columns: repeat(2, 1fr); }
}

.mode-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1.4rem 0.8rem;
  background: linear-gradient(160deg, #29293f, #20203a);
  border: 1px solid #3a3a5a;
  border-radius: 10px;
  cursor: pointer;
  color: #e0e0e0;
  font-family: inherit;
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.mode-card:hover {
  transform: translateY(-3px);
  border-color: #ab47bc;
  box-shadow: 0 6px 20px rgba(171, 71, 188, 0.25);
}

.mode-preview {
  font-size: 1.7rem;
  line-height: 1;
  color: #ce93d8;
  letter-spacing: 0.05em;
}

.mode-name {
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* ---- header reset button ---- */

#reset-btn {
  margin-top: 0.6rem;
  padding: 0.35rem 1rem;
  font-size: 0.85rem;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

#sound-btn {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.6rem;
  font-size: 0.95rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  cursor: pointer;
  transition: background 0.15s;
}

#sound-btn:hover { background: #546e7a; }

#reset-btn:hover {
  background: #546e7a;
  color: #fff;
}

/* ---- in-game action buttons (offer draw / pause) ---- */

.game-action {
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  padding: 0.35rem 0.9rem;
  font-size: 0.85rem;
  line-height: 1;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.game-action:hover:not(:disabled) { background: #546e7a; color: #fff; }

.game-action:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* ---- auto-decline checkboxes ---- */

.autodecline-opt {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.6rem;
  margin-right: 0.5rem;
  font-size: 0.8rem;
  color: #90a4ae;
  cursor: pointer;
  user-select: none;
}

/* The one dropdown among the header options ("Reverse pieces"), styled to sit
   with the buttons rather than as a raw OS control. */
.autodecline-opt select {
  font-family: inherit;
  font-size: 0.8rem;
  line-height: 1;
  padding: 0.2rem 0.3rem;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: #263238;
  color: #cfd8dc;
  cursor: pointer;
}

.autodecline-opt select:hover { border-color: #ab47bc; color: #fff; }

/* The `hidden` attribute must win over the inline-flex above (used to show the
   phone-layout extension toggles only after Phone mode is selected). */
.autodecline-opt[hidden] { display: none; }

.autodecline-opt input {
  accent-color: #ab47bc;
  cursor: pointer;
}

/* ---- pause bar (non-blocking; keeps the whole board visible) ---- */

.pause-bar {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.6rem 0.75rem 0.6rem 1.1rem;
  background: rgba(38, 50, 56, 0.97);
  border: 1px solid #ab47bc;
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
  z-index: 130;
}

.pause-bar.hidden { display: none; }

.pause-bar-label {
  font-size: 1rem;
  font-weight: 600;
  color: #ce93d8;
  letter-spacing: 0.02em;
}

.pause-bar #resume-btn {
  padding: 0.35rem 1rem;
  font-size: 0.95rem;
}

/* ---- transient toast notice ---- */

#toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translate(-50%, 1rem);
  background: #37474f;
  color: #eceff1;
  padding: 0.6rem 1.1rem;
  border-radius: 6px;
  border: 1px solid #546e7a;
  font-size: 0.9rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s, transform 0.2s;
  z-index: 120;
}

#toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---- setup: selected state, time control, start ---- */

.mode-card.selected {
  border-color: #ab47bc;
  box-shadow: 0 0 0 2px rgba(171, 71, 188, 0.5), 0 6px 20px rgba(171, 71, 188, 0.25);
  background: linear-gradient(160deg, #33334d, #262642);
}

.setup-section-label {
  margin-top: 2rem;
  margin-bottom: 0.9rem;
  color: #90a4ae;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
}

#time-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.8rem;
  max-width: 480px;
  margin: 0 auto;
}

.time-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.9rem 0.6rem;
  background: linear-gradient(160deg, #29293f, #20203a);
  border: 1px solid #3a3a5a;
  border-radius: 10px;
  cursor: pointer;
  color: #e0e0e0;
  font-family: inherit;
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.time-card:hover {
  transform: translateY(-2px);
  border-color: #ab47bc;
}

.time-card.selected {
  border-color: #ab47bc;
  box-shadow: 0 0 0 2px rgba(171, 71, 188, 0.5);
  background: linear-gradient(160deg, #33334d, #262642);
}

.time-short {
  font-size: 1.2rem;
  font-weight: 700;
  color: #ce93d8;
  font-family: 'Courier New', monospace;
  letter-spacing: 0.04em;
}

.time-name {
  font-size: 0.78rem;
  color: #b0bec5;
}

#start-btn {
  margin-top: 2.2rem;
  padding: 0.8rem 2.6rem;
  font-size: 1.1rem;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: 0.04em;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: #fff;
  background: linear-gradient(135deg, #ab47bc, #7b1fa2);
  box-shadow: 0 6px 18px rgba(123, 31, 162, 0.4);
  transition: transform 0.15s, box-shadow 0.15s;
}

#start-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 9px 24px rgba(123, 31, 162, 0.5);
}

/* ---- profile: recent games ---- */

.pf-recent { margin-top: 0.4rem; }
.rg-list { display: flex; flex-direction: column; gap: 0.35rem; }

.rg-row {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.45rem 0.55rem;
  border-radius: 6px;
  background: #1b1b31;
  border-left: 3px solid #546e7a;   /* the result, readable before you read anything */
}
.rg-row[hidden] { display: none; }   /* [hidden] alone loses to display:flex */
.rg-row.win  { border-left-color: #aad576; }
.rg-row.loss { border-left-color: #ef5350; }
.rg-row.draw { border-left-color: #78909c; }

.rg-mark {
  flex: none;
  width: 1.4rem;
  text-align: center;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.5;
  color: #90a4ae;
}
.rg-row.win .rg-mark  { color: #aad576; }
.rg-row.loss .rg-mark { color: #ef5350; }

.rg-main { flex: 1; min-width: 0; }
.rg-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.rg-opp { font-size: 0.92rem; color: #e0e0e0; }
.rg-bot {
  margin-left: 0.35rem;
  padding: 0.05rem 0.3rem;
  border: 1px solid #546e7a;
  border-radius: 3px;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #90a4ae;
}
.rg-end { font-size: 0.75rem; color: #90a4ae; }

/* Both ladders on one line where there's room, wrapping to two when there
   isn't — four numbers is a lot to fit on a phone. */
.rg-runs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.9rem;
  margin-top: 0.15rem;
  font-size: 0.78rem;
  color: #90a4ae;
  font-variant-numeric: tabular-nums;
}
.rg-who { color: #78909c; }
.rg-run b { color: #e0e0e0; font-weight: 600; }
.rg-delta.up   { color: #aad576; }
.rg-delta.down { color: #ef5350; }
.rg-delta.even { color: #78909c; }

.pf-more { margin-top: 0.5rem; }

/* ---- in-game clocks ---- */

.clock-box {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.6rem;
  margin-bottom: 0.4rem;
  padding: 0.35rem 1rem;
  border-radius: 6px;
  background: #20203a;
  border: 1px solid #2f2f4a;
  min-width: 150px;
  transition: background 0.2s, border-color 0.2s, box-shadow 0.2s;
}

.clock-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #90a4ae;
}

.clock-time {
  font-family: 'Courier New', monospace;
  font-size: 1.5rem;
  font-weight: 700;
  color: #e0e0e0;
  font-variant-numeric: tabular-nums;
  /* Sized for the WIDEST reading it can ever show, not the usual one. Under ten
     seconds the clock switches to tenths (js/clock.js), so "0:09" becomes
     "0:09.4" — two characters more. Reserving only four meant the box grew at
     the ten-second mark, and in the reflection view that widened both gutters
     enough to wrap the move log below the boards, mid-game, exactly when you
     were least able to afford looking away. Six also covers a long game's
     "120:00", so the box is one fixed size in every state it has. */
  min-width: 6ch;
  text-align: right;
}

.clock-box.active {
  border-color: #aad576;
  background: #25351f;
  box-shadow: 0 0 12px rgba(170, 213, 118, 0.3);
}

.clock-box.active .clock-time { color: #c8e6a0; }

.clock-box.low .clock-time { color: #ffa726; }

.clock-box.active.low {
  border-color: #ffa726;
  background: #3a2a14;
  box-shadow: 0 0 12px rgba(255, 167, 38, 0.35);
}

.clock-box.flagged {
  border-color: #ef5350;
  background: #3a1a1a;
}

.clock-box.flagged .clock-time { color: #ef5350; }

/* ---- online play: setup buttons ---- */

#start-row {
  display: flex;
  gap: 1rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 2.2rem;
}

#start-row #start-btn { margin-top: 0; }

#online-btn {
  padding: 0.8rem 2.6rem;
  font-size: 1.1rem;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: 0.04em;
  border-radius: 8px;
  cursor: pointer;
  color: #ce93d8;
  background: transparent;
  border: 1px solid #ab47bc;
  transition: transform 0.15s, background 0.15s, color 0.15s;
}

#online-btn:hover {
  transform: translateY(-2px);
  background: rgba(171, 71, 188, 0.15);
  color: #fff;
}

/* ---- bots: setup button, picker, in-game indicator ---- */

#bot-btn, #bot-back-btn {
  padding: 0.8rem 2.6rem;
  font-size: 1.1rem;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: 0.04em;
  border-radius: 8px;
  cursor: pointer;
  color: #ce93d8;
  background: transparent;
  border: 1px solid #ab47bc;
  transition: transform 0.15s, background 0.15s, color 0.15s;
}

#bot-btn:hover, #bot-back-btn:hover {
  transform: translateY(-2px);
  background: rgba(171, 71, 188, 0.15);
  color: #fff;
}

#bot-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.8rem;
  margin-top: 1.2rem;
}

@media (max-width: 560px) { #bot-grid { grid-template-columns: 1fr; } }

.bot-card {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.9rem 1rem;
  text-align: left;
  border: 1px solid #2f2f4a;
  border-radius: 10px;
  background: #20203a;
  color: #e0e0e0;
  cursor: pointer;
  font-family: inherit;
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.bot-card:hover {
  transform: translateY(-2px);
  border-color: #ab47bc;
  box-shadow: 0 6px 20px rgba(171, 71, 188, 0.2);
}

.bot-card.selected {
  border-color: #ab47bc;
  box-shadow: 0 0 0 2px rgba(171, 71, 188, 0.5);
  background: linear-gradient(160deg, #33334d, #262642);
}

.bot-name { font-size: 1.05rem; font-weight: 700; color: #ce93d8; }
.bot-blurb { font-size: 0.85rem; color: #b0bec5; line-height: 1.35; }

.bot-level { display: flex; gap: 0.3rem; margin-top: 0.2rem; }
.bot-level .pip {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  border: 1px solid #546e7a;
}
.bot-level .pip.on { background: #ab47bc; border-color: #ab47bc; }

#bot-color-row {
  display: flex;
  gap: 0.8rem;
  justify-content: center;
  margin-top: 0.6rem;
}

.color-card {
  padding: 0.5rem 1.6rem;
  font-size: 1rem;
  font-family: inherit;
  border: 1px solid #2f2f4a;
  border-radius: 8px;
  background: #20203a;
  color: #cfd8dc;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.color-card.selected {
  border-color: #ab47bc;
  box-shadow: 0 0 0 2px rgba(171, 71, 188, 0.5);
}

#bot-indicator,
#opp-indicator {
  font-size: 0.9rem;
  color: #90a4ae;
  margin-top: 0.2rem;
}

#opp-indicator:empty { display: none; } /* room links carry no identity */

#bot-indicator.thinking { color: #ce93d8; }

/* ---- online play: lobby / share screen ---- */

#lobby-screen {
  max-width: 620px;
  margin: 3rem auto 0;
  text-align: center;
  padding: 1rem;
  animation: setup-fade 0.4s ease;
}

.lobby-instructions {
  color: #b0bec5;
  font-size: 1rem;
  line-height: 1.5;
  max-width: 460px;
  margin: 0 auto 1.6rem;
}

.share-row {
  display: flex;
  gap: 0.6rem;
  max-width: 520px;
  margin: 0 auto;
}

.share-input {
  flex: 1;
  padding: 0.7rem 0.9rem;
  font-family: 'Courier New', monospace;
  font-size: 0.95rem;
  color: #e0e0e0;
  background: #20203a;
  border: 1px solid #3a3a5a;
  border-radius: 8px;
}

.lobby-btn {
  padding: 0.7rem 1.6rem;
  font-size: 1rem;
  font-weight: 600;
  font-family: inherit;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: #fff;
  background: linear-gradient(135deg, #ab47bc, #7b1fa2);
  box-shadow: 0 6px 18px rgba(123, 31, 162, 0.4);
  transition: transform 0.15s, box-shadow 0.15s;
}

.lobby-btn:hover { transform: translateY(-2px); }

.copy-feedback {
  min-height: 1.2rem;
  margin: 0.6rem 0 0;
  color: #66bb6a;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}

.waiting-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  margin-top: 2rem;
  color: #90a4ae;
  font-size: 0.95rem;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid #3a3a5a;
  border-top-color: #ab47bc;
  border-radius: 50%;
  display: inline-block;
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.lobby-cancel {
  margin-top: 2rem;
  padding: 0.4rem 1.2rem;
  font-size: 0.85rem;
  font-family: inherit;
  border: 1px solid #546e7a;
  border-radius: 4px;
  background: transparent;
  color: #90a4ae;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.lobby-cancel:hover { background: #546e7a; color: #fff; }

/* ---- online play: in-game seat / connection indicators ---- */

#seat-indicator {
  margin-top: 0.3rem;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: #b0bec5;
}

#seat-indicator.white { color: #eceff1; }
#seat-indicator.black { color: #b0bec5; }
#seat-indicator.your-turn { color: #ce93d8; }

#conn-indicator {
  min-height: 1rem;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: #ffa726;
}

#conn-indicator.conn-lost::before { content: '● '; }

/* ================= Home / landing screen ================= */

#home-screen {
  max-width: 720px;
  margin: 2.5rem auto 0;
  padding: 1rem 1.2rem 3rem;
  text-align: center;
  animation: setup-fade 0.4s ease;
}

#home-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2.6rem;
}

/* Animated brand: "MChess" that expands to "Möbius Chess" on hover. */
.brand {
  cursor: default;
  user-select: none;
  font-size: clamp(1.6rem, 5vw, 2.4rem);
  letter-spacing: 0.05em;
  color: #f0f0f0;
  font-weight: 700;
}
.brand .brand-text { display: inline-flex; align-items: baseline; }
.brand .b-ext {
  display: inline-block;
  max-width: 0;
  overflow: hidden;
  opacity: 0;
  white-space: pre;      /* preserve the trailing space */
  color: #ce93d8;
  transition: max-width 0.45s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s ease;
}
.brand:hover .b-ext,
.brand:focus-within .b-ext {
  max-width: 6ch;
  opacity: 1;
}

/* Login / profile corner. A page-level element (index.html) rather than part of
   any screen, so it survives navigation — every screen replaces the whole of
   #game-container, which is how it used to disappear on the leaderboard.
   Fixed, so it stays put while a long standings table scrolls under it. */
#site-corner {
  position: fixed;
  top: 1rem;
  right: 1rem;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 2.2rem;
}

#site-corner[hidden] { display: none; }   /* a board hides it; [hidden] alone loses to display:flex */

/* The home screen's own top row keeps the brand and nothing else now, so it no
   longer needs to reserve the right-hand side for the corner. */
#home-top { padding-right: 9rem; }

@media (max-width: 560px) {
  #site-corner { top: 0.5rem; right: 0.5rem; }
  #home-top { padding-right: 4.5rem; }
  /* On a narrow screen the name and rating give way to the avatar alone —
     there isn't room for both beside the brand. */
  #site-corner .auth-name { display: none; }
}
.auth-login,
.auth-name {
  font-family: inherit;
  font-size: 0.9rem;
  color: #e0e0e0;
  background: transparent;
  border: 1px solid #546e7a;
  border-radius: 6px;
  padding: 0.4rem 0.9rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.auth-login:hover,
.auth-name:hover { background: #546e7a; color: #fff; }
.auth-name {
  border-color: #ab47bc;
  display: flex;
  flex-direction: column;   /* name over rating */
  align-items: flex-end;
  gap: 0.1rem;
  line-height: 1.15;
  padding: 0.32rem 0.9rem;
  text-align: right;
}
.auth-who { font-size: 0.9rem; }
.auth-rating {
  font-size: 0.72rem;
  color: #ce93d8;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.03em;
}
/* Provisional ratings are mostly still the 1500 everyone starts at — shown, but
   not dressed up as a real number. */
.auth-rating.provisional { color: #90a4ae; }
.auth-name:hover .auth-rating { color: #f3e5f5; }
.auth-avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(150deg, #ab47bc, #7e3f9e);
  transition: transform 0.15s;
}
.auth-avatar:hover { transform: scale(1.06); }

/* primary matchmaking buttons */
#home-actions {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 460px;
  margin: 0 auto;
}
.home-big {
  font-family: inherit;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #e0e0e0;
  padding: 1.1rem 1rem;
  border-radius: 10px;
  border: 1px solid #3a3a5a;
  background: linear-gradient(160deg, #29293f, #20203a);
  cursor: pointer;
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.home-big:hover {
  transform: translateY(-2px);
  border-color: #ab47bc;
  box-shadow: 0 6px 20px rgba(171, 71, 188, 0.25);
}
.home-big.primary {
  color: #fff;
  border-color: #ab47bc;
  background: linear-gradient(160deg, #7e3f9e, #5e2f78);
}

/* matchmaking options */
.mm-note {
  margin: 1.1rem auto 0.4rem;
  color: #90a4ae;
  font-size: 0.82rem;
  letter-spacing: 0.03em;
}
.mm-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: #b0bec5;
  font-size: 0.85rem;
  cursor: pointer;
}
.mm-toggle input { accent-color: #ab47bc; width: 1rem; height: 1rem; cursor: pointer; }

/* secondary row */
#home-secondary {
  display: flex;
  justify-content: center;
  gap: 1rem;
  margin-top: 2rem;
}
.home-small {
  font-family: inherit;
  font-size: 0.95rem;
  color: #cfd8dc;
  background: transparent;
  border: 1px solid #546e7a;
  border-radius: 8px;
  padding: 0.7rem 1.4rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.home-small:hover { background: #546e7a; color: #fff; }

.setup-back {
  position: absolute;
  left: 1rem;
  top: 1rem;
  font-family: inherit;
  font-size: 0.85rem;
  color: #90a4ae;
  background: transparent;
  border: 1px solid #546e7a;
  border-radius: 6px;
  padding: 0.35rem 0.8rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.setup-back:hover { background: #546e7a; color: #fff; }

/* toast */
.home-toast {
  position: fixed;
  left: 50%;
  bottom: 2rem;
  transform: translate(-50%, 1rem);
  background: #263238;
  color: #eceff1;
  border: 1px solid #455a64;
  border-radius: 8px;
  padding: 0.7rem 1.2rem;
  font-size: 0.9rem;
  opacity: 0;
  transition: opacity 0.28s ease, transform 0.28s ease;
  z-index: 1000;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.home-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ================= Auth modals ================= */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  z-index: 1100;
  animation: setup-fade 0.2s ease;
}
.modal-card {
  position: relative;
  background: linear-gradient(160deg, #29293f, #20203a);
  border: 1px solid #3a3a5a;
  border-radius: 12px;
  padding: 1.8rem 1.6rem;
  width: min(400px, 100%);
  text-align: center;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
}
.modal-x {
  position: absolute;
  top: 10px;
  right: 12px;
  background: none;
  border: none;
  color: #90a4ae;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 4px;
  transition: color 0.15s;
}
.modal-x:hover { color: #f0f0f0; }
.modal-title {
  color: #f0f0f0;
  font-size: 1.4rem;
  margin-bottom: 0.5rem;
}
.modal-sub {
  color: #b0bec5;
  font-size: 0.9rem;
  line-height: 1.5;
  margin-bottom: 1.2rem;
}
.modal-input {
  width: 100%;
  box-sizing: border-box;
  font-family: inherit;
  font-size: 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: 8px;
  border: 1px solid #546e7a;
  background: #1a1a2e;
  color: #f0f0f0;
  margin-bottom: 0.4rem;
}
.modal-input:focus { outline: none; border-color: #ab47bc; }
.modal-error {
  color: #ef9a9a;
  font-size: 0.82rem;
  min-height: 1.1rem;
  margin-bottom: 0.6rem;
}
.modal-btn {
  display: block;
  width: 100%;
  font-family: inherit;
  font-size: 0.95rem;
  padding: 0.7rem 1rem;
  border-radius: 8px;
  border: 1px solid #546e7a;
  background: transparent;
  color: #e0e0e0;
  cursor: pointer;
  margin-top: 0.55rem;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.modal-btn:hover { background: #546e7a; color: #fff; }
.modal-btn.primary {
  border-color: #ab47bc;
  background: linear-gradient(160deg, #7e3f9e, #5e2f78);
  color: #fff;
}
.modal-btn.primary:hover { background: linear-gradient(160deg, #9548bb, #6d3789); }
.modal-btn.primary:disabled { opacity: 0.6; cursor: default; }
.modal-btn.ghost { border-color: transparent; color: #90a4ae; }
.modal-btn.ghost:hover { background: transparent; color: #cfd8dc; }
.modal-btn.dev {
  margin-top: 1rem;
  border-style: dashed;
  border-color: #546e7a;
  color: #80cbc4;
  font-size: 0.85rem;
}
.modal-btn.dev:hover { background: rgba(128, 203, 196, 0.12); color: #a7ffeb; }

.mm-searching { display: flex; justify-content: center; padding: 8px 0 14px; }

/* live search feedback: elapsed timer + the current rating window */
.mm-timer {
  font-variant-numeric: tabular-nums;
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #e6e6f0;
  text-align: center;
  margin: 2px 0 4px;
}
.mm-range {
  font-size: 0.85rem;
  color: #9a9ac0;
  text-align: center;
  min-height: 1.1em;
  margin: 0 0 12px;
}
.mm-range:empty { margin: 0; }

/* post-game rating card (inside the game-over dialog) */
#game-over-extra:empty { display: none; }
.rr-rating {
  margin: 0.7rem auto 0.2rem;
  max-width: 320px;
  border-top: 1px solid #3a3a5a;
  padding-top: 0.6rem;
}
.rr-line { display: flex; justify-content: space-between; gap: 1rem; padding: 0.3rem 0; font-size: 0.95rem; }
.rr-name { color: #b0bec5; }
.rr-nums { color: #eceff1; }
.rr-nums b { color: #fff; }
.rr-delta { font-weight: 700; margin-left: 5px; }
.rr-delta.up { color: #66bb6a; }
.rr-delta.down { color: #ef5350; }
.rr-delta.even { color: #90a4ae; }
.rr-prov { margin-top: 0.6rem; color: #ab47bc; font-size: 0.85rem; }
.rr-prov b { color: #ce93d8; }

/* The game-over dialog's one-line note when there are no figures to show:
   an unrated game, a report still in flight, or one that failed. */
.rr-note { margin: 0.6rem 0 0; font-size: 0.9rem; color: #b0bec5; }
.rr-note.pending { font-style: italic; }

/* ---- a badge landing in the game-over dialog ---- */

.bg-earned { position: relative; margin-top: 0.9rem; padding-top: 0.85rem; border-top: 1px solid #3a3a5a; }
.bg-earned-title {
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: #ce93d8;
  margin-bottom: 0.65rem;
}
.bg-earned-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.7rem; }
.bg-earned .bg-slot { cursor: default; }

/* One turn of the coin. `both` holds the end state, which is a full 360° — i.e.
   face-on — so the badge is left exactly as it would have been drawn. */
@keyframes bg-flip {
  from { transform: rotateY(0deg); }
  to   { transform: rotateY(360deg); }
}
.bg-flip { animation: bg-flip 0.75s cubic-bezier(0.35, 0, 0.2, 1) 1 both; }

/* Confetti falls past the dialog's buttons rather than being boxed into the
   badge row — hence the fixed band and pointer-events: none, so nothing it
   drifts over stops being clickable. */
.bg-confetti {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 250px;
  overflow: hidden;
  pointer-events: none;
}
.bg-confetti-bit {
  position: absolute;
  top: -14px;
  width: 7px;
  height: 11px;
  border-radius: 1px;
  animation: bg-confetti 1.6s ease-in 1 forwards;
}
@keyframes bg-confetti {
  0%   { opacity: 1; transform: translate(0, 0) rotate(0deg); }
  100% { opacity: 0; transform: translate(var(--drift, 0), 250px) rotate(var(--spin, 360deg)); }
}

/* Asked to keep still: the badge simply appears, and the confetti doesn't. */
@media (prefers-reduced-motion: reduce) {
  .bg-flip { animation: none; }
  .bg-confetti { display: none; }
}

/* Rating change pinned in the move-log panel, so it outlives the game-over
   dialog. Collapses entirely until there's something to say. */
.mh-rating:empty { display: none; }
.mh-rating {
  padding: 0.45rem 0.55rem;
  border-top: 1px solid #2f2f4a;   /* it sits under the moves now, not above */
  background: #1b1b31;
  font-size: 0.85rem;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4rem;
}
.mh-rating-label { color: #90a4ae; text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.7rem; }
.mh-rating-nums { color: #eceff1; font-variant-numeric: tabular-nums; }
.mh-rating-nums b { color: #fff; }
.mh-rating.unavailable { color: #90a4ae; font-style: italic; }
/* The two states a finished game starts in, before (or instead of) figures. */
.mh-rating.unrated { color: #90a4ae; }
.mh-rating.pending { color: #b0bec5; font-style: italic; }

/* leaderboard screen */
#leaderboard-screen { max-width: 960px; margin: 2.5rem auto 3rem; padding: 1rem 1.2rem 3rem; animation: setup-fade 0.4s ease; }
.lb-title { font-size: clamp(1.8rem, 5vw, 2.6rem); color: #f0f0f0; letter-spacing: 0.04em; margin: 0 0 1.2rem; text-align: center; }
.lb-status { text-align: center; color: #90a4ae; }
.lb-card { background: linear-gradient(160deg, #29293f, #20203a); border: 1px solid #3a3a5a; border-radius: 14px; padding: 16px 18px; margin-bottom: 20px; }
.lb-card h2 { font-size: 15px; margin: 0 0 4px; color: #f0f0f0; }
.lb-cap { font-size: 12.5px; color: #b0bec5; margin: 0 0 12px; }
.lb-empty { color: #90a4ae; font-size: 13px; }
.lb-table { width: 100%; border-collapse: collapse; font-size: 13.5px; font-variant-numeric: tabular-nums; }
.lb-table th, .lb-table td { text-align: left; padding: 9px 12px; white-space: nowrap; }
.lb-table thead th { border-bottom: 2px solid #546e7a; font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase; color: #90a4ae; font-weight: 600; }
.lb-table tbody td { color: #eceff1; border-bottom: 1px solid #33334d; }
.lb-table tbody tr:nth-child(even) td { background: rgba(130, 130, 130, 0.06); }
/* You, on the board. After the striping rule on purpose — same specificity, so
   source order is what keeps the tint from being eaten on even rows. */
.lb-table tbody tr.lb-me td { background: rgba(171, 71, 188, 0.18); color: #fff; }
.lb-table tbody tr.lb-me td:first-child { box-shadow: inset 3px 0 0 #ab47bc; }
.lb-you { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: #ab47bc; border: 1px solid #ab47bc; border-radius: 4px; padding: 1px 5px; margin-left: 6px; }
.lb-table .num { text-align: right; }
.lb-table .muted { color: #90a4ae; }
.lb-rank { color: #90a4ae; width: 30px; }
.lb-tag { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: #ce93d8; border: 1px solid #7e3f9e; border-radius: 4px; padding: 1px 5px; }
.lb-togo { color: #ab47bc; font-size: 11px; }
.lb-chart-box { overflow-x: auto; }
.lb-chart { display: block; width: 100%; height: auto; overflow: visible; }
.lb-gl { stroke: #33334d; stroke-width: 1; }
.lb-ax { fill: #6f7d86; font-size: 11px; }
.lb-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* Today's carried-over rating: hollow, so it doesn't read as a game played. */
.lb-today { fill: none; stroke-width: 2; }
.lb-end { font-size: 12px; font-weight: 600; }
/* Your own series: same colour, more weight — found at a glance, still comparable. */
.lb-line.lb-me { stroke-width: 3.5; }
.lb-today.lb-me { stroke-width: 2.5; }
.lb-end.lb-me { font-size: 13px; font-weight: 800; }
.lb-note { margin: 8px 0 0; }
.lb-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 18px; margin: 2px 0 12px; }
.lb-seg-group { display: inline-flex; gap: 14px; }
.lb-seg, .lb-ci-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: #b0bec5; cursor: pointer; }
.lb-seg input, .lb-ci-toggle input { accent-color: #ab47bc; cursor: pointer; }

/* ---- profile screen ---- */
/* Reuses the leaderboard's card shell (.lb-card) so the two screens read as one
   family; .pf-* is only what the account page adds. */

#profile-screen {
  max-width: 720px;
  margin: 2.5rem auto 3rem;
  padding: 1rem 1.2rem 3rem;
  animation: setup-fade 0.4s ease;
}

.pf-head { display: flex; align-items: center; gap: 1rem; margin: 0.5rem 0 1.6rem; }
.pf-avatar {
  width: 3.6rem;
  height: 3.6rem;
  flex: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.7rem;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(150deg, #ab47bc, #7e3f9e);
}
.pf-who { min-width: 0; }
.pf-name {
  font-size: clamp(1.5rem, 4vw, 2.1rem);
  color: #f0f0f0;
  letter-spacing: 0.02em;
  margin: 0;
  overflow-wrap: anywhere;
}
.pf-email { color: #90a4ae; font-size: 0.85rem; margin: 0.15rem 0 0; overflow-wrap: anywhere; }
.pf-inline-btn {
  margin-top: 0.4rem;
  padding: 0;
  font-family: inherit;
  font-size: 0.85rem;
  color: #ce93d8;
  background: none;
  border: none;
  cursor: pointer;
}
.pf-inline-btn:hover { color: #f3e5f5; text-decoration: underline; }

.pf-card { text-align: left; }

/* Rating: the number carries the block, the counts sit beside it. */
.pf-rating-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.6rem 1.4rem; margin: 0.5rem 0 0.7rem; }
.pf-rating { font-size: 2.4rem; font-weight: 700; color: #eceff1; font-variant-numeric: tabular-nums; line-height: 1; }
.pf-rating.provisional { color: #b0bec5; }
.pf-stats { display: flex; flex-wrap: wrap; gap: 0 1.1rem; }
.pf-stat { display: flex; flex-direction: column; align-items: center; }
.pf-stat-v { font-size: 1rem; color: #eceff1; font-variant-numeric: tabular-nums; }
.pf-stat-k { font-size: 10px; letter-spacing: 0.07em; text-transform: uppercase; color: #90a4ae; }

/* ---- badges ---- */

/* Circles, earned and unearned side by side. The unearned ones keep their ring
   at full contrast and dim only the glyph inside: greying the whole disc makes
   a new player's profile look broken rather than unfinished, and the lit rings
   are what let the grid be read as a set of slots at a glance. */

.bg-count {
  float: right;
  font-size: 11px;
  letter-spacing: 0.07em;
  color: #90a4ae;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.bg-group { margin-top: 0.9rem; }

.bg-group-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #90a4ae;
  margin-bottom: 0.45rem;
}

.bg-lock { color: #7e6a86; text-transform: none; letter-spacing: 0.02em; font-size: 11px; }

/* Names sit under their circles, so the cells are a fixed width and the rows
   align at the top — a two-line name must not shove its neighbours down. */
.bg-grid { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.6rem 0.35rem; }

/* The slot is the button: circle, plus the name once it's earned. */
.bg-slot {
  width: 4.4rem;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.32rem;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  font-family: inherit;
  cursor: pointer;
}

.bg-badge {
  width: 3.1rem;
  height: 3.1rem;
  flex: none;
  border-radius: 50%;
  border: 2px solid #4a4a6a;
  background: radial-gradient(circle at 50% 35%, #32324e, #24243c);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.12s, border-color 0.15s, box-shadow 0.15s;
}

.bg-slot:hover .bg-badge { transform: translateY(-2px); }

/* Earned: the ring lights up and the glyph comes to full strength. */
.bg-slot.earned .bg-badge {
  border-color: #ab47bc;
  background: radial-gradient(circle at 50% 35%, #462f52, #2b2340);
  box-shadow: 0 0 0 1px rgba(171, 71, 188, 0.25), 0 2px 8px rgba(171, 71, 188, 0.18);
}

.bg-slot.selected .bg-badge { border-color: #ce93d8; box-shadow: 0 0 0 2px rgba(206, 147, 216, 0.35); }
.bg-slot:focus-visible { outline: 2px solid #ce93d8; outline-offset: 3px; }

.bg-glyph {
  font-size: 1.5rem;
  line-height: 1;
  color: #ce93d8;
  opacity: 0.3;              /* the dim half of "not yet" — the ring stays lit */
  filter: grayscale(1);
  transition: opacity 0.15s, filter 0.15s;
}

.bg-slot.earned .bg-glyph { opacity: 1; filter: none; }

/* Rung numbers need to be legible at four digits inside a 3.1rem circle. */
.bg-glyph.bg-tier { font-size: 0.95rem; font-weight: 700; font-variant-numeric: tabular-nums; }

.bg-svg { width: 1.6rem; height: 1.6rem; display: block; }

/* Only earned badges are captioned. Long names wrap rather than truncate — a
   half-shown badge name is worse than a two-line one. */
.bg-name {
  font-size: 9.5px;
  line-height: 1.25;
  text-align: center;
  color: #ce93d8;
  letter-spacing: 0.01em;
  overflow-wrap: anywhere;
}

.bg-detail { margin: 0.55rem 0 0; }
.bg-detail[hidden] { display: none; }
.bg-detail b { color: #eceff1; }

.pf-saved-title { color: #eceff1; font-size: 1rem; margin-top: 0.3rem; }
.pf-saved-meta { color: #90a4ae; font-size: 12.5px; margin-top: 0.2rem; }
.pf-saved-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.9rem; }
.pf-saved-actions .home-small { font-size: 0.85rem; padding: 0.45rem 0.9rem; }
.pf-share-url { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; margin-top: 0.8rem; font-size: 11.5px; }
.pf-share-url span { letter-spacing: 0.07em; text-transform: uppercase; color: #90a4ae; }
.pf-share-url code { color: #b0bec5; overflow-wrap: anywhere; }

.pf-danger { border-color: #7a4a4a; color: #ef9a9a; }
.pf-danger:hover { background: #7a4a4a; color: #fff; }

/* The two shortcuts this page exists for. Side by side on a desktop, stacked
   once there isn't room for both. */
.pf-links { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 0.7rem; margin-top: 0.6rem; }
.pf-link {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  width: 100%;
  text-align: left;
  font-family: inherit;
  padding: 0.9rem 1rem;
  border: 1px solid #546e7a;
  border-radius: 10px;
  background: transparent;
  color: #cfd8dc;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.15s;
}
.pf-link:hover { background: rgba(171, 71, 188, 0.12); border-color: #ab47bc; transform: translateY(-1px); }
.pf-link-icon { font-size: 1.4rem; line-height: 1; flex: none; }
.pf-link-text { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.pf-link-text b { color: #eceff1; font-size: 0.98rem; font-weight: 600; }
.pf-link-text span { color: #90a4ae; font-size: 12px; }
.pf-link-arrow { margin-left: auto; color: #90a4ae; flex: none; }
.pf-link:hover .pf-link-arrow { color: #ce93d8; }

.pf-account { display: flex; flex-wrap: wrap; gap: 0.6rem; justify-content: center; }
