:root {
    /* Shared corner radii — every panel/button/badge picks one of these two,
       instead of ad hoc per-element values. */
    --radius: 10px;
    --radius-pill: 999px;
    /* The menus' design language (see MENUS: ONE DESIGN LANGUAGE below).
       Each colour means one thing on every screen. */
    --night: #070b14;                 /* panel glass over the scenery */
    --glass: rgba(9, 13, 23, 0.86);
    --sheet: #0a0f1b;                 /* dialogs: solid, nothing shows through */
    --line: rgba(255, 255, 255, 0.09);
    --text: #e6ecf7;
    --muted: #93a0b8;
    --teal: #00ffcc;                  /* every action, and the lit edges */
    --teal-rgb: 0, 255, 204;
    --teal-deep: #008f78;
    --ink: #02211b;                   /* text on a filled teal cap */
    --pixel: #ff3366;                 /* hearts, danger, your best score */
    --pixel-rgb: 255, 51, 102;
    --tier-uncommon: #7bd88f;           /* Pixel tiers: a rarity label, nothing else */
    --tier-rare: #4da3ff;
    --tier-epic: #c06bff;
    --tier-legendary: #ff9a2e;
    --tier-mythic: #ff2d55;
    --pixel-deep: #a31440;
    --gem: #33e0ff;                   /* gems and prices */
    --gem-rgb: 51, 224, 255;
    --gold: #ffd23f;                  /* records, achievements, the leader */
    --gold-rgb: 255, 210, 63;
    --font-display: 'Orbitron', 'Courier New', monospace;
    --font-text: 'Chakra Petch', 'Orbitron', system-ui, sans-serif;
    --panel-w: min(360px, 88vw);
    --radius-card: 16px;
    --shadow-card: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 18px 40px rgba(0, 0, 0, 0.5);
    /* Room for notches and home indicators (viewport-fit=cover). */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
}

/* Buttons don't inherit the page font by default. */
button {
    font-family: inherit;
}

[hidden] {
    display: none !important;
}

/* The page itself never scrolls, zooms or rubber-bands: on iOS a stray double
   tap or swipe used to shift it and push the HUD strip off screen. Menus
   scroll inside their own panels (.menu-page), not the page. */
html {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
}

body {
    position: fixed;
    inset: 0;
    margin: 0;
    overflow: hidden;
    overscroll-behavior: none;
    background: #050505;
    font-family: 'Orbitron', 'Courier New', monospace;
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: none;
}

#game-container {
    position: relative;
    width: 100vw;
    height: 100vh;
    /* Mobile browsers' vh includes the area behind their toolbars. */
    height: 100dvh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #000;
    /* Where the HUD's corners are, as offsets in from the container's edges.
       Zero means the window corners. Renderer.resize() picks a data-layout
       and publishes the playfield's box (--pf-left/top/right/w/h), and the
       layouts below move the HUD onto it. */
    --hud-left: 0px;
    --hud-right: 0px;
    --hud-top: 0px;
    /* Height of the phone HUD strip, not counting the notch. */
    --hud-strip-h: 88px;
}

/* A 3:4 column too narrow to have the HUD beside it: the HUD sits in the
   column's own top corners. */
#game-container[data-layout="overlay"] {
    --hud-left: var(--pf-left, 0px);
    --hud-right: var(--pf-right, 0px);
    --hud-top: var(--pf-top, 0px);
}

/* Phones: the playfield runs from under the HUD strip to the bottom edge
   (under the home indicator too). */
#game-container[data-layout="strip"] {
    align-items: flex-end;
}

#gameCanvas {
    background: #080808;
    /* A frame that takes no layout space (a border would push the canvas
       past its fitted size). */
    box-shadow: 0 0 0 1px #2a2a2a, 0 0 60px #000;
    max-width: 100%;
    max-height: 100%;
}

#game-container[data-layout="strip"] #gameCanvas {
    box-shadow: none;
}

#hud-strip {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: calc(var(--hud-strip-h) + var(--safe-top));
    background: #000;
    pointer-events: none;
    /* Always laid out so the Renderer can measure it, only shown on phones. */
    visibility: hidden;
}

#game-container[data-layout="strip"] #hud-strip {
    visibility: visible;
}

/* ---------- Themed sides ----------
   Around the 3:4 column (flank and overlay layouts), the window takes on the
   current biome: its background colour, a soft glow in its platform colour,
   a still star field and a vignette, and a glowing edge on the column.
   Renderer.themeSides() sets the three colours when the biome changes;
   registering them lets the CSS cross-fade between biomes. */
@property --biome-bg {
    syntax: '<color>';
    inherits: true;
    initial-value: #050505;
}

@property --biome-glow {
    syntax: '<color>';
    inherits: true;
    initial-value: rgba(0, 255, 204, 0.09);
}

@property --biome-edge {
    syntax: '<color>';
    inherits: true;
    initial-value: rgba(0, 255, 204, 0.35);
}

#game-container:not([data-layout="strip"]) {
    /* A stacking context, so the star layer below can sit behind the canvas. */
    isolation: isolate;
    background:
        radial-gradient(ellipse 70% 90% at 50% 45%, var(--biome-glow), transparent 70%),
        var(--biome-bg);
    /* (No transition on the colours: they are inherited, so animating them
       restyled the whole page every frame for as long as it ran. The
       column's edge fades between biomes through its own box-shadow
       transition.) */
}

#game-container:not([data-layout="strip"])::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(ellipse at center, transparent 45%, rgba(0, 0, 0, 0.65) 100%),
        radial-gradient(1px 1px at 12% 18%, rgba(255, 255, 255, 0.45), transparent) 0 0 / 230px 230px,
        radial-gradient(1px 1px at 68% 42%, rgba(255, 255, 255, 0.3), transparent) 0 0 / 230px 230px,
        radial-gradient(1.5px 1.5px at 33% 77%, rgba(255, 255, 255, 0.35), transparent) 0 0 / 310px 310px,
        radial-gradient(1px 1px at 86% 64%, rgba(255, 255, 255, 0.25), transparent) 0 0 / 310px 310px,
        radial-gradient(1px 1px at 51% 9%, rgba(255, 255, 255, 0.3), transparent) 0 0 / 170px 170px;
}

#game-container:not([data-layout="strip"]) #gameCanvas {
    box-shadow: 0 0 0 1px var(--biome-edge), 0 0 50px var(--biome-glow), 0 0 90px #000;
}

/* The scenery (#bgCanvas, drawn by Background in js/background.js) sits
   behind the playfield, which is see-through while it is on (.scene-on).
   Beside a 3:4 column it fills the window (.wide-backdrop), dimmed outside
   the column by the borders below so the playfield stands out. The Renderer
   sets its box. */
#game-container {
    isolation: isolate;
}

#bgCanvas {
    display: none;
    position: absolute;
    z-index: -2;
    pointer-events: none;
}

#game-container.scene-on #bgCanvas {
    display: block;
}

#game-container.scene-on #gameCanvas {
    background: transparent;
}

#game-container:not([data-layout="strip"])::before {
    z-index: -3;
}

/* The borders: a dark panel each side of the column, and the column's
   glowing edge. With the menu open (.menu-open, see Game.setMenuOpen) they
   are away and the scenery fills the window; starting a run slides them in. */
#game-container.wide-backdrop::before,
#game-container.wide-backdrop::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 auto;
    z-index: -1;
    pointer-events: none;
    transition: transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s ease-out;
}

#game-container.wide-backdrop::before {
    left: 0;
    width: var(--pf-left, 0px);
    background: linear-gradient(to right, rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0.5));
}

#game-container.wide-backdrop::after {
    right: 0;
    width: var(--pf-right, 0px);
    background: linear-gradient(to left, rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0.5));
}

#game-container.wide-backdrop.menu-open::before {
    transform: translateX(-100%);
    opacity: 0;
}

#game-container.wide-backdrop.menu-open::after {
    transform: translateX(100%);
    opacity: 0;
}

/* Behind the menu the whole scene sits a little darker. Starting a run
   brings the playfield back up to full brightness as the sides darken in. */
#game-container.scene-on #gameCanvas,
#game-container.scene-on #bgCanvas {
    transition: box-shadow 0.7s ease-out, filter 0.7s ease-out;
}

#game-container.scene-on.menu-open #gameCanvas,
#game-container.scene-on.menu-open #bgCanvas {
    filter: brightness(0.72);
}

#game-container.scene-on.menu-open #gameCanvas {
    box-shadow: 0 0 0 1px transparent, 0 0 50px transparent, 0 0 90px transparent;
}

@media (prefers-reduced-motion: reduce) {
    #game-container {
        transition: none;
    }
}

/* UI LAYOUT - Absolute positioning relative to the container */
#ui-layer {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
}

/* HUD */
#hud {
    position: relative;
    width: 100%;
    height: 100px;
    box-sizing: border-box;
    opacity: 0;
    transition: opacity 0.5s;
    z-index: 10;
}

/* The right-hand stack (gems, hearts, pause, the 2X GEMS booster) is laid
   out from these: each counter is a pill --pill-h tall. */
#game-container {
    --count-size: clamp(16px, 4.6vw, 24px);
    --pill-h: calc(var(--count-size) + 14px);
    --stack-top: calc(var(--hud-top) + 14px + var(--safe-top));
    --stack-right: calc(var(--hud-right) + 14px + var(--safe-right));
}

#score-display {
    position: absolute;
    top: calc(var(--hud-top) + 14px + var(--safe-top));
    left: calc(var(--hud-left) + 18px + var(--safe-left));
    white-space: nowrap;
    font-size: clamp(26px, 8vw, 50px);
    font-weight: 900;
    line-height: 1.1;
    color: #fff;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 2px 0 rgba(0, 0, 0, 0.45), 0 0 18px rgba(255, 255, 255, 0.35);
    letter-spacing: -1px;
}

#best-display-hud {
    position: absolute;
    top: calc(var(--hud-top) + 20px + var(--safe-top));
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    font-size: clamp(13px, 3.6vw, 20px);
    color: var(--gold);
    text-shadow: 0 0 12px rgba(var(--gold-rgb), 0.45);
    font-weight: 900;
    letter-spacing: 1.5px;
    text-align: center;
}

/* Gems and hearts: glass pills, persistent on every screen (the menu's
   wallet and the run's counters). */
#gem-display,
#life-display {
    position: absolute;
    right: var(--stack-right);
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    box-sizing: border-box;
    height: var(--pill-h);
    padding: 0 0.55em 0 0.7em;
    border: 1px solid rgba(var(--pill-rgb), 0.35);
    border-radius: var(--radius-pill);
    background: rgba(6, 10, 18, 0.78);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 6px 18px rgba(0, 0, 0, 0.35);
    white-space: nowrap;
    font-size: var(--count-size);
    line-height: 1;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    color: #fff;
    transform-origin: right center;
    /* Persistent across every screen (menu/shop/gameplay), so it must sit
       above #menus-wrapper (20) and #shop-menu-layer (25). */
    z-index: 40;
}

/* Counter digits in Chakra Petch: Orbitron's zero is slashed, which reads
   badly at this size. */
#gem-display .count,
#life-display .count {
    font-family: var(--font-text);
    font-weight: 700;
}

#gem-display .count + .ico,
#life-display .count + .ico {
    margin-left: 0;
}

#gem-display {
    --pill-rgb: var(--gem-rgb);
    top: var(--stack-top);
}

#gem-display .ico {
    filter: drop-shadow(0 0 6px rgba(var(--gem-rgb), 0.7));
}

@keyframes gem-collect-pop {
    0% { transform: scale(1); border-color: rgba(var(--gem-rgb), 0.35); }
    40% { transform: scale(1.18); border-color: rgba(var(--gem-rgb), 1); }
    100% { transform: scale(1); border-color: rgba(var(--gem-rgb), 0.35); }
}

#gem-display.gem-pop {
    animation: gem-collect-pop 0.35s ease-out;
}

/* Banked hearts, right under the gem counter (and just as persistent).
   Dimmed at zero. */
#life-display {
    --pill-rgb: var(--pixel-rgb);
    top: calc(var(--stack-top) + var(--pill-h) + 6px);
    transition: opacity 0.2s;
}

#life-display .ico {
    filter: drop-shadow(0 0 6px rgba(var(--pixel-rgb), 0.7));
}

#life-display.empty {
    opacity: 0.45;
}

@keyframes life-pop {
    0% { transform: scale(1); }
    40% { transform: scale(1.18); }
    100% { transform: scale(1); }
}

#life-display.life-pop {
    animation: life-pop 0.35s ease-out;
}

/* Narrow screens: three numbers don't fit on one row, so BEST tucks under
   the score. */
@media (max-width: 480px) {
    #best-display-hud {
        top: calc(var(--hud-top) + 58px + var(--safe-top));
        left: calc(var(--hud-left) + 18px + var(--safe-left));
        transform: none;
        font-size: 12px;
        text-align: left;
    }

    #score-display {
        font-size: clamp(24px, 7.5vw, 34px);
    }

    #system-alert {
        padding: 8px 14px;
        gap: 8px;
        font-size: 12px;
        letter-spacing: 0.5px;
    }
}

/* Phones (the strip layout): the numbers live in the black HUD strip above
   the playfield. Score with BEST under it on the left, gems over hearts on
   the right, pause in the middle. On the playfield, top down: the target or
   spectating pill, the power-up bar, then notices, so none land on another. */
#game-container[data-layout="strip"] {
    --count-size: 16px;
    --pill-h: 32px;
    --stack-top: calc(9px + var(--safe-top));
    --stack-right: calc(14px + var(--safe-right));
}

#game-container[data-layout="strip"] #hud {
    height: calc(var(--hud-strip-h) + var(--safe-top));
}

#game-container[data-layout="strip"] #score-display {
    top: calc(10px + var(--safe-top));
    left: calc(16px + var(--safe-left));
    font-size: clamp(26px, 8.5vw, 38px);
}

#game-container[data-layout="strip"] #best-display-hud {
    top: calc(56px + var(--safe-top));
    left: calc(16px + var(--safe-left));
    transform: none;
    font-size: 12px;
    text-align: left;
}

#game-container[data-layout="strip"] #life-display {
    top: calc(var(--stack-top) + var(--pill-h) + 6px);
}

#game-container[data-layout="strip"] .hud-btn {
    top: calc((var(--hud-strip-h) - 40px) / 2 + var(--safe-top));
    right: auto;
    left: 50%;
    transform: translateX(-50%);
}

#game-container[data-layout="strip"] #challenge-hud,
#game-container[data-layout="strip"] #spectate-hud {
    top: calc(var(--pf-top, 0px) + 10px);
}

#game-container[data-layout="strip"] #power-hud {
    top: calc(var(--pf-top, 0px) + 40px);
}

#game-container[data-layout="strip"] #system-alert {
    margin-top: 92px;
}

/* Wide windows (the flank layout): the HUD sits beside the column instead of
   in the window corners. Score and BEST are against its left edge; gems,
   hearts and pause are against its right. Sizes follow the gutter, so the
   numbers fit however narrow it gets. This block is its own commit:
   reverting it puts the HUD back in the window corners. */
#game-container[data-layout="flank"] {
    --flank-gap: 24px;
    --flank-num: min(50px, calc(var(--pf-left, 350px) / 7));
    --count-size: min(26px, calc(var(--pf-left, 350px) / 10));
    --stack-top: calc(var(--pf-top, 0px) + 20px + var(--safe-top));
}

#game-container[data-layout="flank"] #score-display,
#game-container[data-layout="flank"] #best-display-hud {
    left: auto;
    right: calc(var(--pf-right, 0px) + var(--pf-w, 0px) + var(--flank-gap));
    transform: none;
    text-align: right;
}

#game-container[data-layout="flank"] #score-display {
    top: calc(var(--pf-top, 0px) + 14px + var(--safe-top));
    font-size: var(--flank-num);
}

#game-container[data-layout="flank"] #best-display-hud {
    top: calc(var(--pf-top, 0px) + 26px + 1.1 * var(--flank-num) + var(--safe-top));
    font-size: min(18px, calc(var(--pf-left, 350px) / 16));
}

#game-container[data-layout="flank"] #gem-display,
#game-container[data-layout="flank"] #life-display,
#game-container[data-layout="flank"] .hud-btn {
    right: auto;
    left: calc(var(--pf-left, 0px) + var(--pf-w, 0px) + var(--flank-gap));
    transform-origin: left center;
}

/* POWER UP HUD: the power's name over its timer, on a glass pill. */
#power-hud {
    position: absolute;
    top: calc(var(--hud-top) + 80px + var(--safe-top));
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 7px 14px 9px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: rgba(6, 10, 18, 0.8);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity 0.2s;
    z-index: 10;
}

#power-text {
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 2px;
    line-height: 1;
    white-space: nowrap;
    color: #fff;
}

#power-bar-bg {
    width: 180px;
    height: 6px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

#power-bar-fill {
    height: 100%;
    width: 100%;
    border-radius: inherit;
    background: #fff;
    transition: width 0.1s linear, background-color 0.2s;
}

/* ---------- Entering a biome ----------
   The biome's name across the playfield, between two lines that draw
   themselves out from the middle, in the biome's own colour, with what's
   new there underneath. Game.showBiomeBanner() paints the three pictures
   and adds .show; taking it off fades the banner out. Only their position
   and opacity are animated, so a frame of it is three ready-made pictures. */
#biome-banner {
    position: absolute;
    left: var(--pf-left, 0px);
    /* Clear of the notices above it, in short windows too. */
    top: calc(var(--pf-top, 0px) + max(var(--pf-h, 100vh) * 0.38, 250px));
    width: var(--pf-w, 100%);
    opacity: 0;
    pointer-events: none;
    z-index: 9;
    transition: opacity 0.5s ease;
}

#biome-banner.show {
    opacity: 1;
    transition: none;
}

#biome-banner canvas {
    position: absolute;
    left: 0;
    will-change: transform, opacity;
}

#biome-banner.show #biome-banner-band {
    animation: biome-name-in 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

#biome-banner.show #biome-banner-lines {
    animation: biome-line-in 0.6s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

#biome-banner.show #biome-banner-tag {
    animation: biome-note-in 0.5s ease 0.35s both;
}

@keyframes biome-name-in {
    from { opacity: 0; transform: scaleX(1.5); }
    to { opacity: 1; transform: none; }
}

@keyframes biome-line-in {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
}

@keyframes biome-note-in {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
}

/* Text for screen readers only. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* SYSTEM ALERT - centralized notification for status/revive/reward messages */
#system-alert {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Solid glass. (It used to blur what was behind it, which the browser
       had to redo on every frame of the game underneath.) */
    background: rgba(8, 12, 20, 0.95);
    border: 1px solid rgba(0, 204, 255, 0.3);
    border-left: 3px solid #00ccff;
    border-radius: 12px;
    padding: 9px 18px 9px 14px;
    /* Below the HUD row (and the notch), and never wide enough to reach the
       pause button in the top-right corner. */
    margin-top: calc(var(--hud-top) + 20px + var(--safe-top));
    font-weight: 900;
    font-size: 13px;
    line-height: 1.3;
    width: fit-content;
    max-width: min(500px, calc(100% - 2 * (60px + max(var(--safe-left), var(--safe-right)))));
    box-sizing: border-box;
    text-transform: uppercase;
    letter-spacing: 1px;
    text-align: left;
    color: #00ccff;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 16px rgba(0, 204, 255, 0.15);
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.35s ease, transform 0.35s ease, border-color 0.3s, color 0.3s, box-shadow 0.3s;
}

#system-alert.alert-visible {
    opacity: 1;
    transform: translateY(0);
}

#system-alert-icon {
    display: flex;
    font-size: 17px;
    line-height: 1;
    flex-shrink: 0;
}

/* The notice's own colour, not the icon's usual one. */
#system-alert-icon .ico {
    color: inherit;
}

/* Two eyes on a DOM-drawn Pixel (skin picker, gem shop, unlock notices),
   placed like drawPixel() places them on the canvas. */
.pixel-eye {
    position: absolute;
    top: 30%;
    width: 20%;
    height: 20%;
    background: white;
}

.pixel-eye-l {
    left: 20%;
}

.pixel-eye-r {
    right: 20%;
}

/* A tiny Pixel in place of the icon (unlock notices). The faint outline keeps
   near-black Pixels (The Void, The End) visible on the dark alert. */
.alert-pixel {
    display: block;
    position: relative;
    width: 18px;
    height: 18px;
    border-radius: 8%; /* PIXEL_CORNER_RADIUS / 26, like the in-game Pixel */
    outline: 1px solid rgba(255, 255, 255, 0.35);
}

#system-alert.alert-unlock .alert-pixel {
    box-shadow: 0 0 8px rgba(255, 215, 0, 0.5);
}

/* Type variants */
#system-alert.alert-success {
    border-color: rgba(0, 255, 170, 0.4);
    border-left-color: #00ffaa;
    color: #00ffaa;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 16px rgba(0, 255, 170, 0.2);
}

#system-alert.alert-warning {
    border-color: rgba(255, 170, 0, 0.4);
    border-left-color: #ffaa00;
    color: #ffaa00;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 16px rgba(255, 170, 0, 0.2);
}

#system-alert.alert-danger {
    border-color: rgba(255, 51, 102, 0.4);
    border-left-color: #ff3366;
    color: #ff5c85;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 16px rgba(255, 51, 102, 0.2);
}

#system-alert.alert-reward {
    border-color: rgba(255, 215, 0, 0.45);
    border-left-color: #ffd700;
    color: #ffd700;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 18px rgba(255, 215, 0, 0.25);
}

/* A newly unlocked Pixel */
#system-alert.alert-unlock {
    border-color: rgba(255, 215, 0, 0.45);
    border-left-color: #ffd700;
    color: #ffe766;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 18px rgba(255, 215, 0, 0.3);
}

/* A life was spent or a heart picked up */
#system-alert.alert-life,
#system-alert.alert-heart {
    border-color: rgba(255, 51, 102, 0.4);
    border-left-color: #ff3366;
    color: #ff5c85;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 16px rgba(255, 51, 102, 0.2);
}

/* Urgent, attention-grabbing pulse (co-op respawn countdown) */
#system-alert.alert-pulse {
    border-color: rgba(192, 77, 255, 0.5);
    border-left-color: #c04dff;
    color: #d896ff;
    font-size: 18px;
    text-shadow: 0 0 8px #c04dff, 0 0 18px #a020f0;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 20px rgba(192, 77, 255, 0.3);
}

/* Only animate while actually shown, so hiding it doesn't get fought by the keyframe's own opacity */
#system-alert.alert-pulse.alert-visible {
    animation: alertPulse 0.9s ease-in-out infinite;
}

@keyframes alertPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* ============================================================
   MENUS: ONE DESIGN LANGUAGE
   The menus borrow from the game. Every panel is a platform: a dark hull
   with a lit top edge and hover lights under each end. Every button is a
   key cap, like the ones the tutorial draws, with a lip that sinks when
   pressed. Colour means the same thing on every screen (see :root): teal
   acts, red is hearts and danger, cyan is gems, gold is records. Orbitron
   carries titles, buttons and numbers; Chakra Petch carries anything read
   as a sentence. Only the PIXEL JUMP title keeps its violet glow.
   ============================================================ */

/* Drawn icons (the sprite in index.html; icon() in app.js). */
.ico {
    flex: none;
    width: 1em;
    height: 1em;
    fill: currentColor;
    vertical-align: -0.12em;
}

.ico-gem { color: var(--gem); }
.ico-heart { color: var(--pixel); }
.ico-gold { color: var(--gold); }
.count + .ico { margin-left: 0.3em; }

/* Beside a button's label, an icon reads a touch larger than the text. */
.btn > .ico {
    width: 1.2em;
    height: 1.2em;
}

/* ---- Panel: a glass card ----
   A hairline-edged card with a lit accent line along its top, like a
   platform's lit edge. --edge is the accent (teal unless it says otherwise). */
.panel {
    --edge: var(--teal);
    --edge-rgb: var(--teal-rgb);
    position: relative;
    width: var(--panel-w);
    max-width: 100%;
    box-sizing: border-box;
    padding: 18px 16px 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background:
        linear-gradient(rgba(var(--edge-rgb), 0.08), rgba(var(--edge-rgb), 0) 80px),
        var(--glass);
    box-shadow: var(--shadow-card);
}

.panel::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 18px;
    right: 18px;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg, transparent, var(--edge) 20%, var(--edge) 80%, transparent);
    box-shadow: 0 0 12px rgba(var(--edge-rgb), 0.6);
    pointer-events: none;
}

.panel--pixel,
.shop-card {
    --edge: var(--pixel);
    --edge-rgb: var(--pixel-rgb);
}

.panel--gold {
    --edge: var(--gold);
    --edge-rgb: var(--gold-rgb);
}

.panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
}

.panel-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: #fff;
    font-size: 15px;
    font-weight: 900;
    letter-spacing: 1px;
}

.panel-head--stack {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
}

.panel-sub {
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 600;
    padding-left: 26px;
}

.panel-count {
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 600;
}

/* ---- Button: a key cap ----
   --k is the cap's colour. :where() keeps this base at zero specificity, so
   any screen can adjust a button with a plain class. */
:where(.btn, .nav-btn, .gem-skin-buy-btn) {
    --k: var(--teal);
    --k-rgb: var(--teal-rgb);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    box-sizing: border-box;
    padding: 10px 16px;
    border: 1.5px solid rgba(var(--k-rgb), 0.75);
    border-radius: 12px;
    background: linear-gradient(rgba(var(--k-rgb), 0.12), rgba(var(--k-rgb), 0.06)), var(--glass);
    color: var(--k);
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 900;
    letter-spacing: 1.5px;
    line-height: 1.2;
    white-space: nowrap;
    cursor: pointer;
    pointer-events: auto;
    user-select: none;
    box-shadow: 0 4px 0 rgba(var(--k-rgb), 0.3);
    transition: transform 0.07s, box-shadow 0.07s, background 0.15s, color 0.15s, opacity 0.15s;
}

@media (hover: hover) {
    :where(.btn, .nav-btn, .gem-skin-buy-btn):hover:not(:disabled) {
        background: linear-gradient(rgba(var(--k-rgb), 0.26), rgba(var(--k-rgb), 0.26)), var(--glass);
    }
}

/* Pressed: the cap sinks onto its lip. A button that can't be pressed sits
   down already. */
:where(.btn, .nav-btn, .gem-skin-buy-btn):active:not(:disabled),
:where(.btn, .nav-btn, .gem-skin-buy-btn):disabled {
    transform: translateY(3px);
    box-shadow: 0 1px 0 rgba(var(--k-rgb), 0.4);
}

:where(.btn, .nav-btn, .gem-skin-buy-btn):disabled {
    opacity: 0.55;
    cursor: default;
}

:where(.btn, .nav-btn, .gem-skin-buy-btn, .gem-dot, .hourly-open-btn):focus-visible {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

/* The one filled cap on a screen: its main action. */
.btn--primary,
.gem-skin-buy-btn {
    border-color: transparent;
    background: linear-gradient(#7affe8, #00d6b0);
    color: var(--ink);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), 0 4px 0 var(--teal-deep), 0 8px 24px rgba(var(--teal-rgb), 0.28);
}

@media (hover: hover) {
    .btn--primary:hover:not(:disabled),
    .gem-skin-buy-btn:hover:not(:disabled):not(.unaffordable):not(.owned) {
        background: linear-gradient(#9dffee, #19e6c0);
    }
}

.btn--primary:active:not(:disabled),
.gem-skin-buy-btn:active:not(:disabled) {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), 0 1px 0 var(--teal-deep), 0 0 12px rgba(var(--teal-rgb), 0.3);
}

/* Filled red: spend a life-saving ad. */
.btn--pixel {
    border-color: transparent;
    background: linear-gradient(#ff7a9a, var(--pixel));
    color: #2a0010;
    box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.28), 0 4px 0 var(--pixel-deep), 0 0 20px rgba(var(--pixel-rgb), 0.35);
}

@media (hover: hover) {
    .btn--pixel:hover:not(:disabled) { background: linear-gradient(#ff9ab2, #ff4d79); }
}

.btn--danger {
    --k: var(--pixel);
    --k-rgb: var(--pixel-rgb);
}

.btn--gem {
    --k: var(--gem);
    --k-rgb: var(--gem-rgb);
}

.btn--gold {
    --k: var(--gold);
    --k-rgb: var(--gold-rgb);
}

.btn--big {
    padding: 15px 20px;
    border-radius: 14px;
    font-size: 22px;
    letter-spacing: 5px;
}

/* A price inside a BUY cap. */
.btn-cost {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: var(--radius-pill);
    background: rgba(0, 0, 0, 0.22);
}

.btn--primary .ico-gem,
.gem-skin-buy-btn .ico-gem {
    color: #00566a;
}

/* Can't afford it yet, or already yours: an outlined cap, not a filled one. */
.shop-card-btn.unaffordable,
.shop-card-btn.maxed,
.gem-skin-buy-btn.unaffordable,
.gem-skin-buy-btn.owned,
.gem-skin-buy-btn:disabled {
    border-color: rgba(var(--teal-rgb), 0.55);
    background: var(--glass);
    color: var(--teal);
    box-shadow: 0 4px 0 rgba(var(--teal-rgb), 0.25);
}

.shop-card-btn.unaffordable,
.gem-skin-buy-btn.unaffordable {
    opacity: 0.7;
}

.shop-card-btn.unaffordable .ico-gem,
.gem-skin-buy-btn.unaffordable .ico-gem {
    color: var(--gem);
}

.shop-card-btn.maxed .btn-cost {
    display: none;
}

/* ‹ › on the two pickers. */
.nav-btn {
    padding: 8px 12px;
    font-size: 16px;
    letter-spacing: 0;
}

/* BACK, top-left of the Shop, Records and Co-op pages. */
.back-btn {
    position: absolute;
    top: calc(16px + var(--safe-top));
    left: calc(16px + var(--safe-left));
    z-index: 1;
    padding: 9px 14px 9px 11px;
    font-size: 12px;
    letter-spacing: 2px;
}

/* Phones: BACK gets its own row instead of sitting on the title. */
@media (max-width: 520px) {
    .back-btn {
        position: static;
        align-self: flex-start;
        margin-bottom: 8px;
    }
}

/* ---- Pages ---- */
#menus-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    z-index: 20;
    pointer-events: none;
}

.menu-page {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: calc(14px + var(--safe-top)) calc(12px + var(--safe-right)) calc(14px + var(--safe-bottom)) calc(12px + var(--safe-left));
    display: flex;
    flex-direction: column;
    /* Centred when the content fits, scrollable (from the top) when it
       doesn't: the grow-able ::before/::after spacers do the centring and
       shrink to nothing on overflow, where justify-content: center would
       clip the top out of reach. */
    justify-content: flex-start;
    align-items: center;
    overflow-y: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
    /* The launch scene shows through, darker at the top where the title is. */
    background: linear-gradient(rgba(3, 6, 14, 0.8), rgba(3, 6, 14, 0.5) 55%, rgba(3, 6, 14, 0.3));
    transition: transform 0.4s ease-in-out, opacity 0.3s, visibility 0s;
    pointer-events: auto;
    /* Each page is its own stacking context, so nothing on one page can
       show through onto a sibling. */
    isolation: isolate;
}

/* A page that isn't the open one (Game.setMenuPanel makes it inert) goes
   once it has slid away, so it can't show through the page over it. */
.menu-page[inert] {
    visibility: hidden;
    transition: transform 0.4s ease-in-out, opacity 0.3s, visibility 0s 0.4s;
}

.menu-page::before,
.menu-page::after {
    content: "";
    flex: 1 0 0;
}

#mp-menu-layer {
    transform: translateX(100%);
}

/* Shop and Records slide up over the home page. */
#shop-menu-layer,
#records-menu-layer {
    transform: translateY(100%);
    z-index: 25;
    background: linear-gradient(rgba(3, 6, 14, 0.9), rgba(3, 6, 14, 0.7));
}

#shop-menu-layer > .panel,
#shop-menu-layer > .btn,
#records-menu-layer > .panel,
.records-stats {
    margin-bottom: 18px;
}

/* A page's name, behind a small Pixel in the page's colour. */
.page-title {
    --accent: var(--teal);
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
    color: #fff;
    font-size: clamp(22px, 5.5vw, 30px);
    font-weight: 900;
    letter-spacing: 4px;
    text-align: center;
    text-shadow: 0 0 22px rgba(255, 255, 255, 0.2);
}

.page-title::before {
    content: "";
    flex: none;
    width: 0.8em;
    height: 0.8em;
    border-radius: 8%;
    background:
        linear-gradient(var(--night), var(--night)) 20% 32% / 20% 20% no-repeat,
        linear-gradient(var(--night), var(--night)) 80% 32% / 20% 20% no-repeat,
        var(--accent);
    box-shadow: 0 0 16px var(--accent);
}

.page-title--mp { --accent: var(--teal); }

.page-title--shop { --accent: var(--gem); }
.page-title--records { --accent: var(--gold); }

/* The game's own name: white, with the one rainbow glow in the menus. The
   glow's hue drifts slowly (the white text doesn't change); it stands still
   under Reduced Motion and never runs during a run (menu-only). */
.page-title--brand {
    margin-bottom: 18px;
    color: #fff;
    font-size: clamp(30px, 8.5vw, 58px);
    letter-spacing: clamp(1px, 0.8vw, 4px);
    line-height: 1.05;
    text-shadow:
        0 2px 0 #ff2d55,
        0 4px 0 #b31440,
        0 6px 0 #5a0a24,
        0 0 26px rgba(255, 45, 85, 0.55),
        0 0 60px rgba(255, 45, 85, 0.25);
    animation: title-hue 24s linear infinite;
}

@keyframes title-hue {
    to { filter: hue-rotate(360deg); }
}

#game-container:not(.menu-open) .page-title--brand {
    animation: none;
}

@media (prefers-reduced-motion: reduce) {
    .page-title--brand { animation: none; }
}

body.reduce-motion .page-title--brand {
    animation: none;
}

.page-title--brand::before {
    display: none;
}

/* ---- Home ---- */
.home {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    max-width: 100%;
}

.home-actions {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: var(--panel-w);
    max-width: 100%;
}

.home-actions > .btn {
    width: 100%;
}

/* The Pixel picker: the equipped Pixel standing on a lit platform, with
   ‹ › either side and its name, tier and perks underneath. */
#skin-container {
    display: flex;
    align-items: center;
    padding: 14px 14px 16px;
    cursor: default;
}

#skin-display {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.skin-picker {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    margin: 2px 0 6px;
}

/* The stand: room for the Pixel's hop, and its platform underneath. */
.skin-stand {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    width: 150px;
    height: 112px;
}

.skin-stand::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    width: 120px;
    height: 7px;
    margin-left: -60px;
    border-radius: 3px;
    background: linear-gradient(#5fffe0, #00b896);
    box-shadow: 0 0 16px rgba(var(--teal-rgb), 0.55), 0 6px 18px rgba(var(--teal-rgb), 0.2);
}

#skin-preview-box {
    position: relative;
    width: 72px;
    height: 72px;
    margin-bottom: 9px;
    border-radius: 8%; /* PIXEL_CORNER_RADIUS / 26, like the in-game Pixel */
    color: var(--pixel); /* updateSkinUI sets the Pixel's colour: its glow */
    outline: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: 0 0 44px -6px currentColor;
    animation: pixel-idle 2.6s ease-in-out infinite;
}

/* A small idle hop on the menu (never during a run, never with reduced motion). */
@keyframes pixel-idle {
    0%, 62%, 100% { transform: translateY(0) scale(1, 1); }
    70% { transform: translateY(0) scale(1.08, 0.92); }
    80% { transform: translateY(-14px) scale(0.95, 1.06); }
    90% { transform: translateY(0) scale(1.05, 0.95); }
}

#game-container:not(.menu-open) #skin-preview-box,
body.reduce-motion #skin-preview-box {
    animation: none;
}

@media (prefers-reduced-motion: reduce) {
    #skin-preview-box { animation: none; }
}

#skin-name {
    max-width: 100%;
    margin-top: 6px;
    overflow: hidden;
    color: #fff;
    font-size: 20px;
    font-weight: 900;
    letter-spacing: 0.5px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#skin-status {
    min-height: 1.3em; /* kept when empty, so PLAY doesn't move */
    margin-top: 2px;
    color: var(--gold);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1px;
}

#skin-ability {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-content: flex-start;
    gap: 6px;
    margin-top: 4px;
    /* The tier line plus two rows of tags (the most any Pixel needs), so
       stepping between Pixels never moves the picker or PLAY. */
    min-height: 74px;
}

/* Best and last run, on one line. */
.menu-scores {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 16px;
    margin-bottom: 2px;
    font-size: 12px;
    font-weight: 900;
    letter-spacing: 1.5px;
}

#menu-highscore {
    color: var(--gold);
    text-shadow: 0 0 12px rgba(var(--gold-rgb), 0.35);
}
#menu-lastscore { color: var(--muted); }

/* PLAY breathes, so it reads as the thing to press. */
#start-prompt {
    animation: play-glow 1.8s ease-in-out infinite;
}

@keyframes play-glow {
    0%, 100% { filter: brightness(1); }
    50% { filter: brightness(1.14); }
}

.menu-actions {
    display: flex;
    gap: 8px;
}

.menu-actions .btn {
    flex: 1;
    min-width: 0;
    padding-left: 8px;
    padding-right: 8px;
    font-size: 13px;
}

.menu-actions .icon-btn {
    flex: none;
    width: 46px;
    font-size: 18px;
}

/* The shop is gem-cyan, and pulses with a BUY badge when something new is
   affordable. */
#shop-open-btn {
    --k: var(--gem);
    --k-rgb: var(--gem-rgb);
    position: relative;
}

@keyframes shop-pulse {
    0%, 100% { box-shadow: 0 4px 0 rgba(var(--k-rgb), 0.4), 0 0 0 rgba(var(--k-rgb), 0); }
    50% { box-shadow: 0 4px 0 rgba(var(--k-rgb), 0.4), 0 0 22px rgba(var(--k-rgb), 0.8); }
}

#shop-open-btn.can-buy {
    animation: shop-pulse 1.6s ease-in-out infinite;
}

.shop-badge {
    position: absolute;
    top: -10px;
    right: -8px;
    padding: 2px 6px;
    border-radius: 6px;
    background: var(--pixel);
    color: #fff;
    font-size: 10px;
    letter-spacing: 1px;
    box-shadow: 0 0 8px rgba(var(--pixel-rgb), 0.8);
}

/* ABOUT and PRIVACY under the buttons: quiet, but there for anyone looking. */
.menu-links {
    display: flex;
    gap: 18px;
    margin-top: 14px;
}

.menu-links a {
    padding: 4px 2px;
    color: #9aa6bd;
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 1px;
    text-decoration: none;
}

.menu-links a:hover,
.menu-links a:focus-visible {
    color: #fff;
    text-decoration: underline;
}

/* Phones: the pickers (menu and shop) must fit inside the screen. */
@media (max-width: 400px) {
    #skin-container,
    #gem-shop-carousel {
        padding-left: 8px;
        padding-right: 8px;
    }

    .nav-btn {
        padding: 8px 10px;
    }
}

/* Wide but short (CrazyGames' 800x450 and 907x510 frames): the picker and
   the buttons sit side by side, so nothing needs scrolling. */
@media (max-height: 600px) and (min-width: 700px) {
    .home {
        flex-direction: row;
        gap: 22px;
    }

    .home > .panel,
    .home-actions {
        width: min(320px, 42vw);
    }

    .page-title--brand {
        margin-bottom: 12px;
        font-size: clamp(26px, 8vh, 44px);
    }

    .menu-links {
        margin-top: 10px;
    }
}

@media (max-height: 480px) {
    .page-title--brand {
        margin-bottom: 8px;
    }

    #skin-container {
        padding-top: 12px;
        padding-bottom: 10px;
    }

    .skin-stand {
        height: 80px;
    }

    #skin-preview-box {
        width: 50px;
        height: 50px;
        margin-bottom: 9px;
    }

    .btn--big {
        padding: 10px 20px;
        font-size: 19px;
    }

    .menu-links {
        margin-top: 6px;
    }
}

/* ---- Multiplayer: Freeplay, then Co-op ---- */
.mp-box {
    text-align: left;
}

.mp-box label,
.mp-box-title {
    display: block;
    margin-bottom: 8px;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1.5px;
    text-transform: uppercase;
}

/* The setup card: name, then JOIN, an OR rule, then HOST. */
.mp-card {
    padding: 20px 18px 18px;
}

.mp-section {
    margin-top: 18px;
}

.mp-or {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 16px 0 14px;
    color: var(--muted);
    font-size: 11px;
    font-weight: 900;
    letter-spacing: 3px;
}

.mp-or::before,
.mp-or::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line);
}

.mp-hint {
    margin: 8px 0 0;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 500;
    text-align: center;
}

.mp-box input[type="text"] {
    width: 100%;
    box-sizing: border-box;
    padding: 11px 10px;
    border: 1.5px solid rgba(255, 255, 255, 0.14);
    border-radius: 12px;
    background: rgba(0, 0, 0, 0.4);
    color: #fff;
    font-family: inherit;
    font-size: 16px;
    font-weight: bold;
    letter-spacing: 2px;
    text-align: center;
    text-transform: uppercase;
    transition: border-color 0.2s, box-shadow 0.2s;
}

.mp-box input[type="text"]::placeholder {
    color: #6f7b92;
}

.mp-box input[type="text"]:focus {
    outline: none;
    border-color: var(--teal);
    box-shadow: 0 0 12px rgba(var(--teal-rgb), 0.3);
}

.mp-join-row {
    display: flex;
    gap: 8px;
}

.mp-join-row input[type="text"] {
    flex: 1;
    min-width: 0;
}

.mp-box--host .btn,
.mp-freeplay .btn {
    width: 100%;
}

/* ---- Freeplay: between runs (js/freeplay.js) ----
   Shown once when a Freeplay run ends and hidden when the next starts; the
   countdown is written once a second. Nothing here animates during a run. */
.fp-banner {
    position: absolute;
    left: var(--pf-left, 0px);
    top: calc(var(--pf-top, 0px) + var(--pf-h, 100vh) * 0.36);
    width: var(--pf-w, 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 18px 16px;
    box-sizing: border-box;
    background: rgba(2, 4, 10, 0.78);
    border-block: 1px solid var(--line);
    text-align: center;
    z-index: 12;
}

.fp-banner[hidden] {
    display: none;
}

.fp-banner-title {
    color: var(--pixel);
    font-family: var(--font-display);
    font-size: clamp(18px, 4vw, 26px);
    font-weight: 900;
    letter-spacing: 2px;
}

.fp-banner-count {
    color: var(--text);
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 1.5px;
}

.fp-leave-btn {
    margin-top: 4px;
    min-width: 140px;
}

/* ---- Lobby setup <-> party view ----
   Hosting or joining adds .in-party to #mp-menu-layer: the setup panels
   evaporate (fade, blur, lift, collapse) and the party panel rises in. */
.mp-setup {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    max-width: 100%;
    max-height: 600px;
    transition: opacity 0.45s ease, filter 0.45s ease, transform 0.45s ease,
        max-height 0.5s ease 0.15s;
}

#mp-menu-layer.in-party .mp-setup {
    opacity: 0;
    filter: blur(8px);
    transform: translateY(-16px) scale(0.94);
    max-height: 0;
    overflow: hidden;
    pointer-events: none;
}

.mp-party-view {
    display: none;
    flex-direction: column;
    align-items: center;
    max-width: 100%;
}

#mp-menu-layer.in-party .mp-party-view {
    display: flex;
    animation: mp-party-in 0.5s ease 0.2s both;
}

@keyframes mp-party-in {
    from {
        opacity: 0;
        filter: blur(4px);
        transform: translateY(14px) scale(0.97);
    }

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

/* Room code, so anyone in the party can keep sharing it. */
.mp-code-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin-bottom: 10px;
}

.mp-party-code {
    flex: 1;
    min-width: 0;
    /* letter-spacing trails the last glyph; the extra left padding evens it. */
    padding: 8px 0 8px 6px;
    border: 1.5px dashed rgba(var(--teal-rgb), 0.5);
    border-radius: 12px;
    background: rgba(var(--teal-rgb), 0.05);
    color: var(--teal);
    font-size: 22px;
    font-weight: 900;
    letter-spacing: 6px;
    text-align: center;
    user-select: text;
    -webkit-user-select: text;
}

.mp-code-btn {
    padding: 6px 10px;
    font-size: 11px;
    letter-spacing: 1px;
}

.mp-party-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Each row sets --slot to that player's in-game name-tag colour. */
.mp-party-row {
    --slot: #555;
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    padding: 9px 12px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    letter-spacing: 1px;
    text-align: left;
}

.mp-party-row.is-leader {
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.14), rgba(0, 0, 0, 0.3));
}

/* The player's colour, as a small Pixel. */
.mp-party-chip {
    flex: none;
    width: 16px;
    height: 16px;
    border-radius: 8%;
    background:
        linear-gradient(var(--night), var(--night)) 20% 32% / 20% 20% no-repeat,
        linear-gradient(var(--night), var(--night)) 80% 32% / 20% 20% no-repeat,
        var(--slot);
    box-shadow: 0 0 8px var(--slot);
}

.mp-party-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mp-party-tags {
    flex: none;
    display: flex;
    gap: 8px;
}

.mp-party-tag {
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 1px;
}

.mp-party-row.is-leader .mp-party-tag {
    color: var(--gold);
}

.mp-party-row.is-empty {
    background: transparent;
    outline: 1px dashed rgba(255, 255, 255, 0.16);
    outline-offset: -1px;
    color: #7f8aa0;
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.3px;
}

.mp-party-row.is-empty .mp-party-chip {
    background: transparent;
    outline: 1px dashed #556;
    box-shadow: none;
}

.mp-leave-btn {
    width: var(--panel-w);
    max-width: 100%;
    margin-top: 18px;
}

/* Connection status: a pill. app.js sets data-state; no state means idle. */
#mp-status {
    --status: var(--muted);
    margin-top: 16px;
    padding: 5px 16px;
    max-width: var(--panel-w);
    box-sizing: border-box;
    border: 1px solid color-mix(in srgb, var(--status) 45%, transparent);
    border-radius: var(--radius-pill);
    background: var(--glass);
    color: var(--status);
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 1px;
    text-align: center;
    transition: color 0.3s, border-color 0.3s;
}

#mp-status[data-state="pending"] { --status: var(--gold); }
#mp-status[data-state="success"] { --status: var(--teal); }
#mp-status[data-state="danger"] { --status: #ff5c85; }

/* Passive context, not an action: the relay logins could not be fetched, so
   strict networks may refuse the direct link. Hidden unless network.js says
   the relay is outright unavailable, and never replaces #mp-status. */
.mp-relay-note {
    max-width: var(--panel-w);
    box-sizing: border-box;
    margin-top: 8px;
    color: var(--gold);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    line-height: 1.35;
    text-align: center;
}

/* Unlike solo (click anywhere), co-op only starts from this button, which
   stays hidden until a partner has connected. */
#mp-start-prompt {
    display: none;
    width: var(--panel-w);
    max-width: 100%;
    margin-top: 14px;
}

/* Short viewports: tighten the panels so the leader's START RUN stays on
   screen. */
@media (max-height: 760px) {
    #mp-menu-layer .page-title {
        margin-bottom: 12px;
    }

    .mp-setup {
        gap: 12px;
    }

    .mp-box {
        padding: 15px 14px 14px;
    }

    .mp-section {
        margin-top: 12px;
    }

    .mp-or {
        margin: 10px 0;
    }

    .mp-box label,
    .mp-box-title {
        margin-bottom: 6px;
    }

    .mp-box input[type="text"] {
        padding: 8px;
        font-size: 14px;
    }

    .mp-party-code {
        padding: 5px 0 5px 6px;
        font-size: 20px;
    }

    .mp-party-row {
        padding: 6px 10px;
    }

    .mp-leave-btn,
    #mp-status,
    #mp-start-prompt {
        margin-top: 12px;
    }

    .mp-relay-note {
        margin-top: 6px;
    }
}

/* PERK TAGS — one short chip per perk in the perk's own colour (--perk, set
   inline from PERKS). The full stat text sits in .perk-tip, shown on hover or
   when a tap toggles .open (see Game.bindEvents). Shared by menu and shop. */
.perk-tag {
    position: relative;
    display: inline-block;
    padding: 3px 7px;
    border: 1px solid var(--perk);
    color: var(--perk);
    background: color-mix(in srgb, var(--perk) 12%, transparent);
    font-size: 10px;
    font-weight: bold;
    letter-spacing: 1px;
    line-height: 1.2;
    cursor: help;
    pointer-events: auto;
    user-select: none;
    outline: none;
}

.perk-tag:focus-visible,
.perk-tag.open {
    background: color-mix(in srgb, var(--perk) 25%, transparent);
    box-shadow: 0 0 10px color-mix(in srgb, var(--perk) 50%, transparent);
}

.perk-tip {
    display: none;
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    width: max-content;
    max-width: 180px;
    padding: 6px 9px;
    background: var(--night);
    border: 1px solid var(--perk);
    color: #fff;
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.3px;
    line-height: 1.35;
    text-align: center;
    white-space: normal;
    z-index: 50;
    pointer-events: none;
}

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

.perk-tag:focus-visible .perk-tip,
.perk-tag.open .perk-tip {
    display: block;
}

/* Touch has no hover, and a tapped element keeps a "sticky" :hover, so the
   hover tooltip is for real pointers only (taps toggle .open instead). */
@media (hover: hover) {
    .perk-tag:hover {
        background: color-mix(in srgb, var(--perk) 25%, transparent);
        box-shadow: 0 0 10px color-mix(in srgb, var(--perk) 50%, transparent);
    }

    .perk-tag:hover .perk-tip {
        display: block;
    }
}

.perk-none {
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.5px;
}

/* ---- Shop ---- */
.shop-card-stock {
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 600;
}

.shop-card-stock span {
    color: #fff;
    font-weight: 700;
}

.shop-card-desc {
    margin: 0 0 14px;
    color: #c3cde0;
    font-family: var(--font-text);
    font-size: 15px;
    font-weight: 500;
    line-height: 1.45;
}

.shop-card-btn {
    width: 100%;
}

/* The Pixel carousel: the same shape as the home screen's picker, so the
   two read as one component in two places. */
/* "Can't do that" feedback on whatever was pressed (see Game.shakeUI). */
.shake {
    animation: shake 0.4s ease-in-out;
}

@keyframes shake {

    0%,
    100% {
        transform: translateX(0);
    }

    25% {
        transform: translateX(-5px);
    }

    75% {
        transform: translateX(5px);
    }
}

/* PORTABLE:REMOVE:START (continue/revive) */
/* CONTINUE? Both choices are the same size and shape, so it's plain the ad
   is optional (CrazyGames asks for exactly that). */
#revive-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(2, 4, 10, 0.78);
    z-index: 50;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: auto;
}

#revive-box {
    width: min(330px, 92%);
    padding: 24px 18px 18px;
    background:
        linear-gradient(rgba(var(--edge-rgb), 0.13), rgba(var(--edge-rgb), 0.02) 56px),
        #080d18;
    text-align: center;
}

#revive-title {
    margin-bottom: 8px;
    color: #fff;
    font-size: 22px;
    font-weight: 900;
    letter-spacing: 3px;
}

#revive-note {
    margin: 0 0 18px;
    color: #c3cde0;
    font-family: var(--font-text);
    font-size: 15px;
    font-weight: 500;
    line-height: 1.4;
}

.revive-choice {
    width: 100%;
    padding: 13px 16px;
    font-size: 14px;
}

#revive-skip {
    margin-top: 12px;
}
/* PORTABLE:REMOVE:END */

/* PORTABLE:REMOVE:START (gem booster) */
/* The 2x gems booster, with the gem and heart counters (under the pause
   button): a small offer between runs, a countdown while it runs (then it
   can't be pressed). Each HUD layout places it below. */
.gem-boost {
    position: absolute;
    top: calc(var(--stack-top) + 2 * var(--pill-h) + 70px);
    right: var(--stack-right);
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 11px;
    border: 1.5px solid var(--gem);
    border-radius: var(--radius-pill);
    background: rgba(6, 10, 18, 0.8);
    color: var(--gem);
    font-family: inherit;
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 1px;
    white-space: nowrap;
    cursor: pointer;
    z-index: 40;
    /* #ui-layer lets clicks through to the game; this one is a button. */
    pointer-events: auto;
    box-shadow: 0 3px 0 rgba(var(--gem-rgb), 0.4);
}

.gem-boost[hidden] {
    display: none;
}

.gem-boost.is-active {
    cursor: default;
    pointer-events: none;
    border-color: rgba(var(--gem-rgb), 0.4);
    box-shadow: none;
}

@media (hover: hover) {
    .gem-boost:not(.is-active):hover {
        background: rgba(var(--gem-rgb), 0.18);
    }
}

/* Phones: just inside the playfield's top-right corner, under the strip. */
#game-container[data-layout="strip"] .gem-boost {
    top: calc(var(--pf-top, 0px) + 10px);
    right: calc(16px + var(--safe-right));
}

/* Wide windows: beside the column, under the pause button. */
#game-container[data-layout="flank"] .gem-boost {
    right: auto;
    left: calc(var(--pf-left, 0px) + var(--pf-w, 0px) + var(--flank-gap));
    top: calc(var(--stack-top) + 2 * var(--pill-h) + 70px);
}
/* PORTABLE:REMOVE:END */

/* ---------- The buy-confirm card's Pixel ---------- */
#hourly-preview,
.hourly-preview {
    display: flex;
    justify-content: center;
    margin: 2px 0;
}

.hourly-pixel {
    display: block;
    position: relative;
    width: 72px;
    height: 72px;
    border-radius: 8%; /* PIXEL_CORNER_RADIUS / 26, like the in-game Pixel */
    box-shadow: 0 0 24px rgba(255, 255, 255, 0.15);
}

.hourly-name {
    font-size: 18px;
    font-weight: 900;
    color: #fff;
}

.hourly-perks {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
}

/* The tier badge's own first line, above the perk chips (tierLine). */
.tier-line {
    flex-basis: 100%;
    text-align: center;
}

.overlay-btn.cant-afford {
    opacity: 0.45;
}

/* PORTABLE:REMOVE:START (fake ad video) */
/* FAKE AD VIDEO UI */
#ad-video-mock {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: #000;
    z-index: 110;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: auto;
    /* Enable interaction */
}

#ad-countdown {
    position: absolute;
    top: 20px;
    right: 20px;
    color: #fff;
    font-size: 20px;
    font-weight: bold;
    background: rgba(0, 0, 0, 0.5);
    padding: 10px 20px;
    border-radius: var(--radius-pill);
}

#ad-content {
    color: #fff;
    font-size: 30px;
    font-weight: bold;
    animation: pulse 1s infinite;
}

@keyframes pulse {
    0% {
        opacity: 0.8;
    }

    50% {
        opacity: 1;
    }

    100% {
        opacity: 0.8;
    }
}
/* PORTABLE:REMOVE:END */

/* Below the HUD rows (score, BEST, power-up bar) and the system-message box,
   so a badge and a notice can show at the same time. */
/* Sits in the #ui-layer column right under #system-alert (which always
   keeps its space), so a badge never lands on top of a notice. */
#achievement-pop {
    position: relative;
    margin-top: 10px;
    background: linear-gradient(#ffe27a, var(--gold));
    color: #2a1d00;
    padding: 9px 18px;
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 1px;
    border-radius: 12px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 4px 0 #a8820a, 0 8px 24px rgba(var(--gold-rgb), 0.35);
    display: none;
    z-index: 100;
    animation: slideIn 0.5s forwards;
}

@keyframes slideIn {
    0% {
        opacity: 0;
        transform: translateY(-10px);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Respect "reduce motion": no blinking, pulsing or sliding. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ---------- In-run HUD button (pause) ---------- */
.hud-btn {
    position: absolute;
    /* Below the gem and heart counters in the top-right corner. */
    top: calc(var(--stack-top) + 2 * var(--pill-h) + 16px);
    right: var(--stack-right);
    width: 40px;
    height: 40px;
    padding: 0;
    background: rgba(6, 10, 18, 0.8);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 12px;
    color: #e6ecf7;
    font-size: 14px;
    letter-spacing: -2px;
    cursor: pointer;
    pointer-events: auto;
    box-shadow: 0 3px 0 rgba(255, 255, 255, 0.12), 0 6px 18px rgba(0, 0, 0, 0.35);
}

/* The pause icon's two bars, drawn rather than a glyph (Orbitron has none). */
#pause-btn::before,
#pause-btn::after {
    content: "";
    position: absolute;
    top: 12px;
    width: 4px;
    height: 14px;
    border-radius: 1px;
    background: currentColor;
}

#pause-btn::before { left: 13px; }
#pause-btn::after { right: 13px; }

@media (hover: hover) {
    .hud-btn:hover {
        border-color: var(--teal);
        color: var(--teal);
    }
}

/* ---------- Shared modal overlays: pause, settings, run card, Pixel of
   the Hour ---------- */
.overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(16px + var(--safe-top)) 16px calc(16px + var(--safe-bottom));
    box-sizing: border-box;
    background: radial-gradient(ellipse at 50% 40%, rgba(2, 4, 10, 0.62), rgba(2, 4, 10, 0.86));
    pointer-events: auto;
    z-index: 60;
}

/* Dialogs opened from the menus rise in. (Not PAUSED: in co-op that one
   opens over a live run, where the page stays still.) */
.overlay:not(#pause-overlay) > .overlay-box {
    animation: sheet-in 0.24s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

@keyframes sheet-in {
    from { opacity: 0; transform: translateY(14px) scale(0.98); }
    to { opacity: 1; transform: none; }
}

#run-card {
    /* Above the menus it opens over, below the persistent gem counter. */
    z-index: 35;
}

.overlay-box {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    width: min(340px, 100%);
    max-height: 100%;
    overflow-y: auto;
    padding: 26px 20px 20px;
    border-radius: 20px;
    /* Solid, unlike the menu's panels: whatever is under a dialog must not
       show through it. */
    background:
        linear-gradient(rgba(var(--edge-rgb), 0.1), rgba(var(--edge-rgb), 0) 90px),
        var(--sheet);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 24px 60px rgba(0, 0, 0, 0.6);
    text-align: center;
}

/* Long labels wrap here rather than run out of the box. */
.overlay-btn {
    min-height: 46px;
    font-size: 13px;
    white-space: normal;
}

/* (A scrolling box can't hang its hover lights outside itself.) */
.overlay-box::after {
    display: none;
}

.overlay-title {
    margin-bottom: 4px;
    color: #fff;
    font-size: 20px;
    font-weight: 900;
    letter-spacing: 4px;
}

.overlay-note {
    color: var(--gold);
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.5px;
}

/* A neutral cap unless it says otherwise (primary, danger, gem, gold). */
.overlay-btn:not(.btn--primary):not(.btn--danger):not(.btn--gem):not(.btn--gold) {
    --k: #d5ddec;
    --k-rgb: 213, 221, 236;
}

/* The caps sink 3px when pressed: leave the last one room to. */
.overlay-box > .btn:last-child,
.overlay-box > .run-card-actions:last-child {
    margin-bottom: 4px;
}

/* Settings rows: label left, control right. */
.setting-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 48px;
    padding: 6px 2px;
    box-sizing: border-box;
    border-bottom: 1px solid var(--line);
    color: var(--text);
    font-family: var(--font-text);
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-align: left;
    cursor: pointer;
}

/* The volume slider: a slim track and a teal Pixel-square thumb. */
.setting-row input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    width: 55%;
    height: 22px;
    margin: 0;
    background: transparent;
    cursor: pointer;
}

.setting-row input[type="range"]::-webkit-slider-runnable-track {
    height: 6px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
}

.setting-row input[type="range"]::-moz-range-track {
    height: 6px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.12);
}

.setting-row input[type="range"]::-moz-range-progress {
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--teal);
}

.setting-row input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    margin-top: -7px;
    border: 0;
    border-radius: 4px;
    background: var(--teal);
    box-shadow: 0 0 12px rgba(var(--teal-rgb), 0.6);
}

.setting-row input[type="range"]::-moz-range-thumb {
    width: 20px;
    height: 20px;
    border: 0;
    border-radius: 4px;
    background: var(--teal);
    box-shadow: 0 0 12px rgba(var(--teal-rgb), 0.6);
}

/* A checkbox is a switch, and its knob is a little Pixel: grey and to the
   left when off, dark on a lit teal track when on. */
.setting-row input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    flex: none;
    width: 48px;
    height: 28px;
    margin: 0;
    box-sizing: border-box;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: var(--radius-pill);
    /* Two eyes, then the knob, then the track (positions in px from the
       padding box: the knob is 18px, 4px in). */
    background:
        linear-gradient(var(--sheet), var(--sheet)) 8px 9px / 4px 4px no-repeat,
        linear-gradient(var(--sheet), var(--sheet)) 14px 9px / 4px 4px no-repeat,
        linear-gradient(#8f9bb3, #8f9bb3) 4px 4px / 18px 18px no-repeat,
        rgba(255, 255, 255, 0.07);
    cursor: pointer;
    transition: background-position 0.16s ease, background-color 0.16s, border-color 0.16s;
}

.setting-row input[type="checkbox"]:checked {
    border-color: transparent;
    background:
        linear-gradient(var(--teal), var(--teal)) 28px 9px / 4px 4px no-repeat,
        linear-gradient(var(--teal), var(--teal)) 34px 9px / 4px 4px no-repeat,
        linear-gradient(var(--ink), var(--ink)) 24px 4px / 18px 18px no-repeat,
        var(--teal);
    box-shadow: 0 0 14px rgba(var(--teal-rgb), 0.45);
}

.setting-row input:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

/* ---------- End-of-run card ---------- */
/* RUN OVER is a small label; the height is the headline. */
#run-card-title {
    margin: 0;
    color: var(--muted);
    font-size: 13px;
    letter-spacing: 5px;
}

.run-card-distance {
    margin: -4px 0 2px;
    color: #fff;
    font-size: clamp(44px, 14vw, 60px);
    font-weight: 900;
    line-height: 1.05;
    letter-spacing: -1px;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 3px 0 rgba(0, 0, 0, 0.4), 0 0 28px rgba(255, 255, 255, 0.25);
}

.run-card-best {
    align-self: center;
    margin-top: -4px;
    padding: 5px 14px;
    border: 1px solid rgba(var(--gold-rgb), 0.6);
    border-radius: var(--radius-pill);
    background: rgba(var(--gold-rgb), 0.12);
    color: var(--gold);
    font-size: 12px;
    font-weight: 900;
    letter-spacing: 2px;
    box-shadow: 0 0 20px rgba(var(--gold-rgb), 0.25);
}

/* A new best lights the whole card gold. */
.run-card-box:has(.run-card-best:not([hidden])) {
    --edge: var(--gold);
    --edge-rgb: var(--gold-rgb);
}

.run-card-stats,
.records-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.records-stats {
    width: var(--panel-w);
    max-width: 100%;
}

/* An odd tile out spans the row rather than leaving a hole. */
.records-stats .run-stat:last-child:nth-child(odd) {
    grid-column: 1 / -1;
}

/* A stat tile: the number, and what it counts. */
.run-stat {
    padding: 11px 8px 10px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.03);
    text-align: center;
}

.run-stat-value {
    display: block;
    overflow: hidden;
    color: #fff;
    font-size: 16px;
    font-weight: 900;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.run-stat-label {
    display: block;
    margin-top: 4px;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.2px;
}

.run-card-actions {
    display: flex;
    gap: 8px;
}

.run-card-actions .btn {
    flex: 1;
    min-width: 0;
    /* Phones: the three primary actions on the run card must each be a 44px
       touch target (they measured 39.6px at 390x844). */
    min-height: 44px;
    padding-left: 8px;
    padding-right: 8px;
}

/* SHARE RUN is a full-width button under that pair, not inside it. */
#run-share-btn {
    min-height: 44px;
}

#share-toast {
    color: var(--teal);
    word-break: break-all;
}

/* The Online leaderboard (js/leaderboard.js): a climb that makes the board asks for
   a name. */
.run-card-lb {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border: 1px solid rgba(var(--gold-rgb), 0.4);
    border-radius: 14px;
    background: rgba(var(--gold-rgb), 0.07);
}

.run-card-lb-title {
    color: var(--gold);
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 1px;
}

.run-card-lb-row {
    display: flex;
    gap: 8px;
}

.run-card-lb-row input[type="text"] {
    flex: 1;
    min-width: 0;
    box-sizing: border-box;
    padding: 9px 10px;
    border: 1.5px solid rgba(255, 255, 255, 0.14);
    border-radius: 12px;
    background: rgba(0, 0, 0, 0.4);
    color: #fff;
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: bold;
    letter-spacing: 2px;
    text-align: center;
    text-transform: uppercase;
    transition: border-color 0.2s, box-shadow 0.2s;
}

.run-card-lb-row input[type="text"]::placeholder {
    color: #6f7b92;
}

.run-card-lb-row input[type="text"]:focus {
    outline: none;
    border-color: var(--gold);
    box-shadow: 0 0 12px rgba(var(--gold-rgb), 0.3);
}

.run-card-lb-row input[readonly] {
    color: #c3cde0;
}

.run-card-lb-row .btn {
    flex: none;
}

.lb-note--error {
    color: var(--pixel);
}

/* STYLE tab: a section per cosmetic slot, a card per cosmetic. */
#shop-panel-style {
    width: var(--panel-w);
    max-width: 100%;
    margin: 0 auto;
    padding: 4px 0 12px;
}

.style-slot {
    margin-bottom: 14px;
}

.style-slot-name {
    margin: 0 0 6px 2px;
    color: var(--muted);
    font-size: 12px;
    font-weight: 900;
    letter-spacing: 2px;
    text-align: left;
}

.style-items {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
}

.style-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 10px 6px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.03);
    color: #fff;
    font: inherit;
    cursor: pointer;
}

.style-item--on {
    border-color: var(--teal);
    box-shadow: inset 0 0 0 1px var(--teal);
}

.style-item--short {
    opacity: 0.55;
}

.style-swatch {
    display: flex;
    gap: 3px;
    height: 14px;
}

.style-swatch span {
    width: 10px;
    height: 10px;
    margin-top: 2px;
    border-radius: 2px;
    box-shadow: 0 0 6px currentColor;
}

.style-swatch--dot span,
.style-swatch--ring span {
    border-radius: 50%;
}

.style-name {
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 700;
}

.style-action {
    color: var(--gem);
    font-size: 12px;
    font-weight: 900;
}

.style-item--on .style-action,
.style-item--owned .style-action {
    color: var(--teal);
}

.style-note {
    margin: 4px 0 0;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
}

/* The run-perk pick: two cards in their perk tag's colour, and a bar that
   empties over RUN_PERK_PICK_MS (a CSS animation: no page writes per frame).
   In co-op the run goes on underneath, so it leaves the playfield visible. */
.perk-pick {
    background: rgba(0, 0, 0, 0.45);
    /* Only the cards take touches: in co-op the run (and its touch pads)
       carries on underneath. */
    pointer-events: none;
}

.perk-pick .overlay-box {
    pointer-events: auto;
}

.perk-pick-cards {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 12px 0;
}

.perk-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px 10px;
    border: 2px solid var(--perk, var(--teal));
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.04);
    color: #fff;
    font: inherit;
    text-align: center;
    cursor: pointer;
}

.perk-card:focus-visible,
.perk-card:hover {
    box-shadow: 0 0 18px var(--perk, var(--teal));
}

.perk-card-key {
    color: var(--muted);
    font-size: 11px;
    font-weight: 900;
}

.perk-card-name {
    color: var(--perk, var(--teal));
    font-size: 16px;
    font-weight: 900;
    letter-spacing: 1px;
}

.perk-card-desc {
    color: #c3cde0;
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 600;
}

.perk-pick-timer {
    height: 5px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.1);
    overflow: hidden;
}

.perk-pick-timer span {
    display: block;
    height: 100%;
    background: var(--teal);
    transform-origin: left center;
}

.perk-pick-timer span.running {
    animation: perk-timer var(--perk-ms, 5000ms) linear forwards;
}

@keyframes perk-timer {
    from { transform: scaleX(1); }
    to { transform: scaleX(0); }
}

/* The first Pixel to buy, as a goal under a new player's Pixel. */
.first-goal {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    margin-top: 8px;
}

.first-goal-text {
    color: #fff;
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 700;
}

.first-goal-bar {
    width: 150px;
    height: 6px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.1);
    overflow: hidden;
}

.first-goal-bar span {
    display: block;
    height: 100%;
    background: var(--gem);
}

/* The Streak: a line under the menu scores, and a pay line on the run card. */
.menu-streak {
    color: var(--gold);
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 1px;
    text-align: center;
}

.menu-streak .streak-next {
    display: block;
    margin-top: 2px;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0;
}

.run-card-streak {
    margin: 10px 0 2px;
    color: var(--gold);
    font-size: 14px;
    font-weight: 900;
    letter-spacing: 1px;
}

.run-card-streak .streak-reward {
    color: var(--gem);
}

/* An achievement's reward, hard right of its row. */
.achievement-reward {
    flex: none;
    margin-left: auto;
    color: var(--gem);
    font-size: 13px;
    font-weight: 900;
    white-space: nowrap;
}

/* ---------- Records ---------- */
/* Personal leaderboard: your three best climbs. */
#fame-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.fame-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    text-align: left;
}

/* Rank chip: gold, silver and bronze on the podium. */
.fame-rank {
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    background: #222a3a;
    color: var(--muted);
    font-size: 11px;
    font-weight: 900;
    line-height: 22px;
    text-align: center;
}

.fame-swatch {
    flex: none;
    width: 14px;
    height: 14px;
    border-radius: 8%;
    background: #555;
}

/* The Pixel's name takes the slack, so the score stays hard right and the
   digits line up down the column. */
.fame-skin {
    flex: 1 1 auto;
    min-width: 0;
    color: #c3cde0;
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fame-date {
    flex: none;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
    font-weight: 500;
}

.fame-score {
    flex: none;
    color: #fff;
    font-size: 16px;
    font-weight: 900;
}

.fame-row--1 {
    background: linear-gradient(90deg, rgba(var(--gold-rgb), 0.16), rgba(var(--gold-rgb), 0.03));
}

.fame-row--1 .fame-rank {
    background: var(--gold);
    color: #000;
}

.fame-row--1 .fame-score {
    color: var(--gold);
}

.fame-row--2 .fame-rank {
    background: #c0c8d8;
    color: #000;
}

.fame-row--3 .fame-rank {
    background: #cd7f32;
    color: #000;
}

/* The Online leaderboard in Records: rows like the Personal one's, with
   the player's name after their Pixel's swatch, and your own row outlined. */
.lb-name {
    flex: 1 1 auto;
    min-width: 0;
    color: #fff;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lb-race-btn {
    width: 100%;
    margin-top: 10px;
}

.lb-row--me {
    box-shadow: inset 0 0 0 1px var(--teal);
}

#lb-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.fame-empty {
    padding: 4px 0 2px;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 15px;
    font-weight: 500;
    line-height: 1.4;
}

.records-list {
    display: flex;
    flex-direction: column;
}

.achievement-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 11px 2px;
    border-top: 1px solid var(--line);
    text-align: left;
}

.achievement-row:first-child {
    border-top: 0;
    padding-top: 4px;
}

/* A medal, or the Pixel the achievement unlocks: dim until it's earned. */
.achievement-icon {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: #5d6880;
    font-size: 18px;
    opacity: 0.7;
}

.achievement-row.earned .achievement-icon {
    background: rgba(var(--gold-rgb), 0.12);
    color: var(--gold);
    opacity: 1;
    box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), 0.35);
}

.achievement-pixel {
    display: block;
    position: relative;
    width: 20px;
    height: 20px;
    border-radius: 8%;
    outline: 1px solid rgba(255, 255, 255, 0.3);
}

.achievement-row:not(.earned) .achievement-pixel {
    filter: grayscale(1);
}

.achievement-name {
    display: block;
    color: #c3cde0;
    font-size: 13px;
    font-weight: 900;
    letter-spacing: 0.5px;
}

.achievement-row.earned .achievement-name {
    color: var(--gold);
}

.achievement-desc {
    display: block;
    margin-top: 1px;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 14px;
    font-weight: 500;
}

/* Reduced motion chosen in Settings: same as the OS-level preference. */
body.reduce-motion *,
body.reduce-motion *::before,
body.reduce-motion *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
}

/* ---------- On-screen touch bar (phones) ----------
   #touch-controls is laid over the canvas by Game.layoutTouchControls(). The
   bar runs along its bottom edge, split exactly like InputHandler.zoneAt():
   ◀ is the left quarter, ▶ the second quarter, ▲ (jump) the right half. */
#touch-controls {
    position: absolute;
    pointer-events: none;
    z-index: 11;
}

.touch-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    /* About an inch, plus room for the home indicator. */
    height: calc(clamp(56px, 9vh, 96px) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    box-sizing: border-box;
    border-top: 2px solid rgba(255, 255, 255, 0.22);
    background: rgba(0, 0, 0, 0.28);
}

.touch-pad {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 25%;
    box-sizing: border-box;
    color: rgba(255, 255, 255, 0.55);
    transition: background 0.08s, color 0.08s;
}

/* A thin line between ◀ and ▶ (the ⇆ badge sits on it); a firmer one
   between moving and jumping. */
.touch-pad--right { border-left: 1px solid rgba(255, 255, 255, 0.16); }

.touch-pad--jump {
    flex-basis: 50%;
    border-left: 2px solid rgba(255, 255, 255, 0.28);
}

.touch-pad.is-active {
    background: rgba(var(--teal-rgb), 0.18);
    color: #fff;
}

/* Arrows are CSS triangles, not ◀ ▶ ▲ glyphs: those come out at different
   sizes per font, and iOS can draw ▶ as an emoji. */
.touch-arrow {
    width: 20px;
    height: 22px;
    background: currentColor;
    clip-path: polygon(100% 0, 100% 100%, 0 50%);
}

.touch-pad--right .touch-arrow { clip-path: polygon(0 0, 100% 50%, 0 100%); }

.touch-pad--jump .touch-arrow {
    width: 26px;
    height: 22px;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.touch-slide {
    position: absolute;
    left: 25%;
    top: calc(50% - var(--safe-bottom) / 2);
    transform: translate(-50%, -50%);
    padding: 1px 7px 3px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-pill);
    background: #0b0b12;
    color: rgba(255, 255, 255, 0.7);
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 16px;
    line-height: 1.2;
}

/* ---------- Daily challenge target (from a shared link) ---------- */
#challenge-hud {
    position: absolute;
    top: calc(var(--hud-top) + 116px + var(--safe-top));
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 12px;
    border: 1px solid rgba(var(--gold-rgb), 0.5);
    border-radius: var(--radius-pill);
    background: rgba(6, 10, 18, 0.8);
    color: var(--gold);
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 1px;
    white-space: nowrap;
}

#challenge-hud.beaten {
    border-color: #00ffaa;
    color: #00ffaa;
}

/* Phones: BEST sits under the score, so the top centre is free (the old spot
   is where alerts and achievement pops appear). */
@media (max-width: 480px) {
    #challenge-hud {
        top: calc(var(--hud-top) + 26px + var(--safe-top));
        font-size: 11px;
    }
}

/* ---------- Co-op: spectating while dead, room code sharing ---------- */
#spectate-hud {
    position: absolute;
    top: calc(var(--hud-top) + 116px + var(--safe-top));
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 12px;
    border: 1px solid rgba(192, 77, 255, 0.5);
    border-radius: var(--radius-pill);
    background: rgba(6, 10, 18, 0.8);
    color: #d896ff;
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 1px;
    white-space: nowrap;
}

/* PORTABLE:REMOVE:START (install gate) */
/* Phone and tablet browser tabs: install steps cover everything (on Android
   until PLAY IN BROWSER closes them). */
#install-gate {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(24px + var(--safe-top)) calc(16px + var(--safe-right)) calc(24px + var(--safe-bottom)) calc(16px + var(--safe-left));
    background: radial-gradient(ellipse at 50% 0%, rgba(var(--teal-rgb), 0.1), transparent 60%), #05070d;
    color: var(--text);
    font-family: var(--font-text);
    overflow-y: auto;
}

.install-card {
    max-width: 360px;
    text-align: center;
}

.install-pixel {
    position: relative;
    width: 48px;
    height: 48px;
    margin: 0 auto 18px;
    border-radius: 8%;
    background: var(--pixel);
    box-shadow: 0 0 32px rgba(var(--pixel-rgb), 0.6);
}

.install-pixel span {
    position: absolute;
    top: 14px;
    width: 10px;
    height: 10px;
    background: #fff;
}

.install-pixel span:first-child { left: 10px; }
.install-pixel span:last-child { right: 10px; }

#install-gate h1 {
    margin: 0 0 14px;
    font-family: var(--font-display);
    font-size: 30px;
    letter-spacing: 3px;
    color: #fff;
    text-shadow: 0 2px 0 #ff2d55, 0 4px 0 #b31440, 0 0 26px rgba(255, 45, 85, 0.5);
}

.install-lead {
    margin: 0 0 18px;
    font-size: 15px;
    line-height: 1.5;
    color: #c3cde0;
}

.install-note {
    margin: 0 0 16px;
    padding: 10px 12px;
    border: 1px solid rgba(var(--gold-rgb), 0.6);
    border-radius: 12px;
    background: rgba(var(--gold-rgb), 0.07);
    color: var(--gold);
    font-size: 14px;
}

.install-steps {
    margin: 0 0 18px;
    padding: 0;
    list-style: none;
    counter-reset: step;
    text-align: left;
}

.install-steps li {
    counter-increment: step;
    position: relative;
    margin-bottom: 10px;
    padding: 12px 12px 12px 48px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--glass);
    font-size: 15px;
    line-height: 1.4;
}

.install-steps li::before {
    content: counter(step);
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    border-radius: var(--radius-pill);
    background: var(--teal);
    color: var(--ink);
    font-family: var(--font-display);
    font-weight: 900;
    font-size: 14px;
    line-height: 24px;
    text-align: center;
}

.install-steps b {
    color: var(--teal);
}

.install-btn {
    display: block;
    width: 100%;
    margin: 0 0 18px;
    padding: 16px;
    border: 0;
    border-radius: 14px;
    background: linear-gradient(#7affe8, #00d6b0);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 900;
    letter-spacing: 2px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55), 0 4px 0 var(--teal-deep), 0 8px 24px rgba(var(--teal-rgb), 0.28);
    cursor: pointer;
}

.install-btn:active {
    transform: translateY(3px);
}

.install-btn:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 3px;
}

/* PLAY IN BROWSER, under the install steps: the second choice. */
.install-btn--quiet {
    border: 1.5px solid rgba(255, 255, 255, 0.25);
    background: var(--glass);
    color: var(--text);
    font-size: 14px;
    box-shadow: none;
}

.install-btn--quiet:active {
    background: rgba(255, 255, 255, 0.12);
}

.install-done {
    border-color: var(--teal);
    background: rgba(var(--teal-rgb), 0.07);
    color: var(--teal);
}

.install-done b {
    color: #fff;
}

.install-share {
    width: 20px;
    height: 20px;
    vertical-align: -4px;
    color: #00a8ff;
}

.install-foot {
    margin: 0;
    font-size: 12px;
    color: var(--muted);
}
/* PORTABLE:REMOVE:END */

/* Settings > SAVE DATA (js/saves.js SaveBackupUI), site and portable */
.save-backup {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--line);
}
.save-backup-title {
    color: var(--gold);
    font-family: var(--font-display);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 1px;
    text-align: left;
}
.save-backup-code {
    display: block;
    width: 100%;
    min-height: 82px;
    padding: 8px;
    border: 1px solid rgba(var(--teal-rgb), 0.45);
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.45);
    color: #dfe6f5;
    font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
    font-size: 12px;
    line-height: 1.4;
    resize: vertical;
    word-break: break-all;
}
.save-backup-code[hidden] {
    display: none;
}
/* One button per row: the labels are long, and two columns overlap inside the
   narrow settings panel on phones. */
.save-backup-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.save-backup-actions .btn {
    width: 100%;
}
.save-backup-note {
    margin: 0;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 12px;
    line-height: 1.4;
    text-align: left;
}
/* VERSION row (index.html) and the status lines under the portable update
   check and the SAVE DATA buttons. */
.settings-version {
    border-bottom: none;
    color: var(--muted);
    font-size: 14px;
    cursor: default;
}
.settings-version strong {
    color: var(--teal);
    font-family: var(--font-display);
    font-weight: 700;
}
.settings-status {
    min-height: 1.2em;
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 1px;
}
.settings-status[data-state="update"] {
    color: var(--teal);
}
.settings-status[data-state="error"] {
    color: var(--pixel);
}

/* PIXEL TIERS — a label and border in the tier's colour (PIXEL_TIERS). */
.tier-badge {
    display: inline-block;
    padding: 3px 7px;
    border: 1px solid var(--tier);
    color: var(--tier);
    font-size: 10px;
    font-weight: bold;
    letter-spacing: 1px;
    line-height: 1.2;
    user-select: none;
}
.tier-uncommon { --tier: var(--tier-uncommon); }
.tier-rare { --tier: var(--tier-rare); }
.tier-epic { --tier: var(--tier-epic); }
.tier-legendary { --tier: var(--tier-legendary); }
.tier-mythic { --tier: var(--tier-mythic); }

/* Mythic shimmers in the menus and shop only: never during a run, when the
   page must stay still (#game-container loses .menu-open). */
@keyframes tier-shimmer { to { background-position: 200% 0; } }
.tier-badge.tier-mythic,
.tier-mythic .tier-badge,
.shop-list-tier.tier-mythic span {
    animation: tier-shimmer 2.4s linear infinite;
}
.tier-badge.tier-mythic,
.tier-mythic .tier-badge {
    border-color: transparent;
    background: linear-gradient(90deg, #ff2d55, #ffd23f, #ff2d55, #c06bff, #ff2d55) 0 0 / 200% 100%;
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}
/* Mythic cards: their tier colour pulses (same rules as the tag). */
@keyframes tier-pulse { 50% { box-shadow: 0 0 22px rgba(255, 45, 85, 0.55), 0 0 0 1px rgba(255, 210, 63, 0.6); } }
.shop-row.tier-mythic,
.strip-pixel.tier-mythic,
.shop-stage.tier-mythic .stage-pixel {
    animation: tier-pulse 2.4s ease-in-out infinite;
}
#game-container:not(.menu-open) .tier-mythic .stage-pixel,
#game-container:not(.menu-open) .tier-mythic,
#game-container:not(.menu-open) .tier-mythic .tier-badge,
#game-container:not(.menu-open) .tier-mythic span { animation: none; }
@media (prefers-reduced-motion: reduce) {
    .tier-badge.tier-mythic,
    .tier-mythic .tier-badge,
    .shop-list-tier.tier-mythic span,
    .shop-row.tier-mythic,
    .strip-pixel.tier-mythic,
    .shop-stage.tier-mythic .stage-pixel { animation: none; }
}

/* Achievements fold away inside Records: the header is the toggle. */
.records-toggle {
    width: 100%;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.records-toggle .panel-count::after {
    content: " +";
}

.records-toggle.open .panel-count::after {
    content: " \2212";
}

.achievement-bar {
    display: block;
    height: 5px;
    margin-top: 6px;
    border-radius: var(--radius-pill);
    overflow: hidden;
    background: rgba(255, 255, 255, 0.08);
}

.achievement-bar > span {
    display: block;
    height: 100%;
    background: var(--gold);
}

/* ---------- The menu's owned-Pixel picker: ‹ › and the count ---------- */
.skin-step {
    flex: none;
    width: 44px;
    min-height: 56px;
    padding: 0;
    border-color: var(--line);
    background: rgba(255, 255, 255, 0.03);
    box-shadow: none;
    color: var(--teal);
    font-size: 26px;
}

.skin-step:disabled {
    transform: none;
    box-shadow: none;
    opacity: 0.25;
}

.skin-owned-count {
    align-self: flex-end;
    padding: 2px 8px;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    color: var(--muted);
    font-family: var(--font-text);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1px;
}

/* ---------- The shop: RENT / PIXELS / BOOSTERS (js/shop.js) ----------
   A stage for one Pixel at a time, tabs pinned to the bottom for thumbs. */
.shop-page {
    justify-content: flex-start;
}
.shop-page::before,
.shop-page::after {
    display: none;
}
.shop-top,
.shop-main,
.shop-tabs {
    width: min(520px, 100%);
}
/* Room for BACK (in the corner on wide screens, its own row on phones). */
.shop-top {
    display: flex;
    align-items: center;
    min-height: 44px;
}
/* Phones: the HUD strip runs across the top, so the shop starts below it. */
@media (max-width: 520px) {
    .shop-page {
        padding-top: calc(58px + var(--safe-top));
    }
    .shop-top .back-btn {
        margin-bottom: 0;
    }
}
.shop-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 12px 0;
}
.shop-tabs {
    position: sticky;
    bottom: 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    padding: 6px;
    border: 1px solid var(--line);
    border-radius: 16px;
    background: var(--night);
    box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.5);
}
.shop-tab {
    min-height: 52px;
    border: 0;
    border-radius: 11px;
    background: none;
    color: var(--muted);
    font: 900 14px var(--font-display);
    letter-spacing: 1.5px;
    cursor: pointer;
}
/* Four tabs on a phone: a little tighter. */
@media (max-width: 420px) {
    .shop-tab {
        font-size: 12px;
        letter-spacing: 0.5px;
    }
}
.shop-tab.active {
    background: linear-gradient(#6affe4, #00d6b0);
    color: var(--ink);
}
.shop-tab:focus-visible,
.shop-view-toggle button:focus-visible,
.stage-nav:focus-visible,
.strip-pixel:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* SINGLE / LIST */
.shop-view-toggle {
    display: flex;
    justify-content: center;
    gap: 4px;
    margin: 0 auto 12px;
    padding: 3px;
    width: max-content;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--night);
}
.shop-view-toggle button {
    min-height: 32px;
    padding: 4px 14px;
    border: 0;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--muted);
    font: 900 11px var(--font-display);
    letter-spacing: 1.5px;
    cursor: pointer;
}
.shop-view-toggle button.active {
    background: rgba(var(--teal-rgb), 0.16);
    color: var(--teal);
}

/* The stage: one big Pixel, its perks spelled out, its button. */
.shop-stage {
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    gap: 6px;
}
#rent-stage {
    grid-template-columns: 1fr;
}
.stage-center,
#rent-stage {
    text-align: center;
}
.stage-center .tier-badge,
#rent-tier {
    margin-bottom: 10px;
}
.stage-pixel {
    position: relative;
    display: block;
    width: 140px;
    height: 140px;
    margin: 6px auto 14px;
    border-radius: 8%;
    box-shadow: 0 0 56px color-mix(in srgb, var(--tier) 65%, transparent), 0 0 0 2px color-mix(in srgb, var(--tier) 55%, transparent);
}
.stage-pixel .pixel-eye {
    width: 18%;
    height: 22%;
}
.stage-name {
    color: #fff;
    font: 900 clamp(18px, 6vw, 26px) var(--font-display);
    margin-bottom: 4px;
    white-space: nowrap; /* one line, so a long name can't push things down */
    overflow: hidden;
    text-overflow: ellipsis;
}
/* SINGLE: the perk list keeps room for the longest one in the shop (plus a
   wrapped line), so flipping between Pixels doesn't move anything. */
.shop-stage .stage-center .stage-perks {
    display: block;
    width: fit-content;
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
    min-height: calc((var(--perk-rows, 4) + 1) * 1.75em);
}
.need-bar.is-empty {
    visibility: hidden;
}
@media (max-width: 520px) {
    /* Long perk lines wrap on a phone: keep room for two of them. */
    .shop-stage .stage-center .stage-perks {
        min-height: calc((var(--perk-rows, 4) + 2) * 1.75em);
    }
}
.stage-perks {
    display: inline-block;
    margin: 10px 0 4px;
    padding: 0;
    list-style: none;
    color: #dfe6f3;
    font: 500 14px var(--font-text);
    text-align: left;
}
.stage-perks li {
    margin: 6px 0;
}
.stage-perks .perk-tag {
    margin-right: 6px;
}
.stage-cta {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    margin-top: 14px;
}
.stage-cta .btn {
    min-width: 160px;
}
.shop-cta.cant-afford {
    --k: var(--muted);
    --k-rgb: 147, 160, 184;
}
.shop-cta.is-equipped {
    --k: var(--tier-uncommon);
    --k-rgb: 123, 216, 143;
}
.stage-note,
.stage-owned {
    margin-top: 8px;
    color: var(--muted);
    font: 600 13px var(--font-text);
    letter-spacing: 0.5px;
    text-align: center;
}
.stage-owned {
    color: var(--teal);
}
.stage-nav {
    height: 88px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--glass);
    color: var(--teal);
    font: 900 34px var(--font-display);
    cursor: pointer;
}
.stage-strip {
    display: flex;
    justify-content: safe center;
    gap: 5px;
    margin-top: 18px;
    padding-bottom: 4px;
    overflow-x: auto;
}
.strip-pixel {
    padding: 4px;
    border: 2px solid transparent;
    border-bottom: 3px solid var(--tier);
    border-radius: 8px;
    background: var(--glass);
    opacity: 0.6;
    cursor: pointer;
}
.strip-pixel.owned {
    opacity: 1;
}
.strip-pixel.active {
    border-color: var(--teal);
    opacity: 1;
}
.strip-pixel-body {
    position: relative;
    display: block;
    width: 22px;
    height: 22px;
    border-radius: 8%;
}

/* Gems still to go for a Pixel you can't afford yet. */
.need-bar {
    position: relative;
    height: 16px;
    margin: 8px auto 0;
    max-width: 260px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.07);
    overflow: hidden;
}
.need-bar > span {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, rgba(var(--gem-rgb), 0.35), rgba(var(--gem-rgb), 0.7));
}
.need-bar > b {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font: 700 11px var(--font-text);
    letter-spacing: 0.5px;
}

/* LIST: every shop Pixel, grouped by tier, cheapest first. */
.shop-list-tier {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 16px 2px 8px;
    color: var(--tier);
    font: 900 12px var(--font-display);
    letter-spacing: 2px;
}
.shop-list-tier::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, var(--tier), transparent);
}
.shop-list-tier.tier-mythic span {
    background: linear-gradient(90deg, #ff2d55, #ffd23f, #ff2d55) 0 0 / 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.shop-row {
    display: grid;
    grid-template-columns: 52px 1fr auto;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-left: 3px solid var(--tier);
    border-radius: 10px;
    background: var(--glass);
}
.shop-row.equipped {
    box-shadow: 0 0 0 1px var(--tier-uncommon);
}
.shop-row-pixel {
    position: relative;
    display: block;
    width: 52px;
    height: 52px;
    border-radius: 8%;
    box-shadow: 0 0 14px color-mix(in srgb, var(--tier) 50%, transparent);
}
.shop-row-name {
    margin-bottom: 4px;
    color: #fff;
    font: 900 15px var(--font-display);
}
.shop-row-perks {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
.shop-row-mid .need-bar {
    margin-left: 0;
}
.shop-row-cta .btn {
    min-width: 108px;
    min-height: 44px;
}

/* BOOSTERS */
.booster-slots {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 14px;
}
.booster-slot {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 22px 12px 16px;
    border: 1px solid var(--line);
    border-top: 3px solid var(--pixel);
    border-radius: 12px;
    background: var(--glass);
    text-align: center;
}
.booster-slot--gem {
    border-top-color: var(--gem);
}
.booster-ico {
    width: 44px;
    height: 44px;
}
.heart-pips {
    display: flex;
    gap: 6px;
    margin: 4px 0 2px;
}
.heart-pip {
    width: 30px;
    height: 30px;
    color: rgba(255, 255, 255, 0.14);
}
.heart-pip.free,
.heart-pip.bought {
    color: var(--pixel);
    filter: drop-shadow(0 0 6px rgba(var(--pixel-rgb), 0.7));
}
.booster-extra {
    color: var(--gold);
    font: 700 12px var(--font-text);
    letter-spacing: 0.5px;
}
.booster-n {
    color: #fff;
    font: 900 40px var(--font-display);
}
.booster-n small {
    color: var(--muted);
    font-size: 18px;
}
.booster-label {
    color: var(--muted);
    font: 700 12px var(--font-text);
    letter-spacing: 1px;
}
.booster-desc {
    margin: 2px 0 8px;
    color: var(--muted);
    font: 500 13px var(--font-text);
}
.booster-slot .btn {
    margin-top: auto;
    min-height: 44px;
}
