/* Global reset: keep element sizing predictable across menu, overview, and arena pages. */
* {
    box-sizing: border-box;
}

/* Default body layout for simple pages; page-specific classes override scrolling and layout as needed. */
body {
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #2c3e50;
    color: #ecf0f1;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    overflow: hidden;
}

/* Main menu container used by index.html for the title and navigation buttons. */
.main-menu {
    width: min(92vw, 460px);
    display: grid;
    justify-items: center;
    gap: 28px;
    text-align: center;
}

/* Default large heading style used before page-specific heading overrides. */
h1 {
    font-size: 4rem;
    margin: 0 0 2rem;
    text-transform: uppercase;
    letter-spacing: 5px;
}

/* Vertical button stack used on the main menu. */
.button-container {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    align-items: center;
}

/* Base link/button style shared by menu and back-navigation buttons. */
.btn {
    display: inline-block;
    width: 200px;
    padding: 12px 24px;
    font-size: 1.2rem;
    cursor: pointer;
    background-color: #3498db;
    color: white;
    border: none;
    border-radius: 5px;
    text-align: center;
    text-decoration: none;
    transition: background-color 0.2s, opacity 0.2s;
}

/* Hover state for enabled shared buttons. */
.btn:hover:not(:disabled) {
    background-color: #2980b9;
}

/* Disabled shared button state for unavailable menu actions. */
.btn:disabled {
    background-color: #7f8c8d;
    cursor: not-allowed;
    opacity: 0.6;
}

/* Back navigation link used on game and overview pages. */
.btn-back {
    position: absolute;
    top: calc(20px + var(--safe-top));
    left: calc(20px + var(--safe-left));
    z-index: 100;
    text-decoration: none;
    text-align: center;
    width: auto; /* Overrides the base .btn fixed width for compact back navigation. */
}

/* --- Theme tokens --- */

/*
 * Location theme tokens. Every page starts from this neutral slate default;
 * run pages override the --loc-* values with inline styles on <body> via
 * PokeLocations.applyLocationTheme(), and everything below derives from them.
 * Inline styles on <body> survive the innerHTML re-renders the pages use.
 */
body {
    /* Safe-area insets, routed through tokens so every page reads them the same
       way and so they can be overridden to fake values during verification.
       These are all 0 unless the page opts in with 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);

    /* map/profile.js stacks achievement toasts down from this offset; pwa.js
       pushes it further down while a .pwa-notice is on screen so the two
       never overlap. Declared on body (not .achievement-toast) so it can be
       overridden from an ancestor. */
    --toast-top: calc(18px + var(--safe-top));

    --loc-accent: #e0b84f;
    --loc-glow: #4ab0a5;
    --loc-surface: #232f3d;
    --loc-bg-deep: #10161f;
    --loc-bg-mid: #1b2836;
    --page-bg-image: none; /* JS sets url(...) when the location has one */

    --gold: var(--loc-accent);
    --aqua: var(--loc-glow);
    --felt: var(--loc-surface);
    --coral: #d85f4f;
    --paper: #f2f4f5;
    --ink: #251b18;
    --muted: rgba(250, 246, 230, 0.72);
    --panel-deep: color-mix(in srgb, var(--loc-surface) 55%, var(--loc-bg-deep));
    --page-bg:
        radial-gradient(circle at 18% 20%,
            color-mix(in srgb, var(--loc-accent) 14%, transparent), transparent 30%),
        radial-gradient(circle at 82% 76%,
            color-mix(in srgb, var(--loc-glow) 13%, transparent), transparent 32%),
        linear-gradient(150deg, var(--loc-bg-mid), var(--loc-bg-deep) 62%);
    --page-bg-stack:
        linear-gradient(rgba(8, 12, 18, 0.55), rgba(8, 12, 18, 0.72)),
        var(--page-bg-image) center / cover no-repeat fixed,
        var(--page-bg);
    --panel-bg:
        linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(0, 0, 0, 0.16)),
        var(--loc-surface);
}

/* --- Main Menu --- */

/* Shared themed page shell for menu and game pages. */
.menu-page,
.game-page {
    min-height: 100dvh;
    height: auto;
    overflow: auto;
    background: var(--page-bg-stack);
    color: #fbf6e8;
}

/* Themed panels used by the menu card and arena side panels. */
.menu-page .main-menu,
.side-panel {
    border: 1px solid rgba(251, 246, 232, 0.16);
    background: var(--panel-bg);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.14);
}

/* Main menu panel spacing and depth. */
.menu-page .main-menu {
    padding: clamp(28px, 7vw, 56px);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.14), 0 20px 48px rgba(0, 0, 0, 0.28);
}

/* Main menu title override; sized so the longest word stays inside the panel's
   content box and does not skew the grid column. */
.menu-page h1 {
    margin: 0;
    color: #fbf6e8;
    font-size: clamp(2.5rem, 10vw, 3.75rem);
    letter-spacing: 0;
    text-shadow: 0 8px 22px rgba(0, 0, 0, 0.36);
}

/* Home title: mascot icon beside mixed-case text. The icon is tall enough that
   the words wrap under each other at every width, so the pair reads as one
   lockup; nowrap keeps the icon on the text's line instead of stacking above
   it, and the font is sized so the longest word clears the panel from ~320px
   up. */
.menu-page .menu-title {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: center;
    gap: 0.3em;
    font-size: clamp(1.35rem, 7vw, 1.75rem);
    text-transform: none;
}

/* Lets the words wrap inside the row instead of overflowing on a narrow or
   large-font viewport where the one-line fit fails. */
.menu-page .menu-title span {
    min-width: 0;
}

/* Icon rides the title's font size, at 3x its height. */
.menu-title-icon {
    flex: none;
    width: auto;
    height: 3em;
    image-rendering: pixelated;
}

/* Constrains the menu button column width. */
.menu-page .button-container {
    width: min(100%, 260px);
}

/* Shared theme treatment for main-menu buttons and arena action buttons. */
.menu-page .btn,
.arena-button {
    border: 1px solid rgba(251, 246, 232, 0.22);
    border-radius: 6px;
    background-color: color-mix(in srgb, var(--aqua) 28%, transparent);
    font-weight: 760;
}

/* Makes menu buttons fill the menu column. */
.menu-page .btn {
    width: 100%;
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
}

/* The corner back link stays compact despite full-width menu buttons. */
.menu-page .btn-back {
    width: auto;
}

/* Hover/focus color for menu buttons and arena action buttons. */
.menu-page .btn:hover:not(:disabled),
.arena-button:hover:not(:disabled),
.arena-button:focus-visible:not(:disabled) {
    background-color: color-mix(in srgb, var(--aqua) 42%, transparent);
}

/* Disabled menu button override in the themed menu. */
.menu-page .btn:disabled {
    background-color: rgba(0, 0, 0, 0.24);
}

/* --- Starter Picker --- */

/* Let the starter shell scroll from the top when the deck row is tall. */
.starter-page {
    align-items: flex-start;
    justify-content: flex-start;
}

/* Centered column holding the heading and the deck row. */
.starter-page .starter-shell {
    width: min(96vw, 1040px);
    margin: 0 auto;
    padding: clamp(56px, 9vh, 96px) max(16px, var(--safe-right)) max(40px, var(--safe-bottom)) max(16px, var(--safe-left));
    display: grid;
    justify-items: center;
    gap: clamp(20px, 4vh, 40px);
    text-align: center;
}

/* Starter heading matches the menu title scale but a touch smaller. */
.starter-page h1 {
    font-size: clamp(2rem, 6vw, 3.2rem);
    letter-spacing: 0;
    text-shadow: 0 8px 22px rgba(0, 0, 0, 0.36);
}

/* Responsive deck row: wraps on narrow viewports and for any deck count. */
.starter-page .starter-decks {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: clamp(14px, 2vw, 24px);
    width: 100%;
}

/* Each deck is a full felt panel button. */
.starter-page .starter-card {
    flex: 1 1 260px;
    max-width: 320px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: clamp(18px, 2.4vw, 28px);
    border: 1px solid rgba(251, 246, 232, 0.16);
    border-radius: 12px;
    background: var(--panel-bg);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.14), 0 16px 40px rgba(0, 0, 0, 0.28);
    color: #fbf6e8;
    font-family: inherit;
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
}

.starter-page .starter-card:hover,
.starter-page .starter-card:focus-visible {
    transform: translateY(-4px);
    border-color: var(--gold);
    box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.14), 0 22px 52px rgba(0, 0, 0, 0.36);
    outline: none;
}

/* Type chip above the deck name. */
.starter-page .starter-card-type {
    padding: 3px 12px;
    border-radius: 999px;
    background-color: color-mix(in srgb, var(--aqua) 28%, transparent);
    border: 1px solid rgba(251, 246, 232, 0.22);
    font-size: 0.82rem;
    font-weight: 760;
    letter-spacing: 1px;
    text-transform: uppercase;
}

.starter-page .starter-card-name {
    font-size: 1.5rem;
    font-weight: 760;
}

/* Row of the two starter pokemon portraits. */
.starter-page .starter-card-pokemon {
    display: flex;
    justify-content: center;
    gap: 16px;
    width: 100%;
}

.starter-page .starter-mon {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

.starter-page .starter-mon-portrait {
    width: clamp(72px, 8vw, 96px);
    height: clamp(72px, 8vw, 96px);
    object-fit: contain;
    image-rendering: pixelated;
}

.starter-page .starter-mon-name {
    font-size: 0.9rem;
    font-weight: 620;
}

/* Attack/item list. */
.starter-page .starter-card-cards {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 3px;
    color: var(--muted);
    font-size: 0.9rem;
}

/* Call-to-action pinned to the bottom of the card. */
.starter-page .starter-card-cta {
    margin-top: auto;
    padding: 8px 18px;
    border-radius: 6px;
    border: 1px solid rgba(251, 246, 232, 0.22);
    background-color: color-mix(in srgb, var(--aqua) 28%, transparent);
    font-weight: 760;
}

.starter-page .starter-card:hover .starter-card-cta,
.starter-page .starter-card:focus-visible .starter-card-cta {
    background-color: color-mix(in srgb, var(--aqua) 42%, transparent);
}

.starter-page .starter-loading {
    color: var(--muted);
}

/* --- Poke Ball theme --- */

/*
 * Palette for the pages that never receive a location theme (home, starter
 * picker, card overview, achievements, 404) — a Poke Ball read: red shell,
 * off-white shell, dark grey-black band. Pages opt in with `pokeball-theme` on
 * <body>; the run pages keep their location themes untouched.
 */
.pokeball-theme {
    --pb-red: #e3350d;
    --pb-red-deep: #b8250a;
    --pb-red-dark: #7d1605;
    --pb-white: #ffffff;
    --pb-shell: #eef0f2;
    --pb-ink: #24272c;
    --pb-ink-soft: #565d67;
    --pb-steel: #c3c8cf;
    /* Thickness of the ball's centre band. */
    --pb-band: clamp(16px, 4vh, 30px);
    /* The colour of the ball's shell half. Red on the pages that never receive
       a location; the run pages below re-point it at their location's accent. */
    --pb-shell-hue: var(--pb-red);
}

/* Menu-family pages (home, starter picker) go light: shell-coloured ground,
   ink text, red as the single accent. Both the shared --gold/--aqua accents and
   --muted are re-pointed so the panel rules above land on the light palette. */
.menu-page.pokeball-theme {
    --gold: var(--pb-red);
    --aqua: var(--pb-red);
    --muted: var(--pb-ink-soft);
    background-color: var(--pb-shell);
    background-image: none;
    color: var(--pb-ink);
}

.menu-page.pokeball-theme h1 {
    color: var(--pb-ink);
    text-shadow: none;
}

/* Menu buttons become the ball's red with an ink outline. */
.menu-page.pokeball-theme .btn {
    border: 2px solid var(--pb-ink);
    background-color: var(--pb-red);
    color: var(--pb-white);
    box-shadow: 0 3px 0 rgba(36, 39, 44, 0.28);
}

.menu-page.pokeball-theme .btn:hover:not(:disabled),
.menu-page.pokeball-theme .btn:focus-visible:not(:disabled) {
    background-color: var(--pb-red-deep);
}

.menu-page.pokeball-theme .btn:active:not(:disabled) {
    transform: translateY(2px);
    box-shadow: 0 1px 0 rgba(36, 39, 44, 0.28);
}

.menu-page.pokeball-theme .btn:disabled {
    border-color: var(--pb-steel);
    background-color: var(--pb-steel);
    color: var(--pb-ink-soft);
    box-shadow: none;
}

/* The corner back link is a white chip so it reads on both ball halves. */
.menu-page.pokeball-theme .btn-back {
    border: 2px solid var(--pb-ink);
    background-color: var(--pb-white);
    color: var(--pb-ink);
}

.menu-page.pokeball-theme .btn-back:hover {
    background-color: var(--pb-shell);
}

/* --- Home page: the ball itself --- */

/*
 * index.html paints a whole Poke Ball: red top half, dark band across the
 * middle, off-white bottom half, with the menu panel as the centre button.
 * Percentage stops are relative to the body box, which is at least the
 * viewport tall, so the band tracks the middle of the page at any size.
 */
.menu-page.pokeball-page {
    /* The plate is centred in the body box, so the insets go on the page and
       the plate centres inside what is left. The ball's gradient is painted
       over the padding box, so the band does not move. */
    padding: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left);
    background-color: var(--pb-shell);
    background-image:
        radial-gradient(circle at 26% 16%,
            rgba(255, 255, 255, 0.26), transparent 46%),
        linear-gradient(180deg,
            var(--pb-red) 0,
            var(--pb-red) calc(50% - var(--pb-band) / 2),
            var(--pb-ink) calc(50% - var(--pb-band) / 2),
            var(--pb-ink) calc(50% + var(--pb-band) / 2),
            var(--pb-shell) calc(50% + var(--pb-band) / 2),
            var(--pb-shell) 100%);
}

/* The menu panel is the ball's centre button, drawn as a rounded plate rather
   than a circle: white face, thick ink ring, and a shell-coloured halo
   separating the ring from the band. */
.pokeball-page .main-menu {
    /* Narrower than the default panel so the band and both ball halves stay
       visible around it. */
    width: min(86vw, 460px);
    padding: clamp(22px, 6vw, 40px);
    border: clamp(4px, 1vw, 8px) solid var(--pb-ink);
    border-radius: clamp(28px, 9vw, 48px);
    background: var(--pb-white);
    color: var(--pb-ink);
    box-shadow:
        0 0 0 clamp(4px, 1.1vw, 9px) var(--pb-shell),
        0 18px 42px rgba(0, 0, 0, 0.34);
}

.pokeball-page .menu-title {
    color: var(--pb-ink);
}

/* Room to breathe: the plate widens and its rows get more air, but it keeps
   its rectangle at every size. */
@media (min-width: 620px) and (min-height: 700px) {
    .pokeball-page .main-menu {
        width: min(92vw, 520px);
        gap: 22px;
        padding: clamp(34px, 5vw, 54px);
    }
}

/* --- Starter picker --- */

/*
 * The starter page wears the ball's top half as a header strip: red behind the
 * heading, the band beneath it, shell below for the deck row. The strip is
 * sized in px/vh so it stays put however long the deck list grows.
 */
.starter-page.pokeball-theme {
    /* Both grow by the top inset, so the red strip runs under the status bar
       while the heading keeps its height and its place inside the strip. */
    --pb-header: calc(clamp(150px, 22vh, 200px) + var(--safe-top));
    /* Mirrors the shell's own top padding so the heading can fill the strip. */
    --pb-shell-pad: calc(clamp(56px, 9vh, 96px) + var(--safe-top));

    background-color: var(--pb-shell);
    background-image: linear-gradient(180deg,
        var(--pb-red) 0,
        var(--pb-red) var(--pb-header),
        var(--pb-ink) var(--pb-header),
        var(--pb-ink) calc(var(--pb-header) + var(--pb-band)),
        var(--pb-shell) calc(var(--pb-header) + var(--pb-band)));
    background-repeat: no-repeat;
}

/* The row gap has to clear the band, so the band never touches the deck row. */
.starter-page.pokeball-theme .starter-shell {
    padding-top: var(--pb-shell-pad);
    gap: calc(var(--pb-band) + clamp(14px, 2vh, 24px));
}

/* The heading sits on the red strip, and is stretched to fill it so the band
   lands in the gap between the heading and the deck row at any viewport size.
   The strip is sized to hold two wrapped lines at every width tested; a longer
   heading would grow past it and push the deck row down, which loses the band
   under the text but never collides with the cards. */
.starter-page.pokeball-theme h1 {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(var(--pb-header) - var(--pb-shell-pad));
    color: var(--pb-white);
    text-shadow: 0 4px 14px rgba(80, 12, 2, 0.45);
}

/* Deck cards become white plates with ink text. */
.starter-page.pokeball-theme .starter-card {
    border: 2px solid var(--pb-ink);
    background: var(--pb-white);
    box-shadow: 0 10px 26px rgba(36, 39, 44, 0.18);
    color: var(--pb-ink);
}

.starter-page.pokeball-theme .starter-card:hover,
.starter-page.pokeball-theme .starter-card:focus-visible {
    border-color: var(--pb-red);
    box-shadow: 0 18px 36px rgba(36, 39, 44, 0.26);
}

.starter-page.pokeball-theme .starter-card-type,
.starter-page.pokeball-theme .starter-card-cta {
    border: 2px solid var(--pb-ink);
    background-color: var(--pb-red);
    color: var(--pb-white);
}

.starter-page.pokeball-theme .starter-card:hover .starter-card-cta,
.starter-page.pokeball-theme .starter-card:focus-visible .starter-card-cta {
    background-color: var(--pb-red-deep);
}

/* --- Dark pokeball pages (card overview, achievements) --- */

/*
 * These keep their dark shell — the card art needs it — so the theme lands as
 * ink-charcoal panels with the ball's red as the accent and steel as the glow.
 * The battle board is also a .game-page but carries a location palette, so it
 * opts out through .pokeball-run rather than having the red forced on it.
 */
.game-page.pokeball-theme:not(.pokeball-run) {
    --loc-accent: var(--pb-red);
    --loc-glow: #aeb6c1;
    --loc-surface: #2b3038;
    --loc-bg-mid: #22262c;
    --loc-bg-deep: #131619;
    /* Red shell washing down into the charcoal band, so the page reads as the
       ball without lightening the ground the card art sits on. */
    --page-bg: linear-gradient(180deg,
        color-mix(in srgb, var(--pb-red) 78%, var(--loc-bg-deep)) 0,
        color-mix(in srgb, var(--pb-red) 24%, var(--loc-bg-mid)) 190px,
        var(--loc-bg-mid) 300px,
        var(--loc-bg-deep) 100%);
}

/* --- Poke Ball theme on the run pages (location-tinted) --- */

/*
 * The run pages (area map, capture, mart, event, attack, battle) already carry
 * a per-location palette, so they wear the ball in that location's colour
 * rather than red: `pokeball-run` re-points the shell at --loc-accent and
 * everything below derives from it.
 *
 * Two washes exist because a raw accent ranges from near-white (safari-zone)
 * to deep purple (old-chateau). Anything that carries the pages' light text is
 * mixed down into --loc-bg-deep, which lands dark enough at every accent; the
 * raw hue is kept for hairlines and glyphs, where nothing sits on top of it.
 *
 * Declared after .pokeball-theme so the --pb-ink override below wins the tie
 * between two single-class selectors on the same <body>.
 */
.pokeball-run {
    --pb-shell-hue: var(--loc-accent);
    /* Shell fill and its lit variant (top of a shell panel, button faces). */
    --pb-shell-face: color-mix(in srgb, var(--loc-accent) 34%, var(--loc-bg-deep));
    --pb-shell-face-lit: color-mix(in srgb, var(--loc-accent) 48%, var(--loc-bg-deep));
    /* Text on a shell fill: the accent pulled towards white so a dark accent
       still reads, while the hue survives. */
    --pb-shell-text: color-mix(in srgb, var(--loc-accent) 42%, var(--pb-white));
    /* The band under a shell panel. Thinner than the home page's centre band,
       which spans a whole viewport rather than one panel edge. */
    --pb-band-thin: clamp(6px, 1.1vh, 10px);
    /* Near-black band: the run grounds are dark already, so the ball's ink has
       to go darker than them to read as a band instead of another panel. */
    --pb-ink: #0d1014;

    /* Ground: the coloured half washing down into the location's own deep
       slate, so the page reads as the ball top-down even where a shell panel
       does not reach. Overrides the token block on `body` (0,1,0 beats 0,0,1).
       This is the bottom layer of --page-bg-stack, so a location that ships
       background art covers it entirely and the shell panels alone carry the
       ball there; where there is no art, the stack's scrim tones this down. */
    --page-bg: linear-gradient(180deg,
        color-mix(in srgb, var(--loc-accent) 58%, var(--loc-bg-deep)) 0,
        color-mix(in srgb, var(--loc-accent) 20%, var(--loc-bg-mid)) 220px,
        var(--loc-bg-mid) 380px,
        var(--loc-bg-deep) 100%);
}

/*
 * Shell panel: the ball's coloured half as a component. A hairline of the raw
 * location accent along the top, the washed fill under it, and the ball's band
 * as a fat ink bottom edge. Every run page renders one of these topbars above
 * its content, so the band always lands under the header whatever height the
 * header's own contents give it.
 */
.pokeball-run .area-topbar,
.pokeball-run .capture-topbar,
.pokeball-run .mart-topbar,
.pokeball-run .event-topbar,
.pokeball-run .attack-topbar {
    border: 2px solid var(--pb-ink);
    border-bottom-width: var(--pb-band-thin);
    border-radius: 14px;
    background:
        linear-gradient(180deg,
            var(--pb-shell-hue) 0, var(--pb-shell-hue) 4px,
            var(--pb-shell-face-lit) 4px,
            var(--pb-shell-face) 100%);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.34);
}

/* Kickers sit on the shell fill, so they take the lightened accent. */
.pokeball-run .area-kicker,
.pokeball-run .capture-kicker,
.pokeball-run .mart-kicker,
.pokeball-run .event-kicker,
.pokeball-run .attack-kicker {
    color: var(--pb-shell-text);
}

/*
 * Run-page buttons pick up the menu's chunky ball button: ink outline, shell
 * face, and a hard bottom shadow that collapses on press. The list is explicit
 * because each page names its own buttons; `.btn.btn-back` is doubled up to
 * clear the `.area-page .btn-back` rules, which live in the later stylesheets.
 */
.pokeball-run .arena-button,
.pokeball-run .btn.btn-back,
.pokeball-run .mart-buy-button,
.pokeball-run .mart-service-button,
.pokeball-run .mart-continue-button,
.pokeball-run .event-primary-button,
.pokeball-run .event-secondary-button,
.pokeball-run .event-icon-button {
    border: 2px solid var(--pb-ink);
    background-color: var(--pb-shell-face-lit);
    color: #fbf6e8;
    box-shadow: 0 3px 0 rgba(0, 0, 0, 0.45);
}

.pokeball-run .arena-button:hover:not(:disabled),
.pokeball-run .arena-button:focus-visible:not(:disabled),
.pokeball-run .btn.btn-back:hover,
.pokeball-run .btn.btn-back:focus-visible,
.pokeball-run .mart-buy-button:hover:not(:disabled),
.pokeball-run .mart-service-button:hover:not(:disabled),
.pokeball-run .mart-continue-button:hover,
.pokeball-run .event-primary-button:hover:not(:disabled),
.pokeball-run .event-secondary-button:hover:not(:disabled),
.pokeball-run .event-icon-button:hover:not(:disabled) {
    background-color: color-mix(in srgb, var(--loc-accent) 62%, var(--loc-bg-deep));
}

.pokeball-run .arena-button:active:not(:disabled),
.pokeball-run .btn.btn-back:active,
.pokeball-run .mart-buy-button:active:not(:disabled),
.pokeball-run .mart-service-button:active:not(:disabled),
.pokeball-run .mart-continue-button:active,
.pokeball-run .event-primary-button:active:not(:disabled),
.pokeball-run .event-secondary-button:active:not(:disabled),
.pokeball-run .event-icon-button:active:not(:disabled) {
    transform: translateY(2px);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
}

.pokeball-run .arena-button:disabled,
.pokeball-run .mart-buy-button:disabled,
.pokeball-run .mart-service-button:disabled,
.pokeball-run .event-primary-button:disabled,
.pokeball-run .event-secondary-button:disabled {
    border-color: rgba(13, 16, 20, 0.7);
    background-color: rgba(0, 0, 0, 0.34);
    box-shadow: none;
}

/*
 * The map's wild-encounter node is a drawn Poke Ball, and on a themed run it
 * takes the location's own colour: travelling from one location to the next
 * recolours the ball. The raw accent is safe here because nothing sits on top
 * of the shell half. The legend swatch picks this up from the same rule.
 */
.pokeball-run .area-icon--capture {
    border-color: var(--pb-ink);
    background: linear-gradient(180deg,
        var(--pb-shell-hue) 0 46%,
        var(--pb-ink) 46% 56%,
        var(--pb-shell) 56% 100%);
}

.pokeball-run .area-icon--capture::after {
    border-color: var(--pb-ink);
    background-color: var(--pb-shell);
}

/* --- Battle board as a Poke Ball --- */

/*
 * The battle board is already the ball's shape: rival half, turn-control box,
 * your half. So the rival panel takes the coloured shell, the control box
 * becomes the band, and your panel takes the off-white half — as a pale edge
 * and a whisper of light, because the cards below it need the dark ground.
 *
 * The wide layout (>=1100px) moves the control box into the left column, so
 * the band lands as the panel edge it shares with the rival panel instead;
 * both readings come from the same rules.
 */
.pokeball-run .side-panel--opponent {
    border-color: var(--pb-ink);
    border-top: 4px solid var(--pb-shell-hue);
    /* Fat ink underside: the ball's band, in the gap the two panels share. The
       wide layout keeps it, since the panels stay stacked there. */
    border-bottom: var(--pb-band-thin) solid var(--pb-ink);
    background:
        linear-gradient(180deg,
            var(--pb-shell-face) 0,
            color-mix(in srgb, var(--loc-accent) 10%, var(--loc-surface)) 38%,
            var(--loc-surface) 100%);
}

.pokeball-run .side-panel--player {
    border-color: var(--pb-ink);
    border-top: 3px solid var(--pb-steel);
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--pb-shell) 9%, var(--loc-surface)) 0,
            var(--loc-surface) 30%);
}

/* The band between the halves. Its underside is the player panel's own steel
   edge, so the band only draws the shell-side line. */
.pokeball-run .arena-status {
    border-top: 3px solid var(--pb-shell-hue);
    border-bottom: 0;
    background-color: var(--pb-ink);
}

/* Wide layout: the control box is a left-hand panel rather than a divider, so
   it goes back to a plain ink panel with the shell as its outline. */
@media (min-width: 1100px) {
    .pokeball-run .arena-status {
        border: 2px solid var(--pb-ink);
        border-top: 4px solid var(--pb-shell-hue);
        background:
            linear-gradient(180deg,
                color-mix(in srgb, var(--loc-accent) 16%, var(--pb-ink)) 0,
                var(--pb-ink) 120px);
    }
}

/* --- Arena Prototype --- */

/* Game page shell and responsive card sizing tokens. Cards respond to both viewport width and height. */
.game-page {
    --card-w: clamp(56px, min(5.3vw, 9.6dvh), 78px);
    --card-h: calc(var(--card-w) * 1.52);
    --hand-card-w: clamp(50px, min(4.6vw, 8.2dvh), 66px);
    --hand-card-h: calc(var(--hand-card-w) * 1.52);
    --opponent-hand-card-w: clamp(22px, min(2.7vw, 4.3dvh), 34px);
    --opponent-hand-card-h: calc(var(--opponent-hand-card-w) * 1.52);
    --pile-card-w: clamp(44px, min(4vw, 7.2dvh), 60px);
    --pile-card-h: calc(var(--pile-card-w) * 1.52);
    --panel-gap: clamp(4px, 0.8vw, 8px);

    display: block;
}

/* Fixed back button placement on the game screen. */
.game-page .btn-back {
    position: fixed;
    top: calc(14px + var(--safe-top));
    left: calc(14px + var(--safe-left));
    z-index: 20;
    padding: 9px 14px;
    font-size: 0.95rem;
    background-color: color-mix(in srgb, var(--loc-bg-deep) 88%, transparent);
    border: 1px solid rgba(251, 246, 232, 0.22);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.24);
}

/* Main arena grid filled by arena_render.js with opponent, controls, and player panels. */
.game-board {
    width: 100%;
    min-height: 100dvh;
    padding: max(6px, var(--safe-top)) max(10px, var(--safe-right)) max(8px, var(--safe-bottom)) max(10px, var(--safe-left));
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: var(--panel-gap);
}

/* Player/opponent arena panels that contain status, board slots, piles, and hand. */
.side-panel {
    min-width: 0;
    min-height: 0;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    gap: clamp(4px, 0.7vw, 8px);
    padding: clamp(5px, 0.8vw, 9px);
}

/* Opponent panel accent color. */
.side-panel--opponent {
    border-color: color-mix(in srgb, var(--coral) 38%, transparent);
}

/* Player panel accent color. */
.side-panel--player {
    border-color: color-mix(in srgb, var(--aqua) 40%, transparent);
}

/* Shared horizontal row layout for side headers, hands, and the turn-control box. */
.side-status,
.hand-row,
.arena-status {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Aligns side-panel title and counters at opposite ends. Kept above the
   board row so counters stay readable if a tight viewport overflows cards.
   min-width keeps a long nowrap trainer name from widening the panel column
   on narrow screens; the title truncates instead. */
.side-status {
    position: relative;
    z-index: 3;
    min-width: 0;
    justify-content: space-between;
}

/* Player/opponent heading inside a side panel. Long names truncate with an
   ellipsis; the min-width floor keeps short names ("You") whole when the
   counter pills crowd the row on narrow screens. */
.side-title {
    margin: 0;
    min-width: 3.5em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: clamp(0.86rem, 1.5vw, 1.16rem);
    font-weight: 750;
    letter-spacing: 0;
}


/* Counter group for Pokemon left, deck, hand, discard, and KO totals. */
.side-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
}

/* Compact pill labels used for counters, turn label, and selected-card summary. */
.stat-pill,
.turn-pill,
.selected-pill {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    padding: 4px 8px;
    border-radius: 999px;
    border: 1px solid rgba(251, 246, 232, 0.18);
    background-color: rgba(0, 0, 0, 0.18);
    color: var(--muted);
    font-size: 0.78rem;
    white-space: nowrap;
}

/* Board row inside each side panel: left and right pile pairs flank active slots. */
.battle-row {
    position: relative;
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(var(--pile-card-w), 0.28fr) minmax(160px, 1fr) minmax(var(--pile-card-w), 0.28fr);
    grid-template-rows: repeat(2, minmax(0, auto));
    align-items: center;
    gap: var(--panel-gap);
}

/* Side-level Dragon Gem markers gained by playing gem items. */
.dragon-gem-tray {
    position: absolute;
    left: 4px;
    z-index: 4;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    max-width: min(46%, 180px);
    pointer-events: none;
}

/* Player gem markers sit near the top-left of their board side. */
.dragon-gem-tray--player {
    top: 4px;
}

/* Opponent gem markers sit near the bottom-left of their board side. */
.dragon-gem-tray--opponent {
    bottom: 4px;
}

/* Individual miniature item icon used as a persistent side marker. */
.dragon-gem-token {
    width: clamp(20px, 2vw, 30px);
    height: clamp(20px, 2vw, 30px);
    display: grid;
    place-items: center;
    padding: 2px;
    border: 1px solid rgba(251, 246, 232, 0.5);
    border-radius: 999px;
    background-color: rgba(5, 13, 16, 0.72);
    box-shadow: 0 5px 12px rgba(0, 0, 0, 0.32);
}

/* Scales gem artwork cleanly inside the side marker. */
.dragon-gem-token img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Effect-boost side marker mirrors the gem tray and stacks just inside it so the
   two persistent side markers form one column and never overlap the piles. */
.effect-boost-tray {
    position: absolute;
    left: 4px;
    z-index: 4;
    display: flex;
    pointer-events: none;
}

.effect-boost-tray--player {
    top: 40px;
}

.effect-boost-tray--opponent {
    bottom: 40px;
}

/* The effect-boost glyph is dark grey, so its marker uses the light token shell
   instead of the dark one the gem tokens share. */
.effect-boost-tray .dragon-gem-token {
    border-color: rgba(37, 27, 24, 0.45);
    background-color: rgba(247, 238, 215, 0.94);
}

/* Generic pile wrapper used for deck/discard/KO columns. */
.pile {
    min-width: 0;
    display: grid;
    justify-items: center;
    gap: 4px;
}

/* Pokemon and main decks stack together on the left side of the board row. */
.pile--pokemon-deck,
.pile--deck {
    grid-column: 1;
}

.pile--pokemon-deck {
    grid-row: 1;
}

.pile--deck {
    grid-row: 2;
}

/* Discard and knockout piles stack together on the right side of the board row.
   The wide layout re-columns them just left of the active slots instead. */
.pile--discard,
.pile--knockout {
    grid-column: 3;
}

.pile--discard {
    grid-row: 1;
}

.pile--knockout {
    grid-row: 2;
}

/* Visual card block used for deck, discard, and knockout pile counts. */
.pile-card {
    position: relative;
    width: var(--pile-card-w);
    height: var(--pile-card-h);
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: 8px;
    border: 2px solid rgba(251, 246, 232, 0.18);
    color: #fbf6e8;
    font: inherit;
    font-weight: 800;
    background:
        repeating-linear-gradient(135deg, rgba(251, 246, 232, 0.12) 0 7px, transparent 7px 14px),
        linear-gradient(145deg, #59489a, #1d756e);
    box-shadow: 0 10px 18px rgba(0, 0, 0, 0.28);
    overflow: hidden;
}

button.pile-card {
    cursor: pointer;
}

button.pile-card:hover,
button.pile-card:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--gold) 78%, transparent);
    outline-offset: 2px;
}

.pile-card--card-back {
    border-color: rgba(251, 246, 232, 0.08);
    background: transparent;
}

.pile-card-back-image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: fill;
}

.pile-count-badge {
    position: absolute;
    right: -2px;
    bottom: -2px;
    z-index: 2;
    min-width: 20px;
    min-height: 20px;
    display: grid;
    place-items: center;
    padding: 2px 5px;
    border: 1px solid rgba(251, 246, 232, 0.62);
    border-radius: 999px;
    background-color: rgba(5, 13, 16, 0.88);
    color: #fbf6e8;
    font-size: 0.68rem;
    line-height: 1;
}

.pile-card--discard-preview {
    align-content: center;
    gap: 3px;
    padding: 6px 4px;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0.12)),
        #d8ceb7;
    color: var(--ink);
    text-align: center;
}

.pile-card-kind {
    max-width: 100%;
    color: rgba(37, 27, 24, 0.62);
    font-size: 0.54rem;
    line-height: 1;
    text-transform: uppercase;
}

.pile-card-name {
    max-width: 100%;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    font-size: clamp(0.48rem, calc(var(--pile-card-w) * 0.14), 0.74rem);
    line-height: 1.05;
}

/* Discard pile variant that distinguishes spent action cards from the deck. */
.pile--discard .pile-card {
    color: var(--ink);
    background:
        linear-gradient(160deg, color-mix(in srgb, var(--coral) 24%, transparent), color-mix(in srgb, var(--gold) 22%, transparent)),
        #d8ceb7;
    border-color: rgba(37, 27, 24, 0.28);
}

/* Pokemon deck pile variant used for the separate Pokemon draw deck. */
.pile--pokemon-deck .pile-card {
    background:
        repeating-linear-gradient(135deg, rgba(251, 246, 232, 0.12) 0 7px, transparent 7px 14px),
        linear-gradient(145deg, #2b6e9b, #184b52);
}

/* Knockout pile variant used for defeated Pokemon. */
.pile--knockout .pile-card {
    background:
        repeating-linear-gradient(45deg, rgba(251, 246, 232, 0.1) 0 6px, transparent 6px 12px),
        linear-gradient(145deg, #382c34, #9f3e4a);
    border-color: color-mix(in srgb, var(--coral) 44%, transparent);
}

.pile--deck .pile-card--card-back,
.pile--pokemon-deck .pile-card--card-back {
    background: transparent;
    border-color: rgba(251, 246, 232, 0.08);
}

.pile--discard .pile-card--discard-preview {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0.12)),
        #d8ceb7;
    color: var(--ink);
}

/* Decorative inner borders for pile cards. */
.pile-card::before,
.pile-card::after {
    content: "";
    position: absolute;
    inset: 4px;
    border: 1px solid rgba(251, 246, 232, 0.22);
    border-radius: 6px;
}

.pile-card--card-back::before,
.pile-card--card-back::after,
.pile-card--discard-preview::before,
.pile-card--discard-preview::after {
    display: none;
}

/* Empty pile state shown when a pile has no cards. */
.pile-card.is-empty {
    color: rgba(251, 246, 232, 0.34);
    background: rgba(0, 0, 0, 0.16);
    border-style: dashed;
    box-shadow: none;
}

.pile-empty-count {
    position: relative;
    z-index: 1;
}

/* Small uppercase labels for piles and hand rows. */
.pile-label,
.hand-label {
    color: var(--muted);
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
}

.pile-window {
    position: fixed;
    right: max(clamp(10px, 2.4vw, 28px), var(--safe-right));
    top: 50%;
    z-index: 35;
    width: min(360px, calc(100vw - 20px));
    max-height: min(72dvh, 620px);
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    gap: 10px;
    padding: 12px;
    border: 1px solid rgba(251, 246, 232, 0.22);
    border-radius: 8px;
    background-color: rgba(18, 29, 30, 0.96);
    box-shadow: 0 18px 46px rgba(0, 0, 0, 0.44);
    transform: translateY(-50%);
}

.pile-window-header {
    min-width: 0;
    display: flex;
    align-items: start;
    justify-content: space-between;
    gap: 12px;
}

.pile-window-title {
    margin: 0;
    color: #fbf6e8;
    font-size: 1rem;
    line-height: 1.1;
}

.pile-window-count {
    display: block;
    margin-top: 3px;
    color: var(--muted);
    font-size: 0.76rem;
}

.pile-window-close {
    width: 28px;
    height: 28px;
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    padding: 0;
    border: 1px solid rgba(251, 246, 232, 0.2);
    border-radius: 999px;
    background-color: rgba(0, 0, 0, 0.22);
    color: #fbf6e8;
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
}

.pile-window-close:hover,
.pile-window-close:focus-visible {
    outline: 3px solid color-mix(in srgb, var(--gold) 72%, transparent);
    outline-offset: 2px;
}

.pile-window-cards {
    min-height: 0;
    display: grid;
    align-content: start;
    gap: 8px;
    padding-right: 4px;
    overflow-y: auto;
}

.pile-window-entry {
    min-width: 0;
    display: grid;
    grid-template-columns: 24px 52px minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    padding: 6px;
    border: 1px solid rgba(251, 246, 232, 0.12);
    border-radius: 8px;
    background-color: rgba(0, 0, 0, 0.14);
}

.pile-window-index {
    color: var(--muted);
    font-size: 0.72rem;
    font-weight: 800;
    text-align: right;
}

.pile-window-thumb {
    width: 52px;
    height: 52px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    place-items: center;
    gap: 3px;
    padding: 5px;
    border: 1px solid rgba(251, 246, 232, 0.16);
    border-radius: 8px;
    background-color: rgba(251, 246, 232, 0.08);
    overflow: hidden;
}

.pile-window-thumb img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.pile-window-thumb--pokemon img,
.pile-window-thumb--item img {
    grid-column: 1 / -1;
    width: 100%;
    height: 100%;
}

.pile-window-thumb-type .type-icon,
.pile-window-thumb .type-icon {
    width: 20px;
    height: 20px;
}

.pile-window-card-summary {
    min-width: 0;
    display: grid;
    gap: 4px;
}

.pile-window-card-summary strong,
.pile-window-card-summary span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pile-window-card-summary strong {
    color: #fbf6e8;
    font-size: 0.86rem;
    line-height: 1.1;
}

.pile-window-card-summary span {
    color: var(--muted);
    font-size: 0.74rem;
    text-transform: uppercase;
}

/* Two-slot active Pokemon area rendered for each player. */
.played-slots {
    position: relative;
    min-width: 0;
    grid-column: 2;
    grid-row: 1 / 3;
    display: grid;
    grid-template-columns: repeat(2, minmax(var(--card-w), 1fr));
    align-items: center;
    justify-items: center;
    gap: var(--panel-gap);
}

/* Cursor state when the entire side can be selected as a group target. */
.played-slots.is-group-target {
    cursor: crosshair;
}

/* Animated group-target ring for ALL_ALLIES and ALL_OPPONENTS actions. */
.played-slots.is-group-target::after {
    content: "";
    position: absolute;
    inset: 10px 21%;
    z-index: 0;
    border: 3px solid color-mix(in srgb, var(--aqua) 70%, transparent);
    border-radius: 999px;
    pointer-events: none;
    animation: group-target-flash 1.35s ease-in-out infinite;
}

/* Individual active Pokemon slot and drop target surface. */
.board-slot {
    position: relative;
    z-index: 1;
    min-width: calc(var(--card-w) + 12px);
    min-height: calc(var(--card-h) + 8px);
    display: grid;
    align-content: center;
    justify-items: center;
    gap: 5px;
    padding: 6px;
    border: 2px dashed rgba(251, 246, 232, 0.22);
    border-radius: 8px;
    background-color: rgba(0, 0, 0, 0.12);
}

/* Base visual treatment for every rendered card. */
.playing-card {
    width: var(--card-w);
    height: var(--card-h);
    display: grid;
    grid-template-rows: minmax(0, 1fr) auto auto auto;
    gap: 2px;
    padding: clamp(4px, 0.5vw, 6px);
    border: 2px solid rgba(37, 27, 24, 0.72);
    border-radius: 8px;
    color: var(--ink);
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.1)),
        var(--paper);
    box-shadow: 0 9px 16px rgba(0, 0, 0, 0.26);
    font: inherit;
    text-align: left;
    overflow: hidden;
    user-select: none;
}

/* Interactive card cursor and movement transition for buttons rendered as cards. */
button.playing-card {
    cursor: pointer;
    transition: transform 0.14s ease, box-shadow 0.14s ease, outline-color 0.14s ease;
}

/* Hover/focus lift for clickable cards in hand or target selection. */
button.playing-card:hover,
button.playing-card:focus-visible {
    transform: translateY(-4px);
    outline: 3px solid color-mix(in srgb, var(--gold) 78%, transparent);
    outline-offset: 2px;
    box-shadow: 0 13px 20px rgba(0, 0, 0, 0.32);
}

/* Selected hand card state. */
.playing-card.is-selected {
    transform: translateY(-6px);
    outline: 3px solid var(--gold);
    outline-offset: 2px;
}

/* Card can be selected as a direct action target. */
.playing-card.is-targetable {
    cursor: crosshair;
    outline: 3px solid color-mix(in srgb, var(--coral) 76%, transparent);
    outline-offset: 2px;
}

/* Stronger target feedback while hovering/focusing targetable cards. */
.playing-card.is-targetable:hover,
.playing-card.is-targetable:focus-visible {
    transform: translateY(-4px) scale(1.03);
    outline-color: var(--gold);
}

/* Candidate Pokemon that can use a selected attack. */
.playing-card.is-user-option {
    --card-glow-start: color-mix(in srgb, var(--gold) 42%, transparent);
    --card-glow-size: 6px;
    --card-glow-peak: color-mix(in srgb, var(--gold) 50%, transparent);

    cursor: pointer;
    animation: card-glow-flash 1.45s ease-in-out infinite;
}

/* Selected attack user while choosing that attack's target. */
.playing-card.is-user-active {
    --card-glow-start: color-mix(in srgb, var(--gold) 58%, transparent);
    --card-glow-size: 8px;
    --card-glow-peak: color-mix(in srgb, var(--gold) 68%, transparent);

    animation: card-glow-flash 0.72s ease-in-out infinite;
}

/* Card or side currently valid as an action target. */
.playing-card.is-action-target {
    --card-glow-start: color-mix(in srgb, var(--aqua) 42%, transparent);
    --card-glow-size: 6px;
    --card-glow-peak: color-mix(in srgb, var(--aqua) 56%, transparent);

    cursor: crosshair;
    animation: card-glow-flash 1.35s ease-in-out infinite;
}

/* Smaller card sizing for cards rendered in hand rows. */
.hand-card {
    --card-w: var(--hand-card-w);

    width: var(--hand-card-w);
    height: var(--hand-card-h);
    padding: 3px;
    touch-action: none;
    /* iOS Safari: stop long-press from firing the text-selection callout, which
       otherwise hijacks the pointer stream and kills the drag mid-gesture. */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

/* Fades the original card while a drag ghost is active. */
.playing-card.is-source-dragging {
    opacity: 0.42;
}

/* Shared fixed positioning for transient drag, animation, damage, and stat markers. */
.drag-ghost,
.attack-animation-card,
.draw-animation-card,
.discard-animation-card,
.damage-float,
.stat-change-float {
    position: fixed;
    pointer-events: none;
}

/* Drag clone generated by arena_drag.js while moving a card. */
.drag-ghost {
    z-index: 1000;
    transform: rotate(2deg) scale(1.04);
}

/* Floating pending attack card rendered over the selected user during target selection. */
.attack-hover-card {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 6;
    cursor: grab;
    transform: translate(-50%, -58%) rotate(2deg) scale(0.94);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 62%, transparent), 0 18px 30px rgba(0, 0, 0, 0.38);
    animation: attack-hover-pulse 1.1s ease-in-out infinite;
}

/* Hover/focus feedback for the floating pending attack card. */
.attack-hover-card:hover,
.attack-hover-card:focus-visible {
    transform: translate(-50%, -60%) rotate(2deg) scale(0.98);
    outline: 3px solid color-mix(in srgb, var(--gold) 86%, transparent);
    outline-offset: 2px;
}

/* Reduces the original floating attack card while it is being dragged. */
.attack-hover-card.is-source-dragging {
    opacity: 0.18;
}

/* Drag clone variant for the floating pending attack card. */
.drag-ghost.attack-hover-card {
    position: fixed;
    cursor: grabbing;
    animation: none;
    transform: rotate(2deg) scale(1.04);
}

/* Attack and item animation clone flown from user/hand toward targets.
   Flight movement is driven by controller keyframes (animateCardFlight);
   the base transform matches the flight's first keyframe to avoid a flash. */
.attack-animation-card {
    z-index: 1100;
    transform: rotate(-2deg) scale(0.96);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 58%, transparent), 0 18px 32px rgba(0, 0, 0, 0.38);
}

/* Draw and discard animation clones, also flown by controller keyframes. */
.draw-animation-card,
.discard-animation-card {
    z-index: 1080;
    transform: rotate(-2deg) scale(0.96);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 42%, transparent), 0 16px 28px rgba(0, 0, 0, 0.36);
}

/* Pokemon draw animation clone traveling from Pokemon/KO pile into a board slot. */
.pokemon-draw-animation-card {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--aqua) 58%, transparent), 0 16px 28px rgba(0, 0, 0, 0.36);
}

/* Higher stacking for discard animation so it clears cards and damage text. */
.discard-animation-card {
    z-index: 1110;
}

/* Temporarily hides a real card while its draw animation finishes. */
.playing-card.is-arriving-card {
    opacity: 0;
}

/* Shared readable text treatment for floating damage and stat-change markers. */
.damage-float,
.stat-change-float {
    z-index: 1200;
    color: #fbf6e8;
    text-align: center;
}

/* Floating damage number shown after direct or status damage. */
.damage-float {
    min-width: 42px;
    transform: translate(-50%, -100%);
    padding: 3px 8px;
    border: 1px solid rgba(251, 246, 232, 0.62);
    border-radius: 999px;
    background-color: rgba(122, 26, 30, 0.94);
    font-size: clamp(0.78rem, 1vw, 1rem);
    font-weight: 900;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
    animation: damage-float 0.86s ease-out forwards;
}

/* Floating stat label shown when a stat stage changes. */
.stat-change-float {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 34px;
    transform: translate(-50%, -50%);
    font-size: clamp(0.62rem, 0.86vw, 0.82rem);
    font-weight: 950;
    letter-spacing: 0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.42);
}

/* Arrow body shared by up/down stat-change markers. */
.stat-change-float::before {
    content: "";
    display: block;
    width: 8px;
    height: 20px;
    border-radius: 999px;
}

/* Upward stat-change animation state. */
.stat-change-float--up {
    animation: stat-change-up 0.9s ease-out forwards;
}

/* Up arrow shape for positive stat changes. */
.stat-change-float--up::before {
    background: linear-gradient(180deg, #42cf78, #237b45);
    clip-path: polygon(50% 0, 100% 44%, 72% 44%, 72% 100%, 28% 100%, 28% 44%, 0 44%);
}

/* Downward stat-change animation state. */
.stat-change-float--down {
    flex-direction: column-reverse;
    animation: stat-change-down 0.9s ease-out forwards;
}

/* Down arrow shape for negative stat changes. */
.stat-change-float--down::before {
    background: linear-gradient(180deg, #d84c3d, #8e2f28);
    clip-path: polygon(28% 0, 72% 0, 72% 56%, 100% 56%, 50% 100%, 0 56%, 28% 56%);
}

/* Active drag/drop highlight for board slots and card targets. */
.board-slot.is-drop-target,
.playing-card.is-drop-target,
.pile.is-drop-target .pile-card {
    outline: 3px solid var(--gold);
    outline-offset: 3px;
}

/* Drag preview on the discard pile when a hand card can be discarded there. */
.pile.is-drag-discard-preview .pile-card {
    outline: 3px solid color-mix(in srgb, var(--gold) 70%, transparent);
    outline-offset: 3px;
}

/* "Ready" badge shown on active Pokemon that already queued an attack. */
.slot-badge {
    position: absolute;
    right: 3px;
    top: 3px;
    z-index: 3;
    padding: 2px 5px;
    border-radius: 999px;
    border: 1px solid rgba(251, 246, 232, 0.42);
    background-color: color-mix(in srgb, var(--felt) 94%, transparent);
    color: #fbf6e8;
    font-size: 0.58rem;
    font-weight: 850;
    line-height: 1;
}

/* Top area inside a Pokemon card, aligned around portrait/type/name content. */
.card-top {
    min-height: 0;
    display: flex;
    justify-content: flex-end;
}

/* Pokemon portrait/type/name grid inside a Pokemon card. */
.card-visual {
    position: relative;
    width: min(100%, calc(var(--card-w) * 0.96));
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: auto auto;
    gap: 2px 3px;
    align-self: start;
}

/* Truncation defaults for compact card and log text. */
.card-name,
.card-topline,
.card-footer,
.action-card-name,
.action-card-meta {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Pokemon name line inside Pokemon cards. */
.card-name {
    grid-column: 1 / -1;
    min-width: 0;
    text-align: center;
    white-space: nowrap;
    font-size: 0.54rem;
    font-weight: 850;
    line-height: 1;
}

/* Vertical type icon column inside Pokemon cards. */
.type-row {
    display: grid;
    grid-template-rows: repeat(3, auto);
    gap: 1px;
    align-content: start;
    justify-items: center;
    grid-column: 2;
    grid-row: 1;
}

/* Shared type icon sizing used on cards, filters, and reference chips. */
.type-icon {
    width: clamp(10px, calc(var(--card-w) * 0.16), 18px);
    height: clamp(10px, calc(var(--card-w) * 0.16), 18px);
    padding: 1px;
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.72);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.22);
}

/* Pokemon portrait frame; uses a generated hue fallback behind image portraits. */
.card-portrait {
    position: relative;
    min-height: 0;
    display: grid;
    place-items: center;
    aspect-ratio: 1;
    width: calc(var(--card-w) * 0.646);
    max-width: 100%;
    justify-self: start;
    grid-column: 1;
    grid-row: 1;
    border: 1px solid rgba(37, 27, 24, 0.3);
    border-radius: 5px;
    background:
        radial-gradient(circle at 35% 30%, hsla(var(--portrait-hue), 68%, 78%, 0.88), transparent 28%),
        linear-gradient(145deg, hsl(var(--portrait-hue), 48%, 50%), hsl(calc(var(--portrait-hue) + 44), 42%, 34%));
    color: rgba(255, 255, 255, 0.86);
    font-size: clamp(0.5rem, 0.95vw, 0.74rem);
    font-weight: 900;
    overflow: hidden;
}

/* Pokemon portrait image inside the portrait frame. */
.portrait-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    grid-area: 1 / 1;
}

/* Initials fallback when a portrait image is not displayed. */
.portrait-img + span {
    grid-area: 1 / 1;
    display: none;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
}

/* Status token stack rendered over Pokemon portraits. */
.status-token-row {
    position: absolute;
    left: 2px;
    top: 2px;
    z-index: 2;
    max-width: calc(var(--card-w) * 0.58);
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    pointer-events: none;
}

/* Shared circular token shell for statuses on cards and action cards. */
.status-token,
.action-status-token {
    place-items: center;
    padding: 1px;
    border-radius: 999px;
}

/* Persistent status token shown on Pokemon cards. */
.status-token {
    width: clamp(15px, 1.5vw, 20px);
    height: clamp(15px, 1.5vw, 20px);
    display: grid;
    border: 2px solid rgba(37, 27, 24, 0.62);
    background-color: rgba(252, 248, 238, 0.97);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.34);
}

/* Per-status tints so conditions read at a glance even at token size. */
.status-token--burn { background-color: #ffd3b6; border-color: #b3441e; }
.status-token--poison { background-color: #eccdf5; border-color: #7d3d92; }
.status-token--sleep { background-color: #ccdcf7; border-color: #3c5a8f; }
.status-token--paralysis { background-color: #ffeea8; border-color: #a8830f; }
.status-token--confusion { background-color: #fbd0e0; border-color: #a83d62; }
.status-token--flinch { background-color: #dcd9d2; border-color: #5c564c; }

/* Icon image sizing inside status/action tokens. */
.status-token img,
.action-status-token img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Pokedex screen: a CSS-drawn pokeball overlaid on the bottom-right corner of
   a caught species' portrait. Gold once the species has won a run in the
   active deck (see .pokedex-badge--champion below). */
.pokedex-badge {
    position: absolute;
    right: 2px;
    bottom: 2px;
    z-index: 2;
    width: clamp(13px, 1.5vw, 18px);
    height: clamp(13px, 1.5vw, 18px);
    border-radius: 999px;
    border: 1px solid rgba(20, 16, 12, 0.8);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    background:
        radial-gradient(circle, rgba(20, 16, 12, 0.85) 0 16%, rgba(252, 248, 238, 0.97) 16% 24%, transparent 24%),
        linear-gradient(rgba(20, 16, 12, 0.85), rgba(20, 16, 12, 0.85)) center / 100% 14% no-repeat,
        linear-gradient(to bottom, #e0483a 0% 46%, rgba(252, 248, 238, 0.97) 54% 100%);
}

/* Gold pokeball: this species has won a run with it in the active deck. */
.pokedex-badge--champion {
    background:
        radial-gradient(circle, rgba(20, 16, 12, 0.85) 0 16%, rgba(252, 248, 238, 0.97) 16% 24%, transparent 24%),
        linear-gradient(rgba(20, 16, 12, 0.85), rgba(20, 16, 12, 0.85)) center / 100% 14% no-repeat,
        linear-gradient(to bottom, #f0c419 0% 46%, rgba(252, 248, 238, 0.97) 54% 100%);
    box-shadow: 0 0 4px 1px rgba(240, 196, 25, 0.75), 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* Permanent vitamin tokens sitting under the Pokemon name. One per vitamin
   given to this specific card, so the row grows across a run — it wraps rather
   than widening the card, and stays narrower than the status tokens so a
   well-fed Pokemon still fits the tiny mobile card column. */
.vitamin-token-row {
    grid-column: 1 / -1;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1px;
    margin-top: 1px;
    pointer-events: none;
}

.vitamin-token {
    width: clamp(10px, 1vw, 14px);
    height: clamp(10px, 1vw, 14px);
    display: grid;
    place-items: center;
    padding: 1px;
    border-radius: 999px;
    border: 1px solid rgba(37, 27, 24, 0.62);
    background-color: rgba(252, 248, 238, 0.97);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

/* Per-stat tints, matching the vitamin icon colours. */
.vitamin-token--attack { background-color: #ffd0c4; border-color: #b3441e; }
.vitamin-token--defense { background-color: #cfe0f7; border-color: #3c5a8f; }
.vitamin-token--speed { background-color: #ffeea8; border-color: #a8830f; }

.vitamin-token img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Pokemon health percentage and bar row. */
.health-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 3px;
    align-items: center;
    color: rgba(37, 27, 24, 0.84);
    font-size: 0.56rem;
    font-weight: 850;
}

/* Health bar track inside Pokemon cards. */
.health-track {
    height: 6px;
    overflow: hidden;
    border-radius: 999px;
    background-color: rgba(37, 27, 24, 0.18);
}

/* Filled part of the Pokemon health bar. */
.health-track span {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: linear-gradient(90deg, #4ab05f, #d8b744);
}

/* Pokemon HP/effective-stat grid. */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px 2px;
    color: rgba(37, 27, 24, 0.86);
    font-size: 0.54rem;
    font-weight: 850;
    line-height: 1.05;
}

/* Prevents stat labels from wrapping inside compact cards. */
.stat-grid span {
    min-width: 0;
    overflow: visible;
    white-space: nowrap;
}

/* Positive stat-stage color used on cards and reference table. */
.stat-grid .stat-cell--up,
.stage-up {
    color: #237b45;
}

/* Negative stat-stage color used on cards and reference table. */
.stat-grid .stat-cell--down,
.stage-down {
    color: #b04332;
}

/* A status is raising this stat (e.g. FIGHTING's bonus while any status is up). */
.stat-grid .stat-cell--status-up {
    color: #1668cc;
}

/* A status is lowering this stat (burn, paralysis, fatigue). */
.stat-grid .stat-cell--status-down {
    color: #7b2fa8;
}

/* Card back top/footer labels. */
.card-topline,
.card-footer {
    min-width: 0;
    white-space: nowrap;
    font-size: 0.62rem;
    font-weight: 800;
}

/* Center content for face-down card backs. */
.card-body {
    display: grid;
    place-items: center;
    border: 1px solid rgba(37, 27, 24, 0.24);
    border-radius: 6px;
    color: rgba(37, 27, 24, 0.42);
    font-size: clamp(0.62rem, 1.1vw, 0.8rem);
    font-weight: 850;
}

/* Face-down card styling for hidden opponent cards and unrevealed setup cards. */
.card-back {
    grid-template-rows: auto 1fr auto;
    border-color: rgba(251, 246, 232, 0.14);
    color: transparent;
    background-color: transparent;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 100% 100%;
}

/* Adjusts face-down card body contrast. */
.card-back .card-body {
    border-color: transparent;
    color: transparent;
}

.card-back .card-topline,
.card-back .card-footer {
    color: transparent;
}

.card-back.card-kind-pokemon {
    background-image: url("../assets/card-backs/POKEMON_CARD_BACK.png");
}

.card-back.card-kind-attack,
.card-back.card-kind-item {
    background-image: url("../assets/card-backs/ACTION_CARD_BACK.png");
}

/* Attack and item cards use one full-card action shell instead of Pokemon card rows. */
.playing-card.card-kind-attack:not(.card-back),
.playing-card.card-kind-item:not(.card-back) {
    grid-template-rows: 1fr;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.08)),
        var(--action-card-bg);
}

/* Attack card color token. */
.playing-card.card-kind-attack:not(.card-back) {
    --action-card-bg: #eef8ff;
}

/* Item card color token. */
.playing-card.card-kind-item:not(.card-back) {
    --action-card-bg: #fbf0c7;
}

/* Internal grid for action cards: name, type/item art, effects, and target text. */
.action-card-shell {
    height: 100%;
    min-width: 0;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    gap: 2px;
    text-align: center;
}

/* Attack/item card name. */
.action-card-name {
    align-self: center;
    min-width: 0;
    color: rgba(37, 27, 24, 0.9);
    font-size: 0.48rem;
    font-weight: 900;
    line-height: 1.05;
}

/* Attack type icon row on action cards. */
.action-type-row {
    display: flex;
    justify-content: center;
    gap: 3px;
}

/* Item image row on item cards. */
.item-picture-row {
    min-height: clamp(30px, calc(var(--card-w) * 0.4), 54px);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Item image inside item cards. */
.item-picture {
    width: clamp(30px, calc(var(--card-w) * 0.46), 62px);
    height: clamp(30px, calc(var(--card-w) * 0.46), 62px);
    object-fit: contain;
    filter: drop-shadow(0 3px 4px rgba(37, 27, 24, 0.24));
}

/* Larger type icons for action cards. */
.action-type-row .type-icon {
    width: clamp(13px, calc(var(--card-w) * 0.3), 30px);
    height: clamp(13px, calc(var(--card-w) * 0.3), 30px);
}

/* Visual marker for attacks that require all listed types. */
.action-type-row--all-required {
    width: fit-content;
    align-self: center;
    justify-self: center;
    align-items: center;
    padding: 2px 4px;
    border: 1px solid rgba(52, 152, 219, 0.74);
    border-radius: 999px;
    background-color: rgba(52, 152, 219, 0.18);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.34);
}

/* Placeholder for attacks with no listed type. */
.action-type-row--empty {
    color: rgba(37, 27, 24, 0.48);
    font-size: 0.44rem;
    font-weight: 800;
}

/* Effect badge row for power, statuses, and stat changes on action cards. */
.action-card-effects {
    min-width: 0;
    min-height: clamp(12px, calc(var(--card-w) * 0.18), 20px);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2px 3px;
}

/* Shared badge shell for base power and stat-change summaries. */
.attack-power,
.action-stat-change {
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(37, 27, 24, 0.24);
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.46);
    color: rgba(37, 27, 24, 0.78);
    font-size: 0.38rem;
    font-weight: 900;
    line-height: 1;
}

/* Base-power badge on attack cards. */
.attack-power {
    padding: 1px 3px;
    white-space: nowrap;
}

/* Inline lists for status and stat-change effect badges. */
.action-status-list,
.action-stat-change-list {
    min-width: 0;
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 2px;
}

/* Action-card status/effect token. */
.action-status-token {
    width: clamp(12px, calc(var(--card-w) * 0.18), 20px);
    height: clamp(12px, calc(var(--card-w) * 0.18), 20px);
    display: inline-grid;
    flex: 0 0 auto;
    border: 1px solid rgba(37, 27, 24, 0.32);
    background-color: rgba(247, 238, 215, 0.92);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);
}

/* Text fallback token when a status/effect has no image. */
.action-status-token--text {
    color: rgba(37, 27, 24, 0.72);
    font-size: 0.34rem;
    font-weight: 900;
}

/* Compact stat-change badge inside an action card. */
.action-stat-change {
    gap: 2px;
    padding: 1px 2px;
}

/* Vitamin badge on item cards. Flat permanent points, not stage steps, so it
   reads as a plain number instead of the arrow group next to it. */
.action-vitamin-badge {
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 1px 3px;
    border: 1px solid rgba(37, 27, 24, 0.24);
    border-radius: 999px;
    background-color: rgba(255, 255, 255, 0.46);
    color: rgba(37, 27, 24, 0.78);
    font-size: 0.38rem;
    font-weight: 900;
    line-height: 1;
    white-space: nowrap;
}

/* Stat abbreviation in stat-change badges. */
.action-stat-name {
    color: rgba(37, 27, 24, 0.74);
}

/* Arrow group inside stat-change badges. */
.stat-arrows {
    display: inline-flex;
    align-items: center;
    gap: 1px;
}

/* Triangle base used for stat-change arrows. */
.stat-arrow {
    --stat-arrow-h: clamp(5px, calc(var(--card-w) * 0.072), 9px);
    --stat-arrow-w: clamp(3px, calc(var(--card-w) * 0.045), 6px);
    width: 0;
    height: 0;
    display: inline-block;
    border-left: var(--stat-arrow-w) solid transparent;
    border-right: var(--stat-arrow-w) solid transparent;
}

/* Up arrow inside stat-change badges. */
.stat-arrow--up {
    border-bottom: var(--stat-arrow-h) solid #237b45;
}

/* Down arrow inside stat-change badges. */
.stat-arrow--down {
    border-top: var(--stat-arrow-h) solid #b04332;
}

/* Target text at the bottom of action cards. */
.action-card-meta {
    min-width: 0;
    white-space: nowrap;
    color: rgba(37, 27, 24, 0.68);
    font-size: 0.32rem;
    font-weight: 800;
}

/* --- Card Overview --- */

/* Page shell for card_overview.js. */
.card-overview-page {
    display: block;
}

/* Main content container on the card overview page. */
.card-overview {
    width: min(100%, 1220px);
    margin: 0 auto;
    padding: calc(74px + var(--safe-top)) max(clamp(14px, 3vw, 34px), var(--safe-right)) max(42px, var(--safe-bottom)) max(clamp(14px, 3vw, 34px), var(--safe-left));
}

/* Header row for overview title and type filter controls. */
.overview-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: clamp(22px, 4vw, 42px);
}

/* Overview page title. The lower bound keeps a long single-word title (e.g.
   "Achievements") inside a 320px-wide phone, where it cannot wrap. */
.overview-header h1 {
    margin: 0;
    color: #fbf6e8;
    font-size: clamp(1.9rem, 7vw, 4.6rem);
    letter-spacing: 0;
    line-height: 0.95;
    text-transform: uppercase;
    text-shadow: 0 8px 22px rgba(0, 0, 0, 0.36);
}

/* Selected type/filter pill in the overview header. */
.card-overview-page .overview-filter-pill {
    flex: 0 0 auto;
    grid-column: auto;
    width: auto;
    min-width: 116px;
    justify-content: center;
    color: #fbf6e8;
    font-weight: 820;
}

/* Wrapper for overview sections. */
.overview-content {
    display: grid;
    gap: clamp(28px, 5vw, 54px);
}

/* Individual overview section for Pokemon, attacks, or items. */
.overview-section {
    display: grid;
    gap: 16px;
    padding: clamp(14px, 2vw, 20px) 0 clamp(22px, 3vw, 32px);
    border-top: 1px solid rgba(251, 246, 232, 0.16);
}

/* Section heading row with label and controls. */
.overview-section-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
}

/* Overview section heading text. */
.overview-section-header h2 {
    margin: 0;
    color: #fbf6e8;
    font-size: clamp(1.25rem, 2.6vw, 2rem);
    letter-spacing: 0;
}

/* Responsive card grid for overview cards. */
.overview-card-grid {
    display: grid;
    grid-template-columns: repeat(6, var(--card-w));
    justify-content: center;
    gap: clamp(10px, 1.5vw, 16px);
}

/* Card preview transition shell on overview pages. */
.overview-card {
    transition: opacity 0.16s ease, filter 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}

/* Highlighted overview card that matches the selected type filter. */
.overview-card.is-type-match {
    transform: translateY(-4px);
    outline: 3px solid color-mix(in srgb, var(--gold) 86%, transparent);
    outline-offset: 3px;
    box-shadow: 0 15px 28px rgba(0, 0, 0, 0.34);
}

/* Dimmed overview card that does not match the selected type filter. */
.overview-card.is-type-dimmed {
    opacity: 0.28;
    filter: saturate(0.42);
}

/* Clickable type icon used as a filter in the overview page. */
.type-filter-button {
    display: inline-grid;
    place-items: center;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: inherit;
    font: inherit;
    line-height: 0;
    cursor: pointer;
}

/* Hover/focus/selected treatment for overview type filter icons. */
.type-filter-button:hover .type-icon,
.type-filter-button:focus-visible .type-icon,
.type-filter-button.is-type-selected .type-icon {
    outline: 2px solid color-mix(in srgb, var(--gold) 88%, transparent);
    outline-offset: 2px;
    transform: scale(1.12);
}

/* Removes default focus outline so the icon outline is the visible focus indicator. */
.type-filter-button:focus-visible {
    outline: none;
}

.achievements-page {
    display: block;
}

/* Main content container on the achievements page. */
.achievements {
    width: min(100%, 1220px);
    margin: 0 auto;
    padding: calc(74px + var(--safe-top)) max(clamp(14px, 3vw, 34px), var(--safe-right)) max(42px, var(--safe-bottom)) max(clamp(14px, 3vw, 34px), var(--safe-left));
}

/* Responsive grid of achievement rows. */
.achievements-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: clamp(12px, 2vw, 20px);
}

/* One achievement's card: name, description, and progress/unlock meta. */
.achievement-row {
    display: grid;
    gap: 8px;
    padding: 16px 18px;
    border: 1px solid rgba(251, 246, 232, 0.16);
    border-radius: 8px;
    background-color: rgba(0, 0, 0, 0.18);
}

/* Dimmed treatment for a locked achievement row. */
.achievement-row--locked {
    opacity: 0.62;
}

/* Gold-accented treatment for an unlocked achievement row. */
.achievement-row--unlocked {
    border-color: color-mix(in srgb, var(--gold) 55%, transparent);
    background-color: color-mix(in srgb, var(--gold) 12%, rgba(0, 0, 0, 0.18));
    opacity: 1;
}

.achievement-name {
    margin: 0;
    color: #fbf6e8;
    font-size: 1.1rem;
    letter-spacing: 0;
}

.achievement-description {
    margin: 0;
    color: var(--muted);
    font-size: 0.86rem;
    line-height: 1.4;
}

.achievement-unlocked-at {
    margin: 0;
    color: var(--gold);
    font-size: 0.78rem;
    font-weight: 760;
}

.achievement-progress-label {
    margin: 0;
    color: var(--muted);
    font-size: 0.78rem;
}

/* Track for an achievement's progress bar. */
.achievement-progress {
    height: 8px;
    border-radius: 999px;
    background-color: rgba(0, 0, 0, 0.32);
    overflow: hidden;
}

/* Filled portion of an achievement's progress bar; width set inline. */
.achievement-progress-bar {
    height: 100%;
    background-color: var(--gold);
}

/* Floating unlock notice, stacked downward from the top-right corner. */
.achievement-toast {
    position: fixed;
    /* --toast-top is declared on body (see above) so pwa.js can override it. */
    top: var(--toast-top);
    right: max(18px, var(--safe-right));
    z-index: 2400;
    width: min(92vw, 320px);
    display: grid;
    gap: 2px;
    padding: 12px 16px;
    border: 1px solid rgba(251, 246, 232, 0.25);
    border-radius: 8px;
    background: color-mix(in srgb, var(--loc-bg-deep) 96%, transparent);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.36);
    color: #fbf6e8;
    opacity: 0;
    pointer-events: none;
    transform: translateX(24px);
    transition: opacity 0.24s ease, transform 0.24s ease;
}

/* Visible state of an achievement unlock toast. */
.achievement-toast.is-visible {
    opacity: 1;
    transform: translateX(0);
}

.achievement-toast-label {
    color: var(--gold);
    font-size: 0.7rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.achievement-toast-name {
    font-weight: 800;
    font-size: 0.98rem;
}

.achievement-toast-description {
    color: var(--muted);
    font-size: 0.8rem;
}

/*
 * PWA update notice and iOS "Add to Home Screen" hint (pwa.js). Same visual
 * language as .achievement-toast, but seated lower than the toast's top
 * offset so it clears .btn-back (top-left, ~68px tall including its safe-area
 * inset) on the pages that have one - the notice is full-width enough to
 * overlap it horizontally on a phone, so it can only clear it vertically.
 * Rather than moving out of the way of the achievement-toast stack, this
 * keeps its slot and pwa.js pushes the toast stack below it (via
 * --toast-top on body) whenever a notice is on screen.
 */
.pwa-notice {
    position: fixed;
    top: calc(78px + var(--safe-top));
    right: max(18px, var(--safe-right));
    z-index: 2400;
    width: min(92vw, 320px);
    display: grid;
    gap: 10px;
    padding: 12px 16px;
    border: 1px solid rgba(251, 246, 232, 0.25);
    border-radius: 8px;
    background: color-mix(in srgb, var(--loc-bg-deep) 96%, transparent);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.36);
    color: #fbf6e8;
    opacity: 0;
    pointer-events: none;
    transform: translateX(24px);
    transition: opacity 0.24s ease, transform 0.24s ease;
}

.pwa-notice.is-visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateX(0);
}

.pwa-notice-message {
    font-size: 0.85rem;
}

.pwa-notice-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

.pwa-notice-button {
    padding: 6px 14px;
    border: 1px solid var(--gold);
    border-radius: 6px;
    background: transparent;
    color: var(--gold);
    font-size: 0.78rem;
    font-weight: 700;
    cursor: pointer;
}

.pwa-notice-button:hover,
.pwa-notice-button:focus-visible {
    background: var(--gold);
    color: var(--loc-bg-deep);
}

/* Card/user/target glow animation driven by custom glow color variables. */
@keyframes card-glow-flash {
    0%,
    100% {
        box-shadow: 0 9px 16px rgba(0, 0, 0, 0.26), 0 0 0 0 var(--card-glow-start);
    }
    50% {
        box-shadow: 0 9px 16px rgba(0, 0, 0, 0.26), 0 0 0 var(--card-glow-size) var(--card-glow-peak);
    }
}

/* Pulsing ring around group targets. */
@keyframes group-target-flash {
    0%,
    100% {
        opacity: 0.35;
        transform: scaleX(0.92);
    }
    50% {
        opacity: 1;
        transform: scaleX(1);
    }
}

/* Idle pulse for the floating pending attack card. */
@keyframes attack-hover-pulse {
    0%,
    100% {
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 50%, transparent), 0 18px 30px rgba(0, 0, 0, 0.38);
    }
    50% {
        box-shadow: 0 0 0 7px color-mix(in srgb, var(--gold) 34%, transparent), 0 20px 34px rgba(0, 0, 0, 0.42);
    }
}

/* Damage number float-up animation. */
@keyframes damage-float {
    0% {
        opacity: 0;
        transform: translate(-50%, -72%) scale(0.84);
    }
    18% {
        opacity: 1;
        transform: translate(-50%, -118%) scale(1.08);
    }
    100% {
        opacity: 0;
        transform: translate(-50%, -190%) scale(0.96);
    }
}

/* Positive stat-change float animation. */
@keyframes stat-change-up {
    0% {
        opacity: 0;
        transform: translate(-50%, -18%) scale(0.84);
    }
    18% {
        opacity: 1;
        transform: translate(-50%, -72%) scale(1.12);
    }
    100% {
        opacity: 0;
        transform: translate(-50%, -148%) scale(0.98);
    }
}

/* Negative stat-change float animation. */
@keyframes stat-change-down {
    0% {
        opacity: 0;
        transform: translate(-50%, -82%) scale(0.84);
    }
    18% {
        opacity: 1;
        transform: translate(-50%, -28%) scale(1.12);
    }
    100% {
        opacity: 0;
        transform: translate(-50%, 64%) scale(0.98);
    }
}

/* Hand row in each side panel. */
.hand-row {
    min-height: calc(var(--hand-card-h) + 6px);
    overflow: hidden;
}

/* Opponent hand uses tiny backs so the hand count remains readable. */
.hand-row--opponent {
    min-height: calc(var(--opponent-hand-card-h) + 10px);
}

/* Prevents hand labels from shrinking into card rows. */
.hand-label {
    flex: 0 0 auto;
}

/* Horizontally scrollable hand card strip. */
.hand-cards {
    min-width: 0;
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 4px 8px;
    overflow-x: auto;
    scroll-snap-type: x proximity;
}

/* Snap each hand card to the strip's leading edge while scrolling. */
.hand-cards .hand-card {
    scroll-snap-align: start;
}

/* Tight spacing for the opponent's hidden hand strip. */
.hand-row--opponent .hand-cards {
    gap: 4px;
    padding: 3px 2px 4px;
}

/* Keeps hand cards at fixed card widths inside the scroll strip. */
.hand-cards .playing-card {
    flex: 0 0 auto;
}

/* Miniature face-down opponent hand cards; content is decorative only. */
.hand-row--opponent .hand-card {
    --card-w: var(--opponent-hand-card-w);

    width: var(--opponent-hand-card-w);
    height: var(--opponent-hand-card-h);
    padding: 2px;
    border-width: 1px;
    border-radius: 5px;
    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.22);
}

.hand-row--opponent .hand-card .card-topline,
.hand-row--opponent .hand-card .card-footer {
    display: none;
}

.hand-row--opponent .hand-card .card-body {
    border: 0;
    color: transparent;
}

/* Empty hand/slot placeholder text. */
.empty-hand {
    color: rgba(251, 246, 232, 0.45);
    font-size: 0.88rem;
    font-style: italic;
}

/* Central turn-control box rendered between side panels. */
.arena-status {
    justify-content: space-between;
    min-height: 58px;
    padding: 6px clamp(8px, 0.9vw, 11px);
    border-top: 1px solid rgba(251, 246, 232, 0.14);
    border-bottom: 1px solid rgba(251, 246, 232, 0.14);
    background-color: rgba(5, 13, 16, 0.36);
    box-shadow: inset 0 1px rgba(255, 255, 255, 0.06);
}

/* Turn message area inside the control box. */
.turn-copy {
    min-width: 180px;
}

/* Legacy heading style for turn copy, retained for richer status markup. */
.turn-copy h1 {
    margin: 0 0 4px;
    font-size: clamp(1rem, 2.1vw, 1.5rem);
    letter-spacing: 0;
    text-transform: none;
}

/* Main turn instruction text. */
.turn-copy p {
    margin: 0;
    color: var(--muted);
    font-size: clamp(0.78rem, 1.2vw, 0.94rem);
}

/* Button row inside the turn-control box. */
.action-bar {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

/* Base arena action button used for place, end turn, cancel, restart, and rules. */
.arena-button {
    min-height: 38px;
    padding: 8px 12px;
    color: #fbf6e8;
    font: inherit;
    font-size: 0.88rem;
    cursor: pointer;
}

/* Focus/hover outline for enabled arena buttons. */
.arena-button:hover:not(:disabled),
.arena-button:focus-visible:not(:disabled) {
    outline: 2px solid color-mix(in srgb, var(--gold) 65%, transparent);
    outline-offset: 2px;
}

/* Disabled arena button state for unavailable actions. */
.arena-button:disabled {
    cursor: not-allowed;
    opacity: 0.45;
}

/* Destructive/emphasis variant used for End Turn. */
.arena-button--danger {
    background-color: color-mix(in srgb, var(--coral) 32%, transparent);
}

/* Discard command variant. */
.arena-button--discard {
    background-color: color-mix(in srgb, var(--gold) 24%, transparent);
}

/* Discard-the-whole-hand variant: same family as Discard, dialed down. */
.arena-button--discard-hand {
    background-color: color-mix(in srgb, var(--gold) 15%, transparent);
}

/* Undo command variant: secondary to Discard in the same command group. */
.arena-button--undo {
    background-color: color-mix(in srgb, var(--aqua) 24%, transparent);
}

/* Rules/reference button variant in the turn-control box. */
.arena-button--reference {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background-color: color-mix(in srgb, var(--gold) 22%, transparent);
}

/* Circular question-mark glyph inside the Rules button. */
.arena-button--reference > span:first-child {
    width: 18px;
    height: 18px;
    display: inline-grid;
    place-items: center;
    border: 1px solid rgba(251, 246, 232, 0.32);
    border-radius: 999px;
    font-size: 0.78em;
    line-height: 1;
}

/* Scrollable battle log list in the turn-control box. */
.event-log {
    width: min(28vw, 360px);
    max-height: min(24dvh, 180px);
    margin: 0;
    padding: 0 4px 0 0;
    display: grid;
    gap: 4px;
    overflow-y: auto;
    overscroll-behavior: contain;
    color: rgba(251, 246, 232, 0.66);
    font-size: 0.76rem;
    line-height: 1.25;
    list-style: none;
}

/* Single battle log entry. */
.event-log li {
    overflow-wrap: anywhere;
    white-space: normal;
}

/* Entries are newest-first; the latest one reads as the current headline. */
.event-log li:first-child {
    color: #fbf6e8;
    font-weight: 740;
}

/* Temporary popup toast shown for action feedback. */
.arena-popup {
    position: fixed;
    left: 50%;
    top: calc(18px + var(--safe-top));
    z-index: 30;
    max-width: min(92vw, 420px);
    transform: translateX(-50%);
    padding: 12px 16px;
    border: 1px solid rgba(251, 246, 232, 0.25);
    border-radius: 8px;
    background: color-mix(in srgb, var(--loc-bg-deep) 96%, transparent);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.36);
    color: #fbf6e8;
    font-weight: 760;
    text-align: center;
}

/* Hides popup toast when inactive. */
.arena-popup[hidden] {
    display: none;
}

/* Full-screen dim layer that centers the battle reference window. */
.rules-reference-overlay {
    position: fixed;
    inset: 0;
    z-index: 2100;
    display: grid;
    place-items: center;
    padding: max(12px, var(--safe-top)) max(12px, var(--safe-right)) max(12px, var(--safe-bottom)) max(12px, var(--safe-left));
    background-color: rgba(5, 13, 16, 0.38);
}

/* Scrollable floating battle reference window opened from the Rules button. */
.rules-reference-window {
    width: min(960px, calc(100vw - 24px));
    max-height: min(760px, calc(100dvh - 24px));
    min-height: 0;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    overflow: hidden;
    border: 1px solid rgba(251, 246, 232, 0.2);
    border-radius: 8px;
    background:
        linear-gradient(180deg, rgba(251, 246, 232, 0.08), rgba(0, 0, 0, 0.16)),
        var(--loc-surface);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.54);
}

/* Header row in the battle reference window. */
.rules-reference-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    padding: clamp(14px, 2.2vw, 22px);
    border-bottom: 1px solid rgba(251, 246, 232, 0.14);
    background-color: rgba(0, 0, 0, 0.18);
}

/* Reference window title. */
.rules-reference-header h2 {
    margin: 0;
    color: #fbf6e8;
    font-size: clamp(1.2rem, 2.4vw, 1.9rem);
    letter-spacing: 0;
}

/* Shared paragraph text inside the reference window. */
.rules-reference-header p,
.rules-reference-copy p,
.rules-reference-lede,
.reference-rule-row p {
    margin: 0;
    color: rgba(251, 246, 232, 0.72);
    line-height: 1.45;
}

/* Close button in the battle reference window. */
.rules-reference-close {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    border: 1px solid rgba(251, 246, 232, 0.26);
    border-radius: 999px;
    background-color: color-mix(in srgb, var(--coral) 24%, transparent);
    color: #fbf6e8;
    font: inherit;
    font-size: 1rem;
    font-weight: 900;
    cursor: pointer;
}

/* Hover/focus state for the reference close button. */
.rules-reference-close:hover,
.rules-reference-close:focus-visible {
    outline: 2px solid color-mix(in srgb, var(--gold) 70%, transparent);
    outline-offset: 2px;
    background-color: color-mix(in srgb, var(--coral) 38%, transparent);
}

/* Run trainer intro and battle-result floating windows. */
.battle-flow-screen {
    grid-row: 1 / -1;
    min-height: calc(100dvh - 20px);
    display: grid;
    place-items: center;
    padding: 18px;
}

.battle-flow-card,
.battle-result-window {
    width: min(360px, calc(100vw - 28px));
    display: grid;
    justify-items: center;
    gap: 14px;
    padding: 20px;
    border: 1px solid rgba(251, 246, 232, 0.22);
    border-radius: 8px;
    background:
        linear-gradient(180deg, rgba(251, 246, 232, 0.08), rgba(0, 0, 0, 0.16)),
        var(--loc-surface);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.48);
    text-align: center;
}

.battle-result-window--victory {
    border-color: var(--gold, #e8c266);
    background:
        linear-gradient(180deg, rgba(232, 194, 102, 0.16), rgba(0, 0, 0, 0.16)),
        var(--loc-surface);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(232, 194, 102, 0.4);
}

.battle-result-window--victory h1 {
    color: var(--gold, #e8c266);
}

.battle-flow-sprite {
    width: 112px;
    height: 112px;
    object-fit: contain;
    image-rendering: pixelated;
}

.battle-flow-copy {
    display: grid;
    gap: 5px;
}

.battle-flow-kicker {
    color: var(--gold);
    font-size: 0.78rem;
    font-weight: 850;
    text-transform: uppercase;
}

.battle-flow-card h1,
.battle-result-window h1 {
    margin: 0;
    color: #fbf6e8;
    font-size: 1.85rem;
    line-height: 1;
    letter-spacing: 0;
    text-transform: none;
}

.battle-flow-card p,
.battle-result-window p {
    margin: 0;
    color: rgba(251, 246, 232, 0.74);
    line-height: 1.4;
}

.battle-result-rewards {
    width: 100%;
    display: grid;
    gap: 7px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.battle-result-rewards li {
    padding: 8px 10px;
    border: 1px solid rgba(251, 246, 232, 0.12);
    border-radius: 6px;
    background-color: rgba(0, 0, 0, 0.16);
    color: #fbf6e8;
    font-size: 0.88rem;
    font-weight: 760;
}

.battle-flow-primary {
    min-width: 160px;
}

.battle-flow-overlay {
    position: fixed;
    inset: 0;
    z-index: 2300;
    display: grid;
    place-items: center;
    padding: max(14px, var(--safe-top)) max(14px, var(--safe-right)) max(14px, var(--safe-bottom)) max(14px, var(--safe-left));
    background-color: rgba(5, 13, 16, 0.62);
}

.battle-flow-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
}

/* --- Pause menu audio controls (phase 100) ----------------------------- */
.battle-audio-controls {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 10px 0;
    border-top: 1px solid rgba(251, 246, 232, 0.14);
    border-bottom: 1px solid rgba(251, 246, 232, 0.14);
}

.battle-audio-volume {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: rgba(251, 246, 232, 0.74);
    font-size: 0.82rem;
}

.battle-audio-volume input[type="range"] {
    width: 120px;
    accent-color: var(--gold);
}

.battle-audio-volume-value {
    min-width: 2ch;
    color: #fbf6e8;
    font-weight: 760;
    text-align: right;
}

/* --- Mega evolution cutscene (phase 48) -------------------------------- */
/* Reuses the battle-flow overlay + battle-result-window look; the baby card
   spins and shines, then swaps to the mega. */
.evolution-window {
    gap: 18px;
}

.evolution-headline {
    min-height: 1.9rem;
}

/* Enlarged card stage; a local --card-w makes the previewed card read big and
   central on both desktop and narrow phones. */
.evolution-stage {
    --card-w: clamp(120px, 34vw, 168px);
    display: grid;
    place-items: center;
    perspective: 900px;
    min-height: calc(var(--card-w) * 1.52 + 16px);
    padding: 8px 0;
}

.evolution-card {
    transform-style: preserve-3d;
    will-change: transform, filter;
}

/* Baby card mid-evolution: a slow rotateY spin with a brightness/glow pulse. */
.evolution-card--spinning {
    animation: evolution-spin 1.9s ease-in-out both;
}

/* Mega card reveal: a brief settle-in pop. */
.evolution-card--revealed {
    animation: evolution-reveal 0.55s ease-out both;
}

@keyframes evolution-spin {
    0% {
        transform: rotateY(0deg) scale(1);
        filter: brightness(1) drop-shadow(0 0 0 rgba(232, 194, 102, 0));
    }
    50% {
        transform: rotateY(540deg) scale(1.08);
        filter: brightness(2.1) drop-shadow(0 0 22px rgba(232, 194, 102, 0.85));
    }
    100% {
        transform: rotateY(1080deg) scale(1);
        filter: brightness(1.35) drop-shadow(0 0 14px rgba(232, 194, 102, 0.5));
    }
}

@keyframes evolution-reveal {
    0% {
        transform: scale(0.7);
        filter: brightness(2) drop-shadow(0 0 24px rgba(232, 194, 102, 0.9));
    }
    60% {
        transform: scale(1.08);
    }
    100% {
        transform: scale(1);
        filter: brightness(1) drop-shadow(0 0 0 rgba(232, 194, 102, 0));
    }
}

@media (prefers-reduced-motion: reduce) {
    .evolution-card--spinning,
    .evolution-card--revealed {
        animation-duration: 0.01ms;
    }
}

/* Scrollable content area inside the reference window. */
.rules-reference-body {
    min-height: 0;
    display: grid;
    gap: clamp(18px, 3vw, 30px);
    padding: clamp(14px, 2.2vw, 22px);
    overflow-y: auto;
}

/* Type/status/stage section wrapper inside the reference window. */
.rules-reference-section {
    display: grid;
    gap: 12px;
    padding-top: clamp(12px, 1.8vw, 18px);
    border-top: 1px solid rgba(251, 246, 232, 0.14);
}

/* Removes top divider from the first reference section. */
.rules-reference-section:first-child {
    padding-top: 0;
    border-top: 0;
}

/* Reference section headings. */
.rules-reference-section h3,
.rules-reference-section h4 {
    margin: 0;
    color: #fbf6e8;
    letter-spacing: 0;
}

/* Primary section heading sizing. */
.rules-reference-section h3 {
    font-size: clamp(1rem, 1.7vw, 1.3rem);
}

/* Secondary subsection heading sizing. */
.rules-reference-section h4 {
    color: rgba(251, 246, 232, 0.86);
    font-size: 0.92rem;
}

/* Stacked explanatory paragraphs inside the reference window. */
.rules-reference-copy {
    display: grid;
    gap: 7px;
}

/* Wrapped list of every type chip in the reference window. */
.reference-type-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
}

/* Shared inline label shell for type and status/effect chips. */
.reference-type-chip,
.reference-status-chip {
    min-width: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: #fbf6e8;
    font-weight: 820;
    line-height: 1.2;
}

/* Individual type chip in the reference window. */
.reference-type-chip {
    padding: 5px 8px;
    border: 1px solid rgba(251, 246, 232, 0.14);
    border-radius: 999px;
    background-color: rgba(0, 0, 0, 0.16);
    font-size: 0.78rem;
}

/* Icon sizing inside reference type/status chips. */
.reference-type-chip .type-icon,
.reference-status-chip .action-status-token {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
}

/* Vertical list of special type/status/effect rules. */
.reference-rule-list {
    display: grid;
    gap: 9px;
}

/* One label-plus-description rule row in the reference window. */
.reference-rule-row {
    display: grid;
    grid-template-columns: minmax(128px, 0.3fr) minmax(0, 1fr);
    gap: 10px;
    align-items: start;
    padding: 9px 0;
    border-top: 1px solid rgba(251, 246, 232, 0.1);
}

/* Avoids a divider before the first rule row in a list. */
.reference-rule-row:first-child {
    border-top: 0;
}

/* Ensures text fallback status chips lay out like image tokens. */
.reference-status-chip .action-status-token {
    display: inline-grid;
}

/* Two-column stat-stage multiplier table. */
.stage-reference-table {
    width: min(100%, 520px);
    display: grid;
    overflow: hidden;
    border: 1px solid rgba(251, 246, 232, 0.14);
    border-radius: 8px;
}

/* Row inside the stat-stage multiplier table. */
.stage-reference-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    border-top: 1px solid rgba(251, 246, 232, 0.1);
}

/* Removes top border from first stat-stage row. */
.stage-reference-row:first-child {
    border-top: 0;
}

/* Table cell spacing for stat-stage rows. */
.stage-reference-row span {
    min-width: 0;
    padding: 8px 10px;
}

/* Column divider inside stat-stage rows. */
.stage-reference-row span + span {
    border-left: 1px solid rgba(251, 246, 232, 0.1);
}

/* Header row inside the stat-stage multiplier table. */
.stage-reference-row--header {
    background-color: rgba(0, 0, 0, 0.2);
    color: #fbf6e8;
    font-weight: 850;
}

/* Wide arena layout and larger card sizing. */
@media (min-width: 1100px) {
    /* Wide card/pile sizing tokens. The dvh terms are sized so both panels
       plus hands fit 100dvh down to ~650px-tall viewports without overlap. */
    .game-page {
        --card-w: clamp(64px, min(7.6vw, 11.8dvh), 128px);
        --hand-card-w: clamp(58px, min(6.4vw, 9.4dvh), 108px);
        --opponent-hand-card-w: clamp(22px, min(2.2vw, 3.6dvh), 36px);
        --pile-card-w: clamp(44px, min(5.3vw, 6.4dvh), 92px);
        --panel-gap: clamp(8px, 1vw, 14px);
    }

    /* Wide arena grid: left-side controls plus the opponent/player board. */
    .game-board {
        position: relative;
        height: 100dvh;
        min-height: 0;
        grid-template-columns: clamp(300px, 31vw, 380px) minmax(0, 1fr);
        grid-template-rows: repeat(2, minmax(0, 1fr));
        padding: max(12px, var(--safe-top)) max(16px, var(--safe-right)) max(16px, var(--safe-bottom)) max(16px, var(--safe-left));
    }

    /* Wide side-panel spacing and clipping. */
    .side-panel {
        gap: clamp(8px, 1vw, 12px);
        padding: clamp(10px, 1.1vw, 16px);
        overflow: hidden;
    }

    /* Wide placement for opponent panel. */
    .side-panel--opponent {
        grid-column: 2;
        grid-row: 1;
    }

    /* Wide placement for player panel mirroring the opponent column. */
    .side-panel--player {
        grid-column: 2;
        grid-row: 2;
    }

    /* Wide board row: both pile pairs sit to the left of the active slots —
       decks in the outer column, discard/KO just inside them. The pile columns
       are sized to the card itself rather than a fraction of the row, so the
       four piles read as one group and the slots keep the leftover width. */
    .battle-row {
        grid-template-columns:
            var(--pile-card-w)
            var(--pile-card-w)
            minmax(160px, 1fr);
    }

    .pile--discard,
    .pile--knockout {
        grid-column: 2;
    }

    .played-slots {
        grid-column: 3;
    }

    .side-panel--opponent .side-status {
        padding-left: 0;
    }

    /* Counters keep their size; a long trainer name truncates instead.
       Wide-only: narrow layouts need the pill group to wrap and shrink. */
    .side-status .side-stats {
        flex-shrink: 0;
    }

    /* Wide turn-control box fills the left column so it can never bleed
       over the player panel at short heights and the log gets the leftover.
       Rows run turn header, selected card, log, then the button bar last so the
       commands sit along the bottom edge of the box. */
    .arena-status {
        position: static;
        grid-column: 1;
        grid-row: 1 / -1;
        align-self: stretch;
        justify-self: stretch;
        z-index: 25;
        width: auto;
        min-width: 0;
        min-height: 0;
        display: grid;
        grid-template-columns: auto 1fr;
        grid-template-rows: auto auto minmax(0, 1fr) auto;
        gap: 8px 10px;
        align-items: center;
        padding: 12px;
        border: 1px solid rgba(251, 246, 232, 0.18);
        border-radius: 8px;
        background:
            linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.18)),
            rgba(13, 32, 34, 0.94);
        box-shadow: 0 18px 38px rgba(0, 0, 0, 0.34);
    }

    /* Turn label and instruction share the top row of the control box. */
    .turn-pill {
        grid-row: 1;
        grid-column: 1;
    }

    /* Allows wide turn text to shrink inside the control box. */
    .turn-copy {
        grid-row: 1;
        grid-column: 2;
        min-width: 0;
    }

    /* Wide turn instruction size. */
    .turn-copy p {
        font-size: clamp(0.84rem, 1vw, 1rem);
    }

    /* Wide selected-card pill spans the control box. */
    .selected-pill {
        grid-column: 1 / -1;
        grid-row: 2;
        width: 100%;
        min-width: 0;
        justify-content: center;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Wide action buttons stretch evenly along the bottom of the control box. */
    .action-bar {
        grid-column: 1 / -1;
        grid-row: 4;
        align-self: end;
        justify-content: stretch;
    }

    /* Wide action button sizing: buttons share a row evenly but never shrink
       below their label, so a full command bar wraps to a second row instead of
       overlapping itself. */
    .arena-button {
        flex: 1 1 0;
        min-width: max-content;
        font-size: clamp(0.9rem, 0.95vw, 1rem);
    }

    /* Wide event log fills the control box width and all leftover height,
       sitting between the turn header and the bottom button bar. */
    .event-log {
        grid-column: 1 / -1;
        grid-row: 3;
        align-self: stretch;
        width: 100%;
        min-height: 0;
        max-height: none;
        font-size: 0.86rem;
    }

    /* Wide card interior spacing. */
    .playing-card {
        gap: 3px;
        padding: clamp(5px, 0.58vw, 8px);
    }

    /* Wide board slot sizing around larger active cards. */
    .board-slot {
        min-width: calc(var(--card-w) + 18px);
        min-height: calc(var(--card-h) + 16px);
        padding: 8px;
    }

    /* Wide ready badge sizing. */
    .slot-badge {
        right: 4px;
        top: 4px;
        padding: 3px 7px;
        font-size: 0.7rem;
    }

    /* Wide pile/hand label sizing. */
    .pile-label,
    .hand-label {
        font-size: 0.84rem;
    }

    /* Wide Pokemon name sizing. */
    .card-name {
        font-size: 0.68rem;
    }

    /* Wide Pokemon health/stat text sizing. */
    .health-row,
    .stat-grid {
        font-size: 0.58rem;
    }

    /* Wide card-back label sizing. */
    .card-topline,
    .card-footer {
        font-size: 0.72rem;
    }

    /* Wide base type icon sizing. */
    .type-icon {
        width: clamp(14px, calc(var(--card-w) * 0.16), 22px);
        height: clamp(14px, calc(var(--card-w) * 0.16), 22px);
    }

    /* Wide action-card type icon sizing. */
    .action-type-row .type-icon {
        width: clamp(20px, calc(var(--card-w) * 0.3), 38px);
        height: clamp(20px, calc(var(--card-w) * 0.3), 38px);
    }

    /* Wide persistent status token sizing. */
    .status-token {
        width: clamp(20px, calc(var(--card-w) * 0.21), 28px);
        height: clamp(20px, calc(var(--card-w) * 0.21), 28px);
    }

    /* Wide toast sits top-left over the control box's header, clear of every
       card and of the command bar now anchored to the box's bottom edge. */
    .arena-popup {
        top: calc(18px + var(--safe-top));
        bottom: auto;
        left: calc(18px + var(--safe-left));
        right: auto;
        transform: none;
        max-width: min(30vw, 420px);
    }

    /* Pile viewer opens over the control column instead of across the board. */
    .pile-window {
        left: max(clamp(10px, 2.4vw, 28px), var(--safe-left));
        right: auto;
    }

    /* Wide action-card name sizing. */
    .action-card-name {
        font-size: 0.58rem;
    }

    /* Wide action-card target sizing. */
    .action-card-meta {
        font-size: 0.38rem;
    }
}

/* Short wide viewports: clamp cards further down so both panels fit 100dvh
   without board rows spilling over headers or hands. */
@media (min-width: 1100px) and (max-height: 720px) {
    .game-page {
        --card-w: clamp(52px, min(7vw, 11.5dvh), 96px);
        --hand-card-w: clamp(44px, min(5.8vw, 8.4dvh), 84px);
        --opponent-hand-card-w: clamp(18px, min(2vw, 3.4dvh), 28px);
        --pile-card-w: clamp(34px, min(4.6vw, 6.6dvh), 64px);
        --panel-gap: 6px;
    }

    .game-board {
        padding: max(8px, var(--safe-top)) max(12px, var(--safe-right)) max(10px, var(--safe-bottom)) max(12px, var(--safe-left));
    }

    .side-panel {
        gap: 6px;
        padding: 8px;
    }

    /* Card interiors track the smaller cards so text never overlaps. */
    .playing-card {
        gap: 1px;
        padding: 4px;
    }

    .card-portrait {
        width: calc(var(--card-w) * 0.58);
    }

    .card-name {
        font-size: 0.5rem;
    }

    .health-row,
    .stat-grid {
        font-size: 0.46rem;
    }

    .card-topline,
    .card-footer {
        font-size: 0.6rem;
    }
}

/* Stacked arena layout and compact card sizing for phones and tablets. */
@media (max-width: 1099px) {
    /* Compact card/pile sizing tokens. */
    .game-page {
        --card-w: clamp(46px, min(16vw, 9.4dvh), 68px);
        --hand-card-w: clamp(38px, min(11.5vw, 8dvh), 52px);
        --opponent-hand-card-w: clamp(20px, min(6vw, 4.6dvh), 28px);
        --pile-card-w: clamp(38px, min(12vw, 7.4dvh), 52px);
        --panel-gap: 8px;
    }

    /* Compact arena stacks opponent, controls, and player vertically. */
    .game-board {
        padding: max(10px, var(--safe-top)) max(8px, var(--safe-right)) max(10px, var(--safe-bottom)) max(8px, var(--safe-left));
        grid-template-rows: auto auto auto;
    }

    /* Compact side-panel spacing. */
    .side-panel {
        padding: 8px;
        gap: 7px;
    }

    /* Compact side-header alignment for wrapped counters. */
    .side-status {
        align-items: flex-start;
        gap: 6px;
    }

    /* Compact counter spacing. */
    .side-stats {
        gap: 4px;
    }

    /* Compact pill sizing for counters, turn, and selection text. */
    .stat-pill,
    .turn-pill,
    .selected-pill {
        min-height: 22px;
        padding: 3px 6px;
        font-size: 0.68rem;
    }

    /* Compact board row with stacked pile columns. */
    .battle-row {
        grid-template-columns: minmax(var(--pile-card-w), 0.24fr) minmax(116px, 1fr) minmax(var(--pile-card-w), 0.24fr);
        gap: 6px;
    }

    /* Compact active-slot spacing. */
    .played-slots {
        gap: 6px;
    }

    /* Compact board slot sizing around small cards. */
    .board-slot {
        min-width: calc(var(--card-w) + 8px);
        min-height: calc(var(--card-h) + 10px);
        padding: 4px;
    }

    /* Compact pile/hand label sizing. */
    .pile-label,
    .hand-label {
        font-size: 0.62rem;
    }

    /* Compact hand row spacing. */
    .hand-row {
        min-height: calc(var(--hand-card-h) + 12px);
        gap: 6px;
    }

    /* Compact hand card strip spacing; fade the edges so off-screen hand
       cards read as horizontally scrollable. */
    .hand-cards {
        gap: 6px;
        padding: 5px 3px;
        -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
        mask-image: linear-gradient(90deg, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
    }

    /* Compact turn-control box stacked into one column; pills keep their
       natural width instead of stretching into full-width bars. */
    .arena-status {
        min-height: 0;
        display: grid;
        grid-template-columns: 1fr;
        justify-items: center;
        gap: 8px;
        padding: 9px;
    }

    /* Compact turn text centered under the turn pill. */
    .turn-copy {
        min-width: 0;
        text-align: center;
    }

    /* Compact action buttons centered. */
    .action-bar {
        justify-content: center;
    }

    /* Compact action button sizing. */
    .arena-button {
        min-height: 34px;
        padding: 7px 9px;
        font-size: 0.78rem;
    }

    /* Compact log uses the full control width with a shorter scroll window. */
    .event-log {
        width: 100%;
        max-height: 108px;
        font-size: 0.72rem;
    }

    /* Compact reference overlay safe padding. */
    .rules-reference-overlay {
        padding: 8px;
    }

    /* Compact reference window fills available viewport width/height. */
    .rules-reference-window {
        width: calc(100vw - 16px);
        max-height: calc(100dvh - 16px);
    }

    /* Compact reference header spacing. */
    .rules-reference-header {
        align-items: center;
        padding: 12px;
    }

    /* Compact reference content spacing. */
    .rules-reference-body {
        padding: 12px;
    }

    /* Compact reference rule rows stack label above description. */
    .reference-rule-row {
        grid-template-columns: 1fr;
        gap: 6px;
    }

    /* Compact type-chip grid spacing. */
    .reference-type-grid {
        gap: 6px;
    }

    /* Compact reference type chip sizing. */
    .reference-type-chip {
        padding: 4px 7px;
        font-size: 0.72rem;
    }

    /* Compact Pokemon stat text sizing. */
    .stat-grid {
        font-size: 0.46rem;
    }

    /* Compact type icon sizing. */
    .type-icon {
        width: 10px;
        height: 10px;
    }

    /* Compact overview page spacing. */
    .card-overview,
    .achievements {
        padding: calc(68px + var(--safe-top)) max(8px, var(--safe-right)) max(28px, var(--safe-bottom)) max(8px, var(--safe-left));
    }

    /* Compact achievements grid collapses to one column. */
    .achievements-list {
        grid-template-columns: 1fr;
    }

    /* Compact overview header stacks title and filters. */
    .overview-header {
        align-items: flex-start;
        flex-direction: column;
        gap: 12px;
    }

    /* Compact overview card grid uses three columns. */
    .overview-card-grid {
        grid-template-columns: repeat(3, var(--card-w));
        gap: 10px;
    }
}

/* Roomier compact cards once the viewport has moved past narrow phone widths. */
@media (min-width: 501px) and (max-width: 1099px) {
    .game-page {
        --card-w: clamp(68px, min(13vw, 10.5dvh), 78px);
        --hand-card-w: clamp(52px, min(9.5vw, 8.4dvh), 62px);
        --opponent-hand-card-w: clamp(22px, min(5vw, 4.8dvh), 32px);
        --pile-card-w: clamp(52px, min(9vw, 7.8dvh), 58px);
        --panel-gap: clamp(8px, 1vw, 12px);
    }

    .board-slot {
        min-width: calc(var(--card-w) + 12px);
        min-height: calc(var(--card-h) + 12px);
        padding: 5px;
    }
}

/* Phone overview grid fits four cards per row across the full width. */
@media (max-width: 500px) {
    /* Overview cards are sized from the space the page actually has: the
       viewport less the page padding and the three gaps between four columns.
       Every card internal is derived from --card-w, so widening the card
       scales its art and text with it instead of leaving dead margins. */
    .card-overview-page {
        --card-w: calc((100vw - max(8px, var(--safe-left)) - max(8px, var(--safe-right)) - 24px) / 4);
    }

    .overview-card-grid {
        grid-template-columns: repeat(4, var(--card-w));
        gap: 8px;
    }

    /* Cards this wide have room for the full-size card text again, so the
       compact overrides used on the cramped battle board are lifted here. */
    .card-overview-page .card-name {
        font-size: 0.56rem;
    }

    .card-overview-page .health-row,
    .card-overview-page .stat-grid {
        font-size: 0.5rem;
    }

    .card-overview-page .action-card-name {
        font-size: 0.5rem;
    }

    .card-overview-page .attack-power,
    .card-overview-page .action-stat-change,
    .card-overview-page .action-card-meta {
        font-size: 0.44rem;
    }

    .card-overview-page .type-icon {
        width: clamp(10px, calc(var(--card-w) * 0.15), 16px);
        height: clamp(10px, calc(var(--card-w) * 0.15), 16px);
    }
}

/* Extra-tight card internals for narrow phones. */
@media (max-width: 380px) {
    .playing-card {
        padding: 3px;
    }

    .board-card {
        border-width: 1px;
    }

    .card-name {
        font-size: 0.48rem;
    }

    .health-row,
    .stat-grid {
        font-size: 0.44rem;
    }

    .stat-grid {
        gap: 1px;
    }

    .action-card-shell {
        gap: 1px;
    }

    .action-card-name {
        font-size: 0.44rem;
    }

    .item-picture-row {
        min-height: 22px;
    }

    .item-picture {
        width: 23px;
        height: 23px;
    }

    .action-type-row .type-icon {
        width: 12px;
        height: 12px;
    }

    .action-card-effects {
        min-height: 10px;
        gap: 1px;
    }

    .attack-power,
    .action-stat-change,
    .action-card-meta {
        font-size: 0.36rem;
    }

    .action-status-token {
        width: 10px;
        height: 10px;
    }
}

/* Mid-width overview grid uses four columns. */
@media (min-width: 700px) and (max-width: 980px) {
    /* Prevents overview cards from crowding at tablet widths. */
    .overview-card-grid {
        grid-template-columns: repeat(4, var(--card-w));
    }
}
