:root,
[data-theme='default'] {
    /* Shell palette — the default dark theme (black / blue / white, high
       contrast). Mirrors /base.css `:root` exactly; /theme.css overrides the
       colour tokens per theme. The `[data-theme='default']` arm lets the worlds
       game force this palette on its own panel even when the site is themed. */
    --bg: #000000;
    --surface: #0a0a0c;
    --surface-2: #121216;
    --surface-3: #1c1c22;
    --border: #2e2e38;
    --border-strong: #45454f;
    --text: #f5f5f7;
    --text-strong: #ffffff;
    --dim: #9a9aa8;
    --dimmer: #66666f;
    --accent: #3b82f6;
    --accent-soft: #10233f;
    /* The accent as TEXT — mirrors /base.css :root exactly (theme.css tunes it per
       theme so it clears 4.5:1 on a surface). */
    --accent-fg: #3b82f6;
    --green: #22c55e;
    --green-soft: #08281a;
    --red: #ff5a5a;
    --btn-bg: #0a0a0c;
    --btn-fg: #ffffff;

    /* Layout tokens (theme-independent) — mirrors /base.css `:root` exactly.
       Sizes favour powers of two. */
    --gutter: 16px;
    --content-max: 800px;
    --radius-sm: 8px;
    --radius: 16px;
    --font-mono: 'Ubuntu Mono', 'JetBrains Mono', ui-monospace, 'Consolas', 'Courier New', monospace;
}

body {
    font-family: var(--font-mono);
    font-size: 16px;
    line-height: 1.5;
    margin: 0;
    padding: 0;
    min-height: 100vh;
    background-color: var(--bg);
    color: var(--text);
    display: flex;
    flex-direction: column;
    align-items: center;
}

header {
    background-color: var(--surface);
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
    width: 100%;
    box-sizing: border-box;
    display: flex;
    justify-content: center;
}

/* Header row: nav on the left, the VersuAM wordmark on the top right,
   mirroring versuam.com. .brand itself is defined in /base.css. */
.header-bar {
    max-width: var(--content-max);
    width: 100%;
    padding: 0 var(--gutter);
    box-sizing: border-box;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    flex-wrap: nowrap;
}

/* Top-right cluster: the language selector sits immediately to the left of the
   VersuAM wordmark, so both stay pinned while the nav wraps. It is FIRST in the
   DOM (index.html) and ordered last here, so flex keeps it on the right on wide
   screens while a float can lift it to the top-right on narrow screens (see the
   media query below). */
.brand-col {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 16px;
    flex: 0 0 auto;
    margin-left: auto;
    order: 2;
}

nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start; /* Left align items */
    align-items: center;
    gap: 8px;
    padding: 0;
    flex: 1 1 auto;
    min-width: 0;
    order: 1; /* on wide screens: nav first, brand-col (order: 2) last */
}

/* Nav pills (+ the language selector) are shared chrome: defined once in
   /base.css and reused by the shell and the standalone pages. */

/* Narrow screens: the header is one non-wrapping flex row on desktop, but on a
   phone the fixed-width brand column squeezes the nav into a one-button-wide
   column and leaves the space under the wordmark empty. Drop the header to a
   plain block and float the brand column, so the inline-block nav links flow
   around it — filling the width beside it on the first line and using the full
   width underneath. The nav becomes a plain block here because a flex container
   refuses to wrap under a float (gap is replaced by link margins). */
@media (max-width: 600px) {
    .header-bar {
        display: block;
    }

    .brand-col {
        float: right;
        margin: 0 0 8px 12px;
        gap: 14px;
    }

    nav {
        display: block;
        font-size: 0; /* collapse the whitespace between inline-block links */
    }

    nav a,
    nav button {
        margin: 0 8px 8px 0;
    }
}

.container {
    position: relative;
    padding: var(--gutter);
    max-width: var(--content-max);
    width: 100%;
    box-sizing: border-box;
}

.container p {
    line-height: 1.5;
    font-family: var(--font-mono);
}

/* Home hero: five minimal one-liners that share the container's left edge,
   evenly spaced with a symmetric margin above and below each line. */
#about p {
    margin: 16px 0;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--text);
}

section {
    margin-bottom: 20px;
}

h2 {
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px;
    font-size: 1.8em;
}

.email-button {
    background-color: transparent;
    color: var(--dim);
    border: 1px solid var(--border-strong);
    padding: 8px 14px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-family: inherit;
    font-size: 13px;
    cursor: pointer;
    border-radius: var(--radius-sm);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.email-button:hover {
    color: var(--text-strong);
    border-color: var(--accent);
}

/* Calculator Styles */
.calculator-header {
    text-align: left;
    margin-bottom: 30px;
}

.price-container {
    font-size: 56px;
    font-weight: bold;
    color: var(--accent);
    margin: 10px 0;
}

.calculator-section {
    margin-bottom: 30px;
}

.calculator-section h3 {
    font-size: 18px;
    margin-bottom: 15px;
    opacity: 0.8;
}

.bubble-container {
    display: flex;
    flex-wrap: wrap;
    gap: 15px;
    justify-content: flex-start;
    margin-bottom: 20px;
}

.bubble {
    background-color: transparent;
    color: var(--text-strong);
    border: 1px solid var(--text-strong);
    padding: 8px 18px;
    border-radius: 30px;
    cursor: pointer;
    transition: all 0.2s;
    user-select: none;
    font-size: 16px;
    font-family: var(--font-mono);
}

.bubble.active {
    background-color: var(--text-strong);
    color: var(--bg);
}

.bulk-button {
    background-color: var(--surface-3);
    color: var(--text-strong);
    border: none;
    padding: 8px 15px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 14px;
    font-family: var(--font-mono);
    margin: 0 5px;
    transition: background-color 0.2s;
}

.bulk-button:hover {
    background-color: var(--border-strong);
}

.calculator-section[style*="text-align: center"] {
    text-align: left !important;
}

.slider-container {
    margin-bottom: 25px;
}

.slider-container label {
    display: block;
    margin-bottom: 10px;
    font-size: 16px;
}

.slider-container input[type="range"] {
    width: 100%;
    margin-bottom: 5px;
}

.slider-container span {
    display: block;
    text-align: right;
    font-size: 16px;
    color: var(--accent);
}

.calculator-footer {
    text-align: left;
    margin-top: 40px;
    font-size: 14px;
    opacity: 0.7;
    line-height: 1.6;
}

/* Checkbox and Tooltip Styles */
.checkbox-container {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    font-size: 16px;
    user-select: none;
    gap: 10px;
}

.checkbox-container input {
    cursor: pointer;
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
}

.tooltip {
    position: relative;
    display: inline-block;
}

.tooltip-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    font-size: 14px;
    color: var(--dim);
    margin-left: 5px;
    cursor: help;
}

.tooltip .tooltip-text {
    visibility: hidden;
    width: 220px;
    background-color: var(--surface);
    color: var(--text);
    text-align: left;
    border-radius: var(--radius-sm);
    padding: 10px;
    position: absolute;
    z-index: 1;
    bottom: 125%;
    left: 50%;
    margin-left: -110px;
    opacity: 0;
    transition: opacity 0.3s;
    border: 1px solid var(--border);
    font-size: 14px;
    line-height: 1.4;
    pointer-events: none;
}

.tooltip:hover .tooltip-text {
    visibility: visible;
    opacity: 1;
}

/* The language selector is shared chrome (see /base.css). */

footer {
    background-color: var(--surface);
    padding: 14px 0;
    border-top: 1px solid var(--border);
    width: 100%;
    box-sizing: border-box;
    display: flex;
    justify-content: center; /* Center content horizontally */
    text-align: left;
}

/* Profile links styles */
.profile-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start; /* Left align items */
    gap: 10px;
    max-width: var(--content-max);
    width: 100%;
    padding: 0 var(--gutter);
    box-sizing: border-box;
}

/* Profile links and buttons — same outlined pill as the nav. */
.profile-links a,
.profile-links button {
    background-color: transparent;
    color: var(--dim);
    border: 1px solid var(--border-strong);
    padding: 8px 14px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-family: inherit;
    font-size: 13px;
    cursor: pointer;
    border-radius: var(--radius-sm);
    white-space: nowrap;
    box-sizing: border-box;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.profile-links a:hover,
.profile-links button:hover {
    color: var(--text-strong);
    border-color: var(--accent);
}

/* ========================================================
   Music Player & Queue Styles
   ======================================================== */
.music-section {
    width: 100%;
}

.player-card {
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px;
    margin-bottom: 25px;
    box-sizing: border-box;
}

.player-track-info {
    display: flex;
    align-items: stretch;
    gap: 16px;
    margin-bottom: 18px;
}

/* The right column of the now-playing block: the track details on top, the
   scrubber pinned to the bottom (so it lines up with the cover's bottom edge).
   min-width: 0 keeps the title/artist ellipsis working beside a fixed-width
   cover column. */
.player-column {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

/* The now-playing cover frame: the current song's album art (its own `image`,
   else the bundled default cover). It FILLS the left column of the
   now-playing block — align-self: stretch drops its bottom edge onto the
   block's bottom edge — and pulses while buffering. It no longer spins; the
   spin keyframes below belong to the play button's spinner. */
.track-visual-disc {
    flex: 0 0 auto;
    align-self: stretch;
    width: 104px;
    /* The floor that keeps the frame square (and the row's height stable) for a
       NON-square cover too — the img's own aspect ratio would otherwise decide
       the height. align-self: stretch still grows it past this if the column
       (a wrapped title) is taller, so the bottom edges always coincide. */
    min-height: 104px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background-color: var(--surface-2);
    border: 1px solid var(--border-strong);
}

.track-visual-disc img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Used by .btn-spinner (the play button's buffering spinner). The cover frame
   no longer rotates, so do not delete these keyframes. */
@keyframes spin-disc {
    100% {
        transform: rotate(360deg);
    }
}

.track-visual-disc.loading {
    animation: pulse-disc 1.2s ease-in-out infinite;
}

@keyframes pulse-disc {
    0%,
    100% {
        opacity: 1;
    }
    50% {
        opacity: 0.45;
    }
}

.btn-spinner {
    width: 16px;
    height: 16px;
    border: 2px solid var(--border-strong);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin-disc 0.8s linear infinite;
    display: inline-block;
}

.btn-spinner[hidden] {
    display: none;
}

.track-details {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
}

.track-title {
    font-size: 1.25em;
    font-weight: bold;
    color: var(--text-strong);
    margin-bottom: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.track-artist {
    font-size: 0.9em;
    color: var(--dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.player-timeline {
    display: flex;
    align-items: center;
    gap: 12px;
    /* Inside .player-column now: the 18px gap before the controls is the row's
       own margin-bottom, so the cover's bottom edge stays flush with this. */
    margin-bottom: 0;
    font-size: 12px;
    color: var(--dim);
}

.player-timeline input[type="range"] {
    width: 100%;
    height: 5px;
    accent-color: var(--accent);
    cursor: pointer;
    background: var(--surface-3);
    border-radius: 3px;
}

.seek-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.seek-buffer {
    height: 3px;
    background: var(--surface-3);
    border-radius: 2px;
    overflow: hidden;
}

.seek-buffer-fill {
    display: block;
    height: 100%;
    width: 0%;
    background: var(--accent);
    border-radius: 2px;
    transition: width 0.2s linear;
}

.player-controls {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
}

.control-btn {
    background-color: var(--btn-bg);
    color: var(--text-strong);
    border: 1px solid var(--border);
    border-radius: 50%;
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 15px;
    transition: all 0.2s ease;
    position: relative;
    padding: 0;
}

.control-btn:hover {
    background-color: var(--surface-3);
    border-color: var(--border-strong);
}

.control-btn.play-main-btn {
    width: 52px;
    height: 52px;
    font-size: 20px;
    background-color: var(--surface-3);
    border-color: var(--border-strong);
}

.control-btn.play-main-btn:hover {
    background-color: var(--surface-3);
    border-color: var(--text-strong);
}

.control-btn.active {
    color: var(--accent);
    border-color: var(--accent);
    background-color: var(--accent-soft);
}

.repeat-mode-badge {
    position: absolute;
    bottom: 2px;
    right: 4px;
    font-size: 9px;
    font-weight: bold;
    color: var(--accent);
}

.player-volume {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    font-size: 12px;
    color: var(--dim);
}

.volume-btn {
    background: none;
    border: none;
    color: var(--dim);
    cursor: pointer;
    font-size: 14px;
    padding: 2px;
}

.volume-btn:hover {
    color: var(--text-strong);
}

.player-volume input[type="range"] {
    width: 80px;
    height: 4px;
    accent-color: var(--accent);
    cursor: pointer;
    background: var(--surface-3);
    border-radius: 2px;
}

#volume-percent {
    min-width: 32px;
    font-size: 11px;
    text-align: right;
}

/* Pitch Control */
.pitch-control {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--dim);
}

.pitch-label {
    font-size: 12px;
    color: var(--dim);
}

.pitch-stepper {
    display: flex;
    align-items: center;
    gap: 2px;
}

.pitch-btn {
    background-color: var(--btn-bg);
    color: var(--dim);
    border: 1px solid var(--border);
    border-radius: 4px;
    width: 22px;
    height: 22px;
    line-height: 1;
    padding: 0;
    cursor: pointer;
    font-size: 14px;
    font-family: var(--font-mono);
    transition: all 0.15s;
}

.pitch-btn:hover:not(:disabled) {
    color: var(--text-strong);
    border-color: var(--border-strong);
}

.pitch-btn:disabled {
    opacity: 0.35;
    cursor: default;
}

#pitch-value {
    /* widest value is "-12"/"+12": a fixed 2-digit slot + the sign */
    width: 2.6ch;
    font-size: 12px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    color: var(--dim);
}

.pitch-control.active .pitch-label,
.pitch-control.active #pitch-value {
    color: var(--accent);
}

/* Stem Toggle Controls */
.stem-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 12px;
    font-family: var(--font-mono);
}

.stem-label {
    font-size: 12px;
    color: var(--dim);
    margin-right: 4px;
}

.stem-btn {
    background-color: var(--btn-bg);
    color: var(--dim);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 5px 12px;
    cursor: pointer;
    font-size: 12px;
    font-family: var(--font-mono);
    transition: all 0.15s;
}

.stem-btn.active {
    color: var(--text-strong);
    border-color: var(--accent);
    background-color: var(--accent-soft);
}

.stem-btn:active {
    background-color: var(--surface-3);
    border-color: var(--border-strong);
    color: var(--text-strong);
}

/* Synced Lyrics Display (player/lyrics.js): one line at a time — the main
   lyric on top, the translation beneath at the same size but dimmed. */
.lyrics-display {
    margin-top: 12px;
    text-align: center;
    font-family: var(--font-mono);
    line-height: 1.5;
}

.lyrics-line-main {
    font-size: 1.05em;
    color: var(--text-strong);
}

.lyrics-line-trans {
    font-size: 1.05em;
    opacity: 0.8;
    color: var(--text);
}

/* Playlist & Queue Containers */
.playlist-container {
    margin-top: 20px;
    margin-bottom: 20px;
}

.section-subhead {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--border);
    padding-bottom: 8px;
    margin-bottom: 12px;
}

.clickable-header {
    cursor: pointer;
    user-select: none;
    transition: opacity 0.15s ease;
}

.clickable-header:hover h3 {
    color: var(--text-strong);
}

.title-with-badge {
    display: flex;
    align-items: center;
    gap: 8px;
}

.section-subhead h3 {
    margin: 0;
    font-size: 1.05em;
    color: var(--text);
}

.badge-count {
    font-size: 11px;
    color: var(--dimmer);
    font-weight: normal;
}

/* Title + inline count. `flex: 0 0 auto` keeps the intrinsic width so the
   count is never orphaned onto its own line inside the flex header; the queue
   controls (which are allowed to wrap) absorb the squeeze instead. */
.catalog-title {
    margin: 0;
    font-size: 1.05em;
    color: var(--text);
    font-weight: 600;
    display: block;
    line-height: 1.4;
    flex: 0 0 auto;
}

.catalog-title .badge-count {
    margin-left: 6px;
    font-size: 11px;
    color: var(--dimmer);
    font-weight: normal;
}

.toggle-arrow {
    font-size: 10px;
    color: var(--dim);
    margin-left: 2px;
    transition: transform 0.2s ease;
}

.queue-collapsible {
    /* No fixed max-height: the panel grows to fit every item and the page
       scrolls (player/collapsible.js animates max-height inline). A fixed cap
       here clipped long queues with no scrollbar. */
    overflow: hidden; /* clip during the open/close tween */
    transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease;
    opacity: 1;
}

.queue-collapsible.collapsed {
    max-height: 0; /* initial state before JS sets an inline height */
    opacity: 0;
    pointer-events: none;
    margin: 0;
}

/* Search Bar */
.search-bar-wrap {
    position: relative;
    display: flex;
    align-items: center;
    margin-bottom: 12px;
}

.search-input {
    width: 100%;
    background-color: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-strong);
    padding: 9px 36px 9px 12px;
    font-family: var(--font-mono);
    font-size: 13px;
    box-sizing: border-box;
    outline: none;
    transition: border-color 0.2s, background-color 0.2s;
}

.search-input:focus {
    border-color: var(--border-strong);
    background-color: var(--surface-3);
}

.search-input::placeholder {
    color: var(--dimmer);
}

.search-clear-btn {
    position: absolute;
    right: 10px;
    background: none;
    border: none;
    color: var(--dim);
    font-size: 12px;
    cursor: pointer;
    padding: 4px;
}

.search-clear-btn:hover {
    color: var(--text-strong);
}

.mini-btn {
    background-color: var(--btn-bg);
    color: var(--dim);
    border: 1px solid var(--border);
    padding: 4px 10px;
    font-size: 11px;
    font-family: var(--font-mono);
    cursor: pointer;
    border-radius: 4px;
    transition: all 0.2s;
}

.mini-btn:hover {
    color: var(--text-strong);
    border-color: var(--border-strong);
    background-color: var(--surface-3);
}

/* ---------- Catalog voice filters ---------- */
.catalog-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.queue-label {
    font-size: 12px;
    color: var(--dim);
    font-family: var(--font-mono);
    margin-right: 2px;
    white-space: nowrap;
}

.voice-menu-wrap {
    position: relative;
    display: inline-block;
}

.voice-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 6px;
    z-index: 20;
    min-width: 120px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}

.voice-menu[hidden] {
    display: none;
}

.voice-menu .mini-btn {
    width: 100%;
    text-align: left;
    justify-content: flex-start;
}

.queue-list, .catalog-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.queue-item, .catalog-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 9px 12px;
    background-color: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-sizing: border-box;
    transition: background 0.15s, border-color 0.15s;
}

.queue-item:hover, .catalog-item:hover {
    background-color: var(--surface-3);
    border-color: var(--border-strong);
}

.queue-item.active {
    background-color: var(--green-soft);
    border-color: var(--green);
}

.catalog-item.active {
    border-left: 3px solid var(--green);
}

/* Catalog multi-select (add to playlist; see player/commands.js + render.js) */
.select-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 12px;
    padding: 8px 12px;
    background-color: var(--surface-2);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
}

.select-bar[hidden] {
    display: none;
}

.catalog-item.selected {
    background-color: var(--accent-soft);
    border-color: var(--accent);
}

.catalog-item.selected .select-mark {
    color: var(--accent);
    font-weight: bold;
}

.item-left {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    cursor: pointer;
    overflow: hidden;
}

.item-index {
    font-size: 12px;
    color: var(--dimmer);
    min-width: 20px;
}

.item-status {
    font-size: 12px;
    color: var(--green);
    width: 14px;
    text-align: center;
}

.item-info {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.item-title {
    font-size: 13px;
    color: var(--text-strong);
    font-weight: bold;
    text-overflow: ellipsis;
    overflow: hidden;
}

.item-artist {
    font-size: 11px;
    color: var(--dimmer);
    text-overflow: ellipsis;
    overflow: hidden;
}

.item-actions {
    display: flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
}

.icon-action-btn {
    background: var(--btn-bg);
    border: 1px solid var(--border);
    color: var(--dim);
    border-radius: 4px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 11px;
    padding: 0;
    font-family: var(--font-mono);
    text-decoration: none;
    transition: all 0.15s;
}

.icon-action-btn:hover:not(:disabled) {
    color: var(--text-strong);
    border-color: var(--border-strong);
    background-color: var(--surface-3);
}

.icon-action-btn:disabled {
    opacity: 0.2;
    cursor: default;
}

.icon-action-btn.delete-btn:hover:not(:disabled) {
    color: var(--red);
    border-color: var(--red);
}

.icon-action-btn.download-btn:hover:not(:disabled) {
    color: var(--accent);
    border-color: var(--accent);
}

.icon-action-btn.share-btn:hover:not(:disabled) {
    color: var(--green);
    border-color: var(--green);
}

/* A playlist that already has a share link keeps the share button lit. */
.icon-action-btn.share-btn.shared {
    color: var(--green);
    border-color: var(--green);
}

.action-btn {
    background: var(--btn-bg);
    border: 1px solid var(--border);
    color: var(--text-strong);
    border-radius: 4px;
    padding: 5px 10px;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 11px;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
}

.action-btn:hover {
    background: var(--surface-3);
    border-color: var(--border-strong);
}

.action-btn.add-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
}

.action-btn.download-btn {
    color: var(--dim);
    font-size: 12px;
    padding: 5px 8px;
}

.action-btn.download-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
}

.action-btn.share-btn {
    color: var(--dim);
    font-size: 12px;
    padding: 5px 8px;
}

.action-btn.share-btn:hover {
    color: var(--green);
    border-color: var(--green);
}

.empty-state {
    padding: 20px;
    text-align: center;
    color: var(--dimmer);
    font-size: 12px;
    font-style: italic;
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
}

/* ---------- Playlists ---------- */
.playlists-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/* Playlist rows reuse the .queue-item look (class="queue-item playlist-item"). */
.playlist-item .item-info {
    min-width: 0;
}

.playlist-item .playlist-count {
    min-width: 22px;
    text-align: center;
    color: var(--accent);
    font-weight: bold;
}

.playlist-item .playlist-name {
    max-width: 100%;
}

/* Mobile Optimizations */
@media (max-width: 600px) {
    .player-card {
        padding: 14px;
        margin-bottom: 18px;
    }

    .track-visual-disc {
        width: 76px;
        min-height: 76px;
    }

    .track-title {
        font-size: 1.1em;
    }

    .player-controls {
        gap: 8px;
    }

    .control-btn {
        width: 38px;
        height: 38px;
        font-size: 13px;
    }

    .control-btn.play-main-btn {
        width: 48px;
        height: 48px;
        font-size: 18px;
    }

    .player-volume input[type="range"] {
        width: 65px;
    }

    .item-actions {
        gap: 4px;
    }

    .action-btn {
        padding: 4px 8px;
        font-size: 10px;
    }

    .action-btn.download-btn {
        padding: 4px 6px;
    }
}
/* ---------- View switching (single-page shell) ---------- */
.view { display: none; }
html[data-view="home"] #view-home,
html[data-view="commission"] #view-commission,
html[data-view="music"] #view-music,
html[data-view="support"] #view-support { display: block; }
/* nav a.active-nav lives in /base.css (shared chrome). */

/* ---------- Persistent mini player ---------- */
.mini-player {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background-color: var(--surface);
    border-top: 1px solid var(--border);
    padding: 8px 12px;
    z-index: 50;
}
.mini-player[hidden] { display: none; }
html[data-view="music"] .mini-player { display: none; }
.mini-player-btn {
    background-color: var(--btn-bg);
    color: var(--text-strong);
    border: none;
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 14px;
}
.mini-player-btn:hover { background-color: var(--surface-3); }
.mini-title {
    color: var(--text);
    font-size: 14px;
    font-family: var(--font-mono);
    max-width: 60%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    cursor: pointer;
}
body.has-mini { padding-bottom: 56px; }

/* ---------- Mini player extras (shuffle / repeat / mute) ---------- */
.mini-player-btn { position: relative; }
.mini-player-btn.active { color: var(--accent); border: 1px solid var(--accent); background-color: var(--accent-soft); }
.mini-player-btn.active:hover { background-color: var(--accent-soft); }
.mini-repeat-badge {
    position: absolute;
    bottom: 0;
    right: 3px;
    font-size: 9px;
    font-weight: bold;
    color: var(--accent);
}

/* ---------- Small-screen polish ---------- */
@media (max-width: 600px) {
    .container { padding: var(--gutter); }
    .mini-player { gap: 6px; padding: 6px 8px; flex-wrap: wrap; }
    .mini-player-btn { padding: 5px 9px; font-size: 13px; }
    .mini-title { max-width: 100%; flex-basis: 100%; text-align: center; font-size: 12px; }
    .player-controls { flex-wrap: wrap; }
    .player-volume { flex-wrap: wrap; }
    .pitch-control { flex-wrap: wrap; }
    .stem-controls { flex-wrap: wrap; }
    .player-timeline input[type="range"] { min-width: 0; }
    .track-details { min-width: 0; }
    .item-actions { flex-wrap: wrap; justify-content: flex-end; }
    .tooltip .tooltip-text { width: auto; max-width: 78vw; left: auto; right: 0; margin-left: 0; }
    .voice-menu { right: auto; left: 0; }

    /* Keep the catalog header on one row: title on the left (it may wrap
       internally), queue controls pinned to the right edge. */
    .section-subhead {
        display: flex;
        justify-content: space-between;
        align-items: center;
        flex-wrap: nowrap;
        gap: 8px;
    }

    .catalog-actions {
        margin-left: auto;
        display: flex;
        align-items: center;
        gap: 6px;
        flex-wrap: wrap;
        justify-content: flex-end;
    }

    .queue-label {
        font-size: 12px;
        color: var(--dim);
        white-space: nowrap;
    }

    /* Playlists: keep the header buttons on the right and let the row actions
       drop to their own line instead of overflowing horizontally. */
    .playlists-actions {
        margin-left: auto;
        flex-wrap: wrap;
        justify-content: flex-end;
    }

    .playlist-item {
        flex-wrap: wrap;
        gap: 6px;
    }

    .playlist-item .item-actions {
        margin-left: auto;
    }

    .playlist-item .item-info {
        max-width: 55vw;
    }
}

/* ---------- Support view ---------- */
.support-content { padding: 8px 0 16px; }

.support-content > p {
    margin: 0 0 24px;
    line-height: 1.6;
    color: var(--text);
}

.support-note {
    color: var(--dim);
    font-size: 12px;
    line-height: 1.5;
    margin: 0 0 6px;
}

.support-note:last-child { margin-bottom: 0; }

.support-section {
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    margin-bottom: 18px;
    box-sizing: border-box;
}

.support-section h3 {
    margin: 0 0 14px;
    font-size: 1.05em;
    color: var(--text);
}

.support-link {
    display: inline-block;
    background-color: var(--accent);
    color: #fff;
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    padding: 9px 16px;
    font-size: 14px;
    font-weight: 700;
    text-decoration: none;
    transition: opacity 0.15s ease;
}

.support-link:hover {
    opacity: 0.9;
    color: #fff;
}

.crypto-block {
    background-color: var(--surface-2);
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
    margin-bottom: 14px;
}

.crypto-block p {
    margin: 0 0 10px;
    font-size: 13px;
    color: var(--text);
    line-height: 1.5;
    word-break: break-all;
}

.crypto-block p:last-child {
    margin-bottom: 0;
    color: var(--dim);
    font-size: 12px;
}

.copy-btn {
    display: inline-block;
    margin-left: 8px;
    vertical-align: middle;
    background-color: var(--btn-bg);
    color: var(--dim);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 3px 9px;
    font-family: var(--font-mono);
    font-size: 11px;
    cursor: pointer;
    transition: all 0.15s ease;
}

.copy-btn:hover {
    color: var(--text-strong);
    border-color: var(--border-strong);
    background-color: var(--surface-3);
}

.copy-btn.copied {
    color: var(--green);
    border-color: var(--green);
}
/* ---------- Chat view (the successor of the feedback form; site/pages/chat.js) ---------- */
html[data-view="chat"] #view-chat { display: block; }

/* The shared view-content wrapper (feedback history + the chat page). */
.feedback-content,
.chat-content {
    padding: 8px 0 16px;
}

.feedback-content > p,
.chat-content > p {
    margin: 0 0 24px;
    line-height: 1.6;
    color: var(--text);
}

/* Shared with the /chat page (site/pages/chat.js): the composer's status line and
   the honeypot field. The old feedback form's own rules (the 💞 rating picker, the
   submit button, the screenshot preview, the submission history) are gone with it. */
.feedback-status { font-size: 13px; min-height: 17px; word-break: break-word; }
.feedback-status.ok { color: var(--green); }
.feedback-status.err { color: var(--red); }

.feedback-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- The chat with versutus (site/pages/chat.js) ----------
   The page reuses the worlds chat chrome (.worlds-chat-* / .comment-*) loaded
   from worlds.css; these rules are only the page-level layout. The chat bar's
   own shape is the `.worlds-chat-embedded .worlds-chatbar` modifier in
   worlds.css; the log override below carries an extra class because worlds.css
   loads AFTER styles.css. The shared .chat-time / .chat-presence / .comment-*
   bits live in base.css. */
.chat-content { max-width: 720px; margin: 0 auto; }
/* The card itself: a little more air than the game's drawer it borrows its chrome from, so
   the header / log / composer read as three distinct bands. */
.chat-content .worlds-chatbar {
    padding: 12px;
    gap: 10px;
}
.chat-content .worlds-chatbar .worlds-chat-log {
    min-height: 320px;
    max-height: min(58vh, 560px);
    /* `dvh` follows a phone's collapsing URL bar; the `vh` line above is the fallback. */
    max-height: min(58dvh, 560px);
    /* The conversation sits on the PAGE colour inside the raised card — that contrast is
       what makes the card read as a chat window rather than a form. */
    background-color: var(--bg);
    padding: 10px;
    /* A row being swiped to reply slides LEFT into this padding: clip the horizontal axis so
       the gesture can never make the log pan sideways (the vertical scroll is untouched). */
    overflow-x: hidden;
    /* The log is its own scroll container: never chain a scroll into the page behind it. */
    overscroll-behavior: contain;
}
/* The composer stays BELOW the log on a phone too — the desktop order. worlds.css
   re-orders the bar's children inside the GAME window (the `.worlds-phone` class,
   set from a phone test the text size cannot defeat — see docs/GOTCHAS.md) for its
   drawer, which drops from the TOP so the on-screen keyboard can never cover
   its input (see docs/features/worlds.md -> "Chat is its own panel"); this page is
   not that drawer: the log is what the fan reads, so the input belongs under it,
   with the newest message right above the box they are typing in instead of behind
   the keyboard. The extra class out-specifies worlds.css's own phone rule whatever
   the load order — the same trick the log's height above uses. */
.chat-content .worlds-chatbar .worlds-chat-form,
.chat-content .worlds-chatbar .worlds-chat-log,
.chat-content .worlds-chatbar .worlds-typing { order: 0; }
/* The composer's field is the one thing a fan touches every time: worlds.css drops its
   outline on `:focus` and recolours only the border, so this adds a soft ring back (the
   border alone is a 1px change on a dark surface). */
.chat-content .worlds-chat-input:focus { box-shadow: 0 0 0 2px var(--accent-soft); }
/* The card's header: who you are talking to (left) and the conversation's tools (right),
   with a hairline under it separating the chrome from the log. It WRAPS rather than
   squeezing the figure and the ⛶ off a phone's screen. */
.chat-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    min-height: 26px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}
.chat-head-tools {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
    margin-left: auto;
    min-width: 0;
}
/* The spend line is the OWNER's bill for this conversation, so it is dim small print and
   it never wraps the header; the "what is this?" words beside it say the rest. */
.chat-spend {
    font-size: 11px;
    color: var(--dim);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* Every band of the card keeps its height; ONLY the log grows and scrolls. Without this a
   constrained card — fullscreen on a phone, the on-screen keyboard open — squeezed the
   header to its `min-height` and its tools spilled out UNDER the log (the fullscreen ⛶ sat
   on top of the first message). */
.chat-content .worlds-chatbar > .chat-head,
.chat-content .worlds-chatbar > .chat-spend-wrap,
.chat-content .worlds-chatbar > .chat-subhead,
.chat-content .worlds-chatbar > .chat-attach,
.chat-content .worlds-chatbar > .chat-quote-bar,
.chat-content .worlds-chatbar > .worlds-chat-form,
.chat-content .worlds-chatbar > .worlds-typing,
.chat-content .worlds-chatbar > #chat-turnstile,
.chat-content .worlds-chatbar > .feedback-status,
.chat-content .worlds-chatbar > .chat-signin { flex: 0 0 auto; }
.chat-content .worlds-chatbar > .worlds-chat-log { flex: 1 1 auto; }
/* The cost line is its OWN band (markup in index.html): a whole sentence beside the ⛶ was
   what pushed the figure under the button on a phone. It reads as one dim meta line, and
   the two parts wrap together rather than overflowing. */
.chat-spend-wrap {
    position: relative;
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
    min-width: 0;
}
.chat-spend-info {
    background: none;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: 11px;
    color: var(--accent-fg);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
    touch-action: manipulation;
}
.chat-spend-info:hover { color: var(--text-strong); }
/* The "what is this?" card (index.html -> #chat-spend-pop): a NON-modal card anchored
   under the figure it explains — the page behind it stays usable. It must stay readable
   on a phone, so it is capped to the viewport, scrolls on its own and contains its
   scroll (never the page's). */
.chat-spend-pop {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 30;
    width: min(320px, calc(100vw - 32px));
    max-height: min(60vh, 320px);
    overflow: auto;
    overscroll-behavior: contain;
    padding: 8px 10px 9px;
    background: var(--surface-3);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
    font-size: 12px;
    line-height: 1.55;
    color: var(--text);
    text-align: left;
}
/* The card has NO heading (the owner wants the sentence alone), so the ✕ floats in the
   top-right corner instead of holding a header ROW: a flex row there would leave an empty
   strip above the words, which is exactly the space the removed heading used to take. The
   paragraph keeps a matching right inset, so its first line never runs under the ✕. */
.chat-spend-pop-head { position: absolute; top: 3px; right: 3px; }
.chat-spend-pop p { margin: 0; padding-right: 18px; }
.chat-spend-pop-close {
    flex: 0 0 auto;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 12px;
    line-height: 1;
    padding: 2px 5px;
    cursor: pointer;
    touch-action: manipulation;
}
.chat-spend-pop-close:hover { color: var(--text-strong); border-color: var(--border-strong); }
/* The header's one-glyph controls (today the ⛶): the .chat-attach-btn chip, squared, so
   the glyph is centred. The site has no page-wide focus rule, so the ring is spelled out
   below — and a tap is a tap (no double-tap-zoom delay). */
.chat-tool {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background-color: var(--surface-3);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    padding: 0;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}
.chat-tool:hover { color: var(--text-strong); border-color: var(--accent); }
.chat-tool-on { color: var(--text-strong); border-color: var(--accent); background-color: var(--accent-soft); }
.chat-tool:focus-visible,
.chat-spend-info:focus-visible,
.chat-spend-pop-close:focus-visible,
.chat-attach-btn:focus-visible,
.chat-attach-remove:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* The second header band: the anonymous budget on the left, the auto-translate switch on
   the right. Both are small print, so they share one dim row. */
.chat-subhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    min-height: 14px;
}
.chat-remaining { font-size: 11px; color: var(--dim); text-align: right; }
.chat-remaining:empty { display: none; }
/* The fan's OWN auto-translate switch (site/pages/chat.js -> #chat-auto-label). It stays
   `hidden` for an anonymous visitor (there is no account to remember it on), and a flex
   display would override that, so [hidden] is spelled out — the same rule .worlds-typing
   and the picker carry. */
.chat-auto {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0 0;
    font-size: 11px;
    color: var(--dim);
    cursor: pointer;
}
.chat-auto[hidden] { display: none; }
.chat-auto input { accent-color: var(--accent); }
/* The `yyyy-mm-dd hh:mm:ss` stamp, pushed to the right of the name + badges. */
.chat-row .who { display: flex; align-items: center; gap: 4px; min-width: 0; }
.chat-row .worlds-chat-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A message THIS page has just sent, before the server has answered: the row is painted
   optimistically (see docs/features/chat.md -> "The /chat page"), so it carries its own
   small note — dim while the send is in flight, red once it is known to have failed. */
.chat-own-note { font-size: 11px; color: var(--dim); margin-top: 2px; }
.chat-own-note.err { color: var(--red); }
.chat-row-pending .worlds-chat-text { opacity: 0.65; }
.chat-row-failed .worlds-chat-text { color: var(--red); }
.chat-signin { font-size: 12px; color: var(--dim); }
.chat-signin a { color: var(--accent-fg); }
/* The anonymous retention note (site/pages/chat.js -> #chat-anon-keep, built from the
   server's `anonDays`): one dim line under the header bands, never shown to an account. */
.chat-anon-keep { font-size: 11px; color: var(--dim); margin: 0 0 2px; }
/* The intro is the log's FIRST row — a real message from versutus (site/pages/chat.js ->
   mountIntro) — so it wears the same row chrome as a message, separated by a dashed rule:
   it is the page's front door, not a paragraph above the card and not a stored message. */
.chat-intro-row { padding-bottom: 10px; border-bottom: 1px dashed var(--border); }
.chat-intro-tag {
    flex: 0 0 auto;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--dim);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0 6px;
    line-height: 1.5;
}
.chat-intro-text { line-height: 1.6; }
/* The QQ fan groups the owner publishes, INSIDE the intro message
   (site/pages/chat.js -> #chat-groups, filled from GET /api/chat/config). ONE dim line,
   and the numbers are the whole point of it, so they get the tabular figures. */
.chat-groups {
    margin-top: 8px;
    font-size: 12px;
    color: var(--dim);
    font-variant-numeric: tabular-nums;
    word-break: break-word;
}
/* ---- replying to ONE message (site/pages/chat.js -> the swipe + the row's ↩) ---- */
/* A row can be swiped LEFT to answer it. `pan-y` hands the vertical scroll back to the
   browser (the log IS a scroller, so a reply gesture must never trap it) and keeps the
   horizontal gesture for us; `pinch-zoom` keeps the page zoomable, which plain `pan-y`
   would switch off. The row is a positioning context for the ↩ the swipe reveals. */
.chat-row { position: relative; touch-action: pan-y pinch-zoom; }
.chat-row.chat-swiping { transition: none; user-select: none; }
/* The snap-back after a release (or the settle of an armed quote): one short ease out, and
   no motion at all for a reader who asked for none. */
.chat-row.chat-swipe-settle { transition: transform 0.18s ease-out; }
@media (prefers-reduced-motion: reduce) {
    .chat-row.chat-swipe-settle { transition: none; }
}
/* The ↩ a swipe reveals, pinned in the gap the row leaves behind: the row slides, this
   counter-slides with the same transform, so it reads as a fixed target at the right edge
   (a glyph that travelled with the message would look like part of its text). It scales and
   fades with the travel, and fills in once the quote is ARMED (the commit point). */
.chat-swipe-hint {
    position: absolute;
    top: calc(50% - 15px);
    right: 4px;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border-strong);
    border-radius: 50%;
    background: var(--surface-2);
    color: var(--accent-fg);
    font-size: 13px;
    line-height: 1;
    opacity: 0;
    pointer-events: none;
    will-change: transform, opacity;
}
.chat-swipe-hint.chat-swipe-armed { border-color: var(--accent); background: var(--surface-3); }
/* The row's ↩ chip is the MOUSE / KEYBOARD half of the same gesture (the swipe is the
   phone's). It stays out of the way until the row is hovered or something in it has focus,
   and a device with NO fine pointer at all (a phone: any-hover none AND any-pointer coarse)
   hides it outright - a touch screen has no hover, so an invisible chip would only be a
   small dead spot beside the 🗑. An iPad WITH a trackpad keeps it, because any-pointer then
   reports a fine pointer, and a keyboard user needs this route to a reply. */
.chat-row .chat-reply { opacity: 0; transition: opacity 0.12s, color 0.15s; }
.chat-row:hover .chat-reply,
.chat-row:focus-within .chat-reply { opacity: 1; }
@media (any-hover: none) and (any-pointer: coarse) {
    .chat-row .chat-reply { display: none; }
}

/* A phone's first screen belongs to the CONVERSATION: the log never reserves more than half
   the viewport, so the composer lands on the same screen as the newest message instead of
   below the fold. Scoped with :not(.chat-fs) so the fullscreen rules below still win — this
   page's fullscreen log fills the height by design. */
@media (max-width: 600px) {
    .chat-content .worlds-chatbar { padding: 10px; gap: 8px; }
    .chat-content:not(.chat-fs) .worlds-chatbar .worlds-chat-log {
        min-height: 180px;
        max-height: min(50dvh, 420px);
    }
}

/* ---------- Fullscreen (the ⛶ in the card's header) ----------
   A CSS pin, NOT the Fullscreen API: iPhone Safari has no Element.requestFullscreen for a
   non-video element (the worlds game keeps the same fallback — see worlds.css), so one
   behaviour ships for every device. The card covers the page, its log takes whatever
   height is left, and `html.chat-fs-open` locks the page scroll behind it. The safe-area
   insets keep the composer off a notch / a home bar, and the pinned box is sized by
   `inset` alone (see the card rule below). */
.chat-content.chat-fs {
    position: fixed;
    inset: 0;
    z-index: 200;
    max-width: none;
    margin: 0;
    padding: 0;
    background-color: var(--bg);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* The card fills the pinned box edge to edge and carries the safe-area insets as its OWN
   padding, so the composer clears a home bar / notch and no strip of page background is
   left under it. `inset: 0` alone sizes the box: an extra `height: 100dvh` can be SHORTER
   than the fixed containing block while a phone's URL bar is showing, which is exactly what
   left the empty band at the bottom. */
.chat-content.chat-fs .worlds-chatbar {
    flex: 1 1 auto;
    width: min(920px, 100%);
    max-width: 100%;
    margin: 0 auto;
    min-height: 0;
    border-top: none;
    border-bottom: none;
    border-radius: 0;
    padding: calc(10px + env(safe-area-inset-top)) calc(12px + env(safe-area-inset-right))
        calc(6px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left));
}
.chat-content.chat-fs .worlds-chat-log {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}
html.chat-fs-open,
html.chat-fs-open body { overflow: hidden; }

/* The optional screenshot on a chat message (site/pages/chat.js): the attach label,
   the downscaled preview and the remove button, then the picture inside a row. The
   same look the old feedback form's .feedback-image-* rules had. */
.chat-attach {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 0;
}
.chat-attach-btn {
    background-color: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-size: 12px;
    padding: 5px 10px;
    cursor: pointer;
}
.chat-attach-btn:hover { border-color: var(--accent); }
.chat-attach-meta { font-size: 12px; color: var(--dim); }
.chat-attach-remove {
    background: none;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 11px;
    padding: 3px 10px;
    cursor: pointer;
}
.chat-attach-remove:hover { color: var(--red); border-color: var(--red); }
.chat-attach-thumb {
    max-width: 120px;
    max-height: 120px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--surface-2);
}
.chat-attach-open { display: inline-block; margin-top: 6px; }
.chat-attach-img {
    display: block;
    max-width: min(320px, 100%);
    max-height: 320px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--surface-2);
}


/* ---------- Blog view ---------- */
html[data-view="blog"] #view-blog { display: block; }

.blog-content { padding: 8px 0 16px; }
.blog-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin: 0 0 16px;
}
.blog-title { font-size: 18px; margin: 0; color: var(--text-strong); }
.blog-head .search-bar-wrap { flex: 1 1 220px; max-width: 360px; }
.blog-list { display: flex; flex-direction: column; }

/* Each post reuses the per-song comment layout (.comment-item / .comment-avatar
   / .comment-main), so only the post-specific bits are styled here. */
.blog-post-title { font-size: 15px; margin: 0 0 4px; color: var(--text-strong); }
.blog-body { color: var(--text); white-space: pre-wrap; word-break: break-word; }
/* Collapsed by default: clamp the body to a short preview until "read more". */
.blog-item.collapsed .blog-body {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.blog-quote {
    margin: 6px 0;
    padding: 6px 10px;
    border-left: 2px solid var(--border-strong);
    color: var(--dim);
    white-space: pre-wrap;
    word-break: break-word;
    font-size: 12px;
}
.blog-langs { color: var(--dimmer); font-size: 11px; }
.blog-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 8px; }
.blog-act {
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 12px;
    padding: 4px 10px;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.blog-act:hover { color: var(--text-strong); border-color: var(--accent); }
.blog-act.liked { color: var(--red); border-color: var(--red); }
.blog-act:disabled { opacity: 0.5; cursor: default; }
.blog-comments { margin-top: 10px; border-top: 1px solid var(--border); }
.blog-more-wrap { margin-top: 16px; text-align: center; }
.blog-status { font-size: 12px; min-height: 16px; margin-top: 10px; color: var(--red); }
.blog-status.ok { color: var(--green); }
.blog-status a { color: var(--accent); }
.blog-empty { color: var(--dimmer); font-size: 13px; padding: 14px 0; }


/* ---------- Games view (lazy, client-only mini-games). The game app is
   imported on demand by site/pages/games.js; see public/js/games/. The worlds
   tab's own rules live in /worlds.css (linked by index.html). ---------- */
html[data-view="games"] #view-games { display: block; }
.games-content { max-width: 560px; margin: 0 auto; }
.games-status { color: var(--dim); font-size: 13px; min-height: 18px; margin: 10px 0; }
.games-tabs { display: flex; gap: 8px; margin-bottom: 16px; }
.games-tab {
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 12px;
    padding: 7px 14px;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}
.games-tab:hover { color: var(--text-strong); border-color: var(--accent); }
.games-tab.active-nav { background: var(--accent-soft); border-color: var(--accent); color: var(--text-strong); }
.game-panel-inner {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: flex-start;
    /* The over-map control scale (the two joysticks + the thumb ring / its
       buttons): fitCanvas() sets the LIVE value on `.worlds-canvas-wrap` from the
       map's rendered size vs the world's native 512x1024, so the controls shrink
       with a smaller (non-fullscreen) map while keeping the same relative spots.
       1 = the design size. This default covers the lobby, where there is no map
       and the 💬 FAB floats over the page. */
    --worlds-ui-scale: 1;
}
.game-status { color: var(--text); font-size: 13px; min-height: 18px; }
.game-score { color: var(--dim); font-size: 12px; }

/* Tic-tac-toe (3x3 hotseat) */
.ttt-grid { display: grid; grid-template-columns: repeat(3, 64px); gap: 6px; }
.ttt-cell {
    width: 64px;
    height: 64px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-strong);
    font-family: inherit;
    font-size: 28px;
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}
.ttt-cell:hover:enabled { border-color: var(--accent); }
.ttt-cell:disabled { cursor: default; }
.ttt-cell.x { color: var(--accent); }
.ttt-cell.o { color: var(--green); }

/* Gomoku (15x15, local hotseat + online). The cell size is viewport-relative so
   all 15 columns + their 2px gaps fit a phone in one row (the games column is
   560px, so the clamp's 30px cap already covers the desktop end). */
.gomoku-grid {
    --gomoku-cell: clamp(16px, 5.4vw, 30px);
    display: grid;
    grid-template-columns: repeat(15, var(--gomoku-cell));
    gap: 2px;
}
.gomoku-cell {
    width: var(--gomoku-cell);
    height: var(--gomoku-cell);
    padding: 0;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 2px;
    color: var(--text-strong);
    font-family: inherit;
    font-size: calc(var(--gomoku-cell) * 0.62);
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}
.gomoku-cell:hover:enabled { border-color: var(--accent); }
.gomoku-cell:disabled { cursor: default; }
.gomoku-cell.x { color: var(--accent); }
.gomoku-cell.o { color: var(--green); }
/* The newest stone, outlined — a 15x15 board is big enough to miss a move. */
.gomoku-grid .last { border-color: var(--text-strong); }

/* Nudge mode: a parked stone is a GHOST — faded and dashed — so it never reads as
   played; its X/O colour still comes from the cell's .x / .o class. The
   `touch-action: none` on the pending cell is what lets it be dragged without the
   page scrolling under the finger (a gesture's touch-action is fixed where it
   starts), and `nudging` keeps the whole grid from selecting text meanwhile. */
.gomoku-cell.pending {
    border-style: dashed;
    border-color: currentColor;
    opacity: 0.55;
    cursor: grab;
    touch-action: none;
    -webkit-touch-callout: none;
}
.gomoku-cell.pending:hover:enabled { border-color: currentColor; }
.gomoku-cell.pending:active { cursor: grabbing; }
.gomoku-grid.nudging { touch-action: none; user-select: none; -webkit-user-select: none; }
.gomoku-nudge { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.gomoku-nudge .mini-btn:disabled { opacity: 0.45; cursor: default; }
.gomoku-nudge-hint { flex-basis: 100%; color: var(--dim); font-size: 11px; }
/* The nudge toggle is a PER-DEVICE preference, not a third game tab: the dashed
   border keeps local/online reading as the one selected pair, while an active
   nudge still gets the shared accent fill. It sits at the row's far end so a
   thumb does not hit it by accident when switching modes. */
.gomoku-nudge-toggle { margin-left: auto; border-style: dashed; }
/* The resign button arms on the first tap (label swap + a red outline); only a
   second tap inside ~3 s sends the frame — see RESIGN_ARM_MS. */
.games-resign.armed { border-color: var(--red); color: var(--red); }

/* Tic-tac-toe: online PvP (lobby + share) */
.ttt-lobby { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ttt-code-input {
    background: var(--bg);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    padding: 8px 10px;
    text-transform: uppercase;
    width: 140px;
}
.ttt-code-input:focus { outline: none; border-color: var(--accent); }
.ttt-online-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.ttt-wait { display: flex; flex-direction: column; gap: 2px; }
.ttt-wait-timer { color: var(--text-strong); font-size: 20px; font-variant-numeric: tabular-nums; }
.ttt-wait-hint { color: var(--dim); font-size: 12px; }

/* The two seats in an online room, rendered like a comment author line
   (profile picture + display name + badges) — see player/comments.js. A
   spectator sees both players read-only. */
.ttt-players { display: flex; flex-direction: column; gap: 2px; width: 100%; }
.ttt-players .ttt-player { border-bottom: none; padding: 2px 0; gap: 8px; align-items: center; }
.ttt-players .ttt-player .comment-avatar { width: 28px; height: 28px; }
.ttt-players .ttt-player .who { display: flex; align-items: center; margin-bottom: 0; }
.ttt-players .ttt-player .ttt-role { font-weight: 700; margin-right: 6px; }
.ttt-players .ttt-player .ttt-role-x { color: var(--accent); }
.ttt-players .ttt-player .ttt-role-o { color: var(--green); }
.ttt-players .ttt-player-you .ttt-name { color: var(--text-strong); }

/* Guess the song */
.guess-options { display: flex; flex-direction: column; gap: 8px; width: 100%; }
/* Difficulty picker: three buttons, each showing its clip length. */
.guess-difficulty { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.guess-diff-label { color: var(--dim); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }
.guess-diff-btn {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--dim);
    font-family: inherit;
    font-size: 12px;
    padding: 5px 12px;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.guess-diff-btn:hover { color: var(--text-strong); border-color: var(--accent); }
.guess-diff-btn.active { background: var(--accent-soft); border-color: var(--accent); color: var(--text-strong); }
.guess-diff-sec { color: var(--dimmer); font-size: 10px; font-variant-numeric: tabular-nums; }
.guess-keys-hint { color: var(--dimmer); font-size: 11px; }
.guess-option {
    text-align: left;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    padding: 10px 12px;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}
.guess-option:hover:enabled { border-color: var(--accent); }
.guess-option:disabled { cursor: default; }
.guess-option.correct { border-color: var(--green); color: var(--green); }
.guess-option.wrong { border-color: var(--red); color: var(--red); }
.guess-loading { display: flex; align-items: center; gap: 8px; color: var(--dim); font-size: 12px; }
.guess-loading[hidden] { display: none; }

/* Guess the song: public leaderboard (best streak — all-time + last 30 days).
   Rows reuse the comment author line (avatar + name + badges). */
.guess-leaderboard { width: 100%; margin-top: 6px; display: flex; flex-direction: column; gap: 14px; }
.guess-lb-heading { color: var(--dim); text-transform: uppercase; letter-spacing: 1px; font-size: 11px; }
.guess-lb-title { color: var(--text-strong); font-size: 12px; margin-bottom: 4px; }
.guess-lb-empty { color: var(--dimmer); font-size: 12px; padding: 4px 0; }
.guess-lb-hint { color: var(--dimmer); font-size: 12px; }
.guess-lb-row { display: flex; align-items: center; gap: 10px; padding: 6px 6px; border-bottom: 1px solid var(--border); }
.guess-lb-row .comment-avatar { width: 28px; height: 28px; }
.guess-lb-row .who { display: flex; align-items: center; gap: 4px; color: var(--dim); font-size: 11px; }
.guess-lb-rank { width: 24px; text-align: center; color: var(--dim); font-size: 13px; flex-shrink: 0; }
.guess-lb-name { color: var(--text-strong); }
.guess-lb-streak { margin-left: auto; color: var(--text-strong); font-size: 13px; font-variant-numeric: tabular-nums; }
.guess-lb-you { background: var(--accent-soft); border-radius: var(--radius-sm); }
.guess-lb-you .guess-lb-name { color: var(--accent); }

/* ---------- Investments view (lazy, embedded via iframe) ---------- */
html[data-view="investments"] #view-investments { display: block; }
#view-investments { padding: 0; }
#investments-frame { width: 100%; min-height: 70vh; border: 0; display: block; background: transparent; }

/* ---------- Account view (real DOM, not an iframe: a theme change here
   restyles the whole shell at once). Logic: site/pages/account.js. ---------- */
html[data-view="account"] #view-account { display: block; }
#view-account { padding: 0; }
#view-account .account-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 28px 26px;
    max-width: 480px;
    margin: 0 auto;
}
#view-account h1 {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--dim);
    font-weight: 600;
    margin: 0 0 20px;
}
#view-account .tabs { display: flex; gap: 6px; margin-bottom: 20px; }
#view-account .tabs button {
    flex: 1;
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 9px 10px;
    color: var(--dim);
    font-family: inherit;
    font-size: 12px;
    cursor: pointer;
}
#view-account .tabs button.active { color: var(--text-strong); border-color: var(--accent); background: var(--accent-soft); }
#view-account form { display: flex; flex-direction: column; gap: 14px; }
#view-account label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--dim); margin-bottom: 6px; }
#view-account input[type="text"],
#view-account input[type="password"] {
    width: 100%;
    background: var(--bg);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 11px 12px;
    color: var(--text);
    font-family: inherit;
    font-size: 14px;
}
#view-account input[type="text"]:focus,
#view-account input[type="password"]:focus { outline: none; border-color: var(--accent); }
#view-account button[type="submit"],
#view-account #signout {
    background: var(--accent);
    border: none;
    border-radius: var(--radius-sm);
    padding: 12px 14px;
    color: #fff;
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}
#view-account button[type="submit"]:hover,
#view-account #signout:hover { opacity: 0.9; }
#view-account .status { font-size: 12px; min-height: 17px; word-break: break-word; margin: 8px 0; }
#view-account .status.ok { color: var(--green); }
#view-account .status.err { color: var(--red); }
/* The settings blocks stack heading / status / toggle button / optional form.
   Give a toggle-opened form room below its button so the first label ("Current
   password") is not flush against it. */
#view-account #username-form,
#view-account #password-form { margin-top: 14px; }
#view-account #signed-in { text-align: center; }
#view-account #signed-in .label,
#view-account #reset-panel .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--dim);
    margin-bottom: 12px;
}
#view-account .who { margin: 0 0 20px; }
#view-account .who .name { font-size: 18px; color: var(--text); }
#view-account .who .handle { display: block; color: var(--dim); font-size: 13px; margin-top: 4px; }
/* Inline display-name editor: a small discrete ✎ beside the name opens an
   inline input + save/cancel in place of the name, so editing profile
   cosmetics takes no extra settings row. site/pages/account.js. */
#view-account .name-edit {
    background: transparent;
    border: none;
    color: var(--dim);
    font-family: inherit;
    font-size: 14px;
    line-height: 1;
    padding: 0 4px;
    margin-left: 2px;
    cursor: pointer;
    vertical-align: middle;
}
#view-account .name-edit:hover { color: var(--accent); }
#view-account .name-edit-form { display: inline-flex; align-items: center; gap: 6px; vertical-align: middle; }
#view-account .name-edit-form input[type="text"] { padding: 4px 8px; font-size: 14px; max-width: 180px; }
#view-account .name-edit-form button { border-radius: var(--radius-sm); font-family: inherit; font-size: 12px; font-weight: 400; padding: 5px 10px; cursor: pointer; }
#view-account .name-edit-form button[type="submit"] { background: var(--accent); border: none; color: #fff; }
#view-account .name-edit-form button[type="submit"]:hover { opacity: 0.9; }
#view-account .name-edit-form button[type="button"] { background: transparent; border: none; color: var(--dim); }
#view-account .name-edit-form button[type="button"]:hover { color: var(--text-strong); }
#view-account #displayname-status { min-height: 0; margin: 6px 0 0; }
#view-account .avatar { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; border: 1px solid var(--border-strong); display: block; margin: 0 auto 10px; }
#view-account .avatar-upload { display: inline-block; margin: 4px 0 12px; cursor: pointer; }
#view-account .avatar-upload span { font-size: 12px; color: var(--accent); text-decoration: underline; }
#view-account #avatar-status { min-height: 16px; }
#view-account #reset-panel { text-align: center; }
#view-account .theme-row { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 16px; }
#view-account .theme-row label { margin: 0; }
/* The theme < / > stepper buttons (site/pages/account.js). */
#view-account .theme-nav {
    background: transparent;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    padding: 6px 10px;
    cursor: pointer;
}
#view-account .theme-nav:hover { border-color: var(--accent); color: var(--text-strong); }
#view-account .theme-row select { background: var(--bg); color: var(--text); border: 1px solid var(--border-strong); border-radius: 4px; padding: 5px 8px; font-family: inherit; font-size: 13px; }
/* The text-size button just opens the floating panel (see #fontsize-panel). */
#view-account #fontsize-open { background: transparent; border: 1px solid var(--border-strong); border-radius: 4px; color: var(--text); font-family: inherit; font-size: 13px; padding: 5px 12px; cursor: pointer; }
#view-account #fontsize-open:hover { border-color: var(--accent); }
/* Preferences / Security section headings. The profile header above them stays
   centred; the grouped settings read left-to-right like a normal form. */
#view-account .account-section-title {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--dim);
    text-align: left;
    margin: 26px 0 14px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}
#view-account .account-block,
#view-account form { text-align: left; }
#view-account #signout { margin-top: 26px; }
/* Text-size popover. site/pages/account.js opens it as a `position: fixed` box
   placed under #fontsize-open (left/top set in JS) and counter-zooms it, so its
   +/- buttons keep the same size and screen position while the page rescales. It
   must stay `fixed` (not absolute/anchor-tracked) for that to hold. */
#fontsize-panel {
    position: fixed;
    z-index: 130;
}
.fontsize-window {
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}
.fontsize-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; width: 100%; }
.fontsize-head span { font-size: 11px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--dim); }
.fontsize-close { background: transparent; border: none; color: var(--dim); font-size: 14px; cursor: pointer; padding: 0 2px; }
.fontsize-hint { font-size: 11px; color: var(--dimmer); max-width: 190px; text-align: center; }
/* The stepper reuses the player's .pitch-btn / .pitch-stepper; only the value
   needs its own width (widest is "400%"). */
#fontsize-panel #fontsize-value {
    min-width: 4ch;
    font-size: 13px;
    text-align: center;
    font-variant-numeric: tabular-nums;
    color: var(--dim);
}

/* ---------- In-page notice / sign-in reminder (player/notice.js) ----------
   A bottom toast for gentle reminders (e.g. "sign in to like songs"). It sits
   above the mini player when that bar is shown (body.has-mini), so the controls
   stay tappable. Tokens keep it in step with the active theme. */
.versu-notice {
    position: fixed;
    left: 50%;
    bottom: 20px;
    transform: translateX(-50%) translateY(8px);
    z-index: 140;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: min(92vw, 460px);
    padding: 10px 14px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 12px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease, transform 0.2s ease;
    pointer-events: none;
}

body.has-mini .versu-notice {
    bottom: 72px;
}

.versu-notice.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}

.versu-notice-text {
    line-height: 1.3;
}

.versu-notice-action {
    color: var(--accent);
    text-decoration: none;
    font-weight: 700;
    white-space: nowrap;
}

.versu-notice-action:hover {
    text-decoration: underline;
}


.versu-notice-action:hover {
    text-decoration: underline;
}

/* ---------- Badges (src/badges.js): 🚀 founding / ✨ friend / 💞 supporter ---------- */
.badge { margin-left: 4px; font-size: 12px; line-height: 1; cursor: default; }
.who-badges { margin-left: 6px; }

/* ---------- Comment engagement (player/comments.js) ---------- */
.comment-actions { display: flex; align-items: center; gap: 10px; margin-top: 4px; font-size: 11px; }
.comment-act {
	background: transparent;
	border: none;
	color: var(--dim);
	font-family: inherit;
	font-size: 11px;
	cursor: pointer;
	padding: 0;
	display: inline-flex;
	align-items: center;
	gap: 3px;
}
.comment-act:hover { color: var(--accent); }
.comment-act.liked { color: var(--red); }
.comment-act .count-badge { color: inherit; opacity: 0.85; }
.comment-report-done { color: var(--dimmer); font-size: 11px; }
/* Replies sit indented under a hairline rail; collapsed unless expanded
   (except an admin reply, which always shows — see player/comments.js). */
.comment-replies { margin-top: 6px; padding-left: 12px; border-left: 2px solid var(--border); }
.comment-replies .comment-item { padding: 8px 0; border-bottom: 1px solid var(--border); }
.comment-replies .comment-item:last-child { border-bottom: none; }
.comment-reply .comment-avatar { width: 28px; height: 28px; }
.comment-reply-form { display: flex; gap: 8px; margin-top: 6px; }
.comment-reply-form textarea {
	flex: 1;
	resize: vertical;
	background: var(--bg);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	color: var(--text);
	font-family: inherit;
	font-size: 12px;
	padding: 6px 8px;
}
.comment-reply-form textarea:focus { outline: none; border-color: var(--accent); }
.comment-reply-form .comment-act { color: var(--accent); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 0 10px; }

/* ---------- Support CTA (view-support) ---------- */
.support-cta { margin: 4px 0 16px; }
.support-feedback-link {
	display: inline-block;
	background: var(--accent);
	color: #fff;
	font-weight: 700;
	font-size: 13px;
	padding: 9px 16px;
	border-radius: var(--radius-sm);
	text-decoration: none;
}
.support-feedback-link:hover { opacity: 0.9; }
/* The fan stream tally — the calculator under the CTA (site/pages/support.js): the field
   sits INLINE in the site's own sentence, so the line is one flowing paragraph. The block
   is hidden (the attribute) until a session with a user arrives. */
.support-content > p.support-calc { line-height: 2; }
.support-calc-input {
	width: 7em;
	margin: 0 6px;
	padding: 4px 8px;
	background-color: var(--surface);
	color: var(--text-strong);
	border: 1px solid var(--border);
	border-radius: var(--radius-sm);
	font-family: var(--font-mono);
	font-size: 13px;
	text-align: right;
}
.support-calc-input:focus { outline: none; border-color: var(--accent); }
.support-calc-plus { margin-left: 4px; }
.support-donate-title { color: var(--dim); text-transform: uppercase; letter-spacing: 1px; font-size: 11px; margin-bottom: 8px; }

/* ---------- Notification bell + panel (site/notifications.js) ---------- */
.nav-notif {
	position: relative;
	background: transparent;
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	color: var(--text);
	font-family: inherit;
	font-size: 13px;
	padding: 5px 9px;
	cursor: pointer;
	line-height: 1;
}
.nav-notif:hover { border-color: var(--accent); color: var(--text-strong); }
.nav-notif.active-nav { border-color: var(--accent); background: var(--accent-soft); }
.notif-count { margin-left: 3px; font-size: 10px; color: var(--red); font-variant-numeric: tabular-nums; }
.notif-panel {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.55);
	display: flex;
	align-items: flex-start;
	justify-content: center;
	z-index: 105;
	padding: 64px 16px 16px;
}
.notif-card {
	background: var(--surface);
	border: 1px solid var(--border-strong);
	border-radius: var(--radius);
	width: 100%;
	max-width: 440px;
	max-height: 70vh;
	display: flex;
	flex-direction: column;
}
.notif-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 12px 14px;
	border-bottom: 1px solid var(--border);
	color: var(--dim);
	text-transform: uppercase;
	letter-spacing: 1px;
	font-size: 11px;
}
.notif-head-actions { display: flex; align-items: center; gap: 8px; }
.notif-read-all {
	background: transparent;
	border: 1px solid var(--border-strong);
	border-radius: var(--radius-sm);
	color: var(--text);
	font-family: inherit;
	font-size: 11px;
	padding: 4px 8px;
	cursor: pointer;
	text-transform: none;
	letter-spacing: 0;
}
.notif-read-all:hover { border-color: var(--accent); }
.notif-read-all.active { border-color: var(--accent); background: var(--accent-soft); color: var(--text-strong); }
.notif-close { background: transparent; border: none; color: var(--dim); font-size: 15px; cursor: pointer; padding: 2px 6px; }
.notif-list { overflow-y: auto; }
.notif-empty { color: var(--dimmer); font-size: 12px; padding: 16px 14px; }
.notif-item {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 10px 14px;
	border-bottom: 1px solid var(--border);
	font-size: 13px;
	cursor: pointer;
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--surface-2); }
.notif-item.unread { border-left: 3px solid var(--accent); }
.notif-avatar { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; flex-shrink: 0; background: var(--surface-2); }
.notif-main { flex: 1; min-width: 0; }
.notif-text { color: var(--text); }
.notif-time { color: var(--dimmer); font-size: 11px; margin-left: 4px; }
.notif-snippet { color: var(--dim); font-size: 12px; margin-top: 2px; word-break: break-word; }

