/* osu-rotate, styled after osu!lazer's multiplayer screens: every surface is a dark tint of one
   hue (lazer's "Plum", 320), highlights are the bright tint of it, and mods carry lazer's colours
   by kind. Dark only, like lazer. Nunito (SIL OFL, fonts/Nunito-OFL.txt) stands in for lazer's
   Torus, which isn't free to ship. No inline styles anywhere (the CSP forbids them). */

@font-face {
    font-family: "Nunito";
    src: url("fonts/nunito-latin-wght.woff2") format("woff2");
    font-weight: 200 1000;
    font-style: normal;
    font-display: swap;
}

:root {
    color-scheme: dark;

    /* lazer's OverlayColourProvider at hue 320: Background6 to Background3, Content and Light. */
    --page: hsl(320 10% 10%);
    --surface: hsl(320 10% 15%);
    --surface-raised: hsl(320 10% 20%);
    --surface-high: hsl(320 10% 25%);
    --text: #ffffff;
    --text-2: hsl(320 40% 90%);
    --text-3: hsl(320 10% 62%);
    --label: hsl(320 40% 80%);
    --hairline: hsl(320 10% 22%);
    --hairline-strong: hsl(320 10% 30%);
    --accent: hsl(320 100% 70%);
    --accent-ink: hsl(320 100% 78%);
    --on-accent: hsl(320 10% 10%);
    --accent-soft: hsl(320 100% 70% / 0.14);
    --positive: #66ff73;
    --negative: #ff6666;
    --waiting: #ffd966;
    --shadow: 0 8px 24px hsl(320 10% 4% / 0.5);
    --bar: hsl(320 10% 32%);

    /* lazer's OsuColour.ForModType. */
    --mod-reduction: #b2ff66;
    --mod-increase: #ff6666;
    --mod-automation: #66ccff;
    --mod-conversion: #8c66ff;
    --mod-free: hsl(320 100% 70%);

    --sans: "Nunito", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --mono: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, "Liberation Mono", monospace;
    --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Base */

*, *::before, *::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--page);
    color: var(--text);
    font-family: var(--sans);
    font-size: 15px;
    line-height: 22px;
}

a {
    color: var(--text);
    text-decoration: underline;
    text-decoration-color: var(--hairline-strong);
    text-underline-offset: 3px;
    transition: text-decoration-color 140ms var(--ease), color 140ms var(--ease);
}

a:hover {
    text-decoration-color: currentColor;
}

h1, h2, h3 {
    margin: 0;
    font-weight: 700;
}

h1:focus {
    outline: none;
}

h2 {
    font-size: 15px;
    line-height: 20px;
}

h3 {
    font-size: 13px;
    line-height: 20px;
    color: var(--text-2);
}

p {
    margin: 0;
}

ol, ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

time, .mono {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Top bar */

.topbar {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--page);
    border-bottom: 1px solid var(--hairline);
}

.topbar-inner {
    display: flex;
    align-items: center;
    gap: 24px;
    max-width: 1440px;
    height: 56px;
    margin: 0 auto;
    padding: 0 24px;
}

.wordmark {
    font-weight: 700;
    font-size: 16px;
    text-decoration: none;
    letter-spacing: 0;
}

.site {
    display: flex;
    gap: 4px;
}

.site a {
    padding: 6px 12px;
    border-radius: 8px;
    color: var(--text-2);
    text-decoration: none;
    transition: background-color 140ms var(--ease), color 140ms var(--ease);
}

.site a:hover {
    color: var(--text);
    background: var(--surface-raised);
}

.site a.active {
    color: var(--text);
    background: var(--surface-raised);
    box-shadow: inset 0 -2px 0 var(--accent);
}

.account {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
    color: var(--text-3);
    font-size: 13px;
}

.account strong {
    color: var(--text-2);
    font-weight: 500;
}

.account form {
    margin: 0;
}

/* Page */

.page {
    max-width: 1440px;
    margin: 0 auto;
    padding: 24px 24px 64px;
}

.page-title {
    font-size: 28px;
    line-height: 32px;
    margin-bottom: 20px;
}

/* Panels: every section of the desk is a card */

.page section {
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: 14px;
    box-shadow: var(--shadow);
    padding: 20px;
}

.page section > h2,
.section-head {
    margin-bottom: 16px;
}

.section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.section-head h2 {
    margin: 0;
}

.page section > h3 {
    margin: 20px 0 8px;
}

.page section p + p {
    margin-top: 8px;
}

.empty,
.page section > p:only-of-type {
    color: var(--text-3);
}

.message {
    margin-top: 12px;
    color: var(--text-2);
    font-size: 13px;
}

.confirm {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    color: var(--text-2);
}

/* Controls */

button {
    font: inherit;
    font-size: 14px;
    line-height: 20px;
    padding: 6px 16px;
    border-radius: 8px;
    border: 1px solid var(--hairline-strong);
    background: var(--surface-raised);
    color: var(--text);
    cursor: pointer;
    transition: background-color 140ms var(--ease), border-color 140ms var(--ease), transform 120ms var(--ease);
}

button:hover:not(:disabled) {
    border-color: var(--text-3);
}

button:active:not(:disabled) {
    transform: scale(0.97);
}

button:disabled {
    opacity: 0.5;
    cursor: default;
}

/* The primary action of each form: create, send, save. Ink, not the accent: the accent is kept
   for the current host, the page you're on and starting a match. */
form button[type=submit] {
    background: var(--text);
    border-color: var(--text);
    color: var(--page);
    font-weight: 500;
}

form button[type=submit]:hover:not(:disabled) {
    border-color: var(--text);
    background: var(--text-2);
}

.start button[type=submit] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.start button[type=submit]:hover:not(:disabled) {
    background: var(--accent);
    border-color: var(--accent-ink);
}

button.quiet,
.account button[type=submit] {
    background: transparent;
    border-color: transparent;
    color: var(--text-2);
    font-weight: 400;
    padding: 4px 8px;
}

.account button[type=submit]:hover {
    color: var(--text);
    border-color: var(--hairline-strong);
}

.abort,
.close {
    color: var(--negative);
}

.kick-confirm,
.close-confirm {
    background: var(--negative);
    border-color: var(--negative);
    color: #fff;
}

input,
select,
textarea {
    font: inherit;
    font-size: 14px;
    line-height: 20px;
    padding: 6px 12px;
    border-radius: 8px;
    border: 1px solid var(--hairline-strong);
    background: var(--page);
    color: var(--text);
    min-width: 0;
    transition: border-color 140ms var(--ease);
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--accent);
}

input[type=checkbox] {
    accent-color: var(--accent);
    width: 16px;
    height: 16px;
    margin: 0;
}

input[type=number] {
    width: 96px;
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
}

label {
    color: var(--text-2);
    font-size: 14px;
}

/* A one-line form: label with input, then its button. */
form:not(.rules) {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0;
}

form:not(.rules) label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 200px;
    font-size: 13px;
}

/* Tables */

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

th {
    text-align: left;
    font-weight: 500;
    font-size: 12px;
    color: var(--text-3);
    padding: 0 12px 8px 0;
    border-bottom: 1px solid var(--hairline);
}

td {
    padding: 8px 12px 8px 0;
    border-bottom: 1px solid var(--hairline);
    vertical-align: top;
}

tr:last-child td {
    border-bottom: 0;
}

.tag {
    font-family: var(--mono);
    font-size: 12px;
    color: var(--text-3);
}

/* The lobby desk */

.desk {
    display: grid;
    grid-template-columns: minmax(0, 1.65fr) minmax(320px, 1fr);
    gap: 16px;
    align-items: start;
}

.desk-main {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* The order to read the room in: its status, the match, the players, then the room's own
   controls, which are rarely needed once it is open. With no room, making one comes first. */
.desk-main > .lobby-status { order: 0; }
.desk-main > .status-note { order: 0; }
.desk-main > .lobby-host-controls { order: 1; }
.desk-main > .lobby-players { order: 2; }
.desk-main > .lobby-lifecycle { order: 3; }
.desk.no-room .desk-main > .lobby-lifecycle { order: 1; }

.desk-side {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* One plain sentence under the status when the lobby is not simply open. */
.status-note {
    margin: 0;
    padding: 12px 16px;
    border-radius: 10px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    color: var(--text-2);
    font-size: 14px;
}

.status-note.problem {
    border-color: var(--negative);
    color: var(--text);
}

.page > .status-note {
    margin-bottom: 16px;
}

.lede,
.hint {
    color: var(--text-3);
    font-size: 13px;
}

.hint {
    margin-top: 8px;
}

.page section > .lede {
    margin: -8px 0 12px;
}

.desk + section {
    margin-top: 16px;
}

/* Status: four quiet cards in a row, the signature dot on the two that are live. */

.page section.lobby-status {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1px;
    padding: 0;
    overflow: hidden;
    background: var(--hairline);
}

.lobby-status > p {
    margin: 0;
    padding: 16px 20px;
    background: var(--surface);
    color: var(--text-3);
    font-size: 13px;
    line-height: 20px;
}

.page section.lobby-status p + p {
    margin-top: 0;
}

.lobby-status > p strong,
.lobby-status > p > a {
    display: block;
    margin-top: 4px;
    color: var(--text);
    font-size: 18px;
    line-height: 24px;
    font-weight: 500;
    overflow-wrap: anywhere;
}

.lobby-status .room a {
    font-size: 15px;
}

.lobby-status .match span {
    display: block;
    margin-top: 4px;
    font-family: var(--mono);
}

/* The status dot: the one detail that marks something live. */
.lobby-status > p:first-child strong::before,
.lobby-status .connection strong::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin: 0 8px 2px 0;
    border-radius: 50%;
    background: var(--text-3);
    vertical-align: middle;
}

.lobby-status[data-status=Open] > p:first-child strong::before {
    background: var(--positive);
}

.lobby-status[data-status=Connecting] > p:first-child strong::before,
.lobby-status[data-status=Creating] > p:first-child strong::before,
.lobby-status[data-status=Rejoining] > p:first-child strong::before,
.lobby-status[data-status=Syncing] > p:first-child strong::before,
.lobby-status[data-status=Reconnecting] > p:first-child strong::before,
.lobby-status[data-status=Closing] > p:first-child strong::before {
    background: var(--waiting);
}

.lobby-status[data-connected=yes] .connection strong::before {
    background: var(--positive);
}

.lobby-status[data-connected=no] .connection strong::before {
    background: var(--negative);
}

/* The queue: the rotation as a numbered track, the current host leading in the accent. */

.match-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-end;
}

.match-controls form.start {
    flex: 1 1 280px;
}

/* Players: one row each, in host-queue order, with everything that can be done to them. */

.lobby-players .count {
    font-family: var(--mono);
    font-size: 13px;
    color: var(--text-3);
}

.roster li {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 4px 12px;
    min-height: 44px;
    padding: 8px 0;
    border-top: 1px solid var(--hairline);
}

.roster li:first-child {
    border-top: 0;
}

.roster .pos {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    background: var(--surface-high);
    color: var(--text-2);
    font-family: var(--mono);
    font-size: 12px;
    line-height: 24px;
    text-align: center;
}

.roster li.host .pos {
    background: var(--accent);
    color: var(--on-accent);
    font-weight: 700;
}

.roster .who {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
    min-width: 0;
}

.roster .name,
.lobby-moderation .name {
    min-width: 0;
    overflow-wrap: anywhere;
}

.roster .name {
    font-weight: 600;
}

.badge {
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--surface-high);
    color: var(--text-2);
    font-size: 11px;
    font-weight: 700;
    white-space: nowrap;
}

.badge.host {
    background: var(--accent-soft);
    color: var(--accent-ink);
}

.badge.denied {
    color: var(--text-3);
}

.roster .where {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-3);
    font-size: 12px;
    white-space: nowrap;
}

.roster .slot {
    font-family: var(--mono);
}

.roster .team.blue {
    color: #66ccff;
}

.roster .team.red {
    color: var(--negative);
}

.roster .actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 4px;
}

.roster .actions button,
.lobby-moderation li button {
    padding: 2px 10px;
    font-size: 13px;
}

.roster .actions .up,
.roster .actions .down {
    min-width: 32px;
    padding: 2px 8px;
}

.lobby-players .referees {
    margin-top: 12px;
    color: var(--text-3);
    font-size: 13px;
}

.lobby-moderation .name {
    flex: 1;
}

/* Player states as lazer's pills. */
.state {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 700;
    background: var(--surface-high);
    color: var(--text-2);
}

.state.playing {
    background: hsl(320 100% 70% / 0.18);
    color: var(--accent-ink);
}

.state.finished {
    background: rgb(102 255 115 / 0.14);
    color: var(--positive);
}

/* Room lifecycle */

.lobby-lifecycle {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.page section.lobby-lifecycle > h2 {
    margin-bottom: 4px;
}

.lobby-lifecycle .notice,
.lobby-rules > .notice {
    padding: 12px 16px;
    border-radius: 10px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline-strong);
    font-size: 14px;
    color: var(--text);
}

.lobby-lifecycle > button {
    align-self: flex-start;
}

/* Moderation */

.lobby-moderation ul {
    margin-bottom: 12px;
}

.lobby-moderation li {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--hairline);
}

.lobby-moderation li:last-child {
    border-bottom: 0;
}

/* Chat: a tall panel, newest at the bottom, the box to type in pinned under it. */

.page .desk-side section.lobby-chat {
    display: flex;
    flex-direction: column;
    height: clamp(320px, 58vh, 560px);
    padding: 0;
}

/* A reversed column keeps the scroller at its end, the newest line, as lines arrive. */
.chat-scroll {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column-reverse;
    overflow-y: auto;
}

.lobby-chat > .empty {
    flex: 1;
}

/* With no room there is no chat to make room for. */
.page .desk.no-room .desk-side section.lobby-chat {
    height: auto;
}

.lobby-chat > .hint {
    margin: 0;
    padding: 12px 20px 16px;
    border-top: 1px solid var(--hairline);
}

.lobby-chat > h2 {
    padding: 16px 20px 0;
}

.page section.lobby-chat > h2 {
    margin-bottom: 12px;
}

.lobby-chat > p {
    padding: 0 20px 16px;
}

.chat-lines {
    padding: 0 20px 12px;
    font-size: 14px;
    line-height: 20px;
}

.chat-lines li {
    position: relative;
    padding: 4px 0 4px 52px;
}

.chat-lines time {
    position: absolute;
    left: 0;
    top: 4px;
    color: var(--text-3);
    font-size: 12px;
}

.chat-lines .from {
    font-weight: 500;
    margin-right: 4px;
}

.chat-lines .text,
.chat-lines .action {
    overflow-wrap: anywhere;
}

.chat-lines .action {
    color: var(--text-2);
}

.chat-lines .bot .from,
.chat-lines .bot .text {
    color: var(--text-2);
    font-family: var(--mono);
    font-size: 13px;
}

.chat-lines .owner .from {
    color: var(--accent-ink);
}

.lobby-chat form.say {
    padding: 12px 20px 16px;
    border-top: 1px solid var(--hairline);
}

.lobby-chat .message {
    padding: 0 20px 12px;
}

/* Rules: lazer's settings layout. Sections side by side, each a column of rounded form rows on
   the card, label on the left, the control on the right. */

form.rules {
    display: grid;
    /* min() lets a column shrink below 340px on a phone instead of spilling out of the card. */
    grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
    gap: 16px;
    margin: 0;
    align-items: start;
}

.settings-section {
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.settings-section legend {
    padding: 0 0 8px;
    font-size: 15px;
    font-weight: 700;
    color: var(--text);
}

.form-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    min-height: 52px;
    padding: 8px 12px;
    border-radius: 10px;
    background: var(--surface-raised);
    color: var(--text);
}

.form-row.stacked,
.form-row.tile-row,
.form-row.mod-row {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 12px;
}

.form-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.form-label {
    font-size: 14px;
    font-weight: 600;
    color: var(--label);
}

.form-hint {
    font-size: 12px;
    line-height: 16px;
    color: var(--text-3);
}

.form-row input:not([type=checkbox]):not([type=range]),
.form-row textarea {
    background: var(--page);
    border-color: var(--hairline-strong);
}

.text-row input {
    flex: 0 1 220px;
    min-width: 0;
}

.form-row.stacked textarea {
    width: 100%;
    min-height: 96px;
}

/* lazer's SwitchButton: a pill track with a round nub, lit in the highlight colour when on. */
input.switch {
    appearance: none;
    flex: none;
    position: relative;
    width: 44px;
    height: 24px;
    margin: 0;
    border-radius: 12px;
    background: var(--surface-high);
    border: 2px solid var(--hairline-strong);
    cursor: pointer;
    transition: background-color 160ms var(--ease), border-color 160ms var(--ease);
}

input.switch::before {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--text-3);
    transition: transform 160ms var(--ease), background-color 160ms var(--ease);
}

input.switch:checked {
    background: var(--accent);
    border-color: var(--accent);
}

input.switch:checked::before {
    transform: translateX(20px);
    background: var(--on-accent);
}

/* Tiles: lazer's game type picker. The chosen one is outlined and lit. */
.tiles {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.tiles.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tiles.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding: 10px 12px;
    border-radius: 8px;
    border: 2px solid transparent;
    background: var(--surface-high);
    color: var(--text-2);
    text-align: left;
    font-weight: 600;
}

.tiles.compact .tile {
    align-items: center;
    text-align: center;
    padding: 8px;
}

.tile:hover:not(:disabled) {
    border-color: var(--hairline-strong);
}

.tile.chosen,
.tile.chosen:hover:not(:disabled) {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--text);
}

.tile-name {
    font-size: 14px;
    font-weight: 700;
}

.tile-note {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-3);
}

/* Sliders: lazer's bars, in the highlight colour, with the value beside them. */
.slider {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 1 260px;
    min-width: 0;
}

.slider input[type=range] {
    flex: 1;
    min-width: 0;
    accent-color: var(--accent);
}

.slider-value {
    min-width: 64px;
    text-align: right;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.number {
    display: flex;
    align-items: center;
    gap: 8px;
}

.number .unit {
    color: var(--text-3);
    font-size: 13px;
}

/* Mods: lazer's mod buttons, coloured by kind; lit when chosen. */
.mods {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
    gap: 8px;
}

.mod {
    --mod: var(--mod-increase);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 8px 4px;
    border-radius: 8px;
    border: 2px solid transparent;
    background: var(--surface-high);
    color: var(--text-2);
}

.mod.reduction { --mod: var(--mod-reduction); }
.mod.increase { --mod: var(--mod-increase); }
.mod.automation { --mod: var(--mod-automation); }
.mod.conversion { --mod: var(--mod-conversion); }
.mod.freemod { --mod: var(--mod-free); }

.mod-code {
    font-size: 16px;
    font-weight: 700;
    color: var(--mod);
    letter-spacing: 0.02em;
}

.mod-name {
    font-size: 11px;
    line-height: 14px;
    font-weight: 600;
    color: var(--text-3);
}

.mod:hover:not(:disabled) {
    border-color: var(--mod);
}

.mod.on,
.mod.on:hover:not(:disabled) {
    background: var(--mod);
    border-color: var(--mod);
}

.mod.on .mod-code,
.mod.on .mod-name {
    color: var(--on-accent);
}

/* The save bar stays at the bottom of the window while the long form scrolls under it. */
.form-actions {
    grid-column: 1 / -1;
    position: sticky;
    bottom: 12px;
    z-index: 2;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    padding: 12px 16px;
    border-radius: 12px;
    background: var(--surface-high);
    border: 1px solid var(--hairline-strong);
    box-shadow: var(--shadow);
}

.form-actions .save-state {
    margin: 0 auto 0 0;
    color: var(--text-2);
    font-weight: 700;
}

.form-actions[data-dirty=yes] .save-state {
    color: var(--accent-ink);
}

.form-actions .message {
    flex: 1 1 100%;
    order: -1;
    margin: 0;
    color: var(--text);
}

.slider .number input {
    width: 76px;
}

/* Room for the number box without squeezing the slider to a stub. */
.slider:has(.number) {
    flex-basis: 300px;
}

.slider .number .unit {
    min-width: 48px;
}

/* History */

.match-stats + section,
section + .match-list {
    margin-top: 16px;
}

.window {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
}

.stats-grid {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: 24px;
}

.per-day {
    margin: 0;
    min-width: 0;
}

.per-day figcaption {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 16px;
}

.per-day .total {
    font-size: 32px;
    line-height: 36px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

.per-day .caption {
    color: var(--text-3);
    font-size: 13px;
}

.chart {
    display: block;
    width: 100%;
    height: 200px;
}

.chart .bar {
    fill: var(--bar);
    shape-rendering: crispEdges;
    transition: fill 140ms var(--ease);
}

.chart .bar:hover {
    fill: var(--text-3);
}

.chart .bar.latest {
    fill: var(--accent);
}

.chart .baseline {
    stroke: var(--hairline-strong);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.axis {
    display: flex;
    justify-content: space-between;
    margin-top: 8px;
    color: var(--text-3);
    font-family: var(--mono);
    font-size: 12px;
}

.ranked {
    min-width: 0;
}

.ranked h3 {
    margin-bottom: 8px;
}

.ranked ol {
    counter-reset: rank;
}

.ranked li {
    counter-increment: rank;
    position: relative;
    padding: 6px 0 6px 28px;
    border-bottom: 1px solid var(--hairline);
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.ranked li::before {
    content: counter(rank);
    position: absolute;
    left: 0;
    color: var(--text-3);
    font-family: var(--mono);
    font-size: 12px;
}

.ranked li:last-child {
    border-bottom: 0;
}

.match-list td:first-child,
.match-list td:nth-child(2) {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.match-list details summary {
    cursor: pointer;
    color: var(--text-2);
}

.match-list .scores {
    margin-top: 6px;
    font-family: var(--mono);
    font-size: 13px;
    color: var(--text-2);
}

.match-list .pages {
    display: flex;
    gap: 8px;
    margin-top: 16px;
}

.match-list .pages:empty {
    display: none;
}

.table-scroll {
    overflow-x: auto;
}

/* Account pages: sign in, signed out, not allowed. One card in the middle of a quiet page. */

.account-page {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 24px 16px;
}

.account-card {
    width: 100%;
    max-width: 400px;
    padding: 32px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: 16px;
    box-shadow: var(--shadow);
}

.account-card .wordmark {
    margin-bottom: 32px;
}

.account-card h1 {
    font-size: 24px;
    line-height: 32px;
    margin-bottom: 8px;
}

.account-card .lede {
    color: var(--text-2);
    margin-bottom: 24px;
}

.account-card .fine {
    margin-top: 16px;
    color: var(--text-3);
    font-size: 13px;
    line-height: 20px;
}

.account-card .notice {
    margin-bottom: 20px;
    padding: 12px 16px;
    border-radius: 10px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline-strong);
    font-size: 14px;
}

.account-card code {
    font-family: var(--mono);
    font-size: 13px;
}

/* A link that does what a button does. */
.button {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 44px;
    padding: 0 20px;
    border-radius: 10px;
    border: 1px solid var(--hairline-strong);
    background: var(--surface-raised);
    color: var(--text);
    font-weight: 500;
    text-decoration: none;
    transition: background-color 140ms var(--ease), border-color 140ms var(--ease), transform 120ms var(--ease);
}

.button:hover {
    border-color: var(--text-3);
}

.button:active {
    transform: scale(0.98);
}

.button.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.button.primary:hover {
    border-color: var(--accent-ink);
}

/* Blazor's own error notes */

#blazor-error-ui {
    background: var(--surface-raised);
    color: var(--text);
    border-top: 1px solid var(--hairline);
    bottom: 0;
    display: none;
    left: 0;
    padding: 12px 48px 12px 20px;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 16px;
    top: 10px;
}

.blazor-error-boundary {
    padding: 16px;
    border-radius: 10px;
    background: var(--surface-raised);
    border: 1px solid var(--negative);
    color: var(--text);
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

/* Narrow screens: one column, the queue first, chat after the room. */

@media (max-width: 1100px) {
    .desk {
        grid-template-columns: minmax(0, 1fr);
    }

    .desk-side {
        position: static;
    }

    .page .desk-side section.lobby-chat {
        height: clamp(280px, 60vh, 480px);
    }

    .stats-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .per-day {
        grid-column: 1 / -1;
    }
}

@media (max-width: 640px) {
    .tiles.cols-4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    body {
        font-size: 14px;
    }

    .topbar-inner {
        gap: 8px;
        padding: 0 16px;
    }

    /* Three pages and the sign-out button fit a phone on one line. */
    .wordmark,
    .account button {
        white-space: nowrap;
    }

    .site {
        gap: 0;
    }

    .site a {
        padding-left: 8px;
        padding-right: 8px;
    }

    .account .who {
        display: none;
    }

    .page {
        padding: 16px 16px 48px;
    }

    .page-title {
        font-size: 24px;
        margin-bottom: 16px;
    }

    .page section {
        padding: 16px;
    }

    .page section.lobby-status {
        grid-template-columns: 1fr 1fr;
        padding: 0;
    }

    .lobby-status > p {
        padding: 12px 16px;
    }

    .lobby-chat > h2,
    .lobby-chat > p,
    .lobby-chat > .hint,
    .chat-lines,
    .lobby-chat form.say {
        padding-left: 16px;
        padding-right: 16px;
    }

    /* On a phone the buttons for a player go on their own line under the name. */
    .roster li {
        grid-template-columns: 24px minmax(0, 1fr) auto;
    }

    .roster .actions {
        grid-column: 2 / -1;
        justify-content: flex-start;
    }

    .stats-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .chart {
        height: 160px;
    }

    .match-list table thead {
        display: none;
    }
}
