:root {
    --sky: #8ccff0;
    --sky-light: #c8ecf8;
    --soil: #6e4028;
    --soil-dark: #4a2a1e;
    --leaf: #2e7a34;
    --leaf-dark: #1d4a2c;
    --outline: #2a1620;
    --sky-top: #0b0820;
    --sky-bottom: #2a1440;
    --text: #f6e7d0;
    --accent: #ff8a1f;
    --ok: #6bd968;
    --gold: #ffd860;
    --cream: #fff1c4;
    --bad: #e65c5c;
    --wait: #f8a535;
    --pixel-font: ui-monospace, 'Cascadia Mono', Consolas, 'Courier New', monospace;
    --emoji-size: clamp(36px, 6vw, 72px);
}

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

html,
body {
    height: 100%;
    margin: 0;
}

body {
    font: 14px/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
    color: var(--text);
    background: linear-gradient(180deg, var(--sky-top), var(--sky-bottom));
    overflow: hidden;
}

/* The ritual patch: a full-screen canvas under absolutely placed DOM buttons and the HUD. */
.patch {
    position: relative;
    container: patch / size;
    width: 100%;
    height: 100%;
    overflow: hidden;
    /* Seen only without a canvas: sky strip over soil. */
    background: linear-gradient(180deg, var(--sky) 0 12%, var(--leaf) 12% 13%, var(--soil) 13%);
}

.scene-canvas {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    image-rendering: pixelated;
}

/* Someone else's walker under the pointer in the cursed world: a click clinks glasses with it (client.js, bindClinking). */
.patch[data-clink-hover] {
    cursor: pointer;
}

/*
 * Each element is a transparent hit zone over its sprite. The scene publishes the sprite box per size in CSS
 * pixels (--hit-*-{size}, --hit-*-bonfire); without a canvas the button is a centred emoji instead.
 */
.pumpkin,
.bonfire,
.circle {
    --w: var(--emoji-size);
    --h: var(--emoji-size);
    --ox: -50%;
    --oy: -50%;
    /* Floating pumpkins carry their hit zone up with them (--float-lift comes from the scene). */
    --lift: 0px;
    position: absolute;
    /*
     * --x / --y come from the config; --spread widens the patch on narrow screens (public/js/layout.js); --out pushes
     * the lit pumpkins away from the root (ROOT and jumpOut in layout.js), the bonfire sits on the root and stays.
     */
    left: calc(50% + (var(--x) - 50) * var(--spread, 1) * var(--out, 1) * 1%);
    top: calc((var(--root-y, 63) + (var(--y) - var(--root-y, 63)) * var(--out, 1)) * 1%);
    width: var(--w);
    height: var(--h);
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font-size: calc(var(--emoji-size) * 0.85);
    line-height: 1;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transform: translate(var(--ox), calc(var(--oy) - var(--lift)));
    /* The jump out takes as long as the sprites' hop (pixel/scene.js, JUMP_MS). */
    transition: left 0.6s ease-out, top 0.6s ease-out;
}

.pumpkin[data-float] {
    --lift: var(--float-lift, 0px);
}

.pumpkin[data-size="s"] {
    --emoji-size: clamp(28px, 4.5vw, 54px);
}

.pumpkin[data-size="l"] {
    --emoji-size: clamp(44px, 7.5vw, 90px);
}

.has-canvas .pumpkin {
    --w: var(--hit-w-m);
    --h: var(--hit-h-m);
    --ox: var(--hit-x-m);
    --oy: var(--hit-y-m);
}

.has-canvas .pumpkin[data-size="s"] {
    --w: var(--hit-w-s);
    --h: var(--hit-h-s);
    --ox: var(--hit-x-s);
    --oy: var(--hit-y-s);
}

.has-canvas .pumpkin[data-size="l"] {
    --w: var(--hit-w-l);
    --h: var(--hit-h-l);
    --ox: var(--hit-x-l);
    --oy: var(--hit-y-l);
}

.has-canvas .bonfire {
    --w: var(--hit-w-bonfire);
    --h: var(--hit-h-bonfire);
    --ox: var(--hit-x-bonfire);
    --oy: var(--hit-y-bonfire);
}

.has-canvas .circle {
    --w: var(--hit-w-circle);
    --h: var(--hit-h-circle);
    --ox: var(--hit-x-circle);
    --oy: var(--hit-y-circle);
}

.has-canvas .pumpkin__emoji,
.has-canvas .element__emoji {
    visibility: hidden;
}

/* Locked (the bonfire until every pumpkin is done, the circle outside finale step 0): it looks inert, but stays in
   the tab order and says why. */
.bonfire[data-locked],
.circle[data-locked] {
    cursor: not-allowed;
}

/*
 * The day has no bonfire yet (the root and its foliage are there instead), the final scene none any more (the ash pit
 * takes its place); the circle exists only in the final scene (docs/spec/scenario.md). An element of an unknown type
 * is not drawn at all. The bar has no patch at all: hidden buttons take no clicks and no focus.
 */
body[data-scene="1"] .bonfire,
body[data-bar] .pumpkin,
body[data-bar] .bonfire,
body[data-bar] .circle,
body[data-final] .bonfire,
body:not([data-final]) .circle,
.element {
    visibility: hidden;
}

.pumpkin:focus-visible,
.bonfire:focus-visible,
.circle:focus-visible {
    outline: calc(var(--px, 2px) * 1) dashed var(--gold);
    outline-offset: calc(var(--px, 2px) * 2);
}

.bonfire[data-locked]:focus-visible,
.circle[data-locked]:focus-visible {
    outline-color: var(--cream);
}

/* The object buttons' ring is for Tab only: the browser shows `:focus-visible` for Space after a mouse click too, and
   on them Space is the drink or the roll. `data-kbd` on <html> — bindObjectKeys in client.js. */
:root:not([data-kbd]) :is([data-element], .bar-counter, .roadrunner, .franken, .rr-meep):focus-visible {
    outline: none;
}

@media (prefers-reduced-motion: reduce) {
    .pumpkin,
    .bonfire,
    .circle,
    .boss-hp__fill {
        transition: none;
    }
}

/* Fallback view only: the canvas animates these states itself. */
.patch:not(.has-canvas) .pumpkin[data-ready] .pumpkin__emoji,
.patch:not(.has-canvas) .bonfire[data-ready] .element__emoji,
.patch:not(.has-canvas) .circle[data-ready] .element__emoji {
    display: inline-block;
    filter: drop-shadow(0 0 6px var(--gold));
}

.patch:not(.has-canvas) .pumpkin[data-done],
.patch:not(.has-canvas) .bonfire[data-locked],
.patch:not(.has-canvas) .circle[data-locked] {
    opacity: 0.6;
}

/*
 * The bar's counter (scene 0): a transparent hit zone over the counter and its mugs. The scene publishes the box in CSS
 * pixels (--counter-*); without a canvas it is a mug emoji at the counter's usual spot.
 */
.bar-counter {
    position: absolute;
    left: var(--counter-x, 64%);
    top: var(--counter-y, 34%);
    width: var(--counter-w, 30%);
    height: var(--counter-h, 16%);
    z-index: 400;
    padding: 0;
    border: 0;
    background: none;
    font-size: clamp(28px, 5vw, 56px);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.has-canvas .bar-counter__emoji {
    visibility: hidden;
}

.bar-counter[aria-disabled="true"] {
    cursor: default;
}

.bar-counter:focus-visible {
    outline: calc(var(--px, 2px) * 1) dashed var(--gold);
    outline-offset: calc(var(--px, 2px) * 2);
}

/*
 * RoadRunner behind the counter after the dawn: a transparent hit zone over his body above the counter (--rr-*, from
 * the scene), above the counter's button; without a canvas, a bird emoji next to the owl's usual spot.
 */
.roadrunner {
    position: absolute;
    left: var(--rr-x, 70%);
    top: var(--rr-y, 30%);
    width: var(--rr-w, 8%);
    height: var(--rr-h, 12%);
    z-index: 401;
    padding: 0;
    border: 0;
    background: none;
    font-size: clamp(24px, 4vw, 44px);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.has-canvas .roadrunner__emoji {
    visibility: hidden;
}

.roadrunner[aria-disabled="true"] {
    cursor: default;
}

.roadrunner:focus-visible {
    outline: calc(var(--px, 2px) * 1) dashed var(--gold);
    outline-offset: calc(var(--px, 2px) * 2);
}

/* Link to the "how it works" page: a small pumpkin with a question mark, not a game element. */
.help-link {
    position: absolute;
    top: 12px;
    left: 12px;
    /* Above the pumpkin buttons, whose z-index follows their y (0..1000). */
    z-index: 1002;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    font-size: 26px;
    line-height: 1;
    text-decoration: none;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--text), 0 0 0 4px var(--outline);
}

.help-link:hover,
.help-link:focus-visible {
    background: var(--soil-dark);
}

.help-link:focus-visible {
    outline: 2px dashed var(--accent);
    outline-offset: 6px;
}

.help-link__mark {
    position: absolute;
    right: -6px;
    bottom: -6px;
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    background: var(--gold);
    color: var(--outline);
    font: 700 13px/1 var(--pixel-font);
    box-shadow: 0 0 0 2px var(--outline);
}

/* Sound controls under the help link (public/js/sound.js, bindSoundControls): narrow, so the moderator's console on
   the right never reaches them. Icons are drawn in CSS boxes, not emoji, to stay pixel. */
.sound-panel {
    position: absolute;
    top: 68px;
    left: 12px;
    z-index: 1002;
    display: grid;
    grid-template-columns: 30px 30px;
    gap: 8px;
    width: 68px;
    padding: 6px 0 0;
}

.sound-panel[hidden] {
    display: none;
}

.sound-panel__button {
    position: relative;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    color: var(--gold);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--text), 0 0 0 4px var(--outline);
    font: 700 16px/1 var(--pixel-font);
    cursor: pointer;
}

.sound-panel__button:hover {
    background: var(--soil-dark);
}

.sound-panel__button:focus-visible,
.sound-panel__volume:focus-visible {
    outline: 2px dashed var(--accent);
    outline-offset: 5px;
}

.sound-panel__button--sound::before {
    content: '';
    position: absolute;
    left: 6px;
    top: 8px;
    width: 12px;
    height: 14px;
    background: currentColor;
    clip-path: polygon(0 30%, 34% 30%, 100% 0, 100% 100%, 34% 70%, 0 70%);
}

.sound-panel__button--sound::after {
    content: ')';
    position: absolute;
    right: 4px;
    top: 7px;
}

.sound-panel__button--music::before {
    content: '♪';
    font-size: 20px;
}

.sound-panel__button[aria-pressed="false"] {
    color: var(--text);
    opacity: 0.75;
}

.sound-panel__button--sound[aria-pressed="false"]::after {
    content: '×';
    color: var(--accent);
}

.sound-panel__button--music[aria-pressed="false"]::after {
    content: '';
    position: absolute;
    left: 4px;
    right: 4px;
    top: 14px;
    height: 2px;
    background: var(--accent);
    transform: rotate(-45deg);
}

/* A pixel slider: a flat track and a square thumb. */
.sound-panel__volume {
    grid-column: 1 / -1;
    width: 68px;
    height: 16px;
    margin: 2px 0 0;
    background: transparent;
    appearance: none;
    cursor: pointer;
}

.sound-panel__volume::-webkit-slider-runnable-track {
    height: 6px;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--text);
}

.sound-panel__volume::-moz-range-track {
    height: 6px;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--text);
}

.sound-panel__volume::-webkit-slider-thumb {
    width: 10px;
    height: 14px;
    margin-top: -4px;
    border: 0;
    border-radius: 0;
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--outline);
    appearance: none;
}

.sound-panel__volume::-moz-range-thumb {
    width: 10px;
    height: 14px;
    border: 0;
    border-radius: 0;
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--outline);
}

/* Pixel panel: square corners and a stepped two-colour frame instead of rounded borders. */
.hud {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 12px;
    z-index: 1001;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 20px;
    width: fit-content;
    max-width: calc(100% - 32px);
    margin-inline: auto;
    padding: 8px 16px;
    font: 700 14px/1.3 var(--pixel-font);
    letter-spacing: 0.02em;
    color: var(--cream);
    background: var(--outline);
    box-shadow:
        0 0 0 2px var(--soil),
        0 0 0 4px var(--outline),
        0 4px 0 2px var(--outline);
    pointer-events: none;
}

.hud b {
    color: var(--gold);
}

.hud__scene-name {
    color: var(--sky-light);
}

/*
 * The connection lamp (client.js, paintStatus): a pixel bulb — green on the line, yellow blinking while it reconnects,
 * red without it; its words are in title and aria-label. Stepped blink, still under reduced motion.
 */
.hud__status {
    display: inline-block;
    align-self: center;
    width: 10px;
    height: 10px;
    margin: 0 2px;
    background: var(--bad);
    box-shadow: 0 0 0 2px var(--soil-dark), inset -2px -2px 0 rgb(0 0 0 / 0.25), inset 2px 2px 0 rgb(255 255 255 / 0.35);
    pointer-events: auto;
}

.hud__status[data-status="connected"] {
    background: var(--ok);
}

.hud__status[data-status="connecting"] {
    background: var(--gold);
    animation: lamp-blink 0.9s steps(1) infinite;
}

@keyframes lamp-blink {
    50% {
        background: var(--soil-dark);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hud__status[data-status="connecting"] {
        animation: none;
    }
}

/* RoadRunner's uptime beside the lamp from finale step 3: the twist, in the ok green of the reveal's uptime card. */
.hud__runner {
    color: var(--ok);
}

@container patch (max-width: 600px) {
    .hud {
        gap: 2px 14px;
        padding: 6px 10px;
        font-size: 12px;
    }
}

.error {
    display: grid;
    place-content: center;
    height: 100%;
    text-align: center;
}

.error__code {
    margin: 0;
    font-size: 96px;
}

.error a {
    color: var(--accent);
}

/* Debug panel (public/js/debug.js): top right, clear of the "?" link on the left. */
.debug {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 1003;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
    max-width: calc(100% - 88px);
    font: 700 12px/1 var(--pixel-font);
}

.debug[hidden] {
    display: none;
}

.debug__button,
.debug select {
    padding: 7px 9px;
    border: 0;
    font: inherit;
    color: var(--cream);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--soil), 0 2px 0 2px var(--outline);
    cursor: pointer;
}

.debug__button:hover {
    background: var(--soil-dark);
}

.debug__button:focus-visible,
.debug select:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 4px;
}

.debug__button[data-armed],
.debug__button[aria-pressed="true"] {
    color: var(--outline);
    background: var(--gold);
}

.debug__button:disabled {
    opacity: 0.6;
    cursor: progress;
}

@container patch (max-width: 600px) {
    .debug {
        gap: 4px;
        font-size: 11px;
    }

    .debug__button,
    .debug select {
        padding: 6px 7px;
    }
}

/* The moderator's console (public/js/debug.js): the debug panel as a framed column with a header that collapses it. */
.console {
    /* Over the reveal panel: the moderator steers the finale from under it. */
    z-index: 1005;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0;
    width: min(360px, calc(100% - 88px));
    max-height: calc(100% - 96px);
    color: var(--cream);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--soil), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    /* Its own compositor layer: over the constantly redrawn canvas, a console that shrank left a stale dark patch. */
    will-change: transform;
}

.console--closed {
    width: auto;
}

.console__toggle {
    display: flex;
    gap: 10px;
    align-items: baseline;
    justify-content: space-between;
    padding: 8px 10px;
    border: 0;
    font: inherit;
    color: var(--gold);
    text-align: left;
    background: none;
    cursor: pointer;
}

.console__toggle::after {
    content: '▾';
    color: var(--cream);
}

.console--closed .console__toggle::after {
    content: '▸';
}

.console__toggle:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: -4px;
}

/* «пауза» in the console's title (debug.js): the progress is paused — a gold pixel badge, seen folded too. */
.console__paused {
    padding: 0 5px;
    color: var(--outline);
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--soil-dark);
    text-transform: uppercase;
    font-size: 11px;
    letter-spacing: 0.08em;
}

.console__paused[hidden] {
    display: none;
}

.console__summary {
    flex: 1;
    color: var(--sky-light);
    font-weight: 400;
    white-space: nowrap;
}

.console__body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 4px 10px 12px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.console__body[hidden] {
    display: none;
}

.console__group {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}

.console__title {
    flex-basis: 100%;
    font-size: 11px;
    color: var(--accent);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.console .debug__button {
    box-shadow: 0 0 0 2px var(--soil);
    background: var(--soil-dark);
}

.console .debug__button:hover {
    background: var(--soil);
}

.console .debug__button[data-ready] {
    color: var(--outline);
    background: var(--ok);
}

.console .debug__button[data-armed],
.console .debug__button[aria-pressed="true"] {
    color: var(--outline);
    background: var(--gold);
}

.console .debug__button[data-note] {
    color: var(--cream);
    background: var(--bad);
}

.console__input {
    padding: 7px 8px;
    border: 0;
    font: inherit;
    color: var(--cream);
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--soil);
}

.console__input:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 2px;
}

/* The owl's quick menu: the lines of this scene or finale step (debug.js, paintMenu). */
.console__lines {
    display: flex;
    flex-basis: 100%;
    flex-wrap: wrap;
    gap: 6px;
}

.console__lines[hidden] {
    display: none;
}

.console__say {
    display: flex;
    flex-basis: 100%;
    gap: 6px;
}

.console__input {
    flex: 1;
    min-width: 0;
    font-weight: 400;
}

.console__k {
    display: flex;
    flex-basis: 100%;
    flex-wrap: wrap;
    gap: 6px;
    align-items: stretch;
}

.console__value {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 4.5em;
    color: var(--gold);
}

.console__input--k {
    flex: 1 0 4em;
    max-width: 7em;
}

.console__info {
    color: var(--sky-light);
    font-weight: 400;
    line-height: 1.3;
}

.console__info + .console__info::before {
    content: '· ';
}

@container patch (max-width: 600px) {
    .console {
        top: 8px;
        right: 8px;
        width: calc(100% - 80px);
        max-height: calc(100% - 120px);
    }

    .console--closed {
        width: auto;
    }

    .console .debug__button {
        padding: 8px 9px;
    }
}

/* The owl's speech bubble (public/js/owl.js), placed by script at the owl; the tail points at its head. */
.owl-bubble {
    position: absolute;
    /* Over the reveal panel: the owl explains its numbers. */
    z-index: 1004;
    max-width: min(320px, calc(100% - 16px));
    padding: 8px 12px;
    font: 700 14px/1.35 var(--pixel-font);
    color: var(--outline);
    background: var(--cream);
    box-shadow: 0 0 0 2px var(--outline), 0 0 0 4px var(--soil), 0 0 0 6px var(--outline);
    pointer-events: none;
}

.owl-bubble[hidden] {
    display: none;
}

.owl-bubble__text {
    margin: 0;
    overflow-wrap: anywhere;
}

/* Stepped tail: two stacked squares under the bubble at --tail-x. */
.owl-bubble::before,
.owl-bubble::after {
    content: '';
    position: absolute;
    left: var(--tail-x, 24px);
    background: var(--cream);
    box-shadow: 0 0 0 2px var(--outline);
}

.owl-bubble::before {
    top: calc(100% + 4px);
    width: 12px;
    height: 8px;
    transform: translateX(-50%);
}

.owl-bubble::after {
    top: calc(100% + 16px);
    width: 6px;
    height: 6px;
    transform: translateX(-50%);
}

.owl-bubble--below::before {
    top: auto;
    bottom: calc(100% + 4px);
}

.owl-bubble--below::after {
    top: auto;
    bottom: calc(100% + 16px);
}

.owl-bubble--free::before,
.owl-bubble--free::after {
    display: none;
}

@container patch (max-width: 600px) {
    .owl-bubble {
        font-size: 13px;
    }
}

/* Finale step 4 (public/js/reveal.js): the evening's numbers, big, on a pixel panel with a stepped gold frame. */
.reveal {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 1003;
    width: min(620px, calc(100% - 32px));
    max-height: calc(100% - 132px);
    overflow-y: auto;
    padding: 18px 22px 20px;
    font: 700 14px/1.35 var(--pixel-font);
    color: var(--cream);
    background: var(--outline);
    box-shadow:
        0 0 0 2px var(--gold),
        0 0 0 4px var(--outline),
        0 0 0 6px var(--soil),
        0 0 0 8px var(--outline),
        0 8px 0 6px var(--outline);
    transform: translate(-50%, -50%);
    /* Above the HUD's bottom edge on short screens. */
    margin-top: -24px;
}

.reveal[hidden] {
    display: none;
}

.reveal__kicker {
    margin: 0;
    font-size: 12px;
    color: var(--accent);
    text-transform: uppercase;
    letter-spacing: 0.16em;
}

.reveal__title {
    margin: 2px 40px 6px 0;
    font-size: 24px;
    line-height: 1.15;
    color: var(--gold);
    text-shadow: 2px 2px 0 var(--soil);
}

.reveal__lead {
    margin: 0 0 14px;
    font-weight: 400;
    color: var(--sky-light);
}

.reveal__grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin: 0;
}

/* A card: the number big on top, the caption under it, the mechanism in small print. */
.reveal__card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px 11px;
    background: #3a2230;
    box-shadow: inset 0 0 0 2px var(--soil-dark), inset 0 -4px 0 0 var(--soil-dark);
}

.reveal__card[hidden] {
    display: none;
}

.reveal__number {
    order: -1;
    margin: 0;
    font-size: 32px;
    line-height: 1.1;
    color: var(--gold);
    text-shadow: 2px 2px 0 var(--soil);
    font-variant-numeric: tabular-nums;
}

.reveal__label {
    margin: 0;
    color: var(--cream);
}

.reveal__note {
    margin: 0;
    font-size: 12px;
    font-weight: 400;
    color: var(--sky-light);
}

/* The punchline: the server's uptime across the whole width, in the green of a live connection. */
.reveal__card--uptime {
    grid-column: 1 / -1;
    background: #1f3326;
    box-shadow: inset 0 0 0 2px var(--ok), inset 0 -4px 0 0 #2d5a32;
}

.reveal__card--uptime .reveal__number {
    font-size: 36px;
    color: var(--ok);
    text-shadow: 2px 2px 0 #14261a;
}

.reveal__card--uptime .reveal__note {
    color: var(--cream);
}

.reveal__last {
    margin: 14px 0 12px;
    color: var(--sky-light);
}

.reveal__link {
    display: inline-block;
    padding: 8px 12px;
    color: var(--outline);
    text-decoration: none;
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--soil), 0 4px 0 0 var(--soil);
}

.reveal__link:hover,
.reveal__link:focus-visible {
    background: var(--accent);
}

.reveal__close {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 32px;
    height: 32px;
    border: 0;
    font: 700 20px/1 var(--pixel-font);
    color: var(--cream);
    background: var(--soil-dark);
    cursor: pointer;
}

.reveal__close:focus-visible {
    outline: 2px dashed var(--gold);
}

@container patch (max-width: 600px) {
    .reveal {
        width: calc(100% - 24px);
        max-height: calc(100% - 150px);
        padding: 14px 14px 16px;
    }

    .reveal__title {
        font-size: 19px;
    }

    .reveal__grid {
        gap: 8px;
    }

    .reveal__card {
        padding: 8px 10px 9px;
    }

    .reveal__number {
        font-size: 24px;
    }

    .reveal__card--uptime .reveal__number {
        font-size: 28px;
    }
}

@container patch (max-width: 380px) {
    .reveal__grid {
        grid-template-columns: 1fr;
    }
}

.hud__item[hidden] {
    display: none;
}

/* "Персонаж" in the HUD: the only part of the HUD that takes clicks. */
.hud__button {
    padding: 0 6px;
    border: 0;
    font: inherit;
    letter-spacing: inherit;
    color: var(--outline);
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--soil-dark);
    cursor: pointer;
    pointer-events: auto;
}

/* «Выпить»: the drink a phone has no Space for, so it stands out from the other HUD buttons. */
.hud__button--drink {
    background: var(--cream);
}

/* The language switch is a link to `?lang=`, drawn as a HUD button. */
.hud__button--lang {
    text-decoration: none;
}

.hud__button:hover {
    background: var(--cream);
}

/* «Выпить» while my clink, gulp or hand-over still plays. */
.hud__button:disabled {
    opacity: 0.55;
    cursor: default;
}

.hud__button:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 4px;
}

/* Join screen (public/js/join.js): a pixel panel like the HUD, over a dimmed patch. */
.join {
    width: min(460px, calc(100vw - 24px));
    max-height: calc(100dvh - 24px);
    padding: 0;
    border: 0;
    color: var(--cream);
    background: var(--outline);
    box-shadow:
        0 0 0 3px var(--soil),
        0 0 0 6px var(--outline),
        0 8px 0 4px var(--outline);
    font: 700 14px/1.3 var(--pixel-font);
    overflow: auto;
}

.join::backdrop {
    background: rgb(11 8 32 / 0.6);
}

.join__form {
    display: grid;
    gap: 14px;
    margin: 0;
    padding: 16px;
}

.join__title {
    margin: 0;
    font-size: 18px;
    color: var(--accent);
    text-align: center;
    text-shadow: 2px 2px 0 var(--soil-dark);
}

.join__body {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 14px;
    align-items: start;
}

/* 48 art pixels shown at 3x; a dark grass tile under the character so the preview is not floating in the void. */
.join__preview {
    width: 144px;
    height: 144px;
    image-rendering: pixelated;
    background:
        linear-gradient(180deg, transparent 80%, var(--leaf-dark) 80% 82%, var(--leaf) 82%),
        var(--sky-bottom);
    box-shadow: 0 0 0 2px var(--soil), 0 0 0 4px var(--soil-dark);
}

.join__fields {
    display: grid;
    gap: 6px;
    min-width: 0;
}

.join__label {
    color: var(--sky-light);
}

.join__name {
    width: 100%;
    padding: 7px 8px;
    border: 0;
    font: inherit;
    color: var(--outline);
    background: var(--cream);
    box-shadow: 0 0 0 2px var(--soil);
}

.join__name:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 4px;
}

.join__name[aria-invalid] {
    box-shadow: 0 0 0 2px var(--bad);
}

.join__error {
    min-height: 1.3em;
    margin: 0;
    font-size: 12px;
    color: var(--bad);
}

.join__parts {
    display: grid;
    gap: 4px;
}

.join__part {
    display: grid;
    grid-template-columns: 5.5em 28px 1fr 28px;
    align-items: center;
    gap: 4px;
}

.join__part-name {
    color: var(--sky-light);
    font-size: 12px;
}

.join__value {
    overflow: hidden;
    color: var(--gold);
    text-align: center;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.join__value--swatch::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
    vertical-align: 1px;
    background: var(--swatch, var(--gold));
    box-shadow: 0 0 0 2px var(--soil-dark);
}

.join__step,
.join__button {
    border: 0;
    font: inherit;
    color: var(--cream);
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--soil), 0 2px 0 2px var(--outline);
    cursor: pointer;
}

.join__step {
    height: 26px;
    padding: 0;
    font-size: 16px;
    line-height: 1;
}

.join__button {
    padding: 9px 14px;
    color: var(--outline);
    background: var(--accent);
}

.join__button--quiet {
    color: var(--cream);
    background: var(--soil-dark);
}

.join__step:hover,
.join__button--quiet:hover {
    background: var(--soil);
}

.join__button:not(.join__button--quiet):hover {
    background: var(--gold);
}

.join__step:focus-visible,
.join__button:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 3px;
}

.join__button:disabled {
    opacity: 0.6;
    cursor: progress;
}

.join__fields > .join__button {
    justify-self: start;
    margin-top: 4px;
}

.join__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 10px;
}

/* Phone width: the preview goes on top, centred, and the parts take the full width under it. */
@media (max-width: 480px) {
    .join__form {
        gap: 10px;
        padding: 12px;
    }

    .join__body {
        grid-template-columns: 1fr;
        gap: 10px;
    }

    .join__preview {
        justify-self: center;
        width: 120px;
        height: 120px;
    }

    .join__actions > .join__button {
        flex: 1;
    }
}

.console__group[hidden] {
    display: none;
}

/*
 * The bar's meter in the HUD (scene 0): a pixel glass filling with beer, a foam head on the level, and «Выпито» beside
 * it («Выпито 12 из 30» for the moderator); --fill (0–1) comes from client.js. Full — the foam runs over.
 */
.hud__drinks {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.hud__drinks[hidden] {
    display: none;
}

.hud__meter {
    position: relative;
    width: clamp(64px, 18vw, 120px);
    height: 10px;
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--cream);
    overflow: hidden;
}

.hud__meter-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: calc(var(--fill, 0) * 100%);
    background: linear-gradient(180deg, var(--cream) 0 3px, var(--gold) 3px);
    box-shadow: 2px 0 0 var(--cream);
}

.hud__drinks[data-full] .hud__meter-fill {
    box-shadow: none;
}

.hud__drinks[data-full] .hud__meter {
    box-shadow: 0 0 0 2px var(--gold);
}

/*
 * The rapier (docs/spec/frontend.md, «Рапира»). The goals of finale step 5 reuse the bar's meter: the mugs drunk with
 * the beer fill, the zombies slain with a green one beside a pixel skull.
 */
.hud__goal--zombies .hud__meter-fill {
    background: linear-gradient(180deg, #d8ffb0 0 3px, #7cc43c 3px);
    box-shadow: 2px 0 0 #d8ffb0;
}

.hud__goal--zombies[data-full] .hud__meter-fill {
    box-shadow: none;
}

/* The pumpkins' meter of scenes 1–3 fills orange under a gold rim. */
.hud__goal--pumpkins .hud__meter-fill {
    background: linear-gradient(180deg, var(--gold) 0 3px, var(--accent) 3px);
    box-shadow: 2px 0 0 var(--gold);
}

.hud__goal--pumpkins[data-full] .hud__meter-fill {
    box-shadow: none;
}

/* A pixel skull from gradient blocks in 2 px steps: the cranium, two eye holes and a toothed jaw. */
.hud__skull {
    position: relative;
    width: 14px;
    height: 14px;
    flex: none;
    background:
        linear-gradient(var(--outline), var(--outline)) 2px 4px / 4px 4px no-repeat,
        linear-gradient(var(--outline), var(--outline)) 8px 4px / 4px 4px no-repeat,
        linear-gradient(var(--outline), var(--outline)) 4px 10px / 2px 2px no-repeat,
        linear-gradient(var(--outline), var(--outline)) 8px 10px / 2px 2px no-repeat,
        linear-gradient(var(--cream), var(--cream)) 0 0 / 14px 10px no-repeat,
        linear-gradient(var(--cream), var(--cream)) 2px 10px / 10px 4px no-repeat;
}

/*
 * The button over FrankenPHP on the circle (a blow of the rapier): the scene publishes his sprite box in CSS pixels
 * (--hit-*-franken); without a canvas it is an emoji over the circle.
 */
.franken {
    --w: var(--emoji-size);
    --h: var(--emoji-size);
    --ox: -50%;
    --oy: -100%;
    position: absolute;
    left: 50%;
    top: calc(var(--root-y, 63) * 1%);
    z-index: 631;
    width: var(--w);
    height: var(--h);
    padding: 0;
    border: 0;
    background: none;
    font-size: calc(var(--emoji-size) * 0.85);
    line-height: 1;
    cursor: crosshair;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transform: translate(var(--ox), var(--oy));
}

.has-canvas .franken {
    --w: var(--hit-w-franken, 64px);
    --h: var(--hit-h-franken, 96px);
    --ox: var(--hit-x-franken, -50%);
    --oy: var(--hit-y-franken, -100%);
}

.has-canvas .franken__emoji {
    visibility: hidden;
}

.franken[aria-disabled="true"] {
    cursor: default;
}

.franken[hidden] {
    display: none;
}

.franken:focus-visible {
    outline: calc(var(--px, 2px) * 1) dashed var(--gold);
    outline-offset: calc(var(--px, 2px) * 2);
}

/*
 * FrankenPHP's health over his head (--boss-x / --boss-y from the scene, CSS pixels; without them at the top in the
 * middle): a pixel frame, the fill going from lime to red as it drains; the moderator gets a crisp «HP 57 / 90» under it.
 */
.boss-hp {
    --hp: 1;
    position: absolute;
    left: var(--boss-x, 50%);
    top: var(--boss-y, 120px);
    z-index: 900;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    font: 700 12px/1 var(--pixel-font);
    color: var(--cream);
    text-shadow: 0 2px 0 var(--outline), 2px 0 0 var(--outline), -2px 0 0 var(--outline), 0 -2px 0 var(--outline);
    transform: translate(-50%, -100%);
    pointer-events: none;
}

.boss-hp[hidden] {
    display: none;
}

.boss-hp__bar {
    position: relative;
    width: clamp(72px, 12vw, 120px);
    height: 8px;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--outline);
    overflow: hidden;
}

.boss-hp__fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: calc(var(--hp) * 100%);
    background: color-mix(in srgb, #a6e22e calc(var(--hp) * 100%), var(--bad));
    box-shadow: inset 0 2px 0 rgb(255 255 255 / 0.35);
    /* A strike only shortens the fill. */
    transition: width 0.25s ease-out;
}

.no-canvas .boss-hp {
    top: 120px;
    left: 50%;
}

/*
 * The magic word at the top in the middle, over the scene and under the console: «Молви слово», the field and
 * «Молвить»; a refusal is a note under it. The zombie worker's line takes its place.
 */
.word,
.word-zombie {
    position: absolute;
    top: 12px;
    left: 50%;
    z-index: 1003;
    max-width: min(440px, calc(100% - 32px));
    margin: 0;
    font: 700 14px/1.3 var(--pixel-font);
    color: var(--cream);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--gold), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    transform: translateX(-50%);
}

.word {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px 8px;
    width: min(440px, calc(100% - 32px));
    padding: 8px 10px;
}

.word[hidden],
.word-zombie[hidden] {
    display: none;
}

.word__label {
    grid-column: 1 / -1;
    color: var(--gold);
    letter-spacing: 0.04em;
}

.word__input {
    min-width: 0;
    padding: 7px 8px;
    border: 0;
    font: inherit;
    font-weight: 400;
    color: var(--cream);
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--soil);
}

.word__button {
    padding: 0 12px;
    border: 0;
    font: inherit;
    color: var(--outline);
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--soil-dark);
    cursor: pointer;
}

.word__button:hover {
    background: var(--cream);
}

.word__button:disabled {
    opacity: 0.6;
    cursor: progress;
}

.word__input:focus-visible,
.word__button:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 2px;
}

.word__note {
    grid-column: 1 / -1;
    min-height: 0;
    margin: 0;
    font-size: 12px;
    color: var(--bad);
}

.word__note:empty {
    display: none;
}

.word-zombie {
    width: max-content;
    padding: 8px 12px;
    color: #c8f0a0;
    box-shadow: 0 0 0 2px #7cc43c, 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
}

/* A phone: under the corner controls and the folded console. */
@container patch (max-width: 600px) {
    .word,
    .word-zombie {
        top: 60px;
        font-size: 13px;
    }

    .hud__goal .hud__meter {
        width: clamp(56px, 16vw, 120px);
    }
}

@container patch (max-width: 600px) {
    /* Without the scene's point the health bar sits under the word form. */
    .boss-hp {
        top: var(--boss-y, 200px);
    }
}

/*
 * The dice of finale step 1 at the top in the middle (docs/spec/frontend.md, «Кости»): the call to roll or the
 * winner, my own roll drawn big — three dice of inline-SVG pixels (dice.js), bouncing by whole art pixels (--dy, a
 * twelfth of a die) — and «Бросить».
 */
.dice {
    --die: 48px;
    position: absolute;
    top: 12px;
    left: 50%;
    z-index: 1003;
    display: grid;
    justify-items: center;
    gap: 8px;
    max-width: min(440px, calc(100% - 32px));
    padding: 8px 14px 10px;
    font: 700 14px/1.3 var(--pixel-font);
    color: var(--cream);
    text-align: center;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--gold), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    transform: translateX(-50%);
}

.dice[hidden],
.dice__faces[hidden],
.dice__roll[hidden] {
    display: none;
}

.dice__note {
    margin: 0;
    color: var(--gold);
    letter-spacing: 0.04em;
}

.dice__faces {
    display: flex;
    gap: calc(var(--die) / 4);
    padding-top: calc(var(--die) / 2);
}

.dice__face {
    display: block;
    width: var(--die);
    height: var(--die);
    transform: translateY(calc(var(--dy, 0) * var(--die) / 12));
}

.dice__face svg {
    display: block;
    width: 100%;
    height: 100%;
}

.dice__faces[data-dice-dim] .dice__face {
    opacity: 0.55;
    transition: opacity 0.4s steps(3);
}

/* 6-6-6: the dice shake by whole pixels while they flare red. */
.dice__faces[data-dice-win] .dice__face {
    animation: dice-shake 0.24s steps(1) infinite;
}

.dice__faces[data-dice-win] .dice__face:nth-child(2) {
    animation-delay: -0.08s;
}

.dice__faces[data-dice-win] .dice__face:nth-child(3) {
    animation-delay: -0.16s;
}

@keyframes dice-shake {
    0% { transform: translate(-2px, 0); }
    25% { transform: translate(2px, -2px); }
    50% { transform: translate(0, 2px); }
    75% { transform: translate(2px, 0); }
}

.dice__roll {
    padding: 6px 18px;
    border: 0;
    font: inherit;
    color: var(--outline);
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--soil-dark), 0 4px 0 0 var(--soil-dark);
    cursor: pointer;
}

.dice__roll:hover {
    background: var(--cream);
}

.dice__roll[aria-disabled="true"] {
    opacity: 0.5;
    cursor: default;
}

.dice__roll[aria-disabled="true"]:hover {
    background: var(--gold);
}

.dice__roll:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
    .dice__faces[data-dice-win] .dice__face {
        animation: none;
    }
}

/* A phone: under the corner controls and the folded console, like the word form. */
@container patch (max-width: 600px) {
    .dice {
        --die: 40px;
        top: 60px;
        font-size: 13px;
    }
}

/*
 * The moderator's hit zone over RoadRunner of the finale (--rr-meep-*, from the scene): shown only while he is on
 * screen (#app[data-rr-shown]) and the client lets it (the moderator, finale step 3+).
 */
.rr-meep {
    position: absolute;
    left: var(--rr-meep-x, 0);
    top: var(--rr-meep-y, 0);
    z-index: 640;
    display: none;
    width: var(--rr-meep-w, 0);
    height: var(--rr-meep-h, 0);
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

#app[data-rr-shown] .rr-meep:not([hidden]) {
    display: block;
}

.rr-meep:focus-visible {
    outline: calc(var(--px, 2px) * 1) dashed var(--gold);
    outline-offset: calc(var(--px, 2px) * 2);
}

/*
 * The evening's top shooters (docs/spec/frontend.md, «Топ стрелков»; client.js and dawn.js): in the top right corner,
 * over the sky or the bar's wall, clear of the counter, the patch and the circle; «место · имя · очки», my row gold.
 * Folded — the three leaders and my row, «весь топ ▾» under them. Presses go through it to the flyers behind; only the
 * toggle takes them.
 */
.dawn-top {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 1002;
    display: flex;
    flex-direction: column;
    width: 236px;
    padding: 8px 10px 10px;
    font: 700 13px/1.3 var(--pixel-font);
    color: var(--cream);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--gold), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    pointer-events: none;
}

.dawn-top[hidden],
.dawn-top__empty[hidden],
.dawn-top__row[hidden],
.dawn-top__toggle[hidden] {
    display: none;
}

/* The moderator's folded console holds the corner: the table stands under it. */
.patch:has(.console:not([hidden])) .dawn-top:not([data-compact]) {
    top: 64px;
}

/* The open console covers the right edge: the table steps out to its left, up in the corner again. */
.patch:has(.console:not([hidden]):not(.console--closed)) .dawn-top:not([data-compact]) {
    top: 16px;
    right: calc(min(360px, 100% - 88px) + 32px);
}

/* On a middling width the panels at the top in the middle reach the corner: the table goes under them — the magic word
   (440 px wide) below 960 px, the dice (about 270 px) below 800 px. */
@container patch (max-width: 960px) {
    .patch:has(.word:not([hidden]), .word-zombie:not([hidden])) .dawn-top:not([data-compact]) {
        top: 176px;
    }
}

@container patch (max-width: 800px) {
    .patch:has(.dice:not([hidden])) .dawn-top:not([data-compact]) {
        top: 176px;
    }
}

.dawn-top__title {
    margin: 0 0 6px;
    font-size: 12px;
    color: var(--gold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-shadow: 2px 2px 0 var(--soil);
}

/* A wide screen's «весь топ ▾» / «свернуть ▴»: small, under the rows, at the right. */
.dawn-top__toggle {
    order: 1;
    align-self: flex-end;
    display: flex;
    gap: 6px;
    margin: 6px 0 0;
    padding: 2px 0;
    border: 0;
    font: inherit;
    font-size: 11px;
    color: var(--sky-light);
    background: none;
    cursor: pointer;
    pointer-events: auto;
}

.dawn-top__toggle:hover {
    color: var(--gold);
}

.dawn-top__list {
    position: relative;
    display: grid;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
    /* A newcomer rides in from beyond the right edge, a dropped row falls out at the bottom. */
    overflow: hidden;
}

.dawn-top__row {
    display: grid;
    grid-template-columns: 2.6em 1fr auto;
    gap: 6px;
    align-items: baseline;
    margin: 0;
    padding: 2px 6px;
    background: #3a2230;
}

.dawn-top__place {
    color: var(--sky-light);
    font-variant-numeric: tabular-nums;
}

.dawn-top__name {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.dawn-top__shots {
    color: var(--gold);
    font-variant-numeric: tabular-nums;
}

/* The columns' heading «место · имя · очки» over the rows: small and dim, no plate; only in the unfolded table. */
.dawn-top__head {
    padding-block: 0;
    background: none;
}

/* Small letters in the cells only: the grid keeps the rows' em, so the columns line up. */
.dawn-top__head > span {
    font-size: 10px;
    letter-spacing: 0.04em;
}

.dawn-top__head,
.dawn-top__head .dawn-top__place,
.dawn-top__head .dawn-top__shots {
    color: var(--sky-light);
}

.dawn-top:has(.dawn-top__empty:not([hidden])) .dawn-top__head,
.dawn-top[data-folded] .dawn-top__head {
    display: none;
}

.dawn-top__row[data-dawn-me],
.dawn-top__row[data-dawn-me] .dawn-top__place,
.dawn-top__row[data-dawn-me] .dawn-top__shots {
    color: var(--outline);
}

.dawn-top__row[data-dawn-me] {
    background: var(--gold);
    box-shadow: inset 0 -2px 0 0 var(--wait);
}

/* Who just climbed flashes cream for a moment, in three hard steps. */
.dawn-top__row[data-dawn-up] {
    animation: dawn-up 0.6s steps(3) both;
}

@keyframes dawn-up {
    0% { background: var(--cream); }
}

/* Pushed out of the top: it keeps its old spot while it drops away (dawn.js). */
.dawn-top__row--gone {
    position: absolute;
    left: 0;
    right: 0;
}

/* My place below the top, under a dashed line: «#23 · ты · 4». */
.dawn-top__row--mine {
    position: relative;
    margin-top: 12px;
}

.dawn-top__row--mine::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: -8px;
    border-top: 2px dashed var(--soil);
}

.dawn-top__empty {
    margin: 0;
    color: var(--sky-light);
}

@media (prefers-reduced-motion: reduce) {
    .dawn-top__row[data-dawn-up] {
        animation: none;
    }
}

/* A phone: a strip «#3 · ты · 7 · топ ▾» over the HUD (--hud-h from client.js), unfolding into the three and mine (the
   dawn's five). */
.dawn-top[data-compact] {
    top: auto;
    right: auto;
    left: 50%;
    bottom: calc(var(--hud-h, 40px) + 24px);
    width: min(300px, calc(100% - 32px));
    padding: 0 8px 8px;
    font-size: 12px;
    transform: translateX(-50%);
}

.dawn-top[data-compact][data-folded] {
    padding-bottom: 0;
}

.dawn-top[data-compact] .dawn-top__title,
.dawn-top[data-compact][data-folded] .dawn-top__list,
.dawn-top[data-compact][data-folded] .dawn-top__empty,
.dawn-top[data-compact][data-folded] .dawn-top__row--mine {
    display: none;
}

.dawn-top[data-compact] .dawn-top__toggle {
    order: 0;
    align-self: stretch;
    gap: 8px;
    justify-content: center;
    margin: 0;
    padding: 7px 4px;
    font-size: inherit;
    color: var(--gold);
}

.dawn-top__toggle::after {
    content: '▴';
    color: var(--cream);
}

.dawn-top[data-folded] .dawn-top__toggle::after {
    content: '▾';
}

.dawn-top__toggle:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: -4px;
}

/*
 * The chat (docs/spec/frontend.md, «Чат»): the field over the HUD in the middle, framed like the word form; a refusal
 * is a note under it. `--hud-h` is the HUD's height (client.js), which wraps with the width.
 */
.chat {
    position: absolute;
    bottom: calc(var(--hud-h, 40px) + 26px);
    left: 50%;
    z-index: 1003;
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 6px 8px;
    width: min(440px, calc(100% - 32px));
    margin: 0;
    padding: 8px 10px;
    font: 700 14px/1.3 var(--pixel-font);
    color: var(--cream);
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    transform: translateX(-50%);
}

.chat[hidden] {
    display: none;
}

.chat__label {
    grid-column: 1 / -1;
    color: var(--gold);
    letter-spacing: 0.04em;
}

.chat__input {
    min-width: 0;
    padding: 7px 8px;
    border: 0;
    font: inherit;
    font-weight: 400;
    color: var(--cream);
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--soil);
}

.chat__button {
    padding: 0 12px;
    border: 0;
    font: inherit;
    color: var(--outline);
    background: var(--cream);
    box-shadow: 0 0 0 2px var(--soil-dark);
    cursor: pointer;
}

.chat__button:hover {
    background: var(--gold);
}

.chat__button:disabled {
    opacity: 0.6;
    cursor: progress;
}

.chat__input:focus-visible,
.chat__button:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 2px;
}

.chat__note {
    grid-column: 1 / -1;
    margin: 0;
    font-size: 12px;
    color: var(--bad);
}

.chat__note:empty {
    display: none;
}

/* `muted`: only the owl's note is left for a moment, then the field closes. */
.chat--told .chat__label,
.chat--told .chat__input,
.chat--told .chat__button {
    display: none;
}

/* `rate limited`, `invalid text`: the field flinches by whole pixels, the text stays. */
.chat--shake {
    animation: chat-shake 0.4s steps(1, end);
}

@keyframes chat-shake {
    0% { transform: translateX(calc(-50% - 4px)); }
    20% { transform: translateX(calc(-50% + 4px)); }
    40% { transform: translateX(calc(-50% - 2px)); }
    60% { transform: translateX(calc(-50% + 2px)); }
    80%, 100% { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
    .chat--shake {
        animation: none;
    }
}

@container patch (max-width: 600px) {
    .chat {
        bottom: calc(var(--hud-h, 48px) + 22px);
        font-size: 13px;
    }
}

/*
 * The emotes (docs/spec/frontend.md, «Эмоции»): a row of emoji buttons over the HUD in the middle, where the chat field
 * opens (the field closes the row); two rows of six on a phone. A press rests the row (aria-disabled) for a second.
 */
.emotes {
    position: absolute;
    bottom: calc(var(--hud-h, 40px) + 26px);
    left: 50%;
    z-index: 1003;
    display: grid;
    grid-template-columns: repeat(12, 36px);
    gap: 4px;
    max-width: calc(100% - 32px);
    padding: 6px;
    background: var(--outline);
    box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--outline), 0 4px 0 2px var(--outline);
    transform: translateX(-50%);
}

.emotes[hidden] {
    display: none;
}

.emotes__button {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    font-size: 22px;
    line-height: 1;
    background: var(--soil-dark);
    box-shadow: inset 0 0 0 2px var(--soil);
    cursor: pointer;
}

.emotes__button:hover {
    background: var(--soil);
}

.emotes__button[aria-disabled="true"] {
    opacity: 0.45;
    cursor: default;
}

.emotes__button:focus-visible {
    outline: 2px dashed var(--gold);
    outline-offset: 1px;
}

/* «😀» in the HUD: the glyph, a touch larger than the HUD's words. */
.hud__button--emote {
    padding: 0 4px;
    font-size: 15px;
    line-height: 1.2;
}

@container patch (max-width: 600px) {
    .emotes {
        bottom: calc(var(--hud-h, 48px) + 22px);
        grid-template-columns: repeat(6, 40px);
    }

    .emotes__button {
        width: 40px;
        height: 40px;
    }
}

/* The console's chat log: rows as text, the newest at the bottom, scrolled inside the group. */
.chat-log {
    display: flex;
    flex-basis: 100%;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.chat-log__list,
.chat-log__muted {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.chat-log__list {
    max-height: 180px;
    padding: 4px 6px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--soil-dark);
    box-shadow: 0 0 0 2px var(--soil);
}

.chat-log__row {
    display: flex;
    flex-wrap: wrap;
    gap: 2px 6px;
    align-items: baseline;
    font-weight: 400;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

.chat-log__time {
    color: var(--sky-light);
}

.chat-log__name {
    font-weight: 700;
    color: var(--gold);
}

.chat-log__tag {
    padding: 0 4px;
    font-size: 11px;
    color: var(--outline);
    background: #7cc43c;
}

.chat-log__text {
    flex: 1 1 8em;
    color: var(--cream);
}

.chat-log__wanted {
    flex-basis: 100%;
    font-size: 12px;
    color: #c8f0a0;
}

.console .chat-log__mute {
    margin-left: auto;
    padding: 2px 6px;
    font-size: 11px;
}

.chat-log__empty {
    margin: 0;
    font-weight: 400;
    color: var(--sky-light);
}

.chat-log__empty[hidden],
.chat-log__title[hidden] {
    display: none;
}

.chat-log__title {
    font-size: 11px;
    color: var(--accent);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
