/* Chessingo - CLASH mode. A Golf Clash-style 1v1 framing on top of play.css:
   opponent card up top, your card at the bottom, board between, a per-move shot
   clock draining on each side, a VS intro splash, an emote bar, and a coins/
   trophy result screen. Rides on play.css for the board, pieces, promo + overlay
   chrome; this file only adds the head-to-head HUD. */

.clash {
    max-width: 1560px;
    margin: 0 auto;
    padding: 0.6rem clamp(0.6rem, 3vw, 1.2rem) 2rem;
}

/* ── Pre-match setup card ───────────────────────────────────────────────── */
.clash-setup { max-width: 420px; margin: 1.4rem auto; }
/* The match HUD keeps its phone-shaped column; only the globe lobby goes wide. */
.clash > .clash-more { max-width: 560px; margin-left: auto; margin-right: auto; }
/* The match is the shared table (play.css .arena-table, GDD s1.2), full width. */
.clash > .clash-stage { max-width: none; padding-inline: 0; }
.clash-lbl {
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin: 0.5rem 0 0.3rem;
}
.clash-setup select { margin-bottom: 0.2rem; }
.clash-setup .btn.primary { margin-top: 0.9rem; }

/* Coin balance pill + vs Bot / vs Player toggle */
.clash-setup-top { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.coin-pill {
    font-family: 'Silkscreen', monospace;
    font-size: 0.8rem;
    color: var(--corn);
    background: rgba(255, 210, 63, 0.12);
    border: 1px solid rgba(255, 210, 63, 0.4);
    border-radius: 9999px;
    padding: 0.18rem 0.6rem;
    white-space: nowrap;
}
.clash-mode-toggle {
    display: flex;
    gap: 0.4rem;
    margin: 0.9rem 0 0.4rem;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid var(--card-line);
    border-radius: 9999px;
    padding: 0.25rem;
}
.clash-mode-btn {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--text-dim);
    font-family: 'Bangers', 'Outfit', sans-serif;
    font-weight: 400;
    letter-spacing: 0.04em;
    padding: 0.45rem 0.6rem;
    border-radius: 9999px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.clash-mode-btn.active { background: linear-gradient(90deg, var(--sky), var(--magenta)); color: #fff; }

/* PvP lobby panel */
#pvp-panel .clash-lbl { text-transform: none; letter-spacing: 0; font-size: 0.86rem; line-height: 1.4; }
.pvp-join-row { display: flex; gap: 0.5rem; margin-top: 0.6rem; }
.pvp-join-row input {
    flex: 1;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    font-family: 'Silkscreen', monospace;
}
.pvp-join-row .btn { width: auto; padding: 0.25rem 1.3rem 0.4rem; }
.pvp-status { margin-top: 0.7rem; font-size: 0.84rem; color: var(--text-dim); min-height: 1.1rem; }
.pvp-status .danger { color: var(--magenta); }

/* ── Head-to-head stage ─────────────────────────────────────────────────── */


/* Seats are the shared .hero-opponent / .seat-card cards; clash only adds the
   turn glow, the shot clock and the speech bubble on top of them. */
.clash-player { position: relative; }
/* The player whose turn it is glows to make the initiative obvious at a glance. */
.clash-player.active { border-color: var(--corn); box-shadow: 0 0 18px rgba(255, 210, 63, 0.45), 0 8px 22px rgba(0, 0, 0, 0.4); }

.clash-ava {
    flex: 0 0 auto;
    width: 60px;
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.1rem;
    border-radius: 14px;
    background: radial-gradient(circle at 50% 35%, rgba(255, 255, 255, 0.22), rgba(0, 0, 0, 0.35));
    border: 2px solid rgba(255, 255, 255, 0.35);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);
    text-shadow: 0 0 12px currentColor;
}
.clash-player.top .clash-ava { color: var(--magenta); }
.clash-player.bottom .clash-ava { color: var(--sky); }
/* A ranked challenger is a real vipsallowed member with real pixel art, so the
   tile drops its glyph styling and becomes a picture frame. Only applied once
   the image has loaded, so a dead CDN leaves the glyph standing. */
.clash-ava.has-ava {
    overflow: hidden;
    text-shadow: none;
    background: rgba(4, 10, 20, 0.82);
}
.clash-ava.has-ava img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Low-res art blown up: keep the pixels. */
    image-rendering: pixelated;
}

.clash-meta { flex: 1 1 auto; min-width: 0; }
.clash-name {
    font-family: 'Outfit', sans-serif;
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.clash-rating {
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    color: var(--text-dim);
    margin-bottom: 0.35rem;
}

/* ── Per-move shot clock (FEAT-2026-0923-0024) ──────────────────────────── */
/* A draining bar + a seconds readout. Fills sky on your side, magenta on the
   bot's; goes corn + pulses under pressure so a flag never sneaks up. */
.clash-clock {
    position: relative;
    height: 12px;
    border-radius: 7px;
    background: rgba(0, 0, 0, 0.45);
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.55);
    overflow: hidden;
    align-self: stretch;
    margin-top: 0.7rem;
}
.clash-clock-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 100%;
    border-radius: 7px;
    background: linear-gradient(90deg, var(--lime), var(--sky));
    transition: width 0.25s linear;
}
.clash-player.top .clash-clock-fill { background: linear-gradient(90deg, var(--tangerine), var(--magenta)); }
.clash-clock-num {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'Silkscreen', monospace;
    font-size: 0.66rem;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
    letter-spacing: 0.04em;
}
.clash-clock.low .clash-clock-fill { background: var(--corn); animation: clashPulse 0.6s ease-in-out infinite; }
.clash-clock.off { opacity: 0.35; }
.clash-clock.off .clash-clock-num::after { content: '\221E'; }
@keyframes clashPulse { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.5); } }

/* ── Speech bubbles (emotes + trash-talk replies) ───────────────────────── */
.clash-bubble {
    position: absolute;
    left: 12px;
    right: 12px;
    padding: 0.4rem 0.7rem;
    border-radius: 14px;
    font-size: 0.85rem;
    line-height: 1.25;
    background: #fff;
    color: #1a1030;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45);
    z-index: 4;
    animation: bubblePop 0.18s ease-out;
}
.clash-player.top .clash-bubble { top: calc(100% - 6px); }
.clash-player.bottom .clash-bubble { bottom: calc(100% - 6px); }
.clash-player.top .clash-bubble::after,
.clash-player.bottom .clash-bubble::after {
    content: '';
    position: absolute;
    left: 22px;
    border: 8px solid transparent;
}
.clash-player.top .clash-bubble::after { top: -14px; border-bottom-color: #fff; }
.clash-player.bottom .clash-bubble::after { bottom: -14px; border-top-color: #fff; }
.clash-bubble.you { background: var(--sky); }
@keyframes bubblePop { from { transform: scale(0.7); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* ── Emote bar ──────────────────────────────────────────────────────────── */
.clash-emotes {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    justify-content: center;
    margin-top: 0.2rem;
}
.emote {
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    background: rgba(255, 255, 255, 0.09);
    cursor: pointer;
    transition: transform 0.08s ease, background 0.12s ease, border-color 0.12s ease;
}
.emote:hover { background: rgba(255, 255, 255, 0.18); border-color: var(--corn); transform: translateY(-1px); }
.emote:active { transform: translateY(1px); }
.emote:disabled { opacity: 0.4; cursor: not-allowed; }

/* ── Result screen additions (rides on play.css #overlay) ───────────────── */
#overlay #result-badge {
    width: 84px;
    height: 84px;
    background: center / contain no-repeat url('/img/ui/ic-trophy.png');
    filter: drop-shadow(0 0 16px rgba(255, 210, 63, 0.6));
    display: none;
}
#overlay.win #result-badge { display: block; }
#overlay.lose #result-badge,
#overlay.draw #result-badge {
    display: block;
    background-image: url('/img/ui/ic-info.png');
    filter: drop-shadow(0 0 12px rgba(255, 45, 120, 0.5));
}
/* Coins/chest reward reveal - when the badge holds a chest, drop the default
   trophy background so the chest owns the slot. */
#overlay #result-badge.has-chest {
    display: block;
    width: auto;
    height: auto;
    background: none;
    filter: none;
}
.chest-reveal { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; }
.chest-box {
    border: 0;
    background: transparent;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    transition: transform 0.15s;
    animation: chestBob 1.1s ease-in-out infinite;
}
.chest-box:hover { transform: scale(1.06); }
.chest-box.popped { animation: chestPop 0.4s ease-out; }
.chest-glyph { font-size: 2.8rem; line-height: 1; filter: drop-shadow(0 0 14px rgba(255, 210, 63, 0.6)); }
.chest-bronze .chest-glyph { filter: drop-shadow(0 0 12px rgba(205, 127, 50, 0.7)); }
.chest-silver .chest-glyph { filter: drop-shadow(0 0 12px rgba(200, 200, 210, 0.8)); }
.chest-gold .chest-glyph { filter: drop-shadow(0 0 16px rgba(255, 210, 63, 0.85)); }
.chest-hint {
    font-size: 0.62rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.chest-coins { display: flex; flex-direction: column; align-items: center; gap: 0.1rem; }
.chest-amt {
    font-family: 'Silkscreen', monospace;
    font-size: 1.15rem;
    color: var(--corn);
    text-shadow: 0 0 10px rgba(255, 210, 63, 0.6);
}
.chest-reveal.open .chest-coins { animation: chestCoinsIn 0.35s ease-out; }
.chest-bal { font-size: 0.68rem; letter-spacing: 0.08em; color: var(--text-dim); }
@keyframes chestBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@keyframes chestPop { 0% { transform: scale(1); } 45% { transform: scale(1.25); } 100% { transform: scale(1); } }
@keyframes chestCoinsIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

#new-clash { margin-top: 0.1rem; }

/* ── VS intro splash ────────────────────────────────────────────────────── */
/* MUST default to display:none. This is a fixed, inset:0, z-index:50 overlay with
   a 90%-opaque background, so a `display:flex` default defeats the `hidden`
   attribute that showVsIntro() toggles and leaves the splash permanently over the
   whole page: /clash rendered dimmed and blurred, and every click on it (including
   SCAN FOR A CHALLENGER) was swallowed by this element instead of reaching the
   button. Shipped that way to prod in v0.3.69. */
#vs-intro {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: none;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    background: rgba(13, 8, 23, 0.9);
    backdrop-filter: blur(4px);
}
#vs-intro.show { display: flex; }
.vs-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    opacity: 0;
}
.vs-card.left { animation: vsInLeft 0.5s ease-out forwards; }
.vs-card.right { animation: vsInRight 0.5s ease-out forwards; }
.vs-ava {
    width: clamp(90px, 26vw, 150px);
    height: clamp(90px, 26vw, 150px);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: clamp(3rem, 12vw, 5.4rem);
    border-radius: 22px;
    background: radial-gradient(circle at 50% 35%, rgba(255, 255, 255, 0.22), rgba(0, 0, 0, 0.4));
    border: 3px solid rgba(255, 255, 255, 0.4);
    text-shadow: 0 0 22px currentColor;
}
.vs-card.left .vs-ava { color: var(--sky); }
.vs-card.right .vs-ava { color: var(--magenta); }
.vs-nm { font-family: 'Bangers', 'Outfit', sans-serif; font-weight: 400; font-size: clamp(1.25rem,  5.0vw,  1.875rem); letter-spacing: 0.03em; }
.vs-word {
    font-family: 'Bangers', 'Outfit', sans-serif;
    font-weight: 400;
    font-size: clamp(3.0rem,  12.5vw,  5.5rem);
    color: var(--corn);
    text-shadow: 0 0 24px rgba(255, 210, 63, 0.7);
    opacity: 0;
    animation: vsPop 0.4s 0.25s ease-out forwards; letter-spacing: 0.03em; }
@keyframes vsInLeft { from { transform: translateX(-60px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes vsInRight { from { transform: translateX(60px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes vsPop { from { transform: scale(0.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }

@media (max-width: 520px) {
    .clash-ava { width: 50px; height: 50px; font-size: 1.7rem; }
    .clash-bubble { left: 60px; }
}

/* ── The Challenge Globe lobby (GDD s16) ──────────────────────────────────
   The globe sits BEHIND the panels, not beside them: finding an opponent is
   the screen, so the spectacle is the background and the controls float on it. */
.cgl {
    position: relative;
    width: 100%;
    max-width: 1040px;
    margin: 0 auto 1.4rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding: 1.2rem 1rem 1.6rem;
    border-radius: 20px;
    border: 1px solid var(--card-line);
    background: radial-gradient(circle at 50% 46%, rgba(63, 216, 255, 0.10), transparent 70%), var(--card);
    overflow: hidden;
}
/* SAME TRAP AS #vs-intro, AND IT BIT TWICE. `display` beats the `hidden`
   attribute, so the rule above would keep the whole lobby painted over the
   board when the challenger handoff hides it (GDD s16.2) - and a DOM check of
   `.hidden` passes the entire time, because the attribute really is set. The
   inner panels already carry this guard; the section itself did not. */
.cgl[hidden] { display: none; }
/* The globe gets its OWN area, sized to the viewport, instead of sitting behind
   the controls in a 560px box: on a wide screen it was a postage stamp with the
   scan button printed across its southern hemisphere. */
.cgl-canvas {
    position: relative; display: block; width: 100%;
    height: clamp(280px, calc(100vh - 380px), 640px);
}
.cgl-head { position: relative; text-align: center; margin-bottom: 0.6rem; }
.cgl-kicker {
    font-family: 'Outfit', sans-serif; font-weight: 800; letter-spacing: 0.08em;
    font-size: 0.86rem; text-transform: uppercase; color: var(--corn);
}
.cgl-count { font-size: 0.82rem; color: var(--text-dim); letter-spacing: 0.04em; }
.cgl-panel {
    position: relative; margin-top: 0.9rem; width: 100%; max-width: 560px;
    display: flex; flex-direction: column; gap: 0.6rem; align-items: stretch;
}
.cgl-panel[hidden] { display: none; }
.cgl-dials { display: flex; gap: 0.6rem; }
.cgl-dial {
    flex: 1; display: flex; flex-direction: column; gap: 0.2rem;
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim);
}
.cgl-dial select {
    width: 100%; padding: 0.45rem 0.5rem; border-radius: 10px;
    border: 1px solid var(--card-line); background: rgba(0, 0, 0, 0.45); color: var(--text);
    font: inherit; font-size: 0.82rem;
}
.cgl-scanline {
    text-align: center; font-family: 'Silkscreen', monospace; font-size: 0.78rem;
    letter-spacing: 0.14em; color: var(--sky); animation: cglPulse 1.1s ease-in-out infinite;
}
@keyframes cglPulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 1; } }
.cgl-ticker {
    height: 1.2rem; overflow: hidden; text-align: center;
    font-family: 'Silkscreen', monospace; font-size: 0.72rem; color: var(--text-dim);
}
.cgl-wait { text-align: center; font-size: 0.76rem; color: var(--text-dim); }
.cgl-card {
    position: relative; text-align: center; padding: 1rem 0.9rem 0.9rem;
    border-radius: 16px; border: 2px solid var(--sky);
    background: rgba(4, 10, 20, 0.82); box-shadow: 0 10px 40px rgba(63, 216, 255, 0.22);
}
.cgl-badge {
    display: inline-block; margin-bottom: 0.4rem; padding: 0.16rem 0.7rem;
    border-radius: 999px; font-family: 'Silkscreen', monospace; font-size: 0.6rem;
    letter-spacing: 0.1em; text-transform: uppercase;
}
/* LIVE is the only badge allowed to use the presence colour. A reserve gets the
   gold "ranked" treatment so the two can never be mistaken at a glance. */
.cgl-badge.is-live { background: var(--lime); color: #04200f; }
.cgl-badge.is-reserve { background: var(--corn); color: #2a1d00; }
/* Opponent avatar tile. vipsallowed ships a real pixel avatar for every pool
   member, so this is an art frame first and a "?" only as the honest fallback.
   Fixed size in every state so the card never reflows when the art lands. */
.cgl-ava {
    position: relative;
    width: 96px;
    height: 96px;
    margin: 0 auto 0.35rem;
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid var(--card-line);
    background: rgba(63, 216, 255, 0.06);
}
.cgl-ava-q {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-family: 'Silkscreen', monospace; font-size: 2.4rem; line-height: 1;
    color: var(--sky); opacity: 0.55;
}
.cgl-ava-img {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    /* Low-res pixel art: keep it crisp when it scales up rather than letting
       the browser smooth it into mush. */
    image-rendering: pixelated;
    opacity: 0; transition: opacity 220ms ease-out;
}
/* The tractor beam: a band that sweeps the tile while the art is in flight, so
   an acquiring avatar reads as "locking on" instead of as a broken image. */
.cgl-ava-beam {
    position: absolute; left: -40%; top: 0; width: 40%; height: 100%;
    background: linear-gradient(90deg,
        rgba(63, 216, 255, 0) 0%,
        rgba(63, 216, 255, 0.55) 50%,
        rgba(63, 216, 255, 0) 100%);
    opacity: 0;
}
.cgl-ava[data-state="beam"] { border-color: var(--sky); box-shadow: inset 0 0 18px rgba(63, 216, 255, 0.35); }
.cgl-ava[data-state="beam"] .cgl-ava-q { animation: cgl-ava-pulse 1.1s ease-in-out infinite; }
.cgl-ava[data-state="beam"] .cgl-ava-beam { opacity: 1; animation: cgl-ava-beam 1.1s linear infinite; }
.cgl-ava[data-state="img"] .cgl-ava-q { opacity: 0; }
.cgl-ava[data-state="img"] .cgl-ava-img { opacity: 1; }
@keyframes cgl-ava-beam { from { left: -40%; } to { left: 100%; } }
@keyframes cgl-ava-pulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 0.75; } }
/* The beam is decoration on the critical path to playing, so it is the first
   thing to drop: the "?" and the art both still resolve without it. */
@media (prefers-reduced-motion: reduce) {
    .cgl-ava[data-state="beam"] .cgl-ava-q,
    .cgl-ava[data-state="beam"] .cgl-ava-beam { animation: none; }
    .cgl-ava[data-state="beam"] .cgl-ava-beam { opacity: 0; }
}
.cgl-nm { font-family: 'Bangers', 'Outfit', sans-serif; font-weight: 400; font-size: 1.438rem; letter-spacing: 0.03em; }
.cgl-sub { font-size: 0.8rem; color: var(--text-dim); letter-spacing: 0.04em; }
.cgl-note { margin-top: 0.4rem; font-size: 0.74rem; color: var(--text-dim); }
.cgl-rival { margin-top: 0.4rem; font-size: 0.78rem; color: var(--magenta); }
.cgl-err { position: relative; margin-top: 0.6rem; font-size: 0.8rem; color: var(--magenta); text-align: center; }
.cgl-flat { position: relative; width: 100%; margin-top: 0.6rem; font-size: 0.8rem; color: var(--text-dim); }
.cgl-flat ul { list-style: none; padding: 0; margin: 0.3rem 0 0; display: flex; flex-wrap: wrap; gap: 0.3rem; }
.cgl-flat li {
    padding: 0.12rem 0.5rem; border-radius: 999px;
    border: 1px solid var(--card-line); font-size: 0.72rem;
}
.clash-more { max-width: 560px; margin: 0 auto 2rem; }
.clash-more > summary {
    cursor: pointer; text-align: center; font-size: 0.82rem; color: var(--text-dim);
    letter-spacing: 0.06em; text-transform: uppercase; padding: 0.5rem;
}
.clash-more[open] > summary { color: var(--sky); }
@media (max-width: 520px) {
    .cgl { min-height: 380px; }
}

/* Phone: the seats are one-line strips (play.css), so the shot clock takes a
   full row under the name instead of collapsing to nothing. */
@media (max-width: 900px) {
    .arena-table .clash-clock { flex-basis: 100%; margin-top: 0.3rem; }
}

/* LOBBY LAYOUT (GDD s16.2): on a desktop the globe takes the left and the
   controls / opponent card the right, so SCAN, the locked card and its PLAY
   button are all on one screen. Stacked, the locked card's PLAY button fell
   below the fold. On a phone it stacks globe-then-controls. */
@media (min-width: 900px) {
    .cgl {
        display: grid;
        grid-template-columns: minmax(0, 1.3fr) minmax(320px, 1fr);
        column-gap: 1.6rem;
        align-content: center;
        align-items: center;
    }
    .cgl-canvas { grid-column: 1; grid-row: 1 / span 8; height: clamp(380px, calc(100vh - 190px), 680px); }
    .cgl-head, .cgl-panel, .cgl-err, .cgl-flat { grid-column: 2; }
    .cgl-head { align-self: end; margin-bottom: 0.2rem; }
    .cgl-panel { align-self: start; margin-top: 0.9rem; }
}

/* Phone: a shorter globe so the controls start on the first screen. */
@media (max-width: 899px) {
    .cgl-canvas { height: clamp(240px, 44vh, 380px); }
}

/* Season run on the result screen (run-bank.js). */
.run-box { margin: .4rem 0 .6rem; text-align: center; }
.run-box .run-line { margin: 0 0 .4rem; font-weight: 700; color: var(--corn, #ffd23f); font-size: .95rem; }
.run-box[hidden] { display: none; }
