/* Game shell: HUD, bottom bar, build sheet, tool row, toasts, dialogs, loading and error overlays.
   Mobile first (375x812 portrait, thumbs at the bottom, tap targets >= 44 px, safe-area insets);
   desktop (>= 900 px) turns the build sheet into a side panel. Colors come from the theme palette:
   app/game.js and app/boot.js set the --cp-* custom properties (ui/auth.js authPaletteVars); the
   values below are fallbacks (= default theme). */

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #e6f6ff;
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
}
#app { position: fixed; inset: 0; overflow: hidden; }
#viewport { position: absolute; inset: 0; touch-action: none; -webkit-user-select: none; user-select: none; }
#viewport canvas { display: block; outline: none; }
#ui { position: absolute; inset: 0; pointer-events: none; }

.cp-ui, .cp-overlay {
  --cp-accent: #f1976c; --cp-accent2: #6794d9; --cp-ok: #61cb8b; --cp-bad: #cf534f; --cp-text: #38383d;
  --cp-panel: #ffffff; --cp-ice: #d0e8ff; --cp-peri: #a0a8c9; --cp-slate: #4f5260; --cp-amber: #ffc044;
  --cp-cream: #fde4c7; --cp-white: #ffffff; --cp-sky-top: #8ed1fc; --cp-sky-mid: #bfe5fd; --cp-sky-bottom: #e6f6ff;
  --cp-ink: #2f4f7a;
  --cp-shadow: 0 3px 0 color-mix(in srgb, var(--cp-ink) 18%, transparent), 0 6px 16px color-mix(in srgb, var(--cp-ink) 14%, transparent);
  --cp-safe-t: env(safe-area-inset-top, 0px);
  --cp-safe-r: env(safe-area-inset-right, 0px);
  --cp-safe-b: env(safe-area-inset-bottom, 0px);
  --cp-safe-l: env(safe-area-inset-left, 0px);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.25;
  color: var(--cp-text);
  -webkit-tap-highlight-color: transparent;
}
.cp-ui { position: absolute; inset: 0; pointer-events: none; }
.cp-ui *, .cp-ui *::before, .cp-ui *::after, .cp-overlay *, .cp-overlay *::before, .cp-overlay *::after { box-sizing: border-box; }
/* :where() keeps this at element specificity so component classes below set their own colours. */
:where(.cp-ui, .cp-overlay) button { font: inherit; color: inherit; cursor: pointer; -webkit-user-select: none; user-select: none; touch-action: manipulation; }
.cp-ui button:focus-visible, .cp-overlay button:focus-visible { outline: 3px solid var(--cp-accent2); outline-offset: 2px; }
.cp-icon { display: block; flex: none; }

/* ---------------------------------------------------------------- HUD */
.cp-hud {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: calc(var(--cp-safe-t) + 8px) calc(var(--cp-safe-r) + 8px) 0 calc(var(--cp-safe-l) + 8px);
  pointer-events: none;
}
.cp-hud > * { pointer-events: auto; }
/* The money pill's wrapper takes the room the other HUD items leave (hud.js fitMoney measures it);
   taps on its empty part still reach the park. Desktop: it never shrinks below the pill. */
.cp-hud > .cp-hud__statsroom { flex: 1 1 auto; min-width: 0; display: flex; pointer-events: none; }
.cp-hud__statsroom > .cp-hud__stats { pointer-events: auto; }
.cp-hud__stat {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 44px;
  padding: 0 12px;
  border-radius: 14px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 0;
}
.cp-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* Money and guests side by side in one pill; HUD items added later (hud.addItem) and the menu sit
   to its right, so the pill only takes the width it needs. */
.cp-hud__stats {
  flex: 0 1 auto;
  gap: 14px;
  padding: 0 14px;
  margin-right: auto;
  overflow: hidden;
}
.cp-hud__money { font-size: 19px; font-weight: 900; line-height: 1.1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cp-hud__money.is-negative { color: var(--cp-bad); }
.cp-hud__guests { display: flex; align-items: center; gap: 4px; flex: none; font-size: 17px; font-weight: 800; line-height: 1.1; color: var(--cp-slate); }
/* Last resort on the narrowest phones (hud.js fitMoney): the money keeps the pill, the guest count goes. */
.cp-hud__stats.is-cramped .cp-hud__guests { display: none; }
.cp-hud__stats.is-up { animation: cp-flash-up 0.6s ease-out; }
.cp-hud__stats.is-down { animation: cp-flash-down 0.6s ease-out; }
@keyframes cp-flash-up { 0% { background: color-mix(in srgb, var(--cp-ok) 45%, var(--cp-panel)); } 100% { background: var(--cp-panel); } }
@keyframes cp-flash-down { 0% { background: color-mix(in srgb, var(--cp-accent) 45%, var(--cp-panel)); } 100% { background: var(--cp-panel); } }
.cp-hud__extra { display: contents; }
.cp-hud__menubtn {
  flex: none;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
  display: grid;
  place-items: center;
}

.cp-menu {
  position: absolute;
  top: calc(var(--cp-safe-t) + 60px);
  right: calc(var(--cp-safe-r) + 8px);
  width: min(300px, calc(100vw - 16px));
  padding: 14px;
  border-radius: 18px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: auto;
}
.cp-menu[hidden] { display: none; }
.cp-menu__user { margin: 0; font-weight: 800; overflow-wrap: anywhere; }
.cp-menu__row { display: flex; align-items: center; gap: 10px; min-height: 44px; cursor: pointer; }
.cp-menu__check { width: 22px; height: 22px; accent-color: var(--cp-accent2); }
.cp-menu__keys { margin: 0; font-size: 14px; color: var(--cp-slate); }
@media (pointer: coarse) { .cp-menu__keys { display: none; } }

/* ---------------------------------------------------------------- buttons */
.cp-btn {
  min-height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 12px;
  background: var(--cp-ice);
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--cp-text) 14%, transparent);
}
/* Dark text on the light accent colours: ~6:1 contrast (white on salmon would be ~2.3:1). */
.cp-btn--primary { background: var(--cp-accent); color: var(--cp-text); }
.cp-btn--danger { background: var(--cp-bad); color: var(--cp-white); }

/* ---------------------------------------------------------------- bottom: sheet, tool row, bar */
.cp-bottom {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 calc(var(--cp-safe-r) + 8px) calc(var(--cp-safe-b) + 8px) calc(var(--cp-safe-l) + 8px);
  pointer-events: none;
}
.cp-bottom > * { pointer-events: auto; }
.cp-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2px;
  padding: 4px;
  border-radius: 18px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
}
.cp-bar__build {
  flex: 0 0 auto;
  min-width: 96px;
  height: 48px;
  padding: 0 12px 0 8px;
  border: 0;
  border-radius: 14px;
  background: var(--cp-accent);
  color: var(--cp-text);
  font-weight: 800;
  font-size: 16px;
  display: flex;
  align-items: center;
  gap: 6px;
  box-shadow: inset 0 -4px 0 color-mix(in srgb, var(--cp-text) 18%, transparent);
}
.cp-bar__build.is-open { background: var(--cp-ice); }
.cp-bar__btn {
  flex: 1 1 0;
  min-width: 44px;
  max-width: 56px;
  height: 48px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  display: grid;
  place-items: center;
  color: var(--cp-slate);
}
.cp-bar__btn:active { background: var(--cp-ice); }
.cp-bar__btn:disabled { opacity: 0.35; cursor: default; }
.cp-bar__btn[aria-pressed="true"] { background: var(--cp-ice); color: var(--cp-accent2); }

.cp-toolrow {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 56px;
  padding: 6px;
  border-radius: 18px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
}
.cp-toolrow[hidden] { display: none; }
.cp-toolrow__chip {
  position: relative;
  flex: none;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 12px;
  background: var(--cp-ice);
  display: grid;
  place-items: center;
  color: var(--cp-ink);
}
.cp-toolrow__x {
  position: absolute;
  top: -5px; right: -5px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--cp-slate);
  color: var(--cp-white);
  display: grid;
  place-items: center;
}
.cp-toolrow__readout { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cp-toolrow__line1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-toolrow__line1 { font-size: 16px; }
.cp-toolrow__name { font-weight: 900; }
.cp-toolrow__value { font-weight: 700; font-variant-numeric: tabular-nums; }
/* The hint is the main instruction for a first-time phone player: 16 px (BRIEF 7.1), and on very
   narrow phones it may take a second line instead of being cut off. */
.cp-toolrow__hint {
  font-size: 16px;
  line-height: 1.2;
  color: var(--cp-slate);
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
.cp-toolrow__readout.is-bad .cp-toolrow__hint { color: var(--cp-bad); font-weight: 800; }
.cp-toolrow__readout.is-ok .cp-toolrow__value,
.cp-toolrow__readout.is-value .cp-toolrow__hint { color: color-mix(in srgb, var(--cp-ok) 55%, var(--cp-text)); font-weight: 800; }
.cp-toolrow__btn {
  flex: none;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 12px;
  background: var(--cp-ice);
  display: grid;
  place-items: center;
}
.cp-toolrow__btn[hidden], .cp-toolrow__confirm[hidden] { display: none; }
.cp-toolrow__confirm {
  flex: none;
  min-width: 92px;
  height: 44px;
  padding: 0 12px 0 8px;
  border: 0;
  border-radius: 12px;
  background: var(--cp-ok);
  color: var(--cp-text);
  font-weight: 900;
  display: flex;
  align-items: center;
  gap: 4px;
  box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--cp-text) 18%, transparent);
}
.cp-toolrow__confirm.is-remove { background: var(--cp-bad); color: var(--cp-white); }
.cp-toolrow__confirm:disabled { background: var(--cp-peri); cursor: default; }

.cp-sheet {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: min(46vh, 340px);
  padding: 8px;
  border-radius: 18px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
}
.cp-sheet[hidden] { display: none; }
.cp-sheet__head { display: flex; gap: 6px; align-items: center; }
/* Tabs share the full sheet width (on phones the bar's Bouwen button turns into Sluiten, so the head
   needs no close button) and size to their label, so five tabs (with Attracties) fit uncut on a
   375 px phone. Labels never ellipsize; if a theme ever adds more tabs than fit, the strip scrolls
   sideways instead of cutting words. */
.cp-sheet__tabs {
  display: flex;
  gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.cp-sheet__tabs::-webkit-scrollbar { display: none; }
.cp-sheet__tab {
  flex: 1 0 auto;
  min-width: 44px;
  height: 44px;
  padding: 0 7px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 15px;
  white-space: nowrap;
  color: var(--cp-slate);
}
.cp-sheet__tab[aria-selected="true"] { background: var(--cp-ink); color: var(--cp-white); }
.cp-sheet__close {
  flex: none;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 12px;
  background: var(--cp-ice);
  display: none;
  place-items: center;
}
/* Phones: a two-column list of wide cards (icon left, name + price right) so Dutch compound names
   ("Snackkraam", "Informatiekiosk") fit on one line at 15 px instead of breaking mid-word.
   The desktop side panel (below) uses tall cards in three columns. */
.cp-sheet__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
  /* Two rows plus a peek of the third; a longer tab scrolls inside the sheet (phones: see below). */
  max-height: 142px;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.cp-card {
  min-height: 54px;
  padding: 6px 8px 6px 6px;
  border: 0;
  border-radius: 14px;
  background: var(--cp-cream);
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  text-align: left;
  box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--cp-accent) 30%, transparent);
}
.cp-card.is-active { background: color-mix(in srgb, var(--cp-accent2) 25%, var(--cp-white)); box-shadow: inset 0 0 0 3px var(--cp-accent2); }
.cp-card.is-locked { background: color-mix(in srgb, var(--cp-peri) 25%, var(--cp-white)); color: var(--cp-slate); box-shadow: none; }
.cp-card__icon { flex: none; color: var(--cp-ink); }
.cp-card.is-locked .cp-card__icon { color: var(--cp-slate); }
.cp-card__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* Words never break (build-bar.js shrinks a too-long single word instead); .is-squeezed is the
   last resort when even NAME_MIN_PX does not fit. */
.cp-card__name { display: block; font-size: 15px; font-weight: 800; line-height: 1.15; overflow: hidden; overflow-wrap: normal; }
.cp-card__name.is-squeezed { overflow-wrap: anywhere; }
.cp-card__cost { font-size: 15px; font-weight: 700; color: var(--cp-slate); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- toasts */
.cp-toasts {
  position: absolute;
  top: calc(var(--cp-safe-t) + 60px);
  left: 0; right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  pointer-events: none !important;
}
.cp-toast {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: min(440px, 100%);
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
  font-weight: 700;
  animation: cp-toast-in 0.18s ease-out;
}
.cp-toast.is-leaving { opacity: 0; transform: translateY(-6px); transition: opacity 0.2s, transform 0.2s; }
.cp-toast__icon { flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; background: var(--cp-ice); color: var(--cp-ink); }
.cp-toast--success .cp-toast__icon { background: var(--cp-ok); color: var(--cp-white); }
.cp-toast--warning .cp-toast__icon, .cp-toast--error .cp-toast__icon { background: var(--cp-bad); color: var(--cp-white); }
@keyframes cp-toast-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* ---------------------------------------------------------------- dialogs */
.cp-modal {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px;
  background: color-mix(in srgb, var(--cp-text) 35%, transparent);
  pointer-events: auto;
  z-index: 10;
}
.cp-dialog {
  width: min(360px, 100%);
  padding: 20px;
  border-radius: 20px;
  background: var(--cp-panel);
  box-shadow: var(--cp-shadow);
}
.cp-dialog__title { margin: 0 0 8px; font-size: 22px; font-weight: 900; }
.cp-dialog__body { margin: 0 0 18px; font-size: 16px; line-height: 1.4; }
.cp-dialog__actions { display: flex; gap: 10px; justify-content: flex-end; }
.cp-dialog__actions .cp-btn { flex: 1 1 0; }

/* ---------------------------------------------------------------- overlays (loading, error) */
.cp-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: calc(var(--cp-safe-t) + 16px) 16px calc(var(--cp-safe-b) + 16px);
  background: linear-gradient(180deg, var(--cp-sky-top) 0%, var(--cp-sky-mid) 45%, var(--cp-sky-bottom) 100%);
  pointer-events: auto;
}
.cp-loading { width: min(320px, 100%); text-align: center; }
.cp-loading__title { margin: 0 0 18px; font-size: 34px; font-weight: 900; color: var(--cp-white); text-shadow: 0 3px 0 color-mix(in srgb, var(--cp-ink) 45%, transparent); }
.cp-loading__bar { height: 16px; border-radius: 999px; background: color-mix(in srgb, var(--cp-white) 70%, transparent); overflow: hidden; box-shadow: inset 0 2px 0 color-mix(in srgb, var(--cp-ink) 12%, transparent); }
.cp-loading__fill { display: block; width: 4%; height: 100%; border-radius: 999px; background: var(--cp-accent); transition: width 0.2s; }
.cp-loading__text { margin: 12px 0 0; font-weight: 700; color: var(--cp-ink); }
.cp-error { width: min(400px, 100%); padding: 22px; border-radius: 20px; background: var(--cp-panel); box-shadow: var(--cp-shadow); }
.cp-error__title { margin: 0 0 8px; font-size: 24px; font-weight: 900; }
.cp-error__body { margin: 0 0 16px; line-height: 1.45; }
.cp-error__details { margin-top: 14px; font-size: 13px; color: var(--cp-slate); }
.cp-error__details pre { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 30vh; overflow: auto; }
/* Maintenance (server away for a deploy/restart; ui/error-screen.js): above the loading overlay. */
.cp-overlay--maintenance { z-index: 61; overflow-y: auto; }
.cp-maintenance { width: min(400px, 100%); padding: 18px 22px 22px; border-radius: 20px; background: var(--cp-panel); box-shadow: var(--cp-shadow); text-align: center; }
.cp-maintenance__logo { margin: 0 auto 10px; max-width: 280px; font-size: 28px; font-weight: 900; }
.cp-maintenance__title { margin: 0 0 8px; font-size: 26px; font-weight: 900; }
.cp-maintenance__body { margin: 0 0 8px; font-size: 17px; font-weight: 700; line-height: 1.4; }
.cp-maintenance__safe { margin: 0 0 14px; line-height: 1.45; color: var(--cp-slate); }
.cp-maintenance__status { margin: 0 0 14px; min-height: 1.4em; font-size: 14px; color: var(--cp-slate); }
.cp-maintenance__retry { width: 100%; min-height: 48px; }

/* ---------------------------------------------------------------- desktop */
@media (min-width: 900px) {
  .cp-bottom { left: 0; right: 0; margin: 0 auto; width: min(760px, calc(100vw - 32px)); padding-left: 0; padding-right: 0; }
  .cp-bar { justify-content: center; gap: 8px; }
  .cp-bar__btn { flex: 0 0 52px; }
  .cp-sheet {
    position: fixed;
    left: 12px;
    top: calc(var(--cp-safe-t) + 64px);
    width: 520px; /* six tabs (Paden .. Land) need 438 px: 520 - 16 padding - 6 gap - 44 close = 454 */
    max-height: calc(100vh - 170px);
  }
  /* The side panel is far from the bar's Bouwen/Sluiten button: give it its own close button. */
  .cp-sheet__close { display: grid; }
  .cp-sheet__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); max-height: none; }
  .cp-card { min-height: 92px; padding: 8px 4px 6px; flex-direction: column; justify-content: flex-start; gap: 3px; text-align: center; }
  .cp-card__text { align-items: center; }
  .cp-card__name { font-size: 14px; }
  .cp-hud { gap: 10px; }
  .cp-hud > .cp-hud__statsroom { flex: 1 0 auto; }
  .cp-hud__stats { gap: 16px; padding: 0 16px; }
}

/* Phones (portrait): the card grid shows at least two full rows of cards plus a group heading
   (Kramen: Eten / Drinken / Voorzieningen) and grows to 44% of the screen minus the fixed parts
   (user 2026-10-16: "the build menu may be bigger, at least 2 rows visible, and scroll"; this
   overrides the 35% coverage of BRIEF 5.9). Fixed parts: HUD band 52 px (8 + 44), bottom padding 6,
   bar 52 (44 + 2 x 4), gap 6, sheet padding 2 x 6 + tabs 44 + gap 6 = 178 px (+ 2 px margin + safe
   areas). Floor 150 px = heading 18 + 2 x 48 px cards + gaps + a peek of the next row. More cards
   scroll inside the grid, whose bottom edge fades out while more are below (.has-more, build-bar.js).
   The tool row hides while the sheet is open (the cards show the active tool), like the ride editor. */
@media (max-width: 899px) {
  .cp-bottom { padding-bottom: calc(var(--cp-safe-b) + 6px); }
  .cp-bar__build, .cp-bar__btn { height: 44px; }
  .cp-sheet { gap: 6px; padding: 6px; max-height: none; }
  .cp-sheet__grid { max-height: max(150px, calc(44vh - 180px - var(--cp-safe-t) - var(--cp-safe-b))); }
  @supports (height: 1dvh) {
    .cp-sheet__grid { max-height: max(150px, calc(44dvh - 180px - var(--cp-safe-t) - var(--cp-safe-b))); }
  }
  .cp-card { min-height: 48px; padding: 4px 8px 4px 6px; }
  .cp-card__name { white-space: nowrap; }
  .cp-card__name.is-wrapped { white-space: normal; }
  .cp-card__cost { line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .cp-bottom.has-sheet > .cp-toolrow { display: none; }
}
.cp-sheet__grid.has-more {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
}

/* Short phones (e.g. 320x640): tighter paddings (HUD 50, bar 50, gaps 4: 164 px fixed + 2 margin);
   the grid still shows a heading and two full rows of 46 px cards (floor 124 px). */
@media (max-width: 899px) and (max-height: 700px) {
  .cp-hud { padding-top: calc(var(--cp-safe-t) + 6px); }
  .cp-bottom { gap: 4px; padding-bottom: calc(var(--cp-safe-b) + 4px); }
  .cp-bar { padding: 3px; }
  .cp-sheet { gap: 4px; padding: 4px; }
  .cp-sheet__grid { gap: 4px; max-height: max(124px, calc(42vh - 166px - var(--cp-safe-t) - var(--cp-safe-b))); }
  .cp-card { min-height: 46px; padding-top: 3px; padding-bottom: 3px; }
  .cp-sheet__grid.has-more {
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 8px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 8px), transparent);
  }
  @supports (height: 1dvh) {
    .cp-sheet__grid { max-height: max(124px, calc(42dvh - 166px - var(--cp-safe-t) - var(--cp-safe-b))); }
  }
}

/* Phones under ~372 px: the bar (build button + 5 icon buttons of 44 px) does not fit with the
   Bouwen/Sluiten label, so the build button shows only its icon; the label stays in the DOM
   (visually hidden) as the button's accessible name. */
@media (max-width: 371px) {
  .cp-bar__build { position: relative; min-width: 56px; padding: 0; justify-content: center; }
  .cp-bar__buildlabel { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* Narrow phones: icon-only confirm (its aria-label keeps the word). */
@media (max-width: 420px) {
  .cp-toolrow__confirm { min-width: 56px; justify-content: center; padding: 0; }
  .cp-toolrow__confirmlabel { display: none; }
}
/* Very narrow phones (320-360 px): slightly smaller tab labels so five tabs still fit uncut. */
@media (max-width: 360px) {
  .cp-sheet__tabs { gap: 2px; }
  .cp-sheet__tab { font-size: 13.5px; padding: 0 4px; }
  .cp-card { padding-left: 5px; padding-right: 5px; gap: 4px; }
  .cp-card__icon .cp-icon { width: 22px; height: 22px; }
}

@media (prefers-reduced-motion: reduce) {
  .cp-hud__stats.is-up, .cp-hud__stats.is-down, .cp-toast { animation: none; }
  .cp-loading__fill { transition: none; }
}

/* ---------------------------------------------------------------- stall cards (docs/api/stalls.md)
   Raster icons (ui/icons.js imageIcon, 64 + 128 px files): 40 px in the 48 px phone list cards, 64 px
   in the desktop side panel. Locked stalls keep their picture (greyed, with a lock badge) so players
   see what is coming; gem stalls show a gem badge and their gem price instead of the euro price.
   The Kramen tab groups its cards under full-width labels (Eten, Drinken, Voorzieningen). */
.cp-card__icon.has-img { position: relative; width: 40px; height: 40px; display: grid; place-items: center; }
.cp-card__img { display: block; width: 40px; height: 40px; object-fit: contain; -webkit-user-drag: none; }
.cp-card.is-locked:not(.is-gemlocked) .cp-card__img { filter: grayscale(0.9); opacity: 0.55; }
.cp-card__badge {
  position: absolute;
  right: -5px; bottom: -3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--cp-slate);
  color: var(--cp-white);
  box-shadow: 0 0 0 2px var(--cp-white);
}
.cp-card__badge.is-gem { background: var(--cp-gem, #6a46c9); }
/* "Heb je al": a placed attraction / coaster family keeps a green check on its card. */
.cp-card__badge.is-owned { background: #2f9e44; }
.cp-card__icon.has-badge { position: relative; }
.cp-card.is-gemlocked {
  background: color-mix(in srgb, var(--cp-gem, #6a46c9) 12%, var(--cp-white));
  color: var(--cp-text);
  box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--cp-gem, #6a46c9) 35%, transparent);
}
.cp-card__gems { display: inline-flex; align-items: center; gap: 3px; color: var(--cp-gem, #6a46c9); font-weight: 800; }
.cp-card__gems .cp-icon { flex: none; }
.cp-sheet__group {
  grid-column: 1 / -1;
  padding: 2px 4px 0;
  font-size: 13px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cp-slate);
}
.cp-toolrow__img { display: block; width: 40px; height: 40px; object-fit: contain; }
@media (min-width: 900px) {
  .cp-card__icon.has-img, .cp-card__img { width: 64px; height: 64px; }
  .cp-sheet__group { padding: 6px 4px 0; font-size: 14px; }
  /* A card with a 64 px picture is taller than the 92 px min-height. The side panel's grid is shrunk
     to the panel height and scrolls, so plain auto rows would stay at the min-height and clip the
     price: rows are at least as tall as their content. */
  .cp-sheet__grid { grid-auto-rows: minmax(min-content, auto); }
}
@media (max-width: 360px) {
  .cp-card__icon.has-img, .cp-card__img { width: 36px; height: 36px; }
}
/* Admin link in the HUD menu (owner only, /beheer). */
.cp-menu__admin { display: flex; justify-content: center; text-decoration: none; }
