/* ========== LOBBY PAGE ========== */

.lobby-page {
    max-width: 1100px;
    margin: 0 auto;
}

.lobby-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
    gap: 1rem;
}

.lobby-header h1 {
    font-size: clamp(1.6rem, 3vw, 2rem);
    margin-bottom: 0.25rem;
}

.lobby-header p {
    color: var(--muted);
    margin: 0;
}

.lobby-connection {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.8rem;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 500;
}

.lobby-connection .connection-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
}

.lobby-connection.conn-ok {
    background: rgb(from var(--mud-palette-primary) r g b / 0.12);
    color: var(--accent-strong);
}

.lobby-connection.conn-ok .connection-dot {
    background: var(--accent);
}

.lobby-connection.conn-warn {
    background: rgba(240, 185, 59, 0.15);
    color: #a36e00;
}

.lobby-connection.conn-warn .connection-dot {
    background: #f0b93b;
    animation: home-pulse 1s ease-in-out infinite;
}

.lobby-connection.conn-off {
    background: rgba(185, 52, 52, 0.12);
    color: #b03434;
}

.lobby-connection.conn-off .connection-dot {
    background: #b03434;
}

/* Mobile section tabs. Hidden here and switched on in the 599.98 block below, so above 600 this
   element has no box and the desktop grid is untouched.
   Why CSS and not MudTabs: MudTabs owns which panel renders, so it can only produce a tabbed view
   by owning the sections at EVERY width -- desktop included. Keeping desktop 3-up would mean
   rendering the page two different ways behind a viewport check (MudHidden/IBrowserViewportService),
   which (a) renders nothing until the JS resize observer reports back, flashing an empty lobby on
   the one page whose job is speed, and (b) re-mounts ChatPanel on every breakpoint cross, dropping
   its SignalR group subscription. The panels are the same DOM at both widths here; only their
   visibility differs, and visibility is CSS's job. The visual language is the .chat-tab strip this
   same component already uses, so the two strips do not read as two different systems.
   Selected state is styled off [aria-selected="true"] rather than a parallel .active class, so the
   thing screen readers announce and the thing sighted users see cannot drift apart. */
.lobby-tabs {
    display: none;
    border-bottom: 1px solid var(--line);
    margin-bottom: 1.25rem;
}

.lobby-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.75rem 0.5rem;
    border: none;
    background: transparent;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
    transition: color 150ms ease;
}

.lobby-tab[aria-selected="true"] {
    color: var(--accent);
    box-shadow: inset 0 -2px 0 var(--accent);
}

/* The queue lives in the Quick Match panel, so a player who tabs away while searching loses sight
   of it. The match-found modal still fires from outside the grid, so the path is intact -- this dot
   just keeps the queue visible from the other two tabs. The label carries the same fact in text. */
.lobby-tab-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
    animation: home-pulse 1s ease-in-out infinite;
}

.lobby-grid {
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: 1.5rem;
}

.lobby-main {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.lobby-section {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 1.25rem;
    padding: 1.5rem;
}

.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
}

.section-header h2 {
    font-size: 1.1rem;
    margin: 0;
}

.section-header p {
    color: var(--muted);
    font-size: 0.85rem;
    margin: 0;
}

.btn-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: none;
    background: rgb(from var(--mud-palette-primary) r g b / 0.08);
    border-radius: 0.5rem;
    color: var(--accent);
    cursor: pointer;
    transition: background 150ms ease;
}

.btn-icon:hover {
    background: rgb(from var(--mud-palette-primary) r g b / 0.15);
}

.quickmatch-buttons {
    display: grid;
    /* A flat minmax(130px, 1fr) did NOT do what its comment claimed. Two 130px tracks plus the
       1rem gap need 276px; at 320 the grid box measures 244px, so auto-fit dropped to ONE column
       -- the exact collapse the 130px was there to prevent. Eight stacked tiles made Quick Match
       1374px tall at 320.
       The floor is now expressed directly instead of being implied by a magic number: the track
       minimum is 130px, or half the grid box (less half the gap) when 130px will not fit two up.
       Above a 276px box min() picks 130px, so every viewport from 375 up is bit-identical -- only
       the case that was broken changes. Measured cols by box width: 244->2, 293->2, 418->2,
       517->3, 686->4, 706->4 (desktop unchanged). */
    grid-template-columns: repeat(auto-fit, minmax(min(130px, calc((100% - 1rem) / 2)), 1fr));
    gap: 1rem;
}

.quickmatch-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 1.25rem 1rem;
    border: 1px solid var(--line);
    border-radius: 1rem;
    background: var(--surface);
    cursor: pointer;
    transition: all 180ms ease;
}

.quickmatch-btn:hover {
    border-color: var(--accent);
    box-shadow: 0 8px 20px rgb(from var(--mud-palette-primary) r g b / 0.15);
    transform: translateY(-2px);
}

.quickmatch-icon {
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgb(from var(--mud-palette-primary) r g b / 0.08);
    border-radius: 0.75rem;
    color: var(--accent);
}

.quickmatch-word {
    border-color: rgba(242, 165, 65, 0.4);
    background: rgba(242, 165, 65, 0.08);
}

.quickmatch-word .quickmatch-icon {
    background: rgba(242, 165, 65, 0.2);
    color: #c97b13;
}

.quickmatch-math {
    border-color: rgba(84, 122, 227, 0.4);
    background: rgba(84, 122, 227, 0.08);
}

.quickmatch-math .quickmatch-icon {
    background: rgba(84, 122, 227, 0.2);
    color: #3759c7;
}

.quickmatch-ludo {
    border-color: rgba(47, 138, 87, 0.4);
    background: rgba(47, 138, 87, 0.08);
}

.quickmatch-ludo .quickmatch-icon {
    background: rgba(47, 138, 87, 0.2);
    color: #2f8a57;
}

.quickmatch-ttt {
    border-color: rgba(47, 47, 57, 0.35);
    background: rgba(47, 47, 57, 0.08);
}

.quickmatch-ttt .quickmatch-icon {
    background: rgba(47, 47, 57, 0.2);
    color: #2f2f39;
}

.quickmatch-rps {
    border-color: rgba(185, 106, 44, 0.45);
    background: rgba(185, 106, 44, 0.1);
}

/* Unlike its siblings this tile holds real text (the RPS chip), so the ink is held to 4.5:1
   against the chip rather than the 3:1 an icon glyph would need. */
.quickmatch-rps .quickmatch-icon {
    background: rgba(185, 106, 44, 0.2);
    color: #8c5321;
}

.quickmatch-label {
    font-weight: 600;
    color: var(--ink);
}

.quickmatch-hint {
    font-size: 0.75rem;
    color: var(--muted);
}

.mini-c4 {
    display: grid;
    grid-template-columns: repeat(2, 10px);
    gap: 2px;
}

.mini-c4-sm {
    grid-template-columns: repeat(2, 8px);
    gap: 1px;
}

.mini-c4-xs {
    grid-template-columns: repeat(2, 6px);
    gap: 1px;
}

.mini-tiles {
    display: grid;
    grid-template-columns: repeat(2, 18px);
    gap: 4px;
    font-weight: 700;
    font-size: 0.65rem;
    color: #fff;
}

.mini-tiles span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.2);
}

.mini-tiles-sm {
    grid-template-columns: repeat(2, 14px);
    gap: 3px;
    font-size: 0.6rem;
}

.mini-tiles-sm span {
    width: 14px;
    height: 14px;
    border-radius: 5px;
}

.mini-tiles-xs {
    grid-template-columns: repeat(2, 12px);
    gap: 2px;
    font-size: 0.55rem;
}

.mini-tiles-xs span {
    width: 12px;
    height: 12px;
    border-radius: 4px;
}

.mini-dots {
    display: grid;
    grid-template-columns: repeat(2, 10px);
    gap: 2px;
}

.mini-dots-sm {
    grid-template-columns: repeat(2, 8px);
    gap: 1px;
}

.mini-dots .dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.mini-dots-sm .dot {
    width: 8px;
    height: 8px;
}

.dot.red {
    background: radial-gradient(circle at 35% 35%, #ff8e8e 0%, #e14a4a 70%);
}

.dot.blue {
    background: radial-gradient(circle at 35% 35%, #8ac5ff 0%, #2f6fdc 70%);
}

.dot.yellow {
    background: radial-gradient(circle at 35% 35%, #ffe28a 0%, #f0b93b 70%);
}

.dot.green {
    background: radial-gradient(circle at 35% 35%, #8de1b1 0%, #2f8a57 70%);
}

.rps-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.2rem 0.4rem;
    border-radius: 0.5rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    /* The chip inherits its ink (currentColor) from a parent that already clears AA against the
       parent's own background -- so the fill must not move that background. A hard white wash did:
       in dark it dragged the tile up to a mid grey and collapsed the ink to 2.8:1. Tinting toward
       the surface is a no-op on a surface-coloured parent, which is most of them. */
    background: rgb(from var(--mud-palette-surface) r g b / 0.2);
    color: currentColor;
}

/* ...but not on an accent fill. --on-accent IS the surface colour in both themes, so the wash above
   tints the chip toward its own ink and collapses it (3.78 dark / 4.02 light). Sit on the accent
   directly instead, exactly like the tab label beside it: 5.12 dark, 6.00 light.
   axe cannot catch this: _activeTab defaults to 0, so the RPS tab never renders active in a shot. */
.lb-tab.active .rps-icon {
    background: transparent;
}

.rps-icon-sm {
    font-size: 0.6rem;
    padding: 0.15rem 0.35rem;
}

.mc4 {
    width: 10px;
    height: 10px;
    border-radius: 50%;
}

.mini-c4-sm .mc4 {
    width: 8px;
    height: 8px;
}

.mini-c4-xs .mc4 {
    width: 6px;
    height: 6px;
}

.mc4-r {
    background: radial-gradient(circle at 35% 35%, #ff8e8e 0%, #e14a4a 70%);
}

.mc4-g {
    background: radial-gradient(circle at 35% 35%, #ffe28a 0%, #f0b93b 70%);
}

.queue-status {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    background: rgb(from var(--mud-palette-primary) r g b / 0.08);
    border: 1px solid rgb(from var(--mud-palette-primary) r g b / 0.15);
    border-radius: 1rem;
}

.queue-spinner {
    width: 24px;
    height: 24px;
    border: 3px solid rgb(from var(--mud-palette-primary) r g b / 0.2);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

.queue-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.queue-title {
    font-weight: 500;
    color: var(--ink);
}

.queue-timer {
    font-size: 0.8rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.lobby-status-message {
    margin-top: 1rem;
    padding: 0.6rem 0.9rem;
    background: rgb(from var(--mud-palette-primary) r g b / 0.06);
    border-radius: 0.5rem;
    font-size: 0.85rem;
    color: var(--muted);
}

.empty-matches {
    text-align: center;
    padding: 2rem 1rem;
    color: var(--muted);
}

.empty-matches svg {
    opacity: 0.4;
    margin-bottom: 0.75rem;
}

.empty-matches p {
    margin: 0 0 0.25rem;
    color: var(--ink);
}

.empty-matches span {
    font-size: 0.85rem;
}

.matches-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.match-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem 1rem;
    background: rgba(255, 255, 255, 0.6);
    border: 1px solid var(--line);
    border-radius: 0.75rem;
}

.match-game-icon {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgb(from var(--mud-palette-primary) r g b / 0.08);
    border-radius: 0.5rem;
    color: var(--accent);
}

.match-details {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.match-players {
    font-weight: 500;
    color: var(--ink);
}

.match-meta {
    font-size: 0.8rem;
    color: var(--muted);
}

.btn-sm {
    padding: 0.4rem 0.8rem;
    font-size: 0.85rem;
}

.btn-sm svg {
    width: 14px;
    height: 14px;
}

.lobby-sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.lobby-chat {
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
}

.chat-tabs {
    display: flex;
    border-bottom: 1px solid var(--line);
}

.chat-tab {
    flex: 1;
    padding: 0.75rem 0.5rem;
    border: none;
    background: transparent;
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--muted);
    cursor: pointer;
    transition: color 150ms ease;
}

.chat-tab.active {
    color: var(--accent);
    box-shadow: inset 0 -2px 0 var(--accent);
}

.chat-content {
    padding: 1rem;
}

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(10, 18, 22, 0.6);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1200;
}

.modal-card {
    background: var(--surface);
    border-radius: 1.25rem;
    padding: 1.5rem;
    box-shadow: 0 24px 50px rgba(0, 0, 0, 0.25);
    max-width: 90vw;
}

.match-found-modal {
    text-align: center;
    min-width: 320px;
}

.match-found-icon {
    color: var(--accent);
    margin-bottom: 0.75rem;
}

.match-found-modal h2 {
    margin-bottom: 0.5rem;
}

.match-found-vs {
    color: var(--muted);
    margin-bottom: 0.75rem;
}

.match-found-countdown {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--accent);
    margin-bottom: 1rem;
}

.cancel-modal {
    text-align: center;
    min-width: 300px;
}

.cancel-modal h3 {
    margin-bottom: 0.5rem;
}

.cancel-modal p {
    color: var(--muted);
    margin-bottom: 1.25rem;
}

.modal-actions {
    display: flex;
    gap: 0.75rem;
    justify-content: center;
}

/* 900 -> 960, the width where the drawer actually moves. The sidebar is a rigid 320px track, so
   the main column only ever gets the remainder: at 961px the drawer takes ~240px of the main
   area and the main column is left with 345px (measured). The old 900 stop collapsed the grid
   at a width where nothing in the shell changes, and kept the 2-column layout across 901-959,
   where the drawer is an overlay and the main column had 568px. That is the non-monotonic bit:
   the same 2-column layout got LESS room at 961 than at 959. Now the grid is 1-column exactly
   while the drawer is an overlay and 2-column exactly while it is inline, so the column count
   tracks the shell's mode instead of an arbitrary width.
   Trade-off, stated plainly: 901-959 loses a sidebar that did fit there.
   The 345px main column at 961 is a property of the rigid 320px track, not of this stop -- no
   viewport breakpoint can fix it, because 959 and 961 differ in available width, not viewport.
   A container query on available width is the real fix, and is a separate change. */
@media (max-width: 959.98px) {
    .lobby-grid {
        grid-template-columns: 1fr;
    }

}

/* Phone tabs, on the existing 600 stop -- no seventh number.
   Why 600 and not the 959.98 stop directly above, which is where the grid actually goes 1-column:
   tabs BUY reachability by SPENDING visibility, so they have to be paid for. Measured page height
   with the sidebar already folded in: 768 -> 1257px (1.23 screens), because a 686px tile grid puts
   Quick Match at 394px. Hiding two of three sections to save a quarter-screen is a bad trade. The
   phone is where it pays: 375 -> 1622px (2.0 screens), 320 -> 2284px (4.0 screens).
   So the rule is not "tabs iff single-column" but "tabs iff the column is longer than the screen",
   and 600 is the scale point that separates those. */
@media (max-width: 599.98px) {
    .lobby-tabs {
        display: flex;
    }

    /* Each tab hides the other two panels. Desktop never matches these selectors, so the sections
       stay in the flow there and the state class is inert. The sidebar (not .lobby-chat) is what
       gets hidden for Chat: an emptied .lobby-sidebar is still a grid item and would still spend
       the grid's 1.5rem gap. */
    .lobby-grid.lobby-show-quick .lobby-spectate,
    .lobby-grid.lobby-show-quick .lobby-sidebar,
    .lobby-grid.lobby-show-live .lobby-quickmatch,
    .lobby-grid.lobby-show-live .lobby-sidebar,
    .lobby-grid.lobby-show-chat .lobby-quickmatch,
    .lobby-grid.lobby-show-chat .lobby-spectate {
        display: none;
    }
}
