/* =========================================================================
   Sail n' Dig -- static marketing site
   Palette and shapes are lifted from the game's own art: bright cartoon
   fills, hard dark outlines, no blur, no gradients on chrome.
   ========================================================================= */

@font-face {
    font-family: "Chela One";
    src: url("../fonts/ChelaOne-Regular.ttf") format("truetype");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    /* U+00BF is deliberately excluded: Chela One reports coverage for the inverted question mark
       but draws it as an inverted exclamation, which quietly mangles Spanish headings. Leaving it
       out of the range lets that one character fall through to the next family in the stack. */
    unicode-range: U+0-BE, U+C0-10FFFF;
}

:root {
    /* Sampled from Sprites/Common/featured-HD.jpg and Logo.png */
    --sky: #2e9be8;
    --sky-light: #7fd0f7;
    --sky-deep: #1b7fd1;
    --sea: #0e4c7e;
    --sea-night: #0e2242;
    --sand: #f2c879;
    --sand-deep: #e5a64c;
    --gold: #ffc72c;
    --gold-deep: #e59c17;
    --red: #e8524b;
    --red-deep: #b8352f;
    --gem-green: #3fd6a0;
    --gem-pink: #ff4fa3;
    --ink: #14263f;
    --paper: #fff6e2;
    --paper-shade: #f2e3c4;

    /* Outline and hard shadow under display type. Reads as a dark navy rather than the near-black
       --ink, which is what the game's own logo does. Chrome (borders, buttons) keeps --ink. */
    --ink-blue: #0d3a6b;
    /* The sea texture's own blue (dominant colour of water-silly.webp, #0878e8). The sea scene
       fades into this and the mailing list starts from it, so the two meet with no seam. */
    --sea-bright: #0b7ae6;
    /* End of the studio gradient and the first stop of the closing CTA's transition. */
    --night-deep: #0a1a33;

    --outline: 3px;
    --radius: 18px;
    --shadow-hard: 0 6px 0 var(--ink);
    --shadow-hard-sm: 0 4px 0 var(--ink);

    --display: "Chela One", "Comic Sans MS", system-ui, sans-serif;
    --body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    --shell: min(1180px, 92vw);
    --ease-pop: cubic-bezier(0.18, 0.89, 0.32, 1.28);
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    /* The reveal transforms start off-axis and would otherwise widen the page on narrow
       screens. `clip` rather than `hidden`: hidden would make <html> a scroll container
       and break the sticky sea backdrop. */
    overflow-x: clip;
}

/* Keeps in-page anchors clear of the fixed nav. */
[id] {
    scroll-margin-top: 5rem;
}

body {
    margin: 0;
    font-family: var(--body);
    font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
    line-height: 1.6;
    color: var(--ink);
    background: var(--sky);
    overflow-x: clip;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: inherit;
}

:focus-visible {
    outline: 3px solid var(--gold);
    outline-offset: 3px;
    border-radius: 6px;
}

/* --------------------------------------------------------------- typography */

.display,
h1,
h2,
h3 {
    font-family: var(--display);
    font-weight: 400;
    line-height: 1.05;
    letter-spacing: 0.01em;
    margin: 0;
}

/* The chunky outline + hard drop shadow the game's logo uses. Drawn in --ink-blue, not --ink:
   the near-black outline read as a black keyline against the sky and the sea. */
.outlined {
    color: var(--paper);
    text-shadow:
        -2px 0 var(--ink-blue), 2px 0 var(--ink-blue), 0 -2px var(--ink-blue), 0 2px var(--ink-blue),
        -2px -2px var(--ink-blue), 2px -2px var(--ink-blue), -2px 2px var(--ink-blue), 2px 2px var(--ink-blue),
        0 7px 0 var(--ink-blue);
}

/* Gold reads well on the deep-sea sections but vanishes on sand and paper, so each
   section sets its own kicker colour. */
.section-kicker {
    font-family: var(--display);
    font-size: clamp(0.95rem, 0.9rem + 0.3vw, 1.15rem);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--kicker, var(--gold));
    text-shadow: var(--kicker-shadow, 0 2px 0 var(--ink-blue));
    margin: 0 0 0.4rem;
}

.section-title {
    font-size: clamp(2.2rem, 1.5rem + 3.4vw, 4rem);
}

/* Marketing body copy is set in the game's own display face, like the headings -- it is short,
   large and never runs to a wall of text. The sans --body is kept for the chrome that has to stay
   legible at small sizes: nav, footer, the email field and its placeholder. */
.section-lede {
    max-width: 58ch;
    margin: 1rem auto 0;
    font-family: var(--display);
    font-size: clamp(1rem, 0.95rem + 0.3vw, 1.2rem);
    letter-spacing: 0.01em;
}

.u-center {
    text-align: center;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.skip-link {
    position: absolute;
    left: 50%;
    top: 0;
    transform: translate(-50%, -150%);
    z-index: 100;
    background: var(--paper);
    border: var(--outline) solid var(--ink);
    border-radius: 0 0 12px 12px;
    padding: 0.6rem 1.2rem;
    font-family: var(--display);
    text-decoration: none;
}

.skip-link:focus {
    transform: translate(-50%, 0);
}

/* -------------------------------------------------------------- primitives */

.shell {
    width: var(--shell);
    margin-inline: auto;
}

.panel {
    background: var(--paper);
    border: var(--outline) solid var(--ink);
    border-radius: var(--radius);
    box-shadow: var(--shadow-hard);
}

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--display);
    font-size: 1.15rem;
    text-decoration: none;
    padding: 0.8rem 1.6rem;
    border: var(--outline) solid var(--ink);
    border-radius: 999px;
    background: var(--gold);
    color: var(--ink);
    box-shadow: var(--shadow-hard);
    cursor: pointer;
    transition: transform 0.12s var(--ease-pop), box-shadow 0.12s var(--ease-pop);
}

.btn:hover,
.btn:focus-visible {
    transform: translateY(2px);
    box-shadow: var(--shadow-hard-sm);
}

.btn:active {
    transform: translateY(6px);
    box-shadow: 0 0 0 var(--ink);
}

.tag {
    display: inline-block;
    font-family: var(--display);
    font-size: 0.9rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.25rem 0.8rem;
    border: 2px solid var(--ink);
    border-radius: 999px;
    background: var(--paper);
}

/* Wavy divider between sections, echoing the game's shoreline art. */
.wave {
    display: block;
    width: 100%;
    height: clamp(40px, 6vw, 90px);
}

/* ------------------------------------------------------------ spine stages */

.spine-stage {
    position: relative;
    display: block;
}

/* The runtime appends its own wrapper as a sibling of the poster. It stays hidden until
   the runtime's own loading overlay has faded, so the poster covers it in the meantime. */
.spine-stage > .spine-player {
    position: absolute;
    inset: 0;
    background: transparent;
    border: 0;
    opacity: 0;
    transition: opacity 0.4s ease;
}

.spine-stage.is-live > .spine-player {
    opacity: 1;
}

.spine-stage canvas {
    display: block;
    width: 100%;
    height: 100%;
    /* The runtime binds touchstart/touchmove on its canvas and preventDefaults them, so on a phone
       a swipe that begins on the ship or a coin never scrolls the page. Every stage left here is
       decoration marked aria-hidden, so no event needs to reach it. Revisit if one ever becomes
       interactive. */
    pointer-events: none;
}

/* The poster is the honest fallback: it stays put unless a player reports success. */
.spine-poster {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.spine-stage .spine-player-controls {
    display: none !important;
}

/* --------------------------------------------------------------- site nav */

.site-nav {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.7rem clamp(1rem, 4vw, 2.5rem);
    background: color-mix(in srgb, var(--sea-night) 78%, transparent);
    backdrop-filter: blur(6px);
    transform: translateY(-100%);
    transition: transform 0.3s ease;
}

.site-nav.is-visible {
    transform: translateY(0);
}

.site-nav__brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--display);
    color: var(--paper);
    text-decoration: none;
    font-size: 1.2rem;
}

.site-nav__brand img {
    width: 42px;
    border-radius: 8px;
}

.site-nav__links {
    display: flex;
    gap: 1.2rem;
    margin-left: auto;
    list-style: none;
    padding: 0;
}

.site-nav__links a {
    font-family: var(--display);
    color: var(--paper);
    text-decoration: none;
    font-size: 1.05rem;
    opacity: 0.85;
}

.site-nav__links a:hover {
    opacity: 1;
    color: var(--gold);
}

.lang-switch {
    display: flex;
    border: 2px solid var(--paper);
    border-radius: 999px;
    overflow: hidden;
}

.lang-switch button {
    font-family: var(--display);
    font-size: 0.9rem;
    padding: 0.25rem 0.7rem;
    background: transparent;
    color: var(--paper);
    border: 0;
    cursor: pointer;
}

.lang-switch button[aria-pressed="true"] {
    background: var(--gold);
    color: var(--ink);
}

@media (max-width: 780px) {
    .site-nav__links {
        display: none;
    }

    .lang-switch {
        margin-left: auto;
    }
}

/* --------------------------------------------------------------- sea scene */

/* Wraps the hero and the explore section so the two share one continuous sea. The water is a
   child of the hero -- that is what keeps its percentages and its `--p` parallax resolving
   against the hero -- but it runs `--sea-drop` past the hero's bottom edge, and this element is
   what clips it, at the foot of the explore section.

   The clipping here also takes over what the hero used to do itself, notably the clouds, which
   animate well past both edges of the viewport.

   `clip`, emphatically not `hidden`. A `hidden` box is still *programmatically* scrollable, and
   the water gives this one ~200vh of scrollable overflow -- so following `#explore` (the "Insert
   coin" link, and the first nav item) made the browser scroll this element as well as the page,
   sliding the hero out of its own clip with no way for the user to scroll it back. `clip` is not
   a scroll container at all, so there is nothing to scroll. */
.sea-scene {
    position: relative;
    overflow: clip;
}

/* The water is clipped mid-texture at the foot of the scene, and #join starts immediately below --
   so without this the two would meet as a hard horizontal line. Ramping into #join's own top colour
   dissolves the sea into it instead. Change this if the section that follows the scene ever
   changes: the end colour has to be that section's first gradient stop.
   No z-index: that leaves the fade above the water and below the explore copy. */
.sea-scene::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: clamp(90px, 14vh, 180px);
    pointer-events: none;
    background: linear-gradient(180deg, rgba(11, 122, 230, 0) 0%, var(--sea-bright) 100%);
}

/* ------------------------------------------------------------------- hero */

.hero {
    position: relative;
    min-height: 100svh;
    display: grid;
    place-items: start center;
    padding: clamp(3.5rem, 9vh, 6rem) 0 4rem;
    background: linear-gradient(180deg, #1673c4 0%, var(--sky) 42%, var(--sky-light) 78%, #bfe9ff 100%);
    /* How far the sea runs below the hero. Any value past the combined height of the explore and
       trailer sections does -- `.sea-scene` clips the remainder -- so this needs no measuring and
       no JS. */
    --sea-drop: 300vh;
}

.hero__layers {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.hero__layer {
    position: absolute;
    left: 0;
    right: 0;
    will-change: transform;
}

.hero__clouds {
    top: 0;
    height: 46%;
    transform: translate3d(0, calc(var(--p, 0) * -40px), 0);
}

/* One painted cloud sprite, drawn solid. Only the width is set per cloud -- the aspect ratio
   comes from the art, so a cloud can never be squashed. */
.cloud {
    position: absolute;
    aspect-ratio: 345 / 296;
    background: url("../img/sky/cloud.webp") no-repeat center / contain;
    animation: float-x linear infinite;
}

.cloud--1 {
    width: 210px;
    top: 18%;
    animation-duration: 78s;
}

.cloud--2 {
    width: 150px;
    top: 40%;
    animation-duration: 54s;
    animation-delay: -20s;
}

.cloud--3 {
    width: 280px;
    top: 58%;
    animation-duration: 96s;
    animation-delay: -55s;
}

.cloud--4 {
    width: 120px;
    top: 8%;
    animation-duration: 44s;
    animation-delay: -12s;
}

@keyframes float-x {
    from {
        transform: translateX(-320px);
    }
    to {
        transform: translateX(calc(100vw + 320px));
    }
}

/* The horizon is a straight line: the strip is a plain rectangle of water texture, no mask.

   `--sea-drop` is added to `bottom` and `height` in equal measure, so the strip grows downward
   only and its top edge does not move. That matters: the cloud bank and the ship's waterline both
   mirror this strip's top edge as the constant 32%, and neither of them knows about the drop.

   The front strip is also the sea the explore and trailer sections sit on, which is why it must be
   one element: a second water background further down could not be kept in phase with this one's
   texture, drift animation and parallax offset, and the mismatch would read as a seam. */
.hero__water {
    bottom: calc(-2% - var(--sea-drop, 0px));
    height: calc(34% + var(--sea-drop, 0px));
    background: url("../img/sea/water-silly.webp") repeat center / 220px;
    transform: translate3d(0, calc(var(--p, 0) * 60px), 0);
    animation: drift-x 26s linear infinite;
}

/* A still bank of cloud along the horizon. Deliberately not animated -- it is the fixed line the
   moving water reads against.

   Only the puffs are meant to be seen: the tile's body runs solid downward and the sea covers it,
   so the bank has no bottom edge of its own. The element is anchored to the bottom and its
   *height* is what places the puffs. 32% is the water layer's own top edge, and the extra is the
   height of the tile's puff band (123px at this width, 150/756 of the art) less a small overlap,
   so the puffs stand on the waterline instead of sinking behind it.

   Two background layers. The tile is drawn at a fixed width so the puffs keep their scale, which
   caps its own height at 371px -- shorter than this element on a tall window. The second layer is
   a flat white fill anchored to the bottom that takes over 340px down, inside the tile's solid
   body and well clear of the puffs. `max(0px, ...)` because on a short window that subtraction
   goes negative, which would be an invalid size. */
.hero__horizon {
    bottom: 0;
    height: calc(32% + 110px);
    background:
        url("../img/sky/cloudline.webp") repeat-x left top / 620px auto,
        linear-gradient(#fff, #fff) no-repeat left bottom / 100% max(0px, 100% - 340px);
    transform: translate3d(0, calc(var(--p, 0) * -20px), 0);
}

@keyframes drift-x {
    from {
        background-position-x: 0;
    }
    to {
        background-position-x: -1200px;
    }
}

/* Seated against the water line, not the bottom of the screen. The ship is sized in pixels while
   the sea is a percentage of the hero, so a fixed `bottom` made it ride high on short, wide
   windows and sink out of sight on tall ones.

   32% is the water layer's top edge; 0.78 is the share of the canvas that sits below the surface,
   and the extra 20px is headroom for `bob`, which lifts the ship 14px at the top of its cycle.
   Together they are what keeps the hull's base under the line at every point of the animation. */
.hero__ship {
    position: absolute;
    left: 50%;
    --ship-size: calc(clamp(200px, 24vw, 360px) * var(--ship-scale, 1));
    bottom: calc(32% - 20px - 0.78 * var(--ship-size));
    width: var(--ship-size);
    aspect-ratio: 1 / 1;
    translate: -50% 0;
    animation: bob 4.5s ease-in-out infinite;
    z-index: 2;
}

@keyframes bob {
    0%,
    100% {
        transform: translateY(0) rotate(-1.5deg);
    }
    50% {
        transform: translateY(-14px) rotate(1.5deg);
    }
}

.hero__content {
    position: relative;
    z-index: 3;
    text-align: center;
    display: grid;
    justify-items: center;
    gap: 1.1rem;
}

.hero__logo {
    width: clamp(260px, 40vw, 540px);
    filter: drop-shadow(0 10px 0 rgba(20, 38, 63, 0.35));
    animation: logo-in 0.9s var(--ease-pop) both;
}

@keyframes logo-in {
    from {
        opacity: 0;
        transform: translateY(-30px) scale(0.92);
    }
}

.hero__tagline {
    font-size: clamp(1.6rem, 1rem + 2.6vw, 3rem);
}

.hero__sub {
    max-width: 46ch;
    /* Keeps the last line from stranding a single word; ignored where unsupported. */
    text-wrap: balance;
    font-family: var(--display);
    letter-spacing: 0.01em;
    color: var(--paper);
    /* A 1px version of `.outlined` rather than a plain drop shadow: the clouds are solid white and
       drift right through this line, and paper-on-white needs an edge to stay readable. */
    text-shadow:
        -1px 0 var(--ink-blue), 1px 0 var(--ink-blue), 0 -1px var(--ink-blue), 0 1px var(--ink-blue),
        0 3px 6px rgba(13, 58, 107, 0.45);
    margin: 0;
}

.hero__scroll {
    position: absolute;
    left: 50%;
    bottom: 1.6rem;
    translate: -50% 0;
    z-index: 3;
    font-family: var(--display);
    color: var(--paper);
    letter-spacing: 0.22em;
    text-transform: uppercase;
    font-size: 0.95rem;
    text-align: center;
    text-shadow: 0 2px 0 var(--ink-blue);
    text-decoration: none;
}

.hero__scroll span {
    display: block;
    animation: blink 1.15s steps(1) infinite;
}

.hero__scroll::after {
    content: "▼";
    display: block;
    font-size: 1.3rem;
    animation: nudge 1.6s ease-in-out infinite;
}

@keyframes blink {
    0%,
    49% {
        opacity: 1;
    }
    50%,
    100% {
        opacity: 0.15;
    }
}

@keyframes nudge {
    0%,
    100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(6px);
    }
}

/* Faded out before it reaches the hero's bottom edge. The vignette stops where the hero stops,
   but the sea no longer does -- left at full strength it darkened the water by ~12% right up to
   that edge and then quit, drawing exactly the horizontal seam this section is meant not to have. */
.hero__vignette {
    position: absolute;
    inset: 0;
    z-index: 4;
    pointer-events: none;
    background: radial-gradient(ellipse at center, transparent 55%, rgba(14, 34, 66, 0.35) 100%);
    -webkit-mask-image: linear-gradient(180deg, #000 45%, transparent 92%);
    mask-image: linear-gradient(180deg, #000 45%, transparent 92%);
}

/* Phone and tablet: the art is scaled down proportionally so the puffs keep their shape, and the
   logo and ship are scaled *up* -- both are read at arm's length on a small screen, and the
   desktop clamps bottom out far too small there. */
@media (max-width: 860px) {
    .hero__horizon {
        height: calc(32% + 66px);
        background-size: 380px auto, 100% max(0px, 100% - 200px);
    }

    .hero__logo {
        width: min(86vw, 460px);
    }

    .hero__ship {
        --ship-scale: 1.5;
    }
}

/* ---------------------------------------------------------------- sections */

.section {
    position: relative;
    padding: clamp(4rem, 9vw, 7.5rem) 0;
}

/* Picks up where the sea scene's fade leaves off -- `--sea-bright` is the water texture's own
   blue -- then runs down to the night sea the studio section continues from. */
.section--deep {
    background: linear-gradient(180deg, var(--sea-bright) 0%, var(--sea) 38%, var(--sea-night) 100%);
    color: var(--paper);
}

/* Carries the dark end of `.section--deep` on, so the two read as one dive. */
.section--night {
    background: linear-gradient(180deg, var(--sea-night) 0%, var(--night-deep) 100%);
    color: var(--paper);
}

.section__head {
    max-width: 70ch;
    margin: 0 auto clamp(2.5rem, 5vw, 4rem);
    text-align: center;
}

/* The Studio is a head and nothing else, so its bottom margin would only be dead space. */
.section__head:only-child {
    margin-bottom: 0;
}

/* The studio's name is set as its logo, so the <h2> holds an image instead of text. The mark is
   white on transparent -- which is why the section it sits in is dark. */
.studio__logo {
    margin: 0.2rem 0 0.4rem;
}

.studio__logo img {
    width: clamp(200px, 34vw, 420px);
    margin-inline: auto;
}

/* ------------------------------------------------------------------ explore */

/* Sits on the hero's water strip, which runs behind it -- so no background of its own, and a
   stacking order that puts the copy above the sea (the strip is `z-index: auto`). */
.explore {
    position: relative;
    z-index: 1;
    min-height: 70svh;
    display: grid;
    place-items: center;
    padding: clamp(4rem, 10vh, 7rem) 0;
}

.explore__inner {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(1.5rem, 4vw, 3.5rem);
    align-items: center;
}

/* Copy first in source order, so the single-column phone layout reads text then island. */
@media (max-width: 860px) {
    .explore__inner {
        grid-template-columns: 1fr;
    }

    /* Centred once it is a single column -- left-aligned type under a centred island looked adrift.
       The body needs the margin too: it is capped at 46ch, so it is narrower than its column. */
    .explore__copy {
        text-align: center;
    }

    .explore__body {
        margin-inline: auto;
    }
}

/* Read against open water, so the same paper-on-shadow treatment as the hero's own copy. */
.explore__copy {
    color: var(--paper);
    text-shadow: 0 2px 6px rgba(13, 58, 107, 0.55);
}

.explore__body {
    max-width: 46ch;
    /* Keeps the last line from stranding a single word; ignored where unsupported. */
    text-wrap: balance;
    font-family: var(--display);
    letter-spacing: 0.01em;
    margin: 1.1rem 0 0;
}

.explore__art {
    display: grid;
    place-items: center;
}

/* Static and unshadowed by design: the island reads as art sitting on the page, not as an object
   floating above it. */
.explore__art img {
    width: min(78%, 340px);
}

/* --------------------------------------------------------------- trailer */

/* Sits on the hero's water strip, which runs behind it -- so no background of its own, and the
   same stacking order as .explore. */
.trailer-section {
    position: relative;
    z-index: 1;
}

/* The trailer is shot vertical, so the frame is 9:16 and capped at a phone-ish width rather than
   stretched across the shell: a 16:9 box would pillarbox it and show more letterbox than game. */
.trailer {
    position: relative;
    width: min(400px, 78vw);
    margin-inline: auto;
    aspect-ratio: 9 / 16;
    border: var(--outline) solid var(--ink);
    border-radius: var(--radius);
    box-shadow: var(--shadow-hard);
    overflow: hidden;
    background: var(--sea-night);
}

.trailer__poster,
.trailer iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.trailer__poster {
    object-fit: cover;
}

/* Facade: nothing is requested from YouTube until this button is pressed, which is what keeps the
   page free of third-party requests on load. The click swaps in the iframe. */
.trailer__play {
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    display: grid;
    place-items: center;
    width: 84px;
    height: 84px;
    padding: 0;
    color: var(--ink);
    background: var(--paper);
    border: var(--outline) solid var(--ink);
    border-radius: 999px;
    box-shadow: var(--shadow-hard);
    cursor: pointer;
    transition: transform 0.12s var(--ease-pop), box-shadow 0.12s var(--ease-pop);
}

.trailer__play:hover,
.trailer__play:focus-visible {
    transform: translateY(2px);
    box-shadow: var(--shadow-hard-sm);
}

.trailer__play:active {
    transform: translateY(6px);
    box-shadow: 0 0 0 var(--ink);
}

/* The triangle is optically centred: a centred glyph in a circle always reads left-of-centre. */
.trailer__play svg {
    margin-left: 6px;
}

/* ------------------------------------------------------------ newsletter */

/* Field and button share one row until the row runs out of width, then wrap and stack -- which is
   also what happens on a phone, so there is no breakpoint here. */
.newsletter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.9rem;
    justify-content: center;
    align-items: center;
}

/* Same chunky outline and hard shadow as .btn beside it, so the pair reads as one control. */
.newsletter__input {
    flex: 1 1 min(360px, 100%);
    max-width: 420px;
    font: inherit;
    color: var(--ink);
    background: var(--paper);
    padding: 0.8rem 1.3rem;
    border: var(--outline) solid var(--ink);
    border-radius: 999px;
    box-shadow: var(--shadow-hard);
}

.newsletter__input::placeholder {
    color: color-mix(in srgb, var(--ink) 50%, transparent);
}

/* Mailchimp's honeypot. Moved off screen rather than `display: none`, which some bots skip -- and
   which would also stop it being submitted at all. */
.newsletter__trap {
    position: absolute;
    left: -5000px;
}

/* ------------------------------------------------------------------ cta */

/* Same sky as before -- the first 12% is only a transition out of the studio section's dark end, so
   the two do not meet as a hard line. */
.cta {
    position: relative;
    text-align: center;
    padding: clamp(4rem, 9vw, 7rem) 0;
    background: linear-gradient(180deg, var(--night-deep) 0%, var(--sky) 12%, var(--sky-light) 100%);
    overflow: hidden;
}

.cta__logo {
    width: clamp(240px, 40vw, 460px);
    margin: 0 auto 1.4rem;
}

/* Store badges are images, not links: the game is unreleased and there is no store page to point
   at. The art carries its own "coming soon" wording, so only the alt text is translated. */
.store-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.9rem;
    justify-content: center;
    margin-top: 1.6rem;
}

.store-badge {
    width: clamp(150px, 38vw, 200px);
}

.cta__coin {
    position: absolute;
    width: clamp(70px, 8vw, 120px);
    aspect-ratio: 1 / 1;
    top: 18%;
}

.cta__coin--left {
    left: 8%;
}

.cta__coin--right {
    right: 8%;
}

@media (max-width: 780px) {
    .cta__coin {
        display: none;
    }
}

/* Round siblings of the store badges: same paper fill, ink outline and hard shadow, so the whole
   closing block reads as one set of controls. */
.cta__social {
    list-style: none;
    display: flex;
    justify-content: center;
    gap: 0.9rem;
    margin: 1.6rem 0 0;
    padding: 0;
}

.cta__social a {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    color: var(--ink);
    background: var(--paper);
    border: var(--outline) solid var(--ink);
    border-radius: 999px;
    box-shadow: var(--shadow-hard);
    transition: transform 0.12s var(--ease-pop), box-shadow 0.12s var(--ease-pop);
}

.cta__social a:hover,
.cta__social a:focus-visible {
    transform: translateY(2px);
    box-shadow: var(--shadow-hard-sm);
}

.cta__social a:active {
    transform: translateY(6px);
    box-shadow: 0 0 0 var(--ink);
}

.site-footer {
    background: var(--sea-night);
    color: var(--paper);
    padding: 2.5rem 0;
    font-size: 0.9rem;
}

.site-footer__inner {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
    justify-content: space-between;
}

.site-footer p {
    margin: 0;
    opacity: 0.75;
}

/* --------------------------------------------------------- scroll reveals */

/* Scoped to .js: without scripting nothing would ever add .is-in, and the whole page
   below the hero would stay invisible. */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(34px);
    transition:
        opacity 0.7s ease,
        transform 0.7s var(--ease-pop);
    transition-delay: calc(var(--i, 0) * 80ms);
}

.js [data-reveal="left"] {
    transform: translateX(-40px);
}

.js [data-reveal="right"] {
    transform: translateX(40px);
}

.js [data-reveal="pop"] {
    transform: scale(0.86) translateY(20px);
}

.js [data-reveal].is-in {
    opacity: 1;
    transform: none;
}

/* ------------------------------------------------------- reduced motion */

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

    *,
    *::before,
    *::after {
        animation: none !important;
        transition: none !important;
    }

    .js [data-reveal] {
        opacity: 1;
        transform: none;
    }

    /* The clouds are positioned entirely by their drift animation, so with animation off they
       all pile up at the left edge. Spread them across the sky instead. */
    .cloud--1 {
        left: 10%;
    }

    .cloud--2 {
        left: 44%;
    }

    .cloud--3 {
        left: 66%;
    }

    .cloud--4 {
        left: 88%;
    }
}
