/* =============================================================================
   Lernapp design system
   Source of truth: Lernapp.dc.html (repo root). Reference viewport is the iPad Air
   in landscape (1180×820); portrait and the 13" iPad Pro are first-class, phones
   and desktops must not break but are not tuned.
   ============================================================================= */

/* ---- Fonts (self-hosted, SIL OFL — see wwwroot/fonts/OFL-*.txt) ------------ */
@font-face {
    font-family: "Baloo 2";
    font-style: normal;
    font-weight: 600 800;
    font-display: swap;
    src: url("../fonts/baloo2-latin.woff2") format("woff2");
}

@font-face {
    font-family: "Nunito";
    font-style: normal;
    font-weight: 600 800;
    font-display: swap;
    src: url("../fonts/nunito-latin.woff2") format("woff2");
}

/* ---- Tokens ---------------------------------------------------------------- */
:root {
    --ink: #1d2b33;
    --page: #dcebe4;
    --frame: #edf7f2;
    --frame-shadow: #c3d8cf;
    --pill-shadow: #cddfd7;
    --cream: #ffe9b8;
    --cream-shadow: #e2cd9a;
    --muted: #5c7a72;
    --muted-warm: #6b5a2e;
    --white: #ffffff;

    --star: oklch(0.7 0.16 65);
    --avatar: oklch(0.68 0.16 40);
    --sticker: oklch(0.62 0.17 340);
    --go: oklch(0.62 0.17 130);
    --link: oklch(0.55 0.15 210);

    --font-display: "Baloo 2", "Nunito", system-ui, sans-serif;
    --font-body: "Nunito", system-ui, -apple-system, "Segoe UI", sans-serif;

    --border: 5px;
    --border-sm: 4px;
    --border-xs: 3px;
    --radius-frame: 44px;
    --radius-tile: 36px;
    --radius-card: 28px;

    /* Vertical measures also bow to the viewport height: on an iPad in landscape with the
       browser's own bars showing (about 740 px instead of 820) the app gets a little
       smaller everywhere instead of pushing its bottom row off the screen. */
    --page-pad: min(clamp(8px, 1.5vw, 24px), 1.6vh);
    --frame-pad-x: clamp(20px, 3.4vw, 40px);
    --frame-pad-top: min(clamp(20px, 2.9vw, 34px), 3vh);
    --frame-pad-bottom: min(clamp(24px, 3.4vw, 40px), 3.4vh);
    --gap: min(clamp(14px, 2vw, 24px), 2.4vh);

    /* Minimum tap target on iPadOS. */
    --tap: 44px;
}

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

html {
    background: var(--page);
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    min-height: 100dvh;
    padding:
        max(var(--page-pad), env(safe-area-inset-top))
        max(var(--page-pad), env(safe-area-inset-right))
        max(var(--page-pad), env(safe-area-inset-bottom))
        max(var(--page-pad), env(safe-area-inset-left));
    font-family: var(--font-body);
    font-weight: 700;
    color: var(--ink);
    background: var(--page);
    line-height: 1.3;
    display: flex;
    justify-content: center;
    align-items: stretch;
}

a {
    color: var(--link);
}

h1,
h2,
h3 {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1.05;
}

/* The rounded "device" frame from the design, stretched to the viewport. */
.app-frame {
    width: 100%;
    max-width: 1366px;
    min-height: calc(100dvh - 2 * var(--page-pad));
    display: flex;
    flex-direction: column;
    background: var(--frame);
    border: var(--border) solid var(--ink);
    border-radius: var(--radius-frame);
    box-shadow: 0 18px 0 var(--frame-shadow);
    padding: var(--frame-pad-top) var(--frame-pad-x) var(--frame-pad-bottom);
    overflow: hidden;
    position: relative;
}

/* ---- Pills (top bar) ------------------------------------------------------- */
.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.topbar__stats {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.pill {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--tap);
    background: var(--white);
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    padding: 10px 24px 10px 12px;
    box-shadow: 0 6px 0 var(--pill-shadow);
}

.pill--kid {
    padding: 8px 22px 8px 8px;
    gap: 14px;
}

.pill--stars {
    background: var(--cream);
    padding: 12px 24px;
    gap: 10px;
}

.pill__stack {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
}

.pill__title {
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 800;
    color: var(--ink);
}

.pill__title--sm {
    font-size: clamp(18px, 1.9vw, 22px);
}

.pill__sub {
    font-size: clamp(13px, 1.3vw, 15px);
    font-weight: 700;
    color: var(--muted);
}

.avatar {
    width: 56px;
    height: 56px;
    flex: none;
    border-radius: 999px;
    background: var(--avatar);
    border: var(--border-sm) solid var(--ink);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: 30px;
    font-weight: 800;
    color: var(--white);
}

.star {
    font-size: 26px;
    color: var(--star);
    line-height: 1;
}

/* ---- Hero ------------------------------------------------------------------ */
.hero {
    margin: min(clamp(18px, 2.5vw, 30px), 3vh) 0 var(--gap);
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

.hero__title {
    font-size: min(clamp(34px, 4.6vw, 54px), 6vh);
    letter-spacing: -0.5px;
    color: var(--ink);
}

.hero__sub {
    margin: 6px 0 0;
    font-size: clamp(16px, 1.7vw, 20px);
    font-weight: 700;
    color: var(--muted);
}

.sticker {
    background: var(--sticker);
    border: var(--border-sm) solid var(--ink);
    border-radius: 22px;
    padding: 12px 20px;
    box-shadow: 0 7px 0 var(--ink);
    transform: rotate(-3deg);
    font-family: var(--font-display);
    font-size: clamp(18px, 1.9vw, 22px);
    font-weight: 800;
    color: var(--white);
    white-space: nowrap;
}

/* ---- Tile grids ------------------------------------------------------------ */
.tile-grid {
    flex: 1;
    display: grid;
    gap: var(--gap);
    align-content: stretch;
}

.tile-grid--modules {
    grid-template-columns: 1fr 1fr;
    grid-auto-rows: minmax(clamp(150px, 22vh, 260px), 1fr);
}

/* ---- Tile ------------------------------------------------------------------ */
.tile {
    --tile-color: oklch(0.63 0.16 var(--hue, 210));
    --tile-tint: oklch(0.955 0.045 var(--hue, 210));

    position: relative;
    display: flex;
    align-items: center;
    gap: clamp(16px, 2.2vw, 26px);
    min-height: var(--tap);
    border: var(--border) solid var(--ink);
    border-radius: var(--radius-tile);
    box-shadow: 0 11px 0 var(--ink);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    transform: rotate(var(--tilt, 0deg));
    transition: transform 120ms ease, box-shadow 120ms ease, filter 120ms ease;

    /* Touch: no tap flash, no 300 ms delay, no long-press text selection. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none;
    user-select: none;
    cursor: pointer;
}

.tile:active {
    transform: rotate(var(--tilt, 0deg)) translateY(6px);
    box-shadow: 0 5px 0 var(--ink);
}

@media (hover: hover) {
    .tile:hover {
        filter: brightness(1.06);
    }
}

.tile--module {
    padding: min(clamp(18px, 2.2vw, 26px), 2.6vh) clamp(20px, 2.6vw, 30px);
    background: var(--tile-color);
}

.tile__glyph {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--white);
    border: var(--border) solid var(--ink);
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1;
    color: var(--tile-color);
    overflow: hidden;
}

.tile--module .tile__glyph {
    width: min(clamp(80px, 10vw, 118px), 13vh);
    height: min(clamp(80px, 10vw, 118px), 13vh);
    border-radius: 30px;
    font-size: clamp(28px, 3.4vw, 40px);
}

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

.tile__body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.tile__title {
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1;
    overflow-wrap: anywhere;
}

.tile--module .tile__title {
    font-size: min(clamp(28px, 3.9vw, 46px), 5.2vh);
    color: var(--white);
}

.tile__sub {
    font-weight: 700;
}

.tile--module .tile__sub {
    font-size: clamp(15px, 1.6vw, 19px);
    color: var(--white);
}

.tile__meta {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    flex-wrap: wrap;
}

.tile__badge {
    background: var(--white);
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    padding: 4px 14px;
    font-family: var(--font-display);
    font-size: clamp(14px, 1.45vw, 17px);
    font-weight: 800;
    color: var(--ink);
    white-space: nowrap;
}

.tile__stars {
    font-size: clamp(14px, 1.45vw, 17px);
    font-weight: 800;
    letter-spacing: 1px;
    white-space: nowrap;
}

.tile--module .tile__stars {
    color: var(--white);
}

/* ---- Entdecken band -------------------------------------------------------- */
/* The seventh tile of the start screen would leave a hole in the 2 × 3 grid, so Entdecken is
   a short band across the full width under the modules: coloured like a module tile, laid
   out in one row so it costs little height. */
.tile-grid--explore {
    flex: none;
    grid-template-columns: 1fr;
    margin-top: var(--gap);
}

.tile--explore {
    min-height: min(clamp(72px, 10vh, 100px), 12vh);
    padding: min(clamp(10px, 1.4vw, 16px), 1.6vh) clamp(20px, 2.6vw, 30px);
    background: var(--tile-color);
}

.tile--explore .tile__glyph {
    width: min(clamp(52px, 6vw, 70px), 8vh);
    height: min(clamp(52px, 6vw, 70px), 8vh);
    border-radius: 20px;
    font-size: clamp(24px, 2.6vw, 32px);
}

.tile--explore .tile__body {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 18px;
}

.tile--explore .tile__title {
    font-size: min(clamp(24px, 3vw, 36px), 4.4vh);
    color: var(--white);
}

.tile--explore .tile__sub {
    font-size: clamp(15px, 1.6vw, 19px);
    color: var(--white);
}

.tile--explore .tile__meta {
    margin-top: 0;
    margin-left: auto;
}

/* ---- Entdecken: a world page ----------------------------------------------- */
/* The section fills the frame below the header band; the mount is the dark box a world
   draws into (the canvas comes with three.js), and the note is what it says until then. */
.explore {
    --night: #221d47;
    --night-2: #2c2660;
    --night-ink: #fff6e5;

    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding-top: var(--gap);
}

.explore__mount {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: radial-gradient(120% 80% at 50% 0%, var(--night-2) 0%, var(--night) 70%);
    border: var(--border) solid var(--ink);
    border-radius: 24px;
    box-shadow: 0 8px 0 var(--ink);
    overflow: hidden;
    touch-action: none;
    /* The panel and the card measure their height budget against the stage (cqh). */
    container-type: size;
}

.explore__canvas {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    touch-action: none;
}

.explore__hud {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 12px;
    pointer-events: none;
}

.explore__hud-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: flex-start;
}

.explore__modes {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    border-radius: 999px;
    background: rgba(20, 16, 50, 0.6);
    pointer-events: auto;
}

.explore__mode[aria-pressed="false"] {
    background: transparent;
    color: var(--night-ink);
    border-color: transparent;
    box-shadow: none;
}

.explore__readout {
    margin-left: auto;
    display: grid;
    justify-items: end;
    gap: 2px;
    padding: 8px 14px;
    border-radius: 18px;
    background: rgba(20, 16, 50, 0.7);
    color: var(--night-ink);
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(16px, 1.9vw, 22px);
    white-space: nowrap;
}

/* The sound switch at the right end of the bar; next to the readout when that is shown. */
.explore__sound {
    margin-left: auto;
}

.explore__readout:not([hidden]) + .explore__sound {
    margin-left: 0;
}

.explore__readout-time,
.explore__readout-flight {
    font-family: var(--font-body);
    font-weight: 700;
    font-size: clamp(13px, 1.4vw, 16px);
    opacity: 0.9;
}

.explore__hud .button {
    pointer-events: auto;
}

.explore__hud-middle {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    margin: 0 0 8px;
}

.explore__panel-host {
    flex: 1 1 36ch;
    min-width: 0;
}

.explore__panel {
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    width: min(100%, 44ch);
    max-height: 45cqh;
    padding: 14px 18px 16px;
    border: var(--border-sm) solid var(--ink);
    border-radius: var(--radius-card);
    background: var(--cream);
    color: var(--ink);
    box-shadow: 0 6px 0 var(--ink);
}

.explore__panel-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.explore__panel-title {
    flex: 1;
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.4vw, 28px);
    font-weight: 800;
}

.explore__panel-body {
    min-height: 0;
    overflow: auto;
    margin-top: 8px;
    font-size: clamp(16px, 1.8vw, 20px);
    line-height: 1.4;
}

.explore__panel-line {
    margin: 0 0 6px;
}

.explore__panel-line:last-child {
    margin-bottom: 0;
}

/* The big glyph over a riddle that has one: the globe's animals. */
.explore__panel-glyph {
    display: block;
    font-size: clamp(44px, 6vw, 72px);
    line-height: 1.1;
    margin: 0 0 6px;
}

.explore__stamps {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 8px;
}

.explore__stamp {
    padding: 4px 10px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    font-weight: 700;
    font-size: 15px;
}

.explore__panel-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;
}

.explore__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: 4px;
    max-height: 38vh;
    overflow: auto;
}

.explore__list li {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: baseline;
}

.explore__list small {
    color: var(--muted-warm);
}

.explore__menu {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: rgba(20, 16, 50, 0.72);
}

.explore__menu-box {
    width: min(100%, 720px);
    max-height: 100%;
    overflow: auto;
    padding: 16px 18px 20px;
    border: var(--border-sm) solid var(--ink);
    border-radius: var(--radius-card);
    background: var(--frame);
    color: var(--ink);
    box-shadow: 0 8px 0 var(--ink);
}

.explore__menu-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.explore__menu-title {
    flex: 1;
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(24px, 3vw, 34px);
    font-weight: 800;
}

.explore__menu-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 12px;
    margin-top: 14px;
}

.explore__menu-tile {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 84px;
    padding: 12px 14px;
    border: var(--border-sm) solid var(--ink);
    border-radius: 22px;
    background: var(--white);
    color: var(--ink);
    text-align: left;
    font: inherit;
    box-shadow: 0 6px 0 var(--ink);
    cursor: pointer;
}

.explore__menu-tile:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--ink);
}

.explore__menu-glyph {
    font-size: 36px;
    line-height: 1;
}

.explore__menu-text {
    display: grid;
    gap: 2px;
}

.explore__menu-text strong {
    font-family: var(--font-display);
    font-size: clamp(18px, 2vw, 22px);
    font-weight: 800;
}

.explore__menu-text small {
    font-size: 14px;
    color: var(--muted);
}

.explore__menu-note {
    margin: 14px 0 0;
    font-size: 14px;
    color: var(--muted);
    text-align: center;
}

.explore__card {
    pointer-events: auto;
    display: flex;
    flex-direction: column;
    margin-left: auto;
    width: min(100%, 44ch);
    max-height: 45cqh;
    margin-bottom: 0;
    padding: 14px 18px 16px;
    border: var(--border-sm) solid var(--ink);
    border-radius: var(--radius-card);
    background: var(--white);
    color: var(--ink);
    box-shadow: 0 6px 0 var(--ink);
}

.explore__card-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.explore__card-body {
    min-height: 0;
    overflow: auto;
}

/* While a game holds the panel the card is one row; "Mehr" or a tap on the name opens it. */
.explore__card--compact {
    width: auto;
    max-width: min(100%, 44ch);
    padding: 10px 14px;
}

.explore__card--compact .explore__card-body {
    display: none;
}

/* More specific than .speak, which is declared later in this file. */
.explore__card .explore__card-more {
    width: auto;
    padding: 0 12px;
    font-size: 15px;
    font-weight: 800;
}

.explore__card:not(.explore__card--compact) .explore__card-more {
    display: none;
}

/* The honest line and its ℹ️ step aside while a panel or a card is open. */
.explore__hud:has(.explore__panel:not([hidden]), .explore__card:not([hidden])) .explore__hud-foot {
    display: none;
}

/* Landscape: both boxes about a third of the stage, the middle free. */
@media (orientation: landscape) and (min-width: 900px) {
    .explore__panel-host {
        flex-basis: 30ch;
    }

    .explore__panel,
    .explore__card {
        width: min(100%, 36ch, 40cqw);
    }

    .explore__card--compact {
        width: auto;
        max-width: min(100%, 36ch, 40cqw);
    }
}

.explore__card-title {
    flex: 1;
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(22px, 2.6vw, 30px);
    font-weight: 800;
}

.explore__tools {
    display: contents;
}

.explore__slider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 8px 0;
    font-size: 24px;
}

.explore__slider input[type=range] {
    flex: 1;
    min-width: 0;
    height: 44px;
    accent-color: var(--ink);
}

.explore__card-link {
    display: inline-block;
    margin-top: 10px;
}

.explore__card-facts {
    margin: 10px 0 0;
    font-size: clamp(16px, 1.8vw, 20px);
    line-height: 1.4;
}

.explore__card-fun {
    margin: 8px 0 0;
    padding: 8px 12px;
    border-radius: 14px;
    background: var(--cream);
    color: var(--muted-warm);
    font-size: clamp(15px, 1.6vw, 18px);
    font-weight: 700;
}

.explore__card-fun::before {
    content: "💡 ";
}

.explore__card-age {
    margin: 8px 0 0;
    font-size: clamp(15px, 1.6vw, 18px);
    font-weight: 700;
}

.explore__card-age::before {
    content: "🎂 ";
}

/* The foot: the honest line in the middle, the ℹ️ that brings it back in the right corner. */
.explore__hud-foot {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: end;
    gap: 8px;
}

.explore__honest {
    grid-column: 2;
    margin: 0;
    max-width: 60ch;
    padding: 6px 14px;
    border: 0;
    border-radius: 999px;
    background: rgba(20, 16, 50, 0.6);
    color: var(--night-ink);
    font: inherit;
    font-size: 14px;
    text-align: center;
    cursor: pointer;
    pointer-events: auto;
}

.explore__honest::after {
    content: " ✕";
    opacity: 0.7;
}

.explore__honest-toggle {
    grid-column: 3;
    justify-self: end;
    width: var(--tap);
    height: var(--tap);
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: rgba(20, 16, 50, 0.6);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    pointer-events: auto;
}

.explore__note {
    margin: 0;
    padding: 16px 24px;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.4vw, 28px);
    font-weight: 800;
    color: var(--night-ink);
    text-align: center;
}

/* ---- Buttons --------------------------------------------------------------- */
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap);
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    padding: 14px 34px;
    box-shadow: 0 7px 0 var(--ink);
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 800;
    text-decoration: none;
    color: var(--white);
    background: var(--go);
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 120ms ease, box-shadow 120ms ease;
}

.button:active {
    transform: translateY(4px);
    box-shadow: 0 3px 0 var(--ink);
}

/* ---- Status / error pages -------------------------------------------------- */
.status-page {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 14px;
    padding: var(--gap);
}

.status-page__code {
    width: clamp(110px, 14vw, 160px);
    height: clamp(110px, 14vw, 160px);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--cream);
    border: var(--border) solid var(--ink);
    border-radius: 40px;
    box-shadow: 0 11px 0 var(--cream-shadow);
    transform: rotate(-3deg);
    font-family: var(--font-display);
    font-size: clamp(44px, 6vw, 72px);
    font-weight: 800;
    color: var(--ink);
    margin-bottom: 12px;
}

.status-page__title {
    font-size: clamp(30px, 4vw, 48px);
}

.status-page__text {
    margin: 0;
    max-width: 34ch;
    font-size: clamp(16px, 1.7vw, 20px);
    color: var(--muted);
}

.status-page__meta {
    margin: 0;
    font-size: 14px;
    color: var(--muted);
}

.status-page .button {
    margin-top: 10px;
}

code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.9em;
}

/* ---- Orientation / breakpoints --------------------------------------------- */

/* iPad portrait (820×1180, 834×1194, 1024×1366): same 2×2 grid, taller cards. */
@media (orientation: portrait) and (min-width: 700px) {
    .tile-grid--modules {
        grid-auto-rows: minmax(clamp(170px, 20vh, 300px), 1fr);
    }

    .tile--module {
        flex-direction: column;
        align-items: flex-start;
        justify-content: center;
        gap: clamp(18px, 3vw, 30px);
    }

    .tile--module .tile__glyph {
        width: clamp(96px, 15vw, 150px);
        height: clamp(96px, 15vw, 150px);
        font-size: clamp(34px, 5vw, 50px);
    }

    .tile--module .tile__title {
        font-size: clamp(34px, 5.6vw, 52px);
    }

    .tile--module .tile__sub {
        font-size: clamp(17px, 2.2vw, 21px);
    }
}

/* Phones: untuned, but never broken. */
@media (max-width: 699px) {
    :root {
        --radius-frame: 28px;
        --radius-tile: 26px;
    }

    .app-frame {
        box-shadow: 0 10px 0 var(--frame-shadow);
    }

    .tile-grid--modules {
        grid-template-columns: 1fr;
        grid-auto-rows: auto;
    }

    .tile {
        transform: none;
    }

    .tile:active {
        transform: translateY(6px);
    }

    .sticker {
        transform: rotate(-2deg);
    }
}

@media (prefers-reduced-motion: reduce) {
    .tile,
    .button {
        transition: none;
    }
}

/* ---- Module page ----------------------------------------------------------- */

/* Header band bleeds to the frame edges, like the design. */
.module-header {
    --tile-color: oklch(0.63 0.16 var(--hue, 210));

    display: flex;
    align-items: center;
    gap: clamp(14px, 2vw, 24px);
    flex-wrap: wrap;
    margin: calc(-1 * var(--frame-pad-top)) calc(-1 * var(--frame-pad-x)) 0;
    padding: min(clamp(14px, 1.9vw, 22px), 1.8vh) var(--frame-pad-x) min(clamp(16px, 2.2vw, 26px), 2vh);
    background: var(--tile-color);
    border-bottom: var(--border) solid var(--ink);
    color: var(--white);
}

.back-button {
    width: clamp(48px, 7vh, 64px);
    height: clamp(48px, 7vh, 64px);
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 22px;
    background: var(--white);
    border: var(--border-sm) solid var(--ink);
    box-shadow: 0 6px 0 var(--ink);
    font-family: var(--font-display);
    font-size: clamp(26px, 4vh, 34px);
    font-weight: 800;
    line-height: 1;
    color: var(--ink);
    text-decoration: none;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 120ms ease, box-shadow 120ms ease;
}

.back-button:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--ink);
}

.module-header__glyph {
    width: min(clamp(68px, 7.3vw, 86px), 9vh);
    height: min(clamp(68px, 7.3vw, 86px), 9vh);
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 26px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    font-family: var(--font-display);
    font-size: min(clamp(24px, 2.7vw, 32px), 4vh);
    font-weight: 800;
    line-height: 1;
    color: var(--tile-color);
}

.module-header__text {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.module-header__title {
    font-size: min(clamp(32px, 4vw, 48px), 5vh);
    color: var(--white);
}

.module-header__sub {
    font-size: min(clamp(15px, 1.6vw, 19px), 2.4vh);
    font-weight: 700;
}

.module-header__stars {
    margin-left: auto;
    box-shadow: 0 6px 0 var(--ink);
}

.module-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--gap);
    padding-top: var(--gap);
}

/* ---- Daily banner ---------------------------------------------------------- */
@keyframes bob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-6px); }
}

.daily-banner {
    display: flex;
    align-items: center;
    gap: clamp(14px, 2vw, 24px);
    flex-wrap: wrap;
    background: var(--cream);
    border: var(--border) solid var(--ink);
    border-radius: 30px;
    padding: min(clamp(10px, 1.3vw, 16px), 1.4vh) clamp(18px, 2.2vw, 26px);
    box-shadow: 0 9px 0 var(--cream-shadow);
}

.daily-banner__badge {
    width: clamp(48px, 7vh, 64px);
    height: clamp(48px, 7vh, 64px);
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    background: var(--avatar);
    border: var(--border) solid var(--ink);
    font-family: var(--font-display);
    font-size: clamp(22px, 3.4vh, 30px);
    font-weight: 800;
    color: var(--white);
    animation: bob 2.4s ease-in-out infinite;
}

.daily-banner__text {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
}

.daily-banner__title {
    font-family: var(--font-display);
    font-size: min(clamp(22px, 2.5vw, 30px), 3.4vh);
    font-weight: 800;
    color: var(--ink);
}

.daily-banner__sub {
    font-size: min(clamp(15px, 1.5vw, 18px), 2.2vh);
    font-weight: 700;
    color: var(--muted-warm);
}

.daily-banner__go {
    margin-left: auto;
}

/* ---- Exercise tiles -------------------------------------------------------- */
.tile-grid--exercises {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-auto-rows: minmax(0, 1fr);
    min-height: 0;
}

.tile--exercise {
    flex-direction: column;
    align-items: stretch;
    justify-content: space-between;
    gap: 8px;
    padding: min(clamp(14px, 1.5vw, 18px), 1.6vh) clamp(16px, 1.9vw, 22px);
    border-radius: var(--radius-card);
    box-shadow: 0 9px 0 var(--ink);
    background: var(--tile-tint);
    transform: none;
}

.tile--exercise:active {
    transform: translateY(5px);
    box-shadow: 0 4px 0 var(--ink);
}

.tile--exercise .tile__glyph {
    width: clamp(44px, 6.4vh, 56px);
    height: clamp(44px, 6.4vh, 56px);
    border-radius: 16px;
    background: var(--tile-color);
    border-width: var(--border-sm);
    font-size: clamp(18px, 2.6vh, 22px);
    color: var(--white);
}

.tile--exercise .tile__body {
    gap: 6px;
}

.tile--exercise .tile__title {
    font-size: min(clamp(21px, 2.3vw, 27px), 3vh);
    color: var(--ink);
}

.tile--exercise .tile__sub {
    font-size: min(clamp(14px, 1.4vw, 16px), 2vh);
    color: #4a615a;
}

.tile--exercise .tile__stars {
    color: var(--star);
}

/* iPad portrait: two columns of compact horizontal cards instead of tall ones. */
@media (orientation: portrait) and (min-width: 700px) {
    .tile-grid--exercises {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-auto-rows: auto;
        align-content: start;
    }

    .tile--exercise {
        flex-direction: row;
        align-items: center;
        justify-content: flex-start;
        gap: 16px;
        padding: 18px 20px;
    }

    .tile--exercise .tile__body {
        flex: 1;
        align-items: flex-start;
    }

    .tile--exercise .tile__glyph {
        width: 64px;
        height: 64px;
        font-size: 26px;
    }
}

@media (max-width: 699px) {
    .tile-grid--exercises {
        grid-template-columns: 1fr;
        grid-auto-rows: auto;
    }

    .module-header__stars,
    .daily-banner__go {
        margin-left: 0;
    }

    .daily-banner__badge {
        animation: none;
    }
}

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

/* ---- Exercise page --------------------------------------------------------- */
.module-header__title--sm {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: clamp(26px, 3vw, 36px);
    line-height: 1.05;
    color: var(--white);
}

.exercise-page {
    --tile-color: oklch(0.63 0.16 var(--hue, 210));
    --tile-tint: oklch(0.955 0.045 var(--hue, 210));

    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--gap) 0 0;
}

.exercise-page__card {
    width: min(100%, 640px);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 12px;
    padding: clamp(24px, 3vw, 40px);
    background: var(--tile-tint);
    border: var(--border) solid var(--ink);
    border-radius: var(--radius-tile);
    box-shadow: 0 11px 0 var(--ink);
}

.exercise-page__glyph,
.exercise-page__image {
    width: clamp(110px, 14vw, 160px);
    height: clamp(110px, 14vw, 160px);
    border-radius: 36px;
    border: var(--border) solid var(--ink);
    background: var(--tile-color);
    margin-bottom: 6px;
}

.exercise-page__glyph {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: clamp(44px, 6vw, 64px);
    font-weight: 800;
    line-height: 1;
    color: var(--white);
}

.exercise-page__image {
    object-fit: cover;
    background: var(--white);
}

.exercise-page__title {
    font-size: clamp(32px, 4vw, 46px);
    color: var(--ink);
}

.exercise-page__description {
    margin: 0;
    font-size: clamp(18px, 1.9vw, 22px);
    color: var(--muted);
}

.exercise-page__note {
    margin: 4px 0 8px;
    max-width: 40ch;
    font-size: clamp(15px, 1.5vw, 17px);
    color: #4a615a;
}

.exercise-page__form {
    margin: 0;
}

button.button {
    font: inherit;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 800;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

/* ---- Utilities ------------------------------------------------------------- */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* ---- Top bar: the name pill is the "switch user" button -------------------- */
.topbar__user {
    margin: 0;
}

.pill--button {
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 120ms ease, box-shadow 120ms ease;
}

.pill--button:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.pill__switch {
    margin-left: 6px;
    font-size: clamp(18px, 2vw, 24px);
    font-weight: 800;
    color: var(--muted);
}

/* ---- Login: PIN pad -------------------------------------------------------- */
.login {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: clamp(16px, 3vh, 32px);
    text-align: center;
}

.login__hero .hero__title {
    font-size: clamp(36px, 5vw, 60px);
}

.login__hero .hero__sub {
    font-size: clamp(18px, 2vw, 24px);
}

.pinpad {
    --key: clamp(64px, 9.5vh, 88px);

    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(12px, 2vh, 22px);
}

.pinpad__dots {
    display: none;
    gap: 12px;
    min-height: 24px;
}

.pinpad--js .pinpad__dots {
    display: flex;
}

.pinpad__dot {
    width: 22px;
    height: 22px;
    border-radius: 999px;
    border: var(--border-xs) solid var(--ink);
    background: var(--white);
    transition: background 80ms ease, transform 80ms ease;
}

.pinpad__dot--filled {
    background: var(--ink);
    transform: scale(1.1);
}

.pinpad__input {
    width: min(100%, 300px);
    min-height: var(--tap);
    padding: 10px 16px;
    border: var(--border-sm) solid var(--ink);
    border-radius: 18px;
    font: inherit;
    font-size: 28px;
    letter-spacing: 8px;
    text-align: center;
    color: var(--ink);
    background: var(--white);
}

/* With the script running, the pad owns the input. */
.pinpad--js .pinpad__input,
.pinpad--js .pinpad__submit {
    position: absolute;
    width: 1px;
    height: 1px;
    min-height: 0;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.pinpad__keys {
    display: grid;
    grid-template-columns: repeat(3, var(--key));
    gap: clamp(10px, 1.6vh, 16px);
}

.pinpad__key {
    width: var(--key);
    height: var(--key);
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    box-shadow: 0 6px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(26px, 3.6vh, 34px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 80ms ease, box-shadow 80ms ease;
}

.pinpad__key--action {
    background: var(--cream);
    box-shadow: 0 6px 0 var(--cream-shadow);
    font-size: clamp(20px, 3vh, 28px);
}

.pinpad__key:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.pinpad--busy .pinpad__key {
    opacity: 0.6;
    pointer-events: none;
}

.login__error {
    margin: 0;
    padding: 8px 18px;
    border-radius: 999px;
    background: oklch(0.93 0.06 25);
    border: var(--border-xs) solid oklch(0.55 0.2 25);
    color: oklch(0.45 0.18 25);
    font-size: clamp(16px, 1.8vw, 20px);
    font-weight: 800;
}

.pinpad--failed .pinpad__dots {
    animation: shake 420ms ease;
}

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

/* iPad landscape: greeting on the left, pad on the right. */
@media (orientation: landscape) and (min-width: 900px) {
    .login {
        flex-direction: row;
        justify-content: space-evenly;
        text-align: left;
    }

    .login__hero {
        max-width: 40%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pinpad--failed .pinpad__dots {
        animation: none;
    }

    .pinpad__key,
    .pinpad__dot,
    .pill--button {
        transition: none;
    }
}

/* ---- Admin: users ---------------------------------------------------------- */
.pill--link {
    text-decoration: none;
    color: var(--ink);
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 120ms ease, box-shadow 120ms ease;
}

.pill--link:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.admin-users {
    flex: 1;
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(300px, 2fr);
    gap: var(--gap);
    align-items: start;
    padding-top: var(--gap);
}

.user-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.user-row {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px 18px;
    background: var(--white);
    border: var(--border-sm) solid var(--ink);
    border-radius: var(--radius-card);
    box-shadow: 0 6px 0 var(--pill-shadow);
}

.user-row__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px 18px;
}

.user-row__actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px 18px;
}

.user-row__who {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 200px;
    flex: 1;
}

.user-row__text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.user-row__name {
    font-family: var(--font-display);
    font-size: clamp(20px, 2.1vw, 24px);
    font-weight: 800;
}

.user-row__meta {
    font-size: 14px;
    color: var(--muted);
}

.user-row__pin {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: right;
    line-height: 1.1;
}

.user-row__label {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 1px;
    color: var(--muted);
}

.user-row__code {
    font-family: var(--font-display);
    font-size: clamp(20px, 2.1vw, 24px);
    font-weight: 800;
    letter-spacing: 2px;
}

.user-row__form {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}

.user-row__error {
    margin: 0;
}

.admin-users__note {
    margin: 14px 4px 0;
    font-size: 14px;
    color: var(--muted);
}

.create-card {
    background: var(--cream);
    border: var(--border-sm) solid var(--ink);
    border-radius: var(--radius-card);
    box-shadow: 0 8px 0 var(--cream-shadow);
    padding: clamp(18px, 2.4vw, 28px);
}

.create-card__title {
    font-size: clamp(24px, 2.6vw, 30px);
    margin-bottom: 14px;
}

.create-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
    align-items: flex-start;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
}

.field__label {
    font-size: 15px;
    font-weight: 800;
    color: var(--muted-warm);
}

.field__input {
    width: 100%;
    min-height: var(--tap);
    padding: 10px 14px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--white);
    font: inherit;
    font-size: 18px;
    color: var(--ink);
}

.field__input--pin {
    font-family: var(--font-display);
    font-weight: 800;
    letter-spacing: 2px;
}

.user-row__form .field__input {
    width: 170px;
}

.form-error {
    color: oklch(0.45 0.18 25);
    font-size: 14px;
    font-weight: 800;
}

.form-error:empty {
    display: none;
}

.button--small {
    padding: 8px 18px;
    font-size: 17px;
    box-shadow: 0 5px 0 var(--ink);
}

.button--danger {
    background: oklch(0.6 0.19 25);
}

/* "Kinder" on a parent's or admin's row: linked kids as chips, a select for the rest. */
.user-row__family {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    padding-top: 12px;
    border-top: 2px dashed var(--pill-shadow);
}

.chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.chips__empty {
    color: var(--muted);
    font-weight: 800;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 12px;
    background: var(--cream);
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 16px;
}

.chip__form {
    margin: 0;
    display: flex;
}

.chip__remove {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--ink);
    color: var(--white);
    font-size: 13px;
    font-weight: 800;
    line-height: 1;
    cursor: pointer;
    touch-action: manipulation;
}

.chip__remove:active {
    transform: translateY(1px);
}

.user-row__form .field__input--kid {
    width: 200px;
}

@media (orientation: portrait) and (min-width: 700px), (max-width: 899px) {
    .admin-users {
        grid-template-columns: 1fr;
    }
}

/* ---------------------------------------------------------------------------
   Meine Kinder (Features/Family): one .user-row per linked kid with its stars,
   and a small per-module breakdown beneath.
   --------------------------------------------------------------------------- */
.kids {
    max-width: 860px;
    margin: 0 auto;
}

.kids__empty {
    margin: 8px 4px 18px;
    font-size: 18px;
    font-weight: 800;
    color: var(--muted);
}

.kid-modules {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.kid-module {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px;
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    background: oklch(0.95 0.05 var(--hue));
    font-weight: 800;
    font-size: 15px;
}

.kid-module__stars {
    color: var(--muted);
}

/* Vorgelesen: the kid's last readings under the stars, each with a player and a delete. */
.kid-readings {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 6px;
    border-top: var(--border-xs) solid var(--frame-shadow);
}

.kid-readings__title {
    font-size: 18px;
    color: var(--ink);
}

.kid-readings__empty {
    margin: 0;
    color: var(--muted);
    font-size: 15px;
    font-weight: 700;
}

.kid-readings__list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.kid-reading {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 8px 12px;
    background: var(--frame);
    border: var(--border-xs) solid var(--frame-shadow);
    border-radius: 18px;
}

.kid-reading__text {
    flex: 1 1 240px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.kid-reading__sentence {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.kid-reading__meta {
    font-size: 13px;
    font-weight: 700;
    color: var(--muted);
}

.kid-reading__audio {
    flex: 0 1 260px;
    min-width: 180px;
    height: 40px;
}

.kid-reading__delete {
    margin: 0;
}

/* Foto-Safari on the Kinder page: a grid of thumbnails, the assignment under each. */
.kid-photos {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 6px;
    border-top: var(--border-xs) solid var(--frame-shadow);
}

.kid-photos__title {
    font-size: 18px;
    color: var(--ink);
}

.kid-photos__empty {
    margin: 0;
    color: var(--muted);
    font-size: 15px;
    font-weight: 700;
}

.kid-photos__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.kid-photo {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px;
    background: var(--frame);
    border: var(--border-xs) solid var(--frame-shadow);
    border-radius: 18px;
}

.kid-photo__link {
    display: block;
    aspect-ratio: 4 / 3;
    max-width: 100%;
    overflow: hidden;
    border-radius: 12px;
    background: var(--cream);
}

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

.kid-photo__prompt {
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 700;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

.kid-photo__meta {
    font-size: 12px;
    font-weight: 700;
    color: var(--muted);
}

.kid-photo__delete {
    margin: 4px 0 0;
}

/* ---------------------------------------------------------------------------
   Exercise player (Features/Exercises + wwwroot/js/exercise)
   Landscape: task column on the left, number pad rail on the right (mock).
   Portrait: rail moves below the task column.
   --------------------------------------------------------------------------- */

/* The hidden attribute must win over component display rules (e.g. .button). */
[hidden] {
    display: none !important;
}

.module-header--player {
    gap: 16px;
}

.module-header__glyph--image {
    padding: 0;
    overflow: hidden;
}

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

.player-progress {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 12px;
    color: var(--white);
    font-family: var(--font-display);
    font-size: clamp(16px, 1.8vw, 22px);
    font-weight: 800;
    white-space: nowrap;
}

.player-progress__pips {
    display: flex;
    gap: 6px;
}

.player-progress__pip {
    width: 18px;
    height: 18px;
    border-radius: 999px;
    border: 3px solid var(--ink);
    background: rgba(255, 255, 255, 0.35);
}

.player-progress__pip--current {
    background: var(--white);
}

.player-progress__pip--done {
    background: var(--star);
}

.player {
    --tile-color: oklch(0.63 0.16 var(--hue, 210));
    --tile-tint: oklch(0.955 0.045 var(--hue, 210));
    --ok: oklch(0.93 0.08 130);
    --wrong: oklch(0.94 0.06 25);

    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding-top: var(--gap);
}

.player__empty,
.player__note {
    margin: auto;
}

.player__stage {
    --split: 0.34; /* share of the width the Schmierblatt gets; set by js/exercise/split.js */
    flex: 1;
    min-height: 0;
    display: flex;
    gap: var(--gap);
}

.player__main {
    flex: calc(1 - var(--split)) 1 0px;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: min(16px, 2vh);
}

.player__handle {
    flex: none;
    width: 26px;
    margin: 0 calc(var(--gap) * -0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: col-resize;
    touch-action: none;
}

.player__handle::before {
    content: "";
    width: 10px;
    height: 96px;
    border-radius: 999px;
    background: var(--frame-shadow);
    border: var(--border-xs) solid var(--ink);
}

/* Bottom row of the task column: feedback bar, number keys, "Prüfen". */
.player__bottom {
    flex: none;
    display: flex;
    align-items: stretch;
    gap: 14px;
}

.player__card {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: min(14px, 1.8vh);
    padding: min(clamp(16px, 2.4vw, 28px), 2.8vh);
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 32px;
    box-shadow: 0 9px 0 var(--pill-shadow);
    text-align: center;
}

.player__image {
    max-height: min(30vh, 260px);
    max-width: 100%;
    object-fit: contain;
    border-radius: 24px;
}

.player__prompt {
    margin: 0;
    font-family: var(--font-display);
    font-size: min(clamp(24px, 2.8vw, 34px), 4.2vh);
    font-weight: 800;
    line-height: 1.2;
}

.player__options {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.player__option {
    min-height: 88px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 12px 18px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 24px;
    box-shadow: 0 7px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(22px, 2.4vw, 30px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 80ms ease, box-shadow 80ms ease;
}

.player__option:active:not(:disabled) {
    transform: translateY(4px);
    box-shadow: 0 3px 0 var(--pill-shadow);
}

.player__option:disabled {
    cursor: default;
}

.player__option--correct {
    background: var(--ok);
    border-color: var(--go);
}

.player__option--wrong {
    background: var(--wrong);
}

.player__option-image {
    height: 64px;
    width: 64px;
    object-fit: contain;
}

.player__answer {
    min-height: clamp(64px, 9vh, 84px);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--cream);
    border: var(--border) dashed var(--ink);
    border-radius: 24px;
    font-family: var(--font-display);
    font-size: min(clamp(36px, 4vw, 52px), 6vh);
    font-weight: 800;
    letter-spacing: 2px;
}

.player__answer:not(:empty) {
    border-style: solid;
}

/* Satzbau: the sentence line above, the chip tray and Prüfen below. A chip is a small
   option pill; a placed one sits in the line and shows its capital when it comes first. */
.player__sentence {
    min-height: clamp(64px, 9vh, 84px);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: var(--cream);
    border: var(--border) dashed var(--ink);
    border-radius: 24px;
}

.player__sentence:not(:empty) {
    border-style: solid;
}

.player__sentence--correct {
    background: var(--ok);
    border-color: var(--go);
}

.player__sentence--wrong {
    background: var(--wrong);
}

.player__sentence-mark {
    font-family: var(--font-display);
    font-size: clamp(26px, 3vw, 36px);
    font-weight: 800;
    color: var(--ink);
}

.player__chips-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}

.player__chips {
    flex: 1;
    min-width: 0;
    min-height: var(--tap);
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.player__chip {
    min-height: max(var(--tap), 52px);
    padding: 6px 18px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 18px;
    box-shadow: 0 5px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 28px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 80ms ease, box-shadow 80ms ease;
}

.player__chip:active:not(:disabled) {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.player__chip:disabled {
    cursor: default;
}

.player__chip--placed {
    background: var(--tile-tint, var(--white));
}

/* Ordnen: the same line and tray, with arrows between the placed chips and an optional head
   chip ("Sonne") that stands at the front and cannot be moved. */
.player__sentence--chain {
    gap: 6px 8px;
}

.player__arrow {
    font-family: var(--font-display);
    font-size: clamp(22px, 2.6vw, 32px);
    font-weight: 800;
    color: var(--ink);
    opacity: 0.6;
}

.player__chip--head {
    display: inline-flex;
    align-items: center;
    background: var(--cream);
    box-shadow: none;
    opacity: 0.75;
    cursor: default;
}

/* Waage: the beam over the post, two pans under its ends, the tray below. --tilt is set by
   the renderer; positive tilts the right end down. The pans follow the beam by --drop. */
.waage {
    --tilt: 0deg;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.waage__top {
    position: relative;
    width: min(100%, 560px);
    height: clamp(56px, 9vh, 80px);
}

.waage__post {
    position: absolute;
    left: 50%;
    bottom: 0;
    width: 16px;
    height: 100%;
    transform: translateX(-50%);
    background: var(--ink);
    border-radius: 8px 8px 0 0;
}

.waage__beam {
    position: absolute;
    left: 4%;
    right: 4%;
    top: 6px;
    height: 14px;
    background: var(--ink);
    border-radius: 7px;
    transform: rotate(var(--tilt));
    transition: transform 320ms ease;
}

.waage__beam::before,
.waage__beam::after {
    content: '';
    position: absolute;
    top: 50%;
    width: 22px;
    height: 22px;
    margin-top: -11px;
    border-radius: 50%;
    background: var(--white);
    border: var(--border) solid var(--ink);
}

.waage__beam::before { left: -6px; }
.waage__beam::after { right: -6px; }

.waage__pans {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    width: min(100%, 560px);
}

.waage__pan {
    min-height: clamp(76px, 12vh, 104px);
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: center;
    gap: 8px;
    padding: 10px 12px;
    background: var(--cream);
    border: var(--border) solid var(--ink);
    border-radius: 0 0 28px 28px;
    transition: transform 320ms ease;
}

.waage__pan--left { transform: translateY(calc(var(--tilt) / 1deg * -1.6px)); }
.waage__pan--right { transform: translateY(calc(var(--tilt) / 1deg * 1.6px)); }

.waage__pan--open {
    border-style: dashed;
    background: var(--tile-tint, var(--cream));
}

.waage--level .waage__pan--open,
.waage--correct .waage__pan--open {
    border-style: solid;
}

.waage--correct .waage__pan--open { background: var(--ok); border-color: var(--go); }
.waage--revealed .waage__pan--open { background: var(--wrong); }

.waage__tray {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    min-height: var(--tap);
}

.waage__weight {
    --size: 10;
    min-width: calc(44px + var(--size) * 1px);
    min-height: max(var(--tap), 48px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 4px 12px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 14px 14px 8px 8px;
    box-shadow: 0 4px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 28px);
    font-weight: 800;
    color: var(--ink);
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.waage__weight--fixed { background: var(--pill-shadow); box-shadow: none; }

.waage__weight--added,
.waage__weight--piece { cursor: pointer; transition: transform 80ms ease, box-shadow 80ms ease; }

.waage__weight--added:active:not(:disabled),
.waage__weight--piece:active:not(:disabled) {
    transform: translateY(3px);
    box-shadow: 0 1px 0 var(--pill-shadow);
}

.waage__weight:disabled { cursor: default; }

/* Silben: the word large, the beats in a row, one big pad to knock on. */
.silben {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(10px, 2vh, 18px);
}

.silben__word {
    padding: 6px 22px;
    background: none;
    border: none;
    font-family: var(--font-display);
    font-size: min(clamp(40px, 5vw, 64px), 8vh);
    font-weight: 800;
    letter-spacing: 2px;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.silben--revealed .silben__word { letter-spacing: 1px; }

.silben__beats {
    min-height: max(var(--tap), 56px);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 12px;
    width: 100%;
    padding: 8px 14px;
    background: var(--cream);
    border: var(--border) dashed var(--ink);
    border-radius: 24px;
}

.silben--correct .silben__beats { background: var(--ok); border-color: var(--go); border-style: solid; }
.silben--revealed .silben__beats { background: var(--wrong); border-style: solid; }

.silben__placeholder {
    font-family: var(--font-display);
    font-size: clamp(18px, 2vw, 24px);
    font-weight: 700;
    color: var(--ink);
    opacity: 0.55;
}

.silben__beat {
    width: max(var(--tap), 52px);
    height: max(var(--tap), 52px);
    border-radius: 50%;
    background: var(--white);
    border: var(--border) solid var(--ink);
    box-shadow: 0 4px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(18px, 2vw, 24px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.silben__beat:disabled { cursor: default; }

.silben__pad {
    width: min(100%, 420px);
    min-height: min(clamp(96px, 16vh, 140px), 20vh);
    background: var(--tile-tint, var(--white));
    border: var(--border) solid var(--ink);
    border-radius: 32px;
    box-shadow: 0 8px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(28px, 3.4vw, 40px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: transform 60ms ease, box-shadow 60ms ease;
}

.silben__pad:active:not(:disabled) {
    transform: translateY(5px);
    box-shadow: 0 3px 0 var(--pill-shadow);
}

.silben__pad:disabled { cursor: default; }

/* Farbmischen: two paints, a plus, an equals, and the bowl that fills once the answer has
   settled. The colours to tap are ordinary options with a chip of their paint. */
.farbmischen {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(12px, 2.4vh, 22px);
}

.farbmischen__table {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: clamp(8px, 1.6vw, 18px);
}

.farbmischen__paint {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 4px;
    background: none;
    border: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.farbmischen__blob {
    width: min(clamp(64px, 9vw, 96px), 12vh);
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--paint, #bdbdbd);
    border: var(--border) solid var(--ink);
    box-shadow: 0 5px 0 var(--pill-shadow);
}

.farbmischen__name {
    font-family: var(--font-display);
    font-size: clamp(18px, 2vw, 24px);
    font-weight: 800;
    color: var(--ink);
}

.farbmischen__sign {
    font-family: var(--font-display);
    font-size: clamp(32px, 4vw, 48px);
    font-weight: 800;
    color: var(--ink);
}

/* The bowl: open at the top, round at the bottom, white until the answer has settled. */
.farbmischen__bowl {
    width: min(clamp(84px, 12vw, 124px), 16vh);
    aspect-ratio: 10 / 7;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 12px 12px 999px 999px / 12px 12px 100% 100%;
    box-shadow: 0 5px 0 var(--pill-shadow);
    transition: background 500ms ease;
}

.farbmischen__bowl--full { background: var(--paint, var(--white)); }

.farbmischen__chip {
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: 12px;
    border: var(--border-xs) solid var(--ink);
    background: var(--paint, #bdbdbd);
}

@media (prefers-reduced-motion: reduce) {
    .farbmischen__bowl { transition: none; }
}

/* Uhr: the clock face sits between the prompt card and the answer, sized like a task picture. */
.clock {
    flex: none;
    align-self: center;
    height: clamp(160px, 30vh, 280px);
    aspect-ratio: 1;
    max-width: 100%;
}

.clock__face {
    fill: var(--white);
    stroke: var(--ink);
    stroke-width: 5;
}

.clock__tick {
    stroke: var(--muted);
    stroke-width: 1.5;
    stroke-linecap: round;
}

.clock__tick--hour {
    stroke: var(--ink);
    stroke-width: 3.5;
}

.clock__number {
    fill: var(--ink);
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 800;
}

.clock__hand {
    stroke-linecap: round;
}

/* The short hand dark, the long hand blue, so "der kleine Zeiger" and "der große Zeiger" read apart. */
.clock__hand--hour {
    stroke: var(--ink);
    stroke-width: 8;
}

.clock__hand--minute {
    stroke: var(--link);
    stroke-width: 5;
}

.clock__pin {
    fill: var(--ink);
}

/* A clock read on the pad: hour, colon, minutes. Slots still to fill, and the fixed :00 of a
   full-hour task, are dim; the field stays dashed until the first digit. */
.player__clock-entry {
    gap: 2px;
    font-variant-numeric: tabular-nums;
}

.player__answer.player__clock-entry--empty {
    border-style: dashed;
}

.player__clock-slot {
    min-width: 1.2ch;
    text-align: center;
}

.player__clock-slot--empty,
.player__clock-slot--fixed {
    color: var(--muted);
}

/* A clock the kid sets: bigger, with knobs on the hands, and it takes the finger instead of the
   page while it can be turned. The size stays after the answer; only the grip goes. */
.clock--set {
    height: clamp(220px, 42vh, 380px);
}

.clock__knob {
    display: none;
    stroke: none;
}

.clock--settable {
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
    cursor: grab;
}

.clock--settable:active {
    cursor: grabbing;
}

.clock--settable .clock__knob {
    display: inline;
}

.clock__hand--hour .clock__knob {
    fill: var(--ink);
}

.clock__hand--minute .clock__knob {
    fill: var(--link);
}

.clock:focus-visible {
    outline: 4px solid var(--link);
    outline-offset: 4px;
    border-radius: 50%;
}

.player__clock-actions {
    display: flex;
    justify-content: center;
}

/* Geld: coins and notes in real proportions. --w and --h (millimetres) come from
   js/exercise/tasks/geld/utils/pieces.js; --mm turns a millimetre into pixels. The metal and paper
   colours are the real ones, not theme colours. */
.money {
    --mm: 3px;
    --copper: #c98552;
    --copper-light: #dd9d6c;
    --gold: #d6b04a;
    --gold-light: #e8c86a;
    --silver: #cdd3d7;
    --note-5: #b8c6bf;
    --note-10: #e7aaa2;
    --note-20: #a9c2e8;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px 12px;
}

.piece {
    flex: none;
    width: calc(var(--w) * var(--mm));
    height: calc(var(--h) * var(--mm));
}

.piece__rim,
.piece__paper {
    stroke: var(--ink);
    stroke-width: 3;
}

.piece__core {
    stroke: var(--ink);
    stroke-width: 1.5;
    stroke-opacity: 0.35;
}

.piece__window {
    fill: rgba(255, 255, 255, 0.4);
}

.piece__value {
    fill: var(--ink);
    font-family: var(--font-display);
    font-size: 40px;
    font-weight: 800;
}

.piece--note .piece__value {
    font-size: 50px;
}

.piece__unit {
    fill: var(--ink);
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 1px;
}

.piece--copper .piece__rim { fill: var(--copper); }
.piece--copper .piece__core { fill: var(--copper-light); }
.piece--gold .piece__rim { fill: var(--gold); }
.piece--gold .piece__core { fill: var(--gold-light); }
.piece--euro-1 .piece__rim { fill: var(--gold); }
.piece--euro-1 .piece__core { fill: var(--silver); }
.piece--euro-2 .piece__rim { fill: var(--silver); }
.piece--euro-2 .piece__core { fill: var(--gold); }
.piece--note-5 .piece__paper { fill: var(--note-5); }
.piece--note-10 .piece__paper { fill: var(--note-10); }
.piece--note-20 .piece__paper { fill: var(--note-20); }

/* The table money is counted on, and the counter a payment is laid on. */
.money--table,
.money--counter {
    flex: none;
    min-height: 104px;
    padding: 12px;
    background: var(--frame);
    border: var(--border-sm) solid var(--frame-shadow);
    border-radius: var(--radius-card);
}

.money--counter.money--empty {
    border-style: dashed;
}

.money__placeholder {
    color: var(--muted);
    font-weight: 700;
}

.money--tray {
    --mm: 2.6px;
    flex: none;
}

.money__take,
.money__give {
    display: inline-flex;
    padding: 4px;
    background: none;
    border: 0;
    border-radius: 12px;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: transform 80ms ease;
}

.money__take:active:not(:disabled),
.money__give:active:not(:disabled) {
    transform: translateY(3px) scale(0.96);
}

.money__take:disabled,
.money__give:disabled {
    cursor: default;
}

.money__hint {
    margin: 0;
    text-align: center;
    font-family: var(--font-display);
    font-size: clamp(18px, 2vw, 22px);
    font-weight: 800;
    color: var(--link);
}

.player__money-actions {
    display: flex;
    justify-content: center;
}

/* Counting: the euro and the cent box; the chosen one is outlined. */
.player__money-entry {
    gap: 16px;
}

.player__money-box {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    min-width: 3ch;
    padding: 2px 14px;
    background: var(--white);
    border: var(--border-sm) solid var(--frame-shadow);
    border-radius: 18px;
    font: inherit;
    color: var(--ink);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    font-variant-numeric: tabular-nums;
}

.player__money-box--chosen {
    border-color: var(--link);
    box-shadow: 0 0 0 3px var(--tile-tint);
}

.player__money-box--empty .player__money-digits,
.player__money-unit {
    color: var(--muted);
}

.player__money-unit {
    font-size: 0.6em;
}

.player__money-box:disabled {
    cursor: default;
}

@media (orientation: portrait), (max-width: 899px) {
    .money {
        --mm: 2.4px;
    }

    .money--tray {
        --mm: 2.1px;
    }
}

.player__word {
    display: flex;
    gap: 14px;
}

.player__word-input {
    flex: 1;
    min-width: 0;
    min-height: 72px;
    padding: 10px 22px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 24px;
    font-family: var(--font-display);
    font-size: clamp(26px, 3vw, 36px);
    font-weight: 800;
    color: var(--ink);
}

.player__word-input:focus {
    outline: none;
    box-shadow: 0 0 0 4px var(--tile-tint);
}

.player__keys {
    flex: none;
    width: clamp(294px, 26vw, 320px); /* six 44 px keys plus gaps */
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    grid-auto-rows: minmax(var(--tap), 1fr);
    gap: 6px;
}

.player__key {
    min-height: var(--tap);
    border: var(--border-sm) solid var(--ink);
    border-radius: 14px;
    background: var(--white);
    box-shadow: 0 5px 0 var(--pill-shadow);
    font-family: var(--font-display);
    font-size: clamp(22px, 2.2vw, 26px);
    font-weight: 800;
    color: var(--ink);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 80ms ease, box-shadow 80ms ease;
}

.player__key--action {
    background: var(--cream);
}

.player__key:active:not(:disabled) {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.player__key:disabled,
.player__check:disabled {
    opacity: 0.55;
    cursor: default;
}

.player__check {
    flex: none;
    border-radius: 24px;
    font-size: clamp(24px, 2.6vw, 30px);
}

.player__bottom .player__check {
    width: clamp(104px, 10vw, 124px);
    padding-left: 12px;
    padding-right: 12px;
}

/* Beside the key block the bar is narrow: no mascot, the text on its own line,
   "Pause" and "Weiter" on a second line. */
.player__bottom--keys .player__feedback {
    flex-wrap: wrap;
    align-content: center;
    gap: 8px 12px;
    padding: 10px 14px;
}

.player__bottom--keys .player__mascot {
    display: none;
}

.player__bottom--keys .player__feedback-text {
    flex: 1 1 100%;
    font-size: clamp(17px, 1.75vw, 21px);
}

.player__bottom--keys .player__pause {
    margin-left: auto;
}

.player__bottom--keys .player__next {
    padding: 8px 14px;
    font-size: clamp(16px, 1.7vw, 19px);
}

.player__bottom--keys .player__pause {
    min-width: var(--tap);
    padding: 8px 10px;
}

.player__feedback {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 12px 20px;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 28px;
    box-shadow: 0 8px 0 var(--pill-shadow);
    transition: background 160ms ease;
}

.player__feedback--ok {
    background: var(--ok);
}

.player__feedback--wrong {
    background: var(--wrong);
    animation: shake 320ms ease;
}

.player__feedback--reveal {
    background: var(--cream);
}

.player__mascot {
    position: relative;
    width: 60px;
    height: 60px;
    flex: none;
    border-radius: 999px;
    background: var(--avatar);
    border: var(--border) solid var(--ink);
    animation: bob 2.6s ease-in-out infinite;
}

.player__mascot::before {
    content: "";
    position: absolute;
    top: 18px;
    left: 14px;
    width: 9px;
    height: 9px;
    border-radius: 999px;
    background: var(--ink);
    box-shadow: 15px 0 0 var(--ink);
}

.player__mascot::after {
    content: "";
    position: absolute;
    left: 15px;
    top: 30px;
    width: 22px;
    height: 11px;
    border-bottom: var(--border-sm) solid var(--ink);
    border-radius: 0 0 40px 40px;
}

.player__feedback-text {
    flex: 1;
    min-width: 0;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.3vw, 27px);
    font-weight: 800;
    line-height: 1.15;
}

.player__next {
    flex: none;
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: 10px 26px;
    font-size: clamp(20px, 2.2vw, 25px);
}

.player__next-label {
    position: relative;
    z-index: 1;
}

/* Countdown to the next task: a bar grows from the left until the button is full. */
.player__next::before {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--ink);
    opacity: 0.32;
    transform: scaleX(0);
    transform-origin: left center;
}

.player__next--filling::before {
    animation: player-fill var(--advance-ms, 1500ms) linear forwards;
}

.player__next--paused::before {
    animation-play-state: paused;
}

@keyframes player-fill {
    from { transform: scaleX(0); }
    to { transform: scaleX(1); }
}

.player__pause {
    flex: none;
    min-width: var(--tap);
    padding: 10px 18px;
    background: var(--cream);
}

/* Two bars drawn with borders; the display font has no pause glyph. */
.player__pause-icon {
    display: block;
    width: 16px;
    height: 20px;
    border-left: 6px solid var(--ink);
    border-right: 6px solid var(--ink);
    box-sizing: border-box;
}

.player__end {
    margin: auto;
    width: min(100%, 560px);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: clamp(24px, 3vw, 40px);
    background: var(--tile-tint);
    border: var(--border) solid var(--ink);
    border-radius: var(--radius-tile);
    box-shadow: 0 11px 0 var(--ink);
    text-align: center;
}

.player__end-stars {
    font-size: clamp(44px, 6vw, 72px);
    color: var(--star);
    letter-spacing: 6px;
    line-height: 1;
}

.player__end-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(28px, 3.4vw, 40px);
    font-weight: 800;
}

.player__end-sub {
    margin: 0 0 8px;
    color: var(--muted);
    font-weight: 700;
    font-size: clamp(16px, 1.8vw, 20px);
}

@media (orientation: portrait), (max-width: 899px) {
    .player__stage {
        flex-direction: column;
    }

    .player__main {
        flex: none;
    }

    .player__handle {
        display: none;
    }

    .player__stage .scratch {
        flex: 1 1 auto;
        min-height: 260px;
    }

    .player__card {
        min-height: 220px;
    }

    /* Keys take a full row above the feedback bar; "Prüfen" stays beside the bar. */
    .player__bottom {
        flex-wrap: wrap;
    }

    .player__keys {
        flex: 1 1 100%;
        width: auto;
        order: -1;
    }

    .player-progress__pips {
        display: none;
    }
}

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

    .player__feedback--wrong {
        animation: none;
    }

    /* No growing bar; the button shows as full while the countdown runs. */
    .player__next--filling::before,
    .game__next--filling::before {
        animation: none;
        transform: scaleX(1);
    }

    .player__next--paused::before {
        transform: scaleX(0);
    }
}

/* ---------------------------------------------------------------------------
   Schmierblatt (wwwroot/js/scratch) — the drawing pane next to a task
   --------------------------------------------------------------------------- */

.scratch {
    flex: var(--split, 0.34) 1 0px;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--white);
    border: var(--border) solid var(--ink);
    border-radius: 32px;
    box-shadow: 0 9px 0 var(--pill-shadow);
    overflow: hidden;
}

.scratch__bar {
    flex: none;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 10px;
    padding: 8px 14px;
    background: var(--cream);
    border-bottom: var(--border) solid var(--ink);
}

.scratch__title {
    flex: none;
    font-family: var(--font-display);
    font-size: clamp(18px, 1.9vw, 22px);
    font-weight: 800;
    white-space: nowrap;
}

.scratch__tools {
    margin-left: auto;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 8px;
}

.scratch__pen,
.scratch__tool {
    flex: none;
    height: var(--tap);
    min-width: var(--tap);
    padding: 0;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 800;
    color: var(--ink);
}

.scratch__pen {
    width: var(--tap);
    background: var(--pen-color);
}

.scratch__pen[aria-pressed="true"] {
    border-width: var(--border);
    box-shadow: inset 0 0 0 3px var(--white);
}

.scratch__tool {
    width: 50px;
}

.scratch__tool--erase[aria-pressed="true"] {
    background: var(--go);
}

.scratch__eraser-icon {
    display: block;
    width: 20px;
    height: 13px;
    border-radius: 3px;
    background: var(--white);
    border: var(--border-xs) solid var(--ink);
    transform: rotate(-20deg);
}

.scratch__sheet {
    flex: 1;
    min-height: 0;
    position: relative;
    background: oklch(0.985 0.012 130);
}

.scratch__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    touch-action: none;
    cursor: crosshair;
}

.scratch__hint {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 20px;
    pointer-events: none;
    font-family: var(--font-display);
    font-size: clamp(18px, 1.9vw, 22px);
    font-weight: 800;
    color: #b7cbc3;
    text-align: center;
    text-wrap: pretty;
}

/* ---------------------------------------------------------------------------
   Note replay page (Features/Notes)
   --------------------------------------------------------------------------- */

.note-page {
    --tile-tint: oklch(0.955 0.045 var(--hue, 210));

    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: var(--gap);
}

.note-page__prompt {
    margin: 0;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.3vw, 27px);
    font-weight: 800;
    line-height: 1.2;
}

.note-page__meta {
    margin: 0;
    color: var(--muted);
    font-weight: 700;
    font-size: clamp(14px, 1.5vw, 17px);
}

/* Fits the remaining height; the aspect ratio of the pad gives the width, capped at the frame. */
.note-page__sheet {
    position: relative;
    flex: 1 1 0;
    min-height: 0;
    width: auto;
    max-width: 100%;
    align-self: center;
    margin: 6px 0 0;
    background: oklch(0.985 0.012 130);
    border: var(--border) solid var(--ink);
    border-radius: 32px;
    box-shadow: 0 9px 0 var(--pill-shadow);
    overflow: hidden;
}

.note-page__canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.note-page__note {
    margin: 0;
    padding: 20px;
    text-align: center;
    color: var(--muted);
}

/* ---------------------------------------------------------------------------
   Admin: exercises (Features/Admin/AdminExercises)
   --------------------------------------------------------------------------- */

.admin-module {
    margin-bottom: 22px;
}

.admin-module__title {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 12px;
    font-family: var(--font-display);
    font-size: clamp(22px, 2.4vw, 28px);
    font-weight: 800;
}

.admin-module__glyph {
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 14px;
    background: oklch(0.63 0.16 var(--hue, 210));
    border: var(--border-xs) solid var(--ink);
    color: var(--white);
    font-size: 18px;
}

.admin-module__count {
    margin-left: auto;
    font-family: var(--font-body);
    font-size: 15px;
    font-weight: 700;
    color: var(--muted);
}

.exercise-row__glyph {
    width: 48px;
    height: 48px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 16px;
    background: oklch(0.955 0.045 var(--hue, 210));
    border: var(--border-xs) solid var(--ink);
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 800;
}

.exercise-row--inactive {
    opacity: 0.6;
    background: var(--frame);
}

.user-row__code--sm {
    font-size: clamp(16px, 1.6vw, 20px);
}

.button--secondary {
    background: var(--white);
    color: var(--ink);
    box-shadow: 0 6px 0 var(--pill-shadow);
}

.field__input--file {
    padding: 10px 14px;
    font-size: 16px;
    background: var(--white);
}

.field__input--file::file-selector-button {
    margin-right: 12px;
    padding: 8px 14px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--cream);
    font-family: var(--font-display);
    font-weight: 800;
    color: var(--ink);
}

.upload-errors {
    margin: 0;
    padding: 12px 16px 12px 32px;
    background: oklch(0.94 0.06 25);
    border: var(--border-xs) solid oklch(0.58 0.19 25);
    border-radius: 16px;
    font-size: 15px;
    font-weight: 700;
    color: oklch(0.45 0.18 25);
    line-height: 1.4;
}

.upload-message {
    margin: 0 0 16px;
    padding: 12px 18px;
    background: oklch(0.93 0.08 130);
    border: var(--border-xs) solid var(--go);
    border-radius: 16px;
    font-weight: 700;
}

.create-card__hint {
    margin: 4px 0 0;
    font-size: 14px;
    color: var(--muted-warm);
    line-height: 1.4;
}

.create-card__hint code {
    font-size: 13px;
}

.module-body__empty {
    margin: auto;
    padding: 24px;
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 800;
    color: var(--muted);
    text-align: center;
}

/* ---------------------------------------------------------------------------
   Zehnerfreunde game (Features/Exercises Game.cshtml + wwwroot/js/game)
   The board keeps the night look of the design mock so the faces read well;
   cards, buttons and pad use the app's styling. Board column left, cards right,
   in both iPad orientations (the cell size adapts, see game-view.js fit()).
   --------------------------------------------------------------------------- */
.game {
    --tile-color: oklch(0.63 0.16 var(--hue, 130));
    --tile-tint: oklch(0.955 0.045 var(--hue, 130));
    --night: #221d47;
    --night-2: #2c2660;
    --gridline: #3a3374;
    --face: #2b2350;
    --night-ink: #fff6e5;
    --night-dim: #b3a9dd;
    --g1: #ffc93c;
    --g2: #ff6b6b;
    --g3: #4ecdc4;
    --g4: #5b9dff;
    --g5: #c07bff;
    --g6: #a8e05f;
    --g7: #ff9a3c;
    --cell: 40px;
    --cell-sm: 22px;

    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding-top: var(--gap);
}

.game__mount {
    flex: 1;
    min-height: 0;
    display: flex;
}

.game__stage {
    flex: 1;
    min-height: 0;
    display: flex;
    justify-content: center;
    gap: var(--gap);
}

.game__board-col {
    flex: none;
    width: 352px; /* set by game-view.js fit() */
    min-height: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}

/* The wrap takes the height above the pad; the box inside is absolute so the
   board's pixel size never stretches the frame. */
.game__board-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
}

.game__board-box {
    position: absolute;
    top: 0;
    left: 0;
    touch-action: none;           /* the board takes drags, taps and flicks itself */
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
}

.game__board {
    display: grid;
    gap: 2px;
    padding: 6px;
    background: radial-gradient(120% 80% at 50% 0%, var(--night-2) 0%, var(--night) 70%);
    border: var(--border-xs) solid var(--ink);
    border-radius: 18px;
    box-shadow: 0 8px 0 var(--ink);
}

.game__cell {
    width: var(--cell);
    height: var(--cell);
    border-radius: calc(var(--cell) * 0.28);
    background: var(--gridline);
    opacity: 0.3;
}

.game__cell[data-color="1"] { --c: var(--g1); }
.game__cell[data-color="2"] { --c: var(--g2); }
.game__cell[data-color="3"] { --c: var(--g3); }
.game__cell[data-color="4"] { --c: var(--g4); }
.game__cell[data-color="5"] { --c: var(--g5); }
.game__cell[data-color="6"] { --c: var(--g6); }
.game__cell[data-color="7"] { --c: var(--g7); }

.game__cell--on {
    opacity: 1;
    background: var(--c);
    box-shadow: inset 0 -4px 0 rgba(0, 0, 0, 0.18), inset 0 3px 0 rgba(255, 255, 255, 0.3);
}

.game__cell--ghost {
    opacity: 0.55;
    background: transparent;
    box-shadow: inset 0 0 0 3px var(--c);
}

.game__cell--hint {
    animation: game-hint 0.9s ease-in-out infinite;
}

.game__cell--pop {
    animation: game-pop 0.34s ease-out forwards;
}

.game__cell--void {
    opacity: 0;
}

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

@keyframes game-pop {
    0% { transform: scale(1); }
    45% { transform: scale(1.22); }
    100% { transform: scale(0); opacity: 0; }
}

@keyframes game-hint {
    0%, 100% { filter: brightness(1); }
    50% { filter: brightness(1.5); }
}

/* Touch pad under the board: five keys as wide as the board. */
.game__pad {
    display: flex;
    gap: 8px;
}

.game__key {
    flex: 1 1 0;
    min-width: 0;
    min-height: 56px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--white);
    box-shadow: 0 5px 0 var(--ink);
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 800;
    color: var(--ink);
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 100ms ease, box-shadow 100ms ease;
}

.game__key--drop {
    background: var(--tile-color);
    color: var(--white);
}

.game__key:active {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--ink);
}

.game__key:disabled {
    opacity: 0.5;
}

/* Side column: cards and buttons. */
.game__side {
    flex: none;
    width: clamp(190px, 20vw, 240px);
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
}

.game__card {
    padding: 12px 14px;
    background: var(--tile-tint);
    border: var(--border-xs) solid var(--ink);
    border-radius: 22px;
    box-shadow: 0 6px 0 var(--ink);
}

.game__card-title {
    margin: 0 0 4px;
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--muted);
}

.game__score {
    font-family: var(--font-display);
    font-size: 34px;
    line-height: 1;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

.game__sub {
    margin-top: 4px;
    font-size: 14px;
    color: var(--muted);
}

.game__next {
    display: grid;
    gap: 2px;
    justify-content: center;
    min-height: calc(var(--cell-sm) * 2 + 2px);
    padding: 4px 0;
}

.game__next .game__cell {
    width: var(--cell-sm);
    height: var(--cell-sm);
    border-radius: 7px;
}

.game__goal-text {
    margin: 0 0 8px;
    font-size: 15px;
    line-height: 1.3;
}

.game__goal-progress {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 800;
}

.game__goal-bar {
    height: 12px;
    margin: 6px 0;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    overflow: hidden;
}

.game__goal-fill {
    height: 100%;
    background: var(--tile-color);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 240ms ease;
}

.game__goal-stars {
    font-size: 20px;
    color: var(--star);
    letter-spacing: 2px;
}

.game__buttons {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: auto;
}

.game__button {
    min-height: var(--tap);
    padding: 8px 12px;
    font-size: 18px;
    background: var(--white);
    color: var(--ink);
    box-shadow: 0 5px 0 var(--ink);
}

.game__button:active {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--ink);
}

.game__button--on {
    background: var(--cream);
}

.game__button:disabled {
    opacity: 0.5;
    transform: none;
}

.game__finish {
    grid-column: 1 / -1;
    background: var(--go);
    color: var(--white);
}

/* The frame the staged games (Merkspiel, Labyrinth, Kistenschieber) play inside. */
.game__stage-shell {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: var(--gap);
    align-items: stretch;
    width: min(100%, 680px);
    margin: 0 auto;
}

.game__stage-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.game__stage-chip {
    padding: 6px 14px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--tile-color);
    color: var(--white);
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 800;
    white-space: nowrap;
}

.game__stage-title {
    font-size: 17px;
    font-weight: 700;
    color: var(--muted);
}

.game__stage-speak {
    margin-left: auto;
}

/* The music switch sits next to the speaker: both are sound, both are optional, and
   neither belongs to any one game. Off is drawn as faded rather than hidden, so a kid
   can see that there is something to turn back on. */
/* When Vorlesen is unavailable its button is hidden, and then the music switch is the
   one that has to be pushed to the right — two elements both claiming the free space
   would split it and strand the speaker in the middle of the bar. */
.game__stage-speak[hidden] + .game__stage-music {
    margin-left: auto;
}

.game__stage-music[aria-pressed="false"] {
    opacity: 0.55;
    box-shadow: 0 2px 0 var(--ink);
    transform: translateY(2px);
}

/* Counting down to the next stage: the same growing bar the exercise player uses for the
   next task, so the two places a kid waits for something look alike. */
.game__next {
    position: relative;
    isolation: isolate;
    overflow: hidden;
}

.game__next-label {
    position: relative;
    z-index: 1;
}

.game__next::before {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--ink);
    opacity: 0.32;
    transform: scaleX(0);
    transform-origin: left center;
}

.game__next--filling::before {
    animation: player-fill var(--advance-ms, 2200ms) linear forwards;
}

.game__stage-body {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--gap);
    background: var(--tile-tint);
    border: var(--border-xs) solid var(--ink);
    border-radius: 22px;
    box-shadow: 0 6px 0 var(--ink);
    overflow: auto;
}

.game__stage-done {
    margin: 0;
    padding: 10px 14px;
    border-radius: 18px;
    background: var(--go);
    color: var(--white);
    font-family: var(--font-display);
    font-size: 19px;
    text-align: center;
}

.game__stage-buttons {
    grid-template-columns: 1fr 1fr;
    margin-top: 0;
}

.game__todo {
    margin: 0;
    color: var(--muted);
    font-size: 17px;
    text-align: center;
}

/* Merkspiel: the table of cards inside the stage shell. */
.game__memo {
    display: grid;
    grid-template-columns: repeat(var(--memo-cols, 4), 1fr);
    gap: 10px;
    align-content: center;
    width: 100%;
    max-width: min(520px, 100%);
    max-height: 100%;
}

.game__memo-card {
    position: relative;
    aspect-ratio: 3 / 4;
    min-height: 0;
    padding: 0;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--tile-color);
    box-shadow: 0 5px 0 var(--ink);
    cursor: pointer;
    transition: transform 180ms ease, background 180ms ease;
    transform-style: preserve-3d;
}

.game__memo-card:active {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--ink);
}

.game__memo-back,
.game__memo-front {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
    border-radius: 14px;
    backface-visibility: hidden;
    transition: opacity 140ms ease;
}

.game__memo-back {
    font-family: var(--font-display);
    font-size: clamp(22px, 5vw, 34px);
    color: var(--white);
}

.game__memo-front {
    opacity: 0;
    background: var(--white);
}

.game__memo-card--open .game__memo-front { opacity: 1; }
.game__memo-card--open .game__memo-back { opacity: 0; }
.game__memo-card--open { background: var(--white); }

.game__memo-card--found {
    background: var(--cream);
    box-shadow: 0 3px 0 var(--ink);
    opacity: 0.75;
    cursor: default;
}

.game__memo-card--match {
    animation: memo-laugh 500ms ease;
}

@keyframes memo-laugh {
    0%, 100% { transform: none; }
    30% { transform: scale(1.08) rotate(-3deg); }
    65% { transform: scale(1.08) rotate(3deg); }
}

.game__memo-text {
    font-family: var(--font-display);
    font-size: clamp(18px, 4.2vw, 30px);
    font-weight: 800;
    color: var(--ink);
    text-align: center;
    line-height: 1.1;
}

.game__memo-image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

@media (prefers-reduced-motion: reduce) {
    .game__memo-card,
    .game__memo-back,
    .game__memo-front { transition: none; }
    .game__memo-card--match { animation: none; }
}

/* Rechen-Malbild: the picture as fields, the palette beside it. The board keeps the
   picture's own proportions and takes whatever room is left; the palette never grows
   wider than its swatches need. */
.game__paint {
    align-items: stretch;
    gap: var(--gap);
}

.game__paint-board {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.game__paint-svg {
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: var(--paint-cols, 1) / var(--paint-rows, 1);
    border: var(--border-xs) solid var(--ink);
    border-radius: 12px;
    background: var(--white);
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    overflow: hidden;
}

.game__paint-sheet {
    fill: var(--white);
}

.game__paint-field {
    fill: var(--white);
    stroke: var(--frame-shadow);
    stroke-width: 0.5;
    cursor: pointer;
    transition: fill 120ms ease, stroke 200ms ease;
}

.game__paint-field--painted {
    stroke: rgba(29, 43, 51, 0.35);
}

/* Prüfen outlined this field as wrong: it wobbles once and keeps a dashed rim until it
   is painted again. It never says which colour it needs. */
.game__paint-field--wrong {
    stroke: var(--ink);
    stroke-width: 1.1;
    stroke-dasharray: 1.6 1.2;
    animation: paint-wobble 500ms ease;
}

@keyframes paint-wobble {
    0%, 100% { transform: none; }
    30% { transform: translateX(-0.6px); }
    65% { transform: translateX(0.6px); }
}

.game__paint-number {
    fill: var(--ink);
    font-family: var(--font-display);
    font-size: 5.2px;
    font-weight: 800;
    text-anchor: middle;
    dominant-baseline: central;
    pointer-events: none;
    transition: opacity 600ms ease;
}

/* The picture is right: the numbers and the seams between the fields fade away, and the
   picture stands there clean. That is the reveal — one class, nothing more. */
.game__paint-board--done .game__paint-number {
    opacity: 0;
}

.game__paint-board--done .game__paint-field {
    stroke: transparent;
    cursor: default;
}

.game__paint-side {
    flex: none;
    width: min(260px, 38%);
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-height: 0;
}

.game__paint-palette {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    overflow: auto;
}

.game__paint-swatch {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: var(--tap);
    padding: 6px 10px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--white);
    box-shadow: 0 4px 0 var(--ink);
    text-align: left;
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 80ms ease, box-shadow 80ms ease;
}

.game__paint-swatch:active {
    transform: translateY(3px);
    box-shadow: 0 1px 0 var(--ink);
}

/* The colour in the kid's hand: raised on the palette's tint and lifted a little more. */
.game__paint-swatch[aria-pressed="true"] {
    background: var(--cream);
    box-shadow: 0 6px 0 var(--ink);
    transform: translateY(-2px);
}

.game__paint-swatch-color {
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    border: var(--border-xs) solid var(--ink);
    background: var(--paint, #bdbdbd);
}

.game__paint-swatch-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.1;
}

.game__paint-swatch-question {
    font-family: var(--font-display);
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 800;
    color: var(--ink);
    white-space: nowrap;
}

/* The name under the question is the second signal for a kid who does not tell red from green. */
.game__paint-swatch-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--muted);
}

.game__paint-line {
    flex: none;
    margin: 0;
    padding: 8px 12px;
    border-radius: 14px;
    background: var(--cream);
    border: var(--border-xs) solid var(--ink);
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
    text-align: center;
}

.game__paint-check {
    flex: none;
}

/* In portrait the palette goes under the picture as a wrapping row of swatches. */
@media (orientation: portrait), (max-width: 899px) {
    .game__paint {
        flex-direction: column;
    }

    .game__paint-side {
        width: 100%;
    }

    .game__paint-palette {
        flex: none;
        flex-direction: row;
        flex-wrap: wrap;
        justify-content: center;
    }

    .game__paint-swatch {
        padding-right: 14px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .game__paint-field,
    .game__paint-number,
    .game__paint-swatch { transition: none; }
    .game__paint-field--wrong { animation: none; }
}

/* Spiegeln on the painting table: the shown half is painted and takes no tap, the mirror
   line runs through the middle of the picture, and both fade into the picture once the
   blank half matches. */
.game__mirror-shown {
    cursor: default;
    pointer-events: none;
}

.game__mirror-line {
    stroke: var(--ink);
    stroke-width: 0.9;
    stroke-dasharray: 2.4 1.6;
    stroke-linecap: round;
    pointer-events: none;
    transition: opacity 600ms ease;
}

.game__paint-board--done .game__mirror-line {
    opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
    .game__mirror-line { transition: none; }
}

/* Stromkreis: the circuit as tiles that turn under a tap, the line under it. */
.game__circuit {
    flex-direction: column;
    gap: var(--gap);
}

.game__circuit-board {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
}

.game__circuit-svg {
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: var(--circuit-cols, 1) / var(--circuit-rows, 1);
    border: var(--border-xs) solid var(--ink);
    border-radius: 12px;
    background: #f4efe4;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    overflow: hidden;
}

.game__circuit-cell {
    fill: var(--white);
    stroke: var(--frame-shadow);
    stroke-width: 0.35;
}

.game__circuit-tile {
    cursor: pointer;
    transform-box: fill-box;
    transform-origin: center;
    transition: transform 220ms ease;
}

.game__circuit-tile--b,
.game__circuit-tile--p { cursor: default; }

.game__circuit-hit { fill: transparent; }

.game__circuit-arm {
    stroke: #6b7a86;
    stroke-width: 2.1;
    stroke-linecap: round;
    transition: stroke 160ms ease;
}

.game__circuit-tile--joined .game__circuit-arm,
.game__circuit-tile--joined .game__circuit-lever { stroke: #3d7cc9; }

.game__circuit-tile--powered .game__circuit-arm,
.game__circuit-tile--powered .game__circuit-lever { stroke: #e0a100; }

.game__circuit-node { fill: #6b7a86; }
.game__circuit-tile--joined .game__circuit-node { fill: #3d7cc9; }
.game__circuit-tile--powered .game__circuit-node { fill: #e0a100; }

.game__circuit-battery {
    fill: var(--ink);
}

.game__circuit-pole { fill: var(--white); }

.game__circuit-bulb {
    fill: var(--white);
    stroke: var(--ink);
    stroke-width: 0.6;
    transition: fill 160ms ease;
}

.game__circuit-bulb--lit {
    fill: #ffd84a;
    filter: drop-shadow(0 0 1.6px #ffc400);
}

.game__circuit-lever {
    stroke: #6b7a86;
    stroke-width: 1.6;
    stroke-linecap: round;
    transition: stroke 160ms ease;
}

.game__circuit-pivot { fill: var(--ink); }

.game__circuit-board--done .game__circuit-svg {
    box-shadow: 0 0 0 4px #ffd84a;
}

.game__circuit-line {
    flex: none;
    margin: 0;
    padding: 8px 12px;
    border-radius: 14px;
    background: var(--cream);
    border: var(--border-xs) solid var(--ink);
    font-size: 16px;
    font-weight: 700;
    color: var(--ink);
    text-align: center;
}

@media (prefers-reduced-motion: reduce) {
    .game__circuit-tile,
    .game__circuit-arm,
    .game__circuit-bulb,
    .game__circuit-lever { transition: none; }
}

/* Tastatur-Spiel: the item to type, one box per character, the keyboard picture under it.
   The text comes first so it stays above an on-screen keyboard; the picture below scrolls. */
.game__type-body {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
}

.game__type {
    display: flex;
    flex-direction: column;
    gap: var(--gap);
    width: 100%;
}

.game__type-dots {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
}

.game__type-dot {
    width: 14px;
    height: 14px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
}

.game__type-dot--now { background: var(--cream); }
.game__type-dot--done { background: var(--go); }

.game__type-text {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.35em 0;
    min-height: 2.2em;
    padding: 8px 0;
    font-family: var(--font-display);
    font-weight: 800;
    line-height: 1.15;
    color: var(--ink);
}

.game__type-text[data-size="huge"] { font-size: clamp(72px, 24vh, 160px); }
.game__type-text[data-size="big"] { font-size: clamp(40px, 11vh, 72px); }
.game__type-text[data-size="line"] { font-size: clamp(26px, 6vh, 44px); }

/* A word never breaks inside; the space after it is part of it, so a line ends there. */
.game__type-word {
    display: inline-flex;
    white-space: nowrap;
}

.game__type-char {
    display: inline-block;
    min-width: 0.6em;
    padding: 0 0.04em;
    border-bottom: 0.08em solid transparent;
    border-radius: 0.12em;
    color: var(--muted);
    opacity: 0.55;
    text-align: center;
    transition: color 120ms ease, opacity 120ms ease, background 120ms ease;
}

.game__type-char--done {
    color: var(--ink);
    opacity: 1;
}

.game__type-char--next {
    color: var(--ink);
    opacity: 1;
    background: var(--cream);
    border-bottom-color: var(--ink);
    animation: type-next 1.1s ease-in-out infinite;
}

.game__type-char--space {
    min-width: 0.45em;
    border-bottom-color: var(--muted);
}

.game__type-text--done .game__type-char {
    color: var(--go);
}

@keyframes type-next {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-0.06em); }
}

.game__type-hint {
    margin: 0;
    padding: 8px 12px;
    border-radius: 14px;
    background: var(--cream);
    border: var(--border-xs) solid var(--ink);
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
    text-align: center;
}

/* The input is there for the keyboard, not for the eye: off the screen, never hidden,
   because a hidden input gets no focus and brings no keyboard. */
.game__type-input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
}

/* ---- The keyboard picture ---- */
.game__type-keys {
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding: 8px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--white);
}

.game__type-row {
    display: flex;
    gap: 5px;
}

/* The rows are staggered the way the real keys are. */
.game__type-row:nth-child(2) { padding-left: 4%; }
.game__type-row:nth-child(3) { padding-left: 7%; }
.game__type-row:nth-child(5) { padding: 0 18%; }

.game__type-key {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    height: clamp(26px, 5vh, 40px);
    border: 2px solid var(--ink);
    border-radius: 7px;
    background: var(--white);
    font-family: var(--font-display);
    font-size: clamp(12px, 2.6vh, 19px);
    font-weight: 800;
    color: var(--ink);
    transition: background 100ms ease, transform 100ms ease;
}

.game__type-key--shift { flex-grow: 1.6; }

.game__type-key--lit {
    background: var(--cream);
    box-shadow: 0 0 0 3px var(--star);
    transform: translateY(-2px);
}

.game__type-bar {
    display: flex;
    justify-content: center;
}

@media (prefers-reduced-motion: reduce) {
    .game__type-char--next { animation: none; }
    .game__type-key, .game__type-char { transition: none; }
}

/* The grid games (Labyrinth, Kistenschieber): the board, its pieces and the D-pad. */
.game__board-body {
    align-items: stretch;
}

.game__maze {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 0;
}

.game__grid {
    display: grid;
    grid-template-columns: repeat(var(--cols, 7), 1fr);
    gap: 2px;
    flex: 0 1 auto;
    width: 100%;
    max-width: min(100%, 58dvh);
    min-height: 0;
    aspect-ratio: 1;
    padding: 6px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 18px;
    background: var(--ink);
    /* The board takes the finger itself, so a swipe never scrolls the page underneath. */
    touch-action: none;
}

.game__grid--bump {
    animation: board-bump 220ms ease;
}

.game__grid--done {
    box-shadow: 0 0 0 4px var(--go);
}

@keyframes board-bump {
    0%, 100% { transform: none; }
    30% { transform: translateX(-4px); }
    70% { transform: translateX(4px); }
}

.game__tile {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-radius: 4px;
    background: var(--white);
    font-size: clamp(8px, 2.2dvh, 20px);
    line-height: 1;
}

.game__tile--wall { background: var(--ink); border-radius: 3px; }
.game__tile--goal { background: var(--go); color: var(--white); }
.game__tile--star { color: var(--tile-color); }
.game__tile--target { color: var(--tile-color); background: var(--tile-tint); }
.game__tile--taken .game__tile-face { opacity: 0.15; }

/* What is standing on a field right now: the figure, a box. */
.game__piece {
    position: absolute;
    inset: 2px;
    display: none;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    font-size: clamp(9px, 2.4dvh, 22px);
}

.game__tile--figure .game__piece,
.game__tile--box .game__piece { display: flex; }

.game__tile--figure .game__tile-face { opacity: 0.25; }

.game__tile--figure .game__piece::before { content: "🙂"; }

.game__tile--box .game__piece {
    background: var(--g7, #ff9a3c);
    border: 2px solid var(--ink);
    box-shadow: inset 0 0 0 2px rgb(0 0 0 / 0.12);
}

.game__tile--box-done .game__piece {
    background: var(--go);
}

/* A box that can no longer reach a goal field — wedged in a corner, or lying in a lane it
   can never leave. It goes pale and dashed: out of play, not wrong. The dashed edge is the
   point, a colour-blind kid must be able to see it too. */
.game__tile--box-stuck .game__piece {
    background: var(--muted);
    border-style: dashed;
    box-shadow: none;
    opacity: 0.8;
}

/* The figure never stands on a box, so this pair can only be the figure. */
.game__tile--figure.game__tile--box .game__piece::before { content: ""; }

.game__maze-hint {
    margin: 0;
    font-size: 16px;
    font-weight: 700;
    color: var(--muted);
    text-align: center;
}

/* The D-pad: a cross of four keys, each at least a fingertip wide, plus what a game adds. */
.game__dpad {
    display: grid;
    grid-template-columns: repeat(3, 64px);
    grid-template-rows: repeat(2, 56px);
    gap: 8px;
    justify-content: center;
}

.game__dpad .game__key--undo { grid-area: 1 / 1; }
.game__dpad .game__key--up { grid-area: 1 / 2; }
.game__dpad .game__key--left { grid-area: 2 / 1; }
.game__dpad .game__key--down { grid-area: 2 / 2; }
.game__dpad .game__key--right { grid-area: 2 / 3; }

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

/* Trommelzauber: the five drums under whatever the stage is showing. */
.game__trommel {
    display: flex;
    flex-direction: column;
    gap: var(--gap);
    width: 100%;
    height: 100%;
    min-height: 0;
    justify-content: flex-end;
}

.game__trommel-hint {
    margin: 0;
    text-align: center;
    font-size: 17px;
    font-weight: 700;
    color: var(--muted);
    min-height: 1.4em;
}

/* ==========================================================================
   Die Ebene — the plane the troop walks (Trommelzauber)

   Everything that moves reads --cycle (seconds for one scroll) and --lean off
   .game__scene; trommel-scene.js sets those from the gait. Only transform and
   background-position are animated, never layout.
   ========================================================================== */
/* The plane takes what is left once the rows below it have what they need, and it is the
   part that gives way when the screen is short — never the drums. */
.game__stage-scene {
    flex: 1 1 auto;
    min-height: 96px;
    max-height: 260px;
}

.game__scene {
    --cycle: 9s;
    --bob: 1.1s;
    --lean: 0deg;
    --ground: 34%;
    --far: oklch(0.68 0.15 var(--hue, 40));
    --near: oklch(0.58 0.16 var(--hue, 40));

    position: relative;
    height: 100%;
    min-height: 120px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 18px;
    overflow: hidden;
    box-shadow: 0 6px 0 var(--ink);
}

.game__sky {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        oklch(0.74 0.17 var(--hue, 40)) 0%,
        oklch(0.85 0.14 var(--hue, 40)) 55%,
        oklch(0.93 0.08 var(--hue, 40)) 100%);
}

/* A low sun behind everything; it does not travel, the world does. */
.game__sun {
    position: absolute;
    left: 74%;
    bottom: var(--ground);
    width: 92px;
    height: 92px;
    margin: 0 0 -30px -46px;
    border-radius: 999px;
    background: oklch(0.95 0.09 var(--hue, 40));
    opacity: 0.85;
}

/* Round canopies, drawn as repeating radial gradients — no image, no request. */
.game__trees {
    position: absolute;
    left: 0;
    right: 0;
    bottom: var(--ground);
    background-repeat: repeat-x;
    background-position-x: 0;
    animation: scene-scroll var(--cycle) linear infinite;
}

.game__trees--far {
    height: 46%;
    background-image:
        radial-gradient(circle at 44px 58px, var(--far) 33px, transparent 34px),
        radial-gradient(circle at 128px 74px, var(--far) 20px, transparent 21px),
        radial-gradient(circle at 196px 66px, var(--far) 26px, transparent 27px);
    background-size: 240px 100%;
    /* Further away, so it drifts by more slowly. */
    animation-duration: calc(var(--cycle) * 3);
}

/* Every scrolling layer tiles at 240px, because that is how far the keyframe travels; a
   tile of any other width would jump at the end of each loop. */
.game__trees--near {
    height: 22%;
    background-image:
        radial-gradient(circle at 30px 46px, var(--near) 19px, transparent 20px),
        radial-gradient(circle at 108px 52px, var(--near) 13px, transparent 14px),
        radial-gradient(circle at 186px 48px, var(--near) 16px, transparent 17px);
    background-size: 240px 100%;
    animation-duration: calc(var(--cycle) * 1.6);
}

.game__ground {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--ground);
    background-color: var(--ink);
    background-image: repeating-linear-gradient(90deg,
        transparent 0 46px, rgba(255, 255, 255, 0.13) 46px 60px);
    background-size: 240px 100%;
    background-repeat: repeat-x;
    animation: scene-scroll var(--cycle) linear infinite;
}

@keyframes scene-scroll {
    to { background-position-x: -240px; }
}

/* Nothing streams past a game that is not running. */
.game__scene[data-moving="false"] .game__trees,
.game__scene[data-moving="false"] .game__ground,
.game__scene[data-moving="false"] .game__lines,
.game__scene[data-moving="false"] .game__wichtel-inner,
.game__scene[data-moving="false"] .game__wichtel-legs > span {
    animation-play-state: paused;
}

/* ---- Die Wichtel ---- */
.game__troop {
    position: absolute;
    left: 26%;
    bottom: calc(var(--ground) - 4px);
    display: flex;
    align-items: flex-end;
    gap: 6px;
}

/* Three ways to cover a field, one per melody. The troop does not travel — the world does —
   so each of these ends where it began. */
.game__troop--step {
    animation: troop-step 260ms ease-out;
}

@keyframes troop-step {
    0% { transform: translateX(-10px); }
    100% { transform: translateX(0); }
}

/* Over the hole, which is sliding left underneath them as this plays. */
.game__troop--jump {
    animation: troop-jump 680ms cubic-bezier(0.3, 0, 0.4, 1);
}

@keyframes troop-jump {
    0% { transform: translate(-12px, 0) rotate(0); }
    30% { transform: translate(0, -44px) rotate(-12deg); }
    58% { transform: translate(10px, -46px) rotate(8deg); }
    100% { transform: translate(0, 0) rotate(0); }
}

/* Round the fruit, and round the flower at the end. */
.game__troop--dance {
    animation: troop-dance 900ms ease-in-out;
}

@keyframes troop-dance {
    0%, 100% { transform: translateY(0) rotate(0); }
    18% { transform: translateY(-12px) rotate(-16deg); }
    42% { transform: translateY(0) rotate(14deg); }
    66% { transform: translateY(-12px) rotate(-10deg); }
    86% { transform: translateY(0) rotate(5deg); }
}

/* The lean is a plain transform, not part of the bob: with reduced motion on, the bob goes
   and the lean stays, so the gait still reads with nothing moving. */
.game__wichtel {
    position: relative;
    display: block;
    width: 26px;
    height: 32px;
    transform: rotate(var(--lean));
    transform-origin: 50% 100%;
    transition: transform 300ms ease;
}

.game__wichtel-inner {
    position: absolute;
    inset: 0;
    /* Each one a little out of step with the next, so it reads as a group and not a comb. */
    animation: wichtel-bob var(--bob) ease-in-out infinite;
    animation-delay: calc(var(--i) * var(--bob) / -6);
}

.game__wichtel-body {
    position: absolute;
    inset: 6px 0 8px;
    border-radius: 50% 50% 44% 44%;
    background: var(--ink);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ---- Beine ---- */
.game__wichtel-legs {
    position: absolute;
    left: 5px;
    right: 5px;
    bottom: 0;
    height: 9px;
    display: flex;
    justify-content: space-between;
}

.game__wichtel-legs > span {
    display: block;
    width: 4px;
    height: 9px;
    border-radius: 0 0 2px 2px;
    background: var(--ink);
    transform-origin: 50% 0;
    animation: wichtel-step var(--bob) ease-in-out infinite;
}

/* The back leg is half a stride behind the front one — that is the whole trick. */
.game__wichtel-legs > span:last-child {
    animation-delay: calc(var(--bob) / -2);
}

@keyframes wichtel-step {
    0%, 100% { transform: rotate(-24deg); }
    50% { transform: rotate(24deg); }
}

/* ---- Arme ---- */
/* Only out when they are going flat out: streaming behind, which is the whole joke. */
.game__wichtel-arms {
    position: absolute;
    left: 0;
    right: 0;
    top: 13px;
    height: 3px;
    opacity: 0;
    transition: opacity 200ms ease;
}

.game__wichtel-arms > span {
    position: absolute;
    right: 14px;
    width: 15px;
    height: 3px;
    border-radius: 2px;
    background: var(--ink);
    transform-origin: 100% 50%;
}

.game__wichtel-arms > span:first-child { transform: rotate(16deg); }
.game__wichtel-arms > span:last-child { top: 5px; transform: rotate(30deg); }

.game__scene[data-gait="4"] .game__wichtel-arms { opacity: 1; }

/* Eyes narrow when they are really shifting. */
.game__scene[data-gait="4"] .game__wichtel-eye {
    height: 8px;
    border-radius: 6px;
}

/* ---- Tempolinien ---- */
/* Three rows of dashes streaming past the troop. Horizontal stripes would not do: a
   pattern that never changes along x looks perfectly still however fast you scroll it. */
.game__lines {
    position: absolute;
    left: 0;
    right: 0;
    bottom: calc(var(--ground) + 2px);
    height: 30%;
    opacity: 0;
    background-image:
        repeating-linear-gradient(90deg, rgba(29, 43, 51, 0.50) 0 30px, transparent 30px 80px),
        repeating-linear-gradient(90deg, rgba(29, 43, 51, 0.38) 0 18px, transparent 18px 80px),
        repeating-linear-gradient(90deg, rgba(29, 43, 51, 0.45) 0 24px, transparent 24px 80px);
    background-size: 240px 3px, 240px 2px, 240px 2px;
    background-position: 0 26%, 0 54%, 0 78%;
    background-repeat: repeat-x;
    animation: scene-scroll calc(var(--cycle) / 2) linear infinite;
    transition: opacity 220ms ease;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 20%, #000 64%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 20%, #000 64%, transparent 100%);
}

.game__scene[data-gait="3"] .game__lines { opacity: 0.35; }
.game__scene[data-gait="4"] .game__lines { opacity: 1; }

.game__wichtel-eye {
    width: 13px;
    height: 13px;
    border-radius: 999px;
    background: var(--white);
    box-shadow: inset 0 0 0 4px var(--ink);
}

/* The one tuft on top; it is what makes the silhouette read as a creature. */
.game__wichtel-tuft {
    position: absolute;
    left: 50%;
    top: 0;
    width: 3px;
    height: 9px;
    margin-left: -1.5px;
    border-radius: 2px;
    background: var(--ink);
    transform-origin: 50% 100%;
}

@keyframes wichtel-bob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-4px); }
}

/* ---- Das kleine HUD in der Ecke ----
   One square per stage, filled as it is banked, and a bar with an end to it for the path
   of the stage on the table. It sits on the sky, so it carries its own outline. */
.game__hud {
    position: absolute;
    left: 10px;
    top: 9px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.game__pips {
    display: flex;
    gap: 4px;
}

.game__pip {
    width: 13px;
    height: 13px;
    border: 2px solid var(--ink);
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.72);
}

.game__pip--done {
    background: var(--ink);
}

.game__bar {
    position: relative;
    display: block;
    width: clamp(84px, 22vw, 150px);
    height: 13px;
    border: 2px solid var(--ink);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.72);
    overflow: hidden;
}

.game__bar-fill {
    display: block;
    width: 0;
    height: 100%;
    background: var(--ink);
    border-radius: 999px;
    transition: width 320ms ease;
}

.game__bar--full .game__bar-fill {
    background: var(--go);
}

/* ---- Was auf dem Weg steht ----

   The first version of this drew the hole in oklch(0.93 0.08 var(--hue)) — which is exactly
   the bottom stop of .game__sky — and stood it above the ground line. It was invisible by
   construction, and the flower was white on the same pale sky. So: a hole is cut *into* the
   black ground, and anything standing *on* the ground carries an outline. */
.game__things {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.game__thing {
    --d: 0;
    position: absolute;
    /* The nearest stands just ahead of the troop at 26%, the others behind it. Far enough
       apart to read as distance, close enough that a jump happens over the hole. */
    left: calc(37% + var(--d) * 16%);
    bottom: var(--ground);
    display: flex;
    align-items: flex-end;
    justify-content: center;
    transition: left 380ms ease, opacity 320ms ease;
}

.game__thing--gone {
    opacity: 0;
}

/* Where they are standing: the flower they have just reached, not one still ahead. */
.game__thing--here {
    left: 31%;
}

.game__thing-face {
    font-size: 34px;
    line-height: 1;
    /* An outline in every direction: these stand on a pale sky and must read from a lap. */
    text-shadow:
        2px 0 0 var(--ink), -2px 0 0 var(--ink), 0 2px 0 var(--ink), 0 -2px 0 var(--ink),
        2px 2px 0 var(--ink), -2px 2px 0 var(--ink), 2px -2px 0 var(--ink), -2px -2px 0 var(--ink);
}

/* A stalk, so the thing stands on the ground instead of hovering over it. */
.game__thing--fruit::after,
.game__thing--flower::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -9px;
    width: 4px;
    height: 12px;
    margin-left: -2px;
    border-radius: 2px;
    background: var(--ink);
}

.game__thing--fruit .game__thing-face {
    color: oklch(0.78 0.19 90);
}

.game__thing--flower .game__thing-face {
    color: oklch(0.88 0.10 350);
}

/* The hole: a pale notch whose flat top sits exactly on the ground line and which dips into
   the black. Pale on black is the one pairing here that cannot disappear. */
.game__thing--hole {
    bottom: calc(var(--ground) - 27px);
    width: 54px;
    margin-left: -27px;
    height: 27px;
    border: 3px solid var(--ink);
    border-top: none;
    border-radius: 0 0 27px 27px / 0 0 20px 20px;
    background: oklch(0.93 0.08 var(--hue, 40));
    box-shadow: inset 0 6px 10px -4px rgba(0, 0, 0, 0.45);
}

.game__thing--bloom .game__thing-face {
    color: oklch(0.74 0.24 350);
    animation: flower-bloom 700ms ease-out;
}

.game__thing--bloom::before {
    content: '';
    position: absolute;
    left: 50%;
    bottom: 0;
    width: 92px;
    height: 92px;
    margin: 0 0 -26px -46px;
    border-radius: 999px;
    background: radial-gradient(circle, oklch(0.85 0.16 350 / 0.6) 0%, transparent 68%);
    animation: flower-burst 900ms ease-out;
}

@keyframes flower-bloom {
    0% { transform: scale(0.4) rotate(-40deg); }
    60% { transform: scale(1.35) rotate(8deg); }
    100% { transform: scale(1) rotate(0); }
}

@keyframes flower-burst {
    0% { transform: scale(0.2); opacity: 0; }
    40% { opacity: 1; }
    100% { transform: scale(1.6); opacity: 0; }
}

/* ---- Angekommen ---- */
.game__scene[data-done="true"] .game__sky {
    filter: brightness(1.12);
}

.game__scene[data-done="true"] .game__wichtel-inner {
    animation: wichtel-cheer 520ms ease-out 3;
}

@keyframes wichtel-cheer {
    0%, 100% { transform: translateY(0); }
    35% { transform: translateY(-14px); }
    70% { transform: translateY(0); }
}


/* The melody to copy, as coloured chips: the same information the ear gets, for an iPad
   whose mute switch is on. */
.game__melody-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    min-height: 44px;
}

/* Was kommt: the melody wanted now, big, and the two fields behind it, small. Until this
   existed the new melody appeared at the very instant it was needed, which a playtest found
   unplayable — a preview is most of the answer. */
.game__ahead {
    display: flex;
    align-items: stretch;
    gap: 8px;
}

.game__step {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 14px;
    background: var(--white);
    opacity: 0.6;
}

/* The one they are walking into. */
.game__step--now {
    opacity: 1;
    background: var(--tile-tint);
    box-shadow: 0 3px 0 var(--ink);
}

.game__step-field {
    font-size: 19px;
    line-height: 1;
    color: var(--ink);
}

.game__step--now .game__step-field {
    font-size: 24px;
}

.game__step[data-field="O"] .game__step-field { color: oklch(0.45 0.13 25); }
.game__step[data-field="*"] .game__step-field { color: var(--go); }
.game__step[data-field="B"] .game__step-field { color: oklch(0.62 0.2 350); }

.game__step-name {
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 800;
    color: var(--ink);
}

.game__step-name:empty {
    display: none;
}

.game__step-chips {
    display: flex;
    gap: 4px;
}

/* The melody changed: only the one in front flashes, the two behind are not news yet. */
.game__step--new {
    animation: melody-new 900ms ease-out;
}

@keyframes melody-new {
    0%, 100% { background: var(--tile-tint); transform: scale(1); }
    20% { background: var(--cream); transform: scale(1.07); }
}

.game__chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 2px solid var(--ink);
    border-radius: 7px;
    background: var(--drum);
    color: var(--white);
    font-size: 12px;
    line-height: 1;
}

/* The melody they need right now is the one worth reading across the room. */
.game__step--now .game__chip {
    width: 32px;
    height: 32px;
    border-radius: 10px;
    font-size: 16px;
}

.game__tally {
    font-size: 18px;
    font-weight: 800;
    color: var(--go);
    min-width: 46px;
}

/* How fast the troop is going. The scene shows it too; the name stays, because with
   reduced motion on it is the only thing that says how fast they are. */
.game__gait {
    padding: 4px 12px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 800;
    white-space: nowrap;
}

.game__gait[data-gait="3"],
.game__gait[data-gait="4"] {
    background: var(--tile-color);
    color: var(--white);
}

/* Four lamps: the beat of the bar walking across them. */
.game__beats {
    display: flex;
    gap: 10px;
    justify-content: center;
}

.game__beat {
    width: 18px;
    height: 18px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    transition: transform 80ms ease, background-color 80ms ease;
}

/* The beats the melody actually sits on, so the empty rest of the bar reads as a rest. */
.game__beat--note {
    background: var(--tile-tint);
}

.game__beat--on {
    background: var(--tile-color);
    transform: scale(1.35);
}

.game__drums {
    display: flex;
    gap: 10px;
    flex: 0 0 auto;
}

.game__drum {
    flex: 1 1 0;
    min-width: 0;
    /* Big enough for a small finger that is aiming in a hurry, on any screen. */
    min-height: clamp(66px, 11vh, 92px);
    border: var(--border-xs) solid var(--ink);
    border-radius: 20px;
    background: var(--drum);
    box-shadow: 0 6px 0 var(--ink);
    color: var(--white);
    font-size: 30px;
    line-height: 1;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 90ms ease, box-shadow 90ms ease;
}

.game__drum:active {
    transform: translateY(4px);
    box-shadow: 0 2px 0 var(--ink);
}

/* Struck: a short flash, restarted by taking the class off for a frame. */
.game__drum--hit {
    animation: drum-hit 260ms ease-out;
}

@keyframes drum-hit {
    0% { filter: brightness(1.9); transform: translateY(4px) scale(1.04); }
    100% { filter: brightness(1); transform: translateY(0) scale(1); }
}

.game__trommel-bar {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px;
}

.game__music {
    min-width: 170px;
}

.game__help {
    min-width: 150px;
}

.game__help[aria-pressed="false"] {
    opacity: 0.72;
}

/* The drums fill the width of the stage body, which the other games keep for a board. */
.game__trommel-body {
    align-items: stretch;
    /* The game fits the space it has; it must never be the thing that scrolls. */
    overflow: hidden;
}

/* A short landscape screen — an iPad on its side is the case that matters. */
@media (max-height: 660px) {
    .game__stage-scene { max-height: 168px; }
    .game__trommel { gap: 10px; }
    .game__melody-row { min-height: 40px; }
}


@media (prefers-reduced-motion: reduce) {
    .game__drum--hit { animation: none; }
    .game__drum:active { transform: none; }
    .game__beat { transition: none; }
    .game__step--new { animation: none; }
    .game__trees,
    .game__ground,
    .game__lines,
    .game__wichtel-inner,
    .game__wichtel-legs > span,
    .game__troop--step,
    .game__troop--jump,
    .game__troop--dance,
    .game__thing--bloom .game__thing-face,
    .game__thing--bloom::before { animation: none; }
    .game__wichtel,
    .game__wichtel-arms,
    .game__bar-fill,
    .game__thing,
    .game__lines { transition: none; }
}

/* Keyboard focus: the games are tapped on an iPad, but a Mac keyboard must still show
   where it is. :focus-visible keeps the ring off a finger tap. */
.game__key:focus-visible,
.game__button:focus-visible,
.game__memo-card:focus-visible,
.game__drum:focus-visible,
.game__music:focus-visible,
.game__help:focus-visible,
.game__stage-music:focus-visible,
.game__stage-speak:focus-visible {
    outline: 3px solid var(--ink);
    outline-offset: 3px;
}

/* Overlays sit on the board: start card, pause, result. */
.game__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 22px;
    border-radius: 18px;
    background: rgba(24, 20, 54, 0.93);
    color: var(--night-ink);
    text-align: center;
}

.game__overlay-title {
    font-size: clamp(24px, 3vw, 30px);
    color: var(--night-ink);
}

.game__overlay-text {
    margin: 0;
    max-width: 26ch;
    font-size: 15px;
    line-height: 1.45;
    color: var(--night-dim);
}

.game__overlay-stars {
    font-size: 40px;
    line-height: 1;
    color: var(--star);
    letter-spacing: 4px;
}

.game__overlay-button {
    width: min(100%, 240px);
    padding: 10px 20px;
    font-size: 20px;
    box-shadow: 0 5px 0 var(--ink);
}

.game__overlay .game__overlay-button:not(.button--primary) {
    background: var(--white);
    color: var(--ink);
}

.game__toast {
    position: absolute;
    top: 14px;
    left: 14px;
    right: 14px;
    padding: 10px 16px;
    border: var(--border-xs) solid var(--ink);
    border-radius: 999px;
    background: var(--star);
    box-shadow: 0 5px 0 var(--ink);
    font-family: var(--font-display);
    font-size: 20px;
    font-weight: 800;
    text-align: center;
    animation: game-toast 240ms ease-out;
}

@keyframes game-toast {
    from { transform: translateY(-12px) scale(0.9); opacity: 0; }
    to { transform: none; opacity: 1; }
}

/* Phones: cards move below the board in a row. */
@media (max-width: 699px) {
    .game__stage {
        flex-direction: column;
        align-items: center;
    }

    .game__side {
        width: 100%;
        flex-direction: row;
        flex-wrap: wrap;
    }

    .game__card {
        flex: 1 1 40%;
    }

    .game__buttons {
        flex: 1 1 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .game__cell--pop {
        animation: none;
        opacity: 0;
    }

    .game__cell--hint {
        animation: none;
        filter: brightness(1.35);
    }

    .game__toast {
        animation: none;
    }

    .game__goal-fill {
        transition: none;
    }
}

/* ==========================================================================
   Vorlesen — the speaker buttons and the auto-speak switch
   ========================================================================== */

.speech {
    display: flex;
    align-items: center;
    gap: 8px;
}

.speak {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap);
    min-height: var(--tap);
    padding: 0 10px;
    border: var(--border-sm) solid var(--ink);
    border-radius: 999px;
    background: var(--white);
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 800;
    line-height: 1;
    box-shadow: 0 4px 0 var(--ink);
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

.speak:active {
    transform: translateY(3px);
    box-shadow: 0 1px 0 var(--ink);
}

/* The switch says whether a new task reads itself out; struck through when it does not. */
.speak--auto {
    padding: 0 16px;
    background: var(--go);
    color: var(--white);
    font-size: clamp(14px, 1.4vw, 17px);
}

.speak--auto.speak--off {
    background: var(--white);
    color: var(--ink);
    text-decoration: line-through;
}

/* The way to the recording page; grown-ups only, so it stays quiet. */
.speak--record {
    text-decoration: none;
    font-size: 20px;
}

.speak--big {
    min-width: 56px;
    min-height: 56px;
    font-size: 26px;
}

/* Prompt and its speaker sit on one line, wrapping on a phone. */
.player__prompt-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    flex-wrap: wrap;
}

/* Foto-Safari: the row under the assignment — for now the one button that counts the
   task; the camera button and the preview join it. */
.player__foto-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    flex-wrap: wrap;
    padding-block: clamp(8px, 1.6vh, 20px);
}

/* The file input stays in the tree for the label, out of sight for everyone else. */
.player__foto-file {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
}

.player__foto-take {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: var(--tap);
    padding: 12px 28px;
    font-size: clamp(20px, 2.4vw, 26px);
    cursor: pointer;
    box-shadow: 0 5px 0 var(--pill-shadow);
}

.player__foto-take:active:not(.player__foto-take--disabled) {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.player__foto-take--disabled {
    opacity: 0.55;
    pointer-events: none;
}

.player__foto-keep {
    min-height: var(--tap);
    padding: 12px 28px;
    font-size: clamp(20px, 2.4vw, 26px);
    box-shadow: 0 5px 0 var(--pill-shadow);
}

.player__foto-keep:disabled {
    opacity: 0.55;
    cursor: default;
}

/* The preview: the shrunk picture as it will be kept, never taller than the card allows. */
.player__foto-preview {
    align-self: center;
    max-width: 100%;
    max-height: min(42vh, 360px);
    object-fit: contain;
    border: var(--border-xs) solid var(--ink);
    border-radius: 16px;
    background: var(--cream);
}

.player__foto-note {
    margin: 0;
    color: var(--muted);
    font-size: 16px;
    font-weight: 700;
    flex-basis: 100%;
    text-align: center;
}

.player__foto-error {
    color: oklch(0.5 0.19 25);
}

.player__foto-found[hidden],
.player__foto-keep[hidden],
.player__foto-preview[hidden],
.player__foto-error[hidden] {
    display: none;
}

/* Lesen: the sentence the kid reads, under the prompt. Left-aligned and widely spaced —
   a beginner follows a line with a finger, and centred prose has no line to follow. */
.player__reading {
    align-self: stretch;
    margin: 0;
    padding: clamp(12px, 1.6vh, 18px) clamp(16px, 2vw, 24px);
    background: var(--cream);
    border: var(--border-xs) solid var(--ink);
    border-radius: 20px;
    font-family: var(--font-display);
    font-size: min(clamp(28px, 3.4vw, 40px), 5vh);
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.02em;
    text-align: left;
    overflow-wrap: anywhere;
}

/* The row under the sentence: the note and the one button where nothing records. */
.player__reading-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    flex-wrap: wrap;
}

.player__reading-note {
    margin: 0;
    color: var(--muted);
    font-size: 16px;
    font-weight: 700;
}

.player__reading-error {
    color: oklch(0.45 0.18 25);
}

/* The recorder: Aufnehmen, Stopp with the seconds beside it, the preview, Behalten. */
.player__recorder {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    flex-wrap: wrap;
    width: 100%;
}

.player__recorder-button {
    min-height: var(--tap);
    padding: 10px 22px;
    font-size: clamp(18px, 2vw, 22px);
    box-shadow: 0 5px 0 var(--pill-shadow);
}

.player__recorder-button:active:not(:disabled) {
    transform: translateY(3px);
    box-shadow: 0 2px 0 var(--pill-shadow);
}

.player__recorder-button:disabled {
    opacity: 0.55;
    cursor: default;
}

.player__recorder-stop {
    background: oklch(0.62 0.2 25);
    color: var(--white);
}

.player__recorder-timer {
    min-width: 3ch;
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 800;
    color: var(--ink);
}

/* The red dot beside the seconds while the microphone is open. */
.player__recorder-timer--live::before {
    content: "";
    display: inline-block;
    width: 12px;
    height: 12px;
    margin-right: 8px;
    border-radius: 50%;
    background: oklch(0.62 0.2 25);
    animation: recorder-pulse 1s ease-in-out infinite;
}

@keyframes recorder-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.player__recorder-preview {
    flex: 1 1 220px;
    min-width: 0;
    max-width: 360px;
    height: 44px;
}

.player__recorder-preview[hidden],
.player__recorder-button[hidden],
.player__reading-done[hidden],
.player__reading-error[hidden] {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .player__recorder-timer--live::before { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
    .speak:active {
        transform: none;
    }
}

/* ==========================================================================
   Vorlesen aufnehmen — /Admin/Exercises/{id}/speech
   ========================================================================== */

/* One column: this page has no upload card beside the list. */
.admin-speech {
    grid-template-columns: minmax(0, 1fr);
}

.speech-row__actions {
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.speech-row__audio {
    height: 40px;
    max-width: 100%;
    flex: 1 1 240px;
}

.speech-row__upload {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.speech-row__file {
    max-width: 210px;
    font-family: var(--font-body);
    font-size: 14px;
}

.speech-row[data-kind="recorded"] {
    border-color: var(--go);
}

/* The record controls only exist once the script decides the browser may listen. */
.speech-row__record[hidden] {
    display: none !important;
}

.speech-row__record {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    width: 100%;
}

.speech-row__error {
    color: oklch(0.45 0.18 25);
    font-weight: 700;
}

.speech-row__timer {
    font-family: var(--font-display);
    font-weight: 800;
    min-width: 46px;
}
