@font-face {
    font-family: "Bree Serif";
    src: url("../fonts/BreeSerif-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

:root {
    --night: #0f1b3d;
    --night-deep: #080f24;
    --moon: #e6c65a;
    --star: #eef2f7;
    --turf: #5d876a;
    --turf-shade: #3f6249;
    --earth: #8c4c37;
    --strata: #5f2f25;
    --strata-deep: #43201a;
    --room: #ab9846;
    --room-ink: #3a1e16;
    --room-ink-soft: #3f2317;
    --teal: #126867;
    --teal-deep: #0c4a49;
    --teal-ink: #ffffff;
    --teal-ink-soft: #d6e8e5;
    --paper: #ffffff;
    --wood: #7a4a2e;
    --bone: #c9d2d8;

    --display: "Bree Serif", "Iowan Old Style", Georgia, serif;
    --body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --rim: 10px;
    --shaft: 34px;
    --turf-height: 36px;
    --gap: clamp(2.5rem, 5vw, 4.5rem);
    --measure: 34rem;

    color-scheme: dark;
}

/* The game's own measures, beside the copied tokens above: the sky is
   shorter than the site's and the earth's top padding makes room for the
   pennants, so the board keeps the first screen. */
:root {
    --sky-height: 96px;
    --earth-top: 28px;
}

/* Same specificity trick as .overlay[hidden] below: the class's display: flex
   would otherwise outrank a bare attribute selector by source order. */
.overlay[x-cloak] {
    display: none;
}

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

html {
    scroll-behavior: smooth;
}

body {
    font-family: var(--body);
    background: var(--strata-deep);
    color: var(--star);
    -webkit-font-smoothing: antialiased;
}

::selection {
    background: var(--moon);
    color: var(--strata-deep);
}

:focus-visible {
    outline: 3px solid var(--moon);
    outline-offset: 4px;
}

h1,
h2,
h3,
label {
    font-family: var(--display);
    font-weight: 400;
}

/* Props: authored SVG furnishings, decorative, never in the reading order */

.prop {
    position: absolute;
    display: block;
    pointer-events: none;
    user-select: none;
}

/* The sky */

.sky {
    position: relative;
    min-height: var(--sky-height);
    padding: clamp(0.75rem, 1.5vw, 1rem) clamp(1.25rem, 5vw, 4rem) 0;
    color: var(--star);
    background-color: var(--night);
    background-image: url("../img/scene/stars.svg"), linear-gradient(180deg, var(--night-deep), var(--night) 70%);
    background-size:
        1600px 220px,
        100% 100%;
    background-position:
        left top,
        0 0;
    background-repeat: repeat-x, no-repeat;
    overflow: hidden;
}

/* The signpost is the way home on this page, so it is a link in the sign's form */

.sign {
    position: relative;
    z-index: 1;
    display: inline-block;
    font-family: var(--display);
    font-size: clamp(1.75rem, 2.6vw, 2.25rem);
    line-height: 1;
    letter-spacing: 0.01em;
    padding: 0.55em 0.9em 0.5em;
    color: var(--star);
    background: var(--strata);
    text-decoration: none;
    border: 3px solid var(--strata-deep);
    border-radius: 6px 6px 3px 3px;
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.45);
    transition:
        transform 0.35s var(--ease-out),
        box-shadow 0.35s var(--ease-out);
}

.sign:hover {
    transform: translateY(-2px);
    box-shadow: 0 9px 18px rgba(0, 0, 0, 0.45);
}

.sign::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 100%;
    width: 12px;
    height: 200px;
    margin-left: -6px;
    background: var(--strata-deep);
}

.sky::after {
    content: "";
    position: absolute;
    right: 3rem;
    top: 0.25rem;
    width: clamp(52px, 6vw, 84px);
    height: clamp(52px, 6vw, 84px);
    border-radius: 50%;
    background: var(--moon);
    box-shadow: 0 0 48px 14px rgba(230, 198, 90, 0.22);
}

.cloud {
    left: 34%;
    top: 12px;
    width: clamp(160px, 22vw, 320px);
    height: auto;
    opacity: 0.9;
}

/* The turf line */

.turf {
    position: relative;
    height: 28px;
    background: var(--turf);
    border-bottom: 8px solid var(--turf-shade);
    background-image: repeating-linear-gradient(90deg, var(--turf-shade) 0 3px, transparent 3px 11px);
    background-size: 11px 12px;
    background-repeat: repeat-x;
    background-position: 0 -4px;
}

.turf::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -40px;
    height: 44px;
    background: url("../img/scene/grass.svg") repeat-x left bottom / 1600px 44px;
}

/* The earth: the game is cut into it, the book nook below */

.earth {
    position: relative;
    padding: var(--earth-top) clamp(1rem, 4vw, 3rem) calc(var(--gap) * 1.5);
    color: var(--star);
    background-color: var(--earth);
    background-image: url("../img/scene/earth-tile.svg"), url("../img/scene/strata.svg");
    background-size:
        1200px 600px,
        1200px 520px;
}

.pennants {
    left: 50%;
    top: -4px;
    width: min(80%, 360px);
    height: auto;
    transform: translateX(-50%);
}

/* The board is a square sized by whichever runs out first: the viewport
   width, or the viewport height less the strata above the board and the
   room the header strip needs. */
#game-wrapper {
    --page-pad: 12px;
    --hud-height: 150px;
    --hud-allowance: calc(
        var(--sky-height) +
        var(--turf-height) +
        var(--earth-top) +
        var(--hud-height) +
        3 *
        var(--page-pad)
    );
    --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: clamp(1.75rem, 2.6vw, 2.375rem);
    line-height: 1.05;
    letter-spacing: 0.01em;
}

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

/* A score box is a signboard that is not takeable: the sign's form, no shadow */
.score-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 88px;
    padding: 4px 12px;
    border: 3px solid var(--strata-deep);
    border-radius: 6px;
    background: var(--strata);
    color: var(--star);
    line-height: 1.2;
}

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

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

/* Buttons: wooden signboards */

#hud button,
.overlay button {
    display: inline-block;
    margin: 0;
    white-space: nowrap;
    font-family: var(--display);
    font-weight: 400;
    font-size: 1.1875rem;
    line-height: 1;
    padding: 0.9em 1.3em 0.85em;
    color: var(--strata-deep);
    background: var(--moon);
    border: 3px solid var(--strata-deep);
    border-radius: 6px;
    box-shadow: 0 5px 12px rgba(0, 0, 0, 0.32);
    cursor: pointer;
    text-shadow: none;
    transition:
        transform 0.35s var(--ease-out),
        box-shadow 0.35s var(--ease-out);
}

#hud button,
.help-head button {
    font-size: 1rem;
    padding: 0.6em 1em 0.55em;
}

#hud button:hover,
.overlay button:hover {
    transform: translateY(-2px);
    box-shadow: 0 9px 18px rgba(0, 0, 0, 0.36);
}

#hud button:active,
.overlay button:active {
    transform: translateY(1px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.32);
}

/* 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: var(--strata);
    box-shadow:
        inset 0 10px 24px rgba(0, 0, 0, 0.22),
        0 0 0 6px var(--strata-deep);
    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: var(--strata-deep);
    box-shadow: inset 0 6px 12px rgba(0, 0, 0, 0.5);
}

/* 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: var(--paper);
}

/* 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(67, 32, 26, 0.35);
    pointer-events: none;
}

.tile .badge {
    position: absolute;
    right: 5%;
    bottom: 5%;
    padding: 0.1em 0.45em;
    border-radius: 0.5em;
    background: rgba(67, 32, 26, 0.7);
    color: var(--star);
    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: var(--star);
    font-size: calc(var(--cell-size) * 0.32);
    font-weight: 800;
}

.tile-high .face {
    background: var(--strata-deep);
}

/* 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(230, 198, 90, 0.45);
    }
    to {
        box-shadow: 0 0 22px 8px rgba(230, 198, 90, 0.9);
    }
}

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

/* 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;
    color: var(--star);
    background: rgba(67, 32, 26, 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;
}

/* A panel is a Strata board standing on the earth */
.panel {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    min-width: 240px;
    max-width: 90%;
    padding: 20px;
    border: 3px solid var(--strata-deep);
    border-radius: 6px;
    background: var(--strata);
    color: var(--star);
    box-shadow: 6px 10px 22px rgba(0, 0, 0, 0.4);
}

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

.panel input {
    font: inherit;
    font-size: 18px;
    width: 100%;
    padding: 10px 12px;
    border: 2px solid var(--moon);
    border-radius: 6px;
    background: var(--strata-deep);
    color: var(--star);
    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(238, 242, 247, 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;
}

/* The book nook: the one teal room, the cover and the way to the ebook */

.room {
    position: relative;
    padding: clamp(1.75rem, 3.5vw, 3rem) clamp(1.75rem, 4vw, 3.25rem);
    background: var(--room);
    border: var(--rim) solid var(--strata);
    border-radius: 44% 56% 48% 52% / 20% 20% 22% 22%;
    box-shadow: inset 0 10px 24px rgba(0, 0, 0, 0.22);
}

.room::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset: calc(var(--rim) * -1);
    border-radius: inherit;
    box-shadow: 0 0 0 6px var(--strata-deep);
    pointer-events: none;
}

.room-book {
    max-width: var(--measure);
    margin: var(--gap) auto 0;
    background: var(--teal);
    color: var(--teal-ink);
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(1.25rem, 3vw, 2rem);
    align-items: center;
}

.room-book h2 {
    font-size: clamp(1.5rem, 2.2vw, 1.875rem);
    line-height: 1.05;
    color: var(--teal-ink);
    margin-bottom: 0.5rem;
}

.room-book p {
    font-size: 1.0625rem;
    line-height: 1.5;
    color: var(--teal-ink-soft);
}

.room-book .button {
    display: inline-block;
    margin-top: 1.25rem;
    white-space: nowrap;
    font-family: var(--display);
    font-size: 1.1875rem;
    line-height: 1;
    padding: 0.9em 1.3em 0.85em;
    color: var(--strata-deep);
    background: var(--moon);
    text-decoration: none;
    border: 3px solid var(--strata-deep);
    border-radius: 6px;
    box-shadow: 0 5px 12px rgba(0, 0, 0, 0.32);
    transition:
        transform 0.35s var(--ease-out),
        box-shadow 0.35s var(--ease-out);
}

.room-book .button:hover {
    transform: translateY(-2px);
    box-shadow: 0 9px 18px rgba(0, 0, 0, 0.36);
}

.room-book .button:active {
    transform: translateY(1px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.32);
}

.room-book .aside {
    margin-top: 0.75rem;
    font-size: 0.9375rem;
}

/* The cover is the book's own art, never redrawn; the frame is the page's */
.cover {
    position: relative;
    width: 120px;
    aspect-ratio: 3 / 4;
    background: var(--teal-deep);
    border: 3px solid var(--moon);
    outline: 3px solid var(--teal-deep);
    border-radius: 3px;
    box-shadow: 6px 10px 22px rgba(0, 0, 0, 0.4);
    overflow: hidden;
    transform: rotate(-2deg);
}

.cover img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (min-width: 600px) {
    .room-book {
        grid-template-columns: 120px 1fr;
    }

    /* On a wide board the header strip is two rows, title beside scores,
       so the board keeps its cap inside a 900px-tall viewport. */
    #game-wrapper {
        --hud-height: 104px;
    }

    #hud {
        display: grid;
        grid-template-columns: 1fr auto;
        align-items: center;
        justify-items: start;
    }

    #hud .button-row {
        grid-column: 1 / -1;
        justify-self: center;
    }
}

/* Bedrock */

.bedrock {
    position: relative;
    padding: 1.5rem clamp(1.25rem, 5vw, 4rem) 6rem;
    color: var(--star);
    background:
        url("../img/scene/bones.svg") space no-repeat left calc(100% - 60px) / 1200px 34px,
        url("../img/scene/stream.svg") repeat-x left bottom / 600px 60px,
        var(--strata-deep);
    font-size: 0.9375rem;
}

@media (max-width: 479px) {
    .bedrock {
        background-image: url("../img/scene/bones-narrow.svg"), url("../img/scene/stream.svg");
        background-size:
            360px 34px,
            600px 60px;
    }
}

/* A short landscape viewport puts the header beside the board and folds
   the sky to a band, the signpost at nav size. */
@media (orientation: landscape) and (max-height: 520px) {
    :root {
        --sky-height: var(--turf-height);
        --earth-top: 16px;
    }

    .sky {
        padding-top: 3px;
    }

    .sign {
        font-size: 0.875rem;
        padding: 0.4em 0.8em 0.35em;
        border-width: 2px;
    }

    .sky::after {
        width: 24px;
        height: 24px;
        top: 6px;
        box-shadow: 0 0 24px 6px rgba(230, 198, 90, 0.22);
    }

    .pennants {
        width: min(50%, 240px);
    }

    #game-wrapper {
        --hud-width: 200px;
        --board-size: min(
            100vh -
            var(--sky-height) -
            var(--turf-height) -
            var(--earth-top) -
            2 *
            var(--page-pad),
            100vw -
            var(--hud-width) -
            3 *
            var(--page-pad),
            var(--board-max)
        );
        --board-size: min(
            100dvh -
            var(--sky-height) -
            var(--turf-height) -
            var(--earth-top) -
            2 *
            var(--page-pad),
            100vw -
            var(--hud-width) -
            3 *
            var(--page-pad),
            var(--board-max)
        );
        flex-direction: row;
        align-items: center;
    }

    #hud {
        display: flex;
        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(238, 242, 247, 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 ground must equal
   the panel's exactly or a seam shows where it hides what scrolls beneath. */
.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: var(--strata);
}

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

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

.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: var(--moon);
    stroke-width: 8;
    stroke-linecap: round;
}

.shot .arrowhead {
    fill: var(--moon);
    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;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    .tile {
        transition-duration: 0s;
    }

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

    .tile-11 {
        animation: none;
    }

    .sign,
    #hud button,
    .overlay button,
    .room-book .button {
        transition: none;
    }

    .sign:hover,
    #hud button:hover,
    .overlay button:hover,
    .room-book .button:hover {
        transform: none;
    }
}

@media print {
    .sky,
    .earth,
    .bedrock,
    .room {
        background: none;
        color: var(--night-deep);
        box-shadow: none;
    }

    .sky::after,
    .sign::after,
    .prop {
        display: none;
    }
}
