/* Cascade layers: responsive overrides live in "screens", which beats
   "base" regardless of order or specificity. Tokens, registered properties
   and keyframes stay unlayered. */
@layer base, screens;

:root {
    --blue-light: #4a9be8;
    --blue-dark: #0b3d91;
    --yellow: #ffd43b;
    --yellow-dark: #9c6f14;
    --beige: #fbf6e6;
    --beige-dark: #d5d1c4;
    --grey-dark: #222;
    --grey: #666;
    --grey-light: #aaa;
    --red: #d6322a;
    --green: #2ecc40;
    --brown-light: #c9ab82;
    --brown: #a9865a;
    --brown-dark: #6e5333;
    --shadow: color-mix(in srgb, black 35%, transparent);
    /* Shared fill for everything blue that sits on the page: slightly
       translucent so the background shows through. */
    --blue-fill: linear-gradient(
        160deg,
        color-mix(in srgb, color-mix(in srgb, var(--blue-dark), var(--blue-light) 30%) 90%, transparent),
        color-mix(in srgb, var(--blue-dark) 90%, transparent));
    --font: "Trebuchet MS", "Helvetica Neue", Arial, sans-serif;
    /* The serif is reserved for the C4 mark: logo, card monogram, and the 4 in the title. */
    --font-mark: Georgia, "Times New Roman", serif;
    --header-panels-width: 220px;
    --space-xs: 4px;
    --space-s: 8px;
    --space-m: 16px;
    --space-l: 32px;
    --radius-large: 20px;
    --radius: 12px;
    /* The dark ring inside every frame. Framed elements pad by a spacing
       token plus the ring, so spacings are measured from the ring's inner edge. */
    --ring: 2px;
    --text-small: 12px;
    --text-base: 16px;
    --text-medium: 20px;
    --text-large: 28px;
    --text-display: clamp(32px, 7vw, 56px);
    --text-symbol: clamp(40px, 10vw, 80px);
}

/* While playing on a touch device the document is locked and parked on a
   bleed above the app, with a second bleed below: mobile Safari only shows
   page pixels behind its bars when the page is scrolled onto them. */
:root {
    --top-bleed: 0px;
    --bottom-bleed: 0px;
}

@property --drained {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 0%;
}

@keyframes fade-in {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(6px); }
    60% { transform: translateX(-4px); }
    80% { transform: translateX(4px); }
}

@keyframes pulse {
    from {
        opacity: 1;
    }

    to {
        opacity: 0.4;
    }
}

@layer base {
    /* Text styles: one font, two running weights, five sizes. Everything on the
       three screens is one of these; the logo and card monogram are the only
       marks outside the scale. */

    .text-display {
        font-size: var(--text-display);
        line-height: 1;
        font-weight: 900;
        color: white;
        text-shadow: 2px 3px 0 var(--blue-dark), 0 6px 14px var(--shadow);
    }

    /* Line boxes trimmed to cap height and baseline, so spacing from rings and
       rules measures to the glyphs rather than to the line box. Form controls
       keep their native boxes so the name field and its button stay level. */
    .text-caption,
    .text-label,
    .text-body,
    .text-strong,
    .text-number,
    .text-big-number,
    .text-heading,
    .text-subheading,
    .entry-theme {
        text-box: trim-both cap alphabetic;
    }

    .primary-button,
    .name-input {
        text-box: normal;
    }

    /* An emoji shown on its own: the trap warning. */
    .text-symbol {
        font-size: var(--text-symbol);
        line-height: 1;
    }

    .text-heading {
        font-size: var(--text-display);
        line-height: 1.1;
        font-weight: 700;
        color: var(--yellow);
        text-shadow: 2px 2px 0 var(--yellow-dark);
    }

    /* Smaller heading for the labels on the bonus lines. */
    .text-subheading {
        font-size: var(--text-medium);
        line-height: 1.1;
        font-weight: 700;
        color: var(--yellow);
        text-shadow: 1px 1px 0 var(--yellow-dark);
    }

    .text-caption {
        font-size: var(--text-small);
        font-weight: 400;
        letter-spacing: 1px;
        text-transform: uppercase;
    }

    .text-label {
        font-size: var(--text-base);
        font-weight: 700;
        color: var(--grey);
    }

    .text-body {
        font-size: var(--text-base);
        font-weight: 400;
    }

    .text-strong {
        font-size: var(--text-base);
        font-weight: 700;
    }

    .text-number {
        font-size: var(--text-medium);
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        color: var(--grey-dark);
    }

    .text-big-number {
        font-size: var(--text-large);
        font-weight: 700;
        font-variant-numeric: tabular-nums;
    }

    * {
        box-sizing: border-box;
        /* Quick successive taps must flip cards, never double-tap zoom. */
        touch-action: manipulation;
    }

    /* The canvas colour matches the top of the gradient, so Safari's status bar
       area blends with the page; once scrolled past the midpoint it switches to
       the bottom colour so the bounce area at the end blends too. */
    html {
        margin: 0;
        min-height: 100%;
        background-color: var(--blue-light);
    }

    html.scrolled-past-half {
        background-color: var(--blue-dark);
    }

    body {
        margin: 0;
        padding-top: var(--top-bleed);
        padding-bottom: var(--bottom-bleed);
        min-height: 100dvh;
        box-sizing: content-box;
        font-family: var(--font);
        color: var(--beige);
        background-image:
            radial-gradient(circle at 20% 30%, color-mix(in srgb, white 10%, transparent) 0 6px, transparent 7px),
            radial-gradient(circle at 70% 60%, color-mix(in srgb, white 8%, transparent) 0 9px, transparent 10px),
            radial-gradient(circle at 45% 80%, color-mix(in srgb, white 6%, transparent) 0 4px, transparent 5px),
            radial-gradient(circle at 85% 20%, color-mix(in srgb, white 7%, transparent) 0 5px, transparent 6px),
            linear-gradient(180deg, var(--blue-light), var(--blue-dark));
        background-size: 160px 160px, 220px 220px, 130px 130px, 190px 190px, 100% 100%;
        -webkit-user-select: none;
        user-select: none;
        -webkit-tap-highlight-color: transparent;
    }

    #app {
        min-height: 100dvh;
        padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    }

    html.playing #app {
        height: 100dvh;
        overflow: hidden;
        /* The app shell swallows pan gestures so the document stays put on its bleed. */
        touch-action: none;
    }

    .screen {
        min-height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: var(--space-l);
        padding: var(--space-m);
    }

    .hidden {
        display: none !important;
    }

    /* Built like the logo (top-aligned boxes at 0.72 line-height) so the 4 sits
       exactly as it does there; the margin restores the box height of a
       line-height of 1 so spacing around the title is unchanged. */
    .title {
        display: flex;
        align-items: flex-start;
        line-height: 0.72;
        margin: 0.14em 0;
    }

    .title-digit {
        font-family: var(--font-mark);
        font-size: 0.75em;
    }

    /* Category screen: scrolls, themes above the leaderboard on phones and
       side by side on wide screens */

    #category-screen {
        justify-content: flex-start;
        padding: var(--space-l);
    }

    /* Themes and leaderboard share one column width, so their edges line up. */
    .home-content {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-l);
        width: min(100%, 480px);
    }

    .home-themes {
        width: 100%;
    }

    #home-leaderboard {
        width: 100%;
    }

    .category-grid {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: clamp(var(--space-m), 3vw, var(--space-l));
        width: 100%;
    }

    .category-tile {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: var(--space-s);
        padding: 0;
        border: none;
        background: none;
        color: var(--beige);
        font: inherit;
        cursor: pointer;
    }

    .category-tile .frame {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        aspect-ratio: 1;
        container-type: inline-size;
        border: 4px solid var(--blue-light);
        border-radius: var(--radius);
        background: var(--blue-fill);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
        box-shadow: 0 6px 14px var(--shadow);
        transition: transform var(--duration-quick);
    }

    .category-tile:active .frame,
    .category-tile:hover .frame {
        transform: scale(1.05);
    }

    /* The blurred frame paints in its own layer, above plain text; the name
       needs a layer of its own to sit above the frame's shadow. */
    .category-name {
        position: relative;
    }

    /* The symbol scales with the tile: half its width. */
    .category-tile .sample {
        font-size: 50cqi;
        line-height: 1;
    }

    /* Game screen */

    #game-screen {
        position: relative;
        height: 100%;
        justify-content: flex-start;
        gap: var(--space-m);
        padding: var(--space-m);
    }

    .game-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--space-m);
        width: 100%;
        flex-shrink: 0;
    }

    .header-panels {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-s);
        width: var(--header-panels-width);
    }

    /* The board is centered on the whole screen, with the header laid over it.
       Side padding keeps the board clear of the panel column. */
    .board-area {
        position: absolute;
        inset: var(--space-m);
        padding: 0 calc(var(--header-panels-width) + var(--space-m));
        display: flex;
        align-items: center;
        justify-content: center;
        container-type: size;
    }

    .game-header {
        position: relative;
        z-index: 1;
        pointer-events: none;
    }

    .board {
        --columns: 4;
        --rows: 3;
        --aspect: 1;
        display: grid;
        grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
        gap: 2cqmin;
        width: min(100cqw, calc(100cqh * var(--aspect)));
        aspect-ratio: var(--aspect);
    }

    .card {
        position: relative;
        padding: 0;
        border: none;
        background: none;
        aspect-ratio: 3 / 4;
        perspective: 800px;
        cursor: pointer;
        font: inherit;
        transition: transform var(--duration-short) cubic-bezier(0.34, 1.56, 0.64, 1), opacity var(--duration-quick) ease;
    }

    .card.undealt {
        transform: scale(0.5);
        opacity: 0;
        transition: transform var(--duration-short) ease-in, opacity var(--duration-quick) ease;
    }

    /* Like the original: cards open and close instantly, no flip animation. */
    .card-inner {
        position: absolute;
        inset: 0;
        transform-style: preserve-3d;
    }

    .card.up .card-inner {
        transform: rotateY(180deg);
    }

    .card-face {
        position: absolute;
        inset: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        /* Cards are sized by the board, so their corners and borders scale with it. */
        border-radius: 2cqmin;
        backface-visibility: hidden;
        -webkit-backface-visibility: hidden;
        box-shadow: 0 4px 10px var(--shadow);
    }

    .card-back {
        background: linear-gradient(160deg, var(--brown-light), var(--brown));
        border: 0.8cqmin solid var(--brown-light);
        box-shadow: inset 0 0 0 var(--ring) var(--brown-dark), 0 4px 10px var(--shadow);
    }

    /* The card back carries the logo, embossed in the wood. */
    .logo.monogram {
        font-size: 11cqmin;
        color: var(--brown-dark);
        text-shadow: 1px 1px 0 var(--brown-light);
    }

    .card-front {
        background: linear-gradient(160deg, white, var(--beige));
        border: 0.8cqmin solid var(--beige-dark);
        transform: rotateY(180deg);
    }

    .card.trap .card-front,
    .card.wrong .card-front {
        border-color: color-mix(in srgb, var(--red), white 55%);
    }

    .card.trap .card-front {
        background: radial-gradient(circle, color-mix(in srgb, var(--red), white 25%), color-mix(in srgb, var(--red), black 35%) 75%);
    }

    .picture {
        font-size: 15cqmin;
        line-height: 1;
    }

    .card.matched .card-front {
        border-color: var(--yellow);
    }

    .card.matched {
        cursor: default;
    }

    /* Header panels */

    .panel {
        padding: calc(var(--space-s) + var(--ring)) calc(var(--space-m) + var(--ring));
        border-radius: var(--radius);
        background: linear-gradient(160deg, white, var(--beige));
        border: 4px solid var(--yellow);
        box-shadow: inset 0 0 0 var(--ring) var(--yellow-dark), 0 6px 14px var(--shadow);
        color: var(--grey-dark);
    }

    .panel-row {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: var(--space-m);
    }

    .score-panel {
        padding: calc(var(--space-m) + var(--ring));
    }

    .panel-title {
        width: fit-content;
        margin: 0 auto var(--space-m);
        color: var(--grey);
        text-align: center;
    }

    /* A rule under every box title, as wide as the title itself. */
    .panel-title::after {
        content: '';
        display: block;
        height: var(--ring);
        margin-top: var(--space-xs);
        border-radius: 1px;
        background: var(--yellow);
    }

    /* The fill is painted as the panel's own background, underneath the inset
       ring, so frame and fill share one corner and no seam can appear. The
       fill is one solid colour that runs green, yellow, red as time drains, and
       the beige layer covers it from the left with a hard stop. */
    .clock-panel {
        --warming: calc(min(var(--drained) * 2, 100%));
        --burning: calc(max((var(--drained) - 50%) * 2, 0%));
        --clock-colour: color-mix(in srgb, color-mix(in srgb, var(--green), var(--yellow) var(--warming)), var(--red) var(--burning));
        height: 22px;
        padding: 0;
        background:
            linear-gradient(90deg, var(--beige) var(--drained), transparent 0),
            var(--clock-colour);
    }

    /* Only the refill at the start of a round is eased; live ticks are instant. */
    .clock-panel.refilling {
        transition: --drained var(--duration-short) ease-out;
    }

    /* The logo takes the width left of the panels and centres itself in it. */
    .logo {
        display: flex;
        flex: 1;
        justify-content: center;
        align-items: flex-start;
        font-family: var(--font-mark);
        font-size: 64px;
        font-weight: 900;
        line-height: 0.72;
        color: white;
        text-shadow: 2px 3px 0 var(--blue-dark), 0 6px 14px var(--shadow);
    }

    .logo-letter {
        font-size: 1em;
    }

    .logo-digit {
        font-size: 0.75em;
        margin-left: -0.4em;
    }

    .quit-button {
        position: absolute;
        right: var(--space-m);
        bottom: var(--space-m);
        z-index: 3;
        width: 36px;
        height: 36px;
        border: 2px solid var(--blue-light);
        border-radius: 50%;
        background: var(--blue-fill);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
        color: var(--beige);
        font: inherit;
        cursor: pointer;
    }

    /* On the scrolling game-over screen the close button pins to the viewport. */
    .gameover-close {
        position: fixed;
        right: calc(var(--space-m) + env(safe-area-inset-right));
        bottom: calc(var(--space-m) + env(safe-area-inset-bottom));
    }

    /* A larger hit area around the small button, reaching the screen corner. */
    .quit-button::before {
        content: '';
        position: absolute;
        inset: calc(-1 * var(--space-m));
    }

    /* Popups */

    .overlay {
        position: absolute;
        inset: 0;
        z-index: 2;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        visibility: hidden;
        transition: visibility 0s linear var(--duration-quick);
    }

    .overlay.open {
        visibility: visible;
        transition: visibility 0s;
    }

    .popup {
        width: min(80%, 420px);
        padding: var(--space-l) var(--space-l) var(--space-m);
        border-radius: var(--radius-large);
        border: 4px solid var(--blue-light);
        background: var(--blue-fill);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
        box-shadow: 0 10px 30px var(--shadow);
        text-align: center;
        opacity: 0;
        transform: scale(0.8);
        transition:
            opacity var(--duration-quick) ease,
            transform var(--duration-quick) ease-in;
    }

    .overlay.open .popup {
        opacity: 1;
        transform: scale(1);
        transition:
            opacity var(--duration-quick) ease,
            transform var(--duration-short) cubic-bezier(0.34, 1.56, 0.64, 1);
    }

    .popup h2 {
        margin: 0 0 var(--space-l);
    }

    .popup p {
        margin: 0;
    }

    .popup p + p {
        margin-top: var(--space-l);
    }

    /* The hint fades in, then pulses. */
    .popup .tap-hint {
        margin-top: var(--space-l);
        color: color-mix(in srgb, var(--beige) 75%, transparent);
        animation:
            fade-in var(--duration-medium) ease forwards,
            pulse var(--duration-long) ease-in-out var(--duration-medium) infinite alternate;
    }

    .popup .tap-hint.pending {
        visibility: hidden;
        animation: none;
    }

    /* A zero bonus shakes its head. */
    .bonus-line .shaking {
        display: inline-block;
        animation: shake var(--duration-medium) ease;
    }

    .bonus-line {
        display: flex;
        flex-direction: column;
        gap: var(--space-m);
    }

    /* The separator gets the same breathing room above and below. */
    .bonus-line + .bonus-line {
        margin-top: var(--space-l);
        padding-top: var(--space-l);
        border-top: 2px solid color-mix(in srgb, white 25%, transparent);
    }

    /* Game over */

    #gameover-screen {
        justify-content: flex-start;
        padding: var(--space-l);
    }

    .score-form {
        display: flex;
        gap: var(--space-s);
        width: min(100%, 420px);
    }

    .name-input {
        flex: 1;
        min-width: 0;
        padding: calc(var(--space-s) + var(--ring)) calc(var(--space-m) + var(--ring));
        border: 4px solid var(--yellow);
        border-radius: var(--radius);
        background: white;
        box-shadow: inset 0 0 0 var(--ring) var(--yellow-dark), 0 6px 14px var(--shadow);
        color: var(--grey-dark);
        font-family: inherit;
    }

    .name-input:focus {
        outline: none;
    }

    .name-input.invalid {
        color: var(--red);
    }

    .primary-button:disabled {
        opacity: 0.5;
        cursor: default;
    }

    /* Cells carry half the column and row gaps as padding, so the box pads
       less on the sides and the bottom to land the text at one spacing from
       the ring; the own-row band sits 8px inside the ring all round, square
       cornered, which is what concentric means at that inset. */
    .leaderboard {
        width: min(100%, 420px);
        padding:
            calc(var(--space-m) + var(--ring))
            calc(var(--space-s) + var(--ring))
            calc(var(--space-m) - var(--space-s) + var(--ring));
        border-radius: var(--radius);
        background: linear-gradient(160deg, white, var(--beige));
        border: 4px solid var(--yellow);
        box-shadow: inset 0 0 0 var(--ring) var(--yellow-dark), 0 6px 14px var(--shadow);
        color: var(--grey-dark);
    }

    .leaderboard-table {
        width: 100%;
        border-collapse: separate;
        border-spacing: 0;
        font-variant-numeric: tabular-nums;
    }

    .leaderboard-table th,
    .leaderboard-table td {
        padding: var(--space-s);
        vertical-align: middle;
    }

    .leaderboard-table th {
        padding-top: 0;
        padding-bottom: var(--space-s);
        text-align: left;
        color: var(--grey-light);
    }

    /* Rank, theme, level and score hug their content; the name takes the rest. */
    .leaderboard-table th:nth-child(1),
    .leaderboard-table th:nth-child(2),
    .leaderboard-table th:nth-child(4),
    .leaderboard-table th:nth-child(5) {
        width: 1px;
        white-space: nowrap;
    }

    .leaderboard-table th:nth-child(4),
    .leaderboard-table th:nth-child(5),
    .entry-rank,
    .entry-level,
    .entry-score {
        text-align: right;
    }

    .leaderboard-table tr.own td {
        background: color-mix(in srgb, var(--yellow) 30%, transparent);
    }

    .leaderboard-table tr.empty td,
    .leaderboard-table tr.gap td {
        color: var(--grey-light);
    }

    /* Separates the top ten from the player's own row below them. */
    .leaderboard-table tr.gap td {
        text-align: center;
    }

    .entry-rank,
    .entry-name {
        color: var(--grey);
    }

    .entry-theme {
        text-align: center;
        font-size: var(--text-medium);
        line-height: 1;
    }

    .entry-name {
        max-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .visually-hidden {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .primary-button {
        padding: calc(var(--space-s) + var(--ring)) var(--space-m);
        border: 4px solid var(--blue-light);
        border-radius: var(--radius);
        background: var(--blue-fill);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
        box-shadow: 0 6px 14px var(--shadow);
        color: var(--beige);
        font-family: inherit;
        cursor: pointer;
    }
}

@layer screens {
    @media (pointer: coarse) {
        html.playing {
            --top-bleed: 80px;
            --bottom-bleed: 160px;
        }
    }

    @media (min-aspect-ratio: 1 / 1) {
        .home-content {
            flex-direction: row;
            align-items: flex-start;
            justify-content: center;
            gap: var(--space-l);
            width: 100%;
        }

        .home-themes {
            width: min(100%, 640px);
        }

        #home-leaderboard {
            width: 320px;
            flex-shrink: 0;
        }

    }

    /* Portrait phones: the same header, with the board pushed down into thumb
       reach and kept clear of the close button in the corner. */

    @media (max-aspect-ratio: 1 / 1) {
        .board-area {
            position: relative;
            inset: auto;
            padding: 0 0 calc(2 * var(--space-l));
            flex: 1;
            width: 100%;
            min-height: 0;
            align-items: flex-end;
        }

        .category-grid {
            grid-template-columns: repeat(3, minmax(0, 1fr));
        }
    }

    /* Landscape game screen: the logo keeps its corner, the screen breathes more
       at the edges, and the board and close button follow that inset. */
    @media (min-aspect-ratio: 1 / 1) {
        .game-header {
            align-items: flex-start;
        }

        .game-header .logo {
            flex: initial;
            justify-content: flex-start;
        }

        #game-screen {
            padding: var(--space-l);
        }

        .board-area {
            inset: var(--space-l);
            padding: 0 calc(var(--header-panels-width) + var(--space-l));
        }

        .quit-button {
            right: var(--space-l);
            bottom: var(--space-l);
        }
    }
}
