/* Kurt Kratzt! – pixel UI. Every size that touches pixel art is a multiple of --px (CSS px per
   art pixel, set by src/ui/layout.js); Press Start 2P runs at --pf, headline numbers at --pf2
   (whole device pixels).
   Frames come from src/art/ui-kit.js as --kk-<frame> / --kk-<frame>-bw border-image vars. */

:root {
  --px: 3px;
  --pf: 8px;
  --pf2: 16px;
  --fs: calc(12px + var(--px) * 1.5);
  --font-pixel: "Press Start 2P", ui-monospace, monospace;
  --font-body: "Pixelify Sans", system-ui, sans-serif;
  /* Palette subset (mirrors src/art/palette.js; test-art checks the values). */
  --c-ink0: #140d1f;
  --c-ink: #271a38;
  --c-du0: #3a2953;
  --c-du1: #55407a;
  --c-du2: #7a64a6;
  --c-du3: #a99ad1;
  --c-gr1: #4a4f6b;
  --c-go2: #dd8a35;
  --c-go3: #f4c44a;
  --c-go4: #ffe98c;
  --c-go5: #fffbe0;
  --c-re1: #93254a;
  --c-re2: #d9465a;
  --c-re3: #f2827a;
  --c-te0: #17474f;
  --c-te3: #74d19a;
  --c-wo0: #2e1a2a;
  --c-wo1: #4d2a35;
  --c-cr0: #d9b48a;
  --c-cr1: #efd6ad;
  --c-cr2: #fdf1d6;
  --c-gr4: #c3c8da;
}

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

[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  height: 100%;
  background: var(--c-ink0);
  color: var(--c-cr2);
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  font: 400 var(--fs) / 1.35 var(--font-body);
  /* Pixelify Sans' "fi" ligature reads like "ß" ("Thunfisch"). */
  font-variant-ligatures: none;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
}

canvas,
.ico,
[class*="kk-"],
.btn {
  image-rendering: pixelated;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- pixel frames ------------------------------------------------------------------------ */

[class*="kk-"] {
  border-style: solid;
}
.kk-panel { border-width: var(--kk-panel-bw); border-image: var(--kk-panel); }
.kk-card { border-width: var(--kk-card-bw); border-image: var(--kk-card); }
.kk-card-hot { border-width: var(--kk-card-hot-bw); border-image: var(--kk-card-hot); }
.kk-tab { border-width: var(--kk-tab-bw); border-image: var(--kk-tab); }
.kk-tab:focus-visible { border-image: var(--kk-tab-hover); }
@media (hover: hover) { .kk-tab:hover { border-image: var(--kk-tab-hover); } }
.kk-tab-active { border-width: var(--kk-tab-active-bw); border-image: var(--kk-tab-active); }
.kk-inset { border-width: var(--kk-inset-bw); border-image: var(--kk-inset); }
.kk-shelf { border-width: var(--kk-shelf-bw); border-image: var(--kk-shelf); }
.kk-bubble { border-width: var(--kk-bubble-bw); border-image: var(--kk-bubble); }
.kk-modal { border-width: var(--kk-modal-bw); border-image: var(--kk-modal); }
.kk-mat { border-width: var(--kk-mat-bw); border-image: var(--kk-mat); }

/* ---- sprites as CSS images ---------------------------------------------------------------- */

.ico {
  display: inline-block;
  flex: none;
  width: calc(16 * var(--px));
  height: calc(16 * var(--px));
  background: var(--img) 0 0 / 100% 100% no-repeat;
}
.ico.coin { --img: var(--kk-img-coin); }
.ico.coin-small {
  --img: var(--kk-img-coinSmall);
  width: calc(8 * var(--px));
  height: calc(8 * var(--px));
}
.ico.icon-home { --img: var(--kk-img-icon-home); }
.ico.icon-speaker { --img: var(--kk-img-icon-speaker); }
.ico.icon-speakerOff { --img: var(--kk-img-icon-speakerOff); }
.ico.icon-cart { --img: var(--kk-img-icon-cart); }
.ico.icon-phone { --img: var(--kk-img-icon-phone); }
.ico.icon-plate { --img: var(--kk-img-icon-plate); }
.ico.lock-small {
  --img: var(--kk-img-lockSmall);
  width: calc(9 * var(--px));
  height: calc(10 * var(--px));
}

/* ---- buttons (approved style frame) ------------------------------------------------------- */

.btn {
  appearance: none;
  background: none;
  margin: 0;
  min-height: 44px;
  padding: var(--px) calc(3 * var(--px));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(2 * var(--px));
  font: 400 var(--pf) / 2 var(--font-pixel);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  outline: none;
  user-select: none;
  -webkit-user-select: none;
}
.btn:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: var(--px);
}
.btn.gold { border-width: var(--kk-btn-gold-bw); border-image: var(--kk-btn-gold); color: var(--c-ink); }
.btn.gold:focus-visible { border-image: var(--kk-btn-gold-hover); }
@media (hover: hover) { .btn.gold:hover { border-image: var(--kk-btn-gold-hover); } }
.btn.gold:active { border-width: var(--kk-btn-gold-pressed-bw); border-image: var(--kk-btn-gold-pressed); }
.btn.teal { border-width: var(--kk-btn-teal-bw); border-image: var(--kk-btn-teal); color: var(--c-ink); }
.btn.teal:focus-visible { border-image: var(--kk-btn-teal-hover); }
@media (hover: hover) { .btn.teal:hover { border-image: var(--kk-btn-teal-hover); } }
.btn.teal:active { border-width: var(--kk-btn-teal-pressed-bw); border-image: var(--kk-btn-teal-pressed); }
.btn.red { border-width: var(--kk-btn-red-bw); border-image: var(--kk-btn-red); color: var(--c-cr2); }
.btn.red:focus-visible { border-image: var(--kk-btn-red-hover); }
@media (hover: hover) { .btn.red:hover { border-image: var(--kk-btn-red-hover); } }
.btn.red:active { border-width: var(--kk-btn-red-pressed-bw); border-image: var(--kk-btn-red-pressed); }
.btn.plum { border-width: var(--kk-btn-plum-bw); border-image: var(--kk-btn-plum); color: var(--c-cr2); }
.btn.plum:focus-visible { border-image: var(--kk-btn-plum-hover); }
@media (hover: hover) { .btn.plum:hover { border-image: var(--kk-btn-plum-hover); } }
.btn.plum:active { border-width: var(--kk-btn-plum-pressed-bw); border-image: var(--kk-btn-plum-pressed); }
/* Off wins over the colour (aria-disabled buttons stay focusable and explain themselves). */
.btn.off,
.btn.off:hover,
.btn.off:active {
  border-width: var(--kk-btn-off-bw);
  border-image: var(--kk-btn-off);
  color: var(--c-ink);
  cursor: default;
}

.icon-btn {
  min-width: 44px;
  padding: 0 var(--px);
}

/* ---- app grid ----------------------------------------------------------------------------- */
/* tall: phones and narrow windows. split: landscape below 1024 px. wide: desktop.
   --layout is read by layout.js and mirrored to html[data-layout]. */

.app {
  --layout: tall;
  position: relative;
  display: grid;
  height: 100vh;
  height: 100dvh;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  grid-template-areas: "hud" "kiosk" "table" "buy";
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  overflow: hidden;
}

/* HUD: home, coin counter, (title), sound. */
.hud {
  grid-area: hud;
  display: flex;
  align-items: center;
  gap: calc(2 * var(--px));
  min-width: 0;
  padding: calc(2 * var(--px)) calc(3 * var(--px));
  background: var(--c-ink);
}
.coins {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--px));
  min-width: 0;
  padding: 0 calc(3 * var(--px)) 0 0;
  color: var(--c-go4);
}
.coins.bump {
  animation: kk-bump 0.16s steps(1, end);
}
/* Owed to Bruno: a compact red pill next to the coins (tap to call and pay). */
.debt-btn {
  padding: 0 calc(2 * var(--px));
  color: var(--c-cr2);
}
.debt-btn .ico {
  width: calc(12 * var(--px));
  height: calc(12 * var(--px));
}
.debt-sum::before {
  content: "-";
}
html[data-layout="wide"] .debt-btn {
  font-size: var(--pf2);
}
/* Teller-Job: a plum pill next to the coins (scrub a plate for a little money). */
.job-btn {
  position: relative;
  min-width: 44px;
  padding: 0 calc(2 * var(--px));
}
.job-btn .ico {
  width: calc(12 * var(--px));
  height: calc(12 * var(--px));
}
@media (max-width: 400px) {
  .job-label {
    display: none;
  }
}
.hud-title {
  display: none;
  margin: 0;
  flex: 1;
  text-align: center;
  font: 400 var(--pf2) / 1 var(--font-pixel);
  color: var(--c-go3);
  text-shadow: var(--px) var(--px) 0 var(--c-wo1);
}
#sound {
  margin-left: auto;
}
.shop-btn {
  position: relative;
  margin-left: auto;
  padding: 0 calc(2 * var(--px));
}
.shop-btn + #sound {
  margin-left: 0;
}
.shop-btn .ico {
  width: calc(12 * var(--px));
  height: calc(12 * var(--px));
}
/* Something affordable: a gold dot with an ink rim (never colour alone: the label says it too). */
.dot,
.tab-dot {
  position: absolute;
  top: calc(-2 * var(--px));
  right: calc(-2 * var(--px));
  width: calc(5 * var(--px));
  height: calc(5 * var(--px));
  background: var(--c-re2);
  box-shadow: 0 0 0 var(--px) var(--c-ink0);
  visibility: hidden;
}
.new > .dot,
.new > .tab-dot {
  visibility: visible;
}
.shop-btn.hint {
  animation: kk-hint 1.2s steps(1, end) infinite;
}
@keyframes kk-hint {
  0%, 60% { transform: none; }
  70%, 90% { transform: translateY(calc(-2 * var(--px))); }
}

/* Rolling odometer: each digit is a 0-9 strip in a one-digit window. */
.odo {
  display: inline-flex;
  font: 400 var(--pf2) / 1 var(--font-pixel);
  height: 1em;
  overflow: hidden;
  white-space: nowrap;
}
.odo-d {
  display: inline-block;
  height: 1em;
  overflow: hidden;
}
.odo-s {
  display: flex;
  flex-direction: column;
  transform: translateY(calc(var(--d, 0) * -1em));
  transition: transform 0.12s steps(3, end);
}
.odo-s > span,
.odo-c {
  display: block;
  height: 1em;
  line-height: 1;
}

/* ---- kiosk -------------------------------------------------------------------------------- */

.kiosk {
  grid-area: kiosk;
  position: relative;
  height: calc(52 * var(--px));
  background: var(--c-ink0);
}
.kiosk-view {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background-repeat: repeat-x;
  image-rendering: pixelated;
}
#kiosk-canvas {
  position: absolute;
  left: 0;
  top: 0;
}

.bubble {
  position: absolute;
  z-index: 2;
  width: max-content;
  padding: var(--px) calc(3 * var(--px));
  color: var(--c-ink);
  font-weight: 600;
  pointer-events: none;
}
.bubble p {
  margin: 0;
  line-height: 1.2;
}
.bubble .rest {
  visibility: hidden;
}
.bubble .tail {
  position: absolute;
  width: calc(7 * var(--px));
  height: calc(6 * var(--px));
  background: var(--kk-img-tailDown) 0 0 / 100% 100% no-repeat;
}
/* Tails cover the bubble's 2 px rim with fill. */
.bubble.above .tail {
  top: 100%;
  left: calc(3 * var(--px));
}
.bubble.side .tail {
  right: 100%;
  top: calc(2 * var(--px));
  height: calc(7 * var(--px));
  background-image: var(--kk-img-tailLeft);
}

/* ---- scratch table ------------------------------------------------------------------------ */

.table {
  grid-area: table;
  position: relative;
  min-height: 0;
  overflow: hidden;
  background: var(--c-wo1) var(--kk-wood) 0 0 / calc(48 * var(--px)) calc(32 * var(--px)) repeat;
  box-shadow: inset 0 var(--px) 0 var(--c-wo0);
}
.slot {
  position: absolute;
  inset: calc(3 * var(--px));
}
.mat {
  position: absolute;
  z-index: 1;
  left: 0;
  top: 0;
  width: calc(128 * var(--px));
  height: calc(184 * var(--px));
}
.ticket {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(120 * var(--px));
  height: calc(176 * var(--px));
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  cursor: var(--kk-cursor), pointer;
  outline: none;
}
.ticket.scratching {
  cursor: var(--kk-cursor-tilt), pointer;
}
.ticket:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: calc(2 * var(--px));
}
.ticket canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.ticket-shadow {
  transform: translate(calc(2 * var(--px)), calc(2 * var(--px)));
}
/* Bought tickets lying on the table (pile.js places them). Over the empty mat they are buttons;
   while a ticket is scratched they wait under its edge or beside it. */
.pile {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}
.pile.aside {
  z-index: 0;
}
.pile-card {
  appearance: none;
  position: absolute;
  left: 0;
  top: 0;
  width: calc(30 * var(--px));
  height: calc(40 * var(--px));
  padding: 0;
  border: 0;
  background: none;
  pointer-events: auto;
  cursor: pointer;
  transition: transform var(--slide, 320ms) cubic-bezier(0.2, 0.8, 0.3, 1.1);
  filter: drop-shadow(calc(2 * var(--px)) calc(2 * var(--px)) 0 rgb(20 13 31 / 0.55));
}
.pile.aside .pile-card {
  pointer-events: none;
  cursor: default;
}
.pile-card canvas {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}
.pile-card:focus-visible canvas {
  transform: translateY(calc(-2 * var(--px)));
}
@media (hover: hover) {
  .pile:not(.aside) .pile-card:hover canvas { transform: translateY(calc(-2 * var(--px))); }
}
.pile-card:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: var(--px);
}
.slot-empty {
  z-index: 3;
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.slot-empty .btn {
  pointer-events: auto;
}
/* Live strip at the top edge of the table: win chance of the ticket and what is open so far. It sits
   in the margin above the ticket; tapping it opens "Gewinne & Chancen". */
.win-live {
  appearance: none;
  position: absolute;
  top: var(--px);
  left: 50%;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: calc(3 * var(--px));
  max-width: calc(100% - 2 * var(--px));
  height: calc(9 * var(--px));
  margin: 0;
  padding: 0 calc(2 * var(--px));
  transform: translateX(-50%);
  background: var(--c-ink0);
  color: var(--c-cr2);
  font: 400 var(--pf) / 1 var(--font-pixel);
  white-space: nowrap;
  cursor: pointer;
}
@media (hover: hover) {
  .win-live:hover .wl-chance {
    color: var(--c-go5);
  }
}
.win-live:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: var(--px);
}
.wl-chance {
  color: var(--c-du3);
}
.wl-win {
  color: var(--c-cr2);
}
.win-live.has-win .wl-win {
  color: var(--c-go4);
}
.win-live.pop {
  animation: kk-live-pop 0.2s steps(1, end);
}
html[data-layout="wide"] .win-live {
  font-size: var(--pf2);
}
@keyframes kk-live-pop {
  0% { transform: translateX(-50%) translateY(calc(-1 * var(--px))); }
  100% { transform: translateX(-50%); }
}
#slot-phone {
  flex-direction: column;
  padding: calc(3 * var(--px)) calc(4 * var(--px));
  line-height: 1.6;
}
#slot-phone .ico {
  width: calc(24 * var(--px));
  height: calc(24 * var(--px));
}
/* Ringing: the handset rattles in short bursts (stepped, under 3 Hz flashes, none when reduced). */
.btn.ringing .ico {
  animation: kk-ring 1.2s steps(1, end) infinite;
}
@keyframes kk-ring {
  0% { transform: translateX(calc(-1 * var(--px))); }
  8% { transform: translateX(var(--px)); }
  16% { transform: translateX(calc(-1 * var(--px))); }
  24% { transform: translateX(var(--px)); }
  32%, 100% { transform: none; }
}

/* ---- buy bar ------------------------------------------------------------------------------ */

.buy {
  grid-area: buy;
  display: flex;
  align-items: flex-end;
  gap: calc(4 * var(--px));
  min-width: 0;
  padding: var(--px) calc(2 * var(--px));
  color: var(--c-cr2);
}
/* --stack-h: art pixels of pile height; shelf.js reads it and draws that many card layers. */
.stack {
  --stack-h: 45;
  position: relative;
  flex: none;
  width: calc(32 * var(--px));
  height: calc(var(--stack-h) * var(--px));
}
.stack canvas {
  display: block;
  width: 100%;
  height: 100%;
}
.badge {
  position: absolute;
  right: calc(-3 * var(--px));
  bottom: 0;
  min-width: calc(10 * var(--px));
  padding: 0 var(--px);
  text-align: center;
  font: 400 var(--pf) / 2 var(--font-pixel);
  color: var(--c-go4);
}
.buy-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--px));
}
/* Phones show the ticket name on the ticket itself; the bar keeps to two rows of buttons. */
.buy-info {
  display: none;
  align-items: baseline;
  gap: calc(2 * var(--px));
  margin: 0;
  white-space: nowrap;
}
/* A text link styled button ("Gewinne & Chancen"): underlined, with a 44 px tall hit area. */
.odds-link {
  appearance: none;
  margin: 0;
  padding: 0 var(--px);
  min-height: 44px;
  border: 0;
  background: none;
  font: inherit;
  color: var(--c-go4);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}
@media (hover: hover) {
  .odds-link:hover {
    color: var(--c-go5);
  }
}
.odds-link:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: calc(-1 * var(--px));
}
.buy-info .odds-link {
  flex: none;
  margin-left: auto;
  min-height: 0;
  margin: calc(-2 * var(--px)) 0;
  padding: calc(2 * var(--px)) var(--px);
}
.lic .odds-link {
  min-height: 32px;
  color: var(--c-du1);
}
@media (hover: hover) {
  .lic .odds-link:hover {
    color: var(--c-ink);
  }
}
.buy-label {
  flex: none;
  color: var(--c-cr0);
}
#buy-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 600;
}
.buy-row {
  display: flex;
  flex-wrap: wrap;
  gap: calc(2 * var(--px));
}
#buy1 {
  flex: 1 1 auto;
}
#buy1.bare .buy-word {
  display: none;
}
/* x5 and x10 wrap together (on screens too narrow for one row), never one alone. */
.buy-more {
  display: flex;
  gap: calc(2 * var(--px));
}
.buy-more .btn {
  min-width: 44px;
  padding-inline: calc(2 * var(--px));
}

/* ---- shop panels ------------------------------------------------------------------------- */
/* Desktop: always in the right column. Phones and landscape: a sheet from the HUD shop button. */

.panels {
  /* tall: the sheet covers table and buy bar; Kurt stays visible above it. */
  grid-row: 3 / 5;
  grid-column: 1;
  z-index: 5;
  display: none;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: calc(2 * var(--px)) calc(2 * var(--px)) var(--px);
  background: var(--c-ink0);
}
.app.shop-open .panels {
  display: flex;
}
.panels-head {
  display: flex;
  align-items: flex-end;
  gap: calc(2 * var(--px));
  padding: 0 calc(2 * var(--px));
}
.tabs {
  display: flex;
  flex: 1;
  min-width: 0;
  gap: var(--px);
}
.tab {
  position: relative;
  appearance: none;
  background: none;
  margin: 0;
  flex: 0 1 auto;
  min-width: 40px;
  min-height: 44px;
  padding: var(--px) calc(2 * var(--px)) 0;
  display: grid;
  place-items: center;
  cursor: pointer;
  outline: none;
}
.tab .ico {
  opacity: 0.7;
}
/* The active tab sits on the panel's top rim; its open bottom merges with the board. */
.tab.kk-tab-active {
  z-index: 1;
  margin-bottom: calc(-2 * var(--px));
  padding-bottom: calc(2 * var(--px));
}
.tab.kk-tab-active .ico {
  opacity: 1;
}
.tab:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: 0;
}
.tab-dot {
  top: calc(2 * var(--px));
  right: calc(2 * var(--px));
}
.shop-close {
  margin-bottom: var(--px);
}
.panel-box {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  color: var(--c-cr2);
}
.pane-title {
  margin: 0 0 calc(2 * var(--px));
  padding: 0 var(--px);
  font: 400 var(--pf) / 1.5 var(--font-pixel);
  color: var(--c-go3);
}
.panes {
  flex: 1;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-color: var(--c-du2) var(--c-du0);
  container: panes / inline-size;
}
.pane:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: calc(-1 * var(--px));
}
.cards {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--px));
  padding-bottom: calc(2 * var(--px));
}
.pane-lead {
  margin: 0;
  padding: 0 var(--px);
  color: var(--c-cr1);
}

/* Upgrade and wish cards: icon, text, button. */
.ucard {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(2 * var(--px)) calc(3 * var(--px));
  padding: var(--px) calc(2 * var(--px));
  color: var(--c-ink);
}
.ucard > .ico {
  align-self: start;
  margin-top: var(--px);
}
.ucard-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
}
.ucard-body > b {
  font-weight: 700;
}
.desc {
  color: var(--c-du1);
}
.sub {
  color: var(--c-te0);
  font-weight: 600;
}
.need {
  color: var(--c-re1);
  font-weight: 600;
}
/* Upgrade groups (Rubbeln, Extras, ...) and the badge on upgrades that just showed up. */
.ugroup {
  margin: calc(2 * var(--px)) 0 0;
  padding: 0 var(--px);
  font: 400 var(--pf) / 1.6 var(--font-pixel);
  color: var(--c-go3);
}
.ugroup:first-child {
  margin-top: 0;
}
.sub.info {
  color: var(--c-du1);
}
.new-badge {
  display: inline-block;
  padding: 0 var(--px);
  font: 400 calc(var(--pf) * 0.75) / 1.5 var(--font-pixel);
  vertical-align: middle;
  color: var(--c-ink);
  background: var(--c-go3);
  box-shadow: 0 0 0 var(--px) var(--c-ink);
}
.ucard > .btn {
  min-width: calc(30 * var(--px));
}
.chip {
  padding: 0 calc(2 * var(--px));
  font: 400 var(--pf) / 2 var(--font-pixel);
  color: var(--c-te3);
  background: var(--c-ink);
  box-shadow: 0 0 0 var(--px) var(--c-ink0);
}
.ucard.done {
  opacity: 0.85;
}
.ucard.goal .ucard-body > b {
  color: var(--c-re1);
}
@container panes (max-width: 300px) {
  .ucard {
    grid-template-columns: auto minmax(0, 1fr);
  }
  .ucard > .btn,
  .ucard > .chip {
    grid-column: 2;
    justify-self: start;
  }
}
/* Long-text cards (new life) always put their button under the text. */
.ucard.btn-below {
  grid-template-columns: auto minmax(0, 1fr);
}
.ucard.btn-below > .btn {
  grid-column: 2;
  justify-self: start;
}
/* Affordable cards pulse between two gold rims (stepped, about 1 Hz). */
.panels .kk-card-hot {
  animation: kk-card-pulse 1.2s steps(1, end) infinite;
}
@keyframes kk-card-pulse {
  0%, 50% { border-image: var(--kk-card-hot); }
  51%, 100% { border-image: var(--kk-card-glow); }
}

.pips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--px);
  margin-top: var(--px);
}
.pip {
  width: calc(5 * var(--px));
  height: calc(5 * var(--px));
  background: var(--kk-img-pipOff) 0 0 / 100% 100%;
}
.pip.on {
  background-image: var(--kk-img-pipOn);
}
.wish-pips {
  padding: 0 var(--px);
}

/* Auto-buy controls. */
.ab-ctrl {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--px) calc(4 * var(--px));
  margin-top: var(--px);
}
.stepper {
  display: flex;
  align-items: center;
  gap: var(--px);
}
.step-label {
  margin-right: var(--px);
}
.btn.step {
  min-width: 40px;
  padding: 0 var(--px);
}
.btn.step[aria-disabled="true"] {
  border-width: var(--kk-btn-off-bw);
  border-image: var(--kk-btn-off);
  color: var(--c-ink);
  cursor: default;
}
.step-val {
  min-width: calc(14 * var(--px));
  text-align: center;
  font: 400 var(--pf) / 2 var(--font-pixel);
  color: var(--c-go4);
}

/* Switches: the whole row is the button. */
.switch {
  appearance: none;
  background: none;
  border: 0;
  margin: 0;
  display: flex;
  align-items: center;
  gap: calc(3 * var(--px));
  min-height: 44px;
  padding: 0 var(--px);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  outline: none;
}
.switch:focus-visible {
  outline: var(--px) solid var(--c-wo1);
}
.tgl {
  flex: none;
  width: calc(15 * var(--px));
  height: calc(7 * var(--px));
  background: var(--kk-img-toggleOff) 0 0 / 100% 100%;
}
.switch.on .tgl {
  background-image: var(--kk-img-toggleOn);
}

/* Ticket licences: a grid of mini cards. */
.lic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(calc(42 * var(--px)), 1fr));
  gap: calc(2 * var(--px));
  padding-bottom: calc(2 * var(--px));
}
.lic {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--px);
  min-width: 0;
  padding: var(--px);
  text-align: center;
  color: var(--c-ink);
  line-height: 1.15;
}
.lic-card {
  display: block;
  width: calc(30 * var(--px));
  height: calc(40 * var(--px));
}
.lic-name {
  font-weight: 700;
  overflow-wrap: anywhere;
}
.lic-meta {
  color: var(--c-du1);
  font-size: 0.9em;
}
.lic.locked .lic-name {
  color: var(--c-gr1);
}
.lic > .btn {
  align-self: stretch;
  padding: 0 var(--px);
  margin-top: auto;
}

/* Lives. */
.hearts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--px);
  padding: var(--px);
}
.heart {
  width: calc(9 * var(--px));
  height: calc(8 * var(--px));
  background: var(--kk-img-heartEmpty) 0 0 / 100% 100%;
}
.heart.on {
  background-image: var(--kk-img-heart);
}
.hearts-extra {
  margin-left: var(--px);
  font: 400 var(--pf) / 1 var(--font-pixel);
  color: var(--c-re3);
}

/* Stats. */
.stat-card {
  padding: var(--px) calc(2 * var(--px));
  color: var(--c-ink);
}
.stats,
.modal-stats {
  margin: 0;
}
.stat-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(3 * var(--px));
  padding: var(--px) 0;
  box-shadow: 0 var(--px) 0 var(--c-cr0);
}
.stat-row:last-child {
  box-shadow: none;
}
.stat-row dd {
  margin: 0;
  font-weight: 700;
  text-align: right;
  white-space: nowrap;
}
.per {
  width: 100%;
  border-collapse: collapse;
}
.per caption {
  text-align: left;
  padding: var(--px) 0;
  font: 400 var(--pf) / 1.5 var(--font-pixel);
  color: var(--c-wo1);
}
.per th,
.per td {
  padding: var(--px) 0;
  text-align: right;
  box-shadow: 0 var(--px) 0 var(--c-cr0);
}
.per th:first-child {
  text-align: left;
}
.per thead th {
  color: var(--c-du1);
  font-weight: 600;
}

/* Options. */
.opt-card {
  display: flex;
  flex-direction: column;
  gap: var(--px);
  padding: calc(2 * var(--px));
  color: var(--c-ink);
}
.opt-card > .btn {
  align-self: flex-start;
}
.opt-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--px) calc(3 * var(--px));
  min-height: 44px;
  padding: 0 var(--px);
}
/* A rule under each setting turns the tall 44 px touch rows into one list instead of loose gaps;
   the motion row keeps its hint below it. */
.opt-card > .opt-row,
.opt-card > .switch {
  box-shadow: 0 var(--px) 0 var(--c-cr0);
}
.opt-card > .motion {
  box-shadow: none;
}
.opt-label {
  font-weight: 600;
}
.opt-hint {
  margin: 0;
  padding: 0 var(--px);
  color: var(--c-du1);
}
.seg {
  display: flex;
  flex-wrap: wrap;
  gap: var(--px);
}
.seg .btn {
  padding: 0 calc(2 * var(--px));
}
/* Volume: a native range over a pixel track (the input carries focus and the value). */
.slider {
  position: relative;
  flex: 1;
  min-width: calc(40 * var(--px));
  height: calc(9 * var(--px));
}
.slider-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--c-go3);
  box-shadow: inset 0 calc(-1 * var(--px)) 0 var(--c-go2);
}
.slider input {
  position: absolute;
  left: calc(-4 * var(--px));
  right: calc(-4 * var(--px));
  top: 50%;
  width: calc(100% + 8 * var(--px));
  height: 44px;
  margin: 0;
  transform: translateY(-50%);
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  cursor: pointer;
  outline: none;
}
.slider input::-webkit-slider-runnable-track {
  height: 100%;
  background: transparent;
}
.slider input::-moz-range-track {
  background: transparent;
}
.slider input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: calc(7 * var(--px));
  height: calc(8 * var(--px));
  margin-top: calc(22px - 4 * var(--px));
  border: 0;
  background: var(--kk-img-thumb) 0 0 / 100% 100%;
  image-rendering: pixelated;
}
.slider input::-moz-range-thumb {
  width: calc(7 * var(--px));
  height: calc(8 * var(--px));
  border: 0;
  border-radius: 0;
  background: var(--kk-img-thumb) 0 0 / 100% 100%;
  image-rendering: pixelated;
}
.slider:focus-within {
  outline: var(--px) solid var(--c-wo1);
  outline-offset: calc(2 * var(--px));
}

/* Desktop shelf dock under the buy bar: one compact button per ticket. */
.dock {
  grid-area: dock;
  min-width: 0;
  min-height: 0;
  margin: 0 calc(2 * var(--px)) calc(2 * var(--px));
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-color: var(--c-du2) var(--c-du0);
}
.shelf-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(calc(38 * var(--px)), 1fr));
  gap: calc(2 * var(--px));
}
.shelf-item {
  display: flex;
  min-width: 0;
}
.btn.shelf-tile {
  flex: 1;
  min-width: 0;
  flex-direction: column;
  gap: var(--px);
  padding: var(--px);
  line-height: 1.5;
}
.shelf-stub {
  display: block;
  width: calc(30 * var(--px));
  height: calc(16 * var(--px));
}
.shelf-cap {
  display: inline-flex;
  align-items: center;
  gap: var(--px);
}

/* ---- dialogs ------------------------------------------------------------------------------ */

.modal {
  width: min(calc(100vw - 24px), calc(150 * var(--px)), 440px);
  max-height: calc(100dvh - 24px);
  margin: auto;
  padding: var(--px) calc(2 * var(--px)) calc(2 * var(--px));
  background: none;
  color: var(--c-ink);
  overflow: auto;
}
.modal.wide {
  width: min(calc(100vw - 24px), calc(190 * var(--px)), 560px);
}
.modal::backdrop {
  background: rgba(20, 13, 31, 0.7);
}
.modal[open] {
  animation: kk-modal-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
.modal[open]::backdrop {
  animation: kk-fade-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes kk-modal-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
@keyframes kk-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.modal-head {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--px));
  margin-bottom: calc(2 * var(--px));
}
.modal-title {
  margin: 0;
  font: 400 var(--pf) / 1.6 var(--font-pixel);
  color: var(--c-wo1);
}
.modal-body p {
  margin: 0 0 calc(2 * var(--px));
}
.modal-stats {
  margin: 0 0 calc(3 * var(--px));
  padding: var(--px) calc(2 * var(--px));
  background: var(--c-cr2);
  box-shadow: 0 0 0 var(--px) var(--c-cr0);
}
/* Bruno on the line: portrait and what he growls. */
.bruno-call {
  display: flex;
  align-items: center;
  gap: calc(3 * var(--px));
  margin: 0 0 calc(3 * var(--px));
}
canvas.bruno {
  flex: none;
  width: calc(32 * var(--px));
  height: calc(32 * var(--px));
  image-rendering: pixelated;
}
.modal-body .bruno-says {
  margin: 0;
  padding: calc(2 * var(--px)) calc(3 * var(--px));
  background: var(--c-cr2);
  box-shadow: 0 0 0 var(--px) var(--c-cr0);
}
.bruno-name {
  color: var(--c-re1);
}

/* "Gewinne & Chancen": ticket switcher, summary, prize table. */
.odds-nav {
  display: flex;
  align-items: center;
  gap: calc(2 * var(--px));
  margin: 0 0 calc(3 * var(--px));
}
.odds-card {
  flex: none;
  width: calc(24 * var(--px));
  height: auto;
  image-rendering: pixelated;
}
.odds-head {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--px);
}
.odds-name {
  font-size: 1.15em;
  line-height: 1.2;
  color: var(--c-wo1);
}
.odds-price {
  color: var(--c-du1);
}
.odds-step {
  flex: none;
}
.odds-step:disabled {
  visibility: hidden;
}
.odds-locked {
  color: var(--c-re1);
}
.odds-table {
  width: 100%;
  margin: 0 0 calc(3 * var(--px));
  border-collapse: collapse;
  background: var(--c-cr2);
  box-shadow: 0 0 0 var(--px) var(--c-cr0);
  font-variant-numeric: tabular-nums;
}
.odds-table th,
.odds-table td {
  padding: var(--px) calc(2 * var(--px));
  text-align: right;
  white-space: nowrap;
}
.odds-table thead th {
  font-weight: 700;
  color: var(--c-du1);
  box-shadow: 0 var(--px) 0 var(--c-cr0);
}
.odds-table thead th:first-child,
.odds-table .odds-prize {
  text-align: left;
}
.odds-table tbody tr + tr > * {
  box-shadow: 0 calc(-1 * var(--px)) 0 var(--c-cr1);
}
.odds-prize {
  font-weight: 700;
}
.odds-top > * {
  background: var(--c-go5);
}
.odds-top .odds-prize {
  color: var(--c-wo1);
}
.odds-niete > * {
  color: var(--c-du1);
}
/* Narrow dialogs: "1 zu N" says the same as the percentage. */
@media (max-width: 420px) {
  .odds-table .odds-pct {
    display: none;
  }
}
.modal-body .odds-note {
  margin-bottom: var(--px);
  color: var(--c-du1);
}
.modal-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: calc(2 * var(--px));
}

/* ---- overlays ----------------------------------------------------------------------------- */

.fx {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 30;
  pointer-events: none;
}
/* An open shop sheet covers the ticket, so its flakes and coins pass under the sheet; a big-win
   show still plays on top of everything. */
.app.shop-open:not(.celebrating) ~ .fx {
  z-index: 4;
}
.dim {
  position: fixed;
  inset: 0;
  z-index: 25;
  background: rgba(20, 13, 31, 0.6);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.25s, visibility 0.25s;
}
.dim.on {
  opacity: 1;
  visibility: visible;
}
.toast:not([hidden]) {
  animation: kk-toast-in 0.2s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes kk-toast-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.toast {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 50;
  width: max-content;
  max-width: calc(100vw - 24px);
  margin: 0 auto;
  padding: var(--px) calc(4 * var(--px));
  color: var(--c-cr2);
}
.boot {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  background: var(--c-ink0);
  text-align: center;
}
.boot-title {
  margin: 0 0 12px;
  font: 400 16px / 1.4 var(--font-pixel);
  color: var(--c-go3);
}
.boot-msg {
  margin: 0;
  color: var(--c-du3);
}

/* ---- title -------------------------------------------------------------------------------- */
/* Own pixel scale (src/ui/title.js sets --px, --pf, --tf and the frame widths on .title), so
   --fs is declared again to follow it. Stacked on portrait screens, scene beside logo otherwise. */

.title {
  --fs: calc(12px + var(--px) * 1.5);
  position: fixed;
  inset: 0;
  z-index: 45;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: var(--c-ink0) var(--kk-title-bg) 0 0 / calc(32 * var(--px)) calc(32 * var(--px)) repeat;
  image-rendering: pixelated;
  font-size: var(--fs);
}
.title-card {
  display: grid;
  grid-template-areas: "logo" "scene" "info" "actions";
  justify-items: center;
  align-items: center;
  gap: calc(4 * var(--px));
  width: max-content;
}
.title.side .title-card {
  grid-template-areas: "scene logo" "scene info" "scene actions";
  grid-template-rows: auto auto auto;
  align-content: center;
  column-gap: calc(8 * var(--px));
}
.title-logo {
  grid-area: logo;
  display: block;
}
.title.side .title-logo {
  align-self: end;
}
.title-view {
  grid-area: scene;
  position: relative;
  overflow: hidden;
  cursor: pointer;
}
#title-kiosk {
  display: block;
}
.title-info {
  grid-area: info;
  contain: inline-size;
  justify-self: stretch;
  margin: 0;
  text-align: center;
  color: var(--c-du3);
  font-weight: 600;
}
.title-actions {
  grid-area: actions;
  contain: inline-size;
  justify-self: stretch;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(3 * var(--px));
}
.title.side .title-info,
.title.side .title-actions {
  align-self: start;
}
.title-actions .btn:not(.icon-btn) {
  font-size: var(--tf);
  min-height: max(44px, calc(var(--tf) * 2 + 4 * var(--px)));
  padding-inline: calc(5 * var(--px));
}
.title-actions .icon-btn {
  min-height: max(44px, calc(var(--tf) * 2 + 4 * var(--px)));
}
#title-play[aria-busy="true"] {
  cursor: progress;
}

/* ---- onboarding pointers (src/ui/coach.js) -------------------------------------------------- */

.coach {
  position: fixed;
  inset: 0;
  z-index: 20;
  pointer-events: none;
  overflow: hidden;
}
.coach-arrow,
.coach-hand {
  position: absolute;
  left: 0;
  top: 0;
  image-rendering: pixelated;
  background: var(--img) 0 0 / 100% 100% no-repeat;
}
.coach-arrow {
  --img: var(--kk-img-coachArrow);
  width: calc(11 * var(--px));
  height: calc(12 * var(--px));
  animation: kk-bob 0.8s steps(1, end) infinite;
}
.coach-hand {
  --img: var(--kk-img-coachHand);
  width: calc(13 * var(--px));
  height: calc(16 * var(--px));
}
@keyframes kk-bob {
  0%, 50% { transform: none; }
  50.01%, 100% { transform: translateY(calc(-2 * var(--px))); }
}

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

.app.shake {
  animation: kk-shake 0.36s steps(1, end);
}
@keyframes kk-shake {
  0% { transform: translate(calc(2 * var(--px)), 0); }
  17% { transform: translate(calc(-2 * var(--px)), var(--px)); }
  33% { transform: translate(var(--px), calc(-1 * var(--px))); }
  50% { transform: translate(calc(-1 * var(--px)), 0); }
  67% { transform: translate(var(--px), var(--px)); }
  83% { transform: translate(0, calc(-1 * var(--px))); }
  100% { transform: none; }
}
@keyframes kk-bump {
  0% { transform: translateY(calc(-1 * var(--px))); }
  100% { transform: none; }
}

/* Reduced motion follows the in-game setting (game.js mirrors it to html[data-motion]). */
html[data-motion="reduce"] .modal[open],
html[data-motion="reduce"] .modal[open]::backdrop,
html[data-motion="reduce"] .toast,
html[data-motion="reduce"] .app.shake,
html[data-motion="reduce"] .coins.bump,
html[data-motion="reduce"] .shop-btn.hint,
html[data-motion="reduce"] .coach-arrow,
html[data-motion="reduce"] .panels .kk-card-hot,
html[data-motion="reduce"] .btn.ringing .ico {
  animation: none;
}
html[data-motion="reduce"] .odo-s,
html[data-motion="reduce"] .dim {
  transition: none;
}

/* ---- layouts ------------------------------------------------------------------------------ */

@media (orientation: landscape) {
  .app {
    --layout: split;
    grid-template-columns: minmax(0, 1.25fr) minmax(250px, 1fr);
    /* The kiosk takes the column's spare height, up to the whole scene. */
    grid-template-rows: auto minmax(calc(64 * var(--px)), calc(120 * var(--px))) auto minmax(0, 1fr);
    grid-template-areas: "table hud" "table kiosk" "table buy" "table panels";
  }
  .kiosk {
    height: auto;
  }
  .stack {
    --stack-h: 52;
  }
  .buy-info {
    display: flex;
  }
  .panels {
    grid-row: 2 / -1;
    grid-column: 2;
  }
}

@media (orientation: landscape) and (min-width: 1024px) {
  .app {
    --layout: wide;
    grid-template-columns: minmax(280px, 1fr) minmax(0, 1.3fr) minmax(280px, 1fr);
    /* The shelf keeps its height; the kiosk gives way first (layout.js re-crops it). Table and
       panels are size-contained so their tall content cannot claim the shelf row. */
    grid-template-rows: auto minmax(0, calc(120 * var(--px))) auto minmax(min-content, 1fr);
    grid-template-areas: "hud hud hud" "kiosk table panels" "buy table panels" "dock table panels";
  }
  .panels {
    grid-area: panels;
    display: flex;
    z-index: auto;
    padding-top: calc(3 * var(--px));
  }
  .shop-btn,
  .shop-close {
    display: none;
  }
  .kiosk {
    height: auto;
  }
  .table,
  .panels {
    contain: size;
  }
  .buy {
    align-self: start;
  }
  .hud-title {
    display: block;
  }
}

/* ---- Teller-Job ------------------------------------------------------------------------------ */
.plate-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: calc(2 * var(--px));
  margin: 0 0 calc(2 * var(--px));
}
canvas.plate {
  width: min(100%, 240px, calc(100dvh - 250px));
  min-width: 96px;
  aspect-ratio: 1;
  image-rendering: pixelated;
  touch-action: none;
  cursor: var(--kk-cursor), pointer;
  background: var(--c-gr1);
  box-shadow: 0 0 0 var(--px) var(--c-ink0);
}
canvas.plate:focus-visible {
  outline: var(--px) solid var(--c-go4);
  outline-offset: calc(2 * var(--px));
}
.plate-status {
  min-height: 2.5em;
  margin: 0;
  text-align: center;
}
.plate-status.win {
  color: var(--c-te0);
}
.plate-status.lost {
  color: var(--c-re1);
}
.plate-again {
  max-width: 100%;
}
.plate-again[hidden] {
  display: none;
}
/* Low landscape screens: plate on the left, result and button beside it. */
@media (orientation: landscape) and (max-height: 500px) {
  .plate-wrap {
    grid-template-columns: auto minmax(min-content, 1fr);
    align-items: center;
    column-gap: calc(3 * var(--px));
  }
  canvas.plate {
    grid-row: span 2;
    width: max(96px, calc(100dvh - 250px));
  }
}
