/* ============ WallRush — light theme, violet accents ============ */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
}

[hidden] {
    display: none !important;
}

/* ---------- how a touch feels ----------
   Two things were making every tap read as slightly late.

   `manipulation` tells the browser this element will never be double-tapped
   to zoom, so it stops holding the tap back to find out — that wait is a few
   hundred milliseconds on the elements that lacked it.

   And the press animation ran on the same .15s easing as the release, so the
   button was still shrinking after the finger had already moved on. Pressing
   is now instant and only the spring back is animated: the shape follows the
   finger down and eases up behind it. */
/* Menus only. The board is left alone: it sets its own touch rules, and a
   cell that overrides them changes how a move feels. */
button,
a,
label,
.card,
[role="button"] {
    touch-action: manipulation;
}

.card,
.btn-big,
.btn-support,
.lang-fab,
.streak-pill,
.flame-btn,
.cr-opts button,
.wallet button,
.rp-btn,
.nav-btn,
.btn-back {
    transition: transform .16s cubic-bezier(.2, .8, .3, 1);
}

.card:active,
.btn-big:active,
.btn-support:active,
.lang-fab:active,
.streak-pill:active,
.flame-btn:active,
.cr-opts button:active,
.wallet button:active,
.rp-btn:active,
.nav-btn:active,
.btn-back:active {
    transition-duration: 0s;
}

:root {
    --bg: #eef1f7;
    --bg2: #e2e7f2;
    --card: #ffffff;
    --text: #1d2440;
    --muted: #8b93af;
    --violet: #2f6df6;
    /* primary accent is blue now */
    --violet2: #5b8cff;
    --violet-dark: #1f52d4;
    --red: #e33d52;
    --blue: #2f6df6;
    --green: #21c07a;
    --navy: #222b47;
    /* walls */
    --bezel: #c9d2e2;
    /* board frame */
    --shadow: 0 8px 24px rgba(50, 70, 130, .12);
    --radius: 20px;
}

html,
body {
    min-height: 100%;
}

html {
    background: var(--bg);
}

body {
    font-family: 'Segoe UI', system-ui, -apple-system, Roboto, sans-serif;
    background:
        linear-gradient(180deg, rgba(255, 120, 120, .06), rgba(124, 92, 255, .04) 40%, rgba(61, 123, 255, .06)),
        repeating-linear-gradient(0deg, transparent 0 39px, rgba(120, 120, 160, .07) 39px 40px),
        repeating-linear-gradient(90deg, transparent 0 39px, rgba(120, 120, 160, .07) 39px 40px),
        var(--bg);
    color: var(--text);
    user-select: none;
    -webkit-user-select: none;
    overscroll-behavior: none;
}

#app {
    max-width: 520px;
    margin: 0 auto;
    min-height: 100dvh;
    position: relative;
}

/* Ad networks inject their banners as a direct <body> child, outside #app,
   wherever they please. While a match is on screen (<html class="in-game">)
   hide whatever turns up there, so an ad can never cover the board or swallow
   a tap mid-move. Ads belong in the menus only.

   Written against the body child rather than any one network's class name on
   purpose: the networks come and go, this rule should outlive them. */
html.in-game>body>*:not(#app):not(script):not(style) {
    display: none !important;
}

/* Optional "Support WallRush" button on the game-over screen: deliberately
   quieter than Rematch/Menu so it reads as an offer, never a demand. */
.btn-support {
    display: block;
    width: 100%;
    margin: 14px 0 0;
    padding: 12px 16px;
    border: none;
    border-radius: 14px;
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    color: #7a5b00;
    background: rgba(255, 199, 0, .16);
    transition: transform .15s ease, background .15s ease;
}

.btn-support:active {
    transform: scale(.97);
}

.btn-support:disabled {
    cursor: default;
    opacity: .75;
}

.support-hint {
    text-align: center;
    color: var(--muted);
    font-size: 11.5px;
    margin-top: 6px;
}

html[data-theme="dark"] .btn-support {
    color: #ffd76a;
    background: rgba(255, 199, 0, .12);
}

/* USDT address block inside the support dialog */
.wallet {
    background: var(--bg2);
    border-radius: 14px;
    padding: 11px;
    margin-top: 10px;
    text-align: center;
}

.wallet-net {
    display: block;
    font-size: 11px;
    letter-spacing: .6px;
    color: var(--muted);
    text-transform: uppercase;
}

/* A TRC20 address is 34 characters. Shrink it to fit one line rather than let
   it break in half, which makes it look mistyped. */
.wallet code {
    display: block;
    margin: 6px 0 9px;
    font-size: 11.5px;
    line-height: 1.4;
    letter-spacing: -.2px;
    word-break: break-all;
    user-select: all;
    -webkit-user-select: all;
    color: var(--text);
}

.wallet button {
    border: none;
    border-radius: 10px;
    padding: 9px 20px;
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    background: var(--violet);
    color: #fff;
}

.wallet button:active {
    transform: scale(.97);
}

/* The one paragraph that is real text in the served file, and the only place
   on the home screen that says in plain words what this game is. Quiet, at the
   bottom, below everything a returning player came for. */
.about {
    margin: 26px 2px 8px;
    text-align: start;
}

.about h2 {
    font-size: 15px;
    margin-bottom: 7px;
}

.about p {
    color: var(--muted);
    font-size: 13px;
    line-height: 1.65;
}

/* ============ offline ============ */
#offline-bar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 600;
    background: #2c3349;
    color: #fff;
}

/* the online modes stay in place rather than vanishing — the menu should not
   rearrange itself the moment a train goes into a tunnel */
.card:disabled {
    opacity: .4;
    box-shadow: none;
    cursor: default;
}

.card:disabled:active {
    transform: none;
}

.lb-stale {
    text-align: center;
    color: var(--muted);
    font-size: 12px;
    margin: 0 0 10px;
}

/* ============ screens ============ */
.screen {
    display: none;
    min-height: 100dvh;
    padding: 20px 18px calc(90px + env(safe-area-inset-bottom, 0px));
    animation: fadeIn .25s ease;
}

.screen.active {
    display: block;
}

@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(8px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* ============ home ============ */
.home-head {
    text-align: center;
    padding: 26px 0 20px;
    position: relative;
}

/* Language chip in the corner of the very first screen — a globe reads the same
   in every language, so nobody has to hunt through the profile to switch. */
.lang-fab {
    position: absolute;
    top: 10px;
    inset-inline-end: 2px;
    z-index: 3;
    border: none;
    cursor: pointer;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    padding: 7px 12px;
    border-radius: 999px;
    background: var(--card);
    color: var(--text);
    box-shadow: var(--shadow);
}

.lang-fab:active {
    transform: scale(.95);
}

.logo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
}

.logo h1 {
    font-size: 34px;
    letter-spacing: -1px;
}

/* The header mark, redrawn to match the app icon.

   It used to be a blue tile with three white bars — from before the icon
   existed, and unrelated to it. A logo that disagrees with the icon on the home
   screen is the kind of thing nobody reports and everybody notices.

   Same three spans, same markup, placed to echo the icon: a wall across the
   middle with a pawn shut on either side. Colours are sampled from the artwork
   (see icons/icon.svg, which is the same mark as an SVG). */
.logo-mark {
    width: 46px;
    height: 46px;
    border-radius: 13px;
    background: linear-gradient(135deg, #232b40, #171e2d);
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 10px 6px 10px;
    gap: 1px;
    padding: 9px;
    box-shadow: 0 6px 16px rgba(23, 30, 45, .45);
}

/* the wall — middle row, full width, the heaviest thing in the mark */
.logo-mark span:nth-child(1) {
    grid-row: 2;
    border-radius: 3px;
    background: linear-gradient(90deg, #fbd77c, #cb8626);
}

/* the two pawns, on opposite sides of it */
.logo-mark span:nth-child(2) {
    grid-row: 1;
    justify-self: end;
    width: 10px;
    border-radius: 50%;
    background: #9a79e1;
}

.logo-mark span:nth-child(3) {
    grid-row: 3;
    justify-self: start;
    width: 10px;
    border-radius: 50%;
    background: #fac558;
}

.tagline {
    color: var(--muted);
    letter-spacing: 3px;
    text-transform: uppercase;
    font-size: 12px;
    margin-top: 8px;
}

.online-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    background: var(--card);
    border-radius: 999px;
    padding: 7px 16px;
    font-size: 14px;
    box-shadow: var(--shadow);
}

.online-pill .dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--green);
    animation: pulse 2s infinite;
}

@keyframes pulse {
    50% {
        opacity: .4;
    }
}

.cards {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.cards-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}

.card {
    display: flex;
    align-items: center;
    gap: 14px;
    text-align: left;
    border: none;
    cursor: pointer;
    border-radius: var(--radius);
    padding: 18px;
    font: inherit;
    color: inherit;
    background: var(--card);
    box-shadow: var(--shadow);
    transition: transform .15s ease, box-shadow .15s ease;
}

.card:active {
    transform: scale(.97);
}

.cards-row .card {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    padding: 16px;
}

.card-icon {
    width: 46px;
    height: 46px;
    border-radius: 14px;
    flex: none;
    display: grid;
    place-items: center;
    font-size: 22px;
    background: rgba(255, 255, 255, .25);
}

.card-icon.dark {
    background: #eeeaff;
}

.card-icon.lvl-easy {
    background: #ddf7e8;
}

.card-icon.lvl-normal {
    background: #dfeaff;
}

.card-icon.lvl-hard {
    background: #ffe9d6;
}

.card-icon.lvl-hardcore {
    background: #2a3050;
}

.card-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.card-text b {
    font-size: 17px;
}

.card-text small {
    color: var(--muted);
    font-size: 13px;
}

.card-arrow {
    font-size: 26px;
    color: var(--muted);
}

.card-primary {
    background: linear-gradient(120deg, #4f8bff, #2f6df6 55%, #1f52d4);
    color: #fff;
}

.card-primary .card-text small,
.card-primary .card-arrow {
    color: rgba(255, 255, 255, .85);
}

.card-violet {
    background: linear-gradient(135deg, var(--violet), var(--violet-dark));
    color: #fff;
}

.card-violet2 {
    background: linear-gradient(135deg, var(--violet2), var(--violet));
    color: #fff;
}

.card-violet .card-text small,
.card-violet2 .card-text small {
    color: rgba(255, 255, 255, .8);
}

/* ============ sub screens ============ */
.sub-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0 20px;
}

.sub-head.center {
    flex-direction: column;
    gap: 4px;
    text-align: center;
}

.sub-head h2 {
    font-size: 24px;
}

.btn-back {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    background: var(--card);
    box-shadow: var(--shadow);
    font-size: 24px;
    color: var(--text);
    display: grid;
    place-items: center;
    padding-bottom: 4px;
}

.hint {
    color: var(--muted);
    font-size: 14px;
    line-height: 1.5;
}

.how-text {
    text-align: left;
    margin: 10px 0;
}

.btn-big {
    width: 100%;
    padding: 16px;
    border: none;
    border-radius: 16px;
    cursor: pointer;
    font: inherit;
    font-size: 17px;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(120deg, var(--violet), var(--violet-dark));
    box-shadow: 0 6px 18px rgba(124, 92, 255, .35);
    transition: transform .15s ease;
}

.btn-big:active {
    transform: scale(.97);
}

.btn-outline {
    background: var(--card);
    color: var(--violet);
    box-shadow: var(--shadow);
}

.btn-ghost {
    background: transparent;
    color: var(--muted);
    box-shadow: inset 0 0 0 2px var(--bezel);
}

.btn-mini {
    border: none;
    background: var(--blue);
    color: #fff;
    border-radius: 10px;
    padding: 7px 16px;
    font-size: 16px;
    cursor: pointer;
}

/* slim install banner pinned above the home header (competitor-style) */
#install-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--card);
    border-radius: 14px;
    padding: 10px 12px;
    margin: 2px 0 10px;
    box-shadow: var(--shadow);
    font-size: 13px;
}

#install-banner .ib-text {
    flex: 1;
    font-weight: 700;
}

#install-banner-go {
    border: none;
    background: var(--blue);
    color: #fff;
    font-weight: 700;
    border-radius: 10px;
    padding: 8px 14px;
    font-size: 13px;
    cursor: pointer;
}

#install-banner-close {
    border: none;
    background: transparent;
    color: var(--muted);
    font-size: 15px;
    cursor: pointer;
    padding: 4px 6px;
}

html[data-theme="dark"] #install-banner {
    background: #1c2033;
}

/* create-room settings dialog */
.cr-group {
    margin: 14px 0;
    text-align: left;
}

.cr-label {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 8px;
}

.cr-opts {
    display: flex;
    gap: 8px;
}

.cr-opts button {
    flex: 1;
    border: 2px solid var(--bezel);
    background: var(--card);
    color: var(--text);
    border-radius: 12px;
    padding: 12px 6px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: transform .12s ease;
}

.cr-opts button.on {
    border-color: var(--blue);
    background: rgba(47, 109, 246, .1);
    color: var(--blue);
}

.cr-opts button:active {
    transform: scale(.95);
}

#cr-mode-hint {
    margin: 8px 2px 0;
}

/* lobby room shows its type under the nick */
.r-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 1px;
    text-align: left;
}

.r-info small {
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 600;
}

html[data-theme="dark"] .cr-opts button {
    background: #232a40;
}

html[data-theme="dark"] .cr-opts button.on {
    background: rgba(47, 109, 246, .22);
}

/* legal footer links */
/* The whole footer now, since the social row and the two side buttons that used
   to sit above it are gone. It carries the top margin the removed block was
   providing, so the legal links do not ride up under the last card. */
.footer-block {
    margin-top: 26px;
    padding-bottom: 4px;
}

.legal-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 7px;
    margin-top: 18px;
}

.legal-links a {
    color: var(--muted);
    font-size: 12px;
    cursor: pointer;
}

.legal-links a:active {
    color: var(--violet);
}

.legal-links span {
    color: var(--bezel);
    font-size: 12px;
}

.legal-agree {
    text-align: center;
    color: var(--muted);
    font-size: 10.5px;
    margin: 8px 12px 0;
    opacity: .8;
}

/* legal page text: preserve line breaks, scrollable */
/* Documents keep their title and close button pinned while the body scrolls,
   so a long text never hides the way out of the dialog. */
/* .modal sets text-align:center further down the file and has equal
   specificity, so this has to be stated more specifically to win. */
.modal.legal-modal {
    text-align: start;
    max-height: 88dvh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    padding: 24px 0 20px;
}

.legal-modal h2 {
    text-align: center;
    flex: none;
    padding: 0 22px;
    font-size: 20px;
}

.legal-modal .doc-updated {
    flex: none;
    text-align: center;
    padding: 6px 22px 0;
    color: var(--muted);
    font-size: 11.5px;
}

.legal-modal .modal-buttons {
    flex: none;
    padding: 0 22px;
    margin-top: 14px;
}

.legal-text {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 14px 22px 4px;
    margin: 0;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text);
    -webkit-overflow-scrolling: touch;
}

/* Long-form prose reads left-aligned; centring it was the main reason the
   documents looked amateur. */
.legal-text p {
    margin: 0 0 12px;
}

.legal-text h3 {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text);
    margin: 20px 0 7px;
    padding-bottom: 5px;
    border-bottom: 1px solid var(--bg2);
}

.legal-text h3:first-child {
    margin-top: 0;
}

.legal-text ul {
    margin: 0 0 12px;
    padding-inline-start: 18px;
}

.legal-text li {
    margin-bottom: 5px;
}

.legal-text strong {
    font-weight: 700;
}

.legal-text a {
    color: var(--violet);
    font-weight: 600;
}

/* fades that hint there is more text below */
.legal-modal {
    position: relative;
}

.legal-modal::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: 74px;
    height: 22px;
    background: linear-gradient(transparent, var(--card));
    pointer-events: none;
}

html[data-theme="dark"] .legal-links span {
    color: #333c5c;
}

.btn-danger {
    background: linear-gradient(120deg, #ff6b6b, #e0455e);
    box-shadow: 0 6px 18px rgba(255, 90, 90, .35);
}

.btn-link {
    background: none;
    border: none;
    color: var(--violet);
    font: inherit;
    font-size: 14px;
    cursor: pointer;
    padding: 6px;
}

.input {
    width: 100%;
    padding: 15px 16px;
    border: 2px solid transparent;
    border-radius: 14px;
    background: var(--card);
    box-shadow: var(--shadow);
    font: inherit;
    font-size: 16px;
    color: var(--text);
    outline: none;
    text-align: center;
}

.input:focus {
    border-color: var(--violet);
}

/* ============ rooms ============ */
.rooms-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 18px;
    min-height: 120px;
}

.room-item {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--card);
    border-radius: 16px;
    padding: 14px 16px;
    box-shadow: var(--shadow);
}

.room-item .r-avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    flex: none;
    background: linear-gradient(135deg, var(--violet2), var(--violet));
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 700;
}

.room-item b {
    flex: 1;
}

.room-item .btn-join {
    border: none;
    cursor: pointer;
    font: inherit;
    font-weight: 600;
    color: #fff;
    background: var(--violet);
    border-radius: 12px;
    padding: 10px 20px;
}

.rooms-empty {
    text-align: center;
    color: var(--muted);
    padding: 40px 20px;
}

/* ============ friend / waiting ============ */
.friend-box {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-top: 10px;
}

.divider {
    text-align: center;
    color: var(--muted);
}

.waiting-box {
    min-height: 70dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 20px;
    text-align: center;
}

.spinner {
    width: 54px;
    height: 54px;
    border-radius: 50%;
    border: 5px solid rgba(124, 92, 255, .2);
    border-top-color: var(--violet);
    animation: spin 1s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.code-box {
    background: var(--card);
    border-radius: 18px;
    padding: 18px;
    box-shadow: var(--shadow);
    width: 100%;
    max-width: 340px;
}

.code-box .btn-big {
    margin-top: 12px;
}

.invite-or {
    color: var(--muted);
    font-size: 12px;
    margin-top: 14px;
}

.code {
    font-size: 30px;
    font-weight: 800;
    letter-spacing: 7px;
    color: var(--violet);
    margin-top: 2px;
    direction: ltr;
}

/* ============ game ============ */
#screen-game {
    padding: 12px 10px calc(10px + env(safe-area-inset-bottom, 0px));
    display: none;
}

#screen-game.active {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-height: 100dvh;
}

.game-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 2px 4px;
}

.g-logo {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 19px;
}

/* The same mark at 32px, in the game header. Rows and dots shrink with it —
   left at their full size they overflow the padding and the wall touches the
   edge. */
.logo-mark.sm {
    width: 32px;
    height: 32px;
    border-radius: 10px;
    padding: 6px;
    grid-template-rows: 7px 4px 7px;
    gap: 1px;
    box-shadow: 0 5px 12px rgba(23, 30, 45, .4);
}

.logo-mark.sm span:nth-child(2),
.logo-mark.sm span:nth-child(3) {
    width: 7px;
}

.btn-giveup {
    border: none;
    cursor: pointer;
    font: inherit;
    font-weight: 700;
    font-size: 13px;
    background: var(--card);
    color: var(--text);
    border-radius: 14px;
    padding: 9px 14px;
    box-shadow: var(--shadow);
}

/* VS row: two colored player pills */
.vs-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
}

.p-pill {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    border-radius: 16px;
    padding: 9px 10px;
    color: #fff;
    box-shadow: 0 8px 18px rgba(30, 45, 90, .25), inset 0 1px 0 rgba(255, 255, 255, .25);
}

.p-pill.blue {
    background: linear-gradient(160deg, #33549c, #24407e);
}

.p-pill.red {
    background: linear-gradient(160deg, #d8404d, #b32538);
}

.p-pill .chip-ball {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    flex: none;
    position: relative;
    box-shadow: inset -4px -6px 8px rgba(0, 0, 0, .35), inset 3px 4px 6px rgba(255, 255, 255, .35), 0 3px 6px rgba(0, 0, 0, .3);
}

/* Rank rides on the ball rather than beside the nickname: the pill is narrow
   and the nickname must stay readable. */
.p-pill .chip-ball .rank-ic {
    position: absolute;
    inset-inline-end: -5px;
    bottom: -4px;
    font-size: 13px;
    line-height: 1;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .5);
}

.pill-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    min-width: 0;
}

.pill-info b {
    font-size: 14px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pill-info small {
    font-size: 11px;
    opacity: .85;
}

.p-pill .chip-clock {
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    font-size: 15px;
    background: rgba(255, 255, 255, .18);
    border-radius: 9px;
    padding: 5px 7px;
    color: #fff;
}

.p-pill .chip-clock.danger {
    background: rgba(255, 90, 90, .55);
    animation: pulse 1s infinite;
}

.p-pill.turn-active {
    box-shadow: 0 0 0 3px #fff, 0 0 0 6px rgba(47, 109, 246, .45), 0 8px 18px rgba(30, 45, 90, .3);
}

.vs-badge {
    align-self: center;
    background: var(--card);
    color: var(--muted);
    font-weight: 800;
    font-size: 13px;
    border-radius: 12px;
    padding: 10px 9px;
    box-shadow: var(--shadow);
    flex: none;
}

.board-wrap {
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.zone-label {
    display: flex;
    align-items: center;
    gap: 12px;
    justify-content: center;
    font-size: 12px;
    letter-spacing: 3px;
    font-weight: 800;
    padding: 6px 6px;
}

.zone-label::before,
.zone-label::after {
    content: '';
    flex: 1;
    max-width: 130px;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    opacity: .5;
}

.zone-label.blue {
    color: #3b78e7;
}

.zone-label.red {
    color: #d8404d;
}

/* board: silver tray with a thin pencil grid */
#board {
    position: relative;
    width: 100%;
    aspect-ratio: 1;
    max-width: min(87vw, 55dvh);
    margin: 16px auto;
    background: linear-gradient(168deg, #fdfdff, #f0f1f8 70%, #e9ebf4);
    border-radius: 14px;
    box-shadow:
        0 0 0 11px var(--bezel),
        0 0 0 12px #aeb9cf,
        0 1px 0 12px #98a5c0,
        0 26px 46px rgba(45, 65, 120, .32),
        inset 0 2px 6px rgba(120, 135, 175, .25);
    /* pan-y, not none: with none the browser refuses to scroll while the finger
     is on the board, so the emoji row below it could not be reached during a
     game. Tapping a cell still works — a touch that travels more than 14px is
     already treated as a scroll rather than a move. */
    touch-action: pan-y;
}

/* pencil grid over one continuous surface, like the competitor */
.grid-line {
    position: absolute;
    z-index: 1;
    pointer-events: none;
    background: rgba(95, 115, 165, .30);
}

/* translucent end zones with a bright bar on the board edge */
.zone-band {
    position: absolute;
    z-index: 0;
    pointer-events: none;
}

.zone-band.top {
    border-radius: 13px 13px 0 0;
}

.zone-band.bottom {
    border-radius: 0 0 13px 13px;
}

.zone-band.top.red {
    background: linear-gradient(180deg, rgba(227, 61, 82, .30), rgba(227, 61, 82, .10) 65%, transparent);
    box-shadow: inset 0 3px 0 rgba(227, 61, 82, .85);
}

.zone-band.top.blue {
    background: linear-gradient(180deg, rgba(47, 109, 246, .30), rgba(47, 109, 246, .10) 65%, transparent);
    box-shadow: inset 0 3px 0 rgba(47, 109, 246, .85);
}

.zone-band.bottom.red {
    background: linear-gradient(0deg, rgba(227, 61, 82, .30), rgba(227, 61, 82, .10) 65%, transparent);
    box-shadow: inset 0 -3px 0 rgba(227, 61, 82, .85);
}

.zone-band.bottom.blue {
    background: linear-gradient(0deg, rgba(47, 109, 246, .30), rgba(47, 109, 246, .10) 65%, transparent);
    box-shadow: inset 0 -3px 0 rgba(47, 109, 246, .85);
}

/* race mode: the shared finish line on top is green */
.zone-band.top.finish {
    background: linear-gradient(180deg, rgba(33, 192, 122, .30), rgba(33, 192, 122, .10) 65%, transparent);
    box-shadow: inset 0 3px 0 rgba(33, 192, 122, .85);
}

.zone-label.finish {
    color: #1da96c;
}

/* cells are invisible tap targets on top of the grid */
.cell {
    position: absolute;
    z-index: 2;
    background: transparent;
}

.cell.legal {
    cursor: pointer;
}

/* legal moves = little glossy balls of your colour */
.cell.legal::after {
    content: '';
    position: absolute;
    inset: 33%;
    border-radius: 50%;
    box-shadow: inset -2px -3px 4px rgba(0, 0, 0, .3), inset 1px 2px 3px rgba(255, 255, 255, .5), 0 2px 4px rgba(0, 0, 0, .25);
    animation: hintPop .25s ease;
}

@keyframes hintPop {
    from {
        transform: scale(.4);
        opacity: 0;
    }
}

#board.my-blue .cell.legal::after {
    background: radial-gradient(circle at 32% 28%, #9cc1ff, #2f6df6 65%, #1d4fbd);
}

#board.my-red .cell.legal::after {
    background: radial-gradient(circle at 32% 28%, #ffa3ac, #e33d52 65%, #b02338);
}

.pawn {
    position: absolute;
    border-radius: 50%;
    z-index: 5;
    pointer-events: none;
    box-shadow: inset -4px -8px 12px rgba(0, 0, 0, .4), inset 2px 4px 6px rgba(255, 255, 255, .25), 0 8px 12px rgba(10, 20, 50, .45);
    /* Linear. Three things were asked for and every curve tried breaks one:

       one square only    — any control point above 1 overshoots and comes back
       even, unhurried    — an ease-in stalls at the start, an ease-out at the end
       .21s               — the length itself was never the complaint

     A straight line does all three. Constant speed from the square it leaves
     to the square it lands on: nothing to overshoot, nothing to wait through,
     no part of the journey faster than any other. */
    transition: left .21s linear, top .21s linear;
}

/* crisp specular highlight, like a billiard ball */
.pawn::after {
    content: '';
    position: absolute;
    left: 20%;
    top: 12%;
    width: 30%;
    height: 24%;
    border-radius: 50%;
    background: radial-gradient(ellipse at center, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 72%);
}

.pawn.red {
    background: radial-gradient(circle at 31% 24%, #ffd0d5 0%, #f57784 22%, #e33d52 55%, #8f1626 100%);
}

.pawn.blue {
    background: radial-gradient(circle at 31% 24%, #cfe1ff 0%, #6f9cf9 22%, #2f6df6 55%, #143a8f 100%);
}

.pawn.glow {
    box-shadow: 0 0 0 4px rgba(255, 255, 255, .95), 0 0 18px 6px rgba(120, 150, 220, .55), inset -4px -7px 10px rgba(0, 0, 0, .35), 0 6px 10px rgba(20, 35, 80, .35);
}

/* walls: glossy capsules in the owner's color (blue = player 0, red = player 1) */
.wall {
    position: absolute;
    border-radius: 999px;
    z-index: 4;
    pointer-events: none;
    background: linear-gradient(180deg, #48547e 0%, #2b3355 45%, #161c34 100%);
    box-shadow: 0 5px 9px rgba(12, 18, 40, .5), inset 0 2px 2px rgba(255, 255, 255, .3);
    animation: wallIn .2s ease;
}

.wall.blue {
    background: linear-gradient(180deg, #7aa3fb 0%, #2f6df6 45%, #1a48b8 100%);
    box-shadow: 0 5px 9px rgba(18, 45, 120, .45), inset 0 2px 2px rgba(255, 255, 255, .35);
}

.wall.red {
    background: linear-gradient(180deg, #f2808f 0%, #e33d52 45%, #ad1f33 100%);
    box-shadow: 0 5px 9px rgba(130, 20, 35, .45), inset 0 2px 2px rgba(255, 255, 255, .35);
}

@keyframes wallIn {
    from {
        transform: scale(.6);
        opacity: 0;
    }
}

.wall.no-anim {
    animation: none;
}

.wall.preview-ok {
    opacity: .88;
    outline: 2px dashed rgba(255, 255, 255, .95);
    outline-offset: 1px;
}

.wall.preview-bad {
    background: #c3c8d6 !important;
    opacity: .65;
    box-shadow: none;
}

.game-hint {
    text-align: center;
    font-size: 12px;
    color: var(--muted);
    padding: 2px 10px;
    min-height: 18px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* wall dock: grab a wall (─ or │) and drag it onto the board */
.wall-dock {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    background: var(--card);
    border-radius: 18px;
    padding: 9px 14px;
    margin: 4px auto 0;
    max-width: 320px;
    box-shadow: var(--shadow);
}

.dock-count {
    font-weight: 800;
    font-size: 15px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 5px;
}

.dock-handle {
    border: none;
    cursor: grab;
    width: 74px;
    height: 52px;
    border-radius: 14px;
    background: linear-gradient(180deg, #ffffff, #eef1f8);
    box-shadow: 0 5px 12px rgba(50, 70, 130, .18), inset 0 1px 0 #fff, inset 0 -2px 4px rgba(140, 155, 190, .25);
    display: grid;
    place-items: center;
    touch-action: none;
    transition: transform .12s ease, opacity .15s ease;
}

.dock-handle:active {
    transform: scale(.93);
    cursor: grabbing;
}

.dock-handle.disabled {
    opacity: .35;
    pointer-events: none;
}

.dh-bar {
    border-radius: 999px;
    background: linear-gradient(180deg, #48547e 0%, #2b3355 45%, #161c34 100%);
    box-shadow: 0 3px 6px rgba(12, 18, 40, .45), inset 0 2px 2px rgba(255, 255, 255, .3);
}

.dh-bar.h {
    width: 42px;
    height: 12px;
}

.dh-bar.v {
    width: 12px;
    height: 34px;
}

.game-bottom2 {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
}

.turn-pill {
    flex: 1;
    text-align: center;
    font-weight: 700;
    font-size: 14px;
    color: #fff;
    background: #384263;
    border-radius: 999px;
    padding: 10px 14px;
    box-shadow: 0 8px 18px rgba(30, 45, 90, .3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.emoji-bar {
    display: flex;
    gap: 4px;
}

.emoji-bar button {
    border: none;
    background: var(--card);
    box-shadow: var(--shadow);
    cursor: pointer;
    font-size: 19px;
    width: 40px;
    height: 40px;
    border-radius: 13px;
    transition: transform .12s ease;
}

.emoji-bar button:active {
    transform: scale(1.25);
}

.emoji-pop {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 30;
    font-size: 44px;
    animation: emojiIn .35s cubic-bezier(.4, 1.8, .5, 1);
    filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .25));
}

@keyframes emojiIn {
    from {
        transform: scale(0) rotate(-30deg);
    }
}

/* ============ overlays / modals ============ */
.overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    place-items: center;
    background: rgba(35, 35, 60, .45);
    backdrop-filter: blur(4px);
    animation: fadeIn .2s ease;
}

.modal {
    width: min(88vw, 380px);
    background: var(--card);
    border-radius: 24px;
    padding: 28px 22px;
    text-align: center;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
    animation: modalIn .28s cubic-bezier(.4, 1.4, .5, 1);
    /* Content taller than the phone used to be clipped by the viewport with no
     way to reach it. Every dialog now scrolls instead of losing its tail. */
    max-height: 88dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
}

@keyframes modalIn {
    from {
        transform: scale(.85);
        opacity: 0;
    }
}

.result-emoji {
    font-size: 58px;
    margin-bottom: 8px;
}

.modal h2 {
    margin-bottom: 6px;
    font-size: 21px;
    text-wrap: balance;
}

.modal-buttons {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 20px;
}

.modal-buttons.row {
    flex-direction: row;
}

/* an <a> styled as a button must not keep the link underline */
a.btn-big {
    text-decoration: none;
    display: block;
}

/* victory screen (competitor style) */
.win-modal {
    border-top: 7px solid var(--blue);
    padding-top: 22px;
    position: relative;
}

.win-modal.lose {
    border-top-color: var(--red);
}

.result-title {
    font-size: 42px;
    font-weight: 900;
    letter-spacing: 1px;
    color: var(--blue);
    margin-bottom: 2px;
}

.win-modal.lose .result-title {
    color: var(--red);
}

.result-stats {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 18px;
    background: #f4f6fc;
    border-radius: 18px;
    padding: 14px 10px;
    margin-top: 16px;
}

.rs-side {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    flex: 1;
    min-width: 0;
}

.rs-side b {
    font-size: 14px;
    max-width: 110px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rs-side small {
    font-size: 11px;
    letter-spacing: 2px;
    font-weight: 800;
    color: var(--muted);
}

.rs-side small.win {
    color: var(--green);
}

.rs-side small.loss {
    color: var(--red);
}

.rs-ball {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    box-shadow: inset -4px -6px 8px rgba(0, 0, 0, .35), inset 3px 4px 6px rgba(255, 255, 255, .4), 0 4px 8px rgba(0, 0, 0, .25);
}

.rs-ball.red {
    background: radial-gradient(circle at 32% 26%, #ffb9c0, #e33d52 62%, #a91f33);
}

.rs-ball.blue {
    background: radial-gradient(circle at 32% 26%, #b6d2ff, #2f6df6 62%, #1a48b8);
}

.rs-mid {
    color: var(--muted);
    font-weight: 800;
    font-size: 13px;
}

.confetti {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.confetti span {
    position: absolute;
    top: -4vh;
    width: 9px;
    height: 15px;
    border-radius: 3px;
    animation: confettiFall linear infinite;
}

@keyframes confettiFall {
    0% {
        transform: translateY(-6vh) rotate(0deg);
    }

    100% {
        transform: translateY(108vh) rotate(720deg);
    }
}

/* ============ leaderboard ============ */
.lb-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.lb-item {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--card);
    border-radius: 16px;
    padding: 12px 16px;
    box-shadow: var(--shadow);
}

.lb-item .lb-rank {
    width: 30px;
    font-weight: 800;
    color: var(--muted);
    text-align: center;
    font-size: 15px;
}

.lb-item:nth-child(1) .lb-rank {
    font-size: 20px;
}

.lb-item .r-avatar {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--violet2), var(--violet));
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 700;
    flex: none;
}

.lb-item .lb-nick {
    flex: 1;
    font-weight: 600;
}

.lb-item .lb-score b {
    color: var(--violet);
    font-size: 17px;
}

.lb-item .lb-score small {
    color: var(--muted);
    display: block;
    text-align: right;
    font-size: 11px;
}

.lb-empty {
    text-align: center;
    color: var(--muted);
    padding: 50px 20px;
}

/* ============ profile ============ */
.profile-card {
    background: var(--card);
    border-radius: 22px;
    padding: 24px;
    text-align: center;
    box-shadow: var(--shadow);
    margin-bottom: 16px;
}

.avatar {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    margin: 0 auto 10px;
    background: linear-gradient(135deg, var(--violet2), var(--violet));
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 30px;
    font-weight: 800;
}

.stats-row {
    display: flex;
    justify-content: center;
    gap: 18px;
    flex-wrap: wrap;
    margin: 16px 0 10px;
}

.stat {
    display: flex;
    flex-direction: column;
}

.stat b {
    font-size: 22px;
}

.stat small {
    color: var(--muted);
    font-size: 12px;
}

.auth-box {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 16px;
}

.auth-msg {
    color: var(--red);
    font-size: 14px;
    text-align: center;
}

.auth-msg.ok {
    color: var(--green);
}

.settings-box {
    background: var(--card);
    border-radius: 18px;
    box-shadow: var(--shadow);
}

.setting-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 15px 18px;
    font-weight: 600;
}

.setting-row+.setting-row {
    border-top: 1px solid var(--bg2);
}

/* ============ support / advertise dialogs ============ */
.modal-emoji {
    font-size: 34px;
    line-height: 1;
    margin-bottom: 4px;
}

/* labelled separator instead of a stray bullet floating between blocks */
.opt-or {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 12px 2px 0;
    color: var(--muted);
    font-size: 12px;
}

.opt-or::before,
.opt-or::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--bg2);
}

/* ============ daily streak ============ */
/* The flame never becomes a different object — it is recoloured and grown, so
   each tier reads as the same fire levelling up rather than a new trophy. */
.flame {
    display: inline-block;
    line-height: 1;
    filter: saturate(.75);
    font-size: 15px;
}

.flame.fl-1 {
    filter: saturate(.6) brightness(1.05);
    font-size: 14px;
}

.flame.fl-7 {
    filter: saturate(1.15);
    font-size: 15px;
}

.flame.fl-30 {
    filter: hue-rotate(185deg) saturate(1.5);
    font-size: 16px;
}

.flame.fl-50 {
    filter: hue-rotate(255deg) saturate(1.5);
    font-size: 16px;
}

.flame.fl-100 {
    filter: grayscale(1) brightness(1.7) drop-shadow(0 0 5px #9fd8ff);
    font-size: 17px;
}

.flame.fl-200 {
    filter: hue-rotate(-18deg) saturate(2) drop-shadow(0 0 5px #ffc400);
    font-size: 17px;
}

.flame.fl-365 {
    filter: saturate(2.2) drop-shadow(0 0 4px #ff4fa3) drop-shadow(0 0 9px #4fd2ff);
    font-size: 18px;
}

/* Alive, but today has not been played yet — the fire is out until it is.
   Sits after every tier above: same specificity, so source order is what makes
   it win, and replacing the whole filter drops the tier glow with it. */
.flame.unlit {
    filter: grayscale(1) opacity(.45);
}

.head-pills {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
}

.streak-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 12px;
    background: var(--card);
    border-radius: 999px;
    padding: 7px 14px;
    font-size: 14px;
    box-shadow: var(--shadow);
}

.streak-card {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--bg2);
    border-radius: 16px;
    padding: 11px 14px;
    margin-top: 9px;
    text-align: start;
}

.streak-card.cold {
    opacity: .72;
}

/* Offered only when a streak was lost, so it should read as a way back rather
   than as another thing to buy — icy blue, not the gold of the support button. */
.btn-restore {
    margin-top: 10px;
    background: #e8f1ff;
    color: #1a4f9c;
    border: 1px solid #c2dbff;
}

/* The flame is a button on both screens, and always tappable: it opens the
   window that explains itself. The ring is added only when a broken streak is
   waiting behind it, so the offer still reads as urgent without a banner. */
.streak-pill,
.flame-btn {
    border: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.flame-btn {
    background: none;
    padding: 0;
    line-height: 1;
}

.streak-pill:active,
.flame-btn:active {
    transform: scale(.95);
}

.streak-pill.broken {
    box-shadow: var(--shadow), 0 0 0 2px rgba(47, 109, 246, .35);
}

/* the flame window */
/* the window is long, so the flame is smaller here than in the celebration and
   the sections sit tight — most phones then get the whole thing without a scroll */
#overlay-streak-info .flame.cel-flame {
    font-size: 46px;
    animation: none;
}

#overlay-streak-info h2 {
    font-size: 19px;
    margin-top: 4px;
}

#overlay-streak-info .hint {
    font-size: 13px;
}

#overlay-streak-info .modal-buttons {
    margin-top: 16px;
}

.info-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background: var(--bg2);
    border-radius: 14px;
    padding: 11px 14px;
    margin: 14px 0 7px;
    font-size: 14px;
    text-align: start;
}

.info-row b {
    white-space: nowrap;
    font-size: 16px;
}

.info-h {
    font-size: 12px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
    margin-top: 16px;
    margin-bottom: 6px;
}

.flame-list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: center;
    margin-bottom: 8px;
}

.flame-list li {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 13px;
    background: var(--bg2);
    border-radius: 999px;
    padding: 5px 10px;
    /* ranges and milestone lists read low-to-high in every language */
    direction: ltr;
    unicode-bidi: isolate;
}

/* the tier the player is on right now */
.flame-list li.now {
    box-shadow: inset 0 0 0 2px var(--blue);
    font-weight: 700;
}

.flame-list .flame {
    font-size: 18px;
}

.milestones {
    font-weight: 700;
    font-size: 15px;
    direction: ltr;
    unicode-bidi: isolate;
}

html[data-theme="dark"] .btn-restore {
    background: #1d2b46;
    color: #9fc8ff;
    border-color: #2c3f63;
}

.streak-card .flame {
    font-size: 26px;
}

.streak-meta {
    min-width: 0;
}

.streak-meta b {
    display: block;
    font-size: 15px;
}

.streak-meta small {
    display: block;
    color: var(--muted);
    font-size: 12px;
}

.streak-line {
    text-align: center;
    font-weight: 700;
    font-size: 14.5px;
    margin-top: 6px;
    color: var(--text);
}

.streak-line.milestone {
    font-size: 16.5px;
    color: var(--violet);
}

/* milestone celebration */
.streak-overlay {
    z-index: 120;
    background: rgba(10, 10, 26, .88);
}

.cel {
    position: relative;
    text-align: center;
    padding: 0 26px;
    animation: celIn .45s cubic-bezier(.3, 1.5, .5, 1);
}

@keyframes celIn {
    from {
        transform: scale(.7);
        opacity: 0;
    }
}

.cel-glow {
    position: absolute;
    top: -30px;
    left: 50%;
    width: 260px;
    height: 260px;
    transform: translateX(-50%);
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle, rgba(255, 160, 40, .55), transparent 65%);
    animation: celPulse 2.2s ease-in-out infinite;
}

@keyframes celPulse {
    50% {
        transform: translateX(-50%) scale(1.18);
        opacity: .75;
    }
}

.flame.cel-flame {
    position: relative;
    font-size: 88px;
    animation: celFlame 1.6s ease-in-out infinite;
}

@keyframes celFlame {
    50% {
        transform: scale(1.09) translateY(-4px);
    }
}

.cel-num {
    position: relative;
    font-size: 62px;
    font-weight: 800;
    color: #fff;
    line-height: 1;
    margin-top: 4px;
    letter-spacing: -2px;
}

.cel-title {
    position: relative;
    color: #fff;
    font-size: 20px;
    margin-top: 8px;
}

.cel-sub {
    position: relative;
    color: rgba(255, 255, 255, .75);
    font-size: 14px;
    margin: 8px 0 22px;
}

.cel .btn-big {
    position: relative;
    min-width: 180px;
}

/* sparks drifting up behind the flame */
.sparks {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
}

.sparks i {
    position: absolute;
    bottom: -20px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #ffb340;
    box-shadow: 0 0 8px #ff8a1f;
    opacity: 0;
    animation: spark linear infinite;
}

@keyframes spark {
    0% {
        transform: translateY(0) scale(1);
        opacity: 0;
    }

    15% {
        opacity: .9;
    }

    100% {
        transform: translateY(-105vh) scale(.3);
        opacity: 0;
    }
}

/* ============ ladder: rank card, badges, points ============ */
.rank-card {
    display: flex;
    align-items: center;
    gap: 13px;
    background: var(--bg2);
    border-radius: 16px;
    padding: 12px 14px;
    margin: 14px 0 4px;
    text-align: start;
}

.rank-badge {
    font-size: 30px;
    line-height: 1;
    flex: none;
}

.rank-meta {
    flex: 1;
    min-width: 0;
}

.rank-meta b {
    display: block;
    font-size: 16px;
}

.rank-meta small {
    display: block;
    color: var(--muted);
    font-size: 12px;
}

.rank-bar {
    height: 6px;
    border-radius: 99px;
    background: var(--card);
    margin: 7px 0 5px;
    overflow: hidden;
}

.rank-bar i {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--violet2), var(--violet));
    transition: width .5s ease;
}

.veteran-badge {
    font-size: 12px;
    font-weight: 700;
    color: #a37500;
    margin-top: 6px;
}

/* rank icon beside a nickname during the match — icon only, no number */
.rank-ic:not(:empty) {
    margin-inline-end: 4px;
}

/* points earned, on the result screen */
.pts-row {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 10px;
    margin-top: 14px;
}

.pts-delta {
    font-size: 27px;
    font-weight: 800;
    letter-spacing: -.5px;
}

.pts-delta.up {
    color: var(--green);
}

.pts-delta.down {
    color: var(--red);
}

.pts-total {
    color: var(--muted);
    font-size: 13px;
}

.rank-up {
    text-align: center;
    font-weight: 700;
    font-size: 15px;
    margin-top: 7px;
}

.rank-up.up {
    color: var(--violet);
}

.rank-up.down {
    color: var(--muted);
}

.lb-item .lb-nick {
    min-width: 0;
}

.lb-nick .lb-name {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lb-nick .lb-badge {
    display: block;
    color: var(--muted);
    font-size: 11.5px;
    font-weight: 600;
}

.lb-item .lb-score small {
    text-align: end;
}

.lang-current {
    border: none;
    cursor: pointer;
    font: inherit;
    font-weight: 700;
    font-size: 13px;
    padding: 8px 14px;
    border-radius: 10px;
    background: var(--bg2);
    color: var(--text);
}

.lang-list {
    display: grid;
    gap: 8px;
    margin-top: 14px;
}

.lang-list button {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    border: none;
    cursor: pointer;
    font: inherit;
    font-size: 15px;
    font-weight: 600;
    padding: 13px 15px;
    border-radius: 14px;
    background: var(--bg2);
    color: var(--text);
    text-align: start;
}

.lang-list button .lf {
    font-size: 19px;
    line-height: 1;
}

.lang-list button.active {
    background: var(--violet);
    color: #fff;
}

/* Right-to-left languages flip the menus, but never the board: the grid must
   keep filling left to right or the position would be shown mirrored. */
html[dir="rtl"] .board-wrap,
html[dir="rtl"] #board,
html[dir="rtl"] .wall-dock,
html[dir="rtl"] .vs-row,
html[dir="rtl"] .code,
html[dir="rtl"] .wallet code {
    direction: ltr;
}

/* ================= voice (friend rooms) ================= */

.voice-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 10px auto 0;
    padding: 0 4px;
    /* The peer status drops to its own line rather than being clipped. Label
       lengths vary a lot between the six languages, and "Their mic is on"
       truncated to "Their mic…" tells the player the opposite of nothing — it
       tells them nothing while looking like it said something. */
    flex-wrap: wrap;
}

#voice-audio {
    display: none;
}

.voice-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--muted);
    font: inherit;
    font-size: 12.5px;
    font-weight: 700;
    padding: 8px 13px;
    min-height: 40px;
    border-radius: 14px;
    cursor: pointer;
}

.voice-btn svg {
    width: 17px;
    height: 17px;
    fill: currentColor;
    flex: none;
}

/* Live is the one state that must be readable across the room at a glance —
   it is the difference between talking and being overheard. Red, filled, and
   pulsing, rather than a subtle change of tint. */
.voice-btn.live {
    background: var(--red);
    border-color: var(--red);
    color: #fff;
    animation: voice-pulse 1.6s ease-in-out infinite;
}

.voice-btn.muted {
    color: var(--text);
    border-color: var(--line);
}

.voice-btn.busy {
    opacity: .65;
}

@keyframes voice-pulse {

    0%,
    100% {
        box-shadow: 0 0 0 0 rgba(232, 75, 85, .45);
    }

    50% {
        box-shadow: 0 0 0 7px rgba(232, 75, 85, 0);
    }
}

/* Someone who finds motion distracting still needs to know the mic is open, so
   the colour carries the meaning and only the animation is dropped. */
@media (prefers-reduced-motion: reduce) {
    .voice-btn.live {
        animation: none;
    }
}

.voice-leave {
    border: 1px solid var(--line);
    background: var(--card);
    color: var(--muted);
    font: inherit;
    font-size: 13px;
    line-height: 1;
    width: 34px;
    height: 34px;
    border-radius: 11px;
    cursor: pointer;
    flex: none;
}

.voice-peer {
    font-size: 11.5px;
    color: var(--muted);
    /* Wide enough to be worth reading, or it goes to its own line. */
    flex: 1 1 130px;
    text-align: end;
    min-width: 0;
}

/* Chevrons are drawn as characters, so they need flipping by hand. */
html[dir="rtl"] .card-arrow,
html[dir="rtl"] .btn-back {
    transform: scaleX(-1);
}

/* Tracking is a Latin typographic device. Arabic script is cursive — its
   letters join — and positive letter-spacing prises those joins apart, so the
   Persian tagline rendered as a row of disconnected shapes rather than a word.
   It looks like a broken font, not a styling choice.

   Only the decorative tracking is reset. Negative values are tightening on
   large Latin display text (the logo, the score) and never apply to Persian
   text anyway, and .code keeps its spacing because it is forced to LTR above. */
html[dir="rtl"] .tagline,
html[dir="rtl"] .zone-label,
html[dir="rtl"] .cr-label,
html[dir="rtl"] .info-h,
html[dir="rtl"] .result-title,
html[dir="rtl"] .rs-side small,
html[dir="rtl"] .nav-btn,
html[dir="rtl"] .wallet-net {
    letter-spacing: normal;
}

.toggle {
    position: relative;
    display: inline-block;
    width: 50px;
    height: 28px;
}

.toggle input {
    opacity: 0;
    width: 0;
    height: 0;
}

.toggle span {
    position: absolute;
    inset: 0;
    border-radius: 999px;
    background: var(--bg2);
    transition: .2s;
    cursor: pointer;
}

.toggle span::before {
    content: '';
    position: absolute;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    left: 3px;
    top: 3px;
    background: #fff;
    transition: .2s;
    box-shadow: 0 2px 5px rgba(0, 0, 0, .2);
}

.toggle input:checked+span {
    background: var(--violet);
}

.toggle input:checked+span::before {
    transform: translateX(22px);
}

/* ============ bottom nav ============ */

/* A floating bar rather than a strip welded to the bottom edge.

   The old one sat flush against the screen with a hairline border, which put it
   in the same visual layer as the cards above it — on a light background the
   two ran together and the bar stopped reading as a control. Lifting it, giving
   it its own radius and a real shadow, separates the two: everything above
   scrolls, this stays.

   The gap underneath is the safe-area inset plus a fixed margin, so the bar
   clears the iPhone home indicator and still floats on everything else.

   The ", 0px" is load-bearing, not tidiness. Firefox on the desktop does not
   define safe-area-inset-*, and an env() with no fallback whose variable is
   undefined makes the whole declaration invalid at computed-value time. `bottom`
   then falls back to `auto`, and a position:fixed element with bottom:auto is
   laid out at its STATIC position — which for this element is after every
   screen, at the end of the document. The bar does not move to the wrong place;
   it stops being pinned at all, and lands below the fold where nobody finds it.
   Chrome defines the variable, so it looked perfect there. */
#bottom-nav {
    position: fixed;
    bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
    left: 50%;
    transform: translateX(-50%);
    width: min(calc(100% - 24px), 468px);
    z-index: 50;
    display: flex;
    gap: 4px;
    padding: 7px;
    border-radius: 22px;
    /* Nearly opaque by default. The translucent version below is an upgrade for
       browsers that can actually blur what is behind it — without the blur,
       0.82 alpha is not frosted glass, it is a page of body text showing
       through the navigation. Firefox had backdrop-filter off by default until
       103, and it is still disabled in some privacy builds. */
    background: rgba(255, 255, 255, .97);
    border: 1px solid rgba(255, 255, 255, .7);
    box-shadow:
        0 1px 2px rgba(30, 45, 90, .04),
        0 8px 28px rgba(30, 45, 90, .14);
}

/* -webkit- is not legacy noise here: iOS below 16 honours only the prefixed
   property, and the query has to name both or Safari fails it and keeps the
   opaque background it did not need. */
/* 0.92, not the 0.8 this started at.

   @supports answers whether the browser KNOWS the property, not whether it will
   actually blur — a machine with GPU compositing off reports support and then
   renders nothing, leaving body text legible straight through the navigation.
   At 0.92 the blur is still visible as depth where it works, and the bar is
   still readable where it does not. Navigation legibility is not something to
   stake on an effect that fails silently. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    #bottom-nav {
        background: rgba(255, 255, 255, .92);
        -webkit-backdrop-filter: blur(18px) saturate(1.7);
        backdrop-filter: blur(18px) saturate(1.7);
    }

    html[data-theme="dark"] #bottom-nav {
        background: rgba(24, 28, 44, .9);
    }
}

#bottom-nav.hidden {
    display: none;
}

.nav-btn {
    flex: 1;
    border: none;
    background: none;
    cursor: pointer;
    font: inherit;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    /* 48px of height before padding: the smallest thing a thumb should have to
       hit, and the reason the label sits close under the icon rather than the
       icon being made bigger */
    min-height: 48px;
    padding: 7px 0 6px;
    border-radius: 16px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 650;
    letter-spacing: .1px;
    -webkit-tap-highlight-color: transparent;
    transition: color .18s ease, background-color .18s ease;
}

.nav-btn .nav-ico {
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
}

.nav-btn .nav-ico svg {
    width: 22px;
    height: 22px;
    /* the icon inherits the button's colour, so one rule tints glyph and label */
    transition: transform .22s cubic-bezier(.34, 1.4, .64, 1);
}

.nav-btn .nav-label {
    line-height: 1;
}

/* The active tab gets a tinted pill behind it. Colour alone was carrying the
   whole state before, which is thin at 11px and invisible to anyone who cannot
   separate blue from grey — the shape is the part that does not depend on
   seeing hue. */
.nav-btn.active {
    color: var(--violet);
    background: rgba(47, 109, 246, .1);
}

.nav-btn.active .nav-ico svg {
    transform: translateY(-1px) scale(1.06);
}

.nav-btn:active {
    background: rgba(47, 109, 246, .16);
}

.nav-btn:focus-visible {
    outline: 2px solid var(--violet);
    outline-offset: 2px;
}

/* Someone who has asked for less motion still gets the colour and the pill;
   only the spring on the icon goes. */
@media (prefers-reduced-motion: reduce) {

    .nav-btn,
    .nav-btn .nav-ico svg {
        transition: none;
    }

    .nav-btn.active .nav-ico svg {
        transform: none;
    }
}

/* ============ toast ============ */
#toast {
    position: fixed;
    left: 50%;
    bottom: 100px;
    transform: translateX(-50%);
    background: #2c2c44;
    color: #fff;
    border-radius: 14px;
    padding: 12px 20px;
    font-size: 14px;
    z-index: 200;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .3);
    animation: fadeIn .25s ease;
    max-width: 86vw;
    text-align: center;
}

/* ============ dark theme (profile toggle) ============ */
html[data-theme="dark"] {
    --bg: #12141f;
    --bg2: #1e2233;
    --card: #1b1f30;
    --text: #e8eaf6;
    --muted: #8b93b4;
    --bezel: #2c3349;
    --shadow: 0 10px 28px rgba(0, 0, 0, .5);
}

html[data-theme="dark"] body {
    background:
        linear-gradient(180deg, rgba(90, 110, 220, .06), rgba(40, 50, 110, .05) 40%, rgba(47, 109, 246, .06)),
        repeating-linear-gradient(0deg, transparent 0 39px, rgba(140, 150, 210, .05) 39px 40px),
        repeating-linear-gradient(90deg, transparent 0 39px, rgba(140, 150, 210, .05) 39px 40px),
        var(--bg);
}

html[data-theme="dark"] #board {
    /* deep navy like the competitor's board */
    background: linear-gradient(168deg, #272e4a, #1d2340 70%, #171c33);
    box-shadow:
        0 0 0 11px var(--bezel),
        0 0 0 12px #232a3e,
        0 1px 0 12px #1a2033,
        0 26px 46px rgba(0, 0, 0, .55),
        inset 0 2px 6px rgba(0, 0, 0, .4);
}

html[data-theme="dark"] .grid-line {
    background: rgba(185, 200, 235, .17);
}

html[data-theme="dark"] .dh-bar {
    background: linear-gradient(180deg, #6b779f 0%, #4a5478 45%, #333c5c 100%);
    box-shadow: 0 5px 9px rgba(0, 0, 0, .5), inset 0 2px 2px rgba(255, 255, 255, .25);
}

/* owner colors must survive the dark theme too */
html[data-theme="dark"] .wall.blue {
    background: linear-gradient(180deg, #7aa3fb 0%, #2f6df6 45%, #1a48b8 100%);
    box-shadow: 0 5px 9px rgba(0, 0, 0, .5), inset 0 2px 2px rgba(255, 255, 255, .35);
}

html[data-theme="dark"] .wall.red {
    background: linear-gradient(180deg, #f2808f 0%, #e33d52 45%, #ad1f33 100%);
    box-shadow: 0 5px 9px rgba(0, 0, 0, .5), inset 0 2px 2px rgba(255, 255, 255, .35);
}

html[data-theme="dark"] .wall.preview-bad {
    background: #3a4054 !important;
}

html[data-theme="dark"] .dock-handle {
    background: linear-gradient(180deg, #262c42, #1c2133);
    box-shadow: 0 5px 12px rgba(0, 0, 0, .4), inset 0 1px 0 rgba(255, 255, 255, .06);
}

html[data-theme="dark"] .turn-pill {
    background: #2a3049;
}

html[data-theme="dark"] .vs-badge,
html[data-theme="dark"] .btn-giveup {
    color: var(--text);
}

/* The bar floats now, so it has a border on all four sides rather than a top
   edge — and border-top-color alone would leave the other three at the light
   theme's near-white, drawing a bright outline around a dark bar. */
html[data-theme="dark"] #bottom-nav {
    background: rgba(24, 28, 44, .97);
    border-color: rgba(255, 255, 255, .07);
    box-shadow:
        0 1px 2px rgba(0, 0, 0, .3),
        0 8px 28px rgba(0, 0, 0, .45);
}

html[data-theme="dark"] .nav-btn.active {
    /* the same blue is too dim against #12141f; lift it rather than restate it */
    color: #7ea6ff;
    background: rgba(126, 166, 255, .14);
}

html[data-theme="dark"] .nav-btn:active {
    background: rgba(126, 166, 255, .22);
}

html[data-theme="dark"] .input {
    color: var(--text);
}

html[data-theme="dark"] .card-icon.dark {
    background: #262c42;
}

html[data-theme="dark"] .card-icon.lvl-easy {
    background: #1d3a2d;
}

html[data-theme="dark"] .card-icon.lvl-normal {
    background: #1f2c4d;
}

html[data-theme="dark"] .card-icon.lvl-hard {
    background: #45301c;
}

html[data-theme="dark"] .result-stats {
    background: #232841;
}

html[data-theme="dark"] .toggle span {
    background: #2c3349;
}

html[data-theme="dark"] .opt-or::before,
html[data-theme="dark"] .opt-or::after {
    background: #2c3349;
}

html[data-theme="dark"] .legal-text h3 {
    border-bottom-color: #2c3349;
}

html[data-theme="dark"] .rank-card,
html[data-theme="dark"] .streak-card {
    background: #232841;
}

html[data-theme="dark"] .streak-pill {
    background: #1c2033;
}

html[data-theme="dark"] .streak-line.milestone {
    color: var(--violet2);
}

html[data-theme="dark"] .rank-bar {
    background: #12141f;
}

html[data-theme="dark"] .veteran-badge {
    color: #ffd76a;
}

html[data-theme="dark"] .rank-up.up {
    color: var(--violet2);
}

html[data-theme="dark"] .lang-current,
html[data-theme="dark"] .lang-list button {
    background: #2c3349;
}

html[data-theme="dark"] .lang-list button.active {
    background: var(--violet);
}

html[data-theme="dark"] .lang-fab {
    background: #1c2033;
}

html[data-theme="dark"] .setting-row+.setting-row {
    border-top-color: #262c42;
}

html[data-theme="dark"] .emoji-bar button,
html[data-theme="dark"] .btn-outline {
    color: var(--violet2);
}

/* replay control bar (pinned over the board's bottom) */
#replay-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--card);
    box-shadow: 0 -6px 20px rgba(40, 55, 110, .18);
}

.replay-inner {
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: 460px;
    margin: 0 auto;
}

.rp-btn {
    width: 40px;
    height: 40px;
    flex: none;
    border: none;
    border-radius: 12px;
    cursor: pointer;
    background: var(--bg2, #e9ecf6);
    color: var(--text);
    font-size: 15px;
    display: grid;
    place-items: center;
}

.rp-btn.rp-play {
    background: var(--blue);
    color: #fff;
}

.rp-btn:active {
    transform: scale(.94);
}

.rp-track {
    flex: 1;
    height: 6px;
    border-radius: 6px;
    background: var(--bezel);
    overflow: hidden;
}

.rp-fill {
    height: 100%;
    width: 0;
    background: var(--blue);
    border-radius: 6px;
    transition: width .2s ease;
}

.rp-count {
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
    min-width: 40px;
    text-align: center;
}

.rp-close {
    flex: none;
    border: none;
    background: transparent;
    color: var(--violet);
    font: inherit;
    font-weight: 700;
    font-size: 13px;
    cursor: pointer;
    padding: 6px 4px;
}

html[data-theme="dark"] #replay-bar {
    background: #171a28;
    box-shadow: 0 -6px 20px rgba(0, 0, 0, .5);
}

html[data-theme="dark"] .rp-btn {
    background: #2a3049;
}

html[data-theme="dark"] .rp-btn.rp-play {
    background: var(--blue);
}

.rp-btn.rp-play {
    width: 46px;
    height: 46px;
    font-size: 17px;
}

html[data-theme="dark"] .rooms-empty,
html[data-theme="dark"] .lb-empty {
    color: var(--muted);
}