[x-cloak] {
    display: none !important;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html,
body {
    height: 100%;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: #141a2b;
    color: #f4f1ea;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* The board is a square sized by whichever runs out first: the viewport
   width, or the viewport height less the room the header strip needs. */
#game-wrapper {
    --page-pad: 12px;
    --hud-allowance: 160px;
    --board-max: 600px;
    --board-size: min(100vw - 2 * var(--page-pad), 100vh - var(--hud-allowance), var(--board-max));
    --board-size: min(100vw - 2 * var(--page-pad), 100dvh - var(--hud-allowance), var(--board-max));
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: var(--page-pad);
}

#hud {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    width: var(--board-size);
}

#hud h1 {
    font-size: 28px;
    letter-spacing: 1px;
}

.scores {
    display: flex;
    gap: 8px;
}

.score-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 88px;
    padding: 6px 12px;
    border-radius: 8px;
    background: #2a3350;
}

.score-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    opacity: 0.75;
}

.score-value {
    font-size: 20px;
    font-weight: 700;
}

#hud button,
.overlay button {
    font: inherit;
    font-size: 16px;
    font-weight: 700;
    padding: 12px 24px;
    min-height: 44px;
    border: 0;
    border-radius: 8px;
    background: #f2b134;
    color: #2b1d0e;
    cursor: pointer;
    text-shadow: none;
}

#hud button {
    padding: 8px 16px;
    min-height: 36px;
    font-size: 14px;
}

#hud button:hover,
.overlay button:hover {
    background: #ffc857;
}

/* Board */

/* Cell size and stride derive from the board size, so no script measures
   the board and no resize listener is needed. Container query units would
   also do, but Firefox resolves them to zero inside transform. */
#board {
    --gap: clamp(6px, 2vmin, 12px);
    --cell-size: calc((var(--board-size) - 5 * var(--gap)) / 4);
    --stride: calc(var(--cell-size) + var(--gap));
    position: relative;
    width: var(--board-size);
    aspect-ratio: 1;
    padding: var(--gap);
    border-radius: 10px;
    background: #2a3350;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.cells {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-template-rows: repeat(4, 1fr);
    gap: var(--gap);
    width: 100%;
    height: 100%;
}

.cell {
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.08);
}

/* A tile sits at the origin and is placed by its --row and --col. */
.tiles {
    position: absolute;
    inset: var(--gap);
}

.tile {
    position: absolute;
    top: 0;
    left: 0;
    width: var(--cell-size);
    height: var(--cell-size);
    transform: translate(calc(var(--col) * var(--stride)), calc(var(--row) * var(--stride)));
    transition: transform var(--slide-duration) ease-in-out;
    border-radius: 8px;
}

.tile .face {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    border-radius: inherit;
    background: #f4f1ea;
}

/* A dragged image would cancel the pointer sequence a swipe relies on. */
.tile img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
    -webkit-user-drag: none;
}

/* A paper-white crop needs an edge to read as a tile on the board. */
.tile .face::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    box-shadow: inset 0 0 0 2px rgba(20, 26, 43, 0.35);
    pointer-events: none;
}

.tile .badge {
    position: absolute;
    right: 5%;
    bottom: 5%;
    padding: 0.1em 0.45em;
    border-radius: 0.5em;
    background: rgba(20, 26, 43, 0.7);
    color: #f4f1ea;
    font-size: calc(var(--cell-size) * 0.16);
    font-weight: 700;
    line-height: 1.4;
}

.tile.numeric .face {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: calc(var(--cell-size) * 0.32);
    font-weight: 800;
}

.tile-high .face {
    background: #8f2f14;
}

/* Animations; every duration comes from a custom property main.js sets
   from js/constants.js at boot. */

.tile.spawn .face {
    animation: spawn-pop var(--pop-duration) ease-out;
}

.tile.merge .face {
    animation: merge-pop var(--pop-duration) ease-in-out;
}

.tile-11 {
    animation: glow 1.6s ease-in-out infinite alternate;
}

#board.shake {
    animation: shake var(--shake-duration) ease-in-out;
}

@keyframes spawn-pop {
    from {
        transform: scale(0.2);
    }
    to {
        transform: scale(1);
    }
}

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

@keyframes glow {
    from {
        box-shadow: 0 0 6px 2px rgba(255, 200, 87, 0.45);
    }
    to {
        box-shadow: 0 0 22px 8px rgba(255, 200, 87, 0.9);
    }
}

@keyframes shake {
    0%,
    100% {
        translate: 0;
    }
    25% {
        translate: -6px;
    }
    75% {
        translate: 6px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .tile {
        transition-duration: 0s;
    }

    .tile.spawn .face,
    .tile.merge .face,
    #board.shake {
        animation-duration: 0s;
    }

    .tile-11 {
        animation: none;
    }
}

/* Overlays */

.overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
    pointer-events: none;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
    background: rgba(20, 26, 43, 0.6);
}

/* The name prompt toggles the hidden attribute rather than x-show, so its
   input can be focused in the same tick the overlay appears; the class's
   display: flex would otherwise outrank the user-agent [hidden] rule. */
.overlay[hidden] {
    display: none;
}

.overlay button,
.overlay input,
.overlay .panel {
    pointer-events: auto;
}

.overlay h2 {
    font-size: 32px;
}

.overlay .hint {
    font-size: 16px;
    opacity: 0.9;
}

.overlay .score-line {
    font-size: 20px;
}

.button-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
}

.panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    min-width: 240px;
    max-width: 90%;
    padding: 20px;
    border-radius: 12px;
    background: rgba(20, 26, 43, 0.92);
    text-shadow: none;
}

.panel label {
    font-size: 14px;
    opacity: 0.85;
}

.panel input {
    font: inherit;
    font-size: 18px;
    width: 100%;
    padding: 10px 12px;
    border: 2px solid #f2b134;
    border-radius: 8px;
    background: #0e1220;
    color: #f4f1ea;
    text-align: center;
}

.panel table {
    border-collapse: collapse;
    width: 100%;
    font-size: 16px;
}

.panel th,
.panel td {
    padding: 6px 10px;
    text-align: left;
}

.panel th:last-child,
.panel td:last-child {
    text-align: right;
}

.panel tbody tr:nth-child(odd) {
    background: rgba(255, 255, 255, 0.05);
}

/* Ten rows plus a header must fit a short phone; the panel scrolls before
   the overlay would clip it. */
.panel {
    max-height: 100%;
    overflow-y: auto;
}

.panel th:first-child,
.panel td:first-child {
    width: 2.5em;
    opacity: 0.7;
}

.panel td:nth-child(2) {
    overflow-wrap: anywhere;
}

/* A short landscape viewport puts the header beside the board. */
@media (orientation: landscape) and (max-height: 520px) {
    #game-wrapper {
        --hud-width: 200px;
        --board-size: min(100vh - 2 * var(--page-pad), 100vw - var(--hud-width) - 3 * var(--page-pad), var(--board-max));
        --board-size: min(100dvh - 2 * var(--page-pad), 100vw - var(--hud-width) - 3 * var(--page-pad), var(--board-max));
        flex-direction: row;
        align-items: center;
    }

    #hud {
        width: var(--hud-width);
    }

    #hud h1 {
        font-size: 22px;
    }
}

@media (max-width: 400px) {
    #hud h1 {
        font-size: 22px;
    }

    .overlay h2 {
        font-size: 26px;
    }

    .overlay .score-line {
        font-size: 18px;
    }
}

/* Help panel */

/* The overlay class disables pointer events so score overlays never block
   the board; the help backdrop takes the closing click and shields the board
   from a stray tap. */
#help-overlay {
    pointer-events: auto;
}

.help-panel {
    width: 100%;
    max-width: 520px;
    align-items: stretch;
    gap: 18px;
    text-align: left;
    padding-top: 0;
    scrollbar-width: thin;
    scrollbar-color: rgba(244, 241, 234, 0.35) transparent;
}

/* The head row sticks to the top of the scrolling panel so Close is in reach
   at any scroll position. A sticky box cannot leave its containing block, so
   the panel's top padding moves onto the head row, whose solid ground hides
   what scrolls beneath it. */
.help-head {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0 -20px 0;
    padding: 20px 20px 12px;
    background: #141a2b;
}

.help-panel section {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.help-panel h3 {
    font-size: 18px;
}

.help-panel p {
    font-size: 15px;
    line-height: 1.45;
}

.help-panel > button {
    align-self: center;
}

.shots {
    display: flex;
    gap: 10px;
    margin-top: 4px;
}

.shots .shot {
    flex: 1 1 0;
    min-width: 0;
}

.shot {
    position: relative;
    margin-top: 4px;
    text-align: center;
}

.shot img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 6px;
}

/* The SVG shares the picture's 600 by 600 coordinates, so its arrows and
   rings scale with the picture at every width. */
.shot svg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    aspect-ratio: 1;
    pointer-events: none;
    fill: none;
    stroke: #f2b134;
    stroke-width: 8;
    stroke-linecap: round;
}

.shot .arrowhead {
    fill: #f2b134;
    stroke: none;
}

.shot figcaption {
    margin-top: 6px;
    font-size: 13px;
    opacity: 0.85;
}

/* The chain strip reuses the tile rules; these tiles are not placed by row
   and column, so the strip sets the cell size itself and lays them in a
   wrapping row. */
.chain {
    --cell-size: 56px;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    margin-top: 4px;
}

.chain .tile {
    position: static;
    transform: none;
    transition: none;
}
