/* ===========================================================================
   Game hosting
   ---------------------------------------------------------------------------
   Loaded after main.css on game-ordering.php, game-configure.php and
   game-order.php.

   Built from the palette already in main.css -- #242943 ground, #9bf1ff /
   #53e3fb accent, and the muted status tones the theme already uses. Nothing
   here is a new colour, and nothing here is a new breakpoint: the card grid
   auto-fits, so there is no column count to walk back down through media
   queries.

   TWO RULES IN main.css THAT THIS FILE HAS TO WORK AROUND, both invisible in
   the markup and both of which have cost a render cycle before:

     1. EVERY <label> is styled as a field label -- uppercase, 600 weight,
        0.25em letter-spacing. A sentence inside a label renders as shouting,
        so the choice cards reset it locally.
     2. Checkbox and radio inputs are hidden outright (appearance:none;
        opacity:0; z-index:-1) and redrawn as a ::before on the ADJACENT
        SIBLING label. Nesting an input inside its label gives a card with no
        visible control at all -- the markup must be <input id><label for>.
   =========================================================================== */

:root {
    --game-panel:       rgba(255, 255, 255, 0.045);
    --game-panel-hover: rgba(255, 255, 255, 0.075);
    --game-line:        rgba(255, 255, 255, 0.13);
    --game-line-strong: rgba(255, 255, 255, 0.3);
    --game-muted:       rgba(255, 255, 255, 0.62);
    --game-faint:       rgba(255, 255, 255, 0.42);
    --game-accent:      #9bf1ff;
    --game-accent-deep: #53e3fb;
    --game-good:        #87c5a4;
    --game-warn:        #e7b788;
    --game-bad:         #ec8d81;
    --game-radius:      10px;
    --game-radius-lg:   14px;
}

/* --- shared primitives --------------------------------------------------- */

.game-page .inner { max-width: 1400px; }

.game-lede {
    max-width: 62ch;
    color: var(--game-muted);
    font-size: 1.05rem;
    line-height: 1.65;
}

.game-breadcrumb {
    margin-top: -1rem;
    margin-bottom: 2rem;
    font-size: 0.9rem;
    color: var(--game-muted);
}

.game-panel {
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius-lg);
    padding: 1.75rem;
}

.game-panel + .game-panel { margin-top: 1.5rem; }
.game-panel > h2, .game-panel > h3 { margin-top: 0; }

.game-eyebrow {
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--game-faint);
    margin-bottom: 0.4rem;
}

.game-muted { color: var(--game-muted); }
.game-optional { color: var(--game-faint); font-weight: 400; text-transform: none; letter-spacing: 0; }

.game-mono {
    font-family: "Courier New", monospace;
    word-break: break-all;
}

/* --- trust strip --------------------------------------------------------- */

.game-assurances {
    list-style: none;
    padding: 0;
    margin: 2rem 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 2rem;
}

.game-assurances li {
    padding: 0;
    color: var(--game-muted);
    font-size: 0.92rem;
    display: flex;
    align-items: baseline;
    gap: 0.55rem;
}

.game-assurances li::before {
    content: '';
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--game-accent);
}

/* --- toolbar ------------------------------------------------------------- */

.game-toolbar {
    margin: 2.5rem 0 1.5rem;
    display: grid;
    gap: 1.25rem;
}

.game-toolbar-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
}

.game-search { flex: 1 1 260px; min-width: 0; }

.game-toolbar input[type="search"],
.game-toolbar select { margin: 0; }

.game-filter-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.game-filter-group > .game-eyebrow { margin: 0 0.25rem 0 0; }

/*
 * Catalogue tabs.
 *
 * AMP's application list mixes game servers with database engines and language
 * runtimes. These split them so the shop reads as a shop. Uses the same tokens
 * as the availability chips below so the two rows of controls look related
 * rather than like two different designs stacked on top of each other.
 */
.game-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin: 0 0 1.25rem;
    border-bottom: 1px solid var(--game-line);
}

.game-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1.1rem;
    border: 1px solid transparent;
    border-bottom: none;
    border-radius: var(--game-radius) var(--game-radius) 0 0;
    color: var(--game-muted);
    font-size: 0.9rem;
    letter-spacing: 0.03em;
    text-decoration: none;
    /* Sit on top of the container's border rather than above it. */
    margin-bottom: -1px;
}

.game-tab:hover {
    background: var(--game-panel-hover);
    color: #fff;
}

.game-tab.is-active {
    background: var(--game-panel);
    border-color: var(--game-line);
    border-bottom: 1px solid var(--game-panel);
    color: var(--game-accent);
}

.game-tab-count {
    font-size: 0.75rem;
    color: var(--game-faint);
    background: rgba(255, 255, 255, 0.06);
    border-radius: 999px;
    padding: 0.1rem 0.5rem;
    line-height: 1.5;
}

.game-tab.is-active .game-tab-count {
    color: var(--game-accent);
    background: rgba(155, 241, 255, 0.12);
}

/*
 * Cards outside the active tab. The server renders every card so the page works
 * with JavaScript off; this hides the ones the current tab does not want. The
 * script sets [hidden] once it takes over, and that has to win over this rule --
 * hence :not([hidden]) rather than a plain display:none.
 */
/*
 * THIS RULE IS LOAD-BEARING. Without it nothing the script hides is actually
 * hidden.
 *
 * The browser's own stylesheet carries `[hidden] { display: none }`, but that
 * is a presentational default and ANY author rule setting `display` beats it.
 * `.game-card` sets `display: flex` a few rules down, so `card.hidden = true`
 * set the attribute and changed nothing on screen -- the search box, the
 * availability chips and the tabs all "filtered" into a grid that still showed
 * every card.
 *
 * Specificity, not order, is what fixes it: `.game-card[hidden]` is (0,2,0)
 * against `.game-card`'s (0,1,0), so this wins wherever it sits in the file.
 */
.game-card[hidden] {
    display: none !important;
}

.game-card.is-offtab:not([hidden]) {
    display: none;
}

.game-chip {
    appearance: none;
    background: transparent;
    border: 1px solid var(--game-line);
    border-radius: 999px;
    color: var(--game-muted);
    cursor: pointer;
    font-size: 0.82rem;
    letter-spacing: 0.04em;
    padding: 0.35rem 0.9rem;
    line-height: 1.4;
}

.game-chip:hover {
    background: var(--game-panel-hover);
    color: #fff;
}

.game-chip[aria-pressed="true"] {
    border-color: var(--game-accent);
    color: var(--game-accent);
    background: rgba(155, 241, 255, 0.08);
}

.game-result-count {
    margin: 0 0 0 auto;
    color: var(--game-faint);
    font-size: 0.85rem;
}

/* --- the grid ------------------------------------------------------------ */

.game-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.25rem;
}

.game-card {
    padding: 0;
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius-lg);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.game-card:hover,
.game-card:focus-within {
    background: var(--game-panel-hover);
    border-color: var(--game-line-strong);
}

/* Fixed aspect so a missing or oddly proportioned image cannot make one card
   taller than its neighbours and break the grid's rhythm. */
.game-card-art {
    display: block;
    width: 100%;
    aspect-ratio: 92 / 43;
    object-fit: cover;
    background: rgba(0, 0, 0, 0.25);
    border-bottom: 1px solid var(--game-line);
}

.game-card-art-blank {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--game-faint);
    font-size: 2.5rem;
    font-weight: 300;
}

.game-card-body {
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    flex: 1;
}

.game-card h3 {
    font-size: 1rem;
    margin-bottom: 0.5rem;
    line-height: 1.35;
}

.game-badges { margin: 0 0 0.6rem; }

.game-badge {
    display: inline-block;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    border: 1px solid var(--game-line);
    border-radius: 999px;
    padding: 0.2rem 0.6rem;
    color: var(--game-muted);
}

.game-badge-warn { border-color: rgba(231, 183, 136, 0.5); color: var(--game-warn); }

.game-price { margin: 0 0 0.4rem; line-height: 1.2; }
.game-price strong { font-size: 1.5rem; font-weight: 600; color: #fff; }
.game-price span:last-child { color: var(--game-muted); font-size: 0.85rem; }

.game-card-detail {
    color: var(--game-muted);
    font-size: 0.85rem;
    line-height: 1.5;
    margin-bottom: 1rem;
}

/* Pushes the button to the bottom, so buttons line up across a row of cards
   whose text runs to different lengths. */
.game-card-cta { margin-top: auto; align-self: flex-start; }

.game-card.is-unavailable { opacity: 0.62; }

.game-empty {
    margin: 2.5rem 0;
    padding: 2rem;
    text-align: center;
    color: var(--game-muted);
    border: 1px dashed var(--game-line);
    border-radius: var(--game-radius-lg);
}

/* --- notices ------------------------------------------------------------- */

.game-notice {
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-left: 3px solid var(--game-line-strong);
    border-radius: var(--game-radius);
    padding: 1rem 1.25rem;
    margin-bottom: 1.5rem;
    color: var(--game-muted);
}

.game-notice p:last-child { margin-bottom: 0; }
.game-notice-good { border-left-color: var(--game-good); }
.game-notice-warn { border-left-color: var(--game-warn); }
.game-notice-bad  { border-left-color: var(--game-bad); }
.game-notice-info { border-left-color: var(--game-accent); }

/* --- configure page ------------------------------------------------------ */

.game-configure {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: 2.5rem;
    align-items: start;
}

@media screen and (max-width: 980px) {
    .game-configure { grid-template-columns: 1fr; }
}

.game-step {
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius-lg);
    padding: 1.75rem;
    margin-bottom: 1.5rem;
}

.game-step > legend {
    font-size: 0.72rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--game-accent);
    padding: 0 0.5rem;
    margin-left: -0.5rem;
}

.game-step-hint {
    color: var(--game-muted);
    font-size: 0.9rem;
    margin-bottom: 1.5rem;
}

.game-field { margin-bottom: 1.5rem; }
.game-field:last-child { margin-bottom: 0; }

.game-field > label {
    display: block;
    margin-bottom: 0.4rem;
}

.game-field-note {
    color: var(--game-faint);
    font-size: 0.82rem;
    line-height: 1.5;
    margin: 0.4rem 0 0;
}

/* --- plan choices -------------------------------------------------------- */

.game-choices {
    display: grid;
    gap: 0.75rem;
}

.game-choice {
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius);
    background: rgba(255, 255, 255, 0.02);
}

.game-choice:hover { background: var(--game-panel-hover); }

.game-choice:has(input:checked) {
    border-color: var(--game-accent);
    background: rgba(155, 241, 255, 0.07);
}

.game-choice.is-disabled { opacity: 0.45; }
.game-choice.is-disabled:hover { background: rgba(255, 255, 255, 0.02); }

/* Undo main.css's global label treatment. Without this the plan names render
   as spaced-out uppercase shouting. */
.game-choice label {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 0.2rem 1rem;
    margin: 0;
    padding: 1rem 1.1rem 1rem 3rem;
    cursor: pointer;
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
    font-size: 1rem;
}

.game-choice label strong {
    grid-column: 1;
    color: #fff;
    font-weight: 600;
}

.game-choice label .game-choice-detail {
    grid-column: 1;
    color: var(--game-muted);
    font-size: 0.85rem;
    line-height: 1.5;
}

.game-choice label .game-choice-price {
    grid-column: 2;
    grid-row: 1 / span 2;
    font-size: 1.35rem;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
}

.game-choice label .game-choice-price small {
    font-size: 0.8rem;
    font-weight: 400;
    color: var(--game-muted);
}

/* --- order summary ------------------------------------------------------- */

.game-summary {
    position: sticky;
    top: 2rem;
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius-lg);
    padding: 1.75rem;
}

@media screen and (max-width: 980px) {
    .game-summary { position: static; }
}

.game-summary h2 { font-size: 1.1rem; margin-bottom: 1.25rem; }

.game-summary dl { margin: 0 0 1.25rem; }

.game-summary dl > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0;
    border-top: 1px solid var(--game-line);
}

.game-summary dl > div:first-child { border-top: 0; }
.game-summary dt { color: var(--game-muted); margin: 0; font-weight: 400; }
.game-summary dd { margin: 0; text-align: right; word-break: break-word; }

.game-summary-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding-top: 1rem;
    border-top: 1px solid var(--game-line-strong);
    margin-bottom: 0.5rem;
}

.game-summary-total strong { font-size: 1.5rem; font-weight: 600; color: #fff; }

.game-summary-note {
    color: var(--game-faint);
    font-size: 0.82rem;
    line-height: 1.5;
    margin: 0.75rem 0 0;
}

/* --- order page ---------------------------------------------------------- */

.game-track {
    list-style: none;
    padding: 0;
    margin: 2rem 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 0.75rem;
}

@media screen and (max-width: 736px) {
    .game-track { grid-template-columns: repeat(2, 1fr); }
}

.game-track li {
    padding: 0.75rem 0 0;
    border-top: 3px solid var(--game-line);
    color: var(--game-faint);
    font-size: 0.85rem;
}

.game-track li strong { font-weight: 500; }
.game-track li.is-done    { border-top-color: var(--game-good); color: var(--game-muted); }
.game-track li.is-current { border-top-color: var(--game-accent); color: #fff; }

.game-status-banner {
    background: var(--game-panel);
    border: 1px solid var(--game-line);
    border-left: 3px solid var(--game-line-strong);
    border-radius: var(--game-radius);
    padding: 1.25rem 1.5rem;
    margin-bottom: 1.5rem;
    display: grid;
    gap: 0.35rem;
}

.game-status-banner strong { font-size: 1.05rem; }
.game-status-banner p { margin: 0; color: var(--game-muted); font-size: 0.92rem; }

.game-status-pending  { border-left-color: var(--game-warn); }
.game-status-progress { border-left-color: var(--game-accent); }
.game-status-good     { border-left-color: var(--game-good); }
.game-status-bad      { border-left-color: var(--game-bad); }
.game-status-muted    { border-left-color: var(--game-line-strong); }

.game-copy {
    margin: 0 0 0.75rem;
}

.game-copy pre {
    margin: 0;
    padding: 0.9rem 1.1rem;
    background: rgba(0, 0, 0, 0.28);
    border: 1px solid var(--game-line);
    border-radius: var(--game-radius);
    font-family: "Courier New", monospace;
    font-size: 1rem;
    overflow-x: auto;
}

.game-kv { margin: 0; }

.game-kv > div {
    display: grid;
    grid-template-columns: 10rem 1fr;
    gap: 1rem;
    padding: 0.6rem 0;
    border-top: 1px solid var(--game-line);
}

@media screen and (max-width: 736px) {
    .game-kv > div { grid-template-columns: 1fr; gap: 0.2rem; }
}

.game-kv > div:first-child { border-top: 0; }
.game-kv dt { color: var(--game-muted); margin: 0; font-weight: 400; }
.game-kv dd { margin: 0; word-break: break-word; }

.game-timeline {
    list-style: none;
    padding: 0 0 0 1.25rem;
    margin: 0;
}

.game-timeline li {
    position: relative;
    padding: 0 0 1.1rem 1rem;
    border-left: 1px solid var(--game-line);
    color: var(--game-muted);
    font-size: 0.9rem;
}

.game-timeline li::before {
    content: '';
    position: absolute;
    left: -4.5px;
    top: 0.45rem;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--game-line-strong);
}

.game-timeline li:last-child::before { background: var(--game-accent); }
.game-timeline li strong { color: #fff; display: block; }
.game-timeline time { display: block; color: var(--game-faint); font-size: 0.8rem; margin-top: 0.1rem; }

/* --- "your servers" list ------------------------------------------------- */

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

.game-order-list li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 1rem;
    padding: 0.85rem 0;
    border-top: 1px solid var(--game-line);
}

.game-order-list li:first-child { border-top: 0; }
.game-order-list .game-order-name { font-weight: 600; }
.game-order-list .game-order-meta { color: var(--game-muted); font-size: 0.86rem; }
.game-order-list .game-order-action { margin-left: auto; }

/* --- accessibility ------------------------------------------------------- */

.game-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.game-page :focus-visible {
    outline: 2px solid var(--game-accent);
    outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Server dashboard: meters, players, command box

   Added with the console's write side (send a command, kick, ban) and the
   gauges AMP was already sending and nobody was rendering.
   --------------------------------------------------------------------------- */

.game-meters {
	list-style: none;
	margin: 0 0 1em 0;
	padding: 0;
	display: grid;
	/* One column on a phone, three across once there is room. auto-fit rather
	   than a breakpoint: the card is not always full width. */
	grid-template-columns: repeat(auto-fit, minmax(13em, 1fr));
	gap: 0.5em 1.5em;
}

.game-meters li {
	display: flex;
	align-items: center;
	gap: 0.6em;
	padding: 0;
	font-size: 0.85em;
}

.game-meter-label {
	flex: 0 0 3.5em;
	opacity: 0.8;
}

.game-meter-track {
	flex: 1 1 auto;
	height: 0.45em;
	min-width: 3em;
	border-radius: 0.25em;
	background: rgba(144, 144, 144, 0.25);
	overflow: hidden;
}

.game-meter-fill {
	display: block;
	height: 100%;
	background: #21b2a6;
}

.game-meter-value {
	flex: 0 0 auto;
	opacity: 0.7;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.game-command {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	margin: 0.75em 0 0 0;
}

.game-command-label {
	flex: 0 0 auto;
	font-size: 0.85em;
	opacity: 0.8;
}

.game-command input[type="text"] {
	flex: 1 1 14em;
	/* The console above is monospaced; a command typed into a proportional box
	   next to it looks like it is going somewhere else. */
	font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
	margin: 0;
}

.game-panel-players {
	margin-top: 1em;
}

.game-panel-players h4 {
	font-size: 0.9em;
	margin-bottom: 0.4em;
}

.game-panel-players ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.game-panel-players li {
	display: flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.25em 0;
}

.game-panel-players form {
	margin: 0;
}

.game-player-name {
	flex: 1 1 auto;
	/* A player name is chosen by the player. Long ones must not push the
	   buttons off the card. */
	overflow-wrap: anywhere;
}

/* Backups. Added with restore/delete, which is why the confirmation gets its
   own treatment rather than being a line of text next to the button. */

.game-panel-backups {
	margin-top: 1em;
}

.game-panel-backups h4 {
	font-size: 0.9em;
	margin-bottom: 0.4em;
}

.game-panel-backups > form {
	margin: 0 0 0.75em 0;
}

.game-panel-backups ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.game-panel-backups li {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	padding: 0.4em 0;
	border-top: 1px solid rgba(144, 144, 144, 0.2);
}

.game-backup-what {
	flex: 1 1 14em;
	min-width: 0;
}

.game-backup-name {
	display: block;
	overflow-wrap: anywhere;
}

.game-backup-meta {
	display: block;
	font-size: 0.8em;
	opacity: 0.7;
}

.game-backup-actions {
	display: flex;
	gap: 0.4em;
}

.game-backup-actions form,
.game-backup-confirm form {
	margin: 0;
}

.game-backup-confirm {
	/* Full width, so the sentence explaining what is about to be destroyed is
	   not squeezed into a column beside the buttons. */
	flex: 1 1 100%;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	padding: 0.6em 0.8em;
	border-radius: 0.3em;
	background: rgba(200, 120, 60, 0.12);
}

.game-backup-confirm p {
	flex: 1 1 100%;
	margin: 0;
	font-size: 0.85em;
}

.game-backup-warning {
	font-size: 0.85em;
	opacity: 0.85;
}

/* Schedules. Same list shape as backups; the add form is a row of selects that
   has to wrap to one-per-line on a phone rather than shrink to unusable. */

.game-panel-schedules {
	margin-top: 1em;
}

.game-panel-schedules h4 {
	font-size: 0.9em;
	margin-bottom: 0.2em;
}

.game-schedule-note {
	font-size: 0.8em;
	opacity: 0.7;
	margin-bottom: 0.6em;
}

.game-panel-schedules ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.game-panel-schedules li {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	padding: 0.4em 0;
	border-top: 1px solid rgba(144, 144, 144, 0.2);
}

.game-schedule-what {
	flex: 1 1 14em;
	min-width: 0;
}

.game-schedule-name {
	display: block;
	overflow-wrap: anywhere;
}

.game-schedule-meta {
	display: block;
	font-size: 0.8em;
	opacity: 0.7;
}

.game-schedule-actions {
	display: flex;
	gap: 0.4em;
}

.game-schedule-actions form {
	margin: 0;
}

.game-schedule-add {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	margin: 0.9em 0 0 0;
}

.game-schedule-add label {
	flex: 0 0 auto;
	font-size: 0.85em;
	opacity: 0.8;
	margin: 0;
}

.game-schedule-add select {
	flex: 1 1 11em;
	margin: 0;
}

/* ---------------------------------------------------------------------------
   One server's own page.

   A GRID, NOT TABS. Everything is on the page at once, deliberately: you decide
   whether to restore a backup by reading the console, and you pick who to kick
   by reading the player list beside it. The same reasoning that took the JS tab
   strip out of vps-firewall.php applies harder here, and there is no script
   behind any of this -- if it renders, it works.
   --------------------------------------------------------------------------- */

.game-server-head {
	margin-bottom: 1.5em;
}

.game-server-state {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75em;
	margin-bottom: 0.75em;
}

.game-server-players,
.game-server-connect {
	font-size: 0.85em;
	opacity: 0.8;
}

.game-panels {
	display: grid;
	/* One column on a phone, two once there is room for them. The console is
	   the widest thing here and is given the room first. */
	grid-template-columns: repeat(auto-fit, minmax(22em, 1fr));
	gap: 1.5em;
	align-items: start;
}

.game-panel {
	padding: 1.25em;
	border: 1px solid rgba(144, 144, 144, 0.25);
	border-radius: 0.35em;
}

/* THE HEIGHT CAP BELONGS TO THE SIDE-BY-SIDE LAYOUT, not to the panel.
   -----------------------------------------------------------------------
   In two columns an uncapped backup list -- 28 of them on the Crafters
   servers -- pushes everything beside it far down the page, so each panel
   scrolls itself. Stacked in one column there is nothing beside it to push,
   and the cap then costs something real: a scrolling box inside a scrolling
   page, which on a touch screen means a flick that moves the wrong one and a
   list whose bottom you can only reach by landing your thumb outside it.
   Phones scroll; let them. Same reasoning, and the same breakpoint, as
   .vps-panel-scroll in vps.css. */
@media screen and (min-width: 737px) {
	.game-panel {
		max-height: 32em;
		overflow-y: auto;
	}
}

.game-panel h2 {
	font-size: 1em;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	margin-bottom: 0.75em;
	padding-bottom: 0.4em;
	border-bottom: 1px solid rgba(144, 144, 144, 0.25);
}

/* The console is read top to bottom and is the one panel worth the full width
   when there is enough of it to matter. */
.game-panel-console {
	grid-column: 1 / -1;
}

.game-panel-console .game-console {
	max-height: 18em;
}

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

.game-players-list li {
	display: flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.25em 0;
}

.game-players-list form {
	margin: 0;
}


/* The breadcrumb, on a page that also loads vps.css.
   -----------------------------------------------------------------------
   .game-breadcrumb pulls itself up by 1rem so it tucks under the heading on
   the game shop pages, where header.major has no rule beneath it. The two
   management pages load vps.css as well -- they borrow its layout -- and
   vps.css DOES put a rule there, which the negative margin then sits on top
   of. Scoped to .vps-page so the shop pages are untouched. */

.vps-page .game-breadcrumb {
	margin-top: 0;
}


/* The server switcher.
   -----------------------------------------------------------------------
   MEASURED, NOT GUESSED: with four servers on a 375px viewport the strip was
   630px wide and, being a nowrap flex row with visible overflow, it made the
   whole DOCUMENT 654px wide. The entire page scrolled sideways -- every
   paragraph, every panel -- which is far worse than the strip alone doing it.

   Scrolling the strip itself keeps the overflow where it belongs. Not wrapped
   onto several lines, because the underline that marks the current server
   reads as a row: a wrapped strip puts that mark on a line of its own with no
   relationship to anything. */

.game-servers-strip {
	overflow-x: auto;
	/* SET EXPLICITLY, because `overflow-x: auto` alone makes the other axis
	   compute to `auto` as well -- vps.css records that being tried on this
	   same strip and putting a scrollbar down its right-hand end. The tabs
	   hang a pixel below the box to sit on the rule beneath, so the padding
	   below keeps that pixel inside the box and there is nothing for `hidden`
	   to cut off. Measured: no vertical scrollbar at 375px or 1280px. */
	overflow-y: hidden;
	/* The flex children must not be squeezed to fit -- that is what turns a
	   scrollable row back into an unreadable one. */
	flex-wrap: nowrap;
	/* Room for the scrollbar where the platform draws one, so it does not sit
	   on top of the current-server underline. */
	padding-bottom: 0.2em;
	scrollbar-width: thin;
}

.game-servers-strip > * {
	flex: 0 0 auto;
}

/* Files.
   -----------------------------------------------------------------------
   The panel is full width like the console: a listing squeezed into half a
   grid column wraps every filename, and a config file cannot be edited in a
   textarea that narrow. */

.game-panel-files {
	grid-column: 1 / -1;
}

.game-file-crumbs {
	font-size: 0.85em;
	margin-bottom: 0.6em;
	/* A deep path must scroll rather than widen the page -- the same rule the
	   server strip needed, for the same reason. */
	overflow-x: auto;
	overflow-y: hidden;
	white-space: nowrap;
}

.game-file-list {
	list-style: none;
	margin: 0 0 1em 0;
	padding: 0;
}

.game-file-list li {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
	padding: 0.35em 0;
	border-top: 1px solid rgba(144, 144, 144, 0.18);
}

.game-file-up a {
	font-size: 0.85em;
}

.game-file-what {
	flex: 1 1 16em;
	min-width: 0;
}

.game-file-name {
	display: block;
	/* A filename is chosen by whatever wrote it and can be very long. */
	overflow-wrap: anywhere;
}

.game-file-meta {
	display: block;
	font-size: 0.78em;
	opacity: 0.65;
}

.game-file-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35em;
}

.game-file-actions form,
.game-file-tools form {
	margin: 0;
}

.game-file-tools {
	display: flex;
	flex-wrap: wrap;
	gap: 1.5em;
	padding-top: 0.75em;
	border-top: 1px solid rgba(144, 144, 144, 0.25);
}

.game-file-tools form {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5em;
}

.game-file-tools label {
	font-size: 0.85em;
	opacity: 0.8;
	margin: 0;
}

.game-file-tools input[type="text"] {
	flex: 0 1 12em;
	margin: 0;
}

.game-file-editing {
	font-size: 0.95em;
	font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
	overflow-wrap: anywhere;
}

.game-file-editor textarea {
	/* Monospaced and unwrapped: a config file read with its lines rewrapped is
	   a different file to the eye. */
	font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
	font-size: 0.85em;
	white-space: pre;
	margin-bottom: 0.75em;
}
