@font-face {
    font-family: 'Tiny5';
    src: url("../fonts/tiny5-WNmtw3l.woff2") format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

:root {
    --bg: #f5f1e8;
    --surface: #ffffff;
    --ink: #1f1a17;
    --muted: #6b625b;
    --line: #e2dbcf;
    --accent: #7a4b2a;
    --accent-ink: #ffffff;
    --error: #a12b2b;
    --success: #2f6b3a;
    /* Default board scheme (walnut); the boardscheme controller overrides these on <html>. */
    --board-light: #d6cdb6;
    --board-dark: #8b7a68;
    --board-frame: #2b2a3d;
    /*
     * The whole UI wears the pixel face. Tiny5 ships weight 400 only and its em is
     * an 8px grid, so: no bold (synthesis smears the pixels; uppercase and colour
     * carry emphasis instead) and font sizes stay on multiples of 8px / 0.5rem.
     */
    --font-pixel: 'Tiny5', 'Press Start 2P', monospace;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: var(--font-pixel);
    font-size: 1rem;
    font-synthesis: none;
    color: var(--ink);
    background: var(--board-dark);
    line-height: 1.5;
}

a {
    color: var(--accent);
}

.site-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1.5rem;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.brand {
    font-size: 2rem;
    letter-spacing: 0.12em;
    text-decoration: none;
    color: var(--ink);
}

.site-nav {
    display: flex;
    align-items: center;
    gap: 1.25rem;
}

.nav-user {
    color: var(--muted);
}

.auth-link {
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.inline-form {
    display: inline;
}

.site-main {
    max-width: 80rem;
    margin: 0 auto;
    padding: 1.5rem;
    background: var(--board-light);
}

.btn {
    display: inline-block;
    padding: 0.5rem 1rem;
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    background: var(--surface);
    color: var(--ink);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-ink);
}

.nav-login {
    color: var(--board-dark);
}

.nav-signup {
    background: var(--board-dark);
    border-color: var(--board-dark);
    color: var(--accent-ink);
}

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

.btn-block {
    display: block;
    width: 100%;
    margin-top: 1rem;
}

.flash {
    padding: 0.75rem 1rem;
    border-radius: 0.375rem;
    margin-bottom: 1rem;
    background: var(--surface);
    border: 1px solid var(--line);
}

.flash-success {
    border-color: var(--success);
    color: var(--success);
}

.flash-error {
    border-color: var(--error);
    color: var(--error);
}

/* Home */
.board-panel {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(14rem, 1fr);
    gap: 1.5rem;
    align-items: start;
}

@media (max-width: 48rem) {
    .board-panel {
        grid-template-columns: 1fr;
    }
}

.board {
    width: 100%;
    aspect-ratio: 4 / 3;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 0.5rem;
    overflow: hidden;
}

.board canvas {
    display: block;
    width: 100% !important;
    height: auto !important;
}

.board-loading {
    margin: 0;
    padding: 2rem;
    color: var(--muted);
    text-align: center;
}

.board-side {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 0.5rem;
    padding: 1rem;
}

.board-side-title {
    margin: 0 0 0.5rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.board-side > .board-hint {
    margin: 0 0 1.25rem;
}

/* "Make a piece talk" */
.say-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.say-input,
.say-piece {
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    font: inherit;
    background: var(--surface);
    color: var(--ink);
}

.say-input {
    flex: 1 1 8rem;
    min-width: 0;
}

.side-columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
    margin-bottom: 1.25rem;
}

.side-columns select {
    display: block;
    width: 100%;
}

.side-columns select option:disabled {
    color: var(--muted);
}

/* Tint sliders, tucked behind a disclosure since most players never touch them. */
.tint-details {
    margin-bottom: 1.25rem;
}

.tint-details summary {
    cursor: pointer;
    list-style: none;
}

.tint-details summary::-webkit-details-marker {
    display: none;
}

.tint-details summary::before {
    content: '▸';
    display: inline-block;
    width: 1em;
    transition: transform 0.15s ease;
}

.tint-details[open] summary::before {
    transform: rotate(90deg);
}

.tint {
    display: grid;
    gap: 0.4rem;
    margin-top: 0.5rem;
}

.tint-row {
    display: grid;
    grid-template-columns: 5.5rem 1fr 3rem;
    align-items: center;
    gap: 0.5rem;
}

.tint-row input[type="range"] {
    width: 100%;
    min-width: 0;
    accent-color: var(--accent);
}

.tint-value {
    text-align: right;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.tint-output {
    display: block;
    padding: 0.4rem 0.5rem;
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    background: var(--bg);
    word-break: break-all;
    user-select: all;
}

.toggle {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 1.25rem;
    cursor: pointer;
}

.toggle-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.toggle-hint {
    color: var(--muted);
}

/* Colour scheme swatches: light/dark halves inside the frame colour. */
.swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}

.swatch {
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: 3px solid var(--swatch-frame);
    border-radius: 0.375rem;
    background: linear-gradient(135deg, var(--swatch-light) 50%, var(--swatch-dark) 50%);
    cursor: pointer;
}

.swatch[aria-pressed="true"] {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* Highlighted bar above the board: scores on the left, the "say" widget on the right. */
.score-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin-bottom: 0.75rem;
    padding: 0.6rem 1rem;
    background: var(--board-dark);
    color: var(--accent-ink);
    border-radius: 0.5rem;
}

.score-bar-scores {
    display: flex;
    gap: 1.25rem;
    font-size: 1.1rem;
}

.score-item {
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.score-item strong {
    font-variant-numeric: tabular-nums;
}

.turn-indicator {
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 0.25rem 0.6rem;
    border-radius: 0.375rem;
    animation: turn-pulse 5s ease-in-out infinite;
}

@keyframes turn-pulse {
    0%, 100% {
        background: var(--board-light);
        color: var(--ink);
    }
    50% {
        background: var(--board-dark);
        color: var(--accent-ink);
    }
}

.score-bar-say {
    flex-wrap: nowrap;
}

.score-bar-say .say-input,
.score-bar-say .say-piece {
    padding: 0.15rem 0.5rem;
    font-size: 1.1rem;
    background: var(--surface);
    color: var(--ink);
}

.score-bar-say .say-input {
    flex: 1 1 10rem;
}

.score-bar-send {
    background: var(--board-light);
    border-color: var(--board-light);
    color: var(--ink);
}

/*
 * Pixel board. Squares are 6.25rem, sprites (16px wide, 48px tall) are drawn at
 * 64% of the square (a 4x pixel scale at full size), leaving a gap between
 * neighbouring pieces. A sprite is therefore 1.92 squares tall and one sprite
 * row is 4% of a square.
 */
.pixelboard {
    --square: calc(min(100%, 50rem) / 8);
    /* One sprite/bubble pixel at full size (sprites are drawn at 4x). */
    --px: 4px;
    display: grid;
    grid-template-columns: 1.5rem 1fr;
    grid-template-rows: 1fr 1.5rem;
    width: min(100%, 51.5rem);
    margin: 0 auto;
    /* Headroom for the tall sprites on the far rank (0.92 squares) and the king's speech bubble. */
    padding-top: calc(var(--square) * 1.4);
    image-rendering: pixelated;
    image-rendering: crisp-edges;
}

.pixelboard-stage {
    position: relative;
}

/* Overlay for speech bubbles, above every square; sized like the (square) grid. */
.pixelboard-bubbles {
    position: absolute;
    inset: 0;
    z-index: 100;
    pointer-events: none;
}

/*
 * A balloon (20x35 sprite, string curling to the bottom right) tied to a
 * piece. It lives in the piece's square before the sprite, so it is behind
 * its holder but in front of the ranks behind; it floats up and to the left,
 * bobbing gently.
 */
.balloon {
    position: absolute;
    left: calc(50% - 16 * var(--px));
    bottom: calc((1.92 - var(--sprite-top, 2) * 0.04) * 100% - var(--balloon-drop, 23) * var(--px));
    pointer-events: none;
    width: calc(20 * var(--px));
    height: calc(35 * var(--px));
    background: var(--pixel-balloon) 0 0 / 100% 100% no-repeat;
    image-rendering: pixelated;
    transform-origin: 80% 100%;
    animation: balloon-float 4s ease-in-out infinite;
}

/* Colour variants: same shape and float as the default red balloon. */
.balloon.is-green {
    background-image: var(--pixel-balloon-green);
}

.balloon.is-blue {
    background-image: var(--pixel-balloon-blue);
}

.balloon.is-yellow {
    background-image: var(--pixel-balloon-yellow);
}

/* Skull variant: a black balloon that drifts slower and sways the other way. */
.balloon.is-skull {
    background-image: var(--pixel-balloon-skull);
    animation: balloon-float-skull 5.5s ease-in-out infinite;
}

@keyframes balloon-float-skull {
    0%, 100% {
        transform: translate(0, 0) rotate(0deg);
    }
    25% {
        transform: translate(calc(-2 * var(--px)), calc(-2 * var(--px))) rotate(-4deg);
    }
    50% {
        transform: translate(0, calc(-4 * var(--px))) rotate(0deg);
    }
    75% {
        transform: translate(calc(2 * var(--px)), calc(-2 * var(--px))) rotate(4deg);
    }
}

/* Small-skull variant: same black balloon, a quicker, gentler bob. */
.balloon.is-skull-small {
    background-image: var(--pixel-balloon-skull-small);
    animation: balloon-float-small 3.2s ease-in-out infinite;
}

@keyframes balloon-float-small {
    0%, 100% {
        transform: translate(0, 0) rotate(0deg);
    }
    25% {
        transform: translate(calc(-1 * var(--px)), calc(-1 * var(--px))) rotate(-2deg);
    }
    50% {
        transform: translate(0, calc(-2 * var(--px))) rotate(0deg);
    }
    75% {
        transform: translate(calc(1 * var(--px)), calc(-1 * var(--px))) rotate(2deg);
    }
}

@keyframes balloon-float {
    0%, 100% {
        transform: translate(0, 0) rotate(0deg);
    }
    25% {
        transform: translate(calc(1 * var(--px)), calc(-2 * var(--px))) rotate(3deg);
    }
    50% {
        transform: translate(0, calc(-3 * var(--px))) rotate(0deg);
    }
    75% {
        transform: translate(calc(-1 * var(--px)), calc(-2 * var(--px))) rotate(-3deg);
    }
}

/* Tied to the winner's pawn: bounces with it instead of its usual drift. */
.balloon.is-winner {
    animation: piece-bounce 0.6s ease-in-out infinite;
}

.pixelboard-grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    /* Drawn outside the box so squares keep an exact 1/8 of the width (clean 4x sprite scale). */
    box-shadow: 0 0 0 3px var(--board-frame);
    /* The checkerboard is painted here; squares themselves are transparent. */
    background: conic-gradient(var(--board-light) 25%, var(--board-dark) 0 50%, var(--board-light) 0 75%, var(--board-dark) 0) 0 0 / 25% 25%;
}

.pixelboard-square {
    position: relative;
    aspect-ratio: 1;
    padding: 0;
    margin: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    font: inherit;
}

.pixelboard-square img {
    --piece-filter: hue-rotate(0deg);
    --flip: scaleX(1);
    position: absolute;
    left: 18%;
    bottom: 0;
    width: 64%;
    height: auto;
    pointer-events: none;
    transform: var(--flip);
    filter: var(--piece-filter);
    transition: transform 0.15s ease-out, filter 0.15s ease-out;
}

/* Square single-image sets (e.g. demons) fill most of the square instead of towering over it. */
.pixelboard-square img.is-square {
    left: 2%;
    width: 96%;
}

/* The queenside flank of a single-image set, mirrored to face the other way. */
.pixelboard-square img.is-mirrored {
    --flip: scaleX(-1);
}

/* Team sprites take the runtime tint (set on .pixelboard by the tint controller). */
.pixelboard-square img.is-team {
    --piece-filter: var(--team-filter, hue-rotate(0deg));
}

/* Hovered or selected piece: brighten and lift it slightly off its square. */
.pixelboard-square.is-movable:hover img,
.pixelboard-square.is-selected img {
    transform: var(--flip) translateY(calc(-2 * var(--px)));
    filter: var(--piece-filter) brightness(1.25);
}

/* A striker (and its bubble) repeats that lift three times after a capture. */
.pixelboard-square img.is-striking {
    animation: pixel-jump 0.3s ease-out 3;
}

@keyframes pixel-jump {
    50% {
        transform: var(--flip, scaleX(1)) translateY(calc(-2 * var(--px)));
        filter: var(--piece-filter, none) brightness(1.25);
    }
}

/* The winning side keeps bouncing once the game is over. */
.pixelboard-square img.is-winner {
    animation: piece-bounce 0.6s ease-in-out infinite;
}

@keyframes piece-bounce {
    50% {
        transform: var(--flip, scaleX(1)) translateY(calc(-4 * var(--px)));
    }
}

.pixel-bubble.is-striking {
    animation: pixel-bubble-pop 0.2s steps(2, end), pixel-jump 0.3s ease-out 3;
}

.pixelboard-square.is-selected::before,
.pixelboard-square.is-target::before,
.pixelboard-square.is-capture::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
}

.pixelboard-square.is-selected::before {
    box-shadow: inset 0 0 0 4px #f0c040;
    z-index: auto; /* behind the selected piece (painted before its sprite) */
}

.pixelboard-square.is-target::before {
    background: var(--pixel-shadow) center bottom / 64% auto no-repeat;
}

/*
 * Bobbing arrow above a piece that may move, alternating the two sprite frames.
 * --sprite-top (set inline per square by the controller) is the transparent
 * margin above the piece's head, in 1/16-square rows.
 */

.pixelboard-square.is-movable:hover::after {
    content: "";
    position: absolute;
    left: 18%;
    bottom: calc(192% - var(--sprite-top, 0) * 4%);
    width: 64%;
    aspect-ratio: 1;
    background: var(--pixel-arrow-0) center / 100% 100% no-repeat;
    animation: pixel-arrow-bob 0.6s steps(1) infinite;
    pointer-events: none;
}

@keyframes pixel-arrow-bob {
    50% {
        background-image: var(--pixel-arrow-1);
    }
}

.pixelboard-square.is-capture::before {
    box-shadow: inset 0 0 0 4px rgba(161, 43, 43, 0.8);
}

/*
 * Pixel speech bubble in the style of pixelspeechbubble.com: a 1px outline
 * with 3px stepped corners and a 3px inset (the 9-slice frame.png), a tail
 * that opens the bottom outline (tail-*.png) and a 1px 20% shadow towards the
 * tail. --px is the size of one bubble pixel.
 */
.pixel-bubble {
    position: absolute;
    /*
     * Positioned in the overlay from the king's visual column (--col) and rows
     * from the bottom (--row); a square is 12.5% of the overlay. The box sits up
     * and to the right of the piece's head (sprite box is 1.92 squares tall minus
     * --sprite-top rows of 4%) and the tail hangs 6px below it, pointing back at the head.
     */
    left: calc((var(--col) + 0.5) * 12.5% + 4 * var(--px));
    bottom: calc((var(--row) + 1.92 - var(--sprite-top, 2) * 0.04) * 12.5% - 1 * var(--px));
    box-sizing: border-box;
    border: calc(4 * var(--px)) solid transparent;
    border-image: url("../ui/bubble/frame-FhQWanv.png") 4 fill repeat;
    image-rendering: pixelated;
    font-family: var(--font-pixel);
    /* Tiny5 caps are 5 font pixels = 0.63em, so 8px per bubble pixel keeps text and frame on one grid. */
    font-size: calc(8 * var(--px));
    line-height: calc(5 * var(--px));
    color: #000;
    white-space: nowrap;
    text-align: left;
    text-transform: uppercase;
    filter: drop-shadow(calc(-1 * var(--px)) var(--px) 0 rgba(0, 0, 0, 0.2));
    pointer-events: none;
    animation: pixel-bubble-pop 0.2s steps(2, end);
}

.pixel-bubble::after {
    content: "";
    position: absolute;
    left: calc(2 * var(--px));
    bottom: calc(-10 * var(--px));
    width: calc(7 * var(--px));
    height: calc(7 * var(--px));
    background: url("../ui/bubble/tail-left-MnsYeFT.png") 0 0 / 100% 100% no-repeat;
}

/* Multi-line text: block lines with a 2px gap, keeping the 3px inset. */
.pixel-bubble .line {
    display: block;
}

.pixel-bubble .line + .line {
    margin-top: calc(2 * var(--px));
}

/* Thought bubble: the tail is a trail of circles instead of a spike. */
.pixel-bubble.is-thought::after {
    bottom: calc(-12 * var(--px));
    width: calc(9 * var(--px));
    height: calc(9 * var(--px));
    background-image: url("../ui/bubble/tail-think-left-vRp5o1-.png");
}

/* Mirrored variant for pieces near the right edge: box to the left, tail on the right. */
.pixel-bubble.is-flipped {
    left: auto;
    right: calc((7 - var(--col) + 0.5) * 12.5% + 4 * var(--px));
    filter: drop-shadow(var(--px) var(--px) 0 rgba(0, 0, 0, 0.2));
}

.pixel-bubble.is-flipped::after {
    left: auto;
    right: calc(2 * var(--px));
    background-image: url("../ui/bubble/tail-right-vQmV2Gw.png");
}

.pixel-bubble.is-flipped.is-thought::after {
    background-image: url("../ui/bubble/tail-think-right-rd8tXqU.png");
}

@keyframes pixel-bubble-pop {
    from {
        opacity: 0;
        transform: translateY(var(--px));
    }
}

.pixel-bubble.is-fading {
    animation: pixel-bubble-fade 0.8s steps(4, end) forwards;
}

@keyframes pixel-bubble-fade {
    to {
        opacity: 0;
    }
}

.pixelboard-ranks,
.pixelboard-files {
    display: grid;
    color: var(--muted);
}

.pixelboard-ranks {
    grid-template-rows: repeat(8, 1fr);
    align-items: center;
}

.pixelboard-files {
    grid-column: 2;
    grid-template-columns: repeat(8, 1fr);
    text-align: center;
}

.board-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.board-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
}

.zoom {
    display: flex;
    align-items: center;
    gap: 0.3rem;
}

.zoom-step {
    padding: 0.15rem 0.5rem;
    line-height: 1;
}

.zoom-slider {
    width: 5rem;
    accent-color: var(--board-dark);
}

.btn-sm {
    padding: 0.3rem 0.6rem;
    font-size: 0.85rem;
}

.board-actions .btn[aria-pressed="true"] {
    background: var(--board-dark);
    border-color: var(--board-dark);
    color: white;
}

.board-hint {
    color: var(--muted);
    margin-bottom: 0;
}

/* Announces the winner, right above the board. */
.win-banner {
    margin: 0 0 0.5rem;
    color: var(--board-frame);
    font-size: 1.5rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: center;
}

/* Auth forms */
.auth-card {
    max-width: 26rem;
    margin: 2rem auto;
    padding: 2rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 0.5rem;
}

.auth-card h1 {
    margin-top: 0;
}

.login-heading {
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.login-submit {
    background: var(--board-dark);
    border-color: var(--board-dark);
    color: var(--accent-ink);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.login-register-link {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--board-dark);
}

.form-row,
.auth-card form > div {
    margin-bottom: 1rem;
}

.auth-card label {
    display: block;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 0.25rem;
}

.auth-card input[type="text"],
.auth-card input[type="email"],
.auth-card input[type="password"],
.panel input[type="text"],
.panel input[type="email"],
.panel input[type="password"] {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    font: inherit;
}

.auth-card ul {
    margin: 0.25rem 0 0;
    padding-left: 1.25rem;
    color: var(--error);
}

.pixel-select {
    font: inherit;
}

.auth-switch {
    margin-top: 1.5rem;
    text-align: center;
    color: var(--muted);
}

/* Dashboard and admin */
.dashboard {
    max-width: 60rem;
    margin: 0 auto;
}

.dashboard-head {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.dashboard-head h1 {
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: 1.5rem;
    margin-bottom: 1.5rem;
}

.panel {
    padding: 1.5rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 0.5rem;
}

.panel h2 {
    margin-top: 0;
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--muted);
}

.panel label {
    display: block;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 0.25rem;
}

.panel form > div {
    margin-bottom: 1rem;
}

.panel ul {
    color: var(--error);
}

.panel-hint {
    color: var(--muted);
    margin-bottom: 0;
}

.panel-note {
    border-color: var(--accent);
}

/* Roles read as tags, not sentences: the pixel font has no bold to lean on. */
.role-badge {
    display: inline-block;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.85rem;
    color: var(--muted);
}

.role-admin {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--accent-ink);
}

.role-demo {
    border-color: var(--board-frame);
    color: var(--board-frame);
}

.detail-list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.5rem 1rem;
    margin: 0 0 1rem;
}

.detail-list dt {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
}

.detail-list dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.stat-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
}

.stat-row li {
    display: flex;
    flex-direction: column;
}

.stat-value {
    font-size: 2rem;
    line-height: 1;
}

.stat-label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.85rem;
    color: var(--muted);
}

.user-table {
    width: 100%;
    border-collapse: collapse;
}

.user-table th,
.user-table td {
    padding: 0.5rem;
    text-align: left;
    border-bottom: 1px solid var(--line);
    overflow-wrap: anywhere;
}

.user-table th {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 400;
    color: var(--muted);
}

.you {
    color: var(--muted);
}

/* Saved games */
.match-name {
    color: var(--ink);
}

.user-table .btn-sm {
    white-space: nowrap;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Automessages */
.row-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.message-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.message-list li {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--line);
}

.message-list li:last-child {
    border-bottom: none;
}

.message-target {
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.85rem;
}

/* Match title, sharing a row with the action bar above the score bar. Wears the
   scheme's frame colour so it shifts with the board like the rest of the page chrome. */
.match-title {
    margin: 0;
    color: var(--board-frame);
    font-size: 1.5rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* The match's number, trailing its name. Quieter than the name it follows. */
.match-id {
    color: var(--muted);
    font-size: 0.85rem;
    letter-spacing: 0.06em;
}

.match-title .match-id {
    font-size: 1rem;
    opacity: 0.7;
    color: inherit;
}

/* The match's players, trailing its name and id. */
.match-players {
    color: black;
    font-size: 0.85rem;
    letter-spacing: 0.06em;
    text-transform: none;
    margin-left: 0.5rem;
}

.match-title .match-players {
    font-size: 0.9rem;
}
