/* Shared look for the frontpage and every game: blue sky, cream panels, pink buttons. */

/* Fredoka (OFL), self-hosted: no third-party request, no layout jump. */
@font-face {
  font-family: "Fredoka";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/fredoka-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fredoka";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("fonts/fredoka-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
:root {
  --cream: #fff4e1;
  --cream-2: #f6e4c8;
  --cream-dark: #e4c9a4;
  --ink: #5b3a9b;
  --text: var(--ink);
  --muted: #7a62a8; /* 4.8:1 on cream */
  --purple: #8d4fe0;
  --purple-dark: #6a33b8;
  --purple-soft: #b9a4ef;
  --pink: #ff4fa3;
  --pink-dark: #cf2f7f;
  --pink-soft: #ffc6e3;
  --blue: #3fa2ff;
  --green: #5ad43a;
  --green-dark: #3ea626;
  --orange: #ff9a35;
  --red: #ff4b55;
  --lemon: #ffd23a;
  --accent: var(--pink);
  --danger: var(--red);
  --panel-shadow: 0 5px 0 var(--cream-dark), 0 16px 26px -14px rgba(90, 50, 150, 0.45);
  color-scheme: light;
}

* { box-sizing: border-box; }
:focus-visible { outline: 3px solid #2d8dff; outline-offset: 3px; }
[hidden] { display: none !important; }

html, body { margin: 0; }
/* no swipe-back navigation or pull-to-refresh while dragging in a game, and no double-tap zoom */
html, body { overscroll-behavior: none; }
body { touch-action: manipulation; }
/* A long press on a tablet must not open the browser's menu or select text: nothing in the arcade is for
   copying, except what you type in a field. */
body { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
input, textarea, [contenteditable] { -webkit-user-select: text; user-select: text; }
img, svg, canvas { -webkit-user-drag: none; }

html { min-height: 100%; background: var(--theme-sky, #bfe2ff); }

/* The landscape lives on its own fixed layer: iOS ignores background-attachment: fixed and would
   stretch it over the whole page, and a fixed layer doesn't repaint while scrolling. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background: var(--theme-sky, #bfe2ff) var(--theme-bg, url("candy-bg.svg")) center bottom / cover no-repeat;
  pointer-events: none;
}

body {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  color: var(--text);
  font-family: "Fredoka", "Baloo 2", "Nunito", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
}
/* decorations past the edge must not widen the page (phones would zoom out) */
html, body { overflow-x: clip; }

a { color: inherit; }

/* Chunky candy buttons. */
.btn {
  appearance: none;
  border: 0;
  border-radius: 20px;
  padding: 13px 30px;
  font: inherit;
  font-size: 1.2rem;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.15);
  background: linear-gradient(180deg, #ff7cbd, var(--pink));
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.45), 0 6px 0 var(--pink-dark), 0 14px 22px -10px rgba(207, 47, 127, 0.7);
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.1s ease, filter 0.15s ease;
}
.btn:hover { filter: brightness(1.05); }
.btn:active { transform: translateY(5px); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.45), 0 1px 0 var(--pink-dark); }
.btn--purple { background: linear-gradient(180deg, #a872ee, var(--purple)); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 6px 0 var(--purple-dark), 0 14px 22px -10px rgba(106, 51, 184, 0.7); }
.btn--purple:active { box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 1px 0 var(--purple-dark); }
.btn--cream { background: var(--cream); color: var(--ink); text-shadow: none; box-shadow: inset 0 2px 0 #fff, 0 6px 0 var(--cream-dark); }
.btn--cream:active { box-shadow: inset 0 2px 0 #fff, 0 1px 0 var(--cream-dark); }

/* Round pink icon buttons. */
.icon-btn, .back-link {
  display: inline-grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 40% 30%, #ff8ec8, var(--pink) 70%);
  color: #fff;
  font: inherit;
  font-size: 1.5rem;
  font-weight: 700;
  text-decoration: none;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.15);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 5px 0 var(--pink-dark), 0 10px 16px -8px rgba(207, 47, 127, 0.7);
  cursor: pointer;
  transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.icon-btn:active, .back-link:active { transform: translateY(4px); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 1px 0 var(--pink-dark); }

/* Cream panel. */
.panel {
  border-radius: 24px;
  background: linear-gradient(180deg, #fff8ec, var(--cream));
  box-shadow: inset 0 2px 0 #fff, inset 0 0 0 3px #fff, var(--panel-shadow);
}

.label {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--muted);
}

/* Logo-style text: every letter its own candy colour with a thick white outline. */
.candy-title { font-weight: 700; line-height: 1; letter-spacing: 0.01em; }
.candy-title span {
  display: inline-block;
  color: var(--c, var(--purple));
  -webkit-text-stroke: 0.14em #fff;
  paint-order: stroke fill;
  text-shadow: 0 0.09em 0 rgba(90, 50, 150, 0.3);
}
.candy-title span:nth-child(6n + 1) { --c: var(--pink); }
.candy-title span:nth-child(6n + 2) { --c: var(--orange); }
.candy-title span:nth-child(6n + 3) { --c: #f5b800; }
.candy-title span:nth-child(6n + 4) { --c: var(--green); }
.candy-title span:nth-child(6n + 5) { --c: var(--blue); }
.candy-title span:nth-child(6n + 6) { --c: var(--purple); }

/* Sound + restart buttons side by side in game headers */
.top-actions { display: flex; gap: 8px; }
@media (max-width: 400px) {
  .topbar .icon-btn, .topbar .back-link { width: 44px; height: 44px; font-size: 1.2rem; }
  .top-actions { gap: 6px; }
}

/* Hand-drawn icons (assets/art.js) inside buttons and labels */
.icon-btn i[data-icon], .back-link i[data-icon] { display: grid; place-items: center; line-height: 0; }
.icon-btn .art, .back-link .art { width: 0.95em; height: 0.95em; vertical-align: 0; }
kbd .art { width: 1em; height: 1em; vertical-align: -0.15em; }

/* The end-of-game card, the same in every game: an icon, a title, stars or a big score,
   a table with the results and two buttons ("Nog een keer!" and "Menu"). */
.end-card { width: min(400px, 100%); max-height: calc(100dvh - 28px); overflow-y: auto; padding: 18px 18px 20px; display: flex; flex-direction: column; gap: 10px; text-align: center; color: var(--ink); animation: end-card-in 0.3s ease; }
.end-card .over-icon { display: flex; justify-content: center; line-height: 0; }
.end-card .over-title { margin: 0; font-size: 1.7rem; font-weight: 700; line-height: 1.15; outline: none; }
.end-card .over-title.record { color: var(--pink-dark); }
.end-card .over-stars { display: flex; justify-content: center; gap: 6px; line-height: 0; }
.end-card .over-stars:empty { display: none; }
.end-card .over-stars span { width: 44px; height: 44px; }
.end-card .over-stars span:nth-child(2) { width: 54px; height: 54px; margin-top: -8px; }
.end-card .over-stars span:not(.on) { filter: grayscale(1); opacity: 0.3; }
.end-card .over-text { color: var(--muted); font-weight: 500; line-height: 1.45; }
.end-card .over-text:empty { display: none; }
.end-card .over-text p { margin: 0 0 8px; }
.end-card .over-text p:last-child { margin-bottom: 0; }
.end-card table { width: 100%; border-collapse: collapse; color: var(--ink); }
.end-card td { padding: 4px 6px; text-align: left; }
.end-card td:last-child { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; }
.end-card tr + tr td { border-top: 2px dashed var(--cream-2); }
.end-card td .art { vertical-align: -0.3em; }
.end-card tr.win td { color: var(--pink-dark); font-weight: 700; }
.end-card .over-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 6px; }
.end-card .over-actions .btn { flex: 1 1 120px; padding-left: 12px; padding-right: 12px; font-size: 1.1rem; white-space: nowrap; }
@keyframes end-card-in { from { transform: scale(0.85); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .end-card { animation: none; } }

/* ---------- Shared layout helpers for the games: opt in by adding the class ----------
   Phones on their side (landscape, under 500px tall) need the whole height for the field:
   .app.side-bars         The top bar turns into two side columns of --side-w (64px): the back button top left with
                          the HUD under it, the .top-actions top right (stacked), the title hidden. The field is the
                          <main> (or any child with .side-main) and fills the middle at full height.
   .end-card.end-two-col  The end card in two columns: icon and stars left; title, text, table and buttons right. The
                          .over-actions stick to the bottom of the card, so the buttons never need scrolling.
   .start-two-col         On the start card: everything on the left, the .start-actions (the big button) on the
                          right, the .start-utils chips along the bottom. Set --start-rows to the number of items in
                          the left column when it is more than 4. Decorations (aria-hidden="true") are left alone.
   Always:
   .top-title             A top-bar title on one line; when it doesn't fit, arcade.js hides it (.is-cut) instead of
                          letting it wrap, and shows it again when there is room.
   .topbar.safe-pad       Pads the bar with the safe-area insets (notch, rounded corners) when it touches the edges.
   Text floor: nothing interactive below 13px. The shared parts (buttons, chips, sheets, dialogs) keep to it. */
.top-title { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: clip; }
.top-title.is-cut { visibility: hidden; }
.topbar.safe-pad { padding-top: env(safe-area-inset-top); padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }

@media (orientation: landscape) and (max-height: 500px) {
  body .app.side-bars {
    --side-w: 64px;
    max-width: none;
    display: grid;
    grid-template-columns: var(--side-w) minmax(0, 1fr) var(--side-w);
    grid-template-rows: auto auto auto minmax(0, 1fr);
    gap: 8px 10px;
    padding: max(8px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
  }
  body .app.side-bars > .topbar { display: contents; }
  body .app.side-bars > .topbar > * { grid-column: 1; align-self: start; justify-self: center; min-width: 0; max-width: var(--side-w); }
  body .app.side-bars > .topbar > .back-link { grid-row: 1; }
  body .app.side-bars > .topbar > .top-title, body .app.side-bars > .topbar > .mini-logo, body .app.side-bars > .topbar > h1 { display: none; }
  body .app.side-bars > .topbar > .top-actions { grid-column: 3; grid-row: 1 / -1; flex-direction: column; align-items: center; }
  body .app.side-bars > main, body .app.side-bars > .side-main { grid-column: 2; grid-row: 1 / -1; min-width: 0; min-height: 0; }

  /* left: the icon (next to the title and text) and the stars (next to the table); right: the rest */
  body .end-card.end-two-col {
    width: min(720px, 100%);
    max-height: calc(100dvh - 16px);
    display: grid;
    grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr);
    grid-auto-flow: row dense;
    align-content: center;
    gap: 8px 20px;
    padding-bottom: 0;
  }
  body .end-card.end-two-col > * { grid-column: 2; }
  body .end-card.end-two-col > .over-icon { grid-column: 1; grid-row: 1 / span 2; align-self: end; }
  body .end-card.end-two-col > .over-stars { grid-column: 1; grid-row: 3 / span 4; align-self: start; }
  body .end-card.end-two-col > .over-actions {
    position: sticky;
    bottom: 0;
    z-index: 1;
    margin: 0;
    padding: 10px 0 16px;
    background: linear-gradient(180deg, rgba(255, 244, 225, 0), var(--cream) 14px);
  }

  /* :is(#start, body) only lends the rule an id's weight, so a game's own .start-card rules don't undo it */
  :is(#start, body) .start-two-col {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    grid-auto-flow: row dense;
    align-items: center;
    gap: 10px 22px;
    width: min(860px, 100%);
  }
  :is(#start, body) .start-two-col > :not([aria-hidden="true"]) { grid-column: 1; margin-top: 0; margin-bottom: 0; }
  :is(#start, body) .start-two-col > .start-actions { grid-column: 2; grid-row: 1 / span var(--start-rows, 4); align-self: center; }
  :is(#start, body) .start-two-col > .start-utils, :is(#start, body) .start-two-col > details { grid-column: 1 / -1; }
}

/* ---------- Desktop: a big screen ----------
   "Desktop" is `@media (min-width: 1100px) and (min-height: 650px)`; arcade.js puts the same
   test on the page as `html.desktop`, so a game can write `html.desktop .app { … }` or use the media query. Phones
   and smaller tablets never match it, so everything behind it leaves them exactly as they are; a big tablet on its
   side (1180×820 and up) does, and gets the big layout for a finger. What only makes sense with a mouse and a
   keyboard (key caps, key cards, "klik"/"sleep", hover hints) keys on `html.mouse` (desktop and a fine pointer).
   --ui                   The UI scale: 1 everywhere, on desktop clamp(1, min(100vw / 1200px, 100vh / 780px), 1.6):
                          it follows the smaller of width and height, so a wide but low window doesn't overflow.
                          1280×720 and 1366×768: 1 · 1440×900: 1.15 · 1920×1080: 1.38 · 2560×1440: 1.6.
                          Size HUD text, labels and buttons with calc(… * var(--ui)) (or font-size:
                          calc(16px * var(--ui)) on .app with rem/em inside).
                          Floors on desktop: labels 18px, scores 22px, buttons 56px tall, icon buttons 52px.
   .desktop-cols          On desktop a three-column grid: a LEFT column (HUD, scores), the PLAY AREA, a RIGHT column
                          (controls, actions):  grid-template-columns: minmax(220px, 1fr) auto minmax(220px, 1fr)
                          (override with --desktop-cols, e.g. "minmax(260px, 1fr) auto" for both on one side).
                          Children: .desktop-left, .desktop-play, .desktop-right (any order in the HTML); children
                          without one of these fill the columns in order. The side columns are flex columns
                          (gap --desktop-gap) that stretch to the play area's height; the play area is centred.
                          It takes the height it is given: give the container a height (e.g. flex: 1 in the .app,
                          or height: calc(100dvh - <top bar>)) and size the board with min(width, height × aspect).
                          Off desktop it does nothing: the game's own phone layout stays. */
:root { --ui: 1; }
@media (min-width: 1100px) and (min-height: 650px) {
  /* tan(atan2(a, b)) is a / b as a plain number (dividing two lengths directly is too new for most browsers) */
  :root { --ui: clamp(1, min(tan(atan2(100vw, 1200px)), tan(atan2(100vh, 780px))), 1.6); }

  .desktop-cols {
    --desktop-gap: clamp(16px, 1.6vw, 36px);
    display: grid;
    grid-template-columns: var(--desktop-cols, minmax(220px, 1fr) auto minmax(220px, 1fr));
    grid-template-rows: minmax(0, 1fr);
    grid-auto-flow: column;
    align-items: stretch;
    gap: var(--desktop-gap);
    width: 100%;
    max-width: none;
    min-height: 0;
  }
  .desktop-cols > * { min-width: 0; min-height: 0; }
  .desktop-cols > .desktop-left { grid-column: 1; grid-row: 1; }
  .desktop-cols > .desktop-play { grid-column: 2; grid-row: 1; align-self: center; justify-self: center; }
  .desktop-cols > .desktop-right { grid-column: 3; grid-row: 1; }
  .desktop-cols > :is(.desktop-left, .desktop-right) { display: flex; flex-direction: column; gap: var(--desktop-gap); }
}

/* ---------- Desktop: the shared parts ----------
   Sizes here are calc(… * var(--ui)), never a zoom, so a game that sizes the same part itself (also with --ui) simply
   wins and nothing is scaled twice. The weights are kept low on purpose: a game's own rule for its top bar, start
   card or end card beats these.
   Top bar                The back button 60px, the pill's buttons 52px (× --ui). Titles stay the game's.
   .start-two-col         Also on desktop, at any height: the options left, a poster right with the .start-head
                          (hero + title) above the .start-actions (the big button), the .start-utils chips along the
                          bottom. arcade.js counts the left items into --start-left. The hero is `.start-hero`,
                          sized by --hero: at least 260px here.
   .end-card              Zero weight (:where): two columns (icon and stars left, the rest right), 760px × --ui wide,
                          bigger stars and text. A game's own end-card layout always wins.
   .ui-zoom               For a game's own card or panel that is easiest scaled as a whole: zoom: var(--ui). Inside
                          it vw/vh/dvh grow too (divide them by var(--ui)), and don't multiply by --ui again.
   The shared sheets, the theme picker, the stop screen and the sticker card are zoomed by arcade.js (zoom: --ui):
   style what a game puts inside a sheet in plain px/rem. */
@media (min-width: 1100px) and (min-height: 650px) {
  .ui-zoom { zoom: var(--ui); }

  /* the top bar */
  :where(.topbar) > .back-link { width: calc(60px * var(--ui)); height: calc(60px * var(--ui)); font-size: calc(1.7rem * var(--ui)); }
  /* html.desktop (set by arcade.js) gives these the weight to beat the 44px pill rule further down */
  html.desktop :is(#start, body) .topbar .top-actions { gap: calc(6px * var(--ui)); padding: calc(5px * var(--ui)); }
  html.desktop :is(#start, body) .topbar .top-actions > .icon-btn { width: calc(52px * var(--ui)); height: calc(52px * var(--ui)); font-size: calc(1.4rem * var(--ui)); }
  html.desktop :is(#start, body) .topbar .top-actions > .icon-btn .theme-pick-icon { width: calc(36px * var(--ui)); height: calc(36px * var(--ui)); }
  html.desktop :is(#start, body) .topbar .top-actions > .icon-btn .theme-pick-icon svg,
  html.desktop :is(#start, body) .topbar .top-actions > .icon-btn.fs-pick svg { width: calc(25px * var(--ui)); height: calc(25px * var(--ui)); }

  /* buttons are at least 56px tall; a link styled as a button keeps its text in the middle */
  .btn { min-height: 56px; }
  a.btn { display: inline-flex; align-items: center; justify-content: center; }

  /* the start card: options left, the hero, the title and the big button right */
  :is(#start, body) .start-two-col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-auto-flow: row dense;
    align-items: center;
    align-content: center;
    gap: calc(12px * var(--ui)) calc(44px * var(--ui));
    width: min(calc(1040px * var(--ui)), calc(100vw - 48px));
    max-width: none;
  }
  :is(#start, body) .start-two-col > :not([aria-hidden="true"]) { grid-column: 1; grid-row: span 2; margin-top: 0; margin-bottom: 0; }
  :is(#start, body) .start-two-col > .start-head { grid-column: 2; grid-row: 1 / span var(--start-left, 2); align-self: end; }
  :is(#start, body) .start-two-col > .start-actions { grid-column: 2; grid-row: calc(var(--start-left, 2) + 1) / span var(--start-left, 2); align-self: start; }
  :is(#start, body) .start-two-col > :is(.start-utils, details) { grid-column: 1 / -1; grid-row: auto; }
  :is(#start, body) .start-two-col .start-hero { --hero: max(260px, min(calc(260px * var(--ui)), 36vh)); }

  /* the end card (zero weight: a game's own layout wins) */
  :where(.end-card) {
    width: min(calc(760px * var(--ui)), calc(100vw - 48px));
    max-height: calc(100dvh - 32px);
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    grid-auto-flow: row dense;
    align-content: center;
    gap: calc(10px * var(--ui)) calc(28px * var(--ui));
    padding: calc(26px * var(--ui)) calc(28px * var(--ui)) 0;
    font-size: calc(1rem * var(--ui));
  }
  :where(.end-card > *) { grid-column: 2; }
  :where(.end-card > .over-icon) { grid-column: 1; grid-row: 1 / span 2; align-self: end; }
  :where(.end-card > .over-stars) { grid-column: 1; grid-row: 3 / span 4; align-self: start; gap: calc(10px * var(--ui)); }
  :where(.end-card .over-title) { font-size: 2em; }
  :where(.end-card .over-text) { font-size: 1.1em; }
  :where(.end-card .over-stars span) { width: calc(64px * var(--ui)); height: calc(64px * var(--ui)); }
  :where(.end-card .over-stars span:nth-child(2)) { width: calc(80px * var(--ui)); height: calc(80px * var(--ui)); margin-top: calc(-12px * var(--ui)); }
  :where(.end-card > .over-actions) {
    position: sticky;
    bottom: 0;
    z-index: 1;
    margin: 0;
    padding: calc(12px * var(--ui)) 0 calc(24px * var(--ui));
    background: linear-gradient(180deg, rgba(255, 244, 225, 0), var(--cream) 14px);
  }
  :where(.end-card .over-actions .btn) { min-height: calc(56px * var(--ui)); font-size: 1.2em; }

  /* a text field or slider that a game left without a ring gets one back */
  :is(input, select, textarea):focus-visible { outline: 3px solid var(--pink-dark) !important; outline-offset: 3px !important; }
}

/* ---------- Mouse polish, arcade-wide ----------
   Everything clickable shows the hand, draggables (`[data-drag]`, `.draggable`) the open hand and the closed one
   while held; :where() keeps these at zero weight, so a game's own cursor wins. With a mouse, buttons, chips, tiles
   and the choice buttons on a start screen lift on hover (120 ms, transform and filter only: nothing moves around
   them, and each keeps its own shadow), and the focus ring is the theme's accent. */
:where(button, .btn, .start-tile, .icon-btn, .back-link, .start-chip, a.card, summary, label:has(> input[type="checkbox"]), select) { cursor: pointer; }
:where(button:disabled, [aria-disabled="true"]) { cursor: default; }
:where([data-drag], .draggable) { cursor: grab; }
:where([data-drag], .draggable):active { cursor: grabbing; }
@media (hover: hover) and (pointer: fine) {
  :focus-visible { outline-color: var(--pink-dark); }
  body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip):hover:not(:disabled):not([aria-disabled="true"]),
  :where(#start button:not(.start-chip, .btn, :disabled)):hover {
    transform: translateY(-3px);
    filter: brightness(1.06) drop-shadow(0 6px 6px rgba(60, 30, 110, 0.22));
    transition: transform 0.12s ease-out, box-shadow 0.12s ease-out, filter 0.12s ease-out;
  }
  :where(#start button:not(.start-chip, .btn)) { transition: transform 0.34s cubic-bezier(0.3, 1.9, 0.45, 1), filter 0.15s ease; }
  :where(#start button:not(.start-chip, .btn, :disabled)):active { transform: translateY(1px); filter: none; transition-duration: 0.07s; }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: reduce) {
  body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip):hover:not(:disabled):not([aria-disabled="true"]),
  :where(#start button:not(.start-chip, .btn, :disabled)):hover { transform: none; }
}

/* ---------- Press squash, arcade-wide ----------
   Buttons, start tiles, chips and the frontpage cards squash a little while pressed and spring back on release
   (transform only: nothing around them moves). The press is quick; the release overshoots a touch. `body` lends the
   rule weight over a game's own `.start-tile:active { transform: translateY(3px) }`; the game's shadow change stays.
   A game that needs its own press for one of these classes should not: these are the shared ones. */
body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip, a.card, .card--surprise) {
  transition: transform 0.34s cubic-bezier(0.3, 1.9, 0.45, 1), box-shadow 0.18s ease, filter 0.15s ease;
}
body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip, a.card, .card--surprise):active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(2px) scale(0.96);
  transition-duration: 0.07s, 0.07s, 0.15s;
  transition-timing-function: ease-out;
}
/* the big ones squash less, or they would look like they shrink away */
body :is(a.card, .card--surprise):active:not(:disabled):not([aria-disabled="true"]) { transform: translateY(2px) scale(0.98); }
@media (prefers-reduced-motion: reduce) {
  body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip, a.card, .card--surprise) { transition: box-shadow 0.1s ease, filter 0.15s ease; }
  body :is(.btn, .start-tile, .icon-btn, .back-link, .start-chip, a.card, .card--surprise):active:not(:disabled):not([aria-disabled="true"]) { transform: translateY(2px); }
}

/* ---------- The top-right buttons: one cream pill ----------
   A game's `.topbar .top-actions` (sound, restart, pause, theme, full screen) is one cream pill like the chip row,
   with the buttons inside as smaller pink circles (still 44px to tap). In `.app.side-bars` landscape, and wherever a
   game stacks them in a column, the pill stands upright. `:is(#start, body)` lends an id's weight, so a game's own
   button sizes in the top bar don't break the pill (style the buttons' insides, not their size). */
:is(#start, body) .topbar .top-actions {
  flex: none;
  justify-self: end; /* in a game's grid top bar: as wide as its buttons, at the right */
  align-items: center;
  gap: 4px;
  padding: 4px;
  border-radius: 999px;
  background: linear-gradient(180deg, #fff8ec, var(--cream));
  box-shadow: inset 0 2px 0 #fff, 0 4px 0 var(--cream-dark), 0 12px 20px -12px rgba(90, 50, 150, 0.5);
}
:is(#start, body) .topbar .top-actions:empty { display: none; }
:is(#start, body) .topbar .top-actions > .icon-btn {
  width: 44px;
  height: 44px;
  font-size: 1.2rem;
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 3px 0 var(--pink-dark);
}
:is(#start, body) .topbar .top-actions > .icon-btn:active:not(:disabled) { box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 1px 0 var(--pink-dark); }
:is(#start, body) .topbar .top-actions > .icon-btn .theme-pick-icon { width: 30px; height: 30px; }
:is(#start, body) .topbar .top-actions > .icon-btn .theme-pick-icon svg { width: 22px; height: 22px; }
/* phones: as narrow as the loose buttons were, so the title and the scores keep their room */
@media (max-width: 400px) { :is(#start, body) .topbar .top-actions { gap: 2px; padding: 3px; } }
@media (orientation: landscape) and (max-height: 500px) {
  :is(#start, body) .app.side-bars > .topbar > .top-actions { align-self: start; justify-self: center; }
}

/* ---------- Idle motion for the start screens' heroes ----------
   Put one class on the hero drawing (or a part of it); they only move transforms and stop under reduced motion.
   .hero-bob        floats up and down, 3 s
   .hero-wobble     rocks from side to side around its foot, 2.4 s
   .hero-spin-slow  turns round once every 12 s (a ball, a sun, a pizza)
   Set --hero-delay to start parts out of step, e.g. style="--hero-delay: -1s". */
.hero-bob { animation: hero-bob 3s ease-in-out var(--hero-delay, 0s) infinite; }
.hero-wobble { transform-origin: 50% 100%; animation: hero-wobble 2.4s ease-in-out var(--hero-delay, 0s) infinite; }
.hero-spin-slow { animation: hero-spin 12s linear var(--hero-delay, 0s) infinite; }
@keyframes hero-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes hero-wobble { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg); } }
@keyframes hero-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .hero-bob, .hero-wobble, .hero-spin-slow { animation: none; } }
