/* Per-theme palettes mirror the game themes (SRV-7) - menu screen background gradient,
   panel surface, accents - from composeApp/.../ui/style/themes/*.kt. The custom
   user-defined theme is deliberately excluded. Classic is the default (:root), matching
   the game's default theme index 0. */
:root {
    --bg1: #af6222; --bg2: #fad065;
    --surface: #162941; --border: #2c4363;
    --text: #ffffff; --title: #ffffff;
    --accent: #f19e56; --hint: #a0a590;
    --error: #f28b82;
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23ffffff' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
    /* Shared image-state placeholders (SRV-12): a rotating spinner while an image loads
       (SMIL animation - animates as a CSS background), and a broken-image glyph on error.
       Both are toggled by the img-loading / img-loaded / img-error classes below. */
    --img-spinner: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23888'%20stroke-width='2.5'%20stroke-linecap='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'%20stroke-opacity='0.25'/%3E%3Cpath%20d='M12%203a9%209%200%200%201%209%209'%3E%3CanimateTransform%20attributeName='transform'%20type='rotate'%20from='0%2012%2012'%20to='360%2012%2012'%20dur='0.7s'%20repeatCount='indefinite'/%3E%3C/path%3E%3C/svg%3E");
    --img-broken: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23888'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Crect%20x='3'%20y='3'%20width='18'%20height='18'%20rx='2'/%3E%3Ccircle%20cx='8.5'%20cy='8.5'%20r='1.5'/%3E%3Cpath%20d='M21%2015l-5-5L5%2021'/%3E%3C/svg%3E");
}
:root[data-theme="borealis"] {
    --bg1: #67765c; --bg2: #5a6350;
    --surface: #414b36; --border: #55614a;
    --text: #ffffff; --title: #ffffff;
    --accent: #99903f; --hint: #899383;
}
:root[data-theme="source"] {
    --bg1: #578686; --bg2: #44656f;
    --surface: #204d5a; --border: #2f6373;
    --text: #ffffff; --title: #ffffff;
    --accent: #259bb1; --hint: #8999a7;
}
:root[data-theme="strawberry"] {
    --bg1: #ac2f41; --bg2: #5e1a21;
    --surface: #680f1a; --border: #8a2530;
    --text: #fff0ee; --title: #fff0ee;
    --accent: #f4a8b0; --hint: #b3626d;
}
:root[data-theme="velvet"] {
    --bg1: #5e3c2c; --bg2: #6e4535;
    --surface: #2a2018; --border: #4a3a2e;
    --text: #f5ede6; --title: #f5ede6;
    --accent: #d47d60; --hint: #9b9489;
}
:root[data-theme="icecream"] {
    --bg1: #ecddcd; --bg2: #b49e90;
    --surface: #efe3df; --border: #d9c5bc;
    --text: #6b3e2a; --title: #6b3e2a;
    --accent: #a87760; --hint: #b1a89d;
    --error: #b3453c;
    --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236b3e2a' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
}
@font-face {
    font-family: "ZoleMenu";
    src: url("font_menu.ttf") format("truetype");
}
/* Kills the default blue flash mobile browsers draw over any tapped element - separate
   from the outline:none rules below, which only affect keyboard focus. */
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body {
    font-family: system-ui, sans-serif;
    min-height: 100vh;
    background: var(--bg2);
    color: var(--text);
    padding: 24px 16px;
}
/* The gradient paints on a fixed viewport-sized layer instead of the document body, so
   it never stretches or shrinks when the page height changes (paging, expanding). The
   plain --bg2 on body covers overscroll. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    background: linear-gradient(180deg, var(--bg1), var(--bg2));
}
main { max-width: 840px; margin: 0 auto; }
.switchers { display: flex; justify-content: flex-end; gap: 8px; margin-bottom: 16px; }
/* All switcher controls share one fixed height with zero vertical padding, so the
   select text and the profile icon center identically. */
.switchers select {
    appearance: none;
    -webkit-appearance: none;
    background: var(--surface) var(--chevron) no-repeat right 10px center;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    height: 32px;
    padding: 0 28px 0 10px;
    line-height: 1;
    font-family: inherit;
    cursor: pointer;
}
.switchers select:focus { outline: none; }
.switchers button, .switchers a {
    display: flex;
    align-items: center;
    gap: 6px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    height: 32px;
    padding: 0 10px;
    text-decoration: none;
    font-size: 0.9rem;
    cursor: pointer;
}
.switchers button:hover, .switchers a:hover { border-color: var(--accent); }
/* Home link sits on the left of the switchers row; narrow screens keep the icon only. */
.switchers .back-link { margin-right: auto; }
@media (max-width: 480px) {
    .switchers .back-link span { display: none; }
}
.title-banner { position: relative; margin-bottom: 24px; }
.title-banner img {
    display: block;
    width: 100%;
    height: 100px;
    object-fit: cover;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.title-banner h1 {
    font-family: "ZoleMenu", system-ui, sans-serif;
    color: var(--title);
    text-align: center;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
}
/* Text-over-image mode: the title centers on top of the banner image. The banner image
   does NOT change with the theme, so the title stays a fixed white (not the theme --title,
   which is dark on light themes and would vanish on the image). Text-only mode keeps
   --title so it reads on the page gradient. */
.title-banner img + h1 {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    color: #fff;
}
section {
    background: var(--surface);
    border-radius: 12px;
    padding: 16px 20px;
    margin-bottom: 16px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
section h2 { color: var(--accent); margin-bottom: 12px; font-size: 1.1rem; }
section h3 { color: var(--accent); font-size: 1rem; margin: 16px 0 8px; }
.empty { color: var(--hint); }
.banner { margin-bottom: 16px; }
.banner:last-of-type { margin-bottom: 0; }
/* Divider between visible banners - the first visible one never gets a border, even
   when earlier banners are hidden by the collapse/paging logic. */
.banner:not(.collapsed) ~ .banner:not(.collapsed) { border-top: 1px solid var(--border); padding-top: 16px; }
.banner h3 { color: var(--text); margin-bottom: 4px; }
/* Long unbreakable strings (URLs) may wrap mid-word instead of spilling past the
   section padding on narrow screens. */
.banner-text { overflow-wrap: anywhere; }
.banner-text ul { margin: 4px 0; padding-left: 20px; }
.banner a { color: var(--accent); }
.banner-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.banner-date { color: var(--hint); font-size: 0.85rem; white-space: nowrap; }
/* Photo strip scrolls horizontally instead of wrapping when there are many images.
   The scrollbar is themed: transparent track, border-coloured thumb (the standard
   scrollbar-* properties win in Chromium/Firefox; ::-webkit-* covers older engines). */
.banner-images {
    display: flex;
    gap: 8px;
    margin-top: 8px;
    overflow-x: auto;
    padding-bottom: 4px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.banner-images::-webkit-scrollbar { height: 8px; }
.banner-images::-webkit-scrollbar-track { background: transparent; }
.banner-images::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
/* min-width so a failed image keeps its box instead of collapsing to a thin line. The
   background placeholder is state-driven (SRV-12): a spinner while loading, cleared to a
   plain surface once loaded (so a semi-transparent image doesn't show it through), and the
   broken-image glyph only on error. Classes are toggled by trackImageState in script.js. */
.banner-images img { height: 120px; min-width: 150px; object-fit: cover; border-radius: 8px; border: 1px solid var(--border); flex-shrink: 0; cursor: pointer; background: var(--surface) center / 36px no-repeat var(--img-spinner); }
.banner-images img.img-loaded { background: var(--surface); }
.banner-images img.img-error { background: var(--surface) center / 48px no-repeat var(--img-broken); }
/* Fixed column widths so the table doesn't reflow when paging swaps rows; long table
   names get an ellipsis instead of stretching their column. Headers may wrap to two
   rows ("Gājiena laiks") - cell text still never wraps. Below the table's min-width
   (narrow phones) the block scrolls horizontally instead of crushing the columns. */
.table-scroll { overflow-x: auto; scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
.table-scroll::-webkit-scrollbar { height: 8px; }
.table-scroll::-webkit-scrollbar-track { background: transparent; }
.table-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
/* Icon headers keep the numeric columns as narrow as their content ("3 / 4", "30s"),
   freeing width for the name and mode columns; the shares are tuned against the
   min-width so cell values still fit at the narrowest layout. Only data cells
   ellipsize - headers may overflow visibly so the sort marker never turns into "…". */
#tables-block table { table-layout: fixed; min-width: 620px; }
#tables-block td { overflow: hidden; text-overflow: ellipsis; }
/* Icon and text headers share the text baseline; the small negative offset drops the
   icon's bottom edge just below it, matching how the glyphs optically sit. Headers
   never wrap - the sort direction marker must stay beside the icon on narrow screens
   (all headers are one word or an icon since the icon-header change). */
#tables-block th { white-space: nowrap; vertical-align: baseline; }
#tables-block th svg { vertical-align: -2px; }
#tables-block td { white-space: nowrap; }
/* Mode letter codes render as small pills; they may wrap onto extra lines instead of
   ellipsizing when a table has many rule options enabled. */
#tables-block td:nth-child(4) { white-space: normal; }
#tables-block td:nth-child(4) span {
    display: inline-block;
    background: var(--border);
    border-radius: 999px;
    padding: 2px 7px;
    margin: 1px 0;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.3;
}
.mode-legend { color: var(--hint); font-size: 0.85rem; margin-top: 8px; }
/* Columns: code · competitive · players · mode · rounds · timeout · spectators · status
   (the "name" is the 5-letter table code - tables cannot be named). */
/* PT20-7: wide enough for a table ID. At 9% of the 620px minimum this is 56px, and a five-character
   id was ellipsized on a phone - the one column whose content a player has to READ, since it is what
   they look for in the game's own lobby. The width comes out of the modes column, which wraps. */
#tables-block th:nth-child(1) { width: 14%; }
#tables-block th:nth-child(2) { width: 5%; }
#tables-block th:nth-child(3) { width: 10%; }
#tables-block th:nth-child(4) { width: 31%; }
#tables-block th:nth-child(5) { width: 8%; }
#tables-block th:nth-child(6) { width: 10%; }
#tables-block th:nth-child(7) { width: 8%; }
#tables-block th:nth-child(8) { width: 14%; }
/* Collapsed is a state, not a style - it must beat any element's own display rule
   (e.g. the flex admin-banner rows and overlays), hence the !important. */
.collapsed { display: none !important; }
.pager { display: flex; justify-content: center; align-items: center; gap: 12px; margin-top: 12px; }
.pager button {
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    color: var(--accent);
    border: 1px solid var(--border);
    border-radius: 8px;
    width: 32px;
    height: 28px;
    padding: 0 0 2px; /* optical centering - the ‹ › glyphs sit slightly high */
    line-height: 1;
    font-family: inherit;
    font-size: 1rem;
    cursor: pointer;
}
.pager button:disabled { color: var(--hint); cursor: default; }
.pager button:not(:disabled):hover { border-color: var(--accent); }
.pager span { color: var(--hint); font-size: 0.9rem; }
/* Sign-in dialog (home page) - alpha allowed on the overlay only, like the lightbox. */
.dialog-overlay {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: rgba(0, 0, 0, 0.75);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.dialog {
    background: var(--surface);
    border-radius: 12px;
    padding: 20px 24px;
    width: min(100%, 360px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
.dialog h2 { color: var(--accent); margin-bottom: 12px; font-size: 1.1rem; }
.dialog-link {
    display: block;
    margin: 12px auto 0;
    background: none;
    border: none;
    color: var(--accent);
    font-family: inherit;
    font-size: 0.9rem;
    text-decoration: underline;
    cursor: pointer;
}
/* Sign-in form + profile page. */
form { display: flex; flex-direction: column; gap: 8px; }
form label { color: var(--accent); font-size: 0.9rem; }
form input[type="text"], form input[type="password"], form input[type="number"], form textarea {
    background: none;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px 10px;
    font-family: inherit;
    font-size: 1rem;
}
form input:focus, form textarea:focus { outline: none; border-color: var(--accent); }
form textarea { resize: vertical; }
/* Number spinners render on a white chrome that clashes with the theme - hide them,
   typing and arrow keys still work. */
form input[type="number"]::-webkit-inner-spin-button,
form input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
form input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
/* Custom checkbox: transparent when unchecked (the native white box clashes with the
   theme), accent-filled with a surface-coloured check when checked. */
form input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: none;
    cursor: pointer;
    position: relative;
    flex-shrink: 0;
}
form input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
form input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--surface);
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 10px 8px no-repeat;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='8'%3E%3Cpath d='M1 4l3 3 5-6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 10px 8px no-repeat;
}
.checkbox-row { display: flex; align-items: center; gap: 8px; }
.form-actions { display: flex; align-items: center; gap: 8px; }
/* Sign-up-only dialog fields (repeat password + recovery email): shown by script.js in
   sign-up mode, laid out like direct form children. */
.signup-only, .signup-email { display: flex; flex-direction: column; gap: 8px; }
/* Password reset page (reset.html): one narrow centered card. */
.reset-card { max-width: 420px; margin-left: auto; margin-right: auto; }
.reset-card .reset-home-link {
    display: inline-block;
    margin-top: 12px;
    text-decoration: none;
    text-align: center;
}
/* The change-password block sits below the profile stats table. */
.password-change-form { margin-top: 8px; }
/* Password field with the reveal (eye) toggle inside it. */
.password-box { position: relative; display: flex; }
.password-box input { flex: 1; padding-right: 36px; }
.password-toggle {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: none;
    border: none;
    color: var(--hint);
    cursor: pointer;
    padding: 0;
}
.password-toggle:hover { color: var(--accent); }
.password-toggle .eye-off { display: none; }
.password-toggle.revealed .eye { display: none; }
.password-toggle.revealed .eye-off { display: block; }
/* Image URL pill input: pills with a small preview + remove button, the entry field
   flows after them inside one bordered box. */
.pill-input {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 6px;
}
.pill-input:focus-within { border-color: var(--accent); }
.pill-input .pill-entry {
    flex: 1;
    min-width: 160px;
    background: none;
    border: none;
    color: var(--text);
    font-family: inherit;
    font-size: 1rem;
    padding: 4px;
}
.pill-input .pill-entry:focus { outline: none; }
.pill-item {
    display: flex;
    align-items: center;
    gap: 4px;
    background: var(--border);
    border-radius: 6px;
    padding: 2px;
}
.pill-item img { height: 24px; width: 36px; object-fit: cover; border-radius: 4px; display: block; background: var(--surface) center / 16px no-repeat var(--img-spinner); }
.pill-item img.img-loaded { background: var(--surface); }
.pill-item img.img-error { background: var(--surface) center / 18px no-repeat var(--img-broken); }
.pill-remove {
    background: none;
    border: none;
    color: var(--text);
    font-size: 1rem;
    line-height: 1;
    padding: 0 4px;
    cursor: pointer;
}
.pill-remove:hover { color: var(--error); }
/* Player avatars: image or an accent circle with the name's first letter. */
.avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}
span.avatar-initial {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent);
    color: var(--surface);
    font-weight: 600;
    /* line-height 1 centers the glyph - the inherited 1.4-ish line box sat low. */
    line-height: 1;
    font-size: 0.9rem;
}
/* Rankings table: fixed columns; the player cell holds avatar + ellipsizing name.
   Only the NARROW columns are sized and the player column takes what is left - SRV-17 added a
   fifth column to a set of four percentages that already summed to 100, so "rounds won" was laid
   out at width 0 and drawn outside the panel. Sizing every column but one removes that sum. */
#players-block table { table-layout: fixed; min-width: 520px; }
#players-block th:nth-child(1) { width: 3rem; }
#players-block th:nth-child(3) { width: 5rem; }
#players-block th:nth-child(4) { width: 7rem; }
#players-block th:nth-child(5) { width: 7rem; }
/* These headers are long in Latvian ("Uzvarētās partijas"), so they wrap rather than overflow. */
#players-block th { white-space: normal; }
#players-block td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.player-cell { display: flex; align-items: center; gap: 8px; min-width: 0; }
.player-cell .admin-banner-name { overflow: hidden; text-overflow: ellipsis; }
/* Staff in the player list: accent-coloured name + a shield with a role tooltip
   (filled = admin, outlined = moderator). */
.player-cell .role-staff { color: var(--accent); }
.role-badge { display: inline-flex; align-items: center; color: var(--accent); flex-shrink: 0; }
/* Competitive (ELO-rated) table marker in the table list. */
.competitive-mark { display: inline-flex; align-items: center; color: var(--accent); }
.player-elo { color: var(--accent); font-weight: 600; }
/* Forum preview block on the home page: compact one-line posts linking to the thread, with
   a chevron on the right showing they open. */
.forum-preview-post {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0;
    color: var(--text);
    text-decoration: none;
}
/* Dividers sit BETWEEN posts (never below the last), so the trailing "open forum" button
   doesn't leave a dangling line under the final post. */
.forum-preview-post + .forum-preview-post { border-top: 1px solid var(--border); }
.forum-preview-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* Three lines per post: meta (date · author), the thread title, then the first body line.
   Each is nowrap + ellipsis so it can't overflow the min-width:0 column under the fixed arrow;
   the title is the emphasis, the body line muted. */
.forum-preview-main .banner-date { overflow: hidden; text-overflow: ellipsis; }
.forum-preview-title { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.forum-preview-post:hover .forum-preview-title { color: var(--accent); }
.forum-preview-arrow { color: var(--hint); flex-shrink: 0; display: flex; }
.forum-preview-post:hover .forum-preview-arrow { color: var(--accent); }
.forum-preview-text {
    color: var(--hint);
    font-size: 0.9rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.forum-open { margin-top: 12px; }
/* Forum overview: categories with subcategory link rows and inline admin controls. */
.forum-category { margin-bottom: 16px; }
.forum-category:last-of-type { margin-bottom: 0; }
.forum-category-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.forum-category-head h3 { color: var(--text); flex: 1; }
/* Thread rows (the ?sub= list) share the subcategory-row anatomy. */
.forum-sub-row, .forum-thread-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 0 6px 12px;
    border-bottom: 1px solid var(--border);
}
.forum-sub-row:last-of-type, .forum-thread-row:last-of-type { border-bottom: none; }
/* Pinned thread (SRV-10): an accent left-border marks the row (alpha-free per the flat
   colour rule) plus an accent pin badge before the title. */
.forum-thread-row.pinned { border-left: 3px solid var(--accent); padding-left: 9px; }
.forum-pin-badge { color: var(--accent); margin-right: 4px; }
.forum-pin-badge svg { vertical-align: -2px; }
/* Read-only marker next to a subcategory name; the admin's toggle lights up active. */
.forum-lock { color: var(--hint); }
.forum-lock svg { vertical-align: -2px; }
.icon-button.toggled { color: var(--accent); border-color: var(--accent); }
.forum-sub-info { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.forum-sub-link { color: var(--accent); text-decoration: none; }
.forum-sub-link:hover { text-decoration: underline; }
.forum-sub-desc { color: var(--hint); font-size: 0.85rem; }
.forum-last-post { color: var(--hint); font-size: 0.75rem; text-align: right; line-height: 1.4; flex-shrink: 0; }
/* Thread view: the description hugs its heading, with clear air before the form. */
section h2 + .forum-sub-desc { margin: -8px 0 16px; }
/* Image links in posts render inline, size-capped, clickable to the original. */
.post-image { display: block; max-width: min(100%, 400px); max-height: 260px; border-radius: 8px; border: 1px solid var(--border); margin: 4px 0; }
.forum-add-form { flex-direction: row; gap: 8px; margin-top: 8px; }
.forum-add-form input[type="text"] { flex: 1; min-width: 0; padding: 6px 10px; font-size: 0.9rem; }
.forum-breadcrumb { color: var(--hint); text-decoration: none; display: inline-block; margin-bottom: 8px; }
.forum-breadcrumb:hover { color: var(--accent); }
/* Forum page posts: the posts section uses equal padding so each post body sits an equal
   distance from all edges; dividers separate posts (never above the first). */
#forum-section { padding: 20px; }
.forum-post { padding: 0; }
.forum-post + .forum-post { border-top: 1px solid var(--border); margin-top: 16px; padding-top: 16px; }
.forum-post-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.forum-post-head .banner-date { margin-left: auto; }
.forum-post-head .confirm-submit { flex-direction: row; }
.removed-post { color: var(--hint); font-style: italic; }
/* Own profile image editor: large centered preview above the info, URL field below. */
.avatar-form { margin-bottom: 16px; }
.name-form { margin-bottom: 16px; }
.name-form .error { margin: 8px 0 0; }
.avatar-large { display: flex; justify-content: center; margin-bottom: 12px; }
.avatar-large .avatar { width: 96px; height: 96px; }
.avatar-large span.avatar-initial { font-size: 2.5rem; }
.avatar-edit-row { display: flex; align-items: stretch; gap: 8px; }
.avatar-edit-row input { flex: 1; min-width: 0; }
/* The save button matches the input height exactly: stretch must be restated because
   the generic `form .button-secondary` rule pins align-self to flex-start. */
.avatar-edit-row .button-secondary { align-self: stretch; height: auto; }
/* The avatar preview opens full-size in the lightbox. */
.avatar-large img { cursor: pointer; }
/* Footer: store badges + social links. */
footer {
    max-width: 840px;
    margin: 24px auto 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}
.store-badges { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.store-badge {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 8px 16px;
    text-decoration: none;
}
.store-badge:hover { border-color: var(--accent); }
.store-badge { width: 170px; }
.store-badge.disabled { opacity: 0.45; cursor: default; }
.store-badge.disabled:hover { border-color: var(--border); }
.store-badge span { font-weight: 600; line-height: 1.2; }
.store-badge small { display: block; color: var(--hint); font-size: 0.7rem; font-weight: 400; }
/* Footer sits on the page gradient (not a surface card), so use the high-contrast --title
   with a soft shadow - --hint washed out on the light gold. */
.footer-links { display: flex; align-items: center; gap: 8px; color: var(--title); font-size: 0.85rem; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); }
.footer-links a { color: var(--title); }
.footer-links a:hover { color: var(--accent); }
.footer-credit { color: var(--title); font-size: 0.8rem; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45); }
.social-icons { display: flex; gap: 12px; }
.social-icons a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--surface);
    color: var(--hint);
    border: 1px solid var(--border);
}
.social-icons a:hover { color: var(--accent); border-color: var(--accent); }
/* Save/delete confirmation toast, bottom-center, auto-dismissed by script.js. Accent
   (orange) fill so it stands out from the surface-coloured blocks it floats over -
   identical to the tavakava hub's toast. */
.toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translate(-50%, 12px);
    background: var(--accent);
    color: var(--surface);
    border-radius: 8px;
    padding: 10px 20px;
    font-weight: 600;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: opacity 0.2s, transform 0.2s;
    pointer-events: none;
    z-index: 30;
}
.toast.visible { opacity: 1; transform: translate(-50%, 0); }
/* Same box size as .button-secondary (the border is swapped for padding) so primary and
   secondary buttons align side by side in .form-actions. */
.button-primary {
    background: var(--accent);
    color: var(--surface);
    border: none;
    border-radius: 8px;
    padding: 9px 15px;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
}
.button-secondary {
    background: none;
    color: var(--accent);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px 14px;
    font-family: inherit;
    font-size: 0.9rem;
    cursor: pointer;
}
.button-secondary:not(:disabled):hover { border-color: var(--accent); }
.button-secondary:disabled { opacity: 0.5; cursor: default; }
/* Inside a column form (sign-out) a secondary button keeps its natural width. */
form .button-secondary { align-self: flex-start; }
.error { color: var(--error); margin-bottom: 12px; }
.hint-note { color: var(--hint); font-size: 0.85rem; margin-top: 12px; }
/* A hint acting as a subtitle right under a heading hugs it (consistent small gap); in
   flex forms the form's own gap provides the spacing, so drop the heading's bottom margin. */
h2 + .hint-note, h3 + .hint-note { margin-top: 0; }
form h3 { margin-bottom: 0; }
.admin-tools { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
/* Backup / migration: give the native file input's button our button-secondary look. */
input[type="file"] { color: var(--hint); font-family: inherit; font-size: 0.9rem; }
input[type="file"]::file-selector-button {
    background: none;
    color: var(--accent);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px 14px;
    margin-right: 10px;
    font-family: inherit;
    font-size: 0.9rem;
    cursor: pointer;
}
input[type="file"]::file-selector-button:hover { border-color: var(--accent); }
/* Banner editor rows: small date above the title, title takes the free space and
   ellipsizes, icon action buttons keep their size. */
.admin-banner-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.admin-banner-row:last-of-type { border-bottom: none; }
.admin-banner-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.admin-banner-info .banner-date { font-size: 0.75rem; }
.admin-banner-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.button-secondary.danger { color: var(--error); }
/* Account rows (role management) share the banner-row anatomy; the stats line sits
   above the name like the banner date does. */
.admin-account-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.admin-account-row:last-of-type { border-bottom: none; }
/* The admin-issued password-reset link (SRV-1 fallback), full-width under its row. */
.reset-link-box { flex-basis: 100%; display: flex; flex-direction: column; gap: 4px; }
.reset-link {
    font-family: monospace;
    font-size: 0.8rem;
    color: var(--accent);
    word-break: break-all;
    user-select: all;
}
.account-stats { color: var(--hint); font-size: 0.75rem; }
/* The sign-in username under a custom display name - admins only see this list. */
.account-username { color: var(--hint); font-size: 0.75rem; }
.role-form select {
    appearance: none;
    -webkit-appearance: none;
    background: var(--surface) var(--chevron) no-repeat right 10px center;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    height: 32px;
    padding: 0 28px 0 10px;
    line-height: 1;
    font-family: inherit;
    font-size: 0.9rem;
    cursor: pointer;
    flex-shrink: 0;
}
.role-form select:focus { outline: none; border-color: var(--accent); }
/* Search + sort controls above paged lists. */
.list-controls { display: flex; gap: 8px; margin-bottom: 12px; }
.list-search {
    flex: 1;
    min-width: 0;
    background: none;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    height: 32px;
    padding: 0 10px;
    font-family: inherit;
    font-size: 0.9rem;
}
.list-search:focus { outline: none; border-color: var(--accent); }
.list-search::placeholder { color: var(--hint); }
.list-sort-label {
    display: flex;
    align-items: center;
    color: var(--hint);
    font-size: 0.9rem;
    white-space: nowrap;
    flex-shrink: 0;
}
.list-sort {
    appearance: none;
    -webkit-appearance: none;
    background: var(--surface) var(--chevron) no-repeat right 10px center;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 8px;
    height: 32px;
    padding: 0 28px 0 10px;
    font-family: inherit;
    font-size: 0.9rem;
    cursor: pointer;
    flex-shrink: 0;
}
.list-sort:focus { outline: none; }
/* Sortable table headers (tables + players): clickable, direction marker when active. */
th.sortable { cursor: pointer; white-space: nowrap; }
th.sortable:hover { color: var(--text); }
th.sorted-asc::after { content: "▴"; font-size: 0.7rem; margin-left: 2px; }
th.sorted-desc::after { content: "▾"; font-size: 0.7rem; margin-left: 2px; }
/* The edit link is an anchor styled as a button - align its text like one. */
a.button-secondary { text-decoration: none; display: inline-block; }

/* Account-ban notice (WEB-8 moderation). */
.ban-notice { max-width: 520px; margin: 24px auto 0; }
.ban-message {
    color: var(--text);
    border-left: 3px solid var(--error);
    padding: 4px 0 4px 14px;
    margin: 12px 0 0;
    white-space: pre-wrap;
    font-size: 1rem;
}
.icon-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    flex-shrink: 0;
}
a.icon-button { display: flex; }
/* Image lightbox - the only place alpha is allowed (dialog overlay, like in game). */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 10;
    background: rgba(0, 0, 0, 0.75);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 24px;
}
/* width/height (not max-*) + object-fit so small source images scale UP to fill the
   viewport instead of rendering at their natural size. */
.lightbox img { width: calc(100% - 136px); height: 92vh; object-fit: contain; }
.lightbox-arrow {
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    color: #ffffff;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 50%;
    width: 44px;
    height: 44px;
    padding: 0 0 3px; /* optical centering - the ‹ › glyphs sit slightly high */
    line-height: 1;
    font-size: 1.4rem;
    cursor: pointer;
    flex-shrink: 0;
}
.lightbox-arrow:disabled { opacity: 0.3; cursor: default; }
.lightbox-arrow:not(:disabled):hover { border-color: #ffffff; }
.lightbox-close {
    position: absolute;
    top: 12px;
    right: 20px;
    background: none;
    border: none;
    color: #ffffff;
    font-size: 2.2rem;
    cursor: pointer;
    line-height: 1;
}
table { width: 100%; border-collapse: collapse; }
th { text-align: left; color: var(--accent); font-weight: 600; }
th, td { padding: 6px 8px; border-bottom: 1px solid var(--border); }
tr:last-child td { border-bottom: none; }
.playing { color: var(--accent); }
.waiting { color: var(--hint); }
