/* Mobile baseline.
 *
 * The game is built for landscape: the battlefield is a 16:9 arena and the
 * hex map is a wide block, so a phone held sideways is the target shape.
 *
 * Everything here is scoped to `--compact`, a media query for viewports that
 * are either narrow or short (a landscape phone is short, not narrow — 844x390
 * — so width alone would miss it). Desktop layout is deliberately untouched.
 *
 * The filename starts with z on purpose. `stylesheet_link_tag :app` emits one
 * <link> per stylesheet in alphabetical order, so a file named mobile.css was
 * overridden by everything after it in the alphabet — sidebar, storage,
 * prog_bars, world — and rules here silently did nothing at equal
 * specificity. Sorting last makes these overrides land without each one
 * needing an extra class to outrank its target.
 */

:root {
    /* Chrome above and below the battlefield (turn log, message window) that
       the arena has to leave room for when height is what binds. */
    --battle-chrome: 96px;
    /* Height the fixed move bar takes off the arena on a phone. */
    --battle-move-bar: 7.5rem;
    --touch-target: 44px;
    /* The move buttons sit on the arena and there are four of them: at the
       full 44px they cost the arena 56px for 16px of text, and the names are
       one truncated line either way. Still a comfortable target. */
    --touch-target-move: 20px;
}

@media (max-width: 1100px), (max-height: 560px) {
    /* Press Start 2P at 16px is the single biggest space consumer on a phone.
       Scaling html and body together keeps rem-based (Bulma, our own spacing)
       and inherited px-based text in step. */
    html,
    body {
        font-size: clamp(9px, 0.6rem + 0.6vmin, 16px);
    }

    /* Pinned to the viewport, so they have to dodge the notch and the home
       indicator themselves once the page draws under them. */
    .bottom-nav {
        right: max(0.5rem, env(safe-area-inset-right));
        bottom: max(0.5rem, env(safe-area-inset-bottom));
    }

    .message-window {
        left: max(0.5rem, env(safe-area-inset-left));
        bottom: max(0.5rem, env(safe-area-inset-bottom));
        width: min(280px, 55vw);
    }

    /* A finger is not a mouse pointer: every control the game asks you to hit
       during a battle gets a real target. */
    .switch-option,
    .nes-tab,
    .profile__links .nes-btn {
        min-height: var(--touch-target);
    }

    .move-slot .nes-btn {
        min-height: var(--touch-target-move);
    }

    .move-grid {
        grid-auto-rows: minmax(var(--touch-target-move), auto);
    }

    /* NES containers are 1.5rem/2rem of padding each, and the game nests them
       two and three deep (a panel inside a panel inside the screen). On a
       short viewport that padding is the difference between a screen that
       fits and one you have to scroll. */
    .nes-container {
        padding: 0.75rem 1rem;
    }

    .nes-container.with-title > .title {
        margin-top: -1.4rem;
        margin-bottom: 0.6rem;
    }

    /* Bulma's heading sizes are absolute rem values, so they do not follow the
       scaled body text and end up dominating a short screen. */
    .title {
        font-size: 1.15rem;
    }

    .subtitle {
        font-size: 0.9rem;
    }

    /* Storage: shorter slots (and icons to match) fit more of a box on screen
       before scrolling — 64 slots at the desktop height is five viewports. */
    .storage-box-grid .storage-slot {
        height: 56px;
    }

    .storage-box-grid .storage-slot .species-icon {
        width: 32px;
        height: 32px;
    }

    /* Bulma's mt-4 is 1.5rem — a fifth of the room a post-battle screen has
       to work with, spent above the panel. */
    .container.mt-4,
    .capture-review.mt-4 {
        margin-top: 0.5rem !important;
    }

    /* Capture review and the win screen have to be decided at a glance, not
       scrolled. The sprite is the biggest block on them and is decorative —
       the numbers beside it are what the choice is made on. `zoom` rather
       than `transform` because only zoom takes the layout box with it. */
    .capture-review .selectable-character {
        zoom: 0.6;
    }

    /* Six stat rows at default table spacing is most of a phone screen. The
       row height comes from the badge: nes.css gives each 0.5em of margin all
       round, which over six rows is taller than the sprite beside them. */
    .capture-review td,
    .character-stats td {
        padding: 0 0.25rem;
        line-height: 1.15;
    }

    .capture-review .nes-badge,
    .character-stats .nes-badge {
        height: 1.6em;
        margin: 0.12em 0.4em;
    }

    /* Bulma's .columns wraps each button row in its own margins; on a screen
       this short they are two rows of whitespace. */
    .capture-review .columns:last-child {
        margin-top: 0;
        margin-bottom: 0;
    }

    /* The type badge and the ability/item lines, which sit between the sprite
       and the buttons. */
    .capture-review p.mb-2 {
        margin-bottom: 0.15rem !important;
    }

    /* The decision buttons do not need to be full-height rows of their own. */
    .capture-review .columns:last-child .column {
        padding-top: 0;
        padding-bottom: 0;
    }

    .capture-review .nes-btn.mt-2 {
        margin-top: 0.25rem !important;
    }

    /* --- World: the map has to fit the screen, not the other way round --- */

    /* The hex grid is width-driven and roughly 1.2:1, so on a short screen the
       width has to come from the height that is actually available or the map
       runs off the bottom. */
    #hexGrid {
        width: 100%;
        max-width: calc((100dvh - 3rem) * 1.2);
    }

    /* Bulma pads .container.is-fluid by 32px a side; on an 844px screen that
       is 8% of the map's width spent on nothing. */
    .world-map .container.is-fluid {
        padding-left: 0;
        padding-right: 0;
    }

    /* 350px of status text on an 844px-wide screen sat on top of the map. It
       stays out of flow on purpose — as a flex sibling it competed with the
       map for width and squeezed it to under half the screen — but shrinks to
       the one line it needs, in the corner the map does not reach. */
    .world-layout .world-status-panel {
        top: 0;
        width: auto;
        max-width: 45vw;
        font-size: 0.8em;
        text-align: right;
    }

}

/* Short viewports only — a landscape phone. This is where the battle screen
   is restructured: it is vertical room the arena is short of, so a tablet at
   1024x768 keeps the desktop layout even though it matches the query above. */
@media (max-height: 560px) {
    :root {
        /* The arena fills the height here — the moves overlay it rather than
           sitting below it — so the allowance is the turn timer above it plus
           the page's own margins. */
        --battle-chrome: 30px;
        /* The column of free space beside the arena that the turn log lives
           in. A 16:9 arena at full height leaves this much of the width over;
           in px because the scaled root font would make a rem value far too
           narrow to read a sentence in. */
        --battle-log-width: 104px;
    }

    /* --- World: the map is the game, so it gets the screen ---------------

       Five hex rows in 390px of height can only ever be ~70px tiles: the row
       count is what caps them. Dropping the outermost row above and below the
       team leaves a wide 3-row strip — the shape a landscape screen actually
       is — and the height that frees goes straight into tile size (~70px to
       ~135px). The team keeps every neighbour it can move to in view.

       Scoped to .world-map so the whole-floor overview (/floor, which renders
       the same component at a much larger range) is untouched. The nth-child
       arithmetic is the component's own: 5 cells per row at the default
       range, and hidden cells still count for the even-row indent rules. */
    .world-map #hexGrid .hex:nth-child(-n+5),
    .world-map #hexGrid .hex:nth-child(n+21) {
        display: none;
    }

    .world-map #hexGrid {
        /* Three rows instead of five: nearly twice as wide for the same height. */
        max-width: calc((100dvh - 2rem) * 1.95);
    }

    /* The team panel is a strip beside the map. The map is bound by height
       rather than width here, so the few px this costs come out of empty
       space rather than out of the map. */
    .world-sidebar {
        width: 84px;
    }

    /* Six members stacked icon-over-bar is ~470px of strip on a 390px screen,
       so the last of the party fell off the bottom. Side by side, a member
       costs one row instead of two. */
    /* Scoped under .world-sidebar: sidebar.css loads after this file, so at
       equal specificity its column layout would win (see the load-order note
       at the top). */
    .world-sidebar .sidebar-mini {
        gap: 4px;
    }

    .world-sidebar .sidebar-mini__char {
        flex-direction: row;
        align-items: center;
        gap: 4px;
    }

    /* The icons are 40x30 pixel art: at their own size they neither stretch
       nor blur, and object-fit keeps that true for any that differ. */
    .world-sidebar .sidebar-mini__char img {
        flex: none;
        width: 40px;
        height: 30px;
        object-fit: contain;
    }

    .world-sidebar .sidebar-mini .nes-progress {
        height: 10px;
        border-width: 2px;
    }

    /* A full party is six cells in three columns — two rows, and the second
       row is what pushes the dismiss button off a landscape screen. The
       sprite gives up what it can; the HP row is gone from the component
       itself, and the bar now sits under the sprite rather than beside it. */
    .team-gains .character-frame-front {
        height: 104px;
        zoom: 0.85;
    }

    /* A long name should not push its cell's bar out of line with the rest of
       the row. */
    .team-gains .cell > strong {
        display: block;
        font-size: 0.8em;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .team-gains small {
        font-size: 0.75em;
    }

    /* --- Evolution: the choice has to be on screen with the sprite --------
       A 400px stage is taller than the whole viewport here, so the question
       and its buttons sat below the fold. Side by side instead: the sprite
       takes the left, the question and the buttons the right. */
    .evolution-panel {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0 1rem;
    }

    .evolution-panel > .title {
        flex: 1 0 100%;
    }

    .evolution-panel > .evolution-stage {
        flex: 1 1 45%;
        height: 60dvh;
        margin: 0;
    }

    .evolution-panel > [data-evolution-target="prompt"],
    .evolution-panel > .evolution-status {
        flex: 1 1 45%;
    }

    /* The sprites are rendered at a fixed scale of 4; zoom takes the layout
       box with it so the stage can be this short. */
    .evolution-sprite .pokemon-sprite {
        zoom: 0.8;
    }

    /* --- Eggs -------------------------------------------------------------
       The hatch stage is 300px of a 390px screen, which puts "Hatch it" and
       the way out to storage below the fold. The stage is sized from the
       viewport instead, and the egg (a fixed --egg-scale of 6 set inline by
       the helper, so `zoom` rather than the variable) shrinks with it. The
       same for the reveal, whose hatchling sprite is fixed pixels too. */
    .egg-stage {
        height: 38dvh;
        margin: 0.25rem auto;
    }

    .egg-stage .egg-sprite {
        zoom: 0.55;
    }

    .egg-reveal {
        min-height: 30dvh;
    }

    /* Sized for the biggest hatchlings: sprite heights vary by species (a
       Ting-Lu is more than twice a Cosmog), and the Continue button has to
       stay on screen whichever comes out. */
    .egg-reveal .pokemon-sprite {
        zoom: 0.4;
    }

    /* The message window is pinned bottom-left and the nav menu bottom-right,
       so a button in the bottom-left corner of the page ends up underneath
       one of them. Down the middle is the only clear lane. */
    .battle-actions {
        position: relative;
        top: -20px;
        text-align: center;
    }

    /* Bulma only turns .columns into a flex row from 769px up, so a landscape
       phone narrower than that (an SE is 667) stacks every column — the one
       layout a wide, short screen cannot afford. Short viewports get what
       Bulma's .is-mobile would give them. */
    .columns {
        display: flex;
    }

    /* Bulma's width classes live in that same 769px block, so without these
       a flexed column shrinks to whatever its content will allow — which put
       the capture screen's team grid in a 52px-wide column. These are the
       four the app uses; Bulma's .is-mobile defines the rest the same way. */
    .columns > .column.is-narrow {
        flex: none;
        width: unset;
    }

    .columns > .column.is-one-third {
        flex: none;
        width: 33.3333%;
    }

    .columns > .column.is-one-half,
    .columns > .column.is-half {
        flex: none;
        width: 50%;
    }

    /* 0.75rem of gutter on each column, on a screen with none to spare.
       Bulma drives the column padding and the row's matching negative margin
       from this one variable — setting the padding alone leaves the margins
       wider than the padding, and content hangs into the gutter. */
    .columns {
        --bulma-column-gap: 0.4rem;
    }

    /* --- Battle: the arena is the screen ---------------------------------

       The arena fills the height and the controls overlay it, rather than the
       arena giving up a third of the screen to a bar beneath it. What is left
       either side of a 16:9 arena is where the turn log goes. */

    /* Back inside the arena, over the bottom-right corner, under the player's
       name and health. Smaller, and without the "Moves" title — on a phone
       the four buttons are self-evident. */
    .combat-character-player .move-panel {
        position: static;
        margin: 0;
        padding: 0.25rem 0.3rem;
        background: rgba(0, 0, 0, 0.72);
    }

    .move-panel.nes-container.with-title > .title {
        display: none;
    }

    .move-grid {
        gap: 3px;
    }

    /* The name/health panel on one line fewer: the bar takes half the width
       and the numbers and status badge sit beside it rather than under it.
       The title stays on its own row (flex-basis 100%). */
    .combat-panel > section {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 0 6px;
    }

    .combat-panel > section > .title {
        flex: 1 0 100%;
    }

    .combat-panel > section > .nes-progress {
        flex: 1 1 50%;
        height: 12px;
    }

    .combat-panel > section > span {
        flex: 0 1 auto;
        font-size: 0.7em;
        white-space: nowrap;
    }

    /* Wide enough that a move name is not truncated to "SLUDGE...", narrow
       enough to leave the pokemon it belongs to visible beside it. */
    .combat-character-player .combat-panel {
        width: 50%;
        bottom: 1%;
    }

    .combat-character-enemy .combat-panel {
        width: 50%;
    }

    /* Knowing which move it is beats knowing how much pp is left — and the
       long-press tooltip carries both anyway. */
    .move-slot .move-pp {
        font-size: 0.5rem;
    }

    /* The name is one line whatever happens, so the button only needs room
       for one line: a smaller face, no vertical padding, and the text sitting
       in the middle of what is left. */
    .move-slot .nes-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 0.5rem;
        line-height: 1;
        padding: 0 3px;
    }

    /* 37px of turn timer above a 342px arena is a tenth of the screen for a
       progress bar. */
    .timer-container {
        height: 14px;
        margin-top: 0;
    }

    /* Narrower bench cards leave the width for the arena. */
    .switch-panel .switch-option .nes-btn {
        padding: 6px 8px;
    }

    .battle-layout {
        /* Room for the log column, which is fixed and out of flow. */
        padding-left: var(--battle-log-width);
        padding-bottom: 0;
    }

    /* The switch list beside the arena is a column of bench cards, and with
       six of them it is taller than the arena — which made it, not the
       arena, decide the height of the screen. Same budget as the arena, and
       it scrolls within that. */
    .battle-layout > turbo-frame {
        max-height: calc(100dvh - var(--battle-chrome));
        overflow-y: auto;
    }

    /* Widens the log; sized for a finger in its own right, not from the move
       buttons, which are tapped every turn and can afford to be small. */
    .battle-log__toggle {
        display: flex;
        align-items: center;
        justify-content: center;
        min-width: 28px;
        min-height: 28px;
        font-size: 0.7rem;
        background: rgba(0, 0, 0, 0.72);
    }

    /* Half the screen: a long turn ("X used Y! It's super effective! Z was
       hurt by its burn!") reads in a few lines instead of a dozen, without
       scrolling a panel that takes no pointer events anyway. It covers part
       of the arena while open, which is the trade the player is asking for. */
    /* Two classes deliberately: the .battle-log rule below sets the column
       width, and at equal specificity whichever comes last would win. */
    .battle-log.battle-log--expanded {
        width: 50vw;
        background: rgba(0, 0, 0, 0.85);
    }

    /* » to open, « to close. */
    .battle-log.battle-log--expanded .battle-log__toggle {
        transform: scaleX(-1);
    }

    /* Down the free strip to the left of the arena rather than across it: a
       16:9 arena at full height cannot use the whole width, and the log would
       rather be read than dodged. Still takes no pointer events, so nothing
       it covers becomes untappable. */
    .battle-log {
        position: fixed;
        top: 0;
        left: 0;
        right: auto;
        z-index: 30;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        /* A little narrower than the space reserved for it, so it never
           creeps onto the arena's edge. */
        width: calc(var(--battle-log-width) - 10px);
        max-height: none;
        /* Clear of the message window, which is pinned to this same corner. */
        bottom: 2.4rem;
        margin: 0;
        padding: 0.35rem;
        overflow: hidden;
        font-size: 0.8em;
        line-height: 1.35;
        pointer-events: none;
        background: transparent;
    }

}

/* Nothing here should force a page taller than the screen. */
body.environment-battle {
    min-height: 100dvh;
}

/* --- Dev device harness (DevController#devices, local only) -------------- */

.dev-harness {
    padding: 1rem;
}

.dev-harness__controls {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 1rem;
}

.dev-harness__controls .nes-input {
    flex: 1;
    max-width: 40rem;
}

.dev-harness__devices {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
}

.dev-harness__device figcaption {
    padding-bottom: 0.35rem;
    font-size: 0.6rem;
}

.dev-harness__device iframe {
    background: #000;
    border: 4px solid #666;
}

/* Under 400dp of height: an SE held sideways (375), and any phone inside the
   native shell, where the tab bar takes another 48dp off an already short
   screen (390 - 48 = 342). The sprites give up the difference — on the win
   screen that is 13dp a row, which is what keeps a full party's second row
   and the dismiss button on screen. */
@media (max-height: 400px) {
    .capture-review .selectable-character {
        zoom: 0.45;
    }

    .team-gains .character-frame-front {
        height: 88px;
    }
}

/* --- Portrait interstitial ----------------------------------------------
   The battle arena is 16:9 and the hex map is a wide block, so both are only
   playable sideways. There is no reliable way to force orientation on the
   web (screen.orientation.lock() requires fullscreen and iOS Safari has no
   such API), so on a portrait phone those screens ask instead. The PWA
   manifest requests landscape for installed apps; the native shell will
   enforce it for real. */

.rotate-prompt {
    display: none;
}

@media (orientation: portrait) and (max-width: 900px) {
    body.requires-landscape .rotate-prompt {
        position: fixed;
        inset: 0;
        z-index: 5000;
        display: flex;
        flex-direction: column;
        gap: 1.5rem;
        align-items: center;
        justify-content: center;
        padding: 2rem;
        text-align: center;
        background: var(--bulma-body-background-color, #101010);
    }
}

.rotate-prompt__device {
    width: 3rem;
    height: 5rem;
    border: 0.35rem solid currentColor;
    animation: rotate-hint 2.6s ease-in-out infinite;
}

.rotate-prompt__text {
    max-width: 18rem;
    line-height: 1.6;
}

@keyframes rotate-hint {
    0%, 35% { transform: rotate(0deg); }
    55%, 100% { transform: rotate(-90deg); }
}

@media (prefers-reduced-motion: reduce) {
    .rotate-prompt__device {
        animation: none;
        transform: rotate(-90deg);
    }
}
