/*
 * Willo — NamelessMC layer.
 *
 * Load order: base.css (Tebex framework) -> altara.css (design layer) -> this.
 * This file covers components NamelessMC has that the store theme does not:
 * forums, profiles, alerts, pagination, tables.
 *
 * HARD RULE: no literal colour, radius, border width, duration or size may
 * appear below. Reference tokens only. Every token is emitted by
 * template.php from template_settings/schema.php. If a value is needed that
 * has no token yet, add it to the schema first.
 */

/* ==========================================================================
   Derived tokens
   Composites built from the settings-driven primitives above.
   ========================================================================== */

:root {
    --cs-surface-raised: rgb(from var(--color-brighter-bg) calc(r + (255 - r) * 0.05) calc(g + (255 - g) * 0.05) calc(b + (255 - b) * 0.05));
    --cs-outline: var(--cs-border-width) solid var(--cs-border);
    --cs-tint-primary: rgb(from var(--color-primary) r g b / 0.12);
    --cs-tint-danger: rgb(from var(--color-removed) r g b / 0.12);
    --cs-tint-success: rgb(from var(--cs-success) r g b / 0.12);
    --cs-tint-info: rgb(from var(--cs-info) r g b / 0.12);
    --cs-radius-sm: calc(var(--cs-radius) * 0.5);
    --cs-radius-lg: calc(var(--cs-radius) * 1.25);
}

/* ==========================================================================
   Notices — NamelessMC session flashes, validation errors, global warnings
   ========================================================================== */

.notice {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--cs-col-gap);
    padding: var(--widget-padding);
    margin-bottom: var(--cs-col-gap);
    border: var(--cs-outline);
    border-radius: var(--cs-radius);
    background: var(--color-brighter-bg);
    color: var(--color-text);
}

.notice-success { border-color: var(--cs-success); background: var(--cs-tint-success); }
.notice-error   { border-color: var(--color-removed); background: var(--cs-tint-danger); }
.notice-info    { border-color: var(--cs-info); background: var(--cs-tint-info); }
.notice-warning { border-color: var(--color-primary); background: var(--cs-tint-primary); }

.notice [data-dismiss] {
    margin-inline-start: auto;
    border: 0;
    background: none;
    color: var(--color-text-secondary);
    cursor: pointer;
    line-height: 1;
}

.notice [data-dismiss]:hover { color: var(--color-text); }

/* ==========================================================================
   Pagination — markup comes from $template_pagination in template.php
   ========================================================================== */

.cs-pagination {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cs-col-gap);
    justify-content: center;
    margin-block: var(--widget-padding);
}

.cs-pagination-item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--btn-size);
    height: var(--btn-size);
    padding-inline: calc(var(--cs-col-gap) * 1.2);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-brighter-bg);
    color: var(--color-text-darker);
    text-decoration: none;
    transition: background var(--fade-duration), color var(--fade-duration), border-color var(--fade-duration);
}

.cs-pagination-item:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}

.cs-pagination-item.active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-primary-text);
}

/* ==========================================================================
   Avatars
   ========================================================================== */

.cs-avatar {
    display: inline-block;
    border-radius: var(--cs-avatar-radius);
    border: var(--cs-border-width) solid var(--cs-border);
    background: var(--color-bg);
    object-fit: cover;
    image-rendering: pixelated;
}

/* ==========================================================================
   Data tables — forum indexes, member lists, leaderboards
   ========================================================================== */

.cs-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border: var(--cs-outline);
    border-radius: var(--cs-radius);
    overflow: hidden;
    background: var(--color-brighter-bg);
}

.cs-table th,
.cs-table td {
    padding: calc(var(--widget-padding) * 0.75);
    text-align: start;
    border-bottom: var(--cs-border-width) solid var(--cs-border);
}

.cs-table thead th {
    background: var(--cs-surface-raised);
    color: var(--color-text-secondary);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
}

.cs-table tbody tr:last-child td { border-bottom: 0; }
.cs-table tbody tr:hover td { background: var(--cs-tint-primary); }

/*
 * Flush card: dissolves a table's own box so the rows become the card's
 * structure instead of a panel sitting inside it.
 *
 * .cs-table carries a border, a radius and the SAME background as .widget, so
 * nesting one in a card gives you border -> padding -> border again, with no
 * colour change to justify it. This strips the inner box, runs the separators
 * out to the card's edges, and re-pads the cells so their text still lines up
 * with the card's title. Goes on the .widget itself.
 */
.cs-card-flush .cs-table-wrap {
    margin-inline: calc(var(--widget-padding) * -1);
}

.cs-card-flush .cs-table {
    border: 0;
    border-radius: 0;
    background: none;
    overflow: visible;
}

.cs-card-flush .cs-table th,
.cs-card-flush .cs-table td {
    padding-inline: var(--widget-padding);
}

/* Column headings become labels sitting above the rows, not a toolbar strip.
   No top padding: the card's own padding already sets them off. */
.cs-card-flush .cs-table thead th {
    background: none;
    padding-block: 0 calc(var(--cs-col-gap) * 0.75);
    font-size: 12px;
}

/* The card's padding closes the list, so a trailing rule would just float. */
.cs-card-flush .cs-table tbody tr:last-child td { border-bottom: 0; }

/* Keeps the actions divider on the same edge-to-edge line as the separators. */
.cs-card-flush .cs-form-actions {
    margin-inline: calc(var(--widget-padding) * -1);
    padding-inline: var(--widget-padding);
}

/*
 * Sessions read as a dense device list rather than a grid of cells.
 *
 * The default table rhythm is built for wide data cells, which made every row
 * about 100px tall: a three-line stack plus a full-height button. Here each row
 * is one device and should read as one line, so the name, platform and badges
 * share a single wrapping row and the cells lose most of their vertical padding.
 */
.cs-session-table th,
.cs-session-table td {
    padding-block: calc(var(--cs-col-gap) * 0.8);
    vertical-align: middle;
}

.cs-session-device {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: calc(var(--cs-col-gap) * 0.6);
}

.cs-session-device .cs-muted { font-size: 13px; }
.cs-session-badges { display: inline-flex; flex-wrap: wrap; gap: 5px; }

/* Row height should come from its text, not from a full-size button. --btn-size
   drives both height and line-height, so scoping the token is enough. */
.cs-session-table .btn-tertiary { --btn-size: 32px; }

/* ==========================================================================
   Forms module — public form, UserCP submissions list and view
   ========================================================================== */

.cs-form-content { color: var(--color-text-secondary); }
.cs-form-note { margin: 0; color: var(--color-text-secondary); }

.cs-form-divider {
    margin: 0;
    border: 0;
    border-top: var(--cs-border-width) solid var(--cs-border);
}

.cs-input-file { padding-block: calc(var(--cs-col-gap) * 0.6); }
.cs-input-file::file-selector-button {
    margin-inline-end: var(--cs-col-gap);
    padding: calc(var(--cs-col-gap) * 0.5) var(--cs-col-gap);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-brighter-bg);
    color: var(--color-text);
    font: inherit;
    cursor: pointer;
}

.cs-submission-user {
    display: inline-flex;
    align-items: center;
    gap: calc(var(--cs-col-gap) * 0.6);
    font-weight: 600;
}
.cs-submission-user .cs-avatar { border-radius: var(--cs-radius-sm); }
.cs-submission-when { display: block; margin-top: 2px; font-size: 13px; }
.cs-submission-action { text-align: end; }
.cs-submission-table .btn-tertiary { --btn-size: 32px; }

.cs-submission-meta,
.cs-submission-author {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--cs-col-gap);
}
.cs-submission-meta {
    margin-bottom: var(--widget-padding);
    padding-bottom: var(--widget-padding);
    border-bottom: var(--cs-border-width) solid var(--cs-border);
}
.cs-submission-author { margin-bottom: var(--cs-col-gap); }

.cs-answer-list {
    display: flex;
    flex-direction: column;
    gap: var(--widget-padding);
    margin: var(--widget-padding) 0 0;
}
.cs-answer dt { margin-bottom: 4px; font-weight: 700; }
.cs-answer dd { margin: 0; color: var(--color-text-secondary); overflow-wrap: anywhere; }

.cs-comment-list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.cs-comment { padding-block: var(--widget-padding); border-top: var(--cs-border-width) solid var(--cs-border); }
.cs-comment:first-child { padding-top: 0; border-top: 0; }
.cs-comment-form { margin-top: var(--widget-padding); }

/* Session IP with its country flag (flag-icons, bundled in flags/4x3) */
.cs-session-ip {
    display: inline-flex;
    align-items: center;
    gap: calc(var(--cs-col-gap) * 0.6);
    white-space: nowrap;
}

.cs-flag {
    flex: none;
    width: 20px;
    height: 15px;
    object-fit: cover;
    border-radius: calc(var(--cs-radius-sm) * 0.3);
    box-shadow: 0 0 0 1px var(--cs-border);
}

/* ==========================================================================
   Account bar — icon pills sit left of the profile pill
   Extends .cs-account-pill from altara.css rather than redefining it.
   ========================================================================== */

.cs-icon {
    width: 20px;
    height: 20px;
    flex: none;
}

.cs-pill-menu { position: relative; }

/*
 * Icon button for inline SVGs. Deliberately NOT Tebex's .btn-icon, which sets
 * color:transparent and font-size:0 to hide a text label behind a background
 * image — that would also erase an inline currentColor SVG.
 */
.cs-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--btn-size);
    height: var(--btn-size);
    padding: 0;
    border: 0;
    border-radius: var(--cs-radius-sm);
    background: transparent;
    color: var(--color-text-darker);
    cursor: pointer;
    transition: color var(--fade-duration), background var(--fade-duration);
}

.cs-icon-btn:hover,
.cs-icon-btn:focus-visible {
    background: var(--cs-tint-primary);
    color: var(--color-text);
}

/*
 * Account bar — actions pill + profile pill.
 *
 * Mechanism lifted from the store theme's cart pill: the actions pill carries
 * the PRIMARY colour, is rounded on its left edge only, and is pulled under the
 * profile pill by a negative right margin. The profile pill sits on top
 * (z-index 2, opaque background), so the two read as one control whose left
 * section is coloured — not as separate pills.
 *
 * The original .cs-cart-pill rules were removed by the CSS prune, so the
 * geometry is restored here against the same tokens.
 */
.cs-actions-pill {
    display: flex;
    align-items: center;
    gap: calc(var(--cs-account-height) * 0.08);
    height: 100%;
    padding: 0 calc(var(--cs-account-height) * 1.1) 0 calc(var(--cs-account-height) * 0.42);
    background: var(--color-primary);
    color: var(--color-primary-text);
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: 999px 0 0 999px;
    margin-right: calc(var(--cs-account-height) * -0.95);
    position: relative;
    z-index: 1;
    transition: filter var(--fade-duration);
}

/* No profile pill following it (guest with only the mode toggle): round fully */
.cs-account-bar .cs-actions-pill:last-child {
    margin-right: 0;
    border-radius: 999px;
    padding-right: calc(var(--cs-account-height) * 0.5);
}

/*
 * Icons on the pill use --cs-on-accent, which is a single value shared by both
 * palettes (unlike --color-primary-text, which flips to black in dark mode).
 * The pill stays the primary colour in both modes, so its icons must too.
 * Change it under Colours → "Text on accent".
 */
.cs-cluster-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: calc(var(--cs-account-height) * 0.6);
    height: calc(var(--cs-account-height) * 0.6);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--cs-on-accent);
    cursor: pointer;
    transition: transform var(--fade-duration) ease;
}

/* Grow on hover rather than shifting background */
.cs-cluster-btn:hover,
.cs-cluster-btn:focus-visible,
.cs-cluster-btn[aria-expanded="true"] {
    background: transparent;
    transform: scale(1.18);
}

.cs-cluster-btn:active { transform: scale(1.05); }

@media (prefers-reduced-motion: reduce) {
    .cs-cluster-btn { transition: none; }
    .cs-cluster-btn:hover,
    .cs-cluster-btn:focus-visible,
    .cs-cluster-btn[aria-expanded="true"] { transform: none; opacity: .8; }
}

.cs-cluster-btn .cs-icon {
    width: calc(var(--cs-account-height) * 0.36);
    height: calc(var(--cs-account-height) * 0.36);
}

/* Dropdowns have to clear the overlapping profile pill */
.cs-actions-pill .cs-pill-menu { position: relative; }
.cs-actions-pill .cs-account-dropdown { z-index: 60; }

/* The unread badge inverts on the coloured pill so it stays legible */
.cs-actions-pill .cs-pill-count {
    top: 0;
    inset-inline-end: 0;
    background: var(--color-brighter-bg);
    color: var(--color-text);
    border: var(--cs-border-width) solid var(--color-primary);
}

/* Unread badge */
.cs-pill-count {
    position: absolute;
    top: calc(var(--cs-border-width) * -1);
    inset-inline-end: calc(var(--cs-border-width) * -1);
    min-width: 18px;
    height: 18px;
    padding-inline: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: var(--color-primary);
    color: var(--color-primary-text);
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

/* Dropdown internals — the shell comes from .cs-account-dropdown in altara.css */
.cs-dropdown-head {
    margin: 0 0 calc(var(--cs-col-gap) * 0.6);
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
}

.cs-dropdown-list {
    display: flex;
    flex-direction: column;
    max-height: 320px;
    overflow-y: auto;
}

.cs-dropdown-empty {
    padding-block: calc(var(--cs-col-gap) * 1.2);
    color: var(--color-text-secondary);
    text-align: center;
}

.cs-dropdown-divider {
    height: var(--cs-border-width);
    margin-block: calc(var(--cs-col-gap) * 0.6);
    background: var(--cs-border);
}

.cs-dropdown-foot {
    display: block;
    margin-top: calc(var(--cs-col-gap) * 0.6);
    padding-top: calc(var(--cs-col-gap) * 0.6);
    border-top: var(--cs-outline);
    color: var(--color-primary);
    text-align: center;
    text-decoration: none;
}

.cs-dropdown-foot:hover { color: var(--color-primary-hover); }

/* Mode toggle shares the icon-pill shape */
.cs-mode-toggle { cursor: pointer; }

/* ==========================================================================
   Layout modifiers driven by settings (body_class in schema.php)
   ========================================================================== */

/*
 * .site is a GRID above 960px (sidebar | content), so flipping the sidebar
 * means swapping the column track and reordering the items — flex-direction
 * has no effect here. Below 960px .site is a flex column and the sidebar
 * already follows the content, so no override is needed there.
 */
@media (width > 960px) {
    body.cs-sidebar-right .site {
        grid-template-columns: 1fr var(--sidebar-width);
    }

    body.cs-sidebar-right .store-sidebar { order: 2; }
    body.cs-sidebar-right .site-main { order: 1; }

    /* Padding is asymmetric in the default arrangement — mirror it */
    body.cs-sidebar-right .site-main { padding: 30px 25px 30px 45px; }
}

body.cs-heading-centre .cs-page-lead { text-align: center; }
body.cs-no-particles .cs-particles { display: none; }

/* ==========================================================================
   Page scaffolding
   ========================================================================== */

.cs-hidden { display: none !important; }
.cs-muted { color: var(--color-text-secondary); }

.site-content {
    width: 100%;
    max-width: var(--content-inner-width);
    margin-inline: auto;
    padding-inline: var(--widget-padding);
    padding-block-end: calc(var(--widget-padding) * 2);
}

/*
 * Single column. There is exactly one sidebar (the site menu), and everything
 * else — widgets, the UserCP menu — stacks underneath it there. The content
 * column therefore owns the full width of the right-hand side.
 */
.cs-layout {
    display: block;
    width: 100%;
}

.cs-main-col { min-width: 0; width: 100%; }

.cs-widgets { display: flex; flex-direction: column; gap: var(--widget-padding); min-width: 0; }

/* Widgets and the UserCP menu, stacked under the navigation in the sidebar */
.cs-sidebar-widgets {
    display: flex;
    flex-direction: column;
    gap: var(--cs-col-gap);
    margin-top: var(--cs-col-gap);
}

@media (width <= 960px) {
    /*
     * Below 960px altara.css turns .site from a grid into a flex column, but
     * base.css still gives it `align-items: start`. In a grid that is harmless;
     * in a flex column it shrinks every child to its content width, so the
     * sidebar dropped under the content stopped short of the right edge.
     */
    body .site { align-items: stretch; }

    /* Mobile drawer: dim the strip beside the panel (tapping it closes the
       menu) and hold the page still while the menu is open. */
    body.show-navigation .site-navigation { background: rgb(from var(--color-bg) r g b / 0.6); }
    html.cs-nav-open { overflow: hidden; }
}

.cs-usercp-menu { margin-top: var(--cs-col-gap); }

/*
 * Play Now / Discord cards — ICON ONLY.
 *
 * The title and subtitle keep altara.css's --cs-on-accent, which stays light in
 * both modes. Only the leading glyph gets its own paired token so it can go
 * dark in light mode. The chevron is treated as part of the text, not the icon.
 */
.cs-home-cards .info .cs-nav-icon,
.cs-footer-play .cs-footer-play-icon {
    color: var(--cs-card-fg);
}

/* Uploaded navigation icons */
.cs-menu-ico img {
    width: 20px;
    height: 20px;
    object-fit: contain;
    display: block;
}

/* Members filter bar (replaces its old sidebar) */
.cs-member-filters { display: flex; flex-direction: column; gap: var(--cs-col-gap); margin-bottom: var(--widget-padding); }
.cs-filter-row { display: flex; flex-wrap: wrap; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); }
.cs-filter-row .cs-tab { text-decoration: none; font-size: 13px; }

.cs-page-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cs-col-gap);
    align-items: flex-start;
    justify-content: space-between;
    margin-block: var(--widget-padding);
}

.cs-page-head .cs-page-lead,
.cs-page-head .cs-page-lead-xl { margin-bottom: 0; }
.cs-page-actions { display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); }
.cs-lead-text { color: var(--color-text-secondary); margin: 0; }
.cs-section-head { margin-block: var(--widget-padding) var(--cs-col-gap); }
.cs-subhead { margin-block: var(--widget-padding) var(--cs-col-gap); color: var(--color-text-secondary); font-size: 13px; text-transform: uppercase; letter-spacing: .05em; }
.cs-widget-foot { margin: var(--cs-col-gap) 0 0; color: var(--color-text-secondary); font-size: 13px; }
.cs-badge {
    display: inline-flex; align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--cs-tint-primary);
    color: var(--color-primary);
    font-size: 11px; font-weight: 700;
}
.cs-required { color: var(--color-removed); }

/*
 * Forum topic labels. NamelessMC's default label types (StaffCP -> Forums ->
 * Labels -> Label types) emit Bootstrap markup, e.g.
 * <span class="badge badge-success">Solved</span>, which nothing in the theme
 * styled — labels rendered as bare text. Same pill as .cs-badge, one tint per
 * type, all from theme tokens so they follow light/dark mode.
 */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--cs-surface-raised);
    color: var(--color-text-secondary);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.5;
    vertical-align: middle;
    white-space: nowrap;
}
.badge + .badge { margin-inline-start: 4px; }
.badge-primary,
.badge-warning { background: var(--cs-tint-primary); color: var(--color-primary); }
.badge-success { background: var(--cs-tint-success); color: var(--cs-success); }
.badge-info    { background: var(--cs-tint-info); color: var(--cs-info); }
.badge-danger  { background: var(--cs-tint-danger); color: var(--color-removed); }

/* ==========================================================================
   Forms
   ========================================================================== */

.cs-form { display: flex; flex-direction: column; gap: calc(var(--widget-padding) * 0.9); }
.cs-form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cs-col-gap);
    margin-top: calc(var(--widget-padding) * 0.6);
    padding-top: var(--widget-padding);
    border-top: var(--cs-border-width) solid var(--cs-border);
}
/* Visible to screen readers only — for labels the design carries visually
   through a card title, but that a field still needs programmatically. */
.cs-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.cs-field { display: flex; flex-direction: column; gap: calc(var(--cs-col-gap) * 0.7); }
.cs-field-label { font-weight: 600; }
.cs-field-help { color: var(--color-text-secondary); font-size: 12px; margin-top: 2px; }
/* Row, not the column .cs-field sets: e.g. Remember me left, Forgot password right */
.cs-field-inline { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--cs-col-gap); }
.cs-field-link { color: var(--color-primary); text-decoration: none; }
.cs-field-link:hover { color: var(--color-primary-hover); }

.cs-input,
select.cs-input,
textarea.cs-input {
    width: 100%;
    min-height: var(--btn-size);
    padding: calc(var(--cs-col-gap) * 0.8) calc(var(--cs-col-gap) * 1.2);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-bg);
    color: var(--color-text);
    font: inherit;
    transition: border-color var(--fade-duration);
}

.cs-input:focus { outline: none; border-color: var(--color-primary); }
.cs-input::placeholder { color: var(--color-text-secondary); }
textarea.cs-input { min-height: 8em; resize: vertical; }

.cs-radio-group { display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); }

.cs-check { display: inline-flex; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); cursor: pointer; }
.cs-check input { accent-color: var(--color-primary); width: 16px; height: 16px; }

.cs-divider {
    display: flex; align-items: center; gap: var(--cs-col-gap);
    margin-block: var(--widget-padding);
    color: var(--color-text-secondary); font-size: 13px;
}
.cs-divider::before, .cs-divider::after {
    content: ""; flex: 1 1 auto;
    height: var(--cs-border-width);
    background: var(--cs-border);
}

.cs-oauth { display: grid; gap: var(--cs-col-gap); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.cs-oauth-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--cs-col-gap); }
.cs-oauth-btn img { width: 18px; height: 18px; }
.cs-oauth-discord { background: var(--cs-discord); color: var(--cs-on-accent); }

.cs-login-wide { max-width: 720px; }

/*
 * Login + register: one field shape for every input type, matching the store
 * theme's login field (radius, padding, 16px text).
 *
 * Altara only styles `.cs-login .cs-input-wrap input[type=text]`, so email and
 * password inputs fell through to base.css's store-form rules (different
 * padding, 12px bottom margin, no icon indent), and register's .cs-input fields
 * used the smaller --cs-radius-sm. The :not() chain lifts this above base.css's
 * `.store-form input[type=...]` and `select.cs-input` rules without !important.
 * background-color, not background, so a select keeps its arrow image.
 */
.store-form .cs-login .cs-field input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]),
.store-form .cs-login .cs-field select,
.store-form .cs-login .cs-field textarea {
    display: block;
    width: 100%;
    height: auto;
    min-height: 0;
    margin: 0;
    padding: 13px 14px;
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: var(--cs-radius);
    background-color: var(--color-bg);
    color: var(--color-text);
    font: inherit;
    font-size: 16px;
    line-height: 1.25;
    transition: border-color var(--fade-duration);
}

.store-form .cs-login .cs-field input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]):focus,
.store-form .cs-login .cs-field select:focus,
.store-form .cs-login .cs-field textarea:focus {
    outline: none;
    border-color: var(--color-primary);
}

.store-form .cs-login .cs-field input::placeholder,
.store-form .cs-login .cs-field textarea::placeholder { color: var(--color-text-secondary); }

/* Text starts after the icon — same specificity as the shape rule, later in the file. */
.store-form .cs-login .cs-field .cs-input-wrap:has(> .cs-input-icon) input:not([type=checkbox]):not([type=radio]):not([type=hidden]) {
    padding-inline-start: 42px;
}

/* Altara pins the icon with a physical `left`; reset it, then use the logical side so RTL works. */
.cs-login .cs-input-wrap .cs-input-icon { left: auto; inset-inline-start: 14px; }
.cs-login .cs-input-wrap:focus-within .cs-input-icon { color: var(--color-primary); }

/*
 * Autofill. Browsers paint saved-credential fields with a light background; the
 * inset box-shadow in altara.css covers it, but the background still shows
 * through the anti-aliased inner edge of rounded corners as light specks in
 * dark mode. A huge transition delay stops that background ever being painted.
 * The login rule repeats the field selector chain because that rule sets its
 * own transition at higher specificity and would otherwise cancel this one.
 */
.cs-input:-webkit-autofill,
.store-form input:-webkit-autofill,
.store-form .cs-login .cs-field input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=submit]):-webkit-autofill {
    -webkit-text-fill-color: var(--color-text);
    -webkit-box-shadow: 0 0 0 1000px var(--color-bg) inset;
    box-shadow: 0 0 0 1000px var(--color-bg) inset;
    caret-color: var(--color-text);
    transition: border-color var(--fade-duration), background-color 600000s 0s, color 600000s 0s;
}

/*
 * Auth modal. Log in / register open in the store theme's popup shell — the
 * .popup / .popup-content / .popup-close rules in base.css and altara.css —
 * holding the same .cs-login panel the full pages render.
 */
html.cs-modal-open { overflow: hidden; }
html.cs-auth-loading,
html.cs-auth-loading a[data-cs-auth] { cursor: progress; }

.cs-auth-popup-content {
    max-width: 460px;
    padding: calc(var(--widget-padding) * 1.5);
}
.cs-auth-popup-content.cs-auth-wide { max-width: 760px; }
.cs-auth-popup .cs-login { max-width: none; margin: 0; }
.cs-auth-popup .cs-login-title { padding-inline-end: 40px; }
.cs-auth-popup .popup-close { z-index: 2; }

.cs-auth-popup-content[aria-busy=true] .cs-auth-body {
    opacity: 0.6;
    pointer-events: none;
    transition: opacity var(--fade-duration) ease;
}

/* ==========================================================================
   Vertical menus (UserCP, member lists)
   ========================================================================== */

.cs-vertical-menu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.cs-vertical-menu a {
    display: block;
    padding: calc(var(--cs-col-gap) * 0.9) calc(var(--cs-col-gap) * 1.2);
    border-radius: var(--cs-radius-sm);
    color: var(--color-text-darker);
    text-decoration: none;
    transition: background var(--fade-duration), color var(--fade-duration);
}
.cs-vertical-menu a:hover { background: var(--cs-tint-primary); color: var(--color-text); }
.cs-vertical-menu a.active { background: var(--color-primary); color: var(--color-primary-text); }

/* ==========================================================================
   Tabs
   ========================================================================== */

.cs-tabs { display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); margin-block: var(--widget-padding); }
.cs-tab {
    padding: calc(var(--cs-col-gap) * 0.8) calc(var(--cs-col-gap) * 1.6);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-brighter-bg);
    color: var(--color-text-darker);
    cursor: pointer;
    transition: border-color var(--fade-duration), color var(--fade-duration), background var(--fade-duration);
}
.cs-tab:hover { border-color: var(--color-primary); color: var(--color-text); }
.cs-tab.active { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-primary-text); }

/* ==========================================================================
   Forum
   ========================================================================== */

.cs-forum-list, .cs-topic-list, .cs-message-list, .cs-alert-list, .cs-feed-list,
.cs-member-grid, .cs-user-chips, .cs-reaction-list, .cs-leaderboard {
    list-style: none; margin: 0; padding: 0;
}

.cs-forum-row, .cs-topic, .cs-message-row {
    display: grid;
    gap: var(--cs-col-gap);
    align-items: center;
    padding-block: var(--cs-col-gap);
    border-bottom: var(--cs-border-width) solid var(--cs-border);
    grid-template-columns: auto minmax(0, 1fr);
}

@media (min-width: 800px) {
    .cs-forum-row { grid-template-columns: auto minmax(0, 1fr) auto auto; }
    .cs-topic, .cs-message-row { grid-template-columns: auto minmax(0, 1fr) auto auto; }
}

.cs-forum-row:last-child, .cs-topic:last-child, .cs-message-row:last-child { border-bottom: 0; }

.cs-forum-icon { display: inline-flex; color: var(--color-primary); }
.cs-forum-title, .cs-topic-title { margin: 0; font-size: 16px; }
.cs-forum-title a, .cs-topic-title a { color: var(--color-text); text-decoration: none; }
.cs-forum-title a:hover, .cs-topic-title a:hover { color: var(--color-primary); }
.cs-forum-desc { margin: 2px 0 0; color: var(--color-text-secondary); font-size: 13px; }
.cs-forum-children { display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); margin: var(--cs-col-gap) 0 0; font-size: 13px; }

.cs-forum-stats, .cs-topic-stats { display: flex; gap: var(--widget-padding); color: var(--color-text-secondary); font-size: 13px; }
.cs-forum-stats strong, .cs-topic-stats strong { display: block; color: var(--color-text); }

.cs-forum-last, .cs-topic-last, .cs-message-last {
    display: flex; align-items: center; gap: var(--cs-col-gap);
    color: var(--color-text-secondary); font-size: 13px;
}
.cs-topic-meta, .cs-post-meta { margin: 2px 0 0; color: var(--color-text-secondary); font-size: 13px; display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); }
.cs-topic-when { display: block; }

/*
 * Forum and topic rows (forum index, subforums, and topic lists on a forum page).
 *
 *   [icon] Name                ....   12 Topics   [avatar] Latest topic title…
 *          Short description           48 Posts            2 hours ago · User…
 *
 * The stats and last-post columns have FIXED widths, so they line up from row
 * to row whatever the names are, and each last-post line is one line cut with
 * an ellipsis instead of wrapping. Sized against the list's own width (a
 * container query), because the sidebar changes how much room the column has.
 * Declared after the shared :is(.cs-forum-row, .cs-topic-row) / .cs-topic grid above, so these win.
 */
.cs-forum-list,
.cs-topic-list { container-type: inline-size; }

:is(.cs-forum-row, .cs-topic-row) {
    --cs-forum-icon-size: 46px;
    --cs-forum-avatar-size: 42px;
    grid-template-columns: var(--cs-forum-icon-size) minmax(0, 1fr);
    column-gap: var(--widget-padding);
    row-gap: calc(var(--cs-col-gap) * 0.8);
    padding-block: calc(var(--widget-padding) * 0.75);
}

:is(.cs-forum-row, .cs-topic-row) > .cs-forum-icon {
    display: grid;
    place-items: center;
    width: var(--cs-forum-icon-size);
    height: var(--cs-forum-icon-size);
    font-size: 30px;
    line-height: 1;
}
:is(.cs-forum-row, .cs-topic-row) > .cs-forum-icon svg,
:is(.cs-forum-row, .cs-topic-row) > .cs-forum-icon img { width: 32px; height: 32px; object-fit: contain; }

:is(.cs-forum-row, .cs-topic-row) > .cs-forum-main { min-width: 0; }
:is(.cs-forum-row, .cs-topic-row) .cs-forum-title { line-height: 1.35; }
:is(.cs-forum-row, .cs-topic-row) .cs-forum-desc { line-height: 1.45; }

/* Narrow: stats and last post drop under the name, aligned with its text */
:is(.cs-forum-row, .cs-topic-row) > .cs-forum-stats,
:is(.cs-forum-row, .cs-topic-row) > .cs-forum-last { grid-column: 2; }

:is(.cs-forum-row, .cs-topic-row) > .cs-forum-stats { display: flex; flex-wrap: wrap; gap: 2px var(--widget-padding); }
.cs-forum-stat { display: flex; align-items: baseline; gap: 6px; white-space: nowrap; }
:is(.cs-forum-row, .cs-topic-row) .cs-forum-stat strong {
    display: inline-block;
    min-width: 3ch;
    text-align: end;
    font-variant-numeric: tabular-nums;
}

:is(.cs-forum-row, .cs-topic-row) > .cs-forum-last {
    display: grid;
    grid-template-columns: var(--cs-forum-avatar-size) minmax(0, 1fr);
    align-items: center;
    column-gap: var(--cs-col-gap);
    min-width: 0;
}
:is(.cs-forum-row, .cs-topic-row) > .cs-forum-last:empty { display: none; }

.cs-forum-last-avatar {
    width: var(--cs-forum-avatar-size);
    height: var(--cs-forum-avatar-size);
    border-radius: var(--cs-avatar-radius);
    object-fit: cover;
}
.cs-forum-last-lines { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cs-forum-last-line {
    display: block;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.cs-forum-last-topic { color: var(--color-text); font-size: 14px; font-weight: 600; text-decoration: none; }
.cs-forum-last-topic:hover { color: var(--color-primary); }
.cs-forum-last-meta { color: var(--color-text-secondary); font-size: 12px; }
.cs-forum-last-meta a { text-decoration: none; }

/* Wide: fixed stats and last-post columns on the right */
@container (min-width: 640px) {
    :is(.cs-forum-row, .cs-topic-row) { grid-template-columns: var(--cs-forum-icon-size) minmax(0, 1fr) 7.5rem 15rem; }

    :is(.cs-forum-row, .cs-topic-row) > .cs-forum-stats,
    :is(.cs-forum-row, .cs-topic-row) > .cs-forum-last { grid-column: auto; }

    :is(.cs-forum-row, .cs-topic-row) > .cs-forum-stats { display: grid; gap: 2px; }
    :is(.cs-forum-row, .cs-topic-row) > .cs-forum-last:empty { display: block; }
}

/*
 * Topic rows share the columns above. No background on pinned topics any more:
 * the state icon marks them, and a tinted lone row looked like a stray block.
 */
.cs-topic-row > .cs-topic-main { min-width: 0; }
.cs-topic-row .cs-topic-title { line-height: 1.35; }
.cs-topic-row .cs-topic-title .badge { margin-inline-end: 4px; }
.cs-topic-row > .cs-topic-state svg { width: 26px; height: 26px; }
.cs-topic-row.is-locked > .cs-topic-state { color: var(--color-text-secondary); }

/* Inline forum search (replaces the link to a search-bar-only page) */
.cs-forum-search {
    display: flex;
    align-items: stretch;
    gap: calc(var(--cs-col-gap) * 0.8);
    flex: 1 1 18rem;
    max-width: 26rem;
    margin: 0;
}
.cs-forum-search .cs-input-wrap { flex: 1 1 auto; min-width: 0; }
/* Same height and corners as the buttons beside it (--btn-size, --cs-radius).
   appearance: none stops the native search field ignoring the set height. */
.cs-forum-search .cs-input {
    height: var(--btn-size);
    min-height: 0;
    border-radius: var(--cs-radius);
    -webkit-appearance: none;
    appearance: none;
}
.cs-forum-search .btn-primary { flex: none; }

@media (width <= 600px) {
    .cs-forum-search { flex-basis: 100%; max-width: none; }
}

/* Posts */
.cs-post-list { display: flex; flex-direction: column; gap: var(--widget-padding); }
/* The flex gap already spaces the cards; base.css's .widget + .widget margin
   was adding a second gap on top of it. */
.cs-post-list > .widget + .widget { margin-top: 0; }

.cs-forum-post { display: grid; grid-template-columns: 1fr; gap: var(--widget-padding); }
@media (min-width: 760px) { .cs-forum-post { grid-template-columns: 180px minmax(0, 1fr); } }

.cs-post-author-col {
    display: flex; flex-direction: column; align-items: center; gap: calc(var(--cs-col-gap) * 0.6);
    text-align: center;
    padding-inline-end: var(--widget-padding);
    border-inline-end: var(--cs-border-width) solid var(--cs-border);
}
@media (max-width: 759px) {
    .cs-post-author-col { flex-direction: row; flex-wrap: wrap; border-inline-end: 0; border-bottom: var(--cs-border-width) solid var(--cs-border); padding-bottom: var(--cs-col-gap); }
}

.cs-post-avatar { width: 72px; height: 72px; }
.cs-post-username { font-weight: 700; text-decoration: none; }
.cs-post-user-title { margin: 0; font-size: 12px; color: var(--color-text-secondary); }
.cs-post-groups { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.cs-post-stats, .cs-post-fields, .cs-stat-list, .cs-detail-list { margin: 0; width: 100%; font-size: 12px; }
.cs-post-stats > div, .cs-post-fields > div, .cs-stat-list > div, .cs-detail-list > div {
    display: flex; justify-content: space-between; gap: var(--cs-col-gap);
    padding-block: 3px;
}
.cs-post-stats dt, .cs-post-fields dt, .cs-stat-list dt, .cs-detail-list dt { color: var(--color-text-secondary); margin: 0; }
.cs-post-stats dd, .cs-post-fields dd, .cs-stat-list dd, .cs-detail-list dd { margin: 0; font-weight: 600; }

.cs-post-header { display: flex; justify-content: space-between; gap: var(--cs-col-gap); margin-bottom: var(--cs-col-gap); font-size: 13px; }
.cs-post-date { color: var(--color-text-secondary); text-decoration: none; }
.cs-post-seen { color: var(--color-text-secondary); }
.cs-post-content { overflow-wrap: anywhere; }
.cs-post-content img { max-width: 100%; height: auto; }
.cs-post-edited { margin: var(--cs-col-gap) 0 0; font-size: 12px; color: var(--color-text-secondary); }
.cs-post-signature { margin-top: var(--widget-padding); padding-top: var(--cs-col-gap); border-top: var(--cs-border-width) solid var(--cs-border); font-size: 13px; color: var(--color-text-secondary); }
.cs-post-footer { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--cs-col-gap); margin-top: var(--widget-padding); }

/* ==========================================================================
   Topic page — one card: the opening post on top, replies as a comment
   thread beneath it, and the reply box closing the thread.
   ========================================================================== */

.cs-thread-card { padding: calc(var(--widget-padding) * 1.25); }

.cs-thread-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    column-gap: var(--widget-padding);
}
.cs-thread-head.has-avatar { grid-template-columns: 56px minmax(0, 1fr); }

.cs-thread-avatar { position: relative; align-self: start; }
.cs-thread-avatar img {
    display: block;
    width: 56px;
    height: 56px;
    border-radius: var(--cs-avatar-radius);
}

.cs-thread-main { min-width: 0; }
.cs-thread-title { margin: 0 0 6px; font-size: clamp(1.35rem, 1.1rem + 1vw, 1.75rem); line-height: 1.25; }

.cs-thread-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 6px;
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 13px;
}
.cs-thread-meta a { text-decoration: none; }

/* Top row: labels left, follow / moderation / share right */
.cs-thread-top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--cs-col-gap);
    margin-bottom: var(--cs-col-gap);
}
.cs-thread-top .cs-topic-labels { margin-bottom: 0; }

.cs-thread-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: calc(var(--cs-col-gap) * 0.8);
    margin-inline-start: auto;
}
.cs-thread-actions .cs-share { gap: 6px; margin: 0; }

/* The dashed divider now closes the title block, above the post body */
.cs-thread-card .cs-thread-meta {
    padding-bottom: var(--cs-col-gap);
    margin-bottom: var(--widget-padding);
    border-bottom: var(--cs-border-width) dashed var(--cs-border);
}

/* Share buttons in their platform's own colours */
.cs-share-btn { color: var(--cs-brand-on); }
.cs-share-x { background: var(--cs-brand-x); box-shadow: inset 0 0 0 var(--cs-border-width) var(--cs-border); }
.cs-share-facebook { background: var(--cs-brand-facebook); }
.cs-share-btn:is(:hover, :focus-visible) { color: var(--cs-brand-on); filter: brightness(1.18); }
.cs-share-x:is(:hover, :focus-visible) { background: var(--cs-brand-x); }
.cs-share-facebook:is(:hover, :focus-visible) { background: var(--cs-brand-facebook); }

.cs-thread-body { font-size: 15px; line-height: 1.65; }

.cs-thread-count {
    margin: calc(var(--widget-padding) * 1.5) 0 var(--widget-padding);
    font-size: 15px;
    font-weight: 700;
}

/* Thread: each reply's avatar sits in the gutter beside its bubble */
.cs-thread { position: relative; padding-inline-start: 56px; }

.cs-comment { position: relative; }
.cs-comment + .cs-comment { margin-top: calc(var(--cs-col-gap) * 1.4); }

.cs-comment-avatar { position: absolute; inset-inline-start: -56px; top: 4px; }
.cs-comment-avatar img {
    display: block;
    width: 40px;
    height: 40px;
    border-radius: var(--cs-avatar-radius);
    box-shadow: 0 0 0 4px var(--color-brighter-bg);
}

.cs-online-dot {
    position: absolute;
    right: -3px;
    bottom: -3px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--cs-success);
    box-shadow: 0 0 0 3px var(--color-brighter-bg);
}

.cs-bubble {
    min-width: 0;
    padding: 12px 16px 10px;
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-bg);
}

.cs-bubble-who {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    margin-bottom: 4px;
    font-size: 13px;
}
.cs-bubble-who .cs-post-username { font-size: 14px; }
.cs-bubble-when { color: var(--color-text-secondary); text-decoration: none; }
.cs-bubble-user-title { color: var(--color-text-secondary); font-size: 12px; }
.cs-bubble .cs-post-content { font-size: 14px; line-height: 1.6; }

.cs-thread-card .cs-post-footer { align-items: center; margin-top: 10px; }
.cs-thread-card .cs-post-signature { margin-top: var(--cs-col-gap); }

/* Inside a bubble the trays and chips sit one shade up, or they vanish into it */
.cs-bubble .cs-reaction { background: var(--color-brighter-bg); }
.cs-bubble .cs-reaction-picker:is(:hover, :focus-within, .is-open),
.cs-bubble .cs-action-menu:is(:hover, :focus-within, .is-open) { background: var(--color-brighter-bg); }

.cs-comment-composer .cs-bubble { padding: var(--cs-col-gap); }
.cs-composer-locked { margin: 0; color: var(--color-text-secondary); }

@media (max-width: 560px) {
    .cs-thread-card { padding: var(--widget-padding); }
    .cs-thread-head.has-avatar { grid-template-columns: 44px minmax(0, 1fr); }
    .cs-thread-avatar img { width: 44px; height: 44px; }
    .cs-thread { padding-inline-start: 46px; }
    .cs-comment-avatar { inset-inline-start: -46px; }
    .cs-comment-avatar img { width: 32px; height: 32px; }
}

/* Post actions behind one "more" button, fanning out to its left */
.cs-action-menu {
    display: inline-flex;
    flex-direction: row-reverse;
    align-items: center;
    margin-inline-start: auto;
    padding: 2px;
    border: var(--cs-border-width) solid transparent;
    border-radius: 999px;
    transition: background-color var(--fade-duration) ease, border-color var(--fade-duration) ease;
}
.cs-action-menu .cs-icon-btn { flex: none; width: 34px; height: 34px; border-radius: 999px; }
.cs-action-menu .cs-action {
    width: 0;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
    transition: width var(--fade-duration) ease, opacity var(--fade-duration) ease;
}
.cs-action-menu:is(:hover, :focus-within, .is-open) {
    background: var(--color-bg);
    border-color: var(--cs-border);
}
.cs-action-menu:is(:hover, :focus-within, .is-open) .cs-action {
    width: 34px;
    opacity: 1;
    pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
    .cs-action-menu,
    .cs-action-menu .cs-action { transition: none; }
}

/* Post content typography, and quotes that read as quotes */
.cs-post-content > :first-child { margin-top: 0; }
.cs-post-content > :last-child { margin-bottom: 0; }
.cs-post-content p { margin: 0 0 .75em; }
.cs-post-content ul,
.cs-post-content ol { margin: 0 0 .75em; padding-inline-start: 1.4em; }
.cs-post-content h1,
.cs-post-content h2,
.cs-post-content h3,
.cs-post-content h4 { margin: 1em 0 .45em; line-height: 1.3; }

/* core's quote() inserts <blockquote><a href="post">Author:</a><br>content</blockquote> */
.cs-post-content blockquote {
    margin: 0 0 .85em;
    padding: 10px 14px;
    border-inline-start: 3px solid var(--color-primary);
    border-radius: var(--cs-radius-sm);
    background: var(--cs-tint-primary);
    color: var(--color-text);
}
.cs-post-content blockquote > a:first-child {
    display: block;
    margin-bottom: 2px;
    color: var(--color-primary);
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
}
.cs-post-content blockquote > a:first-child + br { display: none; }
.cs-post-content blockquote blockquote { background: rgb(from var(--color-bg) r g b / 0.4); }

.cs-post-content pre {
    margin: 0 0 .85em;
    padding: 12px 14px;
    overflow: auto;
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-brighter-bg);
    font-size: 13px;
}
.cs-post-content :not(pre) > code {
    padding: 1px 6px;
    border-radius: 6px;
    background: var(--cs-tint-primary);
    font-size: .92em;
}
.cs-post-content table { width: 100%; margin: 0 0 .85em; border-collapse: collapse; font-size: 13px; }
.cs-post-content th,
.cs-post-content td { padding: 6px 10px; border: var(--cs-border-width) solid var(--cs-border); text-align: start; }
.cs-post-content hr { margin: 1em 0; border: 0; border-top: var(--cs-border-width) solid var(--cs-border); }

/* Topic toolbar, outside the card: back to the forum on the left, follow /
   moderation / share on the right */
.cs-thread-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--cs-col-gap);
    margin-bottom: var(--widget-padding);
}
.cs-thread-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    color: var(--color-text-secondary);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
}
.cs-thread-back:hover { color: var(--color-primary); }

/* Breadcrumb trail (forum and topic pages), above everything else */
.cs-breadcrumbs { margin-top: var(--widget-padding); font-size: 13px; }
.cs-breadcrumbs ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}
.cs-breadcrumbs li { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.cs-breadcrumbs a { color: var(--color-text-secondary); font-weight: 600; text-decoration: none; }
.cs-breadcrumbs a:hover { color: var(--color-primary); }
.cs-breadcrumb-sep { display: inline-flex; color: var(--color-text-secondary); opacity: .6; }
.cs-breadcrumb-sep .cs-icon { width: 14px; height: 14px; }
[dir=rtl] .cs-breadcrumb-sep .cs-icon { transform: scaleX(-1); }
.cs-breadcrumb-current {
    max-width: 40ch;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--color-text);
    font-weight: 600;
}
.cs-breadcrumbs + .cs-page-head,
.cs-breadcrumbs + .cs-thread-toolbar { margin-top: calc(var(--cs-col-gap) * 1.2); }

/* Forum page head: title left, search + new topic on the same row, right */
.cs-forum-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
}
.cs-forum-head-text { min-width: 0; }
.cs-forum-head .cs-page-actions { flex-wrap: nowrap; justify-content: flex-end; }
.cs-forum-head .cs-forum-search { flex: 0 1 18rem; }

@media (width <= 760px) {
    .cs-forum-head { grid-template-columns: minmax(0, 1fr); }
    .cs-forum-head .cs-page-actions { flex-wrap: wrap; justify-content: flex-start; }
    .cs-forum-head .cs-forum-search { flex: 1 1 100%; max-width: none; }
}
.cs-thread-back .cs-icon { width: 16px; height: 16px; transform: scaleX(-1); }

/* ==========================================================================
   Forum index and forum pages — grouped, collapsible category blocks
   ========================================================================== */

.cs-cat { padding: 0; overflow: hidden; }

.cs-cat-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--cs-col-gap);
    padding: 12px var(--widget-padding);
    /* Only slightly darker at the bottom (88% of the primary, vs 73% for --cs-primary-deep).
       Text uses --cs-on-accent, which stays light in both modes because this bar
       is the primary colour in both. */
    --cs-cat-head-end: rgb(from var(--color-primary) calc(r * 0.88) calc(g * 0.88) calc(b * 0.88));
    background: linear-gradient(180deg, var(--color-primary) 0%, var(--cs-cat-head-end) 100%);
    color: var(--cs-on-accent);
    cursor: pointer;
    user-select: none;
}
.cs-cat-title { margin: 0; font-size: 15px; font-weight: 800; letter-spacing: .4px; text-transform: uppercase; }
.cs-cat-title a { color: inherit; text-decoration: none; }

.cs-cat-stack { display: inline-flex; }
.cs-cat-stack img {
    width: 26px;
    height: 26px;
    margin-inline-start: -8px;
    border: 2px solid var(--cs-cat-head-end);
    border-radius: var(--cs-avatar-radius);
    background: var(--color-bg);
    object-fit: cover;
}
.cs-cat-stack img:first-child { margin-inline-start: 0; }

.cs-cat-stats { display: flex; flex-wrap: wrap; gap: 6px; margin-inline-start: auto; }
.cs-cat-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgb(from var(--cs-on-accent) r g b / 0.16);
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}
.cs-cat-pill .cs-icon { width: 14px; height: 14px; }

.cs-cat-toggle {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: var(--cs-radius-sm);
    background: rgb(from var(--cs-on-accent) r g b / 0.16);
    color: inherit;
    cursor: pointer;
    transition: transform var(--fade-duration) ease;
}
.cs-cat-toggle .cs-icon { width: 16px; height: 16px; }
.cs-cat.is-collapsed .cs-cat-toggle { transform: rotate(-90deg); }
.cs-cat.is-collapsed .cs-cat-body { display: none; }

.cs-cat-body { padding-inline: var(--widget-padding); }
.cs-cat-body > .cs-empty-state { padding-block: calc(var(--widget-padding) * 1.5); }

/* A text button with an arrow after the label (home page "Forum") */
.cs-btn-arrow { display: inline-flex; align-items: center; gap: 6px; }
.cs-btn-arrow .cs-icon { width: 16px; height: 16px; transition: transform var(--fade-duration) ease; }
.cs-btn-arrow:hover .cs-icon,
.cs-btn-arrow:focus-visible .cs-icon { transform: translateX(3px); }

/* ------------------------------------------------------------------ Blog
   The blog category's own layouts (template.php finds it by name): an index
   of post cards and an article page. */
.cs-blog-cats { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: calc(var(--cs-col-gap) * 1.6); }
.cs-blog-cat {
    padding: 6px 14px;
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: 999px;
    background: var(--color-brighter-bg);
    color: var(--color-text);
    font-size: 13px;
    font-weight: 700;
    text-decoration: none;
    transition: border-color var(--fade-duration) ease, color var(--fade-duration) ease;
}
.cs-blog-cat:hover { border-color: var(--color-primary); color: var(--color-primary); }

/* Two posts per row at most; one on phones */
.cs-blog-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: calc(var(--cs-col-gap) * 1.6);
}
@media (width <= 720px) {
    .cs-blog-grid { grid-template-columns: minmax(0, 1fr); }
}
.cs-blog-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    transition: transform var(--fade-duration) ease, border-color var(--fade-duration) ease;
}
.cs-blog-card:hover { transform: translateY(-3px); border-color: rgb(from var(--color-primary) r g b / 0.5); }

.cs-blog-cover {
    position: relative;
    display: block;
    max-width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: linear-gradient(135deg, var(--cs-tint-primary), rgb(from var(--color-primary) r g b / 0.3));
}
.cs-blog-cover img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform calc(var(--fade-duration) * 2.5) ease; }
.cs-blog-card:hover .cs-blog-cover img { transform: scale(1.04); }
.cs-blog-cover-fallback { display: grid; place-items: center; width: 100%; height: 100%; color: var(--color-primary); }
.cs-blog-cover-fallback .cs-icon { width: 42px; height: 42px; opacity: 0.75; }
.cs-blog-pin {
    position: absolute;
    top: 10px;
    inset-inline-start: 10px;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--color-primary);
    color: var(--color-primary-text);
}
.cs-blog-pin .cs-icon { width: 15px; height: 15px; }

.cs-blog-card-body { display: flex; flex: 1; flex-direction: column; gap: 8px; min-width: 0; padding: var(--widget-padding); }
.cs-blog-card-body .cs-node-labels { margin-bottom: 0; }
.cs-blog-card-title { margin: 0; font-size: 18px; line-height: 1.3; overflow-wrap: anywhere; }
.cs-blog-card-title a { color: var(--color-text); text-decoration: none; }
.cs-blog-card-title a:hover { color: var(--color-primary); }
.cs-blog-excerpt {
    display: -webkit-box;
    margin: 0;
    overflow: hidden;
    color: var(--color-text-secondary);
    font-size: 14px;
    line-height: 1.55;
    overflow-wrap: anywhere;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
}

.cs-blog-byline { display: flex; align-items: center; gap: 10px; min-width: 0; margin-top: auto; padding-top: 6px; }
.cs-blog-byline img { flex: none; width: 36px; height: 36px; border-radius: var(--cs-avatar-radius); object-fit: cover; }
.cs-blog-byline-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: 13px; }
.cs-blog-byline-name { overflow: hidden; font-weight: 700; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; }
.cs-blog-byline-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin: 0; color: var(--color-text-secondary); font-size: 12px; }
.cs-blog-byline-meta a { color: inherit; text-decoration: none; }
.cs-blog-byline-meta a:hover { color: var(--color-primary); }
.cs-blog-count { display: inline-flex; align-items: center; gap: 4px; }
.cs-blog-count .cs-icon { width: 13px; height: 13px; }

/* The newest post on page 1 spans the row, with its cover beside the text */
@media (width > 960px) {
    .cs-blog-card.is-featured { grid-column: 1 / -1; flex-direction: row; }
    .cs-blog-card.is-featured .cs-blog-cover { flex: 0 0 55%; min-height: 300px; aspect-ratio: auto; }
    .cs-blog-card.is-featured .cs-blog-card-body { justify-content: center; padding: calc(var(--widget-padding) * 1.5); }
    .cs-blog-card.is-featured .cs-blog-card-title { font-size: clamp(1.35rem, 1rem + 1vw, 1.8rem); }
    .cs-blog-card.is-featured .cs-blog-excerpt { -webkit-line-clamp: 5; line-clamp: 5; }
    .cs-blog-card.is-featured .cs-blog-byline { margin-top: 8px; }
}

/* Article */
.cs-blog-article { padding: 0; overflow: hidden; }
.cs-blog-article-head {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: calc(var(--widget-padding) * 1.5) calc(var(--widget-padding) * 1.5) var(--widget-padding);
    border-bottom: var(--cs-border-width) solid var(--cs-border);
    background: linear-gradient(180deg, var(--cs-tint-primary), transparent);
}
.cs-blog-article-head .cs-topic-labels { margin: 0; }
.cs-blog-article-title { margin: 0; font-size: clamp(1.6rem, 1.15rem + 1.6vw, 2.4rem); line-height: 1.15; overflow-wrap: anywhere; }
.cs-blog-article-head .cs-blog-byline { margin-top: 0; padding-top: 0; }
.cs-blog-article-head .cs-blog-byline img { width: 44px; height: 44px; }
.cs-blog-byline-who { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 14px; }
.cs-blog-byline-who > a { font-weight: 700; text-decoration: none; }

.cs-blog-article-body {
    padding: calc(var(--widget-padding) * 1.25) calc(var(--widget-padding) * 1.5) 0;
    font-size: 16px;
    line-height: 1.75;
}
.cs-blog-article-body :is(h1, h2, h3) { margin: 1.3em 0 .5em; line-height: 1.25; }
.cs-blog-article-body img:not(.twemoji) { border-radius: var(--cs-radius-sm); }
.cs-blog-article-foot { padding: 0 calc(var(--widget-padding) * 1.5) calc(var(--widget-padding) * 1.25); }
.cs-blog-article-foot .cs-post-footer {
    margin-top: calc(var(--widget-padding) * 1.25);
    padding-top: var(--widget-padding);
    border-top: var(--cs-border-width) solid var(--cs-border);
}

.cs-blog-comments { margin-top: calc(var(--cs-col-gap) * 1.6); }
.cs-blog-comments-title { display: flex; align-items: center; gap: 8px; margin: 0 0 var(--widget-padding); font-size: 18px; }
.cs-blog-comments-title .cs-icon { width: 20px; height: 20px; color: var(--color-primary); }

/* Cover image: the preview on the new post form, and the banner across the top of a post */
.cs-cover-preview {
    display: block;
    width: 100%;
    max-width: 100%;
    aspect-ratio: 16 / 9;
    margin-bottom: var(--cs-col-gap);
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: var(--cs-radius-sm);
    object-fit: cover;
}
.cs-cover-error { color: var(--color-removed); }
.cs-cover-preview[hidden],
.cs-cover-error[hidden] { display: none; }
.cs-blog-hero { display: block; width: 100%; max-width: 100%; height: auto; aspect-ratio: 21 / 9; object-fit: cover; }

/* Home page blog section: the newest post large on the left, up to four beside
   and below it. The layout follows the number of posts (is-count-1 to 5). */
.cs-blog-feature {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: 172px;
    gap: var(--cs-col-gap);
    margin-bottom: calc(var(--cs-col-gap) * 2);
}
.cs-blog-feature.is-count-1 { grid-template-columns: minmax(0, 1fr); grid-template-areas: "hero" "hero"; }
.cs-blog-feature.is-count-2 { grid-template-areas: "hero a" "hero a"; }
.cs-blog-feature.is-count-3 { grid-template-areas: "hero a" "hero b"; }
.cs-blog-feature.is-count-4 { grid-template-areas: "hero a" "hero b" "c c"; }
.cs-blog-feature.is-count-5 { grid-template-areas: "hero a" "hero b" "c d"; }
.cs-blog-tile:nth-child(1) { grid-area: hero; }
.cs-blog-tile:nth-child(2) { grid-area: a; }
.cs-blog-tile:nth-child(3) { grid-area: b; }
.cs-blog-tile:nth-child(4) { grid-area: c; }
.cs-blog-tile:nth-child(5) { grid-area: d; }

.cs-blog-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    min-width: 0;
    padding: 14px 16px 12px;
    overflow: hidden;
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: var(--cs-radius);
    background: linear-gradient(135deg, var(--color-primary), var(--cs-primary-deep));
    color: var(--cs-on-accent);
    text-decoration: none;
    isolation: isolate;
}
.cs-blog-tile:hover { color: var(--cs-on-accent); }
.cs-blog-tile:focus-visible { outline: var(--cs-border-width) solid var(--color-primary); outline-offset: 2px; }
.cs-blog-tile-img {
    position: absolute;
    inset: 0;
    z-index: -2;
    width: 100%;
    max-width: none;
    height: 100%;
    object-fit: cover;
    transition: transform calc(var(--fade-duration) * 2.5) ease;
}
.cs-blog-tile:hover .cs-blog-tile-img { transform: scale(1.04); }
.cs-blog-tile::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(180deg, transparent 35%, var(--cs-scrim) 100%);
    transition: opacity var(--fade-duration) ease;
}
.cs-blog-tile.no-cover::before { opacity: 0.5; }
.cs-blog-tile:hover::before { opacity: 1; }

.cs-blog-tile-text { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.cs-blog-tile-title {
    display: -webkit-box;
    overflow: hidden;
    font-size: 20px;
    font-weight: 700;
    line-height: 1.25;
    overflow-wrap: anywhere;
    text-shadow: 0 1px 3px var(--cs-scrim);
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}
.cs-blog-tile.is-hero .cs-blog-tile-title { font-size: clamp(1.5rem, 1.1rem + 1.2vw, 2rem); -webkit-line-clamp: 3; line-clamp: 3; }
.cs-blog-tile-meta { font-size: 12px; opacity: 0.92; text-shadow: 0 1px 2px var(--cs-scrim); }
.cs-blog-tile-meta b { font-weight: 700; text-decoration: underline; }
.cs-blog-tile .twemoji { width: 1.1em; height: 1.1em; vertical-align: -0.15em; }

/* Phones: one column, the newest post twice as tall */
@media (width <= 720px) {
    .cs-blog-feature[class] { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; }
    .cs-blog-feature .cs-blog-tile:nth-child(n) { grid-area: auto; }
    .cs-blog-feature .cs-blog-tile.is-hero { grid-row: span 2; }
}
/* Search results: the same card and rows, with no category header */
.cs-result-excerpt {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
}

/* Nodes: a forum or a topic inside a category block */
.cs-node-list { margin: 0; padding: 0; list-style: none; container-type: inline-size; }

.cs-node {
    display: grid;
    grid-template-columns: 46px minmax(0, 1fr);
    align-items: center;
    gap: var(--cs-col-gap) var(--widget-padding);
    padding-block: 14px;
    border-top: var(--cs-border-width) solid var(--cs-border);
}
.cs-node:first-child { border-top: 0; }

.cs-node-icon {
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: var(--cs-tint-primary);
    color: var(--color-primary);
    font-size: 20px;
    line-height: 1;
}
.cs-node-icon svg,
.cs-node-icon img { width: 22px; height: 22px; object-fit: contain; }
.cs-node.is-locked .cs-node-icon { background: rgb(from var(--color-text-secondary) r g b / 0.12); color: var(--color-text-secondary); }

.cs-node-main { min-width: 0; }
.cs-node-labels { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 4px; }
.cs-node-title { margin: 0; font-size: 16px; font-weight: 700; line-height: 1.3; }
.cs-node-title a { color: var(--color-text); text-decoration: none; }
.cs-node-title a:hover { color: var(--color-primary); }
.cs-node-desc,
.cs-node-meta { margin: 3px 0 0; color: var(--color-text-secondary); font-size: 13px; line-height: 1.45; }
.cs-node-meta a { text-decoration: none; }

.cs-node-sublinks { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; font-size: 12.5px; }
.cs-node-sublinks a { display: inline-flex; align-items: center; gap: 5px; color: var(--color-text-secondary); text-decoration: none; }
.cs-node-sublinks a:hover { color: var(--color-primary); }
.cs-node-sublinks svg { width: 12px; height: 12px; }
.cs-node-sublinks i { font-size: 12px; }

.cs-node-stats { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.cs-stat-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border: var(--cs-outline);
    border-radius: 999px;
    background: var(--color-bg);
    color: var(--color-text-secondary);
    font-size: 12px;
    white-space: nowrap;
}
.cs-stat-pill strong { color: var(--color-text); font-variant-numeric: tabular-nums; }
.cs-stat-pill .cs-icon { width: 13px; height: 13px; }

.cs-node-latest { grid-column: 1 / -1; min-width: 0; }
.cs-latest {
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr);
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 9px 12px;
    border-radius: var(--cs-radius-sm);
    background: var(--color-bg);
}
.cs-latest img { width: 38px; height: 38px; border-radius: var(--cs-avatar-radius); object-fit: cover; }
.cs-latest-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cs-latest-title,
.cs-latest-meta { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.cs-latest-title { color: var(--color-text); font-size: 13px; font-weight: 700; text-decoration: none; }
a.cs-latest-title:hover { color: var(--color-primary); }
.cs-latest-meta { color: var(--color-text-secondary); font-size: 12px; }
.cs-latest-meta a { text-decoration: none; }
.cs-latest.cs-latest-empty { display: flex; align-items: center; gap: 8px; color: var(--color-text-secondary); font-size: 13px; }
.cs-latest-empty .cs-icon { width: 16px; height: 16px; }

@container (min-width: 640px) {
    .cs-node { grid-template-columns: 46px minmax(0, 1fr) minmax(0, 19rem); }
    .cs-node-latest { grid-column: auto; }
}

@media (prefers-reduced-motion: reduce) {
    .cs-cat-toggle { transition: none; }
}
.cs-post-buttons, .cs-post-reactions, .cs-reactions { display: flex; flex-wrap: wrap; gap: calc(var(--cs-col-gap) * 0.6); align-items: center; }

.cs-reaction {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 4px 10px;
    border: var(--cs-outline);
    border-radius: 999px;
    background: var(--color-bg);
    color: var(--color-text-darker);
    cursor: pointer;
}
.cs-reaction:hover, .cs-reaction-active { border-color: var(--color-primary); color: var(--color-text); }
.cs-reaction-count { font-weight: 700; }

.cs-reply-box { margin-top: var(--widget-padding); }

/* Topic labels sit on their own row above the title */
.cs-topic-labels {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: calc(var(--cs-col-gap) * 0.6);
}
.cs-topic-labels .badge + .badge { margin-inline-start: 0; }

/* Follow / Following */
.cs-follow-form { display: inline-flex; margin: 0; }
.cs-follow { display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
.cs-follow .cs-icon { width: 16px; height: 16px; }
/* Each state is its own centred row, so the label never drifts off-centre;
   a min width stops the button jumping between "Following" and "Unfollow". */
.cs-follow.is-following { min-width: 8.5rem; }
.cs-follow-on,
.cs-follow-off { align-items: center; justify-content: center; gap: 6px; line-height: 1; }
.cs-follow-on { display: inline-flex; }
.cs-follow-off { display: none; }
.cs-follow.is-following:is(:hover, :focus-visible) .cs-follow-on { display: none; }
.cs-follow.is-following:is(:hover, :focus-visible) .cs-follow-off { display: inline-flex; }
.cs-share { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cs-col-gap); margin-top: var(--widget-padding); color: var(--color-text-secondary); }

/*
 * Emoji. Core swaps emoji in posts for Twemoji images carrying
 * width="72" height="72", so without this each one rendered 72px tall.
 * Sized to the text around it instead.
 */
img.twemoji,
.cs-post-content img.twemoji {
    display: inline-block;
    width: 1.25em;
    height: 1.25em;
    margin: 0 .05em;
    vertical-align: -0.25em;
}

/* Reactions: counts people can open, and a picker on other people's posts */
button.cs-reaction { font: inherit; font-size: 13px; }
.cs-reaction-emoji { display: inline-flex; font-size: 16px; line-height: 1; }
.cs-reaction-emoji img,
.cs-reaction-pick img { width: 1.1em; height: 1.1em; }

/*
 * Core swaps an emoji for a Twemoji <img> but can leave its invisible variation
 * selector (U+FE0F) behind as text, as it does for the Helpful reaction. That
 * stray character became a second item: in the picker grid it took its own
 * row and pushed the icon up. Keep everything on one centred row instead.
 */
.cs-reaction-emoji { align-items: center; justify-content: center; }
.cs-reaction-pick { grid-auto-flow: column; place-content: center; }
.cs-reaction-emoji img.twemoji,
.cs-reaction-pick img.twemoji { display: block; margin: 0; vertical-align: 0; }

/*
 * Reaction picker, collapsed to its lead reaction (the member's own, else the
 * first). On hover / keyboard focus / .is-open (touch) it fans out into a tray
 * and every reaction can be hovered and pressed.
 */
.cs-reaction-picker {
    display: inline-flex;
    align-items: center;
    padding: 2px;
    border: var(--cs-border-width) solid transparent;
    border-radius: 999px;
    transition: background-color var(--fade-duration) ease, border-color var(--fade-duration) ease;
}

.cs-reaction-pick {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    font-size: 17px;
    line-height: 1;
    overflow: hidden;
    cursor: pointer;
    transition: width var(--fade-duration) ease, opacity var(--fade-duration) ease,
                transform var(--fade-duration) ease, background-color var(--fade-duration) ease;
}

/* Collapsed: everything except the lead takes no room */
.cs-reaction-pick:not(.is-lead) { width: 0; opacity: 0; pointer-events: none; }
.cs-reaction-pick.is-lead:not(.is-active) { opacity: .6; filter: grayscale(.5); }

.cs-reaction-picker:is(:hover, :focus-within, .is-open) {
    background: var(--color-bg);
    border-color: var(--cs-border);
}
.cs-reaction-picker:is(:hover, :focus-within, .is-open) .cs-reaction-pick {
    width: 34px;
    opacity: 1;
    filter: none;
    pointer-events: auto;
}

/* Same hover as the post action buttons: a round tint, no scaling */
.cs-reaction-pick:hover,
.cs-reaction-pick:focus-visible { transform: none; background: var(--cs-tint-primary); outline: none; }
.cs-reaction-pick.is-active { background: var(--cs-tint-primary); }
.cs-reaction-pick:disabled { cursor: progress; }

@media (prefers-reduced-motion: reduce) {
    .cs-reaction-picker,
    .cs-reaction-pick { transition: none; }
}

.cs-post-buttons .cs-icon-btn-danger:hover,
.cs-post-buttons .cs-icon-btn-danger:focus-visible { color: var(--color-removed); }

/*
 * Native <dialog> for report / spam / delete and the "who reacted" list.
 *
 * Centred and animated like the theme's other popups (altara.css .popup:
 * 0.26s spring scale-in, 160ms fade). Position, inset and margin are set
 * explicitly: a modal dialog is only centred by the browser's own
 * `margin: auto`, and a reset that zeroes margins pins it to the top-left.
 * No padding on the dialog itself, so a click that lands on it is the backdrop.
 */
.cs-dialog {
    position: fixed;
    inset: 0;
    margin: auto;
    width: min(92vw, 30rem);
    max-height: calc(100dvh - var(--widget-padding) * 2);
    overflow: auto;
    padding: 0;
    border: var(--cs-outline);
    border-radius: var(--cs-radius);
    background: var(--color-brighter-bg);
    color: var(--color-text);
    box-shadow: var(--cs-shadow-float);
    opacity: 0;
    scale: .82;
    transition: scale .26s cubic-bezier(.34, 1.56, .64, 1), opacity .16s ease,
                overlay .16s allow-discrete, display .16s allow-discrete;
}
.cs-dialog[open] { opacity: 1; scale: 1; }
@starting-style {
    .cs-dialog[open] { opacity: 0; scale: .82; }
}

.cs-dialog::backdrop {
    background: rgb(from var(--color-bg) r g b / 0.7);
    transition: background-color .16s ease, overlay .16s allow-discrete, display .16s allow-discrete;
}
@starting-style {
    .cs-dialog[open]::backdrop { background-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
    .cs-dialog,
    .cs-dialog::backdrop { transition: none; }
}
.cs-dialog-body { padding: calc(var(--widget-padding) * 1.25); }
.cs-dialog .widget-title { margin-bottom: var(--cs-col-gap); }
.cs-dialog p { margin: 0 0 var(--cs-col-gap); color: var(--color-text-secondary); }
.cs-reactions-dialog { width: min(92vw, 34rem); }

/* Home / news posts */
.cs-post { display: flex; flex-direction: column; gap: var(--cs-col-gap); }
.cs-post-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--cs-col-gap); align-items: baseline; }
.cs-post-title { margin: 0; }
.cs-post-title a { color: var(--color-text); text-decoration: none; }
.cs-post-title a:hover { color: var(--color-primary); }
.cs-post-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--cs-col-gap); padding-top: var(--cs-col-gap); border-top: var(--cs-border-width) solid var(--cs-border); }
.cs-post-author { display: inline-flex; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); text-decoration: none; }

/* ==========================================================================
   Profile
   ========================================================================== */

.cs-profile-header {
    display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
    gap: var(--widget-padding);
    margin-block: var(--widget-padding);
    background-size: cover;
    background-position: center;
}
.cs-profile-identity { display: flex; align-items: center; gap: var(--widget-padding); }
.cs-profile-avatar { width: 96px; height: 96px; }
.cs-profile-name { margin: 0; font-size: 24px; }
.cs-profile-title { margin: 2px 0; color: var(--color-text-secondary); }
.cs-profile-groups, .cs-member-groups, .cs-leaderboard-groups { display: flex; flex-wrap: wrap; gap: 4px; }
.cs-profile-actions { display: flex; flex-wrap: wrap; gap: var(--cs-col-gap); }
.cs-profile-feed { display: flex; flex-direction: column; gap: var(--cs-col-gap); }
.cs-wall-post { display: flex; flex-direction: column; gap: calc(var(--cs-col-gap) * 0.6); }
.cs-wall-author { display: inline-flex; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); text-decoration: none; font-weight: 600; }

/* ==========================================================================
   Members, feeds, chips
   ========================================================================== */

.cs-member-grid { display: grid; gap: var(--cs-col-gap); grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.cs-member { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: var(--cs-col-gap); border: var(--cs-outline); border-radius: var(--cs-radius-sm); text-align: center; }
.cs-member a { display: flex; flex-direction: column; align-items: center; gap: 6px; text-decoration: none; }

.cs-user-chips { display: flex; flex-wrap: wrap; gap: calc(var(--cs-col-gap) * 0.6); }
.cs-user-chips a { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: 999px; background: var(--color-bg); text-decoration: none; font-size: 13px; }
.cs-user-chips a:hover { background: var(--cs-tint-primary); }

.cs-feed-list { display: flex; flex-direction: column; }
.cs-feed-item { display: flex; gap: var(--cs-col-gap); padding-block: var(--cs-col-gap); border-bottom: var(--cs-border-width) solid var(--cs-border); }
.cs-feed-item:last-child { border-bottom: 0; }
.cs-feed-body { min-width: 0; }
.cs-feed-content { display: block; color: var(--color-text); text-decoration: none; overflow-wrap: anywhere; }
.cs-feed-content:hover { color: var(--color-primary); }
.cs-feed-meta { margin: 2px 0 0; font-size: 12px; color: var(--color-text-secondary); display: flex; flex-wrap: wrap; gap: 6px; }

/* ==========================================================================
   Alerts, messages, connections, tables
   ========================================================================== */

.cs-alert { display: flex; align-items: center; gap: var(--cs-col-gap); padding-block: var(--cs-col-gap); border-bottom: var(--cs-border-width) solid var(--cs-border); }
.cs-alert:last-child { border-bottom: 0; }
.cs-alert-body { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; text-decoration: none; color: var(--color-text); }
.cs-alert-date { font-size: 12px; color: var(--color-text-secondary); }
.cs-alert-unread .cs-alert-title { font-weight: 700; }

.cs-connection-grid { display: grid; gap: var(--widget-padding); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.cs-connection-user { font-weight: 600; margin: 0 0 var(--cs-col-gap); }

.cs-table-wrap { overflow-x: auto; }

.cs-dropdown-item {
    display: flex; flex-direction: column; gap: 2px;
    padding: calc(var(--cs-col-gap) * 0.8);
    border-radius: var(--cs-radius-sm);
    color: var(--color-text); text-decoration: none;
}
.cs-dropdown-item:hover { background: var(--cs-tint-primary); }

/* ==========================================================================
   Status, leaderboards, popover, cookie notice
   ========================================================================== */

.cs-server-grid { display: grid; gap: var(--widget-padding); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.cs-server-card { display: flex; flex-direction: column; gap: var(--cs-col-gap); }
.cs-status { display: flex; align-items: center; gap: var(--cs-col-gap); }
.cs-status-badge { padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; }
.cs-status-online { background: var(--cs-tint-success); color: var(--cs-success); }
.cs-status-offline { background: var(--cs-tint-danger); color: var(--color-removed); }
.cs-status-count { margin: 0; font-size: 20px; }
.cs-copy-ip { display: inline-flex; align-items: center; gap: var(--cs-col-gap); }
.cs-copy-ip.cs-copied { border-color: var(--cs-success); color: var(--cs-success); }

.cs-leaderboard { counter-reset: rank; display: flex; flex-direction: column; }
.cs-leaderboard-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--cs-col-gap); align-items: center; padding-block: var(--cs-col-gap); border-bottom: var(--cs-border-width) solid var(--cs-border); }
.cs-leaderboard-row:last-child { border-bottom: 0; }
.cs-leaderboard-rank { min-width: 2ch; font-weight: 700; color: var(--color-primary); }
.cs-leaderboard-user { display: inline-flex; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); text-decoration: none; }
.cs-leaderboard-value { font-weight: 700; }
.cs-leaderboard-updated { font-size: 12px; color: var(--color-text-secondary); }

.cs-popover { display: flex; flex-direction: column; gap: var(--cs-col-gap); min-width: 240px; }
.cs-popover-head { display: flex; gap: var(--cs-col-gap); align-items: center; }
.cs-popover-name { margin: 0; font-weight: 700; }
.cs-popover-groups { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.cs-popover-stats { border-top: var(--cs-border-width) solid var(--cs-border); padding-top: var(--cs-col-gap); font-size: 13px; }
.cs-popover-stats p { margin: 0 0 4px; color: var(--color-text-secondary); }

.cs-cookie-notice {
    position: fixed; inset-inline: var(--widget-padding); bottom: var(--widget-padding);
    z-index: 900;
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: var(--widget-padding);
    max-width: var(--content-inner-width);
    margin-inline: auto;
    padding: var(--widget-padding);
    border: var(--cs-outline);
    border-radius: var(--cs-radius);
    background: var(--color-brighter-bg);
}
.cs-cookie-head { margin: 0 0 4px; font-weight: 700; }
.cs-cookie-actions { display: flex; gap: var(--cs-col-gap); }

.cs-reaction-row { display: flex; align-items: center; justify-content: space-between; gap: var(--cs-col-gap); padding-block: calc(var(--cs-col-gap) * 0.8); border-bottom: var(--cs-border-width) solid var(--cs-border); }
.cs-reaction-row:last-child { border-bottom: 0; }
.cs-reaction-user { display: inline-flex; align-items: center; gap: calc(var(--cs-col-gap) * 0.8); text-decoration: none; }
.cs-reaction-meta { display: flex; align-items: center; gap: var(--cs-col-gap); font-size: 12px; color: var(--color-text-secondary); }

.cs-mc-account { display: flex; flex-direction: column; align-items: center; gap: var(--cs-col-gap); text-align: center; }
.cs-mc-username { margin: 0; font-weight: 700; }
.cs-tfa-qr img { max-width: 200px; height: auto; background: var(--cs-on-accent); padding: var(--cs-col-gap); border-radius: var(--cs-radius-sm); }
.cs-tfa-secret { text-align: center; }

.cs-member-search { margin-bottom: var(--cs-col-gap); }

/* ==========================================================================
   TinyMCE — post editor
   No frame of its own: the editor sits inside a card already, so a second
   border around it just doubles up. Toolbar and edit area take the card's own
   colours so the whole thing reads as one surface.
   Switch off with Components -> Restyle post editor.
   ========================================================================== */

body:not(.cs-plain-editor) .tox.tox-tinymce {
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
}

body:not(.cs-plain-editor) .tox .tox-editor-header,
body:not(.cs-plain-editor) .tox .tox-toolbar,
body:not(.cs-plain-editor) .tox .tox-toolbar__primary,
body:not(.cs-plain-editor) .tox .tox-toolbar-overlord,
body:not(.cs-plain-editor) .tox .tox-menubar {
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
}

/* Only separator left: between the toolbar and the writing area */
body:not(.cs-plain-editor) .tox .tox-editor-header {
    border-bottom: var(--cs-border-width) solid var(--cs-border) !important;
    padding-inline: 0 !important;
}

body:not(.cs-plain-editor) .tox .tox-statusbar {
    background: transparent !important;
    border-top: 0 !important;
    color: var(--color-text-secondary) !important;
}

body:not(.cs-plain-editor) .tox .tox-tbtn,
body:not(.cs-plain-editor) .tox .tox-mbtn,
body:not(.cs-plain-editor) .tox .tox-statusbar a,
body:not(.cs-plain-editor) .tox .tox-statusbar__path-item,
body:not(.cs-plain-editor) .tox .tox-statusbar__wordcount {
    color: var(--color-text-darker) !important;
}

body:not(.cs-plain-editor) .tox .tox-tbtn svg,
body:not(.cs-plain-editor) .tox .tox-mbtn svg { fill: currentColor !important; }

body:not(.cs-plain-editor) .tox .tox-tbtn:hover,
body:not(.cs-plain-editor) .tox .tox-mbtn:hover,
body:not(.cs-plain-editor) .tox .tox-tbtn--enabled {
    background: var(--cs-tint-primary) !important;
    color: var(--color-text) !important;
}

/*
 * Exception: the Signature editor on the settings page. Everywhere else the
 * editor is the only thing in its card, so a frame would double up — but here
 * it sits in a column of .cs-input fields and has to match them. Same border,
 * radius, background and focus colour as .cs-input.
 *
 * The body:not(...) prefix is load-bearing, not copy-paste. The frameless rules
 * above are selectors like `body:not(.cs-plain-editor) .tox.tox-tinymce`, which
 * score (0,3,1). Scoping by `.cs-field-editor` alone scores (0,3,0) — LOWER —
 * so those rules would keep winning even with !important on both sides and this
 * one sitting later in the file. Matching their prefix puts this at (0,4,1).
 */
body:not(.cs-plain-editor) .cs-field-editor .tox.tox-tinymce {
    border: var(--cs-outline) !important;
    border-radius: var(--cs-radius-sm) !important;
    background: var(--color-bg) !important;
    overflow: hidden;
}

/* The frameless rule strips this to 0 to sit flush with the card; inside a
   box of its own the toolbar needs the field's own inner padding back. */
body:not(.cs-plain-editor) .cs-field-editor .tox .tox-editor-header {
    padding-inline: calc(var(--cs-col-gap) * 1.2) !important;
}

body:not(.cs-plain-editor) .cs-field-editor .tox .tox-sidebar-wrap,
body:not(.cs-plain-editor) .cs-field-editor .tox .tox-statusbar {
    padding-inline: calc(var(--cs-col-gap) * 0.6) !important;
}

body:not(.cs-plain-editor) .cs-field-editor:focus-within .tox.tox-tinymce {
    border-color: var(--color-primary) !important;
}

/* Menus and dialogs render in .tox-tinymce-aux on <body>, outside the card */
body:not(.cs-plain-editor) .tox .tox-menu,
body:not(.cs-plain-editor) .tox .tox-collection--list,
body:not(.cs-plain-editor) .tox .tox-dialog {
    background: var(--color-brighter-bg) !important;
    border: var(--cs-outline) !important;
    border-radius: var(--cs-radius-sm) !important;
    color: var(--color-text) !important;
}

body:not(.cs-plain-editor) .tox .tox-collection__item { color: var(--color-text-darker) !important; }

body:not(.cs-plain-editor) .tox .tox-collection__item--active,
body:not(.cs-plain-editor) .tox .tox-collection__item:hover {
    background: var(--cs-tint-primary) !important;
    color: var(--color-text) !important;
}

body:not(.cs-plain-editor) .tox .tox-dialog__header,
body:not(.cs-plain-editor) .tox .tox-dialog__footer {
    background: var(--color-brighter-bg) !important;
    border-color: var(--cs-border) !important;
    color: var(--color-text) !important;
}

body:not(.cs-plain-editor) .tox .tox-button {
    background: var(--color-primary) !important;
    border-color: var(--color-primary) !important;
    color: var(--color-primary-text) !important;
    border-radius: var(--cs-radius-sm) !important;
}

body:not(.cs-plain-editor) .tox .tox-button--secondary {
    background: var(--color-secondary) !important;
    border-color: var(--cs-border) !important;
    color: var(--color-text) !important;
}

body:not(.cs-plain-editor) .tox .tox-textfield,
body:not(.cs-plain-editor) .tox .tox-listbox,
body:not(.cs-plain-editor) .tox .tox-textarea {
    background: var(--color-bg) !important;
    border: var(--cs-outline) !important;
    border-radius: var(--cs-radius-sm) !important;
    color: var(--color-text) !important;
}

/* ==========================================================================
   Empty states — page level
   Large, centred, icon above the message. The small inline variant used
   inside widgets stays as .cs-empty.
   ========================================================================== */

.cs-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--cs-col-gap);
    padding-block: calc(var(--widget-padding) * 2);
    text-align: center;
}

.cs-empty-icon {
    display: inline-flex;
    color: var(--color-primary);
    opacity: .7;
}

.cs-empty-icon .cs-icon {
    width: calc(var(--btn-size) * 1.6);
    height: calc(var(--btn-size) * 1.6);
}

.cs-empty-message {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-text);
}

/* ==========================================================================
   Register segment inside the account pill (guests)
   Typography matches .cs-account-label so it reads as one control with the
   Log In pill rather than a button parked next to it.
   ========================================================================== */

.cs-cluster-link {
    display: inline-flex;
    align-items: center;
    padding-inline: calc(var(--cs-account-height) * 0.26);
    color: var(--cs-on-accent);
    font-weight: 600;
    font-size: calc(var(--cs-account-height) * 0.32);
    text-transform: uppercase;
    letter-spacing: .5px;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    transition: transform var(--fade-duration) ease;
}

.cs-cluster-link:hover,
.cs-cluster-link:focus-visible {
    color: var(--cs-on-accent);
    text-decoration: none;
    transform: scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
    .cs-cluster-link { transition: none; }
    .cs-cluster-link:hover,
    .cs-cluster-link:focus-visible { transform: none; opacity: .8; }
}

/* ==========================================================================
   Online Users / Online Staff — avatar grid with tooltip
   Restored from the store theme's Recent Purchases module, which the CSS prune
   had removed. Fixed pixel values are expressed against the shape tokens so the
   widget follows the Corner radius / Outline thickness settings; at the default
   settings the geometry is identical to the store theme.
   ========================================================================== */

:root {
    /*
     * Shadows read as dark in both palettes, so these stay derived constants.
     *
     * The tip is anchored ABOVE its tile, with only --cs-col-gap between the
     * two. A 12px downward offset plus a 30px blur therefore threw the shadow
     * about 27px past the tip's bottom edge — straight over the top half of a
     * 40px avatar, which read as a dark gradient bleeding out of the icon on
     * hover. Kept tight and near-centred so it stays under the tip.
     *
     * Toasts float clear of any content, so they keep the deeper shadow.
     */
    --cs-shadow-tip: 0 2px 10px rgb(0 0 0 / 0.22);
    --cs-shadow-float: 0 12px 30px rgb(0 0 0 / 0.45);

    /* Darkens the lower part of an image so light text on it stays readable in both modes */
    --cs-scrim: rgb(0 0 0 / 0.62);
}

.cs-purchase-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--cs-col-gap);
}

.cs-purchase {
    position: relative;
    display: block;
    width: 100%;
    padding: 0;
    border: none;
    background: transparent;
    cursor: pointer;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

.cs-purchase-avatar {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: calc(var(--cs-radius) * 0.75);
    overflow: hidden;
    background: var(--color-secondary);
    border: var(--cs-border-width) solid var(--cs-border);
    transition: transform var(--fade-duration) ease, border-color var(--fade-duration) ease;
}

.cs-purchase-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    image-rendering: pixelated;
}

.cs-purchase:hover .cs-purchase-avatar,
.cs-purchase:focus-visible .cs-purchase-avatar {
    transform: scale(1.08);
    border-color: var(--color-primary);
}

.cs-purchase.cs-tip-open .cs-purchase-avatar { border-color: var(--color-primary); }

.cs-purchase-tip {
    position: absolute;
    bottom: calc(100% + var(--cs-col-gap));
    left: 50%;
    transform: translateX(-50%) scale(0.8);
    transform-origin: bottom center;
    z-index: 50;
    min-width: 120px;
    max-width: 180px;
    padding: calc(var(--cs-col-gap) * 1.1) calc(var(--cs-col-gap) * 1.25);
    background: var(--color-bg);
    border: var(--cs-border-width) solid var(--cs-border);
    border-radius: calc(var(--cs-radius) * 0.75);
    box-shadow: var(--cs-shadow-tip);
    text-align: center;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--fade-duration) ease,
                transform var(--fade-duration) cubic-bezier(0.4, 0, 1, 1),
                visibility 0s linear var(--fade-duration);
}

.cs-purchase-tip::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 7px solid transparent;
    border-top-color: var(--cs-border);
}

.cs-purchase:hover .cs-purchase-tip,
.cs-purchase:focus-visible .cs-purchase-tip,
.cs-purchase.cs-tip-open .cs-purchase-tip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) scale(1);
    transition: opacity var(--fade-duration) ease,
                transform calc(var(--fade-duration) * 1.4) cubic-bezier(0.34, 1.56, 0.64, 1),
                visibility 0s linear 0s;
}

.cs-purchase-tip-name {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-purchase-tip-pkg {
    display: block;
    margin-top: 2px;
    font-size: 14px;
    color: var(--color-text-secondary);
    line-height: 1.35;
}

/* The tooltip escapes the widget box */
.widget-recent { overflow: visible; }
.widget-recent .widget-content { overflow: visible; }

/* ==========================================================================
   Server Status widget — reuses the home page's Play Now card
   ========================================================================== */

/* Sidebar is one column wide; the home grid is two */
.cs-home-cards-single { grid-template-columns: 1fr; }

/*
 * Offline state. The store theme's card is purely a call-to-action and has no
 * offline concept. Offline drops the coloured gradient for the plain card
 * surface, so the foreground colours must come back to normal text tokens —
 * the online card paints them light for a coloured background.
 */
.cs-home-cards .info.server.cs-card-offline {
    border-color: var(--cs-border);
    background: var(--color-brighter-bg);
    color: var(--color-text);
}

/* The floating-circles overlay is tuned for a coloured card */
.cs-home-cards .info.server.cs-card-offline::before { display: none; }

.cs-home-cards .info.server.cs-card-offline .cs-nav-title {
    color: var(--color-text);
}

.cs-home-cards .info.server.cs-card-offline .cs-nav-icon,
.cs-home-cards .info.server.cs-card-offline .cs-nav-chev,
.cs-home-cards .info.server.cs-card-offline .cs-nav-subtitle,
.cs-home-cards .info.server.cs-card-offline .cs-nav-sub-base,
.cs-home-cards .info.server.cs-card-offline .cs-nav-sub-hover {
    color: var(--color-text-secondary);
}

/* The hexagon ring behind the card icon is driven by --cs-hex-color (the
   Discord card overrides it the same way). Offline goes neutral too. */
.cs-home-cards .info.server.cs-card-offline .cs-nav-icon {
    --cs-hex-color: var(--color-text-secondary);
}

/* ==========================================================================
   Toasts — bottom-right, used for copy-to-clipboard confirmation
   ========================================================================== */

#cs-toasts {
    position: fixed;
    inset-inline-end: var(--widget-padding);
    bottom: var(--widget-padding);
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: var(--cs-col-gap);
    pointer-events: none;
}

.cs-toast {
    display: flex;
    align-items: center;
    gap: var(--cs-col-gap);
    max-width: 340px;
    padding: calc(var(--cs-col-gap) * 1.2) var(--widget-padding);
    border: var(--cs-outline);
    border-radius: var(--cs-radius);
    background: var(--color-brighter-bg);
    color: var(--color-text);
    box-shadow: var(--cs-shadow-float);
    pointer-events: auto;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity var(--fade-duration) ease, transform var(--fade-duration) ease;
}

.cs-toast.cs-toast-in { opacity: 1; transform: none; }

.cs-toast-icon {
    flex: none;
    width: 20px;
    height: 20px;
    color: var(--cs-success);
}

@media (prefers-reduced-motion: reduce) {
    .cs-toast { transition: opacity var(--fade-duration) ease; transform: none; }
}

/* ==========================================================================
   Status page
   Server card (sidebar widget) on the left, player grid (Online Users widget)
   on the right. Rows stack, so multiple servers read one after another.
   ========================================================================== */

.cs-page-lead-xl {
    font-size: 2.2rem;
    line-height: 1.15;
    margin-bottom: var(--widget-padding);
}

.cs-status-list {
    display: flex;
    flex-direction: column;
    gap: calc(var(--widget-padding) * 1.25);
}

.cs-status-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--widget-padding);
    align-items: start;
}

/* Two columns only when that server actually has a player list */
@media (min-width: 900px) {
    .cs-status-row:has(.cs-status-players) {
        grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
    }
}

.cs-status-players { min-width: 0; }

/*
 * Player list: one row only, so the panel matches the server card's height.
 * Heads are smaller than the sidebar's. theme.js trims tiles until they fit and
 * rolls the remainder into the +N tile; overflow:hidden is the safety net.
 */
.cs-status-players {
    display: flex;
    flex-direction: column;
    gap: calc(var(--cs-col-gap) * 0.8);
    padding: calc(var(--widget-padding) * 0.7);
}

.cs-status-players .widget-title {
    margin: 0;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--color-text-secondary);
}

.cs-status-players-body { min-width: 0; }

.cs-status-players .cs-purchase-grid {
    display: flex;
    flex-wrap: nowrap;
    gap: calc(var(--cs-col-gap) * 0.6);
    overflow: hidden;
}

.cs-status-players .cs-purchase {
    flex: 0 0 var(--btn-size);
    width: var(--btn-size);
}

/* "+N more" tile for players trimmed off the row */
.cs-purchase-more {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 var(--btn-size);
    width: var(--btn-size);
    aspect-ratio: 1 / 1;
    border: var(--cs-border-width) dashed var(--cs-border);
    border-radius: calc(var(--cs-radius) * 0.75);
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 700;
}

/* altara.css centres .widget-title globally and only un-centres it inside the
   sidebar; this panel sits in page content, so it needs the same correction. */
.cs-status-players .widget-title { text-align: left; }

/* Card and player panel are always the same height — never two sizes */
.cs-status-row { align-items: stretch; }
.cs-status-row .cs-home-cards-single,
.cs-status-row .cs-home-cards-single .info.server,
.cs-status-row .cs-status-players { height: 100%; }

/* ==========================================================================
   Page titles, buttons, profile card
   ========================================================================== */

/*
 * The main page heading was inheriting a small default. Sized here once so
 * every page matches — the -xl class is kept as an alias for existing markup.
 */
.cs-page-lead,
.cs-page-lead-xl {
    font-size: 2.2rem;
    line-height: 1.15;
    margin-bottom: var(--widget-padding);
}

/*
 * altara.css centres .widget-title for store widgets and only un-centres it
 * inside the sidebar. Content headings in this theme read left.
 */
.site-main .widget-title { text-align: left; }

/* Buttons: centre icon and label together, whichever is present */
.btn-primary,
.btn-secondary,
.btn-tertiary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: calc(var(--cs-col-gap) * 0.7);
    text-align: center;
}

/* ---------- profile card (Top Customer treatment) ---------- */

/*
 * The store card is 720x344 and sizes its internals in cqw (percent of its own
 * width), which is fine in a narrow module slot but enormous across a full
 * content column. Height is fixed here and every cqw-based value overridden —
 * container-type must stay, or the remaining cqw units fall back to the
 * viewport and get bigger still.
 */
.cs-profile-card {
    aspect-ratio: auto;
    height: 150px;
    margin-bottom: var(--widget-padding);
}

/*
 * Banner treatment. Two things hide the image if left alone: this gradient, and
 * .cs-topcustomer::after — an opaque radial of the surface colour over most of
 * the card. Both are driven by --cs-banner-alpha so the user's "overlay
 * strength" controls them together.
 */
.cs-profile-card.cs-has-banner {
    --cs-banner-alpha: 0.78;
    --cs-banner-blur: 0px;
    --cs-banner-pos: center;
    background-size: cover;
    background-position: var(--cs-banner-pos);
}

.cs-profile-card.cs-has-banner.cs-overlay-gradient {
    background-image:
        linear-gradient(160deg,
            rgb(from var(--color-primary) r g b / calc(var(--cs-banner-alpha) * 0.85)) 0%,
            rgb(from var(--cs-primary-deep) r g b / var(--cs-banner-alpha)) 100%),
        var(--cs-profile-banner);
}

.cs-profile-card.cs-has-banner.cs-overlay-plain {
    background-image:
        linear-gradient(
            rgb(from var(--color-bg) r g b / var(--cs-banner-alpha)),
            rgb(from var(--color-bg) r g b / var(--cs-banner-alpha))),
        var(--cs-profile-banner);
}

.cs-profile-card.cs-has-banner.cs-overlay-none {
    background-image: var(--cs-profile-banner);
}

/* The radial keeps the text legible; it follows the same strength control */
.cs-profile-card.cs-has-banner::after {
    background: radial-gradient(82% 82% at 100% 100%,
        rgb(from var(--color-brighter-bg) r g b / var(--cs-banner-alpha)) 0%,
        rgb(from var(--color-brighter-bg) r g b / calc(var(--cs-banner-alpha) * 0.7)) 34%,
        transparent 88%);
}

/* Blur applies to the image only, so text and skin stay sharp */
.cs-profile-card.cs-has-banner::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    backdrop-filter: blur(var(--cs-banner-blur));
    -webkit-backdrop-filter: blur(var(--cs-banner-blur));
}

/* ---------- banner picker panel ---------- */

.cs-banner-panel { margin-bottom: var(--widget-padding); }

.cs-banner-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: var(--cs-col-gap);
    margin-bottom: var(--widget-padding);
}

/* Radio-backed thumbnails: selecting one only previews until Save is pressed */
.cs-banner-option {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    padding: 0;
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background-color: var(--color-bg);
    background-size: cover;
    background-position: center;
    cursor: pointer;
    transition: transform var(--fade-duration) ease, border-color var(--fade-duration) ease;
}

.cs-banner-option input { position: absolute; opacity: 0; pointer-events: none; }

.cs-banner-option:hover,
.cs-banner-option:focus-within { transform: scale(1.03); border-color: var(--color-primary); }

.cs-banner-option:has(:checked) {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 var(--cs-border-width) var(--color-primary);
}

.cs-banner-upload { margin-top: var(--widget-padding); }

/* Skin column: fixed and narrow instead of 42% of the content width */
.cs-profile-card .cs-topcustomer-char { width: 118px; }

/* Nudged right so the model sits inside the card rather than hugging the edge */
.cs-profile-card .cs-topcustomer-fallback,
.cs-profile-card .cs-topcustomer-canvas { transform: translateX(14%) scale(1); }

/* Name plaque sizes to its text rather than 26% of the card */
.cs-profile-card .cs-topcustomer-title {
    height: auto;
    gap: var(--cs-col-gap);
    padding: calc(var(--cs-col-gap) * 0.9) var(--widget-padding);
    border-radius: 0 0 0 var(--cs-radius);
}

.cs-profile-card .cs-topcustomer-title span {
    font-size: 1rem;
    max-width: 42ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cs-profile-card .cs-topcustomer-body {
    left: 118px;
    top: auto;
    gap: calc(var(--cs-col-gap) * 0.7);
    padding: var(--widget-padding);
}

.cs-profile-card .cs-topcustomer-line { font-size: 13px; }

.cs-profile-card .cs-profile-groups { display: flex; flex-wrap: wrap; gap: 4px; }

.cs-profile-card .cs-profile-actions {
    display: flex;
    flex-wrap: wrap;
    gap: calc(var(--cs-col-gap) * 0.8);
}

@media (max-width: 700px) {
    .cs-profile-card { height: auto; min-height: 200px; }
    .cs-profile-card .cs-topcustomer-char { width: 92px; }
    .cs-profile-card .cs-topcustomer-body { left: 92px; }
    .cs-profile-card .cs-topcustomer-title span { font-size: 1rem; max-width: 14ch; }
}

/* Editor field: the textarea is replaced by TinyMCE, which brings its own
   chrome — so no input border here or it doubles up */
/* Shown when TinyMCE is not running; matches .cs-input so the field looks the
   same either way. */
.cs-field-editor textarea {
    width: 100%;
    padding: calc(var(--cs-col-gap) * 0.8) calc(var(--cs-col-gap) * 1.2);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-bg);
    color: var(--color-text);
    font: inherit;
}

/* Free-text About block above the detail list on a profile */
.cs-about-text {
    margin: 0 0 var(--widget-padding);
    color: var(--color-text);
    line-height: 1.6;
    overflow-wrap: anywhere;
}

/* Slider rows in the banner panel */
.cs-slider-row { display: flex; align-items: center; gap: var(--cs-col-gap); }
.cs-slider-row .cs-range { flex: 1 1 auto; min-width: 0; accent-color: var(--color-primary); }
.cs-slider-row output {
    flex: 0 0 auto;
    min-width: 4ch;
    text-align: right;
    color: var(--color-text-secondary);
    font-size: 13px;
}

.cs-banner-style-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--widget-padding);
}

/* Delete control on a user's own banner thumbnails */
.cs-banner-delete {
    position: absolute;
    top: 4px;
    inset-inline-end: 4px;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgb(from var(--color-bg) r g b / 0.75);
    color: var(--color-removed);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--fade-duration) ease, background var(--fade-duration) ease;
}

.cs-banner-own:hover .cs-banner-delete,
.cs-banner-delete:focus-visible { opacity: 1; }
.cs-banner-delete:hover { background: var(--color-removed); color: var(--cs-on-accent); }

/* ==========================================================================
   Input icons — generic
   altara.css only positions .cs-input-icon inside .cs-login, so everywhere
   else (2FA, forgot password, search, members) the icon fell inline in front
   of the field instead of sitting inside it.
   ========================================================================== */

.cs-input-wrap { position: relative; display: block; }

.cs-input-wrap .cs-input-icon {
    position: absolute;
    inset-inline-start: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    color: var(--color-text-secondary);
    pointer-events: none;
    z-index: 1;
}

.cs-input-wrap:has(> .cs-input-icon) input,
.cs-input-wrap:has(> .cs-input-icon) .cs-input,
.cs-input-wrap:has(> .cs-input-icon) textarea { padding-inline-start: 42px; }

.cs-input-wrap:focus-within .cs-input-icon { color: var(--color-primary); }
/* A textarea is tall, so centring the icon would drop it into the middle of
   the text. Pin it to the first line instead. */
.cs-input-wrap:has(textarea) .cs-input-icon { top: calc(var(--cs-col-gap) + 9px); transform: none; }

/* ==========================================================================
   Two-factor authentication
   ========================================================================== */

.cs-tfa-qr {
    display: flex;
    justify-content: center;
    margin-block: var(--widget-padding);
}

.cs-tfa-qr img {
    display: block;
    width: 200px;
    max-width: 100%;
    height: auto;
    padding: var(--cs-col-gap);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--cs-on-accent);
}

.cs-tfa-secret {
    text-align: center;
    margin-block: var(--cs-col-gap);
}

.cs-tfa-secret code {
    display: inline-block;
    padding: calc(var(--cs-col-gap) * 0.6) var(--widget-padding);
    border: var(--cs-outline);
    border-radius: var(--cs-radius-sm);
    background: var(--color-bg);
    color: var(--color-text);
    font-size: 15px;
    letter-spacing: .12em;
    word-break: break-all;
}

/* Toast variants */
.cs-toast-success .cs-toast-icon { color: var(--cs-success); }
.cs-toast-error .cs-toast-icon { color: var(--color-removed); }
.cs-toast-error { border-color: var(--color-removed); }

/* Flash notices are re-rendered as toasts by theme.js. Hide them up front so
   they never paint first; the `cs-js` class is set in <head> and removed again
   if theme.js fails to run, so a script-less visitor still sees the message.
   Warning/info notices are standing state, so they are left alone. */
html.cs-js .notice-success,
html.cs-js .notice-error { display: none; }
