:root {
  --util-face: #e7ecf4;
  --bg: #e6e9ef;
  --bg-side: #c9cfdb;
  --grass: #8fe05c;
  --grass-2: #80d24e;
  --grass-deep: #4f9c34;
  --grass-deep-2: #3a7a24;
  --road: #575c6e;
  --water: #4cc6f2;
  --sky: #c9edff;
  --sky-2: #a4d8f5;
  --block: #ffffff;
  --block-side: #cfd6e4;
  --muted: #56607d;
  --yellow: #ffcc29;
  --yellow-side: #d99700;
  --red: #ff4d5e;
  --red-side: #c42a3a;
  --green: #45d264;
  --green-side: #2b9a45;
  --orange: #ff9f1c;
  --orange-side: #d27800;
  --fortune: #2b2160;      /* the Fortune cards' blue: the corner tile, the deck on the globe, the wheel and the cards share it */
  --fortune-side: #1b1442; /* its darker side */
  --purple: #9b5de5;
  --purple-side: #6c3bb5;
  --font: 'Tomorrow', 'Avenir Next', system-ui, sans-serif;
  color-scheme: light;
  /* page-level layers (things inside the board stack locally and keep small numbers) */
  --z-drawer: 40; --z-drawer-tab: 41; --z-invite: 60; --z-draft: 65; --z-popover: 80; --z-bubble: 85;
}

* { box-sizing: border-box; scrollbar-width: none; }
*::-webkit-scrollbar { display: none; }
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 600 15px/1.45 var(--font);
  overflow: hidden;
}
button { font: inherit; color: inherit; }
input, select { font: inherit; }

/* ---------- shared ---------- */

.ic { width: 1em; height: 1em; vertical-align: -.15em; display: inline-block; flex: none; }
.btn .ic { margin-right: .3em; }
.btn .ic + .ic { margin-left: -.3em; }

/* Every interactive surface is a "block": flat top face, darker side strip underneath. */
.btn {
  --face: var(--block);
  --side: var(--block-side);
  border: 0;
  background: var(--face);
  color: var(--ink);
  padding: 9px 14px;
  border-radius: var(--r-sm);
  box-shadow: 0 4px 0 var(--side);
  cursor: pointer;
  font-weight: 800;
  transition: transform .1s, box-shadow .1s, opacity .15s, filter .15s;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { filter: brightness(1.05); transform: translateY(-1px); box-shadow: 0 5px 0 var(--side); }
.btn:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 1px 0 var(--side); }
.btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn.primary { --face: var(--yellow); --side: var(--yellow-side); color: var(--ink); }
.btn.big { width: 100%; padding: 14px; font: 500 20px/1 var(--font); letter-spacing: .02em; box-shadow: 0 6px 0 var(--side); }
.btn.big:active:not(:disabled) { transform: translateY(5px); box-shadow: 0 1px 0 var(--side); }
.btn.ghost { --face: rgba(255, 255, 255, .7); --side: rgba(30, 37, 64, .15); }
.btn.danger { --face: var(--red); --side: var(--red-side); color: var(--ink); }
.btn.sm { padding: 5px 10px; font-size: 13px; box-shadow: 0 3px 0 var(--side); }
.btn.toggle.on { --face: var(--green); --side: var(--green-side); color: var(--ink); }
.row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 12px; }
.row > .btn { flex: 1; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.pad { padding: 12px 14px; margin: 0; }
.hint { color: var(--muted); margin: 10px 0 0; }
.hint.subtle { font-size: 13px; text-align: center; }
.warn { color: var(--bad); margin: 8px 0 0; }
.dot { display: inline-block; width: 10px; height: 10px; border-radius: 2px; background: var(--g); flex: none; }
.ptoken { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; flex: none; } /* (its face is the .pf inside: see "the pawn" at the end) */
.ptoken .ic, .slot-pawn .ic, .tk .ic, .pawn .ic { width: 62%; height: 62%; color: var(--ink); }
.ptoken.sm { width: 26px; height: 26px; font-size: 14px; display: inline-grid; vertical-align: middle; }

/* Chunky outlined block letters. */
.logo-lg, .logo-sm, .logo {
  font-family: var(--font);
  font-weight: 800;
  color: #fff;
  -webkit-text-stroke: .16em var(--ink);
  paint-order: stroke fill;
  text-shadow: 0 .1em 0 var(--ink);
  letter-spacing: .01em;
}
.logo-lg span, .logo-sm span, .logo span { color: var(--yellow); }
.logo-lg { font-size: clamp(56px, 10vw, 96px); line-height: 1; }
.logo-sm { font-size: 24px; -webkit-text-stroke-width: 6px; text-shadow: 0 3px 0 var(--ink); }

/* ---------- setup ---------- */

#setup { height: 100%; overflow: auto; padding: 36px 20px; }
.setup-inner { margin: 0 auto; }
.slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.slot {
  background: var(--block);
  border-radius: var(--r-md);
  box-shadow: 0 6px 0 var(--bg-side);
  padding: 14px;
  min-height: 236px;
  --from: translateY(12px);
  animation: enter .35s var(--ease-out);
}
.slot.add {
  display: grid; place-content: center; gap: 6px; text-align: center;
  background: rgba(255,255,255,.5); border: 3px dashed rgba(30,37,64,.3); box-shadow: none;
  color: var(--ink); cursor: pointer; font-weight: 800;
  transition: background .15s;
}
.slot.add span { font: 500 38px/1 var(--font); }
.slot.add:hover { background: rgba(255,255,255,.6); }
.slot-top { display: flex; align-items: center; gap: 10px; }
.slot-pawn { border-radius: 50%; display: grid; place-items: center; font-size: 24px; flex: none; }
.slot-name { flex: 1; min-width: 0; background: #eef2f8; border: 0; border-radius: var(--r-sm); padding: 9px 10px; color: var(--ink); font-weight: 800; box-shadow: inset 0 3px 0 var(--block-side); }
.slot-name:focus { outline: 3px solid var(--pc); }
.slot-x { background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 17px; line-height: 0; }
.slot-x:hover { color: var(--bad); }
.swatches { display: flex; flex-wrap: wrap; margin: 14px 0 10px; }
.sw { border-radius: var(--r-sm); border: 0; background: var(--c); cursor: pointer; box-shadow: 0 3px 0 color-mix(in srgb, var(--c) 60%, #000); }
.sw.on { box-shadow: 0 0 0 3px var(--ink); }
.sw:disabled { opacity: .2; cursor: not-allowed; }
.tokens-pick { display: grid; grid-template-columns: repeat(5, 1fr); }
.tk { background: #eef2f8; border: 0; border-radius: var(--r-sm); padding: 5px 0; font-size: 17px; line-height: 0; height: 32px; cursor: pointer; box-shadow: 0 3px 0 var(--block-side); }
.tk.on { background: color-mix(in srgb, var(--pc) 35%, #fff); box-shadow: 0 3px 0 var(--pc); }
.tk:disabled { opacity: .25; cursor: not-allowed; }
.setup-foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 26px; }
.cash-pick { display: flex; align-items: center; gap: 12px; font-weight: 800; background: var(--block); padding: 8px 12px; border-radius: var(--r-sm); box-shadow: 0 4px 0 var(--bg-side); flex-wrap: wrap; }
.chips-row { display: flex; gap: 6px; flex-wrap: wrap; }
.chip { background: #eef2f8; border: 0; padding: 6px 12px; border-radius: var(--r-sm); cursor: pointer; font-weight: 800; box-shadow: 0 3px 0 var(--block-side); }
.chip.on { background: var(--yellow); box-shadow: 0 3px 0 var(--yellow-side); }

/* ---------- game layout ---------- */

#game { display: flex; flex-direction: column; height: 100%; max-width: 640px; margin: 0 auto; background: var(--sky); box-shadow: 0 0 0 6px var(--sky-2); }
#stage-wrap { position: relative; flex: none; width: 100%; height: min(100vw, 54dvh); overflow: hidden; background: var(--bg); }
#stage { position: absolute; inset: 0; display: grid; place-items: center; user-select: none; }
#side {
  flex: 1; display: flex; flex-direction: column; min-height: 0; overflow-y: auto;
  background: var(--sky);
}
.side-head { display: flex; justify-content: space-between; align-items: center; padding: 10px 16px 6px; order: 1; }
#players { order: 2; }
#dock { order: 3; }
#actions { order: 4; }

#players { padding: 4px 12px 6px; display: grid; gap: 6px; }
.pcard {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  background: rgba(255,255,255,.6);
  box-shadow: 0 4px 0 var(--sky-2);
  transition: background .2s, box-shadow .2s, transform .2s;
}
.pcard.active { background: var(--block); box-shadow: 0 4px 0 var(--pc), 0 0 0 3px var(--pc); transform: translateY(-2px); }
.pcard.out { opacity: .4; filter: grayscale(1); }
.pinfo { flex: 1; min-width: 0; }
.pname { font-weight: 800; display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.badge { font-size: 11px; padding: 1px 6px; border-radius: 4px; background: #e6ebf3; font-weight: 800; }
.badge.jail { background: var(--red); color: var(--ink); }
.badge.ab { cursor: help; }
.badge .ic { width: 12px; height: 12px; }
.chips { display: flex; gap: 3px; flex-wrap: wrap; margin-top: 4px; min-height: 10px; }
.chips i { width: 9px; height: 12px; border-radius: 2px; background: var(--g); box-shadow: 0 2px 0 rgba(0,0,0,.2); }
.chips .muted { font-size: 11px; }
.pcash { text-align: right; }
.pcash b { font: 500 20px/1 var(--font); font-variant-numeric: tabular-nums; display: block; }
.pcash.neg b { color: var(--bad); }
.pcash small { color: var(--muted); font-size: 11px; }

.actions { padding: 10px 14px calc(12px + var(--safe-bottom)); background: var(--block); box-shadow: 0 -4px 0 var(--sky-2); }
.turn-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; font-size: 15px; }
.turn-head b { font: 500 20px var(--font); color: var(--ink); }
.actions .btn.primary.big { margin-top: 8px; }

#dock { flex: 1; min-height: 120px; display: flex; flex-direction: column; margin: 0 12px 12px; background: var(--block); border-radius: var(--r-md); box-shadow: 0 5px 0 var(--sky-2); }
#dock-tabs { display: flex; gap: 4px; padding: 8px 8px 0; }
.tab { flex: 1; background: #eef2f8; border: 0; border-radius: var(--r-sm); padding: 8px 4px; color: var(--muted); cursor: pointer; font-weight: 800; box-shadow: 0 3px 0 var(--block-side); transition: transform .1s; }
.tab:hover { color: var(--ink); }
.tab.on { background: var(--yellow); color: var(--ink); box-shadow: 0 3px 0 var(--yellow-side); }
#dock-body { flex: 1; overflow: auto; padding: 12px 10px 14px; }

.assets { display: grid; gap: 6px; }
.asset { display: flex; align-items: center; justify-content: space-between; gap: 6px; background: #f3f6fb; border-radius: var(--r-sm); padding: 6px 6px 6px 10px; box-shadow: 0 2px 0 var(--block-side); }
.asset-name { display: flex; align-items: center; gap: 7px; min-width: 0; background: none; border: 0; padding: 0; cursor: pointer; text-align: left; flex-wrap: wrap; }
.asset-name span { font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.asset-name small { color: var(--muted); font-size: 11px; width: 100%; padding-left: 17px; margin-top: -3px; }
.asset-btns { display: flex; gap: 4px; flex: none; }
.asset-btns .btn { box-shadow: 0 3px 0 var(--side); }
.cash-in { display: flex; align-items: center; gap: 4px; margin-top: 8px; color: var(--muted); }
.cash-in input { width: 100%; background: #fff; color: var(--ink); border: 0; border-radius: var(--r-sm); padding: 7px 8px; font-weight: 800; box-shadow: inset 0 3px 0 var(--block-side), 0 0 0 2px var(--block-side); }
.cash-in input:focus { outline: 3px solid var(--ink); }

#ticker { position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); pointer-events: none; max-width: 90%; z-index: 2; }
#ticker span {
  display: block; padding: 9px 18px; border-radius: var(--r-sm);
  background: var(--ink); color: #fff; box-shadow: 0 4px 0 #0c1020;
  font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  --from: translateY(12px);
  animation: enter .35s var(--ease-out);
}
.toast {
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%); z-index: 3;
  padding: 10px 18px; border-radius: var(--r-sm); background: var(--ink); color: #fff; box-shadow: 0 4px 0 #000; font-weight: 800;
  animation: toast 2.6s ease forwards; pointer-events: none;
}
.floater {
  position: fixed; z-index: var(--z-float); transform: translate(-50%, 0); pointer-events: none;
  font: 500 24px var(--font); -webkit-text-stroke: 5px var(--ink); paint-order: stroke fill;
  animation: floatUp 1.3s var(--ease-out) forwards;
}
.floater.pos { color: var(--green); }
.floater.neg { color: var(--red); }

/* ---------- radial board ---------- */

.board { position: absolute; left: 50%; top: 50%; width: 1000px; height: 1000px; transform-origin: 50% 50%; --rot: 0deg; --turn: .9s cubic-bezier(.3,.7,.2,1); }
.board.snap, .board.snap * { transition: none !important; }
.board-base {
  position: absolute; inset: 3px; border-radius: 50%;
  /* concentric bands in three alternating dark greens */
  background: repeating-radial-gradient(circle at 50% 50%, #2f6b22 0 16px, #3a7a2b 16px 32px, #275d1c 32px 48px);
  box-shadow: 0 16px 0 var(--grass-deep-2), 0 30px 40px -10px rgba(30, 60, 20, .45);
}
.board-center {
  position: absolute; left: 196px; top: 196px; width: 608px; height: 608px; border-radius: 50%; overflow: hidden;
  pointer-events: none;
}
/* glass dome over the globe: a soft top-left glare, a thin bright rim, and a darker lens edge — sits above the map
   and the city markers but never blocks clicks */
.board-center::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; z-index: 5;
}
.map { position: absolute; left: 0; top: 0; width: 608px; height: 608px; overflow: visible; } /* the map fills the top half of the ocean */
.map .city { pointer-events: auto; cursor: pointer; }
/* city markers: lit-up squares sized by the rent they charge (--cs, in px), glowing in their owner's colour */
.map .city rect { transition: fill .2s, x .3s, y .3s, width .3s, height .3s; }
.map .city .dot { fill: var(--mc, #fff); stroke: rgba(30,37,64,.55); stroke-width: 1.2; x: calc(var(--cs, 9) * -.5px); y: calc(var(--cs, 9) * -.5px); width: calc(var(--cs, 9) * 1px); height: calc(var(--cs, 9) * 1px); rx: 2px; }
.map .city .glow { fill: var(--mc, #fff); opacity: .9; filter: blur(5px); x: calc(var(--cs, 9) * -1px); y: calc(var(--cs, 9) * -1px); width: calc(var(--cs, 9) * 2px); height: calc(var(--cs, 9) * 2px); }
.map .city { filter: drop-shadow(0 0 4px var(--mc, #fff)) drop-shadow(0 0 10px var(--mc, #fff)) brightness(1.15); } /* lit up like city lights */
.map .city.owned .glow { opacity: 1; }
.map .city .dot { animation: cityLight 3.2s ease-in-out infinite; }
@keyframes cityLight { 50% { filter: brightness(1.35); } }
.map .city:hover .dot { stroke-width: 2.4; }
.map .city.pop { animation: cityPop .5s var(--ease-out); transform-box: fill-box; transform-origin: center; }
.scene { position: absolute; overflow: visible; }
.scene .isle { fill: var(--grass); }
.scene .isle-side { fill: var(--grass-deep); }
.scene .u { pointer-events: auto; }
.scene .oc { fill: var(--oc, #e3e8f0); stroke: var(--ink); stroke-width: 2px; stroke-linejoin: round; transition: fill .3s; }
.scene .ink { fill: none; stroke: var(--ink); stroke-width: 2.5px; stroke-linecap: round; }
.scene .ink-f { fill: var(--ink); }
.scene .pipe { fill: none; stroke: var(--ink); stroke-width: 5px; stroke-linecap: round; stroke-linejoin: round; }
.scene .wire { fill: none; stroke: var(--ink); stroke-width: 1.3px; }
.scene .sig { fill: none; stroke: var(--ink); stroke-width: 2px; stroke-linecap: round; }
.scene .bldg { fill: #fff; stroke: var(--ink); stroke-width: 2px; }
.scene .glass { stroke: var(--ink); stroke-width: 1.5px; }
.scene .flame { fill: var(--orange); stroke: var(--ink); stroke-width: 1.5px; }
.scene .road, .scene .runway { fill: var(--road); }
.scene .dash { fill: none; stroke: #fff; stroke-width: 1.5px; stroke-dasharray: 5 4; }
.scene .track { fill: none; stroke: var(--ink); stroke-width: 3px; stroke-dasharray: 2 3; }
.scene .pier { fill: #a86b3c; stroke: var(--ink); stroke-width: 1.5px; }
.deck {
  position: absolute; left: 60px; top: 318px; width: 76px; height: 92px; border-radius: 8px;
  display: grid; place-content: center; text-align: center; transform: rotate(-8deg);
  background: var(--fortune);
}
.deck small { font-weight: 800; }

/* pizza-slice tiles: an SVG wedge paints the face (and a darker inner rim), content is clipped to it,
   and a rectangular tag sits on the outer tip */
.tiles { position: absolute; inset: 0; transform: rotate(var(--rot)); transition: transform var(--turn); }
.range { position: absolute; inset: 0; width: 1000px; height: 1000px; pointer-events: none; overflow: visible; }
.range .rn rect { fill: #fff; stroke: var(--ink); stroke-width: 1.4px; }
.range .rn circle { fill: var(--ink); }
.range .rn.bad rect { fill: var(--red); animation: none; }
.range .rn.bad circle { fill: #fff; }
/* (opacity only: a CSS transform would override the marker's own transform attribute and pull it to the corner) */
.range .rn { animation: fadeIn .3s var(--ease-out) backwards; }
@keyframes fadeIn { from { opacity: 0; } }
.tile { position: absolute; cursor: pointer; --face: var(--block); --txt: var(--ink); }
.wedge { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
.w-side { fill: color-mix(in srgb, var(--face) 65%, var(--ink)); }
.w-face { fill: var(--face); stroke: transparent; stroke-width: 0; paint-order: stroke fill; transition: stroke .15s, filter .15s; }
.tile:hover .w-face { filter: brightness(1.06); }
.tile-inner {
  position: absolute; inset: var(--tag, 0px) 0 6px; color: var(--txt);
  display: flex; flex-direction: column; text-align: center;
}
.tile.flip .tile-inner { transform: rotate(180deg); }

.t-body { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; }
.flip .t-body { padding: 6px 5px 8px; }
.k-std .t-body { padding-top: 7px; }
.flip.k-std .t-body { padding-top: 6px; padding-bottom: 7px; }
.t-name { font: 700 8.5px/1.1 var(--font); text-transform: uppercase; letter-spacing: .01em; text-wrap: balance; max-width: 100%; }
.t-price { font: 700 10px/1 var(--font); opacity: .9; }
/* price, icon, name evenly spaced along the slice: the icon sits midway between the price and the name */
.t-body { justify-content: space-evenly !important; padding: 8px 5px 10px !important; gap: 0 !important; }
.t-icon { flex: none !important; }
.k-set .t-name, .k-special .t-name, .k-std .t-name { line-height: 1.15; }
.t-icon { line-height: 0; flex: 1; display: grid; place-items: center; }
.t-icon .ic { width: 30px; height: 30px; }
.t-q { font: 500 34px/1 var(--font); color: var(--fortune); -webkit-text-stroke: 5px var(--ink); paint-order: stroke fill; }
.t-big { font: 800 16px/1 var(--font); letter-spacing: .01em; }

/* landmarks (the four old corners): solid colored wedges */
.k-corner .tile-inner { justify-content: center; align-items: center; }
.t-go { --face: var(--red); --txt: #fff; }
.t-chance.k-corner { --face: var(--fortune); --txt: #fff; }
.t-jail { --face: #b8bec9; --txt: var(--ink); }
.t-deal { --face: var(--purple); --txt: #fff; }
.corner-go { display: grid; justify-items: center; gap: 2px; }
.corner-go .t-big { font-size: 24px; -webkit-text-stroke: 7px var(--ink); paint-order: stroke fill; text-shadow: 0 4px 0 var(--ink); }
.go-arrow { line-height: 0; }
.go-arrow .ic { width: 22px; height: 22px; transform: rotate(180deg); }
.corner-go small { font-weight: 700; font-size: 9px; line-height: 1.15; text-align: center; }
.corner-chance { display: grid; justify-items: center; gap: 8px; }
.card-stack { width: 34px; height: 46px; border-radius: var(--r-sm); background: #fff; display: grid; place-items: center; box-shadow: 4px 4px 0 var(--fortune-side), 0 0 0 3px var(--ink); transform: rotate(-8deg); }
.card-stack b { font: 800 24px var(--font); color: var(--fortune); -webkit-text-stroke: 4px var(--ink); paint-order: stroke fill; }
.corner-chance .t-big { font-size: 13px; }
.corner-deal { display: grid; justify-items: center; gap: 6px; }
.corner-deal .t-icon .ic { width: 40px; height: 40px; color: #fff; filter: drop-shadow(0 2px 0 var(--ink)); }
.corner-deal .t-big { font-size: 15px; -webkit-text-stroke: 4px var(--ink); paint-order: stroke fill; }
/* jail: Visiting by the inner edge, the barred cell mid-slice (drawn in the tokens layer), the brown JAIL sign by the outer edge */
.t-jail .tile-inner { justify-content: stretch; align-items: stretch; }
.corner-jail { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 9px 0 12px; }
.corner-jail .t-big { font-size: 15px; background: #8a5a35; color: #fff; padding: 3px 8px; border-radius: 4px; box-shadow: 0 3px 0 #5e3b20; }
.corner-jail .visit { font: 700 8px/1.1 var(--font); color: var(--muted); }
.jail-cell { position: absolute; left: 0; top: 0; width: 54px; height: 68px; border-radius: 6px; background: #2c303c; box-shadow: inset 0 0 0 3px #1f222b; transform-origin: 50% 50%; }
.jail-bars {
  position: absolute; left: 0; top: 0; width: 54px; height: 68px; border-radius: 6px; z-index: 3;
  background: repeating-linear-gradient(90deg, var(--ink) 0 5px, transparent 5px 13px);
  box-shadow: inset 0 0 0 3px var(--ink), 0 3px 0 rgba(0,0,0,.25);
  transform-origin: 50% 50%;
}
.zoom-toggle {
  position: absolute; top: 10px; right: 10px; z-index: 5;
  display: flex; align-items: center; border: 0;
  background: var(--block); box-shadow: 0 3px 0 var(--bg-side), 0 0 0 2px var(--ink); color: var(--ink); cursor: pointer;
}

/* the tag: a white block on the tip that takes the owner's colour, token and buildings */
.w-tag { fill: var(--owner, #fff); transition: fill .2s; }
/* owned rent tags glow: pushed to fluorescent saturation with a halo in the owner's colour */
/* round board: the rent wedge only shows once owned, in the owner's exact colour with white text */
.board.radial .tile:not(.owned) .rent-low, .board.radial .tile:not(.owned) .rent-high, .board.radial .tile:not(.owned) .tag-in.outer { visibility: hidden; }
.board.radial .tile.owned .w-tag.outer, .board.radial .tile.owned .w-bld { filter: drop-shadow(0 0 5px var(--owner)); }
.board.radial .tile.owned .tag-rent { color: #fff; font-weight: 800; text-shadow: 0 0 2px var(--ink), 0 1px 1px var(--ink), 0 0 1px var(--ink); }
.w-tag-side { fill: color-mix(in srgb, var(--owner, #fff) 62%, var(--ink)); transition: fill .2s; }
.w-hi { fill: none; stroke: rgba(255,255,255,.5); stroke-width: 3px; stroke-linecap: round; pointer-events: none; }
.tile:not(.owned) .w-tag-side.outer { fill: #a9b1c2; }
/* unsold: the rent wedge is greyed out; owned: the price wedge goes away */
.tile:not(.owned) .w-tag.outer { fill: #d6dbe5; }
.tile:not(.owned) .tag-rent { color: var(--muted); }
/* the rent wedge hugs the tile until something is built, then moves out to make room for the buildings */
.tile .rent-high, .tile .bld-zone, .tile .bld-in { display: none; }
.tile.built .rent-low { display: none; }
.tile.built .rent-high, .tile.built .bld-zone, .tile.built .bld-in { display: block; }
.tile .tag-in.outer { top: var(--b); }
.tile.built .tag-in.outer { top: 0; }
.w-bld { fill: color-mix(in srgb, var(--owner, #fff) 55%, #fff); }
.bld-in { position: absolute; left: 0; right: 0; z-index: 2; pointer-events: none; }
.tile.built .bld-in { display: flex; align-items: center; justify-content: center; } /* a lone hotel sits dead centre */
.tag-in { position: absolute; top: 0; left: 0; right: 0; z-index: 2; display: flex; align-items: center; justify-content: center; gap: 3px; transform: rotate(180deg); pointer-events: none; }
.tag-rent { font: 700 11px/1 var(--font); color: var(--ink); }
.bldgs { display: flex; gap: 2px; align-items: center; }
.bldgs:empty { display: none; }
.bldgs.pop .bld { animation: build .45s var(--ease-out) backwards; }
.bldgs.pop .bld:nth-child(2) { animation-delay: .06s; }
.bldgs.pop .bld:nth-child(3) { animation-delay: .12s; }
.bld { display: block; flex: none; }
.bld.house { border-radius: 2px; background: #fff; box-shadow: inset 0 3px 0 var(--red), 0 0 0 1.5px var(--ink); }
.bld.tower { border-radius: 2px; background: repeating-linear-gradient(180deg, #9fd8ff 0 3px, #e8f6ff 3px 5px); box-shadow: inset 0 3px 0 var(--yellow), 0 0 0 1.5px var(--ink); }

/* danger: a reachable tile whose rent would sink the current player */
.tile.danger .w-face { animation: none; stroke: var(--red); stroke-width: 10px; }
.tile.danger .t-body::after { content: 'DANGER'; font: 800 7.5px/1 var(--font); letter-spacing: .06em; color: #fff; background: var(--red); padding: 2px 5px; border-radius: 3px; margin-top: 2px; }

/* highlights ride on the wedge outline */
.tile.step .w-face { animation: step .3s ease-out; }
.tile.flash .w-face { animation: flash .9s ease-out; }
.board.picking .tile:not(.pickable) { opacity: .4; }
.board.picking .tile.pickable .w-face { animation: pickable 1.1s ease-in-out infinite; }

/* dice */
/* dice roll in the middle of the globe, clear of the city markers */
.dice-tray { position: absolute; left: 50%; top: calc(50% + 20px); z-index: 4; display: flex; gap: 10px; transform: translate(-50%, -50%); pointer-events: none; }
.die-wrap { position: relative; width: 46px; height: 46px; }
.die-wrap::before { content: ''; position: absolute; left: 4px; right: 4px; bottom: -14px; height: 10px; border-radius: 3px; background: rgba(30, 60, 20, .3); }
.die {
  position: absolute; inset: 0; border-radius: 9px; background: #fff;
  box-shadow: 0 7px 0 var(--block-side);
  display: grid; grid-template: repeat(3, 1fr) / repeat(3, 1fr); padding: 7px;
}
.die i { place-self: center; }
.die .pip { width: 8px; height: 8px; border-radius: 2px; background: var(--ink); }

/* pawns: voxel blocks standing on their tile */
.tokens { position: absolute; inset: 0; pointer-events: none; transform: rotate(var(--rot)); transition: transform var(--turn); }
.token { position: absolute; left: 0; top: 0; }
.token .up { position: absolute; left: 0; top: 0; transform: rotate(calc(-1 * var(--rot))); transition: transform var(--turn); }
/* flat chips centred on their spot */
.pawn {
  --chip: 26px;
  position: absolute; left: calc(var(--chip) / -2); top: calc(var(--chip) / -2); width: var(--chip); height: var(--chip); border-radius: 50%;
  background: var(--pc);
  display: grid; place-items: center; transition: width .2s, height .2s, left .2s, top .2s;
}
.pawn { filter: saturate(1.3) brightness(1.08); } /* bright chips */
.token.active .pawn { filter: saturate(1.4) brightness(1.12); }
.token { --chip: 26px; }
.token .pawn { --chip: inherit; }
.t-mark { position: absolute; left: -7px; bottom: calc(var(--chip) / 2 + 4px); width: 18px; height: 13px; opacity: 0; clip-path: polygon(0 0, 100% 0, 50% 100%); }
.t-mark::after { content: ''; position: absolute; inset: 2.5px 3px 4px; background: var(--pc); clip-path: polygon(0 0, 100% 0, 50% 100%); }
.t-mark { background: var(--ink); }
.token.active .t-mark { opacity: 1; animation: bob 1s ease-in-out infinite; }

/* ---------- modals ---------- */

#modal-root { position: fixed; inset: 0; pointer-events: none; z-index: var(--z-modal); }
.backdrop { position: absolute; inset: 0; display: grid; place-items: center; padding: 20px; background: rgba(20, 28, 55, .45); pointer-events: auto; }
.modal { width: min(400px, 100%); max-height: 100%; overflow: auto; background: var(--block); border-radius: var(--r-md); padding: 20px; box-shadow: 0 8px 0 var(--block-side), 0 30px 50px -20px rgba(10, 15, 35, .5); }
.modal-body.center { text-align: center; display: grid; justify-items: center; gap: 14px; }
.modal h2 { font: 500 30px/1.1 var(--font); margin: 0; text-wrap: balance; }
.modal-q { font-size: 15px; margin: 14px 0 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.deed { background: #fff; color: var(--ink); border-radius: var(--r-md); overflow: hidden; box-shadow: 0 0 0 3px #e6ebf3; }
.deed-head { background: var(--g, #59627e); color: #fff; padding: 12px 14px; box-shadow: inset 0 -5px 0 rgba(0,0,0,.15); }
.deed.util .deed-head, .deed.plain .deed-head { background: #59627e; }
.deed-head small { font-weight: 800; font-size: 11px; color: oklch(from var(--g, #59627e) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); }
.deed-head h2 { margin: 2px 0 0; font: 500 24px/1.1 var(--font); -webkit-text-stroke: 5px var(--ink); paint-order: stroke fill; display: flex; align-items: center; gap: 6px; }
.deed-head h2 .ic { -webkit-text-stroke: 0; width: 24px; height: 24px; }
.deed.transport .deed-head { background: var(--transport, #59627e); }
.deed table { width: 100%; border-collapse: collapse; font-size: 13px; }
.deed td { padding: 5px 14px; border-bottom: 2px solid #f0f3f8; }
.deed td:last-child { text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }
.deed tr.cur { background: color-mix(in srgb, var(--g, var(--yellow)) 25%, #fff); }
.deed tr.cur td:first-child::before { content: '▶ '; font-size: 10px; }
.deed-foot { display: flex; justify-content: space-between; padding: 8px 14px; font-size: 11px; font-weight: 800; color: var(--muted); }
.deed-owner { padding: 8px 14px; background: var(--pc); color: var(--ink); font-weight: 800; }
.deed.plain p { padding: 12px 14px; margin: 0; }
.ability { padding: 12px 14px; background: #fff6d6; border-bottom: 2px solid #f0f3f8; }
.ability b { font: 500 17px var(--font); }
.ability p { margin: 4px 0 0; font-size: 13px; }

.chance-card { width: 230px; height: 300px; perspective: 900px; }
.cc-inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; animation: flip .8s var(--ease-out) forwards; }
.chance-card.leave { animation: cardOut .25s ease-in forwards; }
.cc-back, .cc-front { position: absolute; inset: 0; border-radius: 12px; backface-visibility: hidden; display: grid; place-content: center; padding: 22px; }
.cc-back b { font: 500 120px/1 var(--font); -webkit-text-stroke: 14px var(--ink); paint-order: stroke fill; }
.cc-front { transform: rotateY(180deg); text-align: center; }
.cc-front small { text-transform: uppercase; font-weight: 800; }
.cc-front h2 { margin: 0; font: 500 28px/1.05 var(--font); }
.cc-front p { margin: 0; }

.trophy { color: var(--yellow); line-height: 0; animation: bump .8s var(--ease-out); }
.trophy .ic { width: 72px; height: 72px; filter: drop-shadow(0 4px 0 var(--yellow-side)); }
.standings { list-style: none; padding: 0; margin: 0; width: 100%; display: grid; gap: 6px; }
.standings li { display: flex; justify-content: space-between; padding: 8px 12px; background: #f3f6fb; border-radius: var(--r-sm); font-weight: 800; box-shadow: 0 3px 0 var(--block-side); }
.standings li:first-child { background: var(--yellow); box-shadow: 0 3px 0 var(--yellow-side); }
.standings li.out { opacity: .5; }

/* ---------- keyframes ---------- */
@keyframes flip { from { transform: rotateY(0) scale(.7); } 60% { transform: rotateY(200deg) scale(1.03); } to { transform: rotateY(180deg) scale(1); } }
@keyframes cardOut { to { transform: translateY(-40px) scale(.8); opacity: 0; } }
@keyframes toast { 0% { opacity: 0; transform: translate(-50%, -10px); } 10%, 85% { opacity: 1; transform: translate(-50%, 0); } 100% { opacity: 0; } }
@keyframes floatUp { from { opacity: 1; } to { opacity: 0; transform: translate(-50%, -50px); } }
@keyframes step { 0% { filter: brightness(1.25); } }
@keyframes flash { 0%, 40% { stroke: var(--yellow); stroke-width: 12px; filter: brightness(1.08); } }
@keyframes pickable { 50% { stroke: var(--water); stroke-width: 10px; } }
/* the nudge option under the finger: its tile holds the pulse's brightest point */
.board.picking .tile.pickable.hot .w-face { animation: none; stroke: var(--water); stroke-width: 10px; }
.board.picking .tile.sq.pickable.hot .face { animation: none; box-shadow: inset 0 0 0 4px var(--water), 0 0 0 3px var(--water); }
@keyframes build { from { transform: translateY(-14px) scale(.4); opacity: 0; } }
@keyframes bob { 50% { transform: translateY(-6px); } }
@keyframes gavel { 0%, 60%, 100% { transform: rotate(0); } 70% { transform: rotate(-35deg); } 80% { transform: rotate(8deg); } }
@keyframes bump { 0% { transform: scale(1.3); } }
@keyframes cityPop { 0% { transform: scale(2.2); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}

/* developer: a 9:16 phone frame, full screen height, centred on the 3440×1440 ultrawide — what a phone player sees,
   scaled up. The board is square on top; everything below it scrolls, with the turn controls pinned to the bottom. */
body.developer { --dev-scale: 1.15; background: var(--bg); }
body.developer #game { height: 100dvh; width: min(100vw, calc(100dvh * 9 / 16)); max-width: none; margin: 0 auto; overflow: hidden;
  box-shadow: 0 0 0 6px var(--sky-2), 0 40px 80px -30px rgba(20, 30, 60, .45); }
body.developer #stage-wrap { flex: none; width: 100%; height: auto; aspect-ratio: 1; }
body.developer #side { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
body.developer .side-head, body.developer #players, body.developer #dock, body.developer #actions, body.developer .modal { zoom: var(--dev-scale); }
body.developer #dock { flex: none; min-height: 260px; }
body.developer #actions { position: sticky; bottom: 0; z-index: 3; }
body.developer .zoom-toggle { zoom: 1.3; }
body.developer #setup { zoom: 1.6; display: grid; align-content: center; }
body.developer .toast, body.developer #ticker { zoom: 1.3; }

/* desktop: the board fills the left of the screen, the controls run down the right */
body.desktop #game { flex-direction: row; max-width: none; box-shadow: none; }
body.desktop #stage-wrap { flex: 1; height: 100%; }
body.desktop #side { flex: none; width: var(--side-w, 400px); box-shadow: -6px 0 0 var(--sky-2); }
body.desktop #side > *, body.wide .side-head, body.wide #players, body.wide #dock, body.wide #actions { zoom: var(--ui-scale, 1); }
body.desktop .modal, body.wide .modal, body.mobile .modal { zoom: var(--ui-scale, 1); }
body.desktop #setup .setup-inner, body.wide #setup .setup-inner { zoom: var(--ui-scale, 1); }
body.mobile #side > * { zoom: var(--ui-scale, 1); }
body.desktop .setup-inner { max-width: 1200px; }
.head-btns { display: flex; gap: 6px; }

@media (max-width: 640px) {
  #game { box-shadow: none; }
}

/* ---------- square board (Monopoly layout) ---------- */

/* the board is a rounded square with concentric bands of dark green, inset like rings */
.board.square .board-base { border-radius: 28px !important; background: #3a7a2b !important;
  box-shadow: inset 0 0 0 16px #3a7a2b, inset 0 0 0 32px #275d1c, inset 0 0 0 48px #2f6b22, inset 0 0 0 64px #3a7a2b, inset 0 0 0 80px #275d1c, inset 0 0 0 96px #2f6b22, inset 0 0 0 112px #3a7a2b, inset 0 0 0 128px #275d1c, inset 0 0 0 144px #2f6b22, inset 0 0 0 160px #3a7a2b, inset 0 0 0 176px #275d1c, inset 0 0 0 192px #2f6b22, inset 0 0 0 208px #3a7a2b, inset 0 0 0 224px #275d1c, inset 0 0 0 240px #2f6b22, inset 0 0 0 256px #3a7a2b, inset 0 0 0 272px #275d1c, inset 0 0 0 288px #2f6b22, inset 0 0 0 304px #3a7a2b, inset 0 0 0 320px #275d1c, inset 0 0 0 336px #2f6b22, 0 16px 0 var(--grass-deep-2), 0 30px 40px -10px rgba(30, 60, 20, .45) !important; }
.board.square .tiles, .board.square .tokens { transform: none !important; }
.board.square .token .up { transform: none !important; }

.tile.sq { position: absolute; display: flex; cursor: pointer; } /* face colours come from the shared .tile / .t-* rules */
.tile.sq.side-b { flex-direction: column; }
.tile.sq.side-t { flex-direction: column-reverse; }
.tile.sq.side-l { flex-direction: row-reverse; }
.tile.sq.side-r { flex-direction: row; }
.tile.sq .face { flex: none; position: relative; margin: 3px; border-radius: 6px; background: var(--face); color: var(--txt);
  box-shadow: inset 0 3px 0 rgba(255,255,255,.35), inset 0 -4px 0 color-mix(in srgb, var(--face) 70%, var(--ink)), 0 2px 0 rgba(0,0,0,.18);
  transition: filter .15s, box-shadow .15s; }
.tile.sq.side-b .face, .tile.sq.side-t .face { height: calc(var(--face-depth) - 6px); }
.tile.sq.side-l .face, .tile.sq.side-r .face { width: calc(var(--face-depth) - 6px); }
.tile.sq.k-corner .face { flex: 1; }
.tile.sq:hover .face { filter: brightness(1.06); }
.tile.sq .tile-face { position: absolute; inset: 0; display: flex; flex-direction: column; text-align: center; overflow: hidden; }
.tile.sq .t-body { padding: 6px 4px 7px !important; }
.tile.sq.side-l .t-body, .tile.sq.side-r .t-body { padding: 4px 6px !important; }
.tile.sq .t-icon .ic { width: 26px; height: 26px; }
.tile.sq.k-corner .tile-face { align-items: center; justify-content: center; }

/* rent strip on the outer end; the build strip between face and rent opens only once something is built */
.tile.sq .rent, .tile.sq .bldz { flex: none; margin: 3px; border-radius: 5px; display: flex; align-items: center; justify-content: center; }
.tile.sq.side-b .rent, .tile.sq.side-t .rent { height: 20px; }
.tile.sq.side-b .bldz, .tile.sq.side-t .bldz { height: 20px; }
.tile.sq.side-l .rent, .tile.sq.side-r .rent, .tile.sq.side-l .bldz, .tile.sq.side-r .bldz { width: 20px; }
.tile.sq .rent { order: 2; visibility: hidden; } /* the rent strip only appears once someone owns the tile */
.tile.sq .bldz { order: 3; visibility: hidden; background: color-mix(in srgb, var(--owner, #fff) 55%, #fff); }
.tile.sq.built .bldz { order: 1; visibility: visible; }
.tile.sq.side-l .tag-rent, .tile.sq.side-r .tag-rent { writing-mode: vertical-rl; transform: rotate(180deg); }
.tile.sq.side-l .bldgs, .tile.sq.side-r .bldgs { flex-direction: column; }
.tile.sq .tag-rent { font: 800 10px/1 var(--font); color: #fff; text-shadow: 0 0 2px var(--ink), 0 1px 1px var(--ink), 0 0 1px var(--ink); }
.tile.sq.owned .rent { visibility: visible; background: var(--owner); box-shadow: inset 0 2px 0 rgba(255,255,255,.35), inset 0 -3px 0 rgba(30,37,64,.25), 0 0 8px var(--owner); }
.tile.sq.owned.built .bldz { filter: saturate(1.6) drop-shadow(0 0 3px var(--owner)); }

/* highlights on the face */
.tile.sq.here .face { box-shadow: inset 0 0 0 4px var(--yellow), 0 0 0 2px var(--yellow); }
.tile.sq.step .face { animation: sqStep .3s ease-out; }
.tile.sq.flash .face { animation: sqFlash .9s ease-out; }
.board.picking .tile.sq:not(.pickable) { opacity: .4; }
.board.picking .tile.sq.pickable .face { animation: sqPick 1.1s ease-in-out infinite; }
.tile.sq.danger .face { animation: none; box-shadow: inset 0 0 0 4px var(--red), 0 0 0 3px var(--red); }
@keyframes sqStep { 0% { filter: brightness(1.25); } }
@keyframes sqFlash { 0%, 40% { box-shadow: inset 0 0 0 5px var(--yellow), 0 0 0 3px var(--yellow); filter: brightness(1.08); } }
@keyframes sqPick { 50% { box-shadow: inset 0 0 0 4px var(--water), 0 0 0 3px var(--water); } }

/* the jail corner: Visiting at the top, the cell in the middle (drawn with the pawns), the sign at the bottom */
.tile.sq.t-jail .corner-jail { padding: 10px 0 12px; }

/* the globe: a pixel map under a sphere's shading, with the service district casting a shadow onto it */
.scene { z-index: 2; }
.map .city { z-index: 3; }

/* ---------- night theme ---------- */
body.night {
  --bg: #0f1428; --bg-side: #070a17;
  --sky: #171f3b; --sky-2: #0d1430;
  --block: #26304f; --block-side: #151c36;
  --grass: #5fae46; --grass-2: #569f3f; --grass-deep: #2f6d22; --grass-deep-2: #1f4a17;
  --water: #1f6fa6;
  color-scheme: dark;
}
body.night { color: var(--night-fg); }
body.night .tile { --txt: var(--night-fg); }
body.night .t-go, body.night .t-deal, body.night .t-chance.k-corner { --txt: #fff; }
body.night .pcard.active { background: #26304f; }
body.night .turn-head b, body.night .modal h2, body.night .deed { color: var(--night-fg); }
body.night .slot { background: #1d2643; }
body.night .cash-pick { background: #1d2643; color: var(--night-fg); }
body.night .badge { background: #2b3558; color: var(--night-fg); }
body.night .board-base { filter: brightness(.78) saturate(.9); }
body.night .t-jail { --face: #59627e; --txt: var(--night-fg); }
body.night .corner-jail .visit { color: #c8d0ea; }
body.night { --util-face: #34406a; --util-txt: var(--night-fg); }
body.night .t-tax, body.night .t-gotojail, body.night .t-chance:not(.k-corner) { --face: #2b3558; --txt: var(--night-fg); }
body.night .slot-name, body.night .tk, body.night .chip, body.night .tab, body.night .asset, body.night .standings li { background: #1d2643; color: var(--night-fg); }
body.night .cash-in input { background: #1d2643; color: var(--night-fg); }
body.night .chip.on, body.night .tab.on { background: var(--yellow); color: var(--ink); }
body.night .modal, body.night .deed { background: #1d2643; color: var(--night-fg); }
body.night .ability { background: #2b3352; }
body.night .scene .bldg { fill: #c8d0ea; }
body.night .scene .win { fill: #ffd84a; filter: drop-shadow(0 0 3px #ffd84a); }
body.night .map .city rect { stroke: #0f1428; }

/* ---------- buy / sell / build buttons: solid colours so they read at a glance ---------- */
.btn[data-act="buy"] { --face: var(--green); --side: var(--green-side); color: var(--ink); font-size: 15px; padding: 11px 16px; }
.btn[data-act="upgrade"] { --face: var(--green); --side: var(--green-side); color: var(--ink); }
.btn[data-act="sell"], .btn[data-act="sell-prop"] { --side: #c8492b; color: oklch(from var(--pc, #ff7a59) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); }
.asset-btns .btn { padding: 7px 11px; font-size: 13px; font-weight: 800; }
.asset-btns .btn:disabled, .row .btn[data-act="upgrade"]:disabled, .row .btn[data-act="sell"]:disabled, .row .btn[data-act="sell-prop"]:disabled { opacity: .38; filter: grayscale(.6); }

/* ---------- night: a mid-to-late sunset sky instead of the green board surround ---------- */
body.night {
  background:
    radial-gradient(1px 1px at 12% 8%, #fff 99%, transparent), radial-gradient(1px 1px at 28% 14%, #fff 99%, transparent),
    radial-gradient(1.5px 1.5px at 46% 6%, #fff 99%, transparent), radial-gradient(1px 1px at 63% 11%, #fff 99%, transparent),
    radial-gradient(1px 1px at 79% 4%, #fff 99%, transparent), radial-gradient(1.5px 1.5px at 91% 15%, #fff 99%, transparent),
    radial-gradient(1px 1px at 7% 22%, rgba(255,255,255,.7) 99%, transparent), radial-gradient(1px 1px at 55% 20%, rgba(255,255,255,.7) 99%, transparent),
    linear-gradient(180deg, #141a3d 0%, #2b2160 26%, #5a2b78 46%, #a03c7a 62%, #e0615f 78%, #f49a52 90%, #f8c070 100%) fixed;
}
body.night .board .board-base, body.night .board.square .board-base {
  filter: none; border-radius: inherit;
  background:
    #3a2370 !important;
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.12), inset 0 0 60px rgba(10, 6, 30, .55), 0 16px 0 #0d0a24, 0 30px 50px -10px rgba(0, 0, 0, .6) !important;
}
body.night #stage-wrap { background: transparent; }
body.night .range .rn rect { stroke: #fff; }
body.night #game { background: transparent; box-shadow: none; } /* let the sunset sky show behind the board */
/* sell buttons wear the current player's colour (set on the dock as --pc) */
.btn[data-act="sell"], .btn[data-act="sell-prop"] { --face: var(--pc, #ff7a59); --side: color-mix(in srgb, var(--pc, #ff7a59) 60%, var(--ink)); color: oklch(from var(--pc, #ff7a59) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); }

/* ownership spreading over the land: a soft blob of the owner's colour around each city they hold, sized by their share
   of the board; on a win, the winner's colour washes over the whole globe */
.map .victory { opacity: 0; transition: opacity 1.4s ease; pointer-events: none; }
.map .victory.on { opacity: .45; }
/* the tile layer spans the whole board; let clicks through to the globe's city markers except on the tiles themselves */
.tiles { pointer-events: none; }
.tiles .tile { pointer-events: auto; }
/* biomes over the temperate green: soft-edged so neighbouring regions blend */
body.night .board.square .board-base { border-radius: 28px !important; }
body.night .board.radial .board-base { border-radius: 50% !important; }

/* ---------- night UI: glass panels over the sunset, sunset-gradient actions, player-colour glows ---------- */
body.night { --night-fg: #fff4ea; --muted: #cdbbdd; --glass: rgba(26, 18, 58, .94); --glass-2: rgba(255, 255, 255, .06);
  --glass-line: rgba(255, 255, 255, .12); --sunset: linear-gradient(135deg, #f8b26a 0%, #f0775f 55%, #d94f7a 100%); --sunset-side: #9c2f5a; }

body.night #side { background: rgba(16, 20, 46, .96); box-shadow: inset 1px 0 0 var(--glass-line), -20px 0 60px -30px rgba(240, 120, 95, .35); }
body.developer.night #side { background: transparent; box-shadow: none; }
body.night .side-head .logo-sm { filter: drop-shadow(0 0 12px rgba(248, 178, 106, .35)); }

body.night .btn.ghost { --face: var(--glass-2); --side: rgba(0, 0, 0, .35); color: var(--night-fg); box-shadow: inset 0 0 0 1px var(--glass-line), 0 3px 0 var(--side); }
body.night .btn.ghost:hover:not(:disabled) { --face: rgba(255, 255, 255, .12); }

/* the big actions wear the sunset */

/* player cards: glass, the active one glows in its player's colour */
body.night .pcard { background: var(--glass-2); box-shadow: inset 0 0 0 1px var(--glass-line); border-radius: var(--r-md); }
body.night .pcard.active { background: color-mix(in srgb, var(--pc) 14%, rgba(255, 255, 255, .05));
  box-shadow: inset 0 0 0 2px var(--pc); transform: translateY(-2px); }
body.night .pcash small { color: var(--muted); }

/* dock and tabs */
body.night #dock { background: var(--glass-2); box-shadow: inset 0 0 0 1px var(--glass-line); border-radius: var(--r-md); }
body.night .tab { background: transparent; color: var(--muted); box-shadow: inset 0 0 0 1px var(--glass-line); }
body.night .asset { background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--glass-line); border-radius: var(--r-md); }
body.night .asset-name small, body.night .hint { color: var(--muted); }

/* turn bar */
body.night .actions { background: linear-gradient(180deg, rgba(26, 18, 58, .2), rgba(26, 18, 58, .75)); box-shadow: inset 0 1px 0 var(--glass-line); }
body.night .turn-head b { color: var(--night-fg); }
body.night .countdown { color: #f8b26a; text-shadow: 0 0 10px rgba(248, 178, 106, .5); }
body.night .countdown.low { color: #ff6b6b; }
body.night .warn { color: #ff9a8b; }

/* pop-ups, ticker and toasts float as glass over the sky */
body.night .backdrop { background: rgba(14, 8, 36, .5); }
body.night .modal { background: rgba(30, 20, 66, .97); box-shadow: inset 0 0 0 1px var(--glass-line), 0 30px 80px -20px rgba(0, 0, 0, .7); }
body.night .deed { background: rgba(255, 255, 255, .04); box-shadow: inset 0 0 0 1px var(--glass-line); }
body.night .deed td { border-color: rgba(255, 255, 255, .07); }
body.night #ticker span { background: rgba(20, 12, 46, .94); box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 20px -6px rgba(0, 0, 0, .6); color: var(--night-fg); }
body.night .toast { box-shadow: 0 4px 0 var(--red-side), 0 0 30px -6px var(--red); }

/* setup screen */
body.night .slot, body.night .cash-pick { background: var(--glass); box-shadow: inset 0 0 0 1px var(--glass-line); }
body.night .slot.add { background: rgba(255, 255, 255, .04); }
body.night .slot-name, body.night .tk { background: rgba(255, 255, 255, .06); box-shadow: inset 0 0 0 1px var(--glass-line); color: var(--night-fg); }
body.night .tk .ic { color: var(--night-fg); }
body.night .tk.on { background: color-mix(in srgb, var(--pc) 35%, rgba(255,255,255,.06)); box-shadow: inset 0 0 0 2px var(--pc); }
/* the night half of the globe: a soft-edged shadow; city lights stay bright on top of it */
.map .night-side { pointer-events: none; }


/* ---------- icons lit like the globe: soft halos, a touch of depth, owner-coloured glows in the service district ---------- */
/* buyable tiles: the icon sits dim and unlit until someone owns the tile, then lights up in the owner's colour */
.tile .t-icon .ic { filter: drop-shadow(0 1px 0 rgba(0,0,0,.25)); }
.tile.t-property:not(.owned) .t-icon .ic, .tile.t-transport:not(.owned) .t-icon .ic, .tile.t-utility:not(.owned) .t-icon .ic { opacity: .55; filter: grayscale(.4); }
.tile.owned .t-icon .ic { opacity: 1; color: #fff; filter: drop-shadow(0 0 2px #fff) drop-shadow(0 0 6px var(--owner)) drop-shadow(0 0 14px var(--owner)); animation: iconLit .6s ease-out; }
@keyframes iconLit { from { filter: drop-shadow(0 0 0 #fff); transform: scale(.85); } }
.corner-go .go-arrow .ic, .corner-deal .t-icon .ic, .card-stack { filter: drop-shadow(0 2px 0 rgba(0,0,0,.3)) drop-shadow(0 0 8px rgba(255,255,255,.45)); }
.t-q { filter: drop-shadow(0 0 6px rgba(255, 204, 41, .6)); }

/* the service district: shaded like the globe, owned landmarks glow in their owner's colour, windows lit warm */
.scene { filter: drop-shadow(0 8px 6px rgba(5, 30, 60, .45)) drop-shadow(0 0 1px rgba(255,255,255,.4)); }
.scene .u .oc { transition: fill .3s, filter .3s; }
.scene .u:not(.owned) { opacity: .75; }
.scene .u.owned .oc { filter: drop-shadow(0 0 4px var(--oc)) drop-shadow(0 0 9px var(--oc)); }
.scene .win { fill: #ffd84a; filter: drop-shadow(0 0 2px #ffd84a); }
.scene .glass { fill: #bfe9ff; filter: drop-shadow(0 0 2px rgba(191, 233, 255, .8)); }
.scene .flame { filter: drop-shadow(0 0 4px #ff9f1c); }
.scene .isle { fill: color-mix(in srgb, var(--grass) 85%, #fff); }
body.night .scene .bldg, body.night .scene .oc { stroke: #0f1428; }

/* owned utilities glow fluorescent in the owner's colour: a neon edge on the tile, a bright "% cut" tag, and the
   landmark on the globe lit up to match */
.tile.t-utility.owned .face, .tile.t-utility.owned .w-face { filter: drop-shadow(0 0 4px var(--owner)) drop-shadow(0 0 10px var(--owner)); }
.tile.sq.t-utility.owned .face { box-shadow: inset 0 0 0 3px var(--owner), inset 0 3px 0 rgba(255,255,255,.35), 0 0 14px var(--owner); }
.tile.t-utility.owned .rent, .board.radial .tile.t-utility.owned .w-tag.outer { filter: saturate(1.8) brightness(1.15) drop-shadow(0 0 6px var(--owner)) drop-shadow(0 0 14px var(--owner)); }
.scene .u.owned[data-key="water"] .oc, .scene .u.owned[data-key="power"] .oc, .scene .u.owned[data-key="telecom"] .oc, .scene .u.owned[data-key="gas"] .oc {
  filter: saturate(1.8) brightness(1.2) drop-shadow(0 0 4px var(--oc)) drop-shadow(0 0 12px var(--oc)); }
.scene .u.owned[data-key="power"] .wire, .scene .u.owned[data-key="telecom"] .sig { stroke: var(--oc); filter: drop-shadow(0 0 3px var(--oc)); }
/* …and the same for transports: taxi, ferry, railway, airport */
.tile.t-transport.owned .face, .tile.t-transport.owned .w-face { filter: drop-shadow(0 0 4px var(--owner)) drop-shadow(0 0 10px var(--owner)); }
.tile.sq.t-transport.owned .face { box-shadow: inset 0 0 0 3px var(--owner), inset 0 3px 0 rgba(255,255,255,.35), 0 0 14px var(--owner); }
.tile.t-transport.owned .rent, .board.radial .tile.t-transport.owned .w-tag.outer { filter: saturate(1.8) brightness(1.15) drop-shadow(0 0 6px var(--owner)) drop-shadow(0 0 14px var(--owner)); }
.scene .u.owned[data-key="taxi"] .oc, .scene .u.owned[data-key="ferry"] .oc, .scene .u.owned[data-key="rail"] .oc, .scene .u.owned[data-key="air"] .oc {
  filter: saturate(1.8) brightness(1.2) drop-shadow(0 0 4px var(--oc)) drop-shadow(0 0 12px var(--oc)); }
.scene .u.owned[data-key="air"] .dash, .scene .u.owned[data-key="rail"] .track { stroke: var(--oc); filter: drop-shadow(0 0 3px var(--oc)); }

/* ---------- globe refinement ---------- */ /* shallow water round the coasts */
.map .night-side { filter: blur(22px); }
/* atmosphere: a thin sky-blue haze on the rim, brighter on the day side */
.board-center { box-shadow: inset 0 0 0 6px #2fa9d8, inset 0 0 28px 4px rgba(150, 220, 255, .45), 0 0 26px 4px rgba(120, 200, 255, .35), 0 10px 24px -6px rgba(10, 40, 80, .45); }

/* ---------- player chips: see "the pawn" at the end of this file (one look everywhere: board, cards, HUD, lobby) ---------- */

/* ultrawide: three columns — header and players left, the board centre at full height, dock and turn controls right */
body.wide #game { display: grid; height: 100dvh; max-width: none; box-shadow: none; overflow: hidden;
  grid-template-columns: var(--col-w, 420px) minmax(0, 1fr) var(--col-w, 420px); grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: 'head stage dock' 'players stage dock' 'players stage actions'; }
body.wide #side { display: contents; }
body.wide #stage-wrap { grid-area: stage; height: 100%; }
body.wide .side-head { grid-area: head; padding: 18px 20px 8px; }
body.wide #players { grid-area: players; padding: 6px 20px 20px; align-content: start; overflow: auto; min-height: 0; }
body.wide #dock { grid-area: dock; margin: 18px 20px 12px; min-height: 0; }
body.wide #actions { grid-area: actions; }
body.wide .side-head, body.wide #players { background: var(--sky); }
body.night.wide .side-head, body.night.wide #players { background: var(--glass); }
body.wide .setup-inner { max-width: 1400px; }
/* short landscape screens (phones on their side): trim chrome so the controls fit */
@media (max-height: 500px) and (orientation: landscape) {
  .side-head .logo-sm { display: none; }
  .pcard { padding: 4px 8px; }
  #dock { min-height: 0; }
}
/* header buttons wrap instead of running off narrow screens */
.side-head { flex-wrap: wrap; gap: 6px; }
.head-btns { flex-wrap: wrap; justify-content: flex-end; }
body.mobile .head-btns .btn { padding: 4px 8px; font-size: 11px; }
/* portrait: the turn controls stay pinned to the bottom while the panels above scroll */
body.mobile #actions { position: sticky; bottom: 0; z-index: 3; }

/* ---------- day: a bright sky instead of the green table, frosted-glass panels, sunny actions ---------- */
body:not(.night) {
  --glass: rgba(255, 255, 255, .92); --glass-2: rgba(255, 255, 255, .45); --glass-line: rgba(255, 255, 255, .8);
  --sun: linear-gradient(135deg, #ffe07a 0%, #ffb257 60%, #ff8f5a 100%); --sun-side: #d9772f;
  background:
    radial-gradient(circle at 82% 12%, rgba(255, 244, 200, .95) 0 3%, rgba(255, 230, 150, .45) 9%, transparent 26%),
    linear-gradient(180deg, #3f9ee8 0%, #6cbcf3 30%, #a6d8f8 62%, #d9eefb 82%, #ffe6c4 100%) fixed;
}
body:not(.night) #game, body:not(.night) #stage-wrap { background: transparent; box-shadow: none; }
body:not(.night) .board .board-base, body:not(.night) .board.square .board-base {
  background:
    #5fb3ef !important;
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.6), inset 0 0 60px rgba(40, 110, 180, .25), 0 16px 0 #2f7fc0, 0 30px 50px -12px rgba(30, 80, 140, .45) !important;
}
body:not(.night) .board.square .board-base { border-radius: 28px !important; }
body:not(.night) .board.radial .board-base { border-radius: 50% !important; }
body:not(.night) .board-center { box-shadow: inset 0 0 0 6px #2fa9d8, inset 0 0 28px 4px rgba(170, 230, 255, .5), 0 0 30px 6px rgba(255, 255, 255, .55), 0 10px 24px -6px rgba(20, 70, 130, .4); }

body:not(.night) #side { background: var(--glass); box-shadow: inset 1px 0 0 var(--glass-line), -20px 0 60px -30px rgba(30, 90, 160, .35); }
body:not(.night) .pcard { background: var(--glass-2); box-shadow: inset 0 0 0 1px var(--glass-line), 0 4px 12px -6px rgba(30, 80, 140, .3); border-radius: var(--r-md); }
body:not(.night) .pcard.active { background: color-mix(in srgb, var(--pc) 16%, rgba(255,255,255,.75)); box-shadow: inset 0 0 0 2px var(--pc); }
body:not(.night) #dock { background: var(--glass-2); box-shadow: inset 0 0 0 1px var(--glass-line); border-radius: var(--r-md); }
body:not(.night) .actions { background: linear-gradient(180deg, rgba(255,255,255,.35), rgba(255,255,255,.8)); box-shadow: inset 0 1px 0 var(--glass-line); }
body:not(.night) .asset { background: rgba(255,255,255,.6); box-shadow: inset 0 0 0 1px var(--glass-line); border-radius: var(--r-md); }
body:not(.night) .tab, body:not(.night) .chip { background: rgba(255,255,255,.55); box-shadow: inset 0 0 0 1px var(--glass-line); }
body:not(.night) .btn.ghost { --face: rgba(255,255,255,.55); --side: rgba(30, 80, 140, .2); }
body:not(.night) .slot, body:not(.night) .cash-pick { background: var(--glass); box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 20px -10px rgba(30, 80, 140, .35); }
body:not(.night) .slot.add { border-color: rgba(255,255,255,.85); }
body:not(.night) .modal { background: rgba(255, 255, 255, .97); box-shadow: inset 0 0 0 1px var(--glass-line), 0 30px 80px -20px rgba(20, 60, 110, .5); }
body:not(.night) .backdrop { background: rgba(30, 80, 140, .25); }
body:not(.night) #ticker span { background: rgba(255,255,255,.85); color: var(--ink); box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 20px -8px rgba(20, 60, 110, .45); }
body:not(.night) .wide .side-head, body:not(.night).wide .side-head, body:not(.night).wide #players { background: var(--glass); }

/* ---------- plastic globe: saturated toy colours, a hard glossy highlight, rim light and a moulded edge ---------- */
.board-center::after {
  background:
    radial-gradient(ellipse 13% 8% at 31% 18%, rgba(255,255,255,1) 0 40%, rgba(255,255,255,0) 100%),                         /* hard specular */
    radial-gradient(ellipse 30% 18% at 33% 21%, rgba(255,255,255,.55) 0%, rgba(255,255,255,.25) 45%, rgba(255,255,255,0) 75%),
    radial-gradient(ellipse 52% 36% at 36% 26%, rgba(255,255,255,.28), transparent 70%),                                         /* soft sheen */
    radial-gradient(ellipse 30% 10% at 64% 88%, rgba(255,255,255,.35), transparent 75%),                                         /* bounce light */
    radial-gradient(circle at 46% 42%, transparent 56%, rgba(4, 28, 70, .22) 80%, rgba(4, 28, 70, .5) 99%) !important;          /* curved shading */
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.7), inset 0 0 0 5px rgba(255,255,255,.12), inset 0 -22px 34px -12px rgba(4, 28, 70, .45),
    inset 0 18px 26px -14px rgba(255, 255, 255, .55) !important;
}
/* zoomed in, the board can be swiped around: grab cursor, no page scroll under the finger, instant follow while dragging */
body:has(.zoom-toggle.on) #stage { cursor: grab; touch-action: none; }
#stage.panning { cursor: grabbing; }
#stage.panning .board { transition: none !important; }
/* dice docked in the corner of the stage while zoomed in */
.dice-tray.docked { position: absolute; left: 18px; bottom: 18px; top: auto; transform: none; z-index: 6; zoom: var(--ui-scale, 1);
  padding: 10px; border-radius: var(--r-md); background: var(--glass, rgba(255,255,255,.5));
  box-shadow: inset 0 0 0 1px var(--glass-line, rgba(255,255,255,.7)), 0 10px 30px -10px rgba(0,0,0,.45); }
/* a jailed player's turn arrow stays inside the cell, behind the bars: smaller, closer to the chip, no bob */
.token.jailed .t-mark { bottom: calc(var(--chip, 26px) / 2 + 1px); width: 10px; height: 7px; left: -5px; animation: none; }
/* auto-roll switch in the turn bar, styled like the zoom switch */
.autoroll { margin-left: auto; display: flex; align-items: center; gap: 6px; padding: 4px 9px 4px 4px; border: 0; border-radius: 99px; cursor: pointer;
  background: var(--glass, var(--block)); color: inherit; font: 700 11px var(--font); box-shadow: inset 0 0 0 1px var(--glass-line, rgba(30,37,64,.15)); }
.autoroll .knob { width: 28px; height: 16px; border-radius: 99px; background: #cfd6e4; position: relative; transition: background .2s; }
.autoroll .knob::after { content: ''; position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; box-shadow: 0 1px 0 rgba(0,0,0,.3); transition: transform .2s; }
.autoroll.on .knob { background: var(--green); }
.autoroll.on .knob::after { transform: translateX(12px); }
.turn-head { flex-wrap: wrap; }

/* ---------- round board, not spinning: every tile carries an upright signboard ---------- */
.board.radial .sign { display: none; }
.board.radial.upright .sign {
  display: grid; align-content: center; gap: 2px; position: absolute; left: 50%; z-index: 2; pointer-events: none; overflow: hidden; box-sizing: border-box; border-radius: 7px; color: var(--txt, #fff);
  background: color-mix(in srgb, var(--face, #fff) 88%, #000);
}
.board.radial.upright .k-corner .sign { width: 66px; height: 50px; }
.board.radial.upright .sign .s-name { font: 800 7.5px/1.1 var(--font); text-transform: uppercase; text-wrap: balance; }
.board.radial.upright .sign .s-row { display: flex; align-items: center; gap: 3px; }
.board.radial.upright .sign .s-price { font: 700 8.5px/1 var(--font); opacity: .9; }
.board.radial.upright .sign .s-big { font: 800 16px/1 var(--font); }
.board.radial.upright :is(.tile, .sign-host).owned .sign { transition: background .3s; }
/* the ring-facing text is replaced by the sign (Jail keeps its own layout); the rent tag reads level too */
.board.radial.upright .tile:not(.t-jail) .tile-inner > * { visibility: hidden; }
.board.radial.upright .tag-rent { display: inline-block; }
/* Jail keeps its cell layout, but its words read level too */
.board.radial.upright .t-jail .corner-jail .t-big, .board.radial.upright .t-jail .corner-jail .visit { display: inline-block; }
/* Breaking out: the JAIL sign lights up in the escaping player's colour until they land */
:is(.tile, .sign-host).freeing .corner-jail .t-big, :is(.tile, .sign-host).freeing .sign .t-big { background: var(--free); box-shadow: 0 3px 0 color-mix(in srgb, var(--free) 60%, #000), 0 0 14px var(--free); transition: background .25s, box-shadow .25s; }
.corner-jail .t-big { transition: background .4s, box-shadow .4s; }
/* The bars (z 3) cover a jailed pawn and its arrow; everyone outside the cell draws above them */
.token:not(.jailed) { z-index: 4; }
.board.radial.upright .sign .s-price.small { font-size: 7px; }
.board.radial.upright :is(.tile, .sign-host).owned.owner-light .sign { text-shadow: none; }
/* Anything drawn on a player's colour picks dark or white ink from that colour's lightness (onyx and bronze get white).
   (A token chip sits on the colour only once picked — .tk.on, further down; the rest sit on the chip's own white or night glass.) */
.ptoken .ic, .slot-pawn .ic, .pawn .ic, .deed-owner { color: oklch(from var(--pc) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); }
/* ---------- vintage atlas globe: parchment land, muted earth biomes, deep navy ocean (player colours pop against it) ---------- */
.board-center { background: radial-gradient(circle at 42% 38%, #2f5a86 0%, #1f4370 42%, #15325a 78%, #0d2242 100%) !important; }
.board-center, body:not(.night) .board-center, body.night .board-center {
  box-shadow: inset 0 0 0 6px #c9a46a, inset 0 0 0 8px #7a5a32, inset 0 0 30px 4px rgba(10, 20, 45, .55), 0 0 26px 2px rgba(201, 164, 106, .3), 0 10px 24px -6px rgba(10, 20, 45, .5) !important;
}
.map { filter: none; }
.map .land { stroke: #6b4f2e; stroke-width: 1.1px; stroke-linejoin: round; }
.map .land-side { fill: #8a6a42; }
/* the gloss stays, softened so it reads as a varnished globe rather than plastic */
.board-center::after { opacity: .6; }
/* night over parchment: a moonlit blue multiply instead of a grey veil, so the land keeps its warmth */
.map .night-side { fill: #7f8fc4; opacity: .55; mix-blend-mode: multiply; }
/* ---------- night mode: the earth at night — dark land, coastlines traced in amber neon, the whole globe in darkness ---------- */
body.night .map .land-side, body.night .map .night-side { display: none; }
body.night .board-center::after { opacity: .3; }
body.night .scene .isle { fill: #0e1430; stroke-width: 1px; }
body.night .scene .isle-side { fill: #070a1c; }
/* the neon coastlines run the night sky's gradient upside down: gold at the top of the globe, through coral and magenta, to purple at the bottom */
body.night .scene .isle { stroke: #f49a52; }
/* night globe, inverted: the land and its neon coastlines show as their colour negative (light land, cool neon); the black
   ocean is left alone, and so are city lights and owner colours, so players still read true. Glow first, then invert, so the halo inverts too. */
body.night .scene .isle { filter: invert(1); }
/* the ring can be swiped round in upright mode too, so level text also cancels the ring's turn (--rot) and turns with it */
.board.radial.upright .sign { transform: translate(-50%, -50%) rotate(calc(-1 * var(--deg) - var(--rot))); transition: transform var(--turn), background .3s; }
.board.radial.upright .tag-rent { transform: rotate(calc(180deg - var(--deg) - var(--rot))); transition: transform var(--turn); }
.board.radial.upright .t-jail .corner-jail .t-big, .board.radial.upright .t-jail .corner-jail .visit { transform: rotate(calc(180deg - var(--deg) - var(--rot))); transition: transform var(--turn); }
/* ---------- not your move: the menu tucks away, the board takes the screen, a Menu tab on the right edge opens it as a drawer ---------- */
#menu-tab { display: none; }
body.watching #menu-tab {
  --drawer-w: min(420px, 86vw);
  display: flex; flex-direction: column; align-items: center; gap: 6px; position: fixed; right: 0; top: 50%; z-index: var(--z-drawer-tab);
  transform: translateY(-50%); padding: 14px 8px 12px; border: 0; border-radius: var(--r-md) 0 0 var(--r-md); cursor: pointer; color: var(--ink);
  box-shadow: -4px 4px 18px -6px rgba(0, 0, 0, .45); transition: right .35s var(--ease-out);
}
body.watching #menu-tab .chev { font: 800 20px/1 var(--font); transition: transform .35s; }
body.watching #menu-tab .lbl { font: 800 13px/1 var(--font); writing-mode: vertical-rl; transform: rotate(180deg); }
body.watching.menu-open #menu-tab { right: min(420px, 86vw); }
body.watching.menu-open #menu-tab .chev { transform: rotate(180deg); }

body.watching:not(.menu-open) #side { display: none; }
body.wide.watching:not(.menu-open) :is(.side-head, #players, #dock, #actions) { display: none; }
body.wide.watching #stage-wrap { grid-column: 1 / -1; grid-row: 1 / -1; }
body.mobile.watching #stage-wrap, body.developer.watching #stage-wrap { flex: 1; height: auto; aspect-ratio: auto; min-height: 0; }
body.mobile.watching #game { height: 100dvh; }
body.watching.menu-open #side {
  display: flex; flex-direction: column; position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 86vw); z-index: var(--z-drawer);
  overflow-y: auto; overscroll-behavior: contain; background: var(--glass, rgba(16, 20, 46, .9));
  box-shadow: -18px 0 50px -20px rgba(0, 0, 0, .55); animation: drawerIn .35s var(--ease-out);
}
body.night.watching.menu-open #side { background: rgba(16, 20, 46, .92); }
@keyframes drawerIn { from { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) { body.watching.menu-open #side { animation: none; } body.watching #menu-tab { transition: none; color: var(--ink); } }
/* warmer continents: honey parchment by day; at night the inverted land comes out a warm peach (base picked so 1 − base is warm) */
.map .land { fill: #f3d39a; }
.swatches { gap: 5px; }
.sw { width: 24px; height: 24px; }
/* mobile view scales with the window: the column is a phone's width × the UI scale, the board grows with it */
body.mobile #game { max-width: var(--mob-w, 640px); }
body.mobile #stage-wrap { height: min(var(--mob-w, 100vw), 54dvh); }
/* ---------- mobile buy prompt: the tile's sign grows up out of the board ---------- */
#buy-pop {
  position: absolute; z-index: 6; width: min(230px, 70%);
  display: grid; background: var(--glass, rgba(255, 255, 255, .9)); box-shadow: 0 0 0 2px var(--pc), 0 14px 30px -10px rgba(0, 0, 0, .55);
}
#buy-pop::after { /* the post down to the tile */
  content: ''; position: absolute; left: 50%; transform: translateX(-50%);
  background: var(--pc); clip-path: polygon(0 0, 100% 0, 50% 100%);
}
body.night #buy-pop { background: rgba(20, 24, 52, .92); }
.bp-sign { position: relative; display: grid; justify-items: center; text-align: center; color: #fff;
  background: var(--g); box-shadow: inset 0 -5px 0 rgba(0, 0, 0, .18); }
.bp-sign small { font: 800 9px/1 var(--font); opacity: .9; }
.bp-name { display: flex; align-items: center; font: 500 24px/1.05 var(--font); -webkit-text-stroke: 4px var(--ink); paint-order: stroke fill; }
.bp-name .ic { -webkit-text-stroke: 0; }
.bp-line { font: 700 13px/1.2 var(--font); }
.bp-more { top: 6px; right: 6px; border: 0; font: 800 9px/1.3 var(--font); color: var(--ink);
  background: rgba(255, 255, 255, .85); cursor: pointer; }
.bp-btns { display: grid; grid-template-columns: 1.4fr 1fr; }
.bp-timer { position: absolute; border-radius: 99px; text-align: center; font: 800 13px/1 var(--font); }
.bp-timer:has(.countdown:empty) { display: none; }
#buy-pop .warn { margin: 0; text-align: center; }
.bp-more { position: static; margin-top: 3px; }
/* mobile ride prompt: riding your own transport, a strip at the bottom of the board offers to stay put */
#ride-pop {
  position: absolute; z-index: 6; left: 50%; bottom: calc(var(--safe-bottom, 0px) + 16px); transform: translateX(-50%); width: min(300px, 86%);
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 10px; padding: 8px 8px 8px 12px; border-radius: var(--r-md);
  background: var(--glass, rgba(255, 255, 255, .9));
  box-shadow: 0 0 0 2px var(--pc), 0 14px 30px -10px rgba(0, 0, 0, .55); --from: translateX(-50%) translateY(24px) scale(.92); animation: enter .4s var(--ease-out);
}
body.night #ride-pop { background: rgba(20, 24, 52, .92); color: #fff; }
#ride-pop .rd-hint { display: flex; align-items: center; gap: 8px; margin: 0; font: 700 13px/1.25 var(--font); }
#ride-pop .rd-hint .ic { flex: none; width: 20px; height: 20px; }
#ride-pop .btn { padding: 10px 14px; white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { #ride-pop { animation: none; } }
/* night: dark continents again, keeping the current (inverted) neon outline — the land sits under the same invert()
   filter, so its base is the light negative of the dark navy it shows as */
/* GO's direction-of-play arrow: the sign stays level, the arrow follows the clockwise tangent at GO's spot on screen
   (tile angle + ring turn), so it stays right through Spin and swipes */
.board.radial.upright .sign .s-dir { display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; }
.board.radial.upright .sign .s-dir .ic { width: 13px; height: 13px; transform: rotate(calc(var(--deg) + var(--rot))); transition: transform var(--turn); }
/* POV phone frames: an iPhone's top safe area (status bar + Dynamic Island) stays clear */
body.pov-frame #game { padding-top: 0; }
/* bigger mobile buy sign: most of the phone's width, large name and buttons */
#buy-pop { width: min(340px, 90%); gap: 12px; padding: 14px; border-radius: var(--r-lg); }
#buy-pop::after { bottom: -16px; width: 22px; height: 16px; }
.bp-sign { gap: 6px; padding: 16px 12px 16px; border-radius: 15px; }
.bp-sign small { font-size: 12px; }
.bp-name { gap: 10px; font-size: 38px; -webkit-text-stroke: 6px var(--ink); }
.bp-name .ic { width: 34px; height: 34px; }
.bp-line { font-size: 17px; }
.bp-line b { font-size: 20px; }
.bp-more { font-size: 13px; padding: 4px 10px; border-radius: var(--r-sm); }
.bp-btns { gap: 10px; }
.bp-btns .btn { padding: 16px 8px; font-size: 20px; border-radius: var(--r-md); }
.bp-timer { top: -14px; left: -14px; min-width: 44px; padding: 6px 9px; font-size: 17px; }
/* ---------- Jail: the JAIL sign is a plaque across the bars; Visiting has its own level sign ---------- */
.board.radial .t-jail .corner-jail .t-big { display: none; }
.board.radial .jail-plaque { position: absolute; pointer-events: none; }
.board.radial .jail-plaque b { display: block; font: 800 15px/1 var(--font); color: #fff; background: #8a5a35; border-radius: 5px;
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, .35), 0 3px 0 #5e3b20, 0 6px 12px -4px rgba(0, 0, 0, .6); }
.board.radial.upright .t-jail .corner-jail .visit { display: none; }
.board.radial.upright .sign.visiting { width: 54px; min-height: 0; background: #3a3f52; }
.board.radial.upright .sign.visiting { height: 24px; }
/* ---------- your turn: a big die and a Roll pop-up over the board ---------- */
.dice-tray { transition: scale .35s var(--ease-out); }
body.my-roll .dice-tray:not(.docked) { scale: 2; }
body.my-roll .dice-tray.docked { scale: 1.5; transform-origin: 0 100%; }
#roll-pop {
  position: absolute; left: 50%; bottom: 6%; z-index: 7; transform: translateX(-50%);
  display: grid; gap: 12px; padding: 16px; border-radius: var(--r-lg); background: var(--glass, rgba(255, 255, 255, .9));
  box-shadow: 0 0 0 2px var(--pc), 0 16px 34px -12px rgba(0, 0, 0, .6);
  --from: translateX(-50%) translateY(30px) scale(.9);
  animation: enter .4s var(--ease-out);
}
body.night #roll-pop { background: rgba(20, 24, 52, .9); }
.rp-head { display: flex; align-items: center; gap: 12px; }
.rp-head .ptoken { width: 46px; height: 46px; }
.rp-head small { display: block; font: 800 11px/1 var(--font); color: var(--muted); }
.rp-head b { font: 500 30px/1.05 var(--font); }
.rp-head .countdown { margin-left: auto; font: 800 17px/1 var(--font); }
.rp-note { margin: 0; font: 700 13px/1.35 var(--font); }
.rp-btns { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 10px; }
.rp-btns .btn { padding: 16px 10px; font-size: 24px; border-radius: var(--r-md); display: flex; align-items: center; justify-content: center; gap: 8px; }
.rp-btns .btn .ic { width: 24px; height: 24px; }
@media (prefers-reduced-motion: reduce) { #roll-pop { animation: none; } .dice-tray { transition: none; } }
/* buildings as outlines: white strokes with a dark edge so they read on any tile colour */
.bld.house, .bld.tower { background: none; box-shadow: none; border-radius: 0; fill: none; stroke: #fff; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 1px 0 var(--ink)); overflow: visible; }
.bld.house { width: 13px; height: 13px; }
.bld.tower { width: 16px; height: 20px; }
/* the board owns its gestures (pinch, swipe), so the browser doesn't zoom or scroll the page under a finger */
.board.radial, #stage:has(.board.radial) { touch-action: none; }
/* ---------- finger indicators: a fingertip ripple for every touch / click, and the AI's taps (labelled, in its colour) ---------- */
.finger { position: fixed; z-index: var(--z-finger); width: 44px; height: 44px; margin: -22px 0 0 -22px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255, 255, 255, .55) 0 38%, rgba(255, 255, 255, .18) 39% 60%, transparent 61%);
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .7), 0 4px 14px rgba(0, 0, 0, .35); animation: fingerTap .6s ease-out forwards; }
.finger.ai { width: 54px; height: 54px; margin: -27px 0 0 -27px;
  background: radial-gradient(circle, color-mix(in srgb, var(--fc) 70%, #fff) 0 34%, color-mix(in srgb, var(--fc) 35%, transparent) 35% 62%, transparent 63%);
  box-shadow: 0 0 0 3px var(--fc), 0 0 18px var(--fc), 0 6px 16px rgba(0, 0, 0, .4); animation: aiTap .9s var(--ease-out) forwards; }
.finger.ai span { position: absolute; left: 50%; top: -20px; transform: translateX(-50%); padding: 2px 6px; border-radius: var(--r-sm); font: 800 11px/1 var(--font);
  letter-spacing: .06em; color: var(--ink); background: var(--fc); box-shadow: 0 2px 6px rgba(0, 0, 0, .35); }
@keyframes fingerTap { from { transform: scale(.6); opacity: 1; } 70% { opacity: .8; } to { transform: scale(1.35); opacity: 0; } }
@keyframes aiTap { 0% { transform: scale(1.6); opacity: 0; } 30% { transform: scale(1); opacity: 1; } 45% { transform: scale(.82); } 60% { transform: scale(1); opacity: 1; } 100% { transform: scale(1.25); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .finger, .finger.ai { animation-duration: .01s; } }
/* the faint dots an AI finger leaves while it drags or pinches */
.finger.ai.trail { width: 18px; height: 18px; margin: -9px 0 0 -9px; box-shadow: 0 0 10px var(--fc); background: color-mix(in srgb, var(--fc) 60%, transparent); animation: fingerTap .5s ease-out forwards; }
.board.radial .jail-plaque { left: 50%; top: 50%; }
.board.radial .jail-plaque b { font-size: 13px; padding: 3px 6px; letter-spacing: .03em; }
/* JAIL plaque sits outside the cell now (not on the swinging door); the door shows its edge as it swings */
.board.radial .jail-plaque { transform: translate(-50%, -50%) rotate(calc(-1 * var(--rot))); }
.jail-bars { backface-visibility: visible; transform-style: flat; }
/* while the cell door is open, both jail signs swing aside on their left corner, then settle back level */
.board.radial .jail-plaque { transition: transform .45s cubic-bezier(.3, .7, .2, 1); }
.board.radial .jail-plaque b { transform-origin: 0 50%; transition: transform .45s cubic-bezier(.3, .7, .2, 1); }
.board.radial.door-open .jail-plaque b { transform: rotate(-62deg) translateX(-6px); }
.board.radial.upright.door-open .sign.visiting { transform: translate(-50%, -50%) rotate(calc(-1 * var(--deg) - var(--rot))) translate(-30px, -4px) rotate(-58deg); }
/* the utilities & transport shelf sits across the top of the globe (narrower there, so it is drawn a little smaller) */
.scene { left: 154px; top: 34px; width: 300px; height: 71px; }
/* ---------- two colours per player: main fills owned signs and rent tags, accent colours the prices and rent ---------- */
.sw-label { margin: 10px 0 -8px; font: 800 11px/1 var(--font); color: var(--muted); }
.sw-label small { text-transform: none; letter-spacing: 0; font-weight: 700; opacity: .8; }
/* ---------- round board: buildings stand on the ground at the slice's outer rim and stack inward (gravity points straight out) ---------- */
.board.radial .tile.built .rent-high, .board.radial .tile.built .bld-zone { display: none; }                 /* the rent tag stays against the tile */
.board.radial .tile.built .tag-in.outer { top: var(--b); }
.board.radial .tile.built .bld-in { padding-top: 2px; }
.board.radial .bld.house { transform: rotate(180deg); }   /* base on the ground, roof toward the globe */
.board.radial .bld.tower { transform: rotate(180deg); }
.board.radial .bldgs.pop .bld { animation-name: buildDrop; }          /* settles down onto the stack (outward = down in tile space) */
/* prices and rent read white on a dark owner colour, black on a light one (no outline) */
.board.radial .tile.owned .tag-rent, .tile.sq.owned .tag-rent { color: oklch(from var(--owner, #fff) clamp(0, (0.62 - l) * 1000, 1) 0 0); text-shadow: none; }
/* round board, built: one continuous rent bar; the buildings are solid blocks in the owner's colour standing on its outer edge */
.board.radial .rent-full { display: none; }
.board.radial .bld .b-body { fill: color-mix(in srgb, var(--owner, #ccc) 62%, #fff); stroke-linejoin: round; }
.board.radial .bld .b-trim { fill: color-mix(in srgb, var(--owner, #ccc) 55%, var(--ink)); stroke: none; }
/* buildings read as blocks standing on the bar: a deeper shade of the owner's colour, ink outline, light door & windows */
.board.radial .bld .b-body { fill: color-mix(in srgb, var(--owner, #ccc) 68%, var(--ink)); stroke: var(--ink); stroke-width: 1.6; }
.board.radial .bld .b-trim { fill: color-mix(in srgb, var(--owner, #ccc) 45%, #fff); }
.board.radial .bld.house, .board.radial .bld.tower { filter: drop-shadow(0 -1px 0 rgba(255, 255, 255, .35)) drop-shadow(0 1.5px 0 rgba(0, 0, 0, .35)); }
/* buildings stand ON the rent bar, roofs pointing outward, side by side along it (the bar stays its normal size) */
.board.radial .tile.built .rent-full { display: none; }
.board.radial .tile.built .rent-low { display: block; }
.board.radial .tile.built .bld-in { flex-direction: row; }
.board.radial .bldgs { flex-direction: row; align-items: flex-end; }
.board.radial .bld.house, .board.radial .bld.tower { transform: none; }
@keyframes buildDrop { from { translate: 0 -10px; opacity: 0; } }          /* drops onto the bar */
/* bigger buildings: they rise from the rent bar out past the build space */
.board.radial .tile.built .bld-in, .board.radial .bldgs { overflow: visible; }
.board.radial .bldgs { gap: 2px; }
/* ---------- round board: no rent bar — the sign carries rent + ownership; buildings rise off the tile's outer edge ---------- */
.board.radial :is(.rent-low, .rent-high, .rent-full, .tag-in, .bld-zone, .bld-lot) { display: none !important; }
.board.radial .tile.built .bld-in { top: 0 !important; height: var(--tag) !important; display: flex; align-items: flex-end; justify-content: center; padding: 0 0 1px; }
.board.radial.upright :is(.tile, .sign-host).owned .sign .s-price { font-weight: 800; }
.board.radial.upright :is(.tile, .sign-host).owned .sign .s-price.long { font-size: 8px; letter-spacing: -.02em; }  /* $1,750 still fits beside the token */
.board.radial.upright :is(.tile, .sign-host).owned .sign .s-row { gap: 2px; }
/* colour pairs: each swatch shows the pair split corner to corner (main / accent) */
.sw.pair { border-radius: 50%; background: linear-gradient(135deg, var(--c) 0 50%, var(--c2) 50% 100%); }
.sw.pair:disabled { opacity: .25; }
/* the player card's token icon wears the player's accent colour */
/* owned: the sign's mark is just the owner's symbol (no chip), and a bar in the owner's colour runs along the tile's inner end */
.board.radial .w-own { display: none; }
.board.radial .tile.owned .w-own { display: block; fill: var(--owner); stroke: none; filter: drop-shadow(0 0 4px var(--owner)); }
/* every sign's colour sits inside a margin: a dark frame round the edge, a light hairline inside it, then the colour */
/* tighter sign text so everything stays inside the framed margin */
.board.radial.upright .sign { row-gap: 1px; padding: 4px 3px; }
.board.radial.upright .sign .s-name { font-size: 6.8px; line-height: 1.02; letter-spacing: 0; }
.board.radial.upright .sign .s-row .ic, .board.radial.upright .sign > .ic { width: 11px; height: 11px; }
.board.radial.upright .sign .s-price { font-size: 8px; }
.board.radial.upright .sign .s-price.small, .board.radial.upright :is(.tile, .sign-host).owned .sign .s-price.long { font-size: 6.6px; }
.board.radial.upright :is(.tile, .sign-host).owned .sign .s-price { font-size: 8.5px; }
.board.radial.upright .sign.visiting { padding: 2px 3px; box-shadow: inset 0 0 0 1.6px var(--ink); }
.board.radial.upright .sign.visiting .s-name { font-size: 6.4px; }
.board.radial.upright .sign:not(.visiting) { padding: 4px; }
/* ---------- set bands: each tile of a set shows the set's purchases as coloured bands (in order of purchase) ---------- */
.board.radial .w-band { display: none; }
.board.radial .w-band.on { display: block; fill: var(--bc); }
.board.radial .tile.t-property .w-own { display: none !important; }            /* the bands replace the bar on cities */
/* signs keep their original tile colour; an owned one wears a halo in the owner's colour */
.board.radial .tile .w-own { display: none !important; }   /* transports & utilities use quarter bands now, like the sets */
/* "For sale" tag just beyond the outer edge of every unowned buyable tile, kept level; gone once someone buys it */
.board.radial .sale { position: absolute; left: 50%; pointer-events: none; white-space: nowrap; font: 800 6.5px/1 var(--font); letter-spacing: .06em; text-transform: uppercase;
  color: #d4183d; background: #fff; }
.board.radial .tile.owned .sale { opacity: 0; }
/* For sale tags never animate a turn: they sit fixed and level on their tile (only the fade on purchase animates) */
.board.radial .sale { transition: opacity .25s; }
/* round board: the commentary in the middle of the globe, just under the dice (its size undoes the board's scale) */
/* the For sale tag sits right above its tile's sign on screen: same anchor as the sign, levelled, then lifted up */
.board.radial .sale { z-index: 3; }
/* the For sale tag is an extension of the sign's top edge: same width, flush on it, rounded only on top */
.board.radial .sale { width: 50px; box-sizing: border-box; padding: 2px 0 1.5px; text-align: center; font-size: 6.2px;
  border-radius: 7px 7px 0 0; box-shadow: inset 0 0 0 1.2px #d4183d, 0 0 0 1.5px var(--ink);
  transform: translate(-50%, -50%) rotate(calc(-1 * var(--deg) - var(--rot))) translateY(-24.6px); }
.board.radial.upright :is(.tile, .sign-host):not(.owned) .sign { border-top-left-radius: 2px; border-top-right-radius: 2px; } /* the sign's top meets the strip */
/* "For sale" is the top portion of an unowned property's sign: a red band inside the frame, contents nudged below it */
.board.radial.upright .sign.for-sale { padding-top: 11px; border-top-left-radius: 7px; border-top-right-radius: 7px; }
.board.radial.upright .sign.for-sale::before { content: 'For sale'; position: absolute; height: 8px; background: #d4183d; color: #fff; font: 800 5.6px/8px var(--font); letter-spacing: .08em; text-transform: uppercase; text-align: center; }
.board.radial.upright .sign.for-sale .s-name { font-size: 6.4px; }
.board.radial.upright .sign.for-sale { padding-bottom: 3px; }
.board.radial.upright .sign.for-sale .s-name { line-height: .98; }
/* ---------- phone, zoomed out: a simplified board — one big label (rent, price or name) along each tile ---------- */
.board.radial .big { display: none; position: absolute; left: 50%; z-index: 2; pointer-events: none; }
.board.radial.simple .big span { display: block; white-space: nowrap; font: 500 34px/1 var(--font); color: #fff;
  -webkit-text-stroke: 6px var(--ink); paint-order: stroke fill; }
.board.radial.simple .big.long span { font-size: 26px; }
.board.radial.simple .tile.t-property:not(.owned) .big span, .board.radial.simple .tile.t-transport:not(.owned) .big span,
.board.radial.simple .tile.t-utility:not(.owned) .big span { font-size: 24px; opacity: .8; }
.board.radial.simple :is(.sign, .tile-inner, .bld-in) { display: none !important; }
/* simple phone board: icon + label along the tile (icon at the globe end), rent glows in the owner's neon colour */
.board.radial.simple .big { align-items: center; gap: 5px; }
.board.radial.simple .tile.bflip .big { flex-direction: row-reverse; }
.board.radial.simple .big .ic { flex: none; width: 26px; height: 26px; color: #fff; filter: drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 2px 0 var(--ink)); }
.board.radial.simple .big.long .ic { width: 22px; height: 22px; }
.board.radial.simple .tile.owned .big span { text-shadow: 0 0 6px var(--owner), 0 0 14px var(--owner), 0 0 24px var(--owner); }
.board.radial.simple .tile.owned .big .ic { filter: drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 0 6px var(--owner)) drop-shadow(0 0 12px var(--owner)); }
/* ---------- simple phone board is an oval: the board stretches (--isx/--isy undo it), readable things stay undistorted ---------- */
.board.radial.simple .big { transform: translate(-50%, -50%) rotate(calc(-1 * (var(--deg) + var(--rot)))) rotate(calc(var(--deg) + var(--rot) - 90deg)); }
.board.radial.simple .tile.bflip .big { transform: translate(-50%, -50%) rotate(calc(-1 * (var(--deg) + var(--rot)))) rotate(calc(var(--deg) + var(--rot) + 90deg)); }
.board.radial.simple .token .up { transform: rotate(calc(-1 * var(--rot))); }
.board.radial.simple .dice-tray:not(.docked) { transform: translate(-50%, -50%); }
.board.radial.simple .board-center .deck { transform:  rotate(-8deg); }
/* ---------- small view (phone, zoomed out): round; the original tile design — price, icon, name facing the centre;
   an owned tile's price is covered by a little sign with the rent (tile colour, owner's halo) ---------- */
.board.radial.simple .big { display: none !important; }
.board.radial.simple .tile-inner { display: flex !important; } /* a column, so the body fills the whole tile */
.board.radial.simple .tile .tile-inner > * { visibility: visible !important; }
.board.radial.simple .t-price.rent-sign { display: inline-block; font-weight: 800; -webkit-text-stroke: 0; }
/* small view: name at the bottom (globe end) of the tile, icon in the middle, price/rent at the outer end —
   flipped tiles (text top toward the centre) reverse the column so the order holds on screen */
.board.radial.simple .tile:not(.t-jail) .t-body { justify-content: space-between; }
.board.radial.simple .tile.flip:not(.t-jail) .t-body { flex-direction: column-reverse; }
.board.radial.simple .t-icon { margin: auto 0; }
/* small view, Jail: only its top sign shows — "top" = the radially outermost one, the plaque beyond the cell */
.board.radial.simple .t-jail .corner-jail > * { display: none !important; }
/* small view: same padding on both halves so the price sits right at the outer edge and the name at the inner edge */
.board.radial.simple .tile:not(.t-jail) .t-body, .board.radial.simple .tile.flip:not(.t-jail) .t-body { padding: 5px 4px; justify-content: space-between; }
/* small view: Deal and Chance read horizontally — their contents cancel the tile's turn (and the half-turn on flipped tiles) */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * { transition: transform var(--turn); }
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner { align-items: center; justify-content: center; }
/* small view, Deal & Chance: one level row along the tile — icon at the outer end, word toward the globe */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * {
  position: absolute; left: 50%; top: 50%; height: 56px; display: flex; flex-direction: row-reverse;
  align-items: center; box-sizing: border-box;
  transform: translate(-50%, -50%) rotate(calc(-1 * (var(--deg) + var(--rot)))); }
.board.radial.simple .tile.flip:is(.t-deal, .t-chance.k-corner) .tile-inner > * { transform: translate(-50%, -50%) rotate(calc(-1 * (var(--deg) + var(--rot)) - 180deg)); }
.board.radial.simple .tile.outer-left:is(.t-deal, .t-chance.k-corner) .tile-inner > * { flex-direction: row; }
.board.radial.simple .t-chance.k-corner .card-stack { flex: none; }
/* Deal & Chance (small view): the row spans the tile's whole length; the word fills the space between the icon and the
   tile's inner edge and is centred in it — the midpoint of icon edge and inner edge */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * { padding: 0; gap: 0; justify-content: flex-start; }
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * > :first-child { flex: none; margin: 0 4px; }
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .t-big { text-align: center; }
/* Deal and Chance use GO's lettering: display face, 24px, thick ink outline and a drop shadow */
.board.radial :is(.corner-deal, .corner-chance) .t-big { font: 800 24px/1 var(--font); -webkit-text-stroke: 7px var(--ink); paint-order: stroke fill; text-shadow: 0 4px 0 var(--ink); color: #fff; letter-spacing: 0; text-transform: none; }
/* Deal & Chance icons keep clear of the tile's outer edge */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * { padding-left: 12px; }
.board.radial.simple .tile.outer-left:is(.t-deal, .t-chance.k-corner) .tile-inner > * { padding-left: 12px; padding-right: 0; }
.board.radial.simple .tile:not(.outer-left):is(.t-deal, .t-chance.k-corner) .tile-inner > * { padding-left: 0; padding-right: 12px; }
/* "Fortune" is seven letters: GO's lettering at a size that fits beside its card */
.board.radial .corner-chance .t-big { font-size: 19px; -webkit-text-stroke: 6px var(--ink); text-shadow: 0 3px 0 var(--ink); }
/* small view: Deal & Chance show only their icon (no word); bigger tile icons; the JAIL plaque sits above the bars */
/* (the icon stays at the tile's outer end, 12px clear of the edge — see the outer-left padding rules above) */
.board.radial.simple .t-icon .ic { width: 44px; height: 44px; }
.board.radial.simple .jail-plaque { transform: translate(calc(-50% + var(--up-x, 0px)), calc(-50% + var(--up-y, 0px))) rotate(calc(-1 * var(--rot))); }
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > * { width: 156px; } /* spans the (longer) corner tile so the icon sits at its far end */
/* tax tiles: "Pay" on its own line above the amount; the Luxury Tax condition in small type under it */
.t-price.tax-price { line-height: 1.05; text-align: center; }
.t-price.tax-price small { display: block; font-size: .62em; font-weight: 700; opacity: .85; }
/* GO's arrow points along the direction of play: the tile's own +x is clockwise, so no turn — undo the half-turn on flipped tiles */
.board.radial .go-arrow .ic { transform: none; }
.board.radial .tile.flip .go-arrow .ic { transform: rotate(180deg); }
/* small view: the price, big and curved along the tile's outer arc (unowned buyables); owned tiles keep their rent sign */
.board.radial .arc-path { fill: none; stroke: none; }
.board.radial .arc-price { display: none; stroke-width: 5px; paint-order: stroke fill; }
.board.radial.simple .tile:not(.owned):not(.flip) .arc-price.n, .board.radial.simple .tile.flip:not(.owned) .arc-price.f { display: block; }
.board.radial.simple .tile:is(.t-property, .t-transport, .t-utility):not(.owned) .t-price { visibility: hidden; }
/* curved small-view prices use the city-name face (UI font, bold caps) with no outline */
.board.radial .arc-price { font: 700 22px/1 var(--font); stroke: none; fill: var(--txt, #fff); letter-spacing: .01em; }
/* zoomed in: Deal and Chance signs drop to the regular sign size, with smaller contents */
.board.radial.upright :is(.tile, .sign-host):is(.t-deal, .t-chance.k-corner) .sign { width: 50px; height: 40px; }
.board.radial.upright :is(.tile, .sign-host):is(.t-deal, .t-chance.k-corner) .sign .s-big { font-size: 12px; }
.board.radial.upright :is(.tile, .sign-host).t-deal .sign > .ic { width: 15px; height: 15px; }
.board.radial.upright :is(.tile, .sign-host):is(.t-deal, .t-chance.k-corner) .sign .s-name { font-size: 6.4px; }
/* outside small view (desktop / Spin text), Deal & Chance words and their icons stay well inside the tile */
.board.radial:not(.simple) :is(.corner-deal, .corner-chance) .t-big { font-size: 14px; -webkit-text-stroke: 4px var(--ink); text-shadow: 0 2px 0 var(--ink); }
.board.radial:not(.simple) .corner-deal .t-icon .ic { width: 30px; height: 30px; }
.board.radial:not(.simple) .corner-chance .card-stack { transform: scale(.8); }
.board.radial:not(.simple) .corner-jail .visit { font-size: 5.5px; letter-spacing: 0; }
/* small view: an owned tile shows the owner's token instead of its landmark, and its rent sign in their colour */
.board.radial .own-ic { display: none; }
.board.radial.simple .tile.owned .own-ic .ic { color: var(--owner); filter: drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 0 6px var(--owner)); }
/* (the sign wears the tile's original set colour, so an owned tile still shows its set; the halo stays the owner's) */
.board.radial.simple .t-price.rent-sign { background: var(--set, var(--owner)); }
/* small view: rent signs set at the same size and face as the curved buy price */
.board.radial.simple .t-price.rent-sign { font: 700 22px/1 var(--font); padding: 4px 7px; border-radius: 8px; white-space: nowrap; }
/* small view, owned: keep the city's own landmark icon, drawn in the owner's colour (no token swap) */
.board.radial.simple .tile.owned .own-ic { display: none; }
/* tax tiles: a white stripe across their inner (bottom) end */
.board.radial .w-taxband { fill: #fff; opacity: .92; }
/* (by day the face is white too: the stripe goes ink, or it vanishes) */
body:not(.night) .board.radial .w-taxband { fill: var(--ink); }
/* Deal and Chance tiles: a white border round the face */
.board.radial .tile:is(.t-deal, .t-chance.k-corner) .w-face { stroke-width: 3px; paint-order: fill stroke; }
/* GO and Jail tiles: a black border round the face */
.board.radial .tile:is(.t-go, .t-jail) .w-face { stroke-width: 3px; paint-order: fill stroke; }
/* GO & Jail: the black border runs round the outer arc and sides only (no bottom edge) */
.board.radial .tile:is(.t-go, .t-jail) .w-face { stroke: transparent; }
.board.radial .w-border { fill: none; stroke: #000; stroke-width: 3px; stroke-linejoin: round; }
/* GO's fuel pump, below its sign, level */
.board.radial .w-border.bottom { stroke-width: 1.3px; }
/* thinner border round the tiles' 3D underside too: black on GO & Jail, white on Deal & Chance */
.board.radial .tile:is(.t-go, .t-jail) .w-side { stroke: #000; stroke-width: 1.3px; stroke-linejoin: round; }
.board.radial .tile:is(.t-deal, .t-chance.k-corner) .w-side { stroke: #fff; stroke-width: 1.3px; stroke-linejoin: round; }
/* sign view: the sign's icon repeated on the tile near its inner edge, always the right way up */
.board.radial .tile-ic { display: none; position: absolute; left: 50%; pointer-events: none; line-height: 0; transition: transform var(--turn); }
.board.radial.upright .tile-ic { display: block; }
.board.radial .tile-ic .ic { color: #fff; filter: drop-shadow(0 0 1.2px var(--ink)) drop-shadow(0 1.5px 0 var(--ink)); }
/* Chance: six face-down cards, roll to pick */
.pick-card { position: relative; aspect-ratio: 3 / 4; min-width: 40px; border-radius: 8px; display: grid; place-items: center;
  background: var(--fortune); box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .55), 0 3px 0 var(--fortune-side), 0 6px 14px -6px rgba(0, 0, 0, .5); }
.pick-card b { font: 500 26px/1 var(--font); color: #fff; -webkit-text-stroke: 4px var(--ink); paint-order: stroke fill; }
.pick-card span { position: absolute; right: 4px; bottom: 3px; font: 800 10px/1 var(--font); color: var(--ink); }
.pick-card.chosen { transform: translateY(-6px) scale(1.08); box-shadow: inset 0 0 0 2px #fff, 0 0 0 3px var(--ink), 0 0 18px var(--yellow); }
/* Fortune's tile mark is a question mark; on every sign the price sits left and the icon right */
.board.radial .tile-q { display: block; font: 800 26px/1 var(--font); color: #fff; -webkit-text-stroke: 4px var(--ink); paint-order: stroke fill; }
.board.radial.upright .sign .s-row { flex-direction: row-reverse; }
.board.radial.upright :is(.tile, .sign-host).t-go .sign .s-row { flex-direction: row; } /* GO keeps "GO" then its arrow */
/* sign view: tile icons a bit bigger */
.board.radial .tile-ic .ic { width: 30px; height: 30px; }
.board.radial .tile-q { font-size: 32px; }
/* tile icons turn with their tile: upright with their foot toward the tile's outer edge (top toward the globe) */
.board.radial .tile-ic { transform: translate(-50%, -50%) rotate(180deg); }
/* …except on the top half of the screen, where they turn round so they read upright there too */
.board.radial .tile:not(.flip) .tile-ic { transform: translate(-50%, -50%) rotate(0deg); }
/* Deal & Chance tile icons sit level on screen (they're on the left and right of the ring) */
.board.radial .tile:is(.t-deal, .t-chance.k-corner) .tile-ic { transform: translate(-50%, -50%) rotate(calc(-1 * var(--deg) - var(--rot))); }
/* Jail's side borders thinner */
.board.radial .tile.t-jail .w-border:not(.bottom) { stroke-width: 1.6px; }
/* tile icons on the left and right of the ring stay tilted with their tile but turned a quarter, so they look upright */
.board.radial .tile.side-r .tile-ic, .board.radial .tile.side-r:is(.t-deal, .t-chance.k-corner) .tile-ic { transform: translate(-50%, -50%) rotate(-90deg); }
.board.radial .tile.side-l .tile-ic, .board.radial .tile.side-l:is(.t-deal, .t-chance.k-corner) .tile-ic { transform: translate(-50%, -50%) rotate(90deg); }
/* ownership bands get the board's 3D bevel: a darker edge, a light top lip, a soft shadow below */
.board.radial .w-band.on { stroke: color-mix(in srgb, var(--bc) 55%, #000); stroke-width: 1.2px; stroke-linejoin: round;
  filter: drop-shadow(0 -1px 0 rgba(255, 255, 255, .45)) drop-shadow(0 1.5px 0 rgba(0, 0, 0, .35)); }
/* Deal & Chance: while the current player stands on them, the white border fades to and from their colour */
.board.radial .tile.here:is(.t-deal, .t-chance.k-corner) :is(.w-face, .w-side) { animation: none; stroke: var(--cur, #fff); }
@media (prefers-reduced-motion: reduce) { .board.radial .tile.here:is(.t-deal, .t-chance.k-corner) :is(.w-face, .w-side) { animation: none; stroke: var(--cur, #fff); } }
/* buildings in 3D: a darker side wall and a lighter roof/top next to the front face */
.board.radial .bld .b-side { fill: color-mix(in srgb, var(--owner, #ccc) 40%, var(--ink)); stroke: var(--ink); stroke-width: 1.1; stroke-linejoin: round; }
.board.radial .bld .b-top { fill: color-mix(in srgb, var(--owner, #ccc) 55%, #fff); stroke: var(--ink); stroke-width: 1.1; stroke-linejoin: round; }
.board.radial .bld.house { width: 24px; height: 19px; }
.board.radial .bld.tower { width: 26px; height: 29px; }
.tile.sq .bld .b-side, .tile.sq .bld .b-top { fill: none; stroke: #fff; stroke-width: 1.3; }
/* sign view: an owned property's sign is filled with the owner's colour and glows */
.board.radial.upright :is(.tile, .sign-host).owned .sign { background: var(--owner); }
/* owned signs: white lettering with a dark outline so it reads on any player colour */
.board.radial.upright :is(.tile, .sign-host).owned .sign :is(.s-name, .s-price, .s-big) { -webkit-text-stroke: 2.4px var(--ink); paint-order: stroke fill; text-shadow: 0 1px 0 var(--ink); }
.board.radial.upright :is(.tile, .sign-host).owned .sign .ic { filter: drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 1px 0 var(--ink)); }
/* Busted's siren a size down */
.board.radial .tile.t-gotojail .tile-ic .ic { width: 22px; height: 22px; }
.board.radial.simple .tile.t-gotojail .t-icon .ic { width: 32px; height: 32px; }
/* Chance sweep: the light runs across the six cards, then the drawn one lifts and the card turns over */
.chance-card.waiting { visibility: hidden; }
.chance-card.waiting .cc-inner { animation: none; } /* the flip waits until the sweep lands */
/* the six options are shown face up while the sweep runs */
.pick-card.open { aspect-ratio: auto; align-content: center; gap: 2px; text-align: center; background: #fff8ec;
  box-shadow: inset 0 0 0 2px var(--fortune), 0 3px 0 var(--fortune-side), 0 6px 14px -6px rgba(0, 0, 0, .5); }
.pick-card.open small { font: 800 7px/1 var(--font); color: var(--fortune); }
.pick-card.open b { font: 700 11px/1.15 var(--font); color: var(--ink); -webkit-text-stroke: 0; text-wrap: balance; }
/* Jail: "Just visiting" and the JAIL plaque both stack in front of the bars (same layer, drawn after them) */
.board.radial.upright .t-jail .sign.visiting { display: none !important; }
.board.radial .jail-visit { display: none; position: absolute; z-index: 4; pointer-events: none;
  transform: translate(-50%, -50%) rotate(calc(-1 * var(--rot))); transition: transform var(--turn); }
.board.radial.upright .jail-visit { display: block; }
.board.radial .jail-visit b { display: block; border-radius: 6px; font: 800 7px/1 var(--font);
  color: #fff; background: #3a3f52; box-shadow: inset 0 0 0 1.6px var(--ink), 0 2px 0 rgba(0, 0, 0, .3); }
.board.radial.door-open .jail-visit b { transform: rotate(-58deg) translateX(-12px); transform-origin: 0 50%; transition: transform .45s cubic-bezier(.3, .7, .2, 1); }
.board.radial .token:not(.jailed) { z-index: 5; } /* visiting pawns stay in front of the jail signs */
/* ================= TOY GLOBE (both themes): a glossy plastic ball — two-tone ocean, flat chunky continents with the
   board's thick ink outline and a pressed-out edge, little 3D pins for cities. No glow, no blobs, no shelf. ================= */
body .board-center { background: radial-gradient(circle at 38% 32%, #4cc3f5 0%, #2a9fe0 46%, #1f7fc4 74%, #17619c 100%) !important;
  box-shadow: inset 0 0 0 5px var(--ink), inset 0 -18px 30px -10px rgba(10, 30, 70, .45), 0 0 0 3px #fff, 0 0 0 6px var(--ink), 0 12px 22px -8px rgba(0, 0, 0, .5) !important; }
body .board-center::after { opacity: 1 !important;
  background: radial-gradient(ellipse 22% 12% at 32% 20%, rgba(255, 255, 255, .85), rgba(255, 255, 255, 0) 70%),
    radial-gradient(ellipse 45% 30% at 36% 26%, rgba(255, 255, 255, .22), transparent 70%) !important; box-shadow: none !important; }
body .map { filter: none !important; }
body .map .land { fill: #7fd06b !important; stroke: var(--ink) !important; stroke-width: 2.6px !important; stroke-linejoin: round; filter: none !important; }
body .map .land-side { display: block !important; fill: #3f8f3a !important; stroke: var(--ink); stroke-width: 2.6px; }
body .map :is(.biomes, .influence, .night-side, .shelf, .clouds) { display: none !important; }
/* cities: little plastic pins — white when free, the owner's colour once bought */
body .map .city { filter: drop-shadow(0 2px 0 rgba(10, 20, 40, .45)) !important; }
body .map .city .glow { display: none; }
body .map .city .dot { fill: var(--mc, #fff) !important; stroke: var(--ink) !important; stroke-width: 2px !important; animation: none !important;
  rx: 50%; x: -5px; y: -5px; width: 10px; height: 10px; }
body .map .city.owned .dot { x: -6.5px; y: -6.5px; width: 13px; height: 13px; }
body.night .board-center, body:not(.night) .board-center { background: radial-gradient(circle at 38% 32%, #4cc3f5 0%, #2a9fe0 46%, #1f7fc4 74%, #17619c 100%) !important;
  box-shadow: inset 0 0 0 5px var(--ink), inset 0 -18px 30px -10px rgba(10, 30, 70, .45), 0 0 0 3px #fff, 0 0 0 6px var(--ink), 0 12px 22px -8px rgba(0, 0, 0, .5) !important; }
body.night .board-center::after, body:not(.night) .board-center::after { opacity: .8 !important; }
body.night .map .land, body:not(.night) .map .land { fill: #7fd06b !important; stroke: var(--ink) !important; stroke-width: 2.6px !important; filter: none !important; }
/* toy globe, coloured to sit with each theme's sky — the ink line design and gloss stay; the day/night shadow is back */
body.night .board-center { background: radial-gradient(circle at 38% 32%, #6a4fc7 0%, #4a2f9e 46%, #33207a 74%, #221556 100%) !important;
  box-shadow: inset 0 0 0 5px var(--ink), inset 0 -18px 30px -10px rgba(10, 5, 40, .5), 0 0 0 3px #ffd2a8, 0 0 0 6px var(--ink), 0 0 26px 2px rgba(240, 119, 95, .35), 0 12px 22px -8px rgba(0, 0, 0, .5) !important; }
body:not(.night) .board-center { background: radial-gradient(circle at 38% 32%, #7fe3ff 0%, #3cc0f0 46%, #2196d8 74%, #1670b3 100%) !important; }
body:not(.night) .map .land { fill: #ffe066 !important; }
body:not(.night) .map .land-side { fill: #d49a2a !important; }
body .map .night-side { display: block !important; fill: #120a3a; opacity: .32; mix-blend-mode: multiply; filter: blur(18px); }
/* the utilities & transport shelf is back across the top of the globe */
body .scene { display: block !important; }
/* owned cities radiate light in their owner's colour */
body .map .city.owned .glow { display: block; fill: var(--mc); opacity: .5; filter: blur(4px); x: -14px; y: -14px; width: 28px; height: 28px; rx: 50%;
  transform-box: fill-box; transform-origin: center; animation: none; }
body .map .city.owned { filter: drop-shadow(0 2px 0 rgba(10, 20, 40, .45)) drop-shadow(0 0 6px var(--mc)) drop-shadow(0 0 14px var(--mc)) !important; }
@keyframes cityRadiate { 0% { transform: scale(.5); opacity: .8; } 100% { transform: scale(1.6); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { body .map .city.owned .glow { animation: none; filter: blur(4px); opacity: .5; } }
/* the GlobeRun logo in the middle of the map, above the dice */
.board-center .globe-logo { position: absolute; z-index: 2; pointer-events: none; white-space: nowrap; -webkit-text-stroke-width: 9px; text-shadow: 0 5px 0 var(--ink); opacity: .95; }
/* logo dead centre of the globe (across the Sahara); dice and commentary step down below it */
/* sign view Jail: only the two signs — the tile's own "Visiting / JAIL" text is hidden; Visiting is two lines, inside the tile */
.board.radial.upright .t-jail .corner-jail > * { visibility: hidden !important; }
.board.radial .jail-visit b { white-space: normal; text-align: center; width: 46px; padding: 3px 2px; line-height: 1.05; font-size: 6.5px; }
/* non-spin (sign view): the door swings within the cell's own band, clear of both signs — so the signs stay put */
.board.radial.upright.door-open .jail-plaque b, .board.radial.upright.door-open .jail-visit b,
.board.radial.upright.door-open .sign.visiting { transform: none !important; }
/* the die in the middle of the globe gets the board's 3D bevel: ink outline, light top lip, darker underside */
.board.radial .dice-tray .die { box-shadow: inset 0 0 0 2.5px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .9), inset 0 -5px 0 rgba(30, 37, 64, .22),
  0 0 0 2px var(--ink), 0 5px 0 var(--ink), 0 9px 14px -4px rgba(0, 0, 0, .5) !important; }
/* the docked die in the stage corner (Zoom mode) gets the same bevel */
.dice-tray.docked .die, #stage > .dice-tray .die { box-shadow: inset 0 0 0 2.5px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .9), inset 0 -5px 0 rgba(30, 37, 64, .22),
  0 0 0 2px var(--ink), 0 5px 0 var(--ink), 0 9px 14px -4px rgba(0, 0, 0, .5) !important; }
/* roll prompt in the commentary's spot (globe centre, under the dice), counter-scaled like the line; the line hides meanwhile */
#roll-pop .btn.big { display: flex !important; }            /* not the board's .big tile labels */
#roll-pop .btn.big { position: static !important; transform: none !important; left: auto !important; top: auto !important; }
/* the die grows evenly from its own centre on the globe, and only enough to stay clear of the GlobeRun logo */
body.my-roll .board.radial .dice-tray:not(.docked) { scale: 1.3; }
/* the Roll prompt on the globe is the one to use: the menu's roll / bail buttons and roll hint step aside while it shows */
body:has(#roll-pop) #actions :is([data-act="roll"], [data-act="bail"], .hint.subtle) { display: none !important; }
#roll-pop, #roll-pop .btn, #roll-pop .btn.big { pointer-events: auto !important; } /* the board's .big tile labels ignore clicks; this button must not */
/* globe Roll prompt: a narrower card, its button sized to the label */
#roll-pop { width: auto; min-width: 0; }
#roll-pop .rp-btns { grid-auto-flow: row; }
#roll-pop .rp-btns .btn { width: auto; padding-inline: 34px; }
/* globe Roll prompt buttons in the GlobeRun logo lettering */
#roll-pop .rp-btns .btn { font-family: var(--font); font-size: 24px;
  -webkit-text-stroke: .16em var(--ink); paint-order: stroke fill; }
/* the nudge prompt: each option stacks the face, the tile it lands on and what happens there; only the face keeps the
   logo lettering */
#roll-pop .rp-btns.nudge .btn { flex-direction: column; gap: 2px; padding: 12px 22px; line-height: 1.1; -webkit-text-stroke: 0; }
#roll-pop .rp-btns.nudge .btn b { font-size: 24px; -webkit-text-stroke: .16em var(--ink); paint-order: stroke fill; }
#roll-pop .rp-btns.nudge .btn .nudge-to { font: 700 15px/1.1 var(--font); }
#roll-pop .rp-btns.nudge .btn small { font: 700 12px/1.2 var(--font); opacity: .85; }
/* fifteen Chance options: five across, three rows */
.pick-card.open b { font-size: 10px; }
.modal.card { width: auto; max-width: 92vw; }
/* Chance options: three per row (five rows of three) */
.pick-card.open { min-height: 34px; padding: 4px; }
body:has(#roll-pop) #actions [data-act="end"] { display: none !important; } /* "Roll again" lives on the globe */
/* globe Roll button: the player-name lettering (display face, as in "Ava" above it) and the player's own token icon */
#roll-pop .rp-btns .btn { letter-spacing: 0; -webkit-text-stroke: 0; text-shadow: none; color: var(--ink); gap: 10px; }
#roll-pop .rp-btns .btn .ic { width: 26px; height: 26px; }
/* player names bold — on the globe prompt, the turn bar, and the Roll button that shares their lettering */
.rp-head b, .turn-head b { font-weight: 800 !important; }
#roll-pop .rp-btns .btn { font-weight: 800 !important; }
/* phones: Manage under Roll opens the menu drawer; the separate Menu tab steps aside while the prompt shows */
body:has(#roll-pop) #menu-tab { display: none !important; }
body.menu-open:has(#roll-pop) #menu-tab { display: flex !important; } /* still there to close the drawer */
/* Roll and Manage: the same size and lettering, no icons */
#roll-pop .rp-btns { display: grid; justify-items: stretch; }
#roll-pop .rp-btns .btn { min-width: 190px; padding: 14px 24px; font: 800 24px/1 var(--font) !important; }
#roll-pop .rp-btns .btn .ic { display: none; }
/* small view: one icon per tile — the middle one, turned like sign view's tile icons (the flipped tile-inner already
   gives the top/bottom halves their sign-view turn; the tiles round Deal and Chance get the quarter turn) */
.board.radial.simple .tile-ic { display: none !important; }
.board.radial.simple .tile.side-r:not(.flip):not(.t-deal, .t-chance.k-corner) .t-icon, .board.radial.simple .tile.side-l.flip:not(.t-deal, .t-chance.k-corner) .t-icon { transform: rotate(-90deg); }
.board.radial.simple .tile.side-r.flip:not(.t-deal, .t-chance.k-corner) .t-icon, .board.radial.simple .tile.side-l:not(.flip):not(.t-deal, .t-chance.k-corner) .t-icon { transform: rotate(90deg); }
/* zoomed out: the commentary and the roll prompt sit just under the ring (fit() keeps room there and sets --under-top) */
#ticker.under, #roll-pop.under { top: var(--under-top, auto); bottom: auto; transform: translateX(-50%); transform-origin: 50% 0; }
#roll-pop.under { animation: none; }
body.my-roll:has(#roll-pop.under) .board.radial .dice-tray:not(.docked) { scale: 1.3; }
/* phones: every player's cash and net worth in a strip above the board (you first); the stage starts under it */
#hud { display: none; }
body:is(.mobile, .bar) #hud { display: flex; gap: 6px; }
.hud-p { flex: 1 1 0; min-width: 0; display: flex; align-items: center; gap: 6px; padding: 5px 7px; border-radius: var(--r-md);
  transition: box-shadow .3s; }
.hud-p.out { opacity: .45; }
.hud-p .ptoken { width: 26px; height: 26px; box-shadow: inset 0 5px 0 rgba(255, 255, 255, .35), 0 2px 0 color-mix(in srgb, var(--pc) 60%, #000); }
.hud-txt { display: grid; min-width: 0; line-height: 1.1; }
.hud-txt small { font: 800 9px/1.1 var(--font); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hud-txt b { font: 800 15px/1.1 var(--font); font-variant-numeric: tabular-nums; }
.hud-txt b.neg { color: #ff6b6b; }
.hud-txt i { font: 700 9px/1.15 var(--font); font-style: normal; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body.night .hud-txt b { color: var(--night-fg); }
/* four players: tighter cards so each cash figure still fits */
#hud:has(> :nth-child(4)) { gap: 4px; padding-inline: 6px; }
#hud:has(> :nth-child(4)) .hud-p { gap: 4px; padding: 5px; }
#hud:has(> :nth-child(4)) .ptoken { display: none; } /* the card takes its player's tint instead */
#hud:has(> :nth-child(4)) .hud-p { background: color-mix(in srgb, var(--pc) 22%, transparent); }
#hud:has(> :nth-child(4)) .hud-txt b { font-size: 13px; }
.hud-txt { overflow: hidden; }
/* card view: the tapped dial is the spotlit one — its ring stays lit, the others step back */
.hud-p.spot { box-shadow: inset 0 0 0 2px var(--pc), 0 0 18px 0 var(--pc); background: color-mix(in srgb, var(--pc) 28%, transparent); }
#hud:has(.spot) .hud-p:not(.spot) { opacity: .55; }
/* the spotlight on the ring: that player's properties stay bright (a glow in their colour), the rest go dim */
.board.spot .tile:not(.lit), .board.spot .sign-host:not(.lit) { filter: saturate(.25) brightness(.45); }
.board.spot .tile.lit { filter: brightness(1.12) drop-shadow(0 0 6px var(--spot, rgba(255, 244, 234, .7))); }
/* the Deal window does the same: only the two sides' tiles stay bright (no filter on those: their lots on the table
   animate, and a filter over an animation is redrawn every frame) */
.board.trade-spot .tile:not(.party), .board.trade-spot .sign-host:not(.party) { filter: saturate(.25) brightness(.45); }
/* the jail's board-level pieces (signs, cell, bars) dim with the ring in either view */
.board:is(.spot, .trade-spot) :is(.jail-plaque, .jail-visit, .jail-cell, .jail-bars) { filter: saturate(.25) brightness(.45); }
/* Reset camera: a round glass undo-arrow button at the top of the stage, only while the view is swiped off or on someone else */
.cam-reset { position: absolute; z-index: 7; top: 10px; left: 50%; display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%;
  background: var(--glass); color: var(--ink); -webkit-tap-highlight-color: transparent;
  box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 18px -8px rgba(0, 0, 0, .6); cursor: pointer;
  opacity: 0; pointer-events: none; transform: translate(-50%, -8px) scale(.94);
  transition: opacity .2s, transform .25s var(--ease-out); zoom: var(--ui-scale, 1); }
body.night .cam-reset { color: var(--night-fg); }
.cam-reset .ic { width: 20px; height: 20px; }
.cam-reset.show { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.cam-reset:active { transform: translate(-50%, 1px) scale(.96); }
/* phones: tucked under the docked die in the top right (die box 66px tall at top+18; room left for it growing on your roll) */
body:is(.mobile, .bar) .cam-reset { top: calc(var(--safe-top) + 112px); left: auto; transform: translateY(-8px) scale(.94); }
body:is(.mobile, .bar) .cam-reset.show { transform: none; }
/* phones: the same chunky round button as Menu (sunset / sun face, black bezel), centred under the die
   (die box 66px wide at right 18 → centre at 51; the 48px button's right edge at 51 − 24 = 27) */
body:is(.mobile, .bar) .cam-reset { right: 27px; width: 48px; height: 48px; transform-origin: 50% 0;
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .6); }
body:is(.mobile, .bar) .cam-reset .ic { width: 24px; height: 24px; }
body:is(.mobile, .bar) .cam-reset:active { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), 0 1px 0 var(--ink); }
/* the Zoom switch, in the app's own style: a glass pill, label then a chunky track that fills with the sunset
   (night) or sun (day) gradient when on, and a raised white knob with the ink edge */
.zoom-toggle { gap: 9px; padding: 6px 6px 6px 14px; border-radius: 99px; font: 800 15px/1 var(--font); letter-spacing: .02em; -webkit-tap-highlight-color: transparent; }
body.night .zoom-toggle { background: var(--glass); color: var(--night-fg); box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 18px -8px rgba(0, 0, 0, .6); }
body:not(.night) .zoom-toggle { background: var(--glass); color: var(--ink); box-shadow: inset 0 0 0 1px var(--glass-line), 0 6px 18px -8px rgba(20, 60, 110, .45); }
.zoom-toggle:focus-visible { outline: 2px solid var(--pc, #f0775f); outline-offset: 2px; }
.zoom-toggle { padding-left: 11px; }
.zoom-toggle > .ic { width: 20px; height: 20px; flex: none; }
/* zoomed out: the roll prompt drops to the bottom of the screen; the commentary stays just under the ring */
#roll-pop.under { top: auto; bottom: calc(var(--safe-bottom) + 22px); }
#stage-wrap:has(#roll-pop.under) #ticker.under { visibility: visible; }
/* the bar over the stage: players (phones) and the zoom button, which always sits off the board — the stage starts
   under the bar. The button is a plain round icon button: a camera to zoom in, a globe (zoomed in) to zoom back out. */
#topbar { position: absolute; z-index: 8; left: 0; right: 0; top: 0; display: flex; align-items: center; gap: 6px;
  padding: calc(var(--safe-top) + 8px) 8px 6px; pointer-events: none; }
#topbar > * { pointer-events: auto; }
body:is(.mobile, .bar) #hud { flex: 1 1 auto; min-width: 0; }
#cam-slot { margin-left: auto; display: flex; }
#stage { top: calc(var(--safe-top) + 62px); }
#topbar .zoom-toggle { position: static; display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border-radius: 50%; gap: 0; }
#topbar .zoom-toggle .ic { width: 24px; height: 24px; }
.zoom-toggle > .ic:last-child, .zoom-toggle.on > .ic:first-child { display: none; }
.zoom-toggle.on > .ic:last-child { display: block; }
body.night #topbar .zoom-toggle { box-shadow: 0 4px 0 var(--sunset-side); }
body:not(.night) #topbar .zoom-toggle { box-shadow: 0 4px 0 var(--sun-side); }
#topbar .zoom-toggle:active { transform: translateY(3px); }
body.night #topbar .zoom-toggle:active { box-shadow: 0 1px 0 var(--sunset-side); }
body:not(.night) #topbar .zoom-toggle:active { box-shadow: 0 1px 0 var(--sun-side); }
/* rent this turn, on the players' cards: + green coming in, − red going out (cleared when the turn passes) */
.pcard, .hud-p { position: relative; }
.delta { position: absolute; top: -7px; right: 6px; z-index: 2; padding: 2px 7px; border-radius: 99px; font: 800 13px/1.2 var(--font);
  font-style: normal; color: #fff; box-shadow: 0 2px 0 rgba(0, 0, 0, .35); --from: translateY(6px) scale(.8); animation: enter .35s var(--ease-out); }
.delta.pos { background: var(--good); }
.delta.neg { background: var(--bad); }
.hud-p .delta { top: -6px; right: 4px; font-size: 11px; z-index: 4; } /* above the jail bars (3 with the sign, 2 for the bars) */
@media (prefers-reduced-motion: reduce) { .delta { animation: none; } }
/* ---------- phones: money and narration live under the board ----------
   zoomed out the bar sits just under the ring (--under-top); zoomed in it runs along the bottom and the stage stops
   above it. Row 1: every player's cash and worth. Row 2: Menu · the narration · the camera. */
#menu-tab .mi { display: none; }
#narr { display: flex; align-items: center; gap: 8px; margin-left: auto; }
#narr-menu:empty, #narr-text:empty { display: none; }
body.mobile #stage { top: var(--safe-top); }
body.pov-frame.mobile #stage { top: 0; }
body:is(.mobile, .bar) #topbar { top: auto; bottom: var(--safe-bottom); flex-direction: column; align-items: stretch; padding: 8px; }
body:is(.mobile, .bar) #topbar.under { top: var(--under-top); bottom: auto; padding-top: 4px; }
body:is(.mobile, .bar) #narr { margin: 0; }
body:is(.mobile, .bar) #narr-text { flex: 1 1 auto; min-width: 0; display: flex; justify-content: center; }
body:is(.mobile, .bar) #narr-text #ticker { position: static; transform: none; max-width: 100%; text-align: center; }
body:is(.mobile, .bar) #narr-text #ticker span { display: inline-block; max-width: 100%; white-space: normal; line-height: 1.25; }
body:is(.mobile, .bar) #narr-menu #menu-tab { position: static; transform: none; display: grid !important; place-items: center; width: 48px; height: 48px;
  padding: 0; border-radius: 50%; flex-direction: row; gap: 0; color: #2a0f24; }
body:is(.mobile, .bar) #narr-menu #menu-tab :is(.chev, .lbl) { display: none; }
body:is(.mobile, .bar) #narr-menu #menu-tab .mi { display: block; width: 24px; height: 24px; }
body:is(.mobile, .bar).night #narr-menu #menu-tab { box-shadow: 0 4px 0 var(--sunset-side); }
body:is(.mobile, .bar):not(.night) #narr-menu #menu-tab { box-shadow: 0 4px 0 var(--sun-side); }
body:is(.mobile, .bar) #narr-menu #menu-tab:active { transform: translateY(3px); }
/* the roll prompt: the bottom of the screen zoomed out (under the bar); zoomed in, just above the bar */
body:is(.mobile, .bar) #roll-pop.under { bottom: calc(var(--safe-bottom) + 16px); }
/* phones, zoomed in: the stage keeps the whole screen; the bar is a solid panel at the bottom — or at the top while
   the view is on the top half of the ring — and fit() centres the view in the rest. A swipe hides every control. */
body.mobile #stage-wrap.zoomed #stage { bottom: 0; overflow: visible; }
#topbar { transition: opacity .2s ease-out; } /* the others keep their own transitions; they just blink out */
@media (prefers-reduced-motion: reduce) { #topbar { transition: none; } }
/* the buy prompt always sits in the middle of the screen (no post down to the tile) */
#buy-pop { left: 50% !important; top: 50% !important; transform: translate(-50%, -50%); transform-origin: 50% 50%; --from: translate(-50%, -50%) scale(.85); animation: enter .4s var(--ease-out); }
#buy-pop::after { display: none; }
@media (prefers-reduced-motion: reduce) { #buy-pop { animation: none; } }
/* phone bar order: the camera line (camera left · narration · Menu right) first, the money counters under it */
body:is(.mobile, .bar) #narr { order: 0; }
body:is(.mobile, .bar) #hud { order: 1; }
body:is(.mobile, .bar) #cam-slot { order: 0; margin-left: 0; }
body:is(.mobile, .bar) #narr-text { order: 1; }
body:is(.mobile, .bar) #narr-menu { order: 2; }
/* no panel behind the bar, by day as by night: the counters and buttons sit straight on the board. (A day-only white
   panel used to outrank this rule and wash out the tiles under the bar: zoomed in, the ones just ahead of your token.) */
body:is(.mobile, .bar) #stage-wrap.zoomed #topbar { background: none; box-shadow: none; }
/* phones zoomed in, bar along the bottom (view on the bottom half): the docked die moves to the top-right corner, clear of it */
/* zoomed in, the roll prompt sits in the middle of the screen (like the buy prompt) */
#stage-wrap.zoomed #roll-pop, body.mobile #stage-wrap.zoomed #roll-pop {
  top: 50%; bottom: auto; transform: translate(-50%, -50%); }
#stage-wrap.zoomed #roll-pop { --from: translate(-50%, -50%) scale(.85); animation: enter .4s var(--ease-out); }
/* the phone's safe areas: a real iPhone reports them; a POV phone frame stands in for the status bar + Dynamic Island
   (top) and the home indicator (bottom). The game fills the whole screen; only the controls keep clear of them. */
:root { --safe-top: env(safe-area-inset-top, 0px); --safe-bottom: env(safe-area-inset-bottom, 0px); --ink: #151a33; --util-txt: var(--ink); --good: #157a3a; --bad: #c8102e; --focus: var(--ink); --r-sm: 8px; --r-md: 12px; --r-lg: 22px; --ease-out: cubic-bezier(.16, 1, .3, 1); --ease-camera: cubic-bezier(.65, 0, .35, 1); --z-modal: 50; --z-float: 55; --z-finger: 90; --z-loader: 100; --z-confirm: 70; --z-overlay: 68; }
body.pov-frame { --safe-top: 54px; --safe-bottom: 30px; }
body.mobile #stage, body.pov-frame.mobile #stage { top: 0; }
body.pov-frame #side { padding-top: var(--safe-top); box-sizing: border-box; }
/* net-worth cards get the board's 3D bevel and a solid dark face, so they read over any part of the sky (the orange
   sunset at the bottom included): ink edge, light top lip, a darker underside and a drop below */
.hud-p { background: rgba(20, 24, 52, .9) !important;
  box-shadow: 0 0 0 1.5px var(--ink), inset 0 1.5px 0 rgba(255, 255, 255, .22), inset 0 -3px 0 rgba(0, 0, 0, .35), 0 4px 0 var(--ink), 0 8px 16px -6px rgba(0, 0, 0, .6); }
#hud:has(> :nth-child(4)) .hud-p { background: color-mix(in srgb, var(--pc) 24%, rgba(20, 24, 52, .92)) !important; }
.hud-p .hud-txt b, .hud-p .hud-txt small, .hud-p .hud-txt i { color: #fff4ea; }
.hud-p .hud-txt i, .hud-p .hud-txt small { color: rgba(255, 244, 234, .72); }
.hud-p .hud-txt b.neg { color: #ff6b6b; }
/* ---------- phones: the menu is a bottom sheet — it rises to ~80% of the screen and sinks back down; an X closes it
   (the Menu button hides while it is open) ---------- */
.sheet-x { display: none; }
body.mobile.watching.menu-open #side {
  top: auto; left: 0; right: 0; bottom: 0; width: auto; height: 80dvh; border-radius: var(--r-lg) var(--r-lg) 0 0;
  padding-bottom: var(--safe-bottom); box-shadow: 0 -18px 50px -20px rgba(0, 0, 0, .6), inset 0 1px 0 var(--glass-line, rgba(255, 255, 255, .14));
  animation: sheetUp .38s var(--ease-out); }
body.pov-frame.mobile.watching.menu-open #side { padding-top: 0; }
body.mobile.watching.menu-open.menu-closing #side { animation: sheetDown .28s cubic-bezier(.55, 0, .75, .2) forwards; }
@keyframes sheetDown { to { transform: translateY(100%); } }
body:is(.mobile, .bar).menu-open #menu-tab { display: none !important; }
body:is(.mobile, .bar) .sheet-x { display: grid; place-items: center; width: 40px; height: 40px; margin-left: 4px; padding: 0; border: 0; border-radius: 50%;
  cursor: pointer; color: var(--night-fg, #fff4ea); background: rgba(255, 255, 255, .1); box-shadow: inset 0 0 0 1px var(--glass-line, rgba(255, 255, 255, .14)); }
body:is(.mobile, .bar):not(.night) .sheet-x { color: var(--ink); background: rgba(255, 255, 255, .6); }
body:is(.mobile, .bar) .sheet-x .ic { width: 20px; height: 20px; }
body:is(.mobile, .bar) .sheet-x:active { transform: scale(.92); }
body.mobile .head-btns { align-items: center; }
/* a grab handle on the sheet's top edge */
body.mobile.watching.menu-open #side::before { content: ''; position: sticky; top: 0; align-self: center; flex: none; width: 44px; height: 5px;
  margin: 8px auto -2px; border-radius: 99px; background: rgba(255, 255, 255, .3); }
@media (prefers-reduced-motion: reduce) { body.mobile.watching.menu-open #side, body.mobile.watching.menu-open.menu-closing #side { animation: none; } }
body:is(.mobile, .bar).menu-open #narr-menu #menu-tab, body:is(.mobile, .bar).menu-open:has(#roll-pop) #menu-tab { display: none !important; }
body.mobile .side-head { display: flex; flex-wrap: nowrap; align-items: center; gap: 8px; }
body.mobile .side-head .logo-sm { font-size: 24px; flex: none; }
body.mobile .side-head .head-btns { margin-left: auto; display: flex; gap: 6px; flex-wrap: nowrap; }
/* Chance: the cards fill the whole window — 15 face-up options in three columns of tall cards; the drawn card turns
   over in the middle, on top of them, and Okay sits along the bottom */
.backdrop[data-kind="card"] { padding: calc(var(--safe-top) + 12px) 12px calc(var(--safe-bottom) + 12px); }
body .modal.card { zoom: 1; display: flex; flex-direction: column; padding: 14px; overflow: hidden; }
.modal.card > .modal-body { flex: 1; position: relative; display: grid; grid-template-rows: 1fr auto; gap: 14px; justify-items: stretch; }
.modal.card .pick-card.open { min-height: 0; aspect-ratio: auto; padding: 10px 8px; border-radius: 14px; gap: 6px; }
.modal.card .pick-card.open small { font-size: clamp(8px, 1.1vmin + 4px, 12px); }
.modal.card .pick-card.open b { font-size: clamp(12px, 1.6vmin + 6px, 20px); line-height: 1.2; }
.modal.card .chance-card { position: absolute; inset: 0 0 64px; z-index: 3; }
.modal.card > .modal-body > .btn { justify-self: center; min-width: 200px; }
@media (min-width: 900px) and (min-height: 760px) { .modal.card .chance-card { zoom: 1.6; } .modal.card > .modal-body > .btn { zoom: 1.3; } }
/* zoomed out, the buy prompt takes the roll prompt's place at the bottom of the screen (zoomed in it stays centred) */
#stage-wrap:not(.zoomed) #buy-pop { top: auto !important; --from: translateX(-50%) translateY(24px) scale(calc(var(--fit, 1) * .92)); animation: enter .4s var(--ease-out); }
@media (prefers-reduced-motion: reduce) { #stage-wrap:not(.zoomed) #buy-pop { animation: none; } }
/* phones zoomed in: the docked die sits on the side of the board being looked at (right half: right, left half:
   left), at the screen end away from the bar */
/* the buy countdown gets the board's bevel and outlined digits so it reads over any tile colour */
.bp-timer { background: var(--ink) !important; color: #fff !important; font-family: var(--font); font-weight: 800;
  box-shadow: 0 0 0 2px var(--pc, #f0775f), inset 0 1.5px 0 rgba(255, 255, 255, .25), inset 0 -3px 0 rgba(0, 0, 0, .4), 0 3px 0 var(--ink) !important; }
.bp-timer .countdown { color: #fff; }
.bp-timer .countdown.low { color: #ff6b6b; }
/* sign view: signs grow by --sign-s (fitSigns: as big as they go without two touching), and their words get a dark
   outline — white letters with an ink bevel read on every tile colour */
.board.radial.upright .sign :is(.s-name, .s-price, .s-big) { color: #fff; -webkit-text-stroke: 2.2px var(--ink); paint-order: stroke fill;
  text-shadow: 0 1px 0 var(--ink); }
.board.radial.upright .sign .s-big { -webkit-text-stroke-width: 3.5px; text-shadow: 0 1.5px 0 var(--ink); }
.board.radial.upright .sign .ic { filter: drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 0 .8px var(--ink)); }

/* sign view: the signs live on their own layer above every tile (and below the pawns), so a grown sign is never
   tucked under its neighbour's wedge. Each sits in a .sign-host that carries its tile's classes and colours. */
.board.radial .signs { position: absolute; inset: 0; pointer-events: none; transform: rotate(var(--rot)); }
.board.radial .sign-host { position: absolute; width: 0; height: 0; }
.board.radial.upright .sign-host .sign { top: 0 !important; left: 0; }
/* the For sale strip gets the same bevel as the sign: outlined letters, a light lip and a darker foot */
.board.radial.upright .sign.for-sale::before { font-size: 6px; -webkit-text-stroke: 1.6px #5a0718; paint-order: stroke fill;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4), inset 0 -1.5px 0 rgba(0, 0, 0, .35), 0 0 0 1px var(--ink); } /* rounded all round, the black edge included */
/* thinner sign bezels: a 1.4px ink edge and a fine light rim inside it */
.board.radial.upright .sign { box-shadow: inset 0 0 0 1.4px var(--ink), 0 2px 0 rgba(0, 0, 0, .25), 0 4px 10px -4px rgba(0, 0, 0, .45); }
.board.radial.upright .sign.for-sale::before { left: 1.6px; right: 1.6px; top: 1.6px; }
/* sign view: one type size for every sign — each box fits its own words (up to its old width, so long names still
   wrap), and the whole set scales together by --sign-s, about each sign's own centre */
.board.radial.upright .sign { scale: none; width: max-content; max-width: 50px; height: auto; min-height: 0; }
.board.radial.upright .k-corner .sign { max-width: 66px; }
.board.radial.upright .sign-host .sign { transform: translate(-50%, -50%) rotate(calc(-1 * var(--rot))) scale(var(--sign-s, 1)); }
/* every (non-Visiting) sign's box fits its words, whatever older per-kind sizes said; a For sale sign stays wide
   enough for its strip to read on one line */
.board.radial.upright .sign-host .sign:not(.visiting) { width: max-content !important; height: auto !important; min-height: 0 !important; max-width: 50px; }
.board.radial.upright .sign-host.k-corner .sign:not(.visiting) { max-width: 66px; }
.board.radial.upright .sign-host .sign.for-sale { min-width: 42px; }
.board.radial.upright .sign.for-sale::before { white-space: nowrap; }
/* night globe: the continents' outline glows neon — the sunset neon (amber → coral → magenta → violet, top to bottom
   of the globe) traced along the coast, with a soft glow spilling onto the sea */
/* the coast neon in hot magenta — it stands off both the peach land and the violet sea — with a pale core glow and a
   wide magenta bloom */
body.night .map .land { stroke: #ff4fd8 !important; stroke-width: 2.4px !important;
  filter: drop-shadow(0 0 1px #ffd6f6) drop-shadow(0 0 3px #ff4fd8) drop-shadow(0 0 9px rgba(255, 60, 200, .65)) !important; }
/* signs a touch leaner inside so they fit their tiles at a larger size */
.board.radial.upright .sign-host .sign:not(.visiting) { padding: 3px 3px; row-gap: 0; }
.board.radial.upright .sign-host .sign.for-sale { padding-top: 10px; }
/* continents get the tiles' 3D bevel: the pressed-out side below (.land-side), a light lip just inside the top edges
   and a darker shade inside the bottom edges (both clipped to the land), then the coastline drawn over all of it —
   ink by day, neon at night */
.map .land-bevel { pointer-events: none; }
.map .land-lip { fill: none; stroke: rgba(255, 255, 255, .55); stroke-width: 2.6px; stroke-linejoin: round; }
.map .land-shade { fill: none; stroke: rgba(30, 37, 64, .28); stroke-width: 4px; stroke-linejoin: round; }
.map .coast { fill: none; stroke: var(--ink); stroke-width: 2.6px; stroke-linejoin: round; pointer-events: none; }
body.night .map .coast { stroke: #ff4fd8; stroke-width: 2.4px; filter: drop-shadow(0 0 1px #ffd6f6) drop-shadow(0 0 3px #ff4fd8) drop-shadow(0 0 9px rgba(255, 60, 200, .65)); }
body.night .map path.land, body:not(.night) .map path.land { stroke: transparent !important; filter: none !important; }
/* sign view: tax and Go to jail tiles carry no sign — their words run along the tile (radially), reading left to
   right: turned one way on the right half of the ring, the other way on the left half (.bflip) */
.board.radial .rlabel { display: none; }
.board.radial.upright:not(.simple) .rlabel { display: grid; justify-items: center; gap: 1px; position: absolute; left: 50%; z-index: 2; pointer-events: none; text-transform: uppercase; color: #fff; text-align: center; }
.board.radial.upright:not(.simple) .tile.bflip .rlabel { transform: translate(-50%, -50%) rotate(90deg); }
.board.radial .rlabel b { font: 800 8px/1 var(--font); letter-spacing: .02em; -webkit-text-stroke: 2.2px var(--ink); paint-order: stroke fill; }
.board.radial .rlabel span { font: 800 10px/1 var(--font); -webkit-text-stroke: 2.6px var(--ink); paint-order: stroke fill; }
/* by day the tax and Busted faces are white, so the white letters only showed as their ink outline (1:1 against the
   face): they turn ink, with no outline to thicken them */
body:not(.night) .board.radial.upright .rlabel { color: var(--ink); }
body:not(.night) .board.radial .rlabel :is(b, span) { -webkit-text-stroke-width: 0; }
.board.radial.upright .sign-host:is(.t-tax, .t-gotojail) { display: none; }
/* the run-along labels wrap to two lines when the name is longer than the tile's free length */
.board.radial.upright:not(.simple) .rlabel { white-space: normal; width: max-content; }
.board.radial .rlabel b { text-wrap: balance; line-height: 1.1; }
.board.radial .rlabel span { white-space: nowrap; }
/* run-along labels take their tile icon's turn exactly (see .tile-ic): upright with the foot outward on the bottom half,
   turned round on the top half, a quarter turn beside Deal and Chance — and the matching width limit */
.board.radial.upright:not(.simple) .rlabel { transform: translate(-50%, -50%) rotate(180deg); max-width: var(--run-wid); }
.board.radial.upright:not(.simple) .tile:not(.flip) .rlabel { transform: translate(-50%, -50%) rotate(0deg); }
.board.radial.upright:not(.simple) .tile.side-r .rlabel { transform: translate(-50%, -50%) rotate(-90deg); max-width: var(--run-len); }
.board.radial.upright:not(.simple) .tile.side-l .rlabel { transform: translate(-50%, -50%) rotate(90deg); max-width: var(--run-len); }
/* (the same four turns again, ranked above the older left/right .bflip rule) */
/* (the turned labels also shrink by --rl-s, set by fitRLabels so each stays inside its tile) */
.board.radial.upright:not(.simple) .tile.tile.flip .rlabel { transform: translate(-50%, -50%) rotate(180deg) scale(var(--rl-s, 1)); }
.board.radial.upright:not(.simple) .tile.tile:not(.flip) .rlabel { transform: translate(-50%, -50%) rotate(0deg) scale(var(--rl-s, 1)); }
.board.radial.upright:not(.simple) .tile.tile.tile.side-r .rlabel { transform: translate(-50%, -50%) rotate(-90deg) scale(var(--rl-s, 1)); }
.board.radial.upright:not(.simple) .tile.tile.tile.side-l .rlabel { transform: translate(-50%, -50%) rotate(90deg) scale(var(--rl-s, 1)); }
/* GO, Chance and Deal signs carry their own --sign-s (on the sign itself); Deal's sign runs wide: handshake beside the word */
.board.radial.upright .sign-host.t-deal .sign { grid-auto-flow: column; align-items: center; column-gap: 5px; padding: 4px 8px; }
/* GO's sign stacks (GO over its arrow, then the salary) so it is narrow enough to sit lower on its upright tile */
.board.radial.upright .sign-host.t-go .sign .s-row { flex-direction: column; gap: 2px; }
.board.radial.upright .sign-host.t-go .sign { padding: 4px 6px; }
/* Deal and Chance signs carry just their word — no handshake, no "?" */
.board.radial.upright .sign-host.t-deal .sign .ic, .board.radial.upright .sign-host.t-chance .sign .s-big { display: none; }
/* the Chance sign gets more room around its word */
.board.radial.upright .sign-host.t-chance .sign { padding: 6px 10px !important; }
/* GO's direction arrow stands on its own: no white disc behind it, white with the signs' dark outline */
.board.radial.upright .sign .s-dir { background: none !important; box-shadow: none !important; color: #fff !important; }
.board.radial.upright .sign .s-dir .ic { filter: drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 0 .8px var(--ink)) drop-shadow(0 1px 0 var(--ink)); }
/* city signs: more room around their words */
.board.radial.upright .sign-host:not(.k-corner):not(.t-chance) .sign:not(.visiting) { padding: 5px 6px; }
.board.radial.upright .sign-host:not(.k-corner):not(.t-chance) .sign.for-sale { padding-top: 12px; }
/* transport signs: tall and near-square on upright tiles, long and low (name beside price) on the side tiles */
.board.radial.upright .sign-host .sign.s-tall { min-height: 48px !important; align-content: center; }
.board.radial.upright .sign-host .sign.s-wide { align-items: center; column-gap: 5px; }
/* utility signs: an upside-down triangle — For sale along the long top edge, the name under it, the icon in the
   middle, the price down towards the point. The ink edge is the sign itself; the face is a slightly smaller triangle. */
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) { max-width: none !important; flex-direction: column; align-items: center; gap: 1px; isolation: isolate; border-radius: 0; }
.board.radial.upright .sign-host.t-utility .sign::after { content: ''; position: absolute; inset: 1.6px 1.6px 3px; z-index: -1;
  background: color-mix(in srgb, var(--face, #fff) 88%, #000); clip-path: polygon(0 0, 100% 0, 50% 100%); }
.board.radial.upright .sign-host.t-utility.owned .sign::after { background: var(--owner); }
.board.radial.upright .sign-host.t-utility .sign .s-name { text-align: center; }
/* utility triangles, tighter around their words so they can grow */
/* the long transport signs keep name over price, just laid out wide and low */
.board.radial.upright .sign-host .sign.s-wide { grid-auto-flow: row; }
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) { padding-bottom: 20px !important; }
/* utility triangles drawn as rounded SVG layers (ink edge, thin light rim, face) behind the words — like the other
   signs' bevel — instead of a hard clip */
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) {
  background: none !important; clip-path: none; box-shadow: none !important; }
.board.radial.upright .sign-host.t-utility .sign::after { display: none; }
.board.radial .sign .tri { display: none; }
.board.radial.upright .sign-host.t-utility .sign .tri { display: block; position: absolute; width: 100%; height: 100%; z-index: -1; overflow: visible; }
.board.radial .tri polygon { stroke-linejoin: round; }
.board.radial .tri-ink { fill: var(--ink); stroke: var(--ink); }
.board.radial .tri-rim { fill: rgba(255, 255, 255, .55); stroke: rgba(255, 255, 255, .55); }
.board.radial .tri-face { fill: color-mix(in srgb, var(--face, #fff) 88%, #000); stroke: color-mix(in srgb, var(--face, #fff) 88%, #000); }
.board.radial .sign-host.owned .tri-face { fill: var(--owner); stroke: var(--owner); }
.board.radial .tri { filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .25)); }
/* utility triangles: wide and shallow (the obtuse angle at the bottom point) — strip and name in the wide top,
   icon beside price below them */
.board.radial.upright .sign-host.t-utility .sign .s-row { flex-direction: row; gap: 3px; }
/* utility triangles: snug around their words at the city signs' type size — strip, name, then icon and price */
/* the utility triangles' For sale strip is the same 3D pill as on the other signs: ink edge, light lip, dark foot */
.board.radial.upright .sign-host.t-utility .sign.for-sale::before { border-radius: 99px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4), inset 0 -1.5px 0 rgba(0, 0, 0, .35), 0 0 0 1px var(--ink); }
/* the triangles end up a little smaller than the city signs on most tiles, so their words are set a size up */
/* transport signs: price on the left, icon on the right */
.board.radial.upright .sign-host.t-transport .sign .s-row { flex-direction: row-reverse; }
/* utility signs: the words are laid out like any city sign (same size, same outline) — the triangle (.tri, sized and
   angled by fitSigns) is drawn round them, and the icon drops into its point (--tip) with the price left in the middle */
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) { width: max-content !important; height: auto !important;
  display: grid; justify-items: center; align-content: center; overflow: visible; }
.board.radial.upright .sign-host.t-utility .sign.for-sale::before { font-size: 5.6px; height: 8px; line-height: 8px; }
.board.radial.upright .sign-host.t-utility .sign .tri { inset: auto; }
.board.radial.upright .sign-host.t-utility .sign .s-row .ic { position: absolute; left: 50%; top: var(--tip, 40px); transform: translate(-50%, -50%); }
/* utility triangles: the price a little lower (towards the middle), the icon bigger and a little up from the point */
/* utility triangles, compact: the For sale pill rides on the triangle's top edge (not inside it), the words hug the
   top, and the 16px icon sits in the point */
.board.radial.upright .sign-host.t-utility .sign.for-sale { padding-top: 5px !important; }
.board.radial.upright .sign-host.t-utility .sign.for-sale::before { left: 50%; right: auto; width: 40px; top: -7px; transform: translateX(-50%); z-index: 1; }
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) { padding: 4px 3px !important; }
.board.radial.upright .sign-host.t-utility .sign .s-row { margin-top: 2px; }
/* Taxi Company: one word a line */
.board.radial.upright .sign-host.t-transport .sign.s-wide .s-name { max-width: 44px; text-wrap: balance; }
.board.radial.upright .sign-host.t-utility .sign .s-name { text-wrap: balance; } /* Natural Gas on two lines keeps its triangle narrow */
/* utility triangles: readability first — their words a size up from the city signs' */
/* utility triangles (final layout): the name is the sign's only in-flow line — city-sign size — the price sits midway
   between it and the icon (--price-y), the icon in the point (--tip), both centred on the triangle */
.board.radial.upright .sign-host.t-utility .sign .s-name { font-size: 6.8px; max-width: 44px; }
.board.radial.upright .sign-host.t-utility .sign .s-price { font-size: 8px; position: absolute; left: 50%; top: var(--price-y, 20px); transform: translate(-50%, -50%); white-space: nowrap; }
.board.radial.upright .sign-host.t-utility .sign .s-row { margin: 0; }
.board.radial.upright .sign-host.t-utility .sign .s-row .ic { width: 13px; height: 13px; }
/* every sign's words centred: each line centred across the sign, and the rows (icon + price) centred too */
.board.radial.upright .sign { text-align: center; justify-items: center; }
.board.radial.upright .sign .s-name { display: block; width: 100%; text-align: center; }
.board.radial.upright .sign .s-row { justify-content: center; justify-self: center; }
.board.radial.upright .sign { justify-content: center; } /* a short name (Water, Power) on a sign held wider by its For sale strip stays centred */
.board.radial.upright .sign-host.t-utility .sign:not(.visiting) { justify-content: center !important; } /* (beats the old flex-start from the first triangle layout) */
/* For sale signs: round top corners on the sign's black bezel too (they were squared off where the strip sits) */
.board.radial.upright .sign-host .sign.for-sale:not(.visiting) { border-radius: 7px !important; }
.board.radial.upright .sign.for-sale::before { border-radius: 4.5px; }
/* rectangular For sale signs: the strip (and its 1px ink ring) sits far enough in, with a radius following the sign's
   7px corners, that no black corner pokes out past the sign's rounded edge */
.board.radial.upright .sign-host:not(.t-utility) .sign.for-sale::before { left: 3px; right: 3px; top: 3px; border-radius: 4px; }
/* phones zoomed in: the die always docks in the top-right corner (the bar is always along the bottom) */
body:is(.mobile, .bar) #stage-wrap.zoomed .dice-tray.docked { left: auto !important; right: 18px !important; bottom: auto !important; top: calc(var(--safe-top) + 18px) !important; }
/* an owned tile's inner bezel (the strip between the tile's inner edge and its face) takes the band's colour, darker */
.board.radial .w-band-bezel { display: none; }
.board.radial .w-band-bezel.on { display: block; fill: color-mix(in srgb, var(--bc) 62%, #000); }
/* the little range dice on the inner rim get the black bezel too (day and night), like the big die */
.range .rn rect, body.night .range .rn rect { stroke: var(--ink); stroke-width: 1.6px; }
.range .rn { filter: drop-shadow(0 1px 0 var(--ink)); }
/* the camera (zoom) and Menu buttons get the board's black bezel: ink ring, light top lip, darker foot */
body.night #topbar .zoom-toggle, body.mobile.night #narr-menu #menu-tab {
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .6); }
body:not(.night) #topbar .zoom-toggle, body.mobile:not(.night) #narr-menu #menu-tab {
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .5), inset 0 -3px 0 rgba(0, 0, 0, .2), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .5); }
body #topbar .zoom-toggle:active, body.mobile #narr-menu #menu-tab:active { box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), 0 1px 0 var(--ink); }
/* phones, zoomed in: no roll pop-up in the middle — just its Roll button, tucked under the die in the top-right corner */
body:is(.mobile, .bar) #stage-wrap.zoomed #roll-pop { bottom: auto !important; left: auto !important; transform: translateX(50%) !important; width: auto; min-width: 0; padding: 0; gap: 0;
  background: none !important; box-shadow: none !important; animation: none; }
body:is(.mobile, .bar) #stage-wrap.zoomed #roll-pop :is(.rp-head, .rp-note) { display: none; }
body:is(.mobile, .bar) #stage-wrap.zoomed #roll-pop .rp-btns .btn { min-width: 0 !important; padding: 10px 20px !important; font-size: 20px !important; }
/* (measured: on your roll the docked die spans 90px, 18px in from the right) — the Roll button centred 12px under it */
body:is(.mobile, .bar) #stage-wrap.zoomed #roll-pop { top: calc(var(--safe-top) + 118px) !important; right: calc(18px + 45px); }
/* phones: the bar along the bottom keeps a clear gap above the phone's bottom edge (home indicator included) */
/* small view (phone, zoomed out): every title, price and rent reads in white with the board's dark outline, and the
   rent signs get the black bezel (ink ring, light lip, dark foot) */
.board.radial.simple .tile :is(.t-name, .t-price, .t-big, .t-q, .visit, .corner-go small) { color: #fff !important;
  -webkit-text-stroke: 2.6px var(--ink); paint-order: stroke fill; text-shadow: none; }
.board.radial.simple .arc-price { fill: #fff !important; stroke: var(--ink) !important; stroke-width: 4.5px !important; paint-order: stroke fill; stroke-linejoin: round; }
.board.radial.simple .t-price.rent-sign { color: #fff !important; -webkit-text-stroke: 3px var(--ink); paint-order: stroke fill;
  box-shadow: 0 0 0 2px var(--ink), inset 0 1.5px 0 rgba(255, 255, 255, .45), inset 0 -2.5px 0 rgba(0, 0, 0, .3), 0 0 12px 1px var(--owner) !important; }
/* every tile gets the board's ink bezel down its two sides (the radial edges, not the arcs at its ends) — except
   where a tile already has its own border (Deal & Fortune's white, GO & Jail's black) */
.board.radial .w-edges { fill: none; stroke: none; }
.board.radial .tile:not(.t-deal):not(.t-go):not(.t-jail):not(.t-chance.k-corner) .w-edges { stroke: var(--ink); stroke-linecap: round; }
/* the side bezels: thin, and in the tile's own darker shade — the colour of its inner 3D side (.w-side) */
.board.radial .tile:not(.t-deal):not(.t-go):not(.t-jail):not(.t-chance.k-corner) .w-edges { stroke: color-mix(in srgb, var(--face) 65%, var(--ink)); stroke-width: 1.1px; }
/* tap a player's money card: the camera goes to them */
.hud-p[data-act="focus"], .pcard[data-act="focus"] { cursor: pointer; }
/* small view (phone, zoomed out): tile icons sit the same way round as the tile's words — no quarter turn */
.board.radial.simple .tile .t-icon { transform: none !important; }
/* tapping a tile: it sinks like a piano key (pressed in towards the globe, a little darker), then springs back */
/* (the separate `translate` property, so each part keeps its own turn; signs, on their own layer, just darken) */
.board.radial .tile.key-press :is(.wedge, .tile-inner, .tile-ic, .rlabel) { animation: keyPress .32s cubic-bezier(.3, .7, .4, 1); }
/* zoomed out on phones: the buy sign shrinks (--fit, set in renderBuyPop) to the room under the money cards */
#buy-pop { --sb: var(--safe-bottom); }
#stage-wrap:not(.zoomed) #buy-pop { transform: translateX(-50%) scale(var(--fit, 1)); transform-origin: 50% 100%; }
/* behind the page (iPhone full-screen app, rubber-band scrolling; Safari tints its bars from it): the menu's navy while
   the menu shows, the game's sky by day once a game is on screen (night games keep the navy) — the same rule as the
   theme-color meta (main.js applyChrome) */
html { background: #10142c; }
html:has(body:not(.night) #game:not([hidden])) { background: #3f9ee8; }

/* small view: tax and Go to jail words sized to stay inside the tile's edges */
.board.radial.simple .tile:is(.t-tax, .t-gotojail) .t-body { padding: 5px 7px; }
.board.radial.simple .tile:is(.t-tax, .t-gotojail) .t-price { font-size: 13px !important; line-height: 1.05; white-space: normal; }
.board.radial.simple .tile:is(.t-tax, .t-gotojail) .t-price small { font-size: 8px; display: block; }
.board.radial.simple .tile:is(.t-tax, .t-gotojail) .t-name { font-size: 9px !important; line-height: 1.05; }
/* small view: Deal and Chance show their word again — level, as a sign in their own style (face colour, ink bezel,
   light rim, white outlined letters) — beside the icon, which keeps its place at the tile's outer end */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .t-big { display: inline-block !important; flex: none; font: 500 17px/1 var(--font); color: #fff; -webkit-text-stroke: 2.6px var(--ink); paint-order: stroke fill; }
/* money cards: the player who's up keeps the same bezel and foot as the others, their colour ringed just inside it */
.hud-p.up { box-shadow: 0 0 0 1.5px var(--ink), inset 0 0 0 2px var(--pc), inset 0 1.5px 0 rgba(255, 255, 255, .22), inset 0 -3px 0 rgba(0, 0, 0, .35), 0 4px 0 var(--ink) !important; }
/* money cards and narration: outlined letters, like the board's */
/* small view: Jail shows its JAIL plaque (above the bars), not the Just visiting sign that sat on top of it */
.board.radial.simple .jail-visit { display: none !important; }
.board.radial.simple .jail-plaque b { -webkit-text-stroke: 0; box-shadow: inset 0 0 0 1.6px var(--ink), inset 0 0 0 2.6px rgba(255, 255, 255, .45), 0 2px 0 rgba(0, 0, 0, .35); } /* readable at the zoomed-out size */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .t-big { font-size: 21px; margin: 0 4px; } /* "Fortune" fits beside its icon */
/* small view, Deal & Chance: just the word (white, ink outline) — no sign box behind it */
.board.radial.simple .tile:is(.t-deal, .t-chance.k-corner) .t-big { background: none !important; box-shadow: none !important; padding: 0 !important; border-radius: 0; }
/* small view, corner Chance: just a big "?" (no card behind it) */
.board.radial.simple .corner-chance .card-stack { background: none !important; box-shadow: none !important; transform: none !important; width: auto; height: auto; filter: none; }
.board.radial.simple .corner-chance .card-stack b { font: 500 54px/1 var(--font); color: #fff; -webkit-text-stroke: 3.5px var(--ink); paint-order: stroke fill; }
/* small view, Deal: a smaller handshake */
.board.radial.simple .corner-deal .t-icon .ic { width: 40px !important; height: 40px !important; }
/* small view, tax and Go to jail: every word sits above the white stripe(s) at the tile's inner end
   (on a flipped tile the inner end is the top of its turned-round box) */
.board.radial.simple .tile.t-tax:not(.flip) .t-body { padding-bottom: 14px !important; }
.board.radial.simple .tile.t-tax.flip .t-body { padding-top: 14px !important; }
.board.radial.simple .tile.t-gotojail:not(.flip) .t-body { padding-bottom: 22px !important; }
.board.radial.simple .tile.t-gotojail.flip .t-body { padding-top: 22px !important; }
/* money cards: a jailed player's card is behind bars, with which jail turn it is tagged underneath */
.hud-p .hud-bars { position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 2;
  background: repeating-linear-gradient(90deg, transparent 0 11px, rgba(20, 24, 40, .85) 11px 15px), linear-gradient(rgba(20, 24, 40, .25), rgba(20, 24, 40, .25));
  box-shadow: inset 0 3px 0 rgba(20, 24, 40, .85), inset 0 -3px 0 rgba(20, 24, 40, .85); }
.hud-p .hud-jail { position: absolute; left: 50%; bottom: -9px; transform: translateX(-50%); z-index: 3; padding: 1px 7px; border-radius: 99px;
  font: 800 9px/1.3 var(--font); font-style: normal; color: #fff; background: #8a5a35;
  box-shadow: 0 0 0 1.4px var(--ink), inset 0 1px 0 rgba(255, 255, 255, .35); white-space: nowrap; }
/* the player who's up: their card's face lights up in their colour, not just its ring */
.hud-p.up .ptoken { box-shadow: 0 0 10px 1px var(--pc), inset 0 5px 0 rgba(255, 255, 255, .35); }
/* corner tiles (GO, Jail, Deal, corner Chance): the same thin side bezel in their own darker shade as every tile — no
   heavy black or white frames; Deal & Chance still pulse in the current player's colour while someone is on them */
.board.radial .w-border { display: none !important; }
.board.radial .tile:is(.t-deal, .t-go, .t-jail, .t-chance.k-corner) .w-edges { stroke: color-mix(in srgb, var(--face) 65%, var(--ink)); stroke-width: 1.1px; }
.board.radial .tile:is(.t-deal, .t-chance.k-corner) .w-face { stroke: none; }
.board.radial .tile.here:is(.t-deal, .t-chance.k-corner) .w-face { stroke-width: 3px; }
.board.radial .tile.here:is(.t-deal, .t-chance.k-corner) .w-side { stroke: none; animation: none; }
/* the darker 3D sides of the corner tiles carry no outline (the old white on Deal & Chance, black on GO & Jail) */
.board.radial .tile:is(.t-deal, .t-chance.k-corner, .t-go, .t-jail) .w-side { stroke: none !important; animation: none !important; }
/* tile press, smoother and a touch deeper: down quickly, back up with a soft ease */
@keyframes keyPress { 0% { translate: 0 0; filter: none; } 35% { translate: 0 5px; filter: brightness(.78); } 100% { translate: 0 0; filter: none; } }
@keyframes keyShade { 35% { filter: brightness(.8); } }
.board.radial .tile.key-press :is(.wedge, .tile-inner, .tile-ic, .rlabel, .big) { animation: keyPress .42s var(--ease-out); }
.board.radial .sign-host.key-press .sign { animation: keyShade .42s var(--ease-out); }
/* the info card (and other windows) rise a little slower, easing out smoothly */
.backdrop.enter { --from: none; animation: enter .3s ease-out; }
.backdrop.enter .modal { --from: scale(.9) translateY(14px); animation: enter .5s var(--ease-out); }
@media (prefers-reduced-motion: reduce) { .backdrop.enter, .backdrop.enter .modal { animation: none; } }
/* money cards: the time left on the current player's turn, ticking down on their card */
.hud-p .hud-timer { position: absolute; top: -8px; z-index: 3; padding: 1px 7px; border-radius: 99px; font: 800 11px/1.3 var(--font);
  color: #fff; background: var(--ink); box-shadow: 0 0 0 1.5px var(--pc); font-variant-numeric: tabular-nums; }
.hud-p .hud-timer:empty { display: none; }
.hud-p .hud-timer.low { background: #c0263a; } /* (left, clear of the rent +/− badge on the right) */
/* small view: an owned tile keeps its own landmark icon, looking exactly as when unowned (no owner token, no colour) */
.board.radial.simple .tile.owned .t-icon > svg { display: inline-block !important; color: inherit !important; filter: none !important; opacity: 1; }
.board.radial.simple .tile .t-icon .own-ic { display: none !important; }
.board.radial.simple .tile.owned .t-icon .ic { animation: none !important; }
/* small view: every property icon solid white with the board's ink bezel (owned or not — ownership shows elsewhere) */
.board.radial.simple .tile:is(.t-property, .t-transport, .t-utility) .t-icon .ic { opacity: 1 !important; color: #fff !important; }
/* the turn timer sits on the right of the money card (the rent badge, when shown, moves to the left) */
.hud-p .hud-timer { left: auto !important; right: 6px; }
.hud-p:has(.hud-timer:not(:empty)) .delta { right: auto; left: 4px; }
/* phone bar: room between the camera/Menu row and the money cards, so the cards' timer badges clear the buttons */
body:is(.mobile, .bar) #topbar { gap: 16px !important; }
/* small view: a heavier ink bezel round every tile icon, so it stands off light ownership bands too */
.board.radial.simple .tile:is(.t-property, .t-transport, .t-utility) .t-icon .ic {
  filter: drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 2px 0 var(--ink)) !important; }
/* small view: the Deal handshake and the Chance "?" get the same heavy ink bezel as the other tile icons */
.board.radial.simple .corner-deal .t-icon .ic { color: #fff !important; opacity: 1 !important;
  filter: drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 2px 0 var(--ink)) !important; }
.board.radial.simple .corner-chance .card-stack b { -webkit-text-stroke: 4px var(--ink); filter: drop-shadow(0 2px 0 var(--ink)); }
/* small view, Deal: the word centred in the space between the handshake and the tile's inner end */
.board.radial.simple .tile.t-deal .tile-inner > * { padding-left: 0 !important; padding-right: 0 !important; }
.board.radial.simple .tile.t-deal .t-big { flex: 1 1 auto; margin: 0 !important; text-align: center; }
/* (Deal, small view, enforced) the handshake inset from the tile's outer end; the word fills and centres the rest */
.board.radial.simple .tile.t-deal .tile-inner > * > .t-icon { margin: 0 0 0 10px !important; }
.board.radial.simple .tile.t-deal:not(.outer-left) .tile-inner > * > .t-icon { margin: 0 10px 0 0 !important; }
.board.radial.simple .tile.t-deal .tile-inner > * > .t-big { flex: 1 1 0 !important; min-width: 0; text-align: center !important; }
/* pressing the camera / Menu buttons: they sink, but keep the black bezel ring the whole time */
body.night #topbar .zoom-toggle:active, body:not(.night) #topbar .zoom-toggle:active,
body:is(.mobile, .bar).night #narr-menu #menu-tab:active, body:is(.mobile, .bar):not(.night) #narr-menu #menu-tab:active {
  transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), inset 0 -2px 0 rgba(0, 0, 0, .2), 0 1px 0 var(--ink) !important; }
/* (Deal, small view) the handshake nudged a little towards the word — moved on its own, so the word stays put */
.board.radial.simple .tile.t-deal.outer-left .tile-inner > * > .t-icon { position: relative; left: 8px; }
.board.radial.simple .tile.t-deal:not(.outer-left) .tile-inner > * > .t-icon { position: relative; left: -8px; }
/* the player who's up: their money card is filled solid in their bright colour (dark outlined text stays readable) */
.hud-p.up { background: var(--pc) !important; }
/* …so its words take dark or white ink from that colour's lightness (white stopped reading on the light neons) */
.hud-p.up .hud-txt :is(b, small, i) { color: oklch(from var(--pc) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); }
/* the bar and other controls stay put while the camera is swiped round (no fading out) */
#stage-wrap:has(#stage.panning) :is(#topbar, #roll-pop, #buy-pop), #stage.panning .dice-tray.docked { opacity: 1 !important; pointer-events: auto !important; }
/* the tile the current player stands on: a flashing halo in that player's colour (not yellow) */
.tile.here .w-face { stroke: var(--cur, #fff) !important; stroke-width: 6px !important; paint-order: fill stroke; }
@media (prefers-reduced-motion: reduce) { .tile.here .w-face { animation: none; } }
/* (smoother halo: a slow, gentle breathe of the stroke alone — no animated glow filter, which stuttered) */
/* The breathe is a copy of the outline on its own layer (.wedge-here) fading its opacity: the compositor runs it, so
   the tile's svg (and every owner glow over it) isn't repainted each frame — animating the stroke itself halved the
   frame rate late in a game. The face keeps the faint low point of the breathe; the copy brings it up to full. */
.tile.here .w-face { stroke-opacity: .3; }
.wedge-here { opacity: 0; }
.wedge-here .w-here { fill: none; stroke: var(--cur, #fff); stroke-width: 6px; }
.tile.here .wedge-here { animation: hereBreathe 1.8s cubic-bezier(.45, 0, .55, 1) infinite alternate; will-change: opacity; }
@keyframes hereBreathe { from { opacity: 1; } to { opacity: 0; } }
/* (no breathe: the full outline, held) */
.board.spot .tile.here .wedge-here, .board.trade-spot .tile.here .wedge-here { animation: none; opacity: 1; }
@media (prefers-reduced-motion: reduce) { .tile.here .wedge-here { animation: none; opacity: 1; } }
.board.radial .tile.here:is(.t-deal, .t-chance.k-corner) .wedge-here { display: none; }
.board.radial .tile.here:is(.t-deal, .t-chance.k-corner) .w-face { stroke-opacity: 1; }
/* Deal & Chance contents appear level straight away — no spinning into place when the view changes */
.board.radial .tile:is(.t-deal, .t-chance.k-corner) .tile-inner > *, .board.radial .tile:is(.t-deal, .t-chance.k-corner) .tile-ic,
.board.radial .sign-host:is(.t-deal, .t-chance) .sign { transition: none !important; }
/* camera switch: a slower, smoother glide of the board, and a cross-fade of the tiles' design */
.board.radial :is(.tiles, .signs, .tokens, .range) { transition: opacity .28s ease, transform var(--turn); }
/* camera switch cross-fade: the old design (a ghost copy riding the same camera move) fades out while the new one fades in */
/* (cross-fade v4) only what differs between the two designs fades — the tile bases, bands and edges stay solid */
/* camera switch: the changing details fade out, stay hidden while the camera moves, then fade in once it has settled */
.board.radial :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price) { transition: opacity .28s ease; }
.board.radial .signs { transition: opacity .28s ease, transform var(--turn); }

.board.radial.xf-in :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price) { transition: opacity .4s ease; }
.board.radial.xf-in .signs { transition: opacity .4s ease, transform var(--turn); }
/* (the fade as opacity keyframes — other rules set their own `transition`, which silently cut a transition-based fade
   short on some parts, so they popped instead) */
@keyframes xfDim { from { opacity: 1; } to { opacity: 0; } }
@keyframes xfLift { from { opacity: 0; } to { opacity: 1; } }
.board.radial.xf-hold :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price, .signs) { opacity: 0 !important; animation: none !important; }
.board.radial.xf-hold :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price, .signs) { transition: none !important; }
/* quicker camera switch: 0.15s fade out, 0.55s camera move, 0.2s fade in */
.board { transition: transform .55s var(--ease-camera); }
/* zooming out is quicker: a 0.32s camera move */
.board.zoom-out { transition: transform .32s var(--ease-camera); }
.board.radial.xf-out :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price, .signs) { animation: xfDim .15s ease forwards !important; }
/* phones, zoomed in: no roll pop-up — the Roll button sits in the bar's middle (where the narration was), the camera
   and Menu buttons close in beside it, and the narration moves up above the row. Greyed out when it's not your roll. */
#bar-roll { display: none; }
body:is(.mobile, .bar):not(.nudging) #stage-wrap.zoomed #roll-pop { display: none !important; }
body:is(.mobile, .bar) #stage-wrap.zoomed #narr { flex-wrap: wrap; justify-content: center; }
body:is(.mobile, .bar) #stage-wrap.zoomed #narr-text { order: -1; flex: 1 1 100%; }
body:is(.mobile, .bar) #stage-wrap.zoomed #bar-roll { display: block; order: 1; flex: 0 0 auto; min-width: 150px; padding: 12px 26px; font: 800 24px/1 var(--font); border-radius: var(--r-md); }
body:is(.mobile, .bar) #stage-wrap.zoomed #cam-slot { order: 0; }
body:is(.mobile, .bar) #stage-wrap.zoomed #narr-menu { order: 2; }
body:is(.mobile, .bar) #stage-wrap.zoomed #bar-roll:disabled { filter: grayscale(1) brightness(.75); opacity: .6; box-shadow: 0 0 0 2px var(--ink), 0 3px 0 var(--ink); cursor: default; }
/* the bar's Roll button: the same black bezel as the camera and Menu buttons, pressed or not */
body:is(.mobile, .bar) #stage-wrap.zoomed #bar-roll { border: 0; box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .6) !important; }
body:is(.mobile, .bar) #stage-wrap.zoomed #bar-roll:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), inset 0 -2px 0 rgba(0, 0, 0, .2), 0 1px 0 var(--ink) !important; }
/* zoomed in: Roll in the middle, and the camera and Menu buttons each centred in the space between it and the screen edge */
body:is(.mobile, .bar) #stage-wrap.zoomed #narr { display: grid !important; grid-template-columns: 1fr auto 1fr; align-items: center; row-gap: 10px; column-gap: 0; }
body:is(.mobile, .bar) #stage-wrap.zoomed #narr-text { grid-column: 1 / -1; grid-row: 1; }
body:is(.mobile, .bar) #stage-wrap.zoomed #cam-slot { grid-column: 1; grid-row: 2; justify-self: center; margin: 0; }
body:is(.mobile, .bar) #stage-wrap.zoomed #bar-roll { grid-column: 2; grid-row: 2; }
body:is(.mobile, .bar) #stage-wrap.zoomed #narr-menu { grid-column: 3; grid-row: 2; justify-self: center; }
/* phones, both views: no roll pop-up; the bar's Roll button (camera · Roll · Menu, narration above) everywhere */
body:is(.mobile, .bar):not(.nudging) #roll-pop { display: none !important; }
/* the nudge prompt has no bar button to stand in for it, so it shows on the bar layouts, over the bar */
body:is(.mobile, .bar).nudging #roll-pop { z-index: 9; }
body:is(.mobile, .bar) #narr { display: grid !important; grid-template-columns: 1fr auto 1fr; align-items: center; row-gap: 10px; column-gap: 0; width: 100%; }
body:is(.mobile, .bar) #narr-text { grid-column: 1 / -1; grid-row: 1; }
body:is(.mobile, .bar) #cam-slot { grid-column: 1; grid-row: 2; justify-self: center; margin: 0; }
body:is(.mobile, .bar) #bar-roll { display: block; grid-column: 2; grid-row: 2; min-width: 150px; padding: 12px 26px; font: 800 24px/1 var(--font); border-radius: var(--r-md); border: 0;
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .6) !important; }
body:is(.mobile, .bar) #bar-roll:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), inset 0 -2px 0 rgba(0, 0, 0, .2), 0 1px 0 var(--ink) !important; }
body:is(.mobile, .bar) #bar-roll:disabled { filter: grayscale(1) brightness(.75); opacity: .6; cursor: default; }
body:is(.mobile, .bar) #narr-menu { grid-column: 3; grid-row: 2; justify-self: center; }

/* Commentary: a white bezel round the message box, and a fade out 5s after each message (fade in is the ticker keyframe) */
#ticker span, body.night #ticker span, body:not(.night) #ticker span { border: 2.5px solid #fff; }
#ticker span { transition: opacity .6s ease-out; }
#ticker span.gone { opacity: 0; }
@media (prefers-reduced-motion: reduce) { #ticker span { transition: none; } }

/* The Fortune deck on the globe: bevelled like the signs (an ink edge, a light inner rim, a darker foot) */
.deck {
  border: 3px solid var(--ink);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .55), inset 0 -5px 0 var(--fortune-side),
    0 5px 0 var(--ink), 6px 12px 0 rgba(20, 60, 90, .25);
}
.deck small { font-size: 12px; }

/* Jail, from back to front: the cell, the JAIL plaque, the jailed pawn, then the bars, so a pawn is never under the sign */
.board.radial .jail-plaque { z-index: 2; }
.board.radial .token.jailed { z-index: 3; }
.board.radial .jail-bars { z-index: 4; }
/* while the door swings (a pawn walking in or out), pawns draw over the door and signs; the bars cover one only once shut */
.board.radial.door-open .token { z-index: 6; }

/* Buying on a phone: the whole board and the money cards only (the bar's Roll, Menu, camera and commentary step aside) */
body:is(.mobile, .bar).buying #narr, body:is(.mobile, .bar).buying #stage-wrap.zoomed #narr { display: none !important; }
body:is(.mobile, .bar).buying #menu-tab { visibility: hidden; }
/* ...and once bought, the tile takes on its owner's colours: the band rises from the inner edge, the tile glows, the sign pops */
.board.radial .tile.claim-wait :is(.w-band, .w-band-bezel) { opacity: 0; }
.board.radial .tile.claim :is(.w-band.on, .w-band-bezel.on) { transform-box: fill-box; transform-origin: 50% 100%; animation: claimBand .75s var(--ease-out) both; }
.board.radial .tile.claim .w-face { animation: claimGlow 1.1s ease-out; }
.board.radial .sign-host.claim .sign { animation: claimSign .6s var(--ease-out) .2s both; }
@keyframes claimBand { from { transform: scaleY(0); opacity: .3; } }
@keyframes claimGlow { 0%, 30% { filter: brightness(1.45); } }
@keyframes claimSign { from { scale: calc(var(--sign-s, 1) * .55); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .board.radial :is(.tile, .sign-host).claim :is(.w-band, .w-band-bezel, .w-face, .sign) { animation: none; } }
#buy-pop.pending { visibility: hidden; animation: none !important; }

/* swiping: the board rides its own compositor layer, so moving the camera doesn't repaint the whole ring each frame */
.board.radial.snap { will-change: transform; }
/* zoomed in, the camera rides along with a moving pawn (glided frame by frame in script) on its own compositor layer */
.board.radial.follow { will-change: transform; transition: none; }

/* The Deal window: handshake header, the players to trade with, lots as big light-up buttons in a scrolling middle,
   cash, the bank's bonus and the two answers pinned to the foot */
.modal:is(.deal, .review) { width: min(420px, 100%); max-height: min(680px, 100%); display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.deal-head { display: flex; align-items: center; justify-content: center; gap: 10px; }
.deal-head .ic { width: 32px; height: 32px; color: var(--yellow); filter: drop-shadow(0 2px 0 var(--yellow-side)); }
.modal:is(.deal, .review) .deal-head { padding: 18px 18px 12px; flex: none; }
.modal.review .deal-head .countdown { margin-left: 4px; }
/* only the lots scroll: you, the players, and the column titles stay put above them */
.deal-top { flex: none; padding: 0 16px; }
.deal-me { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; padding: 8px 12px; border-radius: var(--r-md); background: color-mix(in srgb, var(--pc) 14%, transparent); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--pc) 45%, transparent); }
.deal-me > b { font: 500 17px/1 var(--font); margin-right: auto; }
.deal-me > span:not(.ptoken) { display: grid; justify-items: end; line-height: 1.1; }
.deal-me small { font-size: 11px; font-weight: 800; color: var(--muted); }
.deal-me span b { font-weight: 800; font-size: 15px; }
.deal-me .neg { color: var(--bad); }
.deal-me .pos { color: var(--good); }
.deal-after { padding-left: 4px; }
.deal-titles { flex: none; margin: 14px 16px 0; }
.deal-titles h4 { margin: 0 0 8px; font: 500 15px var(--font); }
/* each side is its own scrolling column, lots stacked from the top with an even gap */
.deal-scroll { flex: 1; min-height: 0; display: flex; overflow: hidden; padding: 0 16px; }
.deal-scroll .deal-sides { flex: 1; min-height: 0; margin-top: 0; display: flex; }
.deal-scroll .lots { flex: 1 1 0; min-width: 0; min-height: 0; align-content: start; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; touch-action: pan-y; margin: 0 -4px; padding: 2px 4px 14px; }
span.lot { display: flex; align-items: center; cursor: default; }
.lot.cash { gap: 6px; padding-left: 10px; }
.lot.cash::before { display: none; }
.lot.cash .ic { width: 18px; height: 18px; color: var(--good); }
.deal-players { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; }
.deal-p { display: grid; justify-items: center; gap: 4px; padding: 10px 6px 9px; border: 0; border-radius: var(--r-md); background: #eef2f8; color: inherit; font: inherit; cursor: pointer; box-shadow: 0 3px 0 var(--block-side); transition: transform .12s, box-shadow .12s, background .12s; }
.deal-p .ptoken { width: 38px; height: 38px; }
.deal-p b { font: 500 15px/1.1 var(--font); }
.deal-p small { font-weight: 800; color: var(--muted); }
.deal-p small.neg { color: var(--bad); }
.deal-p.on { background: color-mix(in srgb, var(--pc) 22%, #eef2f8); box-shadow: 0 0 0 3px var(--pc), 0 4px 0 color-mix(in srgb, var(--pc) 60%, #000); transform: translateY(-2px); }
.deal-pick { text-align: center; margin: 16px 0 4px; }
.deal-sides { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
.lots { display: grid; gap: 7px; }
.lot { position: relative; height: 50px; overflow: hidden; padding: 0 10px 0 30px; border: 0; border-radius: var(--r-sm); background: #eef2f8; color: var(--ink); font: 700 15px/1.15 inherit; text-align: left; cursor: pointer; box-shadow: 0 3px 0 var(--block-side); transition: transform .12s, box-shadow .15s, background .15s; }
.lot::before { content: ''; position: absolute; left: 11px; top: 50%; bottom: auto; width: 10px; border-radius: 3px; background: var(--g); height: 10px; transform: translateY(-50%); }
.lot:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--block-side); }
.lot.on { background: var(--yellow); color: var(--ink); box-shadow: 0 3px 0 var(--yellow-side), 0 0 0 2px #fff8, 0 0 18px color-mix(in srgb, var(--yellow) 70%, transparent); }
.lot:disabled { opacity: .35; cursor: not-allowed; }
.deal-foot { flex: none; padding: 12px 16px calc(14px + var(--safe-bottom, 0px)); border-top: 2px solid var(--block-side); }
.deal-cash { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.deal-cash .cash-in { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: 6px; margin: 0; font-weight: 800; }
.deal-cash .cash-in span { grid-column: 1 / -1; font-size: 13px; margin-bottom: 4px; }
.deal-cash .cash-in input { font-size: 17px; } /* (16px: iOS doesn't zoom the page into the field) */
.deal-note { margin: 10px 0 0; font-size: 13px; color: var(--muted); text-align: center; text-wrap: balance; }
.deal-err { display: block; color: var(--bad); font-weight: 800; }
.deal-err:empty { display: none; }
.modal:is(.deal, .review) .deal-foot .row:first-child { margin-top: 0; }
.modal.deal .row, .modal.review .row { display: flex; gap: 8px; margin-top: 12px; }
.modal.deal .row .btn, .modal.review .row .btn { flex: 1; padding: 13px; font-size: 15px; }
body.night .deal-p, body.night .lot { background: #2b3558; color: var(--night-fg); box-shadow: 0 3px 0 #10162c; }
body.night .deal-p.on { background: color-mix(in srgb, var(--pc) 30%, #2b3558); box-shadow: 0 0 0 3px var(--pc), 0 4px 0 color-mix(in srgb, var(--pc) 60%, #000); }
body.night .lot.on { background: var(--yellow); color: var(--ink); box-shadow: 0 3px 0 var(--yellow-side), 0 0 0 2px #fff6, 0 0 20px color-mix(in srgb, var(--yellow) 60%, transparent); }
body.night .deal-foot { border-top-color: #2b3558; }
body.night .deal-titles h4 { color: var(--night-fg); }
/* Phone: the Deal window is a sheet along the bottom with no dimming — the whole ring stays in view above it */
body.mobile .backdrop:is([data-kind="deal"], [data-kind="review"]) { background: none; padding: 0; place-items: end stretch; }
body.mobile .modal:is(.deal, .review) { width: calc(100vw / var(--ui-scale, 1)); max-height: calc(58dvh / var(--ui-scale, 1)); border-radius: var(--r-lg) var(--r-lg) 0 0; box-shadow: 0 -6px 24px rgba(0, 0, 0, .35); }
body.mobile .modal:is(.deal, .review) { height: calc(58dvh / var(--ui-scale, 1)); } /* (a received offer fills the same sheet as making one) */
body.mobile .modal:is(.deal, .review) .deal-head { padding: 10px 16px 8px; }
body.mobile .modal:is(.deal, .review) .deal-head .ic { width: 24px; height: 24px; }
body.mobile .modal:is(.deal, .review) .deal-head h2 { font-size: 20px; margin: 0; }
body.mobile .modal:is(.deal, .review) .deal-me { margin-bottom: 8px; padding: 6px 10px; }
body.mobile .modal.deal .deal-p { grid-template-columns: auto auto; grid-template-rows: auto auto; column-gap: 6px; row-gap: 0; padding: 6px; align-items: center; }
body.mobile .modal.deal .deal-p .ptoken { grid-row: span 2; width: 28px; height: 28px; }
body.mobile .backdrop.enter .modal:is(.deal, .review) { animation: sheetUp .18s var(--ease-out); } /* (quick: the board is the point) */
body.mobile.dealing #narr, body.mobile.dealing #menu-tab { visibility: hidden; }
/* Deal mode: nothing but the ring and the sheet — every other button steps aside */
body.mobile.dealing :is(#topbar, .zoom-toggle, #roll-pop, #buy-pop, #react-pop) { visibility: hidden !important; pointer-events: none !important; }
/* the board stays sharp behind the Deal window and a trade offer (no frosted blur) */
/* lots on the table in a trade: their tiles glow, fading in and out, in the colour of who'd own them if it goes through */
.wedge-trade { display: none; }
.board.radial .tile.trading { z-index: 3; }
/* a lot on the table: its outline in the colour of the player it leaves, fading into the one it goes to and back
   (each colour a layer of its own whose opacity the compositor fades; the glow is drawn once per layer) */
.board.radial .tile.trading .wedge-trade { display: block; animation: tradeFade 1.6s ease-in-out infinite alternate; will-change: opacity; filter: drop-shadow(0 0 6px var(--c)); }
.wedge-trade.from { --c: var(--trade-from); }
.wedge-trade.to { --c: var(--trade-to); }
.board.radial .tile.trading .wedge-trade.from { animation-direction: alternate-reverse; }
.wedge-trade .w-trade { fill: color-mix(in srgb, var(--c) 30%, transparent); stroke: var(--c); stroke-width: 6px; stroke-linejoin: round; }
@keyframes tradeFade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .board.radial .tile.trading .wedge-trade { animation: none; } .board.radial .tile.trading .wedge-trade.from { opacity: 0; } }
/* a tile that can't go on the table shakes */
.board.radial .tile.nope .wedge { animation: nope .35s ease-in-out; }
@keyframes nope { 20%, 60% { transform: translateX(-4px); } 40%, 80% { transform: translateX(4px); } }
@keyframes sheetUp { from { transform: translateY(100%); } }

/* Chance: the cards fly out of the globe's pile, so the panel itself just fades in (no pop: it would throw their paths off) */
.backdrop.enter .modal.card { --from: none; animation: enter .25s ease-out; }

/* A whole set owned: the band's colour runs on round the set's outline (setRing), in both views */
.board.radial .w-set { display: none; }
.board.radial .w-set.on { display: block !important; fill: var(--bc); stroke: none; } /* unstroked, so its pieces join into one continuous band */
.board.radial .tile.claim-wait .w-set { opacity: 0; }
.board.radial .tile.claim .w-set.on { --from: none; animation: enter .5s ease-out .45s both; }

/* Sign words: the dark outline is drawn by a copy of the text underneath (::before, z −1 in the sign), not on the
   letters themselves, so on a two-line sign the second line's outline no longer paints over the first line's letters */
.board.radial.upright .sign :is(.s-name, .s-price, .s-big),
.board.radial.upright :is(.tile, .sign-host).owned .sign :is(.s-name, .s-price, .s-big) { -webkit-text-stroke: 0; text-shadow: none; position: relative; }
.board.radial.upright .sign :is(.s-name, .s-price, .s-big)::before {
  content: attr(data-t); position: absolute; inset: 0; z-index: -1; padding: inherit; box-sizing: border-box; white-space: pre-line;
  color: transparent; -webkit-text-stroke: 2.2px var(--ink); text-shadow: 0 1px 0 var(--ink); pointer-events: none;
}
.board.radial.upright .sign .s-big::before { -webkit-text-stroke-width: 3.5px; text-shadow: 0 1.5px 0 var(--ink); }
.board.radial.upright :is(.tile, .sign-host).owned .sign :is(.s-name, .s-price, .s-big)::before { -webkit-text-stroke: 2.4px var(--ink); text-shadow: 0 1px 0 var(--ink); }
/* (the utility triangle's own layers drop one level, so the words' outline layer stays above them) */
.board.radial.upright .sign-host.t-utility .sign::after, .board.radial.upright .sign-host.t-utility .sign .tri { z-index: -2; }

/* Zoomed out: houses and hotels stand past the tile's outer end, the same as zoomed in */
.board.radial.simple .tile.built .bld-in { display: flex !important; }
.board.radial.simple .tile.built .bldgs { scale: 1.6; transform-origin: 50% 100%; }

/* A jailed player's turn arrow is drawn on its own layer above the bars (.jail-turn, placed on the pawn by sync):
   the pawn's own arrow would sit behind the bars and the cell, where it can't be seen */
.token.jailed .t-mark { visibility: hidden; }
.jail-turn { position: absolute; left: 0; top: 0; z-index: 5; pointer-events: none; }
.jail-turn .up { position: absolute; left: 0; top: 0; transform: rotate(calc(-1 * var(--rot))); transition: transform var(--turn); }
.jail-turn .t-mark { opacity: 1; animation: bob 1s ease-in-out infinite; }

/* ---------- Wi-Fi play: the host's invite card ---------- */
.invite { position: fixed; inset: 0; z-index: var(--z-invite); display: grid; place-items: center; padding: 16px; background: rgba(10, 15, 35, .45); }
.invite-card { position: relative; width: min(340px, 100%); max-height: 100%; overflow: auto; display: grid; gap: 12px; justify-items: center; text-align: center;
  padding: 22px 18px 18px; }
.invite-card > b { font-size: 20px; }
.invite-card > small { color: var(--muted); margin-top: -6px; }
.invite-seat { display: grid; gap: 6px; justify-items: center; width: 100%; padding: 12px; border-radius: var(--r-md); border: 3px solid var(--pc); }
.invite-name { font-weight: 800; }
.invite-qr { width: 200px; height: 200px; background: #fff; border-radius: var(--r-sm); }
.invite-qr svg { width: 100%; height: 100%; display: block; }
.invite-seat a { font-size: 13px; color: var(--muted); word-break: break-all; }

/* ---------- the deck: card faces, the hand, aiming, the draft, reaction windows ---------- */
.card { display: grid; grid-template-rows: auto auto 1fr auto; justify-items: center; gap: 3px; width: 104px; min-height: 118px; padding: 8px 6px 7px; border: 0; border-radius: var(--r-md); text-align: center;
  background: var(--block); color: var(--ink); box-shadow: 0 3px 0 var(--block-side), inset 0 0 0 2px rgba(255, 255, 255, .5); font: inherit; cursor: default; }
.card.react { background: #fde9c9; }
body.night .card { background: #1d2643; color: var(--night-fg); box-shadow: 0 3px 0 #0e1328, inset 0 0 0 1px rgba(255, 255, 255, .12); }
body.night .card.react { background: #3a2a4e; }
.card .card-ic { width: 26px; height: 26px; color: var(--yellow-side); }
body.night .card .card-ic { color: var(--yellow); }
.card .card-ic .ic, .card .card-ic svg { width: 26px; height: 26px; }
.card b { font: 800 13px/1.1 var(--font); }
.card small { font: 600 11px/1.25 var(--font); color: var(--muted); }
.card i { font: 800 9px/1 var(--font); color: var(--muted); opacity: .8; }
button.card { cursor: pointer; transition: transform .12s; }
button.card:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--block-side); }
/* a reaction's readiness: one pip per turn of rest, lit as it recharges; green when ready */
.cd { display: inline-flex; align-items: center; gap: 4px; padding: 2px 6px 2px 4px; border-radius: 999px; font: 800 9px/1 var(--font); white-space: nowrap;
  background: rgba(127, 140, 190, .18); color: var(--muted); }
.cd .pips { display: inline-flex; gap: 2px; }
.cd .pip { width: 6px; height: 6px; border-radius: 50%; background: rgba(127, 140, 190, .35); }
.cd .pip.on { background: var(--yellow-side); }
.cd.ready { background: rgba(47, 179, 106, .16); color: var(--good); }
.cd.ready .pip { background: var(--good); }
body.night .cd.ready { color: #7fe3a5; }
body.night .cd.ready .pip { background: #7fe3a5; }
body.night .cd .pip.on { background: var(--yellow); }
.card.resting { filter: saturate(.45); opacity: .7; }
.card.resting .cd { filter: saturate(2); }
.rx-row h3 { color: #c79bff; }
/* phones' peek: the turn cards in a row, the reactions as pills beneath */
.hand.peek .peek-row { display: flex; flex-wrap: nowrap; justify-content: center; align-items: flex-end; gap: 6px; }
.hand.peek .peek-rx { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; --from: translateY(18px) scale(.9); animation: enter .32s .16s var(--ease-out) backwards; }
.rx-chip { display: inline-flex; align-items: center; gap: 5px; padding: 4px 6px 4px 9px; border: 0; border-radius: 999px; font: inherit; cursor: pointer;
  background: #fde9c9; color: var(--ink); box-shadow: 0 2px 0 var(--block-side), inset 0 0 0 1.5px rgba(255, 255, 255, .5); }
body.night .rx-chip { background: #3a2a4e; color: var(--night-fg); box-shadow: 0 2px 0 #0e1328, inset 0 0 0 1px rgba(255, 255, 255, .12); }
.rx-chip > .ic, .rx-chip > svg { width: 15px; height: 15px; color: var(--yellow-side); }
body.night .rx-chip > .ic, body.night .rx-chip > svg { color: var(--yellow); }
.rx-chip b { font: 800 13px/1 var(--font); }
.rx-chip.resting { opacity: .7; }
.rx-chip.resting > :is(.ic, svg, b) { filter: saturate(.4); }
.rx-chip.ready { box-shadow: 0 2px 0 var(--block-side), inset 0 0 0 1.5px #2fb36a; }
body.night .rx-chip.ready { box-shadow: 0 2px 0 #0e1328, inset 0 0 0 1.5px rgba(127, 227, 165, .7); }
.rx-chip:active { transform: translateY(2px); }
.card.pick { width: 112px; min-height: 140px; }
.card.pick b { font-size: 15px; }
.hand { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.hand.aim { align-items: center; gap: 10px; padding: 8px 12px; border-radius: var(--r-md); background: rgba(20, 24, 52, .85); color: #fff; }
.hand.aim > b { display: flex; align-items: center; gap: 6px; font-size: 15px; }
.hand.aim > b .ic { width: 18px; height: 18px; }
.aim-opts { display: flex; flex-wrap: wrap; gap: 6px; }
.aim-opts .chip { display: inline-flex; align-items: center; gap: 4px; background: var(--pc, #eef2f8); color: #fff; box-shadow: 0 3px 0 rgba(0, 0, 0, .35); }
.aim-opts .chip .ic { width: 16px; height: 16px; }
.aim-opts .chip:disabled { opacity: .4; }
.hand.aim .muted { color: #cfd6ee; font-weight: 700; }
#hand-bar { width: 100%; }
#hand-bar:empty, #hand-side:empty { display: none; }
body:not(.mobile):not(.bar) #hand-bar { display: none; }
body:is(.mobile, .bar) #hand-side { display: none; }
#hand-side { padding: 0 16px 10px; order: 3; }
#hand-side .card { width: 96px; min-height: 108px; }
body:is(.mobile, .bar) #hand-bar .card { width: 100px; min-height: 104px; padding: 6px 5px; }
body:is(.mobile, .bar) #hand-bar .card small { font-size: 9px; }
.cards-tab { padding: 10px 16px 16px; display: grid; gap: 8px; }
.cards-tab h3 { margin: 6px 0 0; font: 800 11px/1 var(--font); color: var(--muted); }
.cards-tab .hand.big { justify-content: flex-start; }
.deck-row { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.deck-chip { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 999px; font: 800 11px/1 var(--font); background: rgba(127, 140, 190, .18); }
.deck-chip .ic { width: 14px; height: 14px; }

/* a card played: flashes up over the board for everyone */
.card-flash { position: absolute; left: 50%; top: 38%; z-index: 8; display: grid; justify-items: center; gap: 6px; transform: translate(-50%, -50%); pointer-events: none;
  animation: card-flash 2s ease forwards; }
.card-flash small { font: 800 13px/1 var(--font); color: #fff; text-shadow: 0 2px 6px rgba(0, 0, 0, .6); }
.card-flash .card { width: 150px; min-height: 160px; box-shadow: 0 0 0 4px var(--pc), 0 20px 40px -10px rgba(0, 0, 0, .7); transform: scale(1.1); }
.card-flash .card b { font-size: 17px; }
.card-flash .card small { font-size: 13px; }
@keyframes card-flash { 0% { opacity: 0; transform: translate(-50%, -40%) scale(.8); } 12%, 80% { opacity: 1; transform: translate(-50%, -50%) scale(1); } 100% { opacity: 0; transform: translate(-50%, -60%) scale(1); } }

/* the reaction window, over the board under the money cards */
#react-pop { position: absolute; left: 50%; top: calc(var(--safe-top, 0px) + 78px); z-index: 9; width: min(360px, 92%); transform: translateX(-50%); display: grid; gap: 10px; padding: 10px 12px; border-radius: var(--r-md);
  background: rgba(255, 255, 255, .94); color: var(--ink); box-shadow: 0 8px 0 var(--block-side), 0 20px 40px -14px rgba(10, 15, 35, .6); --from: translate(-50%, -8px); animation: enter .25s ease-out; }
body.night #react-pop { background: rgba(20, 24, 52, .94); color: var(--night-fg); box-shadow: 0 8px 0 #0a0d1f, 0 20px 40px -14px rgba(0, 0, 0, .8); }
body:is(.mobile, .bar) #react-pop { top: auto; bottom: calc(var(--safe-bottom) + 150px); }
.rx-head { display: flex; align-items: center; gap: 10px; font-size: 15px; }
.rx-head .ptoken.sm { flex: none; }
.rx-head .countdown { margin-left: auto; font: 800 17px/1 var(--font); }
.rx-body { display: flex; align-items: center; gap: 12px; }
.rx-body .card { flex: none; }
.rx-btns { display: grid; gap: 8px; flex: 1; }

/* the draft, over everything */
#draft { position: fixed; inset: 0; z-index: var(--z-draft); display: grid; place-items: center; padding: 16px; background: rgba(10, 15, 35, .72); }
/* (one column no wider than the card: on a phone the zoomed card is narrower than three 112px offers, which used to
   widen the column and push the offers, the title and the timer past the card's right edge) */
.draft-card { width: min(400px, 100%); display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; justify-items: center; text-align: center; padding: 18px 16px 18px; }
.draft-head { width: 100%; display: flex; align-items: center; justify-content: space-between; }
.draft-head .countdown { font: 800 24px/1 var(--font); }
.draft-card h2 { font: 500 24px/1.1 var(--font); margin: 0; }
.draft-card .muted { margin: -6px 0 0; }
.draft-offer { display: flex; gap: 10px; justify-content: center; width: 100%; }
.draft-offer .card.pick { flex: 0 1 112px; min-width: 0; }
#draft .pick-table { width: 100%; } /* (Pick any eight: its auto-fill columns count from the card's width, not past it) */
@media (max-width: 420px) { .draft-card { padding-inline: 12px; } .draft-offer { gap: 8px; } } /* (a few px more for a long title such as Lockdown) */
.draft-offer .card.pick { box-shadow: 0 4px 0 var(--block-side), 0 0 0 2px var(--pc, transparent); }
body.night .draft-offer .card.pick { box-shadow: 0 4px 0 #0e1328, 0 0 0 2px var(--pc, transparent); }

/* emotes: the button in the bar, the picker above it, the bubble over a player's name on every screen */
#emote-btn { width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%; font-size: 24px; line-height: 1; cursor: pointer; background: rgba(255, 255, 255, .7);
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), 0 4px 0 var(--ink); }
#emote-btn:active { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), 0 1px 0 var(--ink); }
body.night #emote-btn { background: #2a3358; }
#cam-slot { gap: 8px; align-items: center; }
body:is(.mobile, .bar) #cam-slot { flex-direction: row-reverse; }
#emote-pick { position: fixed; z-index: var(--z-popover); transform: translate(-50%, -100%); display: grid; gap: 4px; padding: 6px; border-radius: var(--r-md);
  background: rgba(255, 255, 255, .96); box-shadow: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 0 0 2px var(--ink); --from: translate(-50%, calc(-100% + 8px)); animation: enter .18s ease-out; }
body.night #emote-pick { background: rgba(26, 32, 66, .97); }
#emote-pick button { justify-items: center; gap: 2px; border: 0; background: transparent; cursor: pointer; color: var(--ink); }
#emote-pick button span { font-size: 30px; line-height: 1; }
#emote-pick button small { font: 800 9px/1 var(--font); letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; }
body.night #emote-pick button { color: var(--night-fg); }
#emote-pick button:active { background: rgba(127, 140, 190, .25); }
.emote { position: fixed; z-index: var(--z-bubble); transform: translate(-50%, -100%); align-items: center; pointer-events: none; animation: emote 2.4s ease forwards; }
.emote span { font-size: 38px; line-height: 1; }
@keyframes emote { 0% { opacity: 0; transform: translate(-50%, -80%) scale(.5); } 12% { opacity: 1; transform: translate(-50%, -110%) scale(1.1); } 20%, 80% { opacity: 1; transform: translate(-50%, -105%) scale(1); } 100% { opacity: 0; transform: translate(-50%, -140%) scale(.9); } }

/* utility signs: their own steel-blue face, so the triangle reads as a sign on its navy tile instead of a hole in it */
.board.radial .sign-host.t-utility:not(.owned) .tri-face { fill: #5a6ca9; stroke: #5a6ca9; }
.board.radial.upright .sign-host.t-utility .sign { --txt: #fff; color: #fff; }

/* phones, zoomed in: the hand is a row of pills in the narration's place, so the bar stays the same height */
body:is(.mobile, .bar) #stage-wrap.zoomed #topbar:has(#hand-bar:not(:empty)) #narr-text { display: none; }
body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .hand:not(.aim) { gap: 6px; }
body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .hand:not(.aim) .card { display: inline-flex; flex-direction: row; align-items: center; gap: 5px; width: auto; min-height: 0; padding: 7px 11px; border-radius: 999px; }
body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .card small, body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .card i { display: none; }
body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .card .card-ic, body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .card .card-ic svg { width: 18px; height: 18px; }
body:is(.mobile, .bar) #stage-wrap.zoomed #hand-bar .hand.aim { padding: 6px 10px; }

/* Test mode's die picker */
.die-pick { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; padding: 6px 0 2px; }
.die-pick span { font: 800 10px/1 var(--font); color: var(--muted); margin-right: 4px; }
.die-pick .chip { padding: 5px 9px; font-size: 12px; }

/* pocketed Fortune cards: the deck's blue, one use */
.cc-front .cc-keep { display: block; margin-top: 8px; font: 800 10px/1.3 var(--font); }

/* whose turn it is: the white halo sits on the pawn's arrow, not round the ball (the ball keeps its colour glow) */
.token.active .t-mark, .jail-turn .t-mark { filter: drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 3px #fff); will-change: transform; } /* (own layer: the bob doesn't re-run the halo) */

/* owned utility signs: the same triangle as for sale (steel-blue face, price midway, icon in the point) — the owner
   shows as the triangle's rim and a glow in their colour, not by recolouring the whole face */
.board.radial.upright .sign-host.t-utility.owned .sign .s-price { position: absolute !important; left: 50%; top: var(--price-y, 20px); transform: translate(-50%, -50%); }
.board.radial .sign-host.t-utility.owned .tri-face { fill: #5a6ca9; stroke: #5a6ca9; }
.board.radial.upright .sign-host.t-utility.owned .sign { color: #fff; }

/* owned signs (all kinds): the sign's own colour, the owner's token in place of the landmark, and a soft light in
   the owner's colour behind it — no hard ring */
.board.radial.upright :is(.tile, .sign-host).owned .sign { box-shadow: inset 0 0 0 2.5px var(--ink), 0 0 14px 5px var(--owner2), 0 2px 0 rgba(0, 0, 0, .25); }
.board.radial .sign-host.t-utility.owned .tri-rim { fill: rgba(255, 255, 255, .55); stroke: rgba(255, 255, 255, .55); }
.board.radial .sign-host.t-utility.owned .tri { filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .25)) drop-shadow(0 0 4px var(--owner2)) drop-shadow(0 0 9px var(--owner2)); }

/* owned signs keep their own face colour (the rule above that painted them in the owner's colour is overridden here) */
.board.radial.upright :is(.tile, .sign-host).owned .sign { background: color-mix(in srgb, var(--face, #fff) 88%, #000); color: var(--txt, #fff); text-shadow: none; }
.board.radial.upright :is(.tile, .sign-host).owned.owner-light .sign { color: var(--txt, #fff); }

/* ---------- desktop with the phone's bar (body.bar): money cards, camera · narration · Roll · cards button along the
   bottom; the sidebar is a drawer opened from the cards button ---------- */
body.bar #hand-side { display: none; }
body.bar .dice-tray.docked { left: auto; right: 18px; bottom: auto; top: 18px; }
body.bar.my-roll .dice-tray.docked { transform-origin: 100% 0; }
body.bar #hud { position: static; width: 100%; max-width: 760px; margin: 0 auto; }
body.bar #topbar { left: 50%; right: auto; width: min(100%, 820px); transform: translateX(-50%); }
body.bar #topbar.under { left: 50%; transform: translateX(-50%); }
body.bar.watching.menu-open #side { z-index: 20; }

/* desktop's bar: the hand is always the compact pills, and the row keeps its height so the ring doesn't jump each turn */
body.bar #hand-bar { min-height: 36px; }
body.bar #hand-bar .hand:not(.aim) { gap: 6px; }
body.bar #hand-bar .hand:not(.aim) .card { display: inline-flex; flex-direction: row; align-items: center; gap: 5px; width: auto; min-height: 0; padding: 7px 11px; border-radius: 999px; }
body.bar #hand-bar .card small, body.bar #hand-bar .card i { display: none; }
body.bar #hand-bar .card .card-ic, body.bar #hand-bar .card .card-ic svg { width: 18px; height: 18px; }
body.bar #hand-bar .hand.aim { padding: 6px 10px; }
/* the keys list */
table.keys { width: 100%; border-collapse: collapse; margin: 10px 0 4px; }
table.keys td { padding: 5px 6px; border-bottom: 1px solid rgba(127, 140, 190, .25); font-size: 13px; }
table.keys td:first-child { width: 36%; white-space: nowrap; }
kbd { display: inline-block; padding: 2px 7px; border-radius: var(--r-sm); font: 800 13px/1.3 var(--font); background: rgba(127, 140, 190, .18); box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .18); }

/* ---------- emotes as speech bubbles: a line in quotes from the player, with their name ---------- */
#emote-btn .ic { width: 24px; height: 24px; }
#emote-pick { grid-template-columns: 1fr 1fr; width: 300px; }
#emote-pick button { display: block; width: auto; padding: 9px 10px; font: 800 13px/1.2 var(--font); text-align: center; border-radius: var(--r-md); }
#emote-pick button.mute { grid-column: 1 / -1; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 11px; color: var(--muted); }
#emote-pick button.mute .ic { width: 14px; height: 14px; }
.emote { display: grid; justify-items: center; gap: 2px; padding: 8px 14px 9px; border-radius: var(--r-md); background: #fff; color: var(--ink); box-shadow: 0 0 0 3px var(--ink), 0 0 0 5px var(--pc), 0 10px 24px -8px rgba(0, 0, 0, .6); }
.emote::after { content: ''; position: absolute; left: 50%; bottom: -9px; width: 14px; height: 14px; transform: translateX(-50%) rotate(45deg); background: #fff; box-shadow: 3px 3px 0 0 var(--ink), 5px 5px 0 0 var(--pc); clip-path: polygon(0 100%, 100% 100%, 100% 0); }
.emote small { font: 800 9px/1 var(--font); color: var(--ink); }
.emote b { font: 500 17px/1.1 var(--font); white-space: nowrap; }
.emote span { display: none; }


/* ---------- the card tray: your cards big over the board ---------- */
#tray { position: absolute; inset: 0; z-index: 12; display: grid; align-content: center; justify-items: center; gap: 14px; padding: 16px; overflow: auto;
  background: rgba(10, 15, 35, .72); --from: translateY(-8px); animation: enter .2s ease-out; }
body:not(.night) #tray { background: rgba(40, 50, 90, .55); }
.tray-head { position: relative; display: grid; justify-items: center; gap: 2px; width: min(100%, 720px); padding: 0 48px; text-align: center; color: #fff; }
.tray-head b { font: 500 24px/1.1 var(--font); }
.tray-head .muted { color: #cfd6ee; font-weight: 700; font-size: 13px; }
.tray-x { position: absolute; right: 0; top: -4px; display: grid !important; place-items: center; width: 40px; height: 40px; border: 0; border-radius: 50%; background: rgba(255, 255, 255, .18); color: #fff; }
.tray-x .ic { width: 20px; height: 20px; }
.tray-row { display: grid; justify-items: center; gap: 8px; width: 100%; }
.tray-row h3 { margin: 0; font: 800 11px/1 var(--font); color: #cfd6ee; }
#tray .hand.big .card { width: 136px; min-height: 156px; padding: 12px 10px 10px; }
#tray .hand.big .card b { font-size: 16px; }
#tray .hand.big .card small { font-size: 12px; }
#tray .hand.big .card .card-ic, #tray .hand.big .card .card-ic svg { width: 32px; height: 32px; }
#tray .hand.next .card { width: 104px; min-height: 118px; }
#tray .card.idle { opacity: .75; }
#tray .row.center { justify-content: center; }
.tray-foot { gap: 10px; }
/* big screens: a panel down the right of the stage instead, above the bar, with no scrim: the board, fitted into the
   width left of it (see fit), stays live — pan, zoom, tap a tile, light up a player, roll */
body.bar #tray.side { inset: 12px 12px auto auto; width: 436px; max-height: calc(100% - var(--bar-h, 0px) - 24px); align-content: start; gap: 10px;
  padding: 14px 12px; border-radius: var(--r-lg); background: rgba(10, 15, 35, .86); box-shadow: 0 0 0 2px var(--ink), 0 18px 40px -12px rgba(0, 0, 0, .6);
  --from: translateX(12px); }
body.bar:not(.night) #tray.side { background: rgba(40, 50, 90, .86); }
/* (zoomed in, the docked die moves out of the panel's corner to the board's: 12 + 436 + 42px from the right, in its
   own zoomed px) */
body.bar #stage-wrap.zoomed:has(> #tray.side) .dice-tray.docked { right: calc(490px / var(--ui-scale, 1)) !important; }
body.bar #tray.side .tray-head { width: 100%; padding: 0 44px 0 0; justify-items: start; text-align: left; }
body.bar #tray.side .tray-head b { font-size: 20px; }
body.bar #tray.side .hand.big .card { width: 96px; min-height: 128px; padding: 8px 6px; } /* (four to a row: the hand and a Fortune card) */
body.bar #tray.side .hand.big .card b { font-size: 13px; }
body.bar #tray.side .hand.big .card small { font-size: 10px; }
body.bar #tray.side .hand.big .card :is(.card-ic, .card-ic svg) { width: 26px; height: 26px; }
body.bar #tray.side .hand.next .card { width: 84px; min-height: 96px; }
body.mobile #tray .hand.big .card { width: 104px; min-height: 126px; padding: 8px 6px; }
body.mobile #tray .hand.big .card b { font-size: 13px; }
body.mobile #tray .hand.big .card small { font-size: 10px; }
body.mobile #tray .hand.next .card { width: 84px; min-height: 96px; }
/* pick mode: the whole pool, chosen cards numbered */
.pick-table { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 760px; }
.pick-slot { position: relative; }
.pick-slot .card { width: 100px; min-height: 112px; }
.pick-slot .card.taken { box-shadow: 0 3px 0 var(--block-side), 0 0 0 3px var(--pc, var(--yellow)); }
.pick-slot:not(.taken) .card { opacity: .8; }
.pick-n { position: absolute; left: -6px; top: -6px; width: 22px; height: 22px; display: grid; place-items: center; border-radius: 50%; background: var(--pc, var(--yellow)); color: var(--ink); font: 800 13px/1 var(--font); box-shadow: 0 0 0 2px var(--ink); }
.draft-card.wide { width: min(800px, 100%); }
body.mobile .pick-slot .card { width: 84px; min-height: 98px; padding: 6px 4px; }
body.mobile .pick-slot .card small { font-size: 9px; }

/* ---------- Fortune: dark-blue cards with white type and a picture; the draw is a roulette wheel ---------- */
.cc-back b { -webkit-text-stroke: 14px var(--fortune-side); }
.cc-front .cc-ic { display: grid; place-items: center; border-radius: 50%; }
.card.chance { background: var(--fortune); color: #fff; }
.card.chance .card-ic, .card.chance small, .card.chance i { color: #fff; }
.card.chance small { color: #ddd6ff; }
/* the wheel: the dealt cards round a ring, tangent to it, a pointer at the top; the drawn card turns over in the middle */
.modal.card .roulette { position: relative; margin: auto; --n: 15; }
.modal.card .roulette .wheel { position: absolute; inset: 0; will-change: transform; }
.modal.card .roulette .pick-card.open { position: absolute; left: 50%; top: 50%; width: 15vmin; min-width: 72px; max-width: 110px; height: 11vmin; min-height: 54px; max-height: 80px; margin: calc(-1 * min(max(11vmin, 54px), 80px) / 2) calc(-1 * min(max(15vmin, 72px), 110px) / 2);
  transform: rotate(calc(var(--i) * 360deg / var(--n))) translateY(calc(-1 * var(--r))); padding: 4px 6px; gap: 3px; border-radius: 10px;
  background: var(--fortune); color: #fff; }
.modal.card .roulette .pick-card.open .ic { width: 18px; height: 18px; color: #fff; }
.modal.card .roulette .pick-card.open b { color: #fff; font-size: clamp(9px, 1.2vmin + 4px, 13px); line-height: 1.15; }
.modal.card .roulette .pick-card.open.lit { background: #4a3aa8; box-shadow: 0 3px 0 var(--fortune-side), inset 0 0 0 2px #fff, 0 0 16px #8f7cff; }
.modal.card .roulette .pick-card.open.chosen { background: var(--yellow); color: var(--ink); box-shadow: 0 3px 0 var(--yellow-side), inset 0 0 0 2px #fff, 0 0 22px var(--yellow); }
.modal.card .roulette .pick-card.open.chosen b, .modal.card .roulette .pick-card.open.chosen .ic { color: var(--ink); }
.modal.card .roulette .pointer { position: absolute; left: 50%; top: calc(50% - var(--r) - min(max(11vmin, 54px), 80px) / 2 - 16px); width: 0; height: 0; transform: translateX(-50%);
  border-left: 13px solid transparent; border-right: 13px solid transparent; border-top: 20px solid var(--yellow); filter: drop-shadow(0 2px 0 var(--ink)) drop-shadow(0 0 8px rgba(255, 204, 41, .7)); z-index: 4; }
.modal.card .roulette.done .pick-card.open:not(.chosen) { opacity: .45; }
.modal.card .roulette::before { content: ''; position: absolute; left: 50%; top: 50%; width: calc(var(--r) * 2 + 10px); height: calc(var(--r) * 2 + 10px); transform: translate(-50%, -50%); border-radius: 50%; border: 3px dashed rgba(255, 255, 255, .18); }
body.mobile .modal.card .roulette { --r: 33vmin; }

/* matchups on a card: what it beats (▲) and what it loses to (▼) */
.card .vs { display: grid; gap: 1px; font: 700 9px/1.2 var(--font); font-style: normal; }
.card .vs .up { color: var(--good); }
.card .vs .dn { color: var(--bad); }
body.night .card .vs .up { color: #7fe3a5; }
body.night .card .vs .dn { color: #ff8a98; }
#hand-bar .card .vs, body.bar #hand-bar .card .vs, body.mobile #stage-wrap.zoomed #hand-bar .card .vs { display: none; }
#tray .hand.big .card .vs { font-size: 10px; }
.card-flash .card .vs { font-size: 11px; }

/* ================= the main menu, in the game's own vocabulary: ink-bezelled blocks, the sunset primary, player-tinted
   cards like the money cards in the bar, chips built like the bar's buttons ================= */
#setup { padding: clamp(20px, 4vh, 40px) 16px calc(var(--safe-bottom) + 24px); }
.setup-inner { max-width: 1080px; display: grid; gap: 22px; }
.logo-lg { font-size: clamp(52px, 9vw, 92px); }
.setup-sec { display: grid; gap: 10px; }
.sec-title { margin: 0 0 0 4px; font: 500 24px/1 var(--font); color: var(--ink); }
body.night .sec-title { color: #fff; -webkit-text-stroke: 0; }
/* player cards: the money-card look, tinted by the player's colour */
.slots { gap: 12px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.slot, body.night .slot { min-height: 0; padding: 12px 12px 14px; border-radius: var(--r-md); --from: translateY(12px); animation: enter .35s var(--ease-out);
  background: color-mix(in srgb, var(--pc) 16%, var(--block)); color: var(--ink);
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .35), 0 6px 0 var(--ink); }
body.night .slot { background: color-mix(in srgb, var(--pc) 22%, rgba(20, 24, 52, .94)); color: var(--night-fg); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .14), 0 6px 0 var(--ink); }
.slot.add, body.night .slot.add { background: transparent; border: 2.5px dashed rgba(21, 26, 51, .35); box-shadow: none; color: var(--ink); min-height: 150px; border-radius: var(--r-md); }
body.night .slot.add { border-color: rgba(255, 255, 255, .22); color: #cfd6ee; }
.slot.add:hover, body.night .slot.add:hover { background: rgba(255, 255, 255, .08); border-style: solid; }
.slot.add span { font-size: 30px; }
.slot-pawn { width: 44px; height: 44px; box-shadow: inset 0 8px 0 rgba(255, 255, 255, .35), 0 0 0 2px var(--ink), 0 3px 0 var(--ink), 0 0 14px var(--pc); }
.slot-name, body.night .slot-name { height: 40px; padding: 0 12px; border-radius: var(--r-md); font: 800 15px/40px var(--font); background: rgba(255, 255, 255, .75); color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink), inset 0 3px 0 rgba(0, 0, 0, .12); }
body.night .slot-name { background: rgba(10, 13, 31, .55); color: var(--night-fg); box-shadow: inset 0 0 0 2px var(--ink), inset 0 3px 0 rgba(0, 0, 0, .35); }
.slot-name:focus, body.night .slot-name:focus { outline: 0; box-shadow: inset 0 0 0 2px var(--ink), 0 0 0 3px var(--pc); }
.slot-x, body.night .slot-x { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; color: var(--muted); }
body.night .slot-x { color: #cfd6ee; }
.slot-x .ic { width: 16px; height: 16px; }
.sw-label, body.night .sw-label { margin: 12px 0 6px; color: var(--muted); }
body.night .sw-label { color: #cfd6ee; }
.swatches.pairs { margin: 0 0 10px; gap: 7px; }
.sw.pair { width: 28px; height: 28px; box-shadow: 0 0 0 2px var(--ink); }
.sw.pair.on { box-shadow: 0 0 0 2px var(--ink), 0 0 0 4.5px #fff; }
.tokens-pick { gap: 6px; }
.tk, body.night .tk { height: 36px; border-radius: var(--r-md); background: rgba(255, 255, 255, .75); box-shadow: inset 0 0 0 2px var(--ink); }
body.night .tk { background: rgba(10, 13, 31, .55); }
.tk .ic, body.night .tk .ic { width: 18px; height: 18px; }
.tk.on, body.night .tk.on { background: var(--pc); box-shadow: inset 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .4); }
.tk.on .ic, body.night .tk.on .ic { color: oklch(from var(--pc) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); } /* (on the colour itself: dark or white ink by its lightness) */
/* the options: one panel, a row per setting */
.opts { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 0 28px; padding: 6px 18px; border-radius: var(--r-md);
  background: var(--block); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .35), 0 6px 0 var(--ink); }
body.night .opts { background: rgba(20, 24, 52, .94); color: var(--night-fg); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .12), 0 6px 0 var(--ink); }
.cash-pick, body.night .cash-pick { justify-content: space-between; gap: 12px; padding: 10px 0; background: none; box-shadow: none; border-radius: 0; border-bottom: 1.5px solid rgba(21, 26, 51, .12); }
body.night .cash-pick { border-bottom-color: rgba(255, 255, 255, .09); }
.opts .cash-pick:last-child { border-bottom: 0; }
@media (min-width: 660px) { .opts .cash-pick:nth-last-child(-n + 2) { border-bottom: 0; } }
.cash-pick > span { font: 800 13px/1 var(--font); }
.chip, body.night .chip { padding: 7px 13px; border-radius: var(--r-sm); font: 800 13px/1.2 var(--font); color: var(--ink); background: rgba(255, 255, 255, .75);
  box-shadow: inset 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .5), 0 3px 0 var(--ink); transition: transform .1s, box-shadow .1s; }
body.night .chip { color: var(--night-fg); background: rgba(10, 13, 31, .55); box-shadow: inset 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .12), 0 3px 0 var(--ink); }
.chip:active { transform: translateY(2px); box-shadow: inset 0 0 0 2px var(--ink), 0 1px 0 var(--ink); }
.chip.on, body.night .chip.on, body:not(.night) .chip.on { background: var(--yellow); color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), 0 3px 0 var(--ink); }
.chip:focus-visible { outline: 3px solid var(--pc, var(--yellow)); outline-offset: 2px; }
/* the actions, together, on the right */
.setup-foot { margin: 4px 0 0; justify-content: flex-end; }
/* phones: one column, the actions pinned to the bottom */
@media (max-width: 640px) {
  #setup { padding-bottom: calc(var(--safe-bottom) + 96px); }
  .setup-inner { gap: 18px; }
  .opts { padding: 2px 14px; }
  .cash-pick { flex-wrap: wrap; }
  .setup-foot { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; margin: 0; padding: 10px 14px calc(var(--safe-bottom) + 12px);
    background: linear-gradient(to top, var(--bg) 70%, transparent); }
  body.night .setup-foot { background: linear-gradient(to top, rgba(16, 20, 44, .95) 70%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .slot { animation: none; } }
/* day: the same blocks (the older day-glass rules above are more specific than the shared ones) */
body:not(.night) .slot { background: color-mix(in srgb, var(--pc) 16%, var(--block)); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .35), 0 6px 0 var(--ink); }
body:not(.night) .slot.add { background: transparent; box-shadow: none; }
body:not(.night) .slot.add:hover { background: rgba(255, 255, 255, .35); }
body:not(.night) .cash-pick { background: none; box-shadow: none; }

/* ---------- the sky: toy clouds drifting behind everything, dimmer and blurrier the further back ---------- */
#sky { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
#setup, #game { position: relative; z-index: 1; }
.cloud { position: absolute; top: var(--y); left: 0; width: var(--w); height: calc(var(--w) * .36); opacity: var(--o, .9);
  --c: #ffffff; --u: #dbe6f3; --s: calc(var(--b, 0px) / 1px * 1.2%); /* far clouds get softer edges instead of a (costly) blur */
  background:
    radial-gradient(circle at 24% 62%, var(--c) 0 calc(23% - var(--s)), transparent calc(24% + var(--s))),
    radial-gradient(circle at 44% 40%, var(--c) 0 calc(30% - var(--s)), transparent calc(31% + var(--s))),
    radial-gradient(circle at 66% 48%, var(--c) 0 calc(27% - var(--s)), transparent calc(28% + var(--s))),
    radial-gradient(circle at 82% 66%, var(--c) 0 calc(20% - var(--s)), transparent calc(21% + var(--s))),
    linear-gradient(var(--c), var(--c)) 50% 88% / 72% 30% no-repeat;
  animation: drift var(--d, 140s) linear infinite; animation-delay: var(--delay, 0s); transform: translateX(-50vw); will-change: transform; }
.cloud::after { content: ''; position: absolute; inset: 0; background:
    radial-gradient(circle at 24% 62%, var(--u) 0 calc(23% - var(--s)), transparent calc(24% + var(--s))),
    radial-gradient(circle at 44% 40%, var(--u) 0 calc(30% - var(--s)), transparent calc(31% + var(--s))),
    radial-gradient(circle at 66% 48%, var(--u) 0 calc(27% - var(--s)), transparent calc(28% + var(--s))),
    radial-gradient(circle at 82% 66%, var(--u) 0 calc(20% - var(--s)), transparent calc(21% + var(--s))),
    linear-gradient(var(--u), var(--u)) 50% 88% / 72% 30% no-repeat;
  transform: translateY(6%); z-index: -1; opacity: .9; }
body.night .cloud { --c: #4a4482; --u: #c86a7e; opacity: calc(var(--o, .9) * .55); }
@keyframes drift { from { transform: translateX(-50vw); } to { transform: translateX(110vw); } }
@media (prefers-reduced-motion: reduce) { .cloud { animation: none; transform: translateX(calc(var(--delay, 0s) / -1s * .5vw + 20vw)); } }

/* night continents, brighter: a lighter sand fill, a lighter edge shade, and the dusk wash over the eastern half eased off */
body.night .map .land { fill: #ffcf96 !important; }
body.night .map .land-side { fill: #d8764e !important; }
body.night .map .land-shade { stroke: rgba(30, 37, 64, .16); }
body.night .map .night-side { opacity: .16; }

/* the GLOBERUN logo follows the theme: yellow by day, the sunset's coral-peach at night (menu and the globe alike) */
body.night :is(.logo-lg, .logo-sm, .logo) { color: #fff4ea; }
body.night :is(.logo-lg, .logo-sm, .logo) span { color: #f99a5c; }

/* the deed's current-rent row: a sign band in the set's colour with an ink bezel and outlined white type (both themes) */
.deed tr.cur, body.night .deed tr.cur { background: none; }
.deed tr.cur td, body.night .deed tr.cur td { background: var(--rowbg); color: oklch(from var(--rowbg) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); font-weight: 800; border-bottom-color: transparent;
  box-shadow: inset 0 2.5px 0 var(--ink), inset 0 -2.5px 0 var(--ink), inset 0 5px 0 rgba(255, 255, 255, .4);
  --rowbg: var(--g, var(--yellow)); }
.deed tr.cur td:first-child, body.night .deed tr.cur td:first-child { border-radius: 9px 0 0 9px; box-shadow: inset 2.5px 0 0 var(--ink), inset 0 2.5px 0 var(--ink), inset 0 -2.5px 0 var(--ink), inset 2.5px 5px 0 rgba(255, 255, 255, .4); }
.deed tr.cur td:last-child, body.night .deed tr.cur td:last-child { border-radius: 0 9px 9px 0; box-shadow: inset -2.5px 0 0 var(--ink), inset 0 2.5px 0 var(--ink), inset 0 -2.5px 0 var(--ink), inset -2.5px 5px 0 rgba(255, 255, 255, .4); }
.deed tr.cur td:first-child::before { -webkit-text-stroke: 0; color: currentColor; }
.deed.transport tr.cur td { --rowbg: var(--transport, #7c8496); }
.deed.util tr.cur td { --rowbg: #5a6ca9; }

/* ---------- the wordmark on a smile: SVG text on an arc, ink-outlined, yellow by day and sunset-peach at night ---------- */
.arc-logo { display: block; overflow: visible; }
.arc-logo text { font: 800 100px var(--font); letter-spacing: .01em; fill: #fff; stroke: var(--ink); stroke-width: 16; stroke-linejoin: round; paint-order: stroke fill; }
.arc-logo text .r { fill: var(--yellow); }
.arc-logo text.shadow, .arc-logo text.shadow .r { fill: var(--ink); stroke: var(--ink); }
body.night .arc-logo text { fill: #fff4ea; }
body.night .arc-logo text .r { fill: #f99a5c; }
.logo-arc { width: min(620px, 78vw); margin: 0 auto; }
.board-center .globe-logo { font-size: 0; }
.board-center .globe-logo .arc-logo text { stroke-width: 18; }
@media (max-width: 640px) { .logo-arc { width: min(360px, 92vw); } }

/* ---------- city tiles: the landmark as big vector line art in a darker shade of the tile's colour ---------- */
.board.radial .motif { pointer-events: none; }
.board.radial .motif .art { fill: rgba(21, 26, 51, .06); stroke: var(--ink); stroke-width: 1.3; stroke-linejoin: round; stroke-linecap: round; }
.board.radial .motif :is(path, rect, circle, ellipse) { vector-effect: non-scaling-stroke; }
.board.radial .motif .art .win { fill: #fff; stroke: none; }
.board.radial .motif .hi { fill: none; stroke: #fff; stroke-width: 1.3; stroke-linejoin: round; stroke-linecap: round; transform: translate(-.6px, -.7px); }
.board.radial .motif .hi .win { display: none; }
/* (the small tile icons stay, over the art) */
.board.radial .tile-ic { z-index: 3; }

/* ---------- Fortune cards: a framed, gold-trimmed card with a banner, a roundel for the picture, outlined title ---------- */
.cc-front, .cc-back { border-radius: 14px; }
.cc-front { background: radial-gradient(circle at 50% 28%, #3d2f8a 0%, var(--fortune) 52%, #1f1850 100%); color: #fff; gap: 10px; padding: 24px 20px 26px;
  box-shadow: inset 0 0 0 4px var(--ink), inset 0 0 0 7px var(--yellow), inset 0 0 0 9px var(--ink), inset 0 -16px 0 var(--fortune-side), 0 24px 36px -16px rgba(0, 0, 0, .65); }
.cc-front::before { content: ''; position: absolute; inset: 13px 13px 20px; border: 2px dashed rgba(255, 255, 255, .22); border-radius: 8px; pointer-events: none; }
.cc-front::after { content: ''; position: absolute; inset: 13px 13px 20px; border-radius: 8px; pointer-events: none; opacity: .08;
  background: repeating-linear-gradient(135deg, #fff 0 2px, transparent 2px 12px); }
.cc-front > * { position: relative; z-index: 1; }
.cc-front small { display: inline-block; margin: 0 auto; padding: 5px 14px; border-radius: 999px; background: var(--yellow); color: var(--ink); font-size: 10px; letter-spacing: .22em; box-shadow: 0 0 0 2px var(--ink), 0 3px 0 var(--yellow-side); }
.cc-front .cc-ic { width: 76px; height: 76px; margin: 2px auto 0; background: var(--yellow); box-shadow: 0 0 0 3px var(--ink), inset 0 -7px 0 #e0a800, inset 0 3px 0 rgba(255, 255, 255, .5); }
.cc-front .cc-ic .ic { width: 42px; height: 42px; color: var(--ink); }
.cc-front h2 { font-size: 30px; color: #fff; -webkit-text-stroke: 6px var(--ink); paint-order: stroke fill; text-wrap: balance; }
.cc-front p { font-size: 15px; font-weight: 700; color: #ece8ff; }
.cc-front .cc-keep { color: var(--yellow); }
.cc-back { background: radial-gradient(circle at 50% 35%, #3d2f8a 0%, var(--fortune) 55%, #1f1850 100%);
  box-shadow: inset 0 0 0 4px var(--ink), inset 0 0 0 7px var(--yellow), inset 0 0 0 9px var(--ink), inset 0 -16px 0 var(--fortune-side), 0 24px 36px -16px rgba(0, 0, 0, .65); }
.cc-back::after { content: ''; position: absolute; inset: 13px 13px 20px; border-radius: 8px; opacity: .1; background: repeating-linear-gradient(135deg, #fff 0 2px, transparent 2px 12px); }
.cc-back b { position: relative; z-index: 1; color: var(--yellow); -webkit-text-stroke: 14px var(--ink); }
.modal.card .roulette .pick-card.open { box-shadow: 0 3px 0 var(--fortune-side), inset 0 0 0 2px var(--ink), inset 0 0 0 3.5px rgba(255, 204, 41, .55); }
.card.chance { box-shadow: 0 3px 0 var(--fortune-side), inset 0 0 0 2px var(--ink), inset 0 0 0 3.5px var(--yellow); }
/* the wordmark rides the bottom of the globe, inside the rim */
.board-center .globe-logo { left: 0 !important; top: 0 !important; width: 608px !important; height: 608px !important; transform: none !important; }
.board-center .globe-logo .rim-logo { width: 608px; height: 608px; }
.board-center .globe-logo .rim-logo text { font-size: 54px; stroke-width: 10; letter-spacing: .04em; }


/* Fortune on the board wears the cards' blue and gold: the tiles, the pile on the globe */
.deck small, .deck b { color: #fff; }

/* the die lands in the middle of the map (the plaza), bigger */
.board.radial .dice-tray:not(.docked) { top: 50% !important; }
.board.radial .dice-tray:not(.docked) { scale: 1.25; }
body.my-roll .board.radial .dice-tray:not(.docked), body.my-roll:has(#roll-pop.under) .board.radial .dice-tray:not(.docked) { scale: 1.7; }

/* the Chance draw, livelier: the pointer kicks at each card, the passing card lifts, the winner pops and the wheel
   settles back under the big card as it turns over */
.modal.card .roulette .pointer { transform-origin: 50% 0; will-change: transform; } /* (the kick itself is scripted, see sweepCards) */
.modal.card .roulette .pick-card.open { transition: box-shadow .1s, background .1s, filter .15s; }
.modal.card .roulette .pick-card.open.lit { filter: brightness(1.25); }
.modal.card .roulette .pick-card.open.chosen { animation: chosen-pop .5s var(--ease-out); }
@keyframes chosen-pop { 0% { filter: brightness(1.6); } 40% { filter: brightness(1.3); } 100% { filter: none; } }
.modal.card .roulette .wheel { transition: opacity .6s ease, filter .6s ease; }
/* once drawn, only the big card shows: the rest of the wheel, its ring and pointer go */
.modal.card .roulette .pick-card.open, .modal.card .roulette::before, .modal.card .roulette .pointer { transition: opacity .4s ease, box-shadow .1s, background .1s, filter .15s; }
.modal.card .roulette.done .pick-card.open:not(.chosen), .modal.card .roulette.done::before, .modal.card .roulette.done .pointer { opacity: 0; }
/* a compact panel in the middle of the screen, not the whole window */
.backdrop[data-kind="card"] { place-items: center; }
body .modal.card { width: auto; height: auto; max-width: 94vw; max-height: 100%; border-radius: var(--r-lg); }
.modal.card > .modal-body { min-height: 380px; }
.modal.card .roulette { --r: 33vmin; width: calc(var(--r) * 2 + 130px); height: calc(var(--r) * 2 + 130px); max-width: 100%; }
/* on a phone the wheel takes the whole width: just the cards' half-width either side, room for the pointer on top */
body.mobile .modal.card { max-width: calc(100vw - 16px); padding: 10px; }
/* the side cards stand on end, so the ring needs only their half-height either side */
body.mobile .modal.card .roulette { --r: min(32vmin, calc(50vw - 72px)); width: calc(var(--r) * 2 + 60px); height: calc(var(--r) * 2 + 104px); }
/* no dashed ring round the wheel */
.modal.card .roulette::before { display: none; }
/* the drawn card sits just above Okay, not centred in the wheel's taller box */
.modal.card .chance-card { margin: auto auto 0; }
@media (min-width: 900px) and (min-height: 760px) { .modal.card .roulette { --r: 30vmin; } .modal.card > .modal-body { min-height: 560px; min-width: 420px; } }
/* the hub: a question mark sits still in the middle while the wheel turns round it */
.modal.card .roulette .hub { position: absolute; left: 50%; top: 50%; width: calc(var(--r) * 1.05); height: calc(var(--r) * 1.05); max-width: 170px; max-height: 170px; transform: translate(-50%, -50%);
  display: grid; place-content: center; justify-items: center; gap: 2px; border-radius: 50%; z-index: 2; transition: opacity .4s ease;
  background: radial-gradient(circle at 50% 35%, #3d2f8a 0%, var(--fortune) 60%, #1f1850 100%); box-shadow: 0 4px 0 var(--fortune-side), inset 0 0 0 3px rgba(255, 204, 41, .6), 0 0 26px rgba(143, 124, 255, .35); }
/* the ? is the tile's: the display face in Fortune gold with the ink outline and glow, alone in the middle of the hub */
.modal.card .roulette .hub .q { font: 500 clamp(30px, calc(var(--r) * .5), 70px)/1 var(--font); color: var(--yellow); -webkit-text-stroke: 6px var(--ink); paint-order: stroke fill;
  filter: drop-shadow(0 0 6px rgba(255, 204, 41, .6)); }
.modal.card .roulette.done .hub { opacity: 0; }
.modal.card .roulette::after { content: ''; position: absolute; left: 50%; top: 50%; width: calc(var(--r) * 2 + 10px); height: calc(var(--r) * 2 + 10px); transform: translate(-50%, -50%) scale(.6); border-radius: 50%; opacity: 0; pointer-events: none;
  box-shadow: 0 0 0 4px var(--yellow), 0 0 40px 10px rgba(255, 204, 41, .5); }
.modal.card .roulette.done::after { animation: ring-flash .7s ease-out; }
@keyframes ring-flash { 0% { opacity: .9; transform: translate(-50%, -50%) scale(.6); } 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.05); } }
@media (prefers-reduced-motion: reduce) { .modal.card .roulette .pick-card.open.chosen, .modal.card .roulette.done::after { animation: none; } }

/* the small tile icons stand upright on screen whatever the tile's turn (the sides had them lying along the tile) */
.board.radial .tile .tile-ic, .board.radial .tile.side-r .tile-ic, .board.radial .tile.side-l .tile-ic, .board.radial .tile.flip .tile-ic { transform: translate(-50%, -50%) rotate(calc(-1 * var(--deg) - var(--rot))); }
/* the undocked die scales about its anchor, not its box, so it stays dead centre on the plaza / globe */
.board.radial .dice-tray:not(.docked) { transform-origin: 0 0; }
/* decals turn exactly as the tile icons do (the rules above for .tile-ic): with their tile on the top half of the screen,
   upright on screen on the bottom half, about their own centre (the face clip trims the corners). Where that leaves them
   sideways to the tile, on the left and right of the ring, they shrink a touch to fit its width. They turn about a set
   point of the tile (inline transform-origin, see tileArt), not their own box, so art run out to the tile's edge stays put.
   Decals laid on the tile icon (the flame, the rails, the cards) stand upright with it everywhere, full size */
.board.radial .motif .spin { transform-box: view-box; transform: rotate(0deg); transition: transform var(--turn); }
.board.radial .tile.flip .motif .spin { transform: rotate(calc(-1 * var(--deg) - var(--rot))); }
.board.radial .tile:is(.side-r, .side-l) .motif .spin { transform: rotate(calc(-1 * var(--deg) - var(--rot))) scale(.74); }
.board.radial .tile .motif .spin.at-icon { transform: rotate(calc(-1 * var(--deg) - var(--rot))); }
/* the ferry's waves bow round the globe like the tile's arcs, so they never turn */
.board.radial .tile .motif .spin.at-tile { transform: none; }
/* zoomed out, the tiles are too small for decals: plain faces */
#stage-wrap:not(.zoomed) .board.radial .motif { display: none; }
/* decals in shades of the tile's own colour: lines and fills a darker shade of the face, highlights and windows a lighter one */
.board.radial .motif .art { stroke: color-mix(in srgb, var(--face) 58%, #000); fill: color-mix(in srgb, var(--face) 72%, #000); fill-opacity: .35; opacity: .55; }
.board.radial .motif .art .win { fill: color-mix(in srgb, var(--face) 45%, #fff); fill-opacity: 1; opacity: .8; }
.board.radial .motif .hi { stroke: color-mix(in srgb, var(--face) 45%, #fff); opacity: .5; }
/* the Wi-Fi lobby: joined seats show a tick instead of their QR code; the host's Start button is the way on */
.invite-seat.in { border-style: solid; opacity: .85; }
.invite-in { display: inline-flex; align-items: center; gap: 6px; font-weight: 800; color: inherit; }
.invite-in .ic { width: 18px; height: 18px; }
.invite-start { width: 100%; margin-top: 2px; }
.lobby-seats { justify-content: center; }
.lobby-seats .chip, body.night .lobby-seats .chip { display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px 5px 5px; border: 0; box-shadow: inset 0 0 0 2px var(--pc); color: inherit; background: transparent; opacity: .5; cursor: default; pointer-events: none; }
.lobby-seats .chip.in, body.night .lobby-seats .chip.in { opacity: 1; background: color-mix(in srgb, var(--pc) 18%, transparent); }
.lobby-seats .chip .ptoken.sm { width: 24px; height: 24px; box-shadow: inset 0 5px 0 rgba(255, 255, 255, .35), 0 0 0 2px var(--ink); }
/* each seat dresses itself in the lobby: the same pawn, name field, colour pairs and tokens as setup's slot */
.seat-edit { width: 100%; display: grid; gap: 8px; text-align: left; padding: 12px; border-radius: var(--r-md); background: rgba(255, 255, 255, .35); box-shadow: inset 0 0 0 2px var(--ink); }
body.night .seat-edit { background: rgba(10, 13, 31, .4); }
.seat-edit .sw-label, body.night .seat-edit .sw-label { margin: 6px 0 0; }
.seat-edit .swatches.pairs { margin: 0; justify-content: center; }
.seat-edit .tokens-pick { grid-template-columns: repeat(5, 1fr); }
.lobby-card .seat-edit { margin: 2px 0; }
.invite-card .seat-edit .slot-name { text-align: left; }
.invite-name { display: inline-flex; align-items: center; gap: 7px; color: inherit; }
.invite-name .ptoken.sm { width: 24px; height: 24px; box-shadow: inset 0 5px 0 rgba(255, 255, 255, .35), 0 0 0 2px var(--ink); }

/* the Menu button, top left over the board on every layout (the docked die has the top right), and its short list.
   (big screens need it too: it is their only way to forfeit, and the drawer that once held Settings is out of reach
   there in a game with cards, where the bar's button opens the cards instead) */
#game-menu-btn { position: absolute; z-index: 9; left: 18px; display: grid; place-items: center; width: 48px; height: 48px;
  padding: 0; border: 0; border-radius: 50%; cursor: pointer; zoom: var(--ui-scale, 1);
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink), 0 8px 18px -8px rgba(0, 0, 0, .6); }
#game-menu-btn .ic { width: 24px; height: 24px; }
#game-menu-btn:active, #game-menu-btn[aria-expanded="true"] { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), 0 1px 0 var(--ink); }
body.mobile:is(.buying, .dealing) #game-menu-btn, body.mobile.menu-open #game-menu-btn { visibility: hidden; }
#game-menu { position: absolute; inset: 0; z-index: 14; }
#game-menu .gm-scrim { position: absolute; inset: 0; border: 0; padding: 0; background: rgba(8, 10, 24, .35); cursor: default; --from: none; animation: enter .2s ease-out; }
#game-menu .gm-list { position: absolute; left: 18px; min-width: 210px; display: grid; padding: 6px; border-radius: var(--r-lg); zoom: var(--ui-scale, 1);
  background: var(--block); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), 0 5px 0 var(--ink), 0 18px 40px -12px rgba(0, 0, 0, .7);
  transform-origin: 24px -10px; --from: scale(.85) translateY(-6px); animation: enter .22s var(--ease-out); }
body.night #game-menu .gm-list { color: var(--night-fg); }
/* phones zoomed in: on your roll the docked die grows from its own centre (no corner anchor), and the Menu button sits
   level with that centre (die box 66px tall at top+18 → centre at top+51; the 48px button's top at 51 − 24 = 27), so
   neither the die's middle nor the button moves */
body:is(.mobile, .bar).my-roll #stage-wrap.zoomed .dice-tray.docked { transform-origin: 50% 50% !important; }
#game-menu-btn { top: calc(var(--safe-top) + 27px); }
#game-menu .gm-list { top: calc(var(--safe-top) + 87px); }
#game-menu .gm-list button { display: flex; align-items: center; gap: 12px; padding: 13px 14px; border: 0; border-radius: var(--r-md); background: none; color: inherit;
  font: 800 17px/1 var(--font); text-align: left; cursor: pointer; }
#game-menu .gm-list button .ic { width: 20px; height: 20px; opacity: .8; }
#game-menu .gm-list button:active { background: rgba(127, 140, 190, .2); }
/* the pace line: set by the host before the start, so here it only tells */
#game-menu .gm-pace { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px 6px; font: 700 12px/1.2 var(--font); color: var(--muted); }
#game-menu .gm-pace b { font-weight: 800; color: inherit; }
body.night #game-menu .gm-pace { color: #aab3d4; }
#game-menu .gm-list .danger { margin-top: 4px; border-top: 1px solid rgba(127, 140, 190, .25); border-radius: 0 0 var(--r-md) var(--r-md); color: var(--bad); }
#game-menu .gm-list .danger .ic { opacity: 1; }

/* phones: the cards button lays your hand out over Roll — three cards, then the next one, smaller */
body.mobile #hand-bar .hand.peek { display: flex; flex-direction: column; flex-wrap: nowrap; justify-content: center; align-items: center; gap: 8px; padding: 0;
  transform: translateY(-16px); }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card { display: flex; flex-direction: column; width: 92px; min-height: 116px; padding: 6px 5px; border-radius: var(--r-md); flex: 0 0 auto;
  --from: translateY(18px) scale(.9);
  animation: enter .32s var(--ease-out) backwards; }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card small, body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card i { display: block; }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card:nth-child(2) { animation-delay: .04s; }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card:nth-child(3) { animation-delay: .08s; }
body.mobile #hand-bar .hand.peek:not(.aim) .card.idle { opacity: .75; }
body.mobile #stage-wrap.zoomed #topbar:has(.hand.peek) #narr-text { display: none; }
/* the cards sit centred between the ring and Roll: no commentary between them, and the same room above as below
   (the bar starts 10px under the ring, so 10 + 6 above matches the bar's 16px gap below) */
body.mobile #topbar:has(.hand.peek) #narr-text { display: none; }
body.mobile #topbar.under:has(.hand.peek) { padding-top: 6px; }
/* every line of a card stays inside it: long words wrap rather than run past the edge */
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card > * { min-width: 0; max-width: 100%; overflow-wrap: anywhere; hyphens: auto; }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card b { font-size: 13px; }
body.mobile #stage-wrap #hand-bar .hand.peek:not(.aim) .card i { letter-spacing: .04em; line-height: 1.15; }
/* phones: the cards button does the zooming, so no camera button in the bar */
body.mobile #topbar .zoom-toggle { display: none !important; }
/* opened from the zoomed-in view: the board zooms out first (fade, camera, bar ≈ .5s), then the cards come in */
body.mobile.peek-step #stage-wrap #hand-bar .hand.peek:not(.aim) .card { animation-delay: .5s; }
body.mobile.peek-step #stage-wrap #hand-bar .hand.peek:not(.aim) .card:nth-child(2) { animation-delay: .54s; }
body.mobile.peek-step #stage-wrap #hand-bar .hand.peek:not(.aim) .card:nth-child(3) { animation-delay: .58s; }
body.mobile.peek-step #hand-bar .hand.peek .peek-rx { animation-delay: .66s; }
/* the cards button stays pressed while they're out */
body.mobile #narr-menu #menu-tab[aria-pressed="true"] { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(0, 0, 0, .2), 0 1px 0 var(--ink) !important; }
/* phones (and desktop's bar): the money cards are locked to the bottom of the screen, out of the bar — they stay put
   when the view zooms, swipes or the bar glides. The bar and the buy sign stack above them. */
body:is(.mobile, .bar) #stage-wrap { --hud-h: 58px; --hud-gap: calc(var(--safe-bottom) + 12px); }
body:is(.mobile, .bar) #hud { position: absolute; z-index: 8; left: 0; right: 0; top: auto; bottom: var(--hud-gap); width: calc(100% - 16px);
  max-width: 760px; margin: 0 auto; padding: 0; transform: none; }
body:is(.mobile, .bar) #topbar:not(.under) { bottom: calc(var(--hud-gap) + var(--hud-h) + 8px); }
#stage-wrap:not(.zoomed) #buy-pop { bottom: calc(var(--hud-gap, var(--safe-bottom)) + var(--hud-h, 0px) + 10px); }
/* riding a transport: the ride strip takes the bar's place above the money cards — Roll, cards and emotes step aside */
body:is(.mobile, .bar) #ride-pop { z-index: 9; bottom: calc(var(--hud-gap, var(--safe-bottom)) + var(--hud-h, 0px) + 10px); }
body:is(.mobile, .bar) #stage-wrap:has(#ride-pop) #topbar { visibility: hidden; pointer-events: none; }
body.mobile.dealing #hud { visibility: hidden; pointer-events: none; }

/* ---------- loading screen: the globe turning under the wordmark while the board settles underneath ---------- */
#loader {
  position: fixed; inset: 0; z-index: var(--z-loader); display: grid; place-items: center; overflow: hidden;
  background: radial-gradient(ellipse at 50% 40%, var(--sky) 0%, var(--sky-2) 100%);
  transition: opacity .55s ease .05s;
}
body.night #loader { background: inherit; }
#loader.out { opacity: 0; pointer-events: none; }
.ld-inner { display: grid; justify-items: center; gap: 18px; width: min(360px, 88vw); }
.ld-logo { width: 100%; margin-bottom: -26px; --from: translateY(12px); animation: enter .5s var(--ease-out) both; }
.ld-globe {
  --d: min(240px, 62vw);
  position: relative; width: var(--d); height: var(--d); border-radius: 50%; overflow: hidden;
  background: radial-gradient(circle at 50% 42%, #2fa9d8 0%, var(--water) 55%, #164f7c 100%);
  box-shadow: inset 0 0 0 6px #2fa9d8, 0 0 0 4px var(--ink), 0 14px 0 -2px rgba(13, 10, 36, .5), 0 30px 50px -14px rgba(0, 0, 0, .55);
  --from: scale(.9) translateY(14px);
  animation: enter .6s var(--ease-out) .08s both;
  transition: transform .6s cubic-bezier(.5,0,.75,0);
}
body.night .ld-globe {
  background: radial-gradient(circle at 50% 42%, #2b86c0 0%, var(--water) 55%, #164f7c 100%);
  box-shadow: inset 0 0 0 6px #2b86c0, 0 0 0 4px var(--ink), 0 30px 50px -14px rgba(0, 0, 0, .6);
}
#loader.out .ld-globe { transform: scale(3.2); }
.ld-spin { position: absolute; inset: 0; animation: ldSpin 14s linear infinite; }
.ld-spin .map { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.ld-shine { position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background:
    radial-gradient(ellipse 40% 28% at 34% 22%, rgba(255,255,255,.5) 0%, rgba(255,255,255,.15) 50%, transparent 72%),
    radial-gradient(circle at 40% 36%, transparent 40%, rgba(5, 30, 70, .2) 70%, rgba(5, 30, 70, .5) 96%); }
.ld-pawns { display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; min-height: 62px; }
.ld-pawn { display: grid; justify-items: center; gap: 5px; animation: ldDrop .55s cubic-bezier(.34,1.56,.64,1) calc(.55s + var(--k) * .22s) both; }
.ld-pawn .ptoken { width: 40px; height: 40px; font-size: 20px; }
.ld-pawn .ptoken .ic { animation: bob 1.6s ease-in-out calc(1.2s + var(--k) * .2s) infinite; }
.ld-pawn b { max-width: 76px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 800; color: var(--ink); }
body.night .ld-pawn b { color: var(--night-fg); text-shadow: 0 1px 2px rgba(0, 0, 0, .5); }
.ld-bar { width: 78%; height: 14px; border-radius: 99px; overflow: hidden; background: var(--block); box-shadow: inset 0 3px 0 var(--block-side), 0 0 0 3px var(--ink); }
.ld-bar i { display: block; height: 100%; border-radius: inherit; transform-origin: left; animation: ldFill 2.5s cubic-bezier(.45,.05,.4,1) .15s both;
  background: repeating-linear-gradient(-45deg, var(--yellow) 0 10px, #ffd95a 10px 20px); box-shadow: inset 0 -3px 0 var(--yellow-side); }
.ld-step { position: relative; width: 100%; height: 20px; margin: -6px 0 0; text-align: center; font-size: 13px; font-weight: 800; letter-spacing: .04em; color: var(--muted); }
body.night .ld-step { color: #ffe3c4; }
.ld-step span { position: absolute; inset: 0; opacity: 0; animation: ldStep .5s linear calc(.15s + var(--k) * .5s) both; }
.ld-step span:last-child { animation-name: ldStepLast; }
@keyframes ldSpin { to { transform: rotate(360deg); } }
@keyframes ldDrop { from { opacity: 0; transform: translateY(-36px) scale(.6); } }
@keyframes ldFill { from { transform: scaleX(.04); } to { transform: scaleX(1); } }
@keyframes ldStep { 0% { opacity: 0; transform: translateY(6px); } 20%, 80% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translateY(-6px); } }
@keyframes ldStepLast { 0% { opacity: 0; transform: translateY(6px); } 20%, 100% { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  #loader *, #loader *::before { animation: none !important; transition: none !important; }
  .ld-bar i { transform: none; }
  .ld-step span:last-child { opacity: 1; }
  #loader.out .ld-globe { transform: none; }
}

/* ---------- the Chance draw, smoother and dressed up: the wheel gets a body (a dark gold-edged band the cards ride on,
   thin spokes out from the hub), the pointer a pivot pin, and a lamp over the slot flashes as each card passes — the
   lamp stands still outside the wheel, so the turning wheel never repaints; the drawn card turns over in one easy
   swing, throws gold sparks as it lands, then a glint runs across its face ---------- */
.modal.card .roulette { --ch: min(max(11vmin, 54px), 80px); --cw: min(max(15vmin, 72px), 110px); --hub: min(calc(var(--r) * .525), 85px); }
.modal.card .roulette .wheel::before, .modal.card .roulette .wheel::after { content: ''; position: absolute; left: 50%; top: 50%; border-radius: 50%; transform: translate(-50%, -50%); pointer-events: none; z-index: -1; }
.modal.card .roulette .wheel::after { width: calc(var(--r) * 2 + var(--ch) + 14px); height: calc(var(--r) * 2 + var(--ch) + 14px);
  background: radial-gradient(circle, transparent calc(var(--r) - var(--ch) / 2 - 7px), rgba(255, 204, 41, .5) calc(var(--r) - var(--ch) / 2 - 7px), rgba(255, 204, 41, .5) calc(var(--r) - var(--ch) / 2 - 5px),
    rgba(17, 27, 77, .72) calc(var(--r) - var(--ch) / 2 - 5px), rgba(17, 27, 77, .72) calc(var(--r) + var(--ch) / 2 + 5px), rgba(255, 204, 41, .5) calc(var(--r) + var(--ch) / 2 + 5px), rgba(255, 204, 41, .5) calc(var(--r) + var(--ch) / 2 + 7px), transparent calc(var(--r) + var(--ch) / 2 + 7px)); }
.modal.card .roulette .wheel::before { width: calc(var(--r) * 2 - var(--ch) - 10px); height: calc(var(--r) * 2 - var(--ch) - 10px);
  background: repeating-conic-gradient(from -.7deg, rgba(255, 204, 41, .5) 0 1.4deg, transparent 1.4deg calc(360deg / var(--n)));
  -webkit-mask: radial-gradient(circle, transparent calc(var(--hub) + 8px), #000 calc(var(--hub) + 9px)); mask: radial-gradient(circle, transparent calc(var(--hub) + 8px), #000 calc(var(--hub) + 9px)); }
.modal.card .roulette.done .wheel { filter: none; }
/* the hub: a dotted gold ring inside the rim and a soft highlight on top */
.modal.card .roulette .hub::before { content: ''; position: absolute; inset: 9px; border-radius: 50%; border: 2px dotted rgba(255, 204, 41, .55); pointer-events: none; }
.modal.card .roulette .hub::after { content: ''; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; background: radial-gradient(ellipse 60% 40% at 50% 16%, rgba(255, 255, 255, .22), transparent 70%); }
/* the pointer swings from a gold pin */
.modal.card .roulette .pointer::after { content: ''; position: absolute; left: -7px; top: -27px; width: 14px; height: 14px; border-radius: 50%; background: radial-gradient(circle at 40% 35%, #fff2c2, var(--yellow) 55%, #e0a800); box-shadow: 0 0 0 3px var(--ink); }
/* the lamp over the top slot: lit for a moment as each card passes under the pointer */
.modal.card .roulette .lamp { position: absolute; left: 50%; top: calc(50% - var(--r)); width: calc(var(--cw) + 8px); height: calc(var(--ch) + 8px); transform: translate(-50%, -50%); border-radius: 13px;
  opacity: 0; pointer-events: none; z-index: 3; will-change: opacity; background: rgba(255, 255, 255, .16); box-shadow: inset 0 0 0 2px #fff, 0 0 0 2px rgba(255, 255, 255, .45), 0 0 24px 4px rgba(143, 124, 255, .65); }
.modal.card .roulette.done .lamp { display: none; }
/* the drawn card: one easy swing over (the old flip hitched at its midpoint), rising as it turns */
.modal.card .chance-card .cc-inner { animation: ccFlip 1s cubic-bezier(.3, 1.25, .45, 1) both; }
@keyframes ccFlip { from { transform: translateY(28px) rotateY(0) scale(.72); } to { transform: translateY(0) rotateY(180deg) scale(1); } }
/* gold sparks fly out behind it as it lands: two rings of dots, the second turned half a step and smaller */
.modal.card .chance-card::before, .modal.card .chance-card::after { content: ''; position: absolute; inset: -34px; border-radius: 50%; pointer-events: none; z-index: -1; opacity: 0; animation: ccSparks .9s ease-out .3s both;
  background: radial-gradient(circle at 50% 3%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 83% 17%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 97% 50%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 83% 83%, var(--yellow) 3px, transparent 4px),
    radial-gradient(circle at 50% 97%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 17% 83%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 3% 50%, var(--yellow) 3px, transparent 4px), radial-gradient(circle at 17% 17%, var(--yellow) 3px, transparent 4px); }
.modal.card .chance-card::after { inset: -22px; animation-delay: .42s; animation-duration: .8s;
  background: radial-gradient(circle at 69% 7%, #fff 2px, transparent 3px), radial-gradient(circle at 93% 31%, #fff 2px, transparent 3px), radial-gradient(circle at 93% 69%, #fff 2px, transparent 3px), radial-gradient(circle at 69% 93%, #fff 2px, transparent 3px),
    radial-gradient(circle at 31% 93%, #fff 2px, transparent 3px), radial-gradient(circle at 7% 69%, #fff 2px, transparent 3px), radial-gradient(circle at 7% 31%, #fff 2px, transparent 3px), radial-gradient(circle at 31% 7%, #fff 2px, transparent 3px); }
@keyframes ccSparks { 0% { opacity: 0; transform: scale(.5); } 25% { opacity: 1; } 100% { opacity: 0; transform: scale(1.3); } }
/* a glint runs across the face once it is up */
.cc-front .cc-shine { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; pointer-events: none; z-index: 2; }
.cc-front .cc-shine::after { content: ''; position: absolute; top: -20%; bottom: -20%; left: -60%; width: 45%; transform: translateX(0) skewX(-14deg); animation: ccGlint 1.1s cubic-bezier(.4, 0, .2, 1) 1.05s both;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .22) 40%, rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, .22) 60%, transparent); }
@keyframes ccGlint { to { transform: translateX(450%) skewX(-14deg); } }
/* all of it waits, with the flip, until the wheel has stopped */
.chance-card.waiting::before, .chance-card.waiting::after, .chance-card.waiting .cc-shine::after { animation: none; }
/* Okay sits back while the wheel turns, then comes up with the card */
.modal.card > .modal-body > .btn { transition: opacity .4s ease, transform .4s ease; }
.modal.card > .modal-body:has(.chance-card.waiting) > .btn { opacity: .35; transform: translateY(6px); }
@media (prefers-reduced-motion: reduce) {
  .modal.card .chance-card::before, .modal.card .chance-card::after, .cc-front .cc-shine::after { animation: none; }
  .modal.card .chance-card .cc-inner { animation-duration: .01s; }
}

/* ---------- lighter motion ---------- */
/* the halo on the tile the player stands on breathes without a glow filter (a filtered stroke re-blurred every frame
   was a steady drain on every other transition); under the card view's spotlight it holds still */
.tile.here .w-face { filter: none; will-change: auto; }
.board.spot .tile.here .w-face, .board.trade-spot .tile.here .w-face { animation: none !important; }
/* phones: the menu sheet and the pop-ups slide in without a frosted backdrop (re-blurring the board under a moving
   panel is what made them stutter) — a touch more solid instead */
body.mobile.night.watching.menu-open #side { background: rgba(16, 20, 46, .96); }
body.mobile:not(.night).watching.menu-open #side { background: rgba(255, 255, 255, .94); }
body.mobile.night .modal { background: rgba(30, 20, 66, .96); }
body.mobile:not(.night) .modal { background: rgba(255, 255, 255, .96); }

/* ---------- a steadier camera switch ---------- */
/* the die fades in where it lands (the corner zoomed in, the globe's centre zoomed out) rather than popping there in
   the middle of the camera move */
.dice-tray { --from: none; animation: enter .3s ease-out both; }
.dice-tray.docked { animation-delay: .35s; }
/* the tile icons, names and signs come back with an ease-out rather than a flat fade, so they settle instead of snapping */
.board.radial.xf-in :is(.tile-inner, .big, .tile-ic, .rlabel, .arc-price, .signs) { animation: xfLift .25s var(--ease-out) both !important; }
@media (prefers-reduced-motion: reduce) { .dice-tray { animation: none; } }

/* ---------- touch (phones and tablets): bigger targets, no sticky hover, no double-tap delay ---------- */
/* A fingertip covers ~7mm: on coarse pointers every tappable thing is at least 44px tall, with room between neighbours. */
button, .btn, .chip, .lot, .sw, .tk, .tile { touch-action: manipulation; }
@media (pointer: coarse) {
  .swatches { gap: 6px; }
  .sw, .sw.pair { width: 44px; height: 44px; }
  .tokens-pick { gap: 8px; }
  .tk, body.night .tk { height: 44px; }
  .tk .ic, body.night .tk .ic { width: 22px; height: 22px; }
  .chip { min-height: 44px; padding: 10px 14px; }
  .lobby-seats .chip, body.night .lobby-seats .chip { min-height: 44px; padding: 8px 14px 8px 8px; color: inherit; }
  .slot-x { width: 44px; height: 44px; display: grid; place-items: center; margin: -8px -8px -8px 0; }
  .deal-p { min-height: 48px; }
  .cash-in input { min-height: 44px; }
  .rx-chip { position: relative; min-height: 32px; }
  .rx-chip::before { content: ''; position: absolute; inset: -6px; } /* the hit area reaches past the chip */
}
/* no hover on touch screens: a tapped button must not stay lifted or lit once the finger leaves */
@media (hover: none) {
  .btn:hover:not(:disabled):not(:active) { filter: none; transform: none; box-shadow: 0 4px 0 var(--side); }
  .btn.big:hover:not(:disabled):not(:active) { box-shadow: 0 6px 0 var(--side); }
  .tile:hover .w-face, .tile.sq:hover .face { filter: none; }
}
/* the bar's round buttons and the drawer tab: yellow blocks with the ink bezel (the sunset is kept for Roll and the sky) */
body:is(.mobile, .bar) .cam-reset, #topbar .zoom-toggle, body:is(.mobile, .bar) #narr-menu #menu-tab, #game-menu-btn, body.watching #menu-tab { background: var(--yellow); color: var(--ink); }
/* Roll is the one control in the sunset (night) / sun (day) */
body.night :is(#bar-roll, #roll-pop .rp-btns .btn) { background: var(--sunset); color: #2a0f24; }
body:not(.night) :is(#bar-roll, #roll-pop .rp-btns .btn) { background: var(--sun); color: #3a1d06; }
body .map .city.owned.pop .glow { animation: cityRadiate 1.2s ease-out; }
@keyframes enter { from { opacity: 0; transform: var(--from, none); } }
body:has(#game:not([hidden])) #sky { display: none; }
/* ---------- accessibility ---------- */
html { color-scheme: light; }
html:has(body.night) { color-scheme: dark; }
body.night { --focus: #fff4ea; }
/* one keyboard focus ring everywhere (the selection rings are box-shadows, so the two never look alike) */
:where(button, a, input, select, textarea, [tabindex], [role="button"]):focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.tile:focus-visible { outline: none; }
.tile:focus-visible .w-face, .tile.sq:focus-visible .face { stroke: var(--focus); stroke-width: 8px; box-shadow: inset 0 0 0 4px var(--focus); }
/* screen-reader-only text, and the skip link that appears on focus */
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.skip-link { position: fixed; left: 12px; top: calc(var(--safe-top) + 12px); z-index: var(--z-loader); padding: 10px 14px; border-radius: var(--r-sm); background: var(--yellow); color: var(--ink); font-weight: 800; }
.skip-link:not(:focus-visible) { position: fixed; left: -9999px; } /* off screen until a keyboard lands on it */
/* no grey tap flash: every control has its own pressed state */
button, [data-act], .tile { -webkit-tap-highlight-color: transparent; }
/* a scrolling panel keeps its scroll to itself */
.modal, #dock-body, #tray, .invite-card, #side, .lots, #setup { overscroll-behavior: contain; }
.countdown { font-variant-numeric: tabular-nums; }
/* scrollbars: hidden on touch screens (you swipe), thin ones with a mouse so a long panel shows it scrolls */
@media (pointer: fine) {
  * { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, currentColor 30%, transparent) transparent; }
  *::-webkit-scrollbar { display: initial; width: 8px; height: 8px; }
  *::-webkit-scrollbar-thumb { background: color-mix(in srgb, currentColor 30%, transparent); border-radius: 99px; }
}
@media (pointer: coarse) {
  .tab { min-height: 44px; }
  .bp-more { min-height: 40px; padding: 8px 14px; }
  .autoroll { min-height: 40px; }
  .asset-btns .btn { min-height: 40px; }
  body:is(.mobile, .bar) .sheet-x, .tray-x { width: 44px; height: 44px; }
}
/* reduced motion: still things stay put, and what speaks still shows (a toast, a bubble, a cash pop, a played card
   simply appears and goes — the script removes it on a timer) */
@media (prefers-reduced-motion: reduce) {
  .toast, .floater, .card-flash, .emote { animation: none !important; }
  .tile.here .w-face, .board.picking .tile.pickable .w-face, .board.picking .tile.sq.pickable .face, .token.active .t-mark, .jail-turn .t-mark { animation: none !important; }
}
/* player cards and money cards are buttons now */
.pcard, .hud-p { border: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.pcard { width: 100%; }
.pcard .pinfo, .pcard .pcash, .pcard .pname, .pcard .chips { display: block; }
.pcard .pname { display: flex; }
.pcard .chips { display: flex; }
/* Host on Wi-Fi says what it means on the button itself */
#host-net { display: grid; justify-items: center; gap: 2px; }
#host-net small { font: 600 11px/1.1 var(--font); opacity: .8; }
/* the in-game confirm, over everything but the loader */
#confirm-root { position: fixed; inset: 0; z-index: var(--z-confirm); pointer-events: none; }
#confirm-root:empty { display: none; }
.modal.confirm { width: min(380px, 100%); display: grid; gap: 10px; }
.modal.confirm h2 { font: 500 24px/1.15 var(--font); }
.modal.confirm p { margin: 0; color: var(--muted); }
body.night .modal.confirm { color: var(--night-fg); }
.pick-count { margin: -4px 0 0; font-weight: 800; font-variant-numeric: tabular-nums; }
/* your own seat's player card says so */
.badge.you { background: var(--yellow); color: var(--ink); }

/* ---------- the card library (main menu → Cards) ---------- */
#library { position: fixed; inset: 0; z-index: var(--z-draft); display: grid; place-items: center; padding: calc(var(--safe-top) + 12px) 12px calc(var(--safe-bottom) + 12px); background: rgba(10, 15, 35, .72); }
:is(#library, #tab-cards) .lib-card { width: min(920px, 100%); max-height: 100%; display: flex; flex-direction: column; overflow: hidden; border-radius: var(--r-lg);
  background: var(--block); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), 0 6px 0 var(--ink); --from: translateY(14px) scale(.98); animation: enter .35s var(--ease-out); }
body.night :is(#library, #tab-cards) .lib-card { background: #1d2643; color: var(--night-fg); }
.lib-head { flex: none; display: flex; align-items: center; gap: 14px; padding: 14px 16px 10px; flex-wrap: wrap; }
.lib-head h2 { margin: 0; font: 500 26px/1 var(--font); }
.lib-tabs { display: flex; gap: 6px; }
.lib-tabs .tab { flex: none; padding: 8px 14px; }
:is(#library, #tab-cards) .lib-head .lib-x { display: grid !important; place-items: center; width: 44px; height: 44px; margin-left: auto; padding: 0; border: 0; border-radius: 50%; background: rgba(127, 140, 190, .18); color: inherit; cursor: pointer; }
.lib-x .ic { width: 20px; height: 20px; }
.lib-body { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 4px 16px 18px; }
.lib-intro { max-width: 70ch; margin: 0 0 14px; color: var(--muted); font-weight: 600; text-wrap: pretty; }
.lib-sec { margin: 18px 0 10px; font: 500 20px/1.1 var(--font); }
.lib-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 12px; }
.lib-entry { display: flex; gap: 14px; align-items: flex-start; padding: 12px; border-radius: var(--r-md); background: rgba(127, 140, 190, .1); }
.lib-entry .card { flex: none; }
.lib-text { min-width: 0; }
.lib-text h3 { margin: 0 0 4px; font: 800 17px/1.15 var(--font); }
.lib-text p { margin: 0 0 6px; font-weight: 600; text-wrap: pretty; }
.lib-text .lib-more { color: var(--muted); font-size: 13px; }
.lib-text dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; margin: 8px 0 0; font-size: 13px; }
.lib-text dt { font-weight: 800; color: var(--muted); }
.lib-text dd { margin: 0; font-weight: 600; }
:is(#library, #tab-cards) .pick-table { margin: 6px auto 14px; }
:is(#library, #tab-cards) .row.center { justify-content: center; }
.deck-hint { flex-basis: 100%; color: var(--muted); font-size: 13px; }
/* the deck shelf: the saved decks as chips (the one being edited lit, the one in play tagged), then New deck */
.deck-shelf { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.deck-tab, body.night .deck-tab { display: inline-flex; align-items: center; gap: 7px; max-width: 100%; }
.deck-tab b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deck-tab small { flex: none; padding: 3px 6px; border-radius: 999px; box-shadow: inset 0 0 0 2px currentColor; font: 800 10px/1 var(--font); text-transform: uppercase; letter-spacing: .04em; }
.deck-new { opacity: .9; }
.deck-new:disabled { opacity: .4; cursor: default; }
/* the deck's name beside its card count */
.deck-name { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 0 0 12px; font-weight: 700; }
.deck-name label { display: flex; align-items: center; gap: 8px; }
.deck-name input { width: 190px; max-width: 100%; min-height: 44px; padding: 8px 12px; border: 2px solid var(--ink); border-radius: var(--r-sm); font: inherit; font-weight: 600; background: #fff; color: var(--ink); }
body.night .deck-name input { background: #1d2643; color: var(--night-fg); border-color: #3a4670; }
.deck-name .pick-count { margin: 0 0 0 auto; }
/* which of the shelf's decks to bring: a second row of chips under the Decks choice (setup) and Bring a deck (lobby) */
.deck-names { flex-basis: 100%; margin-top: 4px; }
@media (max-width: 640px) { .lib-list { grid-template-columns: 1fr; } .lib-entry { flex-direction: column; align-items: center; text-align: left; } }

/* ---------- Wi-Fi lobby: the host's card and each friend's own menu ---------- */
.join-row { display: flex; gap: 10px; flex-wrap: wrap; }
.join-row input { flex: 1 1 160px; min-width: 0; height: 48px; padding: 0 14px; border: 0; border-radius: var(--r-md); font: 800 20px/48px var(--font); letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink); background: rgba(255, 255, 255, .85); box-shadow: inset 0 0 0 2px var(--ink); }
body.night .join-row input { color: var(--night-fg); background: rgba(10, 13, 31, .55); }
.join-row input[aria-invalid="true"] { box-shadow: inset 0 0 0 2px var(--bad); }
.join-row .btn { min-width: 110px; }
.invite-card { width: min(420px, 100%); text-align: left; justify-items: stretch; }
.invite-card > h2 { margin: 0; font: 500 26px/1.1 var(--font); text-align: center; }
.invite-card > p { margin: -4px 0 0; text-align: center; }
.invite-card .invite-qr { justify-self: center; }
.room-code { justify-self: center; margin-top: -4px; font: 800 30px/1 var(--font); letter-spacing: .2em; font-variant-numeric: tabular-nums; }
.room-tag { padding: 3px 9px; border-radius: 99px; font: 800 13px/1.2 var(--font); letter-spacing: .08em; background: rgba(127, 140, 190, .18); }
.lobby-card { width: min(420px, 100%); text-align: left; justify-items: stretch; }
.lobby-card > h2, .lobby-card > p { text-align: center; }
.lobby-sec { display: grid; gap: 8px; }
.lobby-sec h3 { margin: 4px 0 0; font: 500 17px/1.1 var(--font); }
.lobby-sec .btn.ghost { justify-self: start; }
ul.lobby-seats { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.lobby-seat { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--r-md); background: rgba(127, 140, 190, .1); box-shadow: inset 0 0 0 2px transparent; opacity: .6; }
.lobby-seat.in { opacity: 1; box-shadow: inset 0 0 0 2px var(--pc); }
.lobby-seat b { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lobby-seat b small { font-weight: 600; color: var(--muted); }
.lobby-status { flex: none; font-size: 13px; font-weight: 700; color: var(--muted); }
.lobby-seat.ready .lobby-status { color: var(--good); }
body.night .lobby-seat.ready .lobby-status { color: #7fe3a5; }
.lobby-deck { justify-content: flex-start; }
.lobby-ready { margin-top: 4px; }
.invite-start { margin-top: 4px; }

/* ---------- equal card sizes in the deck picker and the card library ---------- */
/* Every card in a picker is as tall as the tallest one; inside, the counters and the timing tag sit at the bottom. */
.pick-table { display: grid; grid-template-columns: repeat(auto-fill, 100px); grid-auto-rows: 1fr; justify-content: center; }
body.mobile .pick-table { grid-template-columns: repeat(auto-fill, 84px); }
.pick-slot { display: grid; }
.pick-slot .card, body.mobile .pick-slot .card { min-height: 0; height: 100%; grid-template-rows: auto auto 1fr auto auto; }
.lib-entry .card { width: 104px; min-height: 196px; grid-template-rows: auto auto 1fr auto auto; }

/* ---------- main menu: tabs, Play, Me, Friends, Custom game sheet ---------- */
#menu { position: relative; z-index: 1; height: 100%; display: flex; flex-direction: column; }
#menu[hidden] { display: none; }
.menu-panels { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain; padding: calc(var(--safe-top) + 16px) 16px 24px; }
.menu-panel { width: min(480px, 100%); margin: 0 auto; animation: enter .18s var(--ease-out) both; --from: translateY(8px); }
.menu-panel[hidden] { display: none; }
#tab-play { min-height: 100%; display: grid; grid-template-rows: auto auto 1fr auto; justify-items: center; gap: 14px; }
.menu-logo .logo-arc { margin: 8px 0 0; filter: drop-shadow(0 8px 0 rgba(13, 10, 36, .22)); }
/* on a phone the arc runs the full width, so its RUN would sit under the gear (top right): the logo starts lower, clear
   of the gear's bottom edge */
@media (max-width: 640px) { .menu-logo .logo-arc { margin-top: 30px; } .menu-panel:not(#tab-play) { margin-top: 56px; } } /* (the other tabs' cards start under it too) */
body.night .menu-logo .logo-arc { filter: drop-shadow(0 8px 0 rgba(0, 0, 0, .45)) drop-shadow(0 0 28px rgba(249, 154, 92, .28)); }
/* the globe sits on the sky like a toy ball on a table: a soft shadow puddle under it, and at night a warm sunset rim
   light on its lower right that ties it to the peach logo and the sunset Play button */
.menu-globe { position: relative; display: grid; place-items: center; align-self: center; padding-bottom: 26px; }
.menu-globe::before { content: ''; position: absolute; left: 50%; bottom: 0; width: min(230px, 56vw); height: 30px; border-radius: 50%; transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(13, 10, 36, .32) 0%, rgba(13, 10, 36, .14) 48%, transparent 72%); }
body.night .menu-globe::before { background: radial-gradient(ellipse at center, rgba(0, 0, 0, .55) 0%, rgba(0, 0, 0, .22) 48%, transparent 72%); }
.menu-globe .ld-globe { --d: min(260px, 64vw); animation: none; transition: none; }
.menu-globe .ld-globe .ld-spin { animation-duration: 36s; }
body.night .menu-globe .ld-globe { box-shadow: inset 0 0 0 6px #2b86c0, inset -22px -26px 44px -24px rgba(249, 154, 92, .6), 0 0 0 4px var(--ink), 0 0 64px -8px rgba(240, 119, 95, .35), 0 30px 50px -14px rgba(0, 0, 0, .6); }
body.night .menu-globe .ld-shine { background:
    radial-gradient(ellipse 40% 28% at 34% 22%, rgba(255, 255, 255, .42) 0%, rgba(255, 255, 255, .12) 50%, transparent 72%),
    radial-gradient(circle at 40% 36%, transparent 40%, rgba(5, 30, 70, .22) 70%, rgba(5, 30, 70, .55) 96%),
    radial-gradient(ellipse 55% 45% at 86% 84%, rgba(249, 154, 92, .34) 0%, rgba(240, 119, 95, .12) 50%, transparent 76%); }
.menu-play { display: grid; gap: 10px; width: 100%; padding-bottom: 8px; }
/* the Play block: the same ink bezel and light top lip as the board's toy blocks; yellow by day, the sunset at night */
.btn.menu-go, body.night .btn.menu-go { width: 100%; padding: 18px 0 16px; border-radius: var(--r-md); font: 800 1.5rem/1 var(--font); letter-spacing: .03em;
  box-shadow: 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .45), 0 7px 0 var(--ink); }
.btn.menu-go:hover:not(:disabled), body.night .btn.menu-go:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .45), 0 8px 0 var(--ink); }
.btn.menu-go:active:not(:disabled), body.night .btn.menu-go:active:not(:disabled) { transform: translateY(5px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(0, 0, 0, .18), 0 2px 0 var(--ink); }
body.night .btn.menu-go { background: var(--sunset); color: #2a0f24; }
.menu-go small { display: block; font-size: .78rem; font-weight: 600; margin-top: 4px; letter-spacing: 0; opacity: .8; }
.menu-links { display: flex; justify-content: center; gap: 22px; }
.linkish { background: none; border: 0; padding: 10px 4px; min-height: 44px; color: inherit; font: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 2px; text-decoration-color: color-mix(in srgb, currentColor 45%, transparent); cursor: pointer; }
.linkish:hover { text-decoration-color: currentColor; }
body.night .menu-links .linkish { color: #ffe3c4; }
.menu-h { margin: 4px 0 14px; font-size: 1.4rem; }
/* the tab bar: an ink shelf with a light top lip; the chosen tab is a raised yellow block, the rest sit back in the ink */
.menu-tabs { position: relative; display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 8px max(6px, calc((100% - 480px) / 2)) calc(var(--safe-bottom) + 8px); background: var(--ink);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .14), 0 -10px 30px -12px rgba(13, 10, 36, .45); }
body.night .menu-tabs { box-shadow: inset 0 2px 0 rgba(255, 255, 255, .1), 0 -10px 30px -12px rgba(0, 0, 0, .7); }
.menu-tabs [role="tab"] { display: grid; justify-items: center; gap: 3px; min-height: 52px; padding: 7px 0 6px; border: 2px solid transparent; border-radius: var(--r-md); background: none; color: rgba(255, 255, 255, .72); font: inherit; font-size: .75rem; font-weight: 700; cursor: pointer; transition: transform .18s var(--ease-out), background-color .18s var(--ease-out), color .18s var(--ease-out); }
.menu-tabs [role="tab"]:hover { color: #fff; }
.menu-tabs [role="tab"] .ic { width: 22px; height: 22px; }
.menu-tabs [aria-selected="true"] { background: var(--yellow, #ffd23f); color: var(--ink); border-color: var(--ink); transform: translateY(-6px); box-shadow: inset 0 2px 0 rgba(255, 255, 255, .45), 0 4px 0 #000; }
.menu-tabs [aria-selected="true"]:active { transform: translateY(-3px); box-shadow: inset 0 2px 0 rgba(255, 255, 255, .45), 0 1px 0 #000; }
.menu-tabs [role="tab"]:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.me-field { display: grid; gap: 6px; margin-bottom: 16px; font-weight: 700; }
.me-field input { min-height: 44px; padding: 8px 12px; border: 2px solid var(--ink); border-radius: var(--r-sm); font: inherit; font-weight: 600; background: #fff; color: var(--ink); }
.me-field p { margin: 0; font-weight: 500; }
/* The Google account, at the top of the customisation popup: who you are and Sign out signed in; a guest's lock and Google's button */
.me-account { display: grid; justify-items: start; gap: 6px; margin: 0 0 18px; padding: 12px 14px; border: 2px solid var(--ink); border-radius: var(--r-md); }
.me-account p { margin: 0; }
.me-who { display: grid; gap: 2px; }
.me-who b { font-size: 1.05rem; }
.me-who small { font-size: 12px; font-weight: 600; opacity: .75; overflow-wrap: anywhere; }
body.night .me-account { border-color: #3a4670; }
#tab-cards .lib-in-tab { border-radius: var(--r-lg); overflow: hidden; }
#tab-cards .lib-head .lib-x { display: none !important; }
.fr-static { display: grid; gap: 10px; margin-bottom: 22px; }
.fr-sec { margin-bottom: 20px; }
.fr-sec h3 { margin: 0 0 8px; font-size: 1rem; }
.fr-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.fr-list li { display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 6px 10px; border: 2px solid var(--ink); border-radius: var(--r-md); background: #fff; color: var(--ink); }
.fr-list li > span { flex: 1; display: grid; }
.fr-list small { font-weight: 500; opacity: .75; }
.fr-pawn { width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--ink); background: var(--pc); flex: none; }
.fr-dot { display: inline-block; width: 9px; height: 9px; margin-left: 6px; border-radius: 50%; background: var(--good); border: 1px solid var(--ink); vertical-align: middle; }
body.night .fr-list li, body.night .me-field input { background: #1d2643; color: var(--night-fg); border-color: #3a4670; }
.fr-invite { position: fixed; left: 50%; bottom: calc(var(--safe-bottom) + 84px); z-index: var(--z-popover); width: min(360px, calc(100% - 32px)); transform: translateX(-50%); padding: 14px 16px; border: 3px solid var(--ink); border-radius: var(--r-lg); background: #fff; color: var(--ink); box-shadow: 0 6px 0 var(--ink); animation: enter .3s var(--ease-out) both; --from: translate(-50%, 16px); }
.fr-invite p { margin: 0 0 10px; }
.fr-invite-btns { display: flex; gap: 8px; }
/* the Custom game sheet. The old full-page #setup rules (position, height, padding, zoom, max-width) are beaten by id + class + body. */
/* (must stay below the old #setup rules near line 522-531: these win their specificity ties by coming later) */
body #setup.custom-sheet { position: fixed; inset: 0; z-index: var(--z-draft); display: block; height: auto; zoom: 1; overflow: auto; overscroll-behavior: contain; padding: calc(var(--safe-top) + 40px) 16px 0; background: rgba(10, 15, 35, .55); }
body #setup.custom-sheet[hidden] { display: none; }
/* Start game sticks to the sheet's bottom edge (the phone rule pins it to the screen, which covered the last options) */
body #setup.custom-sheet .setup-foot { position: sticky; left: auto; right: auto; bottom: 0; margin: 8px -16px 0; padding: 12px 16px calc(var(--safe-bottom) + 12px); }
body #setup.custom-sheet .setup-inner { zoom: 1; width: min(560px, 100%); max-width: 560px; min-height: 100%; margin: 0 auto; padding: 16px 16px calc(var(--safe-bottom) + 24px); border-radius: var(--r-lg) var(--r-lg) 0 0; background: var(--sky-1, #fff3d6); animation: enter .32s var(--ease-camera) both; --from: translateY(40px); }
body.night #setup.custom-sheet .setup-inner { background: #141b33; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; }
.sheet-head h2 { margin: 0; }
body #setup.custom-sheet .sheet-x { display: grid; place-items: center; width: 44px; height: 44px; margin: 0; padding: 0; border: 0; border-radius: 50%; background: rgba(127, 140, 190, .18); color: inherit; cursor: pointer; }
body #setup.custom-sheet .sheet-x .ic { width: 20px; height: 20px; }
body #setup.custom-sheet .sheet-x:active { transform: scale(.92); }
@media (prefers-reduced-motion: reduce) {
  .menu-panel, body #setup.custom-sheet .setup-inner, .fr-invite { animation: none; }
  .menu-globe .ld-spin { animation: none; }
  .menu-tabs [role="tab"] { transition: none; }
}

/* ---------- Deal: a sheet over a live board ---------- */
/* the board stays tappable round the Deal sheet (lots are tapped onto the table); desktop gets the sheet too, low
   on the right, so the ring stays in view */
.backdrop[data-kind="deal"] { background: none; pointer-events: none; place-items: end end; }
.backdrop[data-kind="deal"] .modal { pointer-events: auto; }
.backdrop.enter[data-kind="deal"] .modal { animation: sheetUp .18s var(--ease-out); }
body:not(.mobile) .backdrop[data-kind="deal"] { padding-bottom: 96px; } /* (clear of the players' cards) */
body:not(.mobile) .modal.deal { max-height: min(560px, calc(100dvh - 120px)); }
.modal.deal .deal-head .countdown { margin-left: 4px; }
.modal.deal .deal-pick { margin: 8px 0 0; font-size: 13px; }
.deal-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 4px 16px 10px; display: grid; gap: 12px; align-content: start; }
.deal-side { display: grid; gap: 8px; padding: 10px; border-radius: var(--r-md); background: color-mix(in srgb, var(--pc) 10%, transparent); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--pc) 45%, transparent); }
.deal-side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.deal-side-head h4 { margin: 0; font: 500 15px/1.1 var(--font); display: grid; }
.deal-side-head h4 small { font: 800 12px/1.2 inherit; color: var(--muted); }
.deal-side-head h4 small.neg { color: var(--bad); }
.cash-step { display: flex; align-items: center; gap: 4px; }
.cash-step label { display: flex; align-items: center; gap: 2px; margin: 0; font-weight: 800; }
.cash-step input { width: 72px; font-size: 17px; text-align: right; } /* (16px+: iOS doesn't zoom the page into the field) */
.cash-step .step { width: 36px; height: 36px; border: 0; border-radius: 50%; background: #eef2f8; color: var(--ink); font: 800 20px/1 inherit; cursor: pointer; box-shadow: 0 2px 0 var(--block-side); }
.cash-step .step:active { transform: translateY(2px); box-shadow: none; }
.deal-picked { display: flex; flex-wrap: wrap; gap: 6px; }
.deal-picked .lot { height: 38px; display: inline-flex; align-items: center; gap: 6px; padding: 0 10px 0 26px; font-size: 14px; }
.deal-picked .lot::before { left: 9px; }
/* a lot on the table: the colour it leaves at its left edge, the colour it goes to at its right */
.deal-picked .lot.on { box-shadow: inset 5px 0 0 var(--lot-from), inset -5px 0 0 var(--lot-to), 0 3px 0 var(--yellow-side); }
.deal-picked .lot.on .ic { width: 14px; height: 14px; opacity: .7; }
.deal-picked .lot.add { padding: 0 12px; background: none; box-shadow: inset 0 0 0 2px var(--block-side); color: var(--muted); }
.deal-picked .lot.add::before { display: none; }
.deal-picked .lot.add.open { color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink); }
.deal-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 6px; }
.deal-list .lot { height: 42px; font-size: 14px; }
.deal-list .lot.on { box-shadow: inset 5px 0 0 var(--lot-from), inset -5px 0 0 var(--lot-to), 0 3px 0 var(--yellow-side); }
body.night .deal-side-head h4 small { color: var(--night-muted, #a9b3d6); }
body.night .cash-step .step { background: #2b3558; color: var(--night-fg); box-shadow: 0 2px 0 #10162c; }
body.night .deal-picked .lot.add { background: none; color: var(--night-fg); box-shadow: inset 0 0 0 2px #3a4670; }

/* an accepted deal, played back: the two sides named over the board, the cash flying between their cards */
.trade-banner { position: absolute; left: 50%; top: 22%; z-index: 40; display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: 999px;
  background: var(--ink); color: #fff; font: 500 18px/1 var(--font); box-shadow: 0 6px 24px rgba(0, 0, 0, .35); pointer-events: none;
  transform: translateX(-50%); animation: tradeBanner 2.2s var(--ease-out) both; }
.trade-banner > span { display: flex; align-items: center; gap: 6px; }
.trade-banner .ptoken { width: 30px; height: 30px; }
.trade-banner > b .ic { width: 26px; height: 26px; color: var(--yellow); }
@keyframes tradeBanner { 0% { opacity: 0; transform: translateX(-50%) scale(.8); } 12%, 82% { opacity: 1; transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) scale(1); } }
.cash-fly { position: fixed; z-index: 60; padding: 4px 10px; border-radius: 999px; background: var(--good); color: #fff; font: 800 15px/1 inherit; pointer-events: none; box-shadow: 0 3px 10px rgba(0, 0, 0, .3); }
@media (prefers-reduced-motion: reduce) { .trade-banner { animation: none; } }

/* ---------- the pawn ---------- */
/* One pawn everywhere — the board, the player cards, the HUD, a lobby seat: an outline in ink, a rim and the icon in
   the player's secondary colour, the fill in the primary. The .pf is its face; its host (.pawn on the board, .ptoken on
   cards and the HUD, .slot-pawn in setup) only sizes it and glows round it (a filter, so the glow follows the outline).
   The look comes as variables (ui.lookVars): --pc, --pc2 (missing: a dark or white ink that reads on --pc), --clip the
   outline (round: none, the radius does it; shaped: --br 0 and --ic scales the icon to the room the shape leaves). */
.ptoken, .slot-pawn { position: relative; } /* (the board's .pawn is already placed absolutely: its turn arrow hangs off that) */
.ptoken, .slot-pawn, .pawn { background: none !important; box-shadow: none !important;
  --ink2: oklch(from var(--pc) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265);
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--pc) 70%, transparent)); }
.pf { position: absolute; inset: 0; display: grid; place-items: center; border-radius: var(--br, 50%); clip-path: var(--clip, none); background: var(--ink); }
.pf::before, .pf::after { content: ''; position: absolute; border-radius: inherit; clip-path: var(--clip, none); }
.pf::before { inset: 7%; background: var(--pc2, var(--ink2)); }
.pf::after { inset: 16%; background: radial-gradient(circle at 34% 28%, rgba(255, 255, 255, .9) 0 8%, color-mix(in srgb, var(--pc) 60%, #fff) 20%, var(--pc) 50%, color-mix(in srgb, var(--pc) 70%, #000) 100%); }
.pf .ic { position: relative; z-index: 1; width: calc(56% * var(--ic, 1)); height: calc(56% * var(--ic, 1)); color: var(--pc2, var(--ink2)); filter: drop-shadow(0 0 1px rgba(16, 20, 44, .55)); }
body.night :is(.ptoken, .slot-pawn) { filter: drop-shadow(0 0 4px var(--pc)) drop-shadow(0 0 10px color-mix(in srgb, var(--pc) 55%, transparent)); }
.hud-p.up .ptoken { filter: drop-shadow(0 0 5px var(--pc)) drop-shadow(0 0 12px var(--pc)); }
.pawn { filter: saturate(1.3) brightness(1.08) drop-shadow(0 0 5px var(--pc)) drop-shadow(0 0 10px color-mix(in srgb, var(--pc) 60%, transparent)); }
.token.active .pawn { filter: saturate(1.4) brightness(1.12) drop-shadow(0 0 6px var(--pc)) drop-shadow(0 0 16px var(--pc)); }
.pawn .pf .ic { filter: drop-shadow(0 0 1px rgba(16, 20, 44, .7)) drop-shadow(0 1px 0 rgba(255, 255, 255, .35)); }

/* ---------- turn cues: how a pawn shows it's up (Me → Turn cue) ---------- */
/* The arrow is the .t-mark above; every other cue is drawn on the .t-cue, a ring round the pawn's box (the crown is
   its icon, shown where the arrow would be). Only an active token shows any of it. */
.t-cue { --cue: calc(var(--chip, 26px) + 16px); position: absolute; display: none; left: calc(var(--cue) / -2); top: calc(var(--cue) / -2); width: var(--cue); height: var(--cue); border-radius: 50%; pointer-events: none; }
.t-cue .ic { display: none; }
.token.active:not(.cue-arrow) .t-mark { display: none; }
.token.active:not(.cue-arrow) .t-cue { display: block; }
.token.active.cue-crown .t-cue { display: grid; place-items: center; width: 26px; height: 20px; left: -13px; top: auto; bottom: calc(var(--chip, 26px) / 2 + 2px); border-radius: 0; animation: bob 1s ease-in-out infinite; will-change: transform; }
.token.active.cue-crown .t-cue .ic { display: block; width: 22px; height: 22px; color: var(--yellow); filter: drop-shadow(0 0 1px var(--ink)) drop-shadow(0 0 1px var(--ink)) drop-shadow(0 1.5px 0 var(--ink)) drop-shadow(0 0 4px #fff); }
/* halo: rings breathing out from the pawn's edge */
.token.active.cue-halo .t-cue::before, .token.active.cue-halo .t-cue::after { content: ''; position: absolute; inset: 8px; border-radius: 50%; border: 2.5px solid var(--pc); box-shadow: 0 0 6px var(--pc), inset 0 0 6px var(--pc); animation: cueHalo 1.6s ease-out infinite; }
.token.active.cue-halo .t-cue::after { animation-delay: .8s; }
@keyframes cueHalo { 0% { transform: scale(.9); opacity: 1; } 100% { transform: scale(2); opacity: 0; } }
/* orbit: two sparks circling */
.token.active.cue-orbit .t-cue { animation: cueSpin 1.8s linear infinite; }
.token.active.cue-orbit .t-cue::before, .token.active.cue-orbit .t-cue::after { content: ''; position: absolute; left: 50%; top: 1px; width: 8px; height: 8px; margin-left: -4px; border-radius: 50%; background: var(--pc2, #fff); box-shadow: 0 0 0 1.5px var(--ink), 0 0 7px var(--pc2, #fff); }
.token.active.cue-orbit .t-cue::after { top: auto; bottom: 1px; }
@keyframes cueSpin { to { transform: rotate(360deg); } }
/* beacon: a radar sweep round the pawn */
.token.active.cue-beacon .t-cue { background: conic-gradient(from 0deg, transparent 0 50%, color-mix(in srgb, var(--pc) 0%, transparent) 50%, var(--pc) 100%);
  -webkit-mask: radial-gradient(closest-side, transparent calc(100% - 8px), #000 calc(100% - 7px)); mask: radial-gradient(closest-side, transparent calc(100% - 8px), #000 calc(100% - 7px)); animation: cueSpin 1.4s linear infinite; }
/* dashes: a dashed ring turning slowly */
.token.active.cue-dashes .t-cue { --cue: calc(var(--chip, 26px) + 10px); border: 3px dashed var(--pc2, #fff); filter: drop-shadow(0 0 3px var(--pc)); animation: cueSpin 7s linear infinite; }
/* sparkle: twinkling stars wandering round the pawn */
.token.active.cue-sparkle .t-cue { animation: cueSpin 5s linear infinite; }
.token.active.cue-sparkle .t-cue::before, .token.active.cue-sparkle .t-cue::after { content: ''; position: absolute; width: 12px; height: 12px; background: #fff; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%); animation: cueTwinkle 1.2s ease-in-out infinite; }
.token.active.cue-sparkle .t-cue::before { left: 2px; top: 0; }
.token.active.cue-sparkle .t-cue::after { right: 0; bottom: 4px; animation-delay: .6s; }
@keyframes cueTwinkle { 0%, 100% { transform: scale(.3) rotate(0); opacity: .2; } 50% { transform: scale(1) rotate(45deg); opacity: 1; } }

/* ---------- Me: your pawn, dressed the way a Geometry Dash character is ---------- */
/* The pawn big on a stage at the top, its turn cue going; under it one part at a time to pick from. */
.me-look { display: grid; gap: 12px; margin-bottom: 18px; }
.me-stage { position: relative; height: 156px; border-radius: var(--r-lg); overflow: hidden;
  background: radial-gradient(ellipse 80% 70% at 50% 100%, color-mix(in srgb, var(--pc) 28%, transparent), transparent 70%),
    repeating-radial-gradient(circle at 50% 170%, transparent 0 34px, rgba(255, 255, 255, .06) 34px 36px), linear-gradient(180deg, #1b2244, #10142c);
  box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .12), 0 6px 0 var(--ink); }
.me-stage .token { position: absolute; left: 50%; top: 44%; --chip: 64px; --rot: 0deg; }
.me-stage .pawn { --chip: 64px; }
.me-tag { position: absolute; left: 50%; bottom: 12px; max-width: 80%; transform: translateX(-50%); padding: 4px 12px; border-radius: 999px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: var(--pc); color: oklch(from var(--pc) clamp(0.25, (0.62 - l) * 1000, 1) 0.03 265); font: 800 13px/1.3 var(--font); box-shadow: 0 0 0 2px var(--ink); }
.look-tabs { margin-top: 2px; }
.look-part.slide { animation: enter .18s var(--ease-out) both; --from: translateY(6px); } /* (switching parts only: a pick redraws without the blink) */
.me-tokens { grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 6px; }
.me-tokens .tk, body.night .me-tokens .tk { height: 44px; }
.me-tokens .tk .ic, body.night .me-tokens .tk .ic { width: 22px; height: 22px; }
.shapes-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; }
.shp, body.night .shp { position: relative; display: grid; justify-items: center; gap: 5px; padding: 8px 4px 7px; border: 0; border-radius: var(--r-md); background: rgba(255, 255, 255, .75); color: var(--ink); font: 800 11px/1 var(--font); box-shadow: inset 0 0 0 2px var(--ink); cursor: pointer; }
body.night .shp { background: rgba(10, 13, 31, .55); color: var(--night-fg); }
.shp .pf { position: relative; inset: auto; width: 44px; height: 44px; }
.shp.on, body.night .shp.on { background: var(--yellow); color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .45), 0 3px 0 var(--ink); }
.shp:focus-visible, .cue-pick:focus-visible { outline: 3px solid var(--pc, var(--yellow)); outline-offset: 2px; }
.me-sub { display: flex; align-items: baseline; gap: 8px; margin: 4px 0 2px; font-weight: 800; }
.me-sub small { font-weight: 600; opacity: .75; }
.me-look .swatches { gap: 7px; margin: 0; }
.me-look .sw { width: 40px; height: 40px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22), 0 0 0 2px var(--ink); } /* (the faint inner line keeps a black disc visible on the night card) */
.me-look .sw.on { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .22), 0 0 0 2px var(--ink), 0 0 0 5px var(--yellow); }
.me-look .sw:disabled { opacity: .35; background: linear-gradient(135deg, var(--c) 0 43%, var(--ink) 43% 57%, var(--c) 57%); } /* struck through: too close to the primary */
.cues-pick { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 8px; }
.cue-pick { position: relative; display: grid; justify-items: center; align-content: end; height: 98px; padding: 0 4px 8px; border: 0; border-radius: var(--r-md); overflow: hidden;
  background: linear-gradient(180deg, #1b2244, #10142c); color: #fff; font: 800 11px/1 var(--font); box-shadow: inset 0 0 0 2px var(--ink); cursor: pointer; }
.cue-pick .token { position: absolute; left: 50%; top: 42%; --chip: 30px; --rot: 0deg; }
.cue-pick.on { box-shadow: inset 0 0 0 3px var(--yellow); }
.cue-pick.on small { color: var(--yellow); }
/* a game's setup and the Wi-Fi lobby offer every token in one strip that scrolls sideways */
.slot .tokens-pick, .seat-edit .tokens-pick { display: flex; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; padding: 2px 2px 6px; margin: 0 -2px; }
.slot .tokens-pick .tk, .seat-edit .tokens-pick .tk { flex: none; width: 40px; scroll-snap-align: start; }
@media (pointer: coarse) { .slot .tokens-pick .tk, .seat-edit .tokens-pick .tk { width: 44px; } }

/* The socket is down: the game's buttons wait, and a pill says so until it is back. */
body.offline #actions button, body.offline #roll-pop button, body.offline #buy-pop button { opacity: .5; pointer-events: none; }
body.offline::after { content: 'Reconnecting…'; position: fixed; top: 8px; left: 50%; transform: translateX(-50%); padding: 4px 10px; border-radius: 999px; background: var(--ink); color: var(--util-face); font-size: 12px; z-index: 99; }

/* ---------- the Settings window (spec 2026-11-02-settings-menu-guest, section 2) ---------- */
/* the game's own look: a bevelled block with an ink edge and the light inner rim, chunky pills, the yellow for what is
   chosen, every control at least 44px tall */
#overlay-root { position: fixed; inset: 0; z-index: var(--z-overlay); pointer-events: none; }
#overlay-root:empty { display: none; }
#overlay-root .backdrop { position: fixed; padding: calc(var(--safe-top) + 16px) 16px calc(var(--safe-bottom) + 16px); }
.set-panel, .pp-card { width: min(420px, 100%); max-height: 100%; overflow: auto; overscroll-behavior: contain; padding: 16px 18px 18px; border-radius: var(--r-lg);
  background: var(--block); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .55), 0 7px 0 var(--ink), 0 30px 50px -20px rgba(10, 15, 35, .6); }
body.night :is(.set-panel, .pp-card) { color: var(--night-fg); box-shadow: 0 0 0 2px #05070f, inset 0 3px 0 rgba(255, 255, 255, .12), 0 7px 0 #05070f, 0 30px 50px -20px rgba(0, 0, 0, .8); }
.backdrop.enter :is(.set-panel, .pp-card) { --from: scale(.92) translateY(12px); animation: enter .4s var(--ease-out); }
.set-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.set-head h2 { display: flex; align-items: center; gap: 8px; margin: 0; font: 500 26px/1.1 var(--font); }
.set-head h2 .ic { width: 24px; height: 24px; }
#overlay-root .set-head .sheet-x { display: grid; place-items: center; width: 44px; height: 44px; margin: 0; padding: 0; border: 0; border-radius: 50%; background: rgba(127, 140, 190, .18); color: inherit; cursor: pointer; }
#overlay-root .set-head .sheet-x .ic { width: 20px; height: 20px; }
#overlay-root .set-head .sheet-x:active { transform: scale(.92); }
.set-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px 12px; min-height: 52px; padding: 6px 0; border-top: 2px solid rgba(127, 140, 190, .18); font-weight: 800; }
.set-slide { grid-template-columns: 1fr 3.4em; }
.set-slide label { grid-column: 1 / -1; }
.set-slide output { font: 800 14px/1 var(--font); text-align: right; }
.set-slide input[type=range] { -webkit-appearance: none; appearance: none; width: 100%; height: 44px; margin: 0; background: none; cursor: pointer; }
.set-slide input[type=range]::-webkit-slider-runnable-track { height: 12px; border-radius: 99px; background: linear-gradient(90deg, var(--yellow) var(--fill, 50%), #cfd6e4 var(--fill, 50%)); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(0, 0, 0, .15); }
.set-slide input[type=range]::-moz-range-track { height: 12px; border-radius: 99px; background: #cfd6e4; box-shadow: 0 0 0 2px var(--ink); }
.set-slide input[type=range]::-moz-range-progress { height: 12px; border-radius: 99px; background: var(--yellow); }
body.night .set-slide input[type=range]::-webkit-slider-runnable-track { background: linear-gradient(90deg, var(--yellow) var(--fill, 50%), #46507a var(--fill, 50%)); box-shadow: 0 0 0 2px #05070f, inset 0 2px 0 rgba(0, 0, 0, .25); }
body.night .set-slide input[type=range]::-moz-range-track { background: #46507a; box-shadow: 0 0 0 2px #05070f; }
.set-slide input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 30px; height: 30px; margin-top: -9px; border-radius: 50%; background: #fff; box-shadow: 0 0 0 2px var(--ink), inset 0 -3px 0 rgba(0, 0, 0, .18), 0 3px 0 var(--ink); }
.set-slide input[type=range]::-moz-range-thumb { width: 28px; height: 28px; border: 0; border-radius: 50%; background: #fff; box-shadow: 0 0 0 2px var(--ink), 0 3px 0 var(--ink); }
.set-slide input[type=range]:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 99px; }
/* (each pair the same width, so the rows' pills line up down the window) */
.pills { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 4px; min-width: 164px; padding: 4px; border-radius: 99px; background: rgba(127, 140, 190, .18); }
.pill { min-width: 64px; min-height: 44px; padding: 0 16px; border: 0; border-radius: 99px; background: none; color: inherit; font: 800 14px/1 var(--font); cursor: pointer; transition: transform .15s var(--ease-out); }
.pill.on { background: var(--yellow); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .5), 0 3px 0 var(--ink); }
.pill:active { transform: translateY(2px); }
.pill:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.set-account { padding-top: 12px; border-top: 2px solid rgba(127, 140, 190, .18); }
.set-account p { margin: 0 0 8px; font-weight: 600; }
.gsi-slot { min-height: 44px; }
/* the main menu's gear, top right */
.menu-gear { position: absolute; z-index: 2; top: calc(var(--safe-top) + 12px); right: calc(env(safe-area-inset-right, 0px) + 14px); display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: var(--yellow); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .45), inset 0 -3px 0 rgba(0, 0, 0, .25), 0 4px 0 var(--ink); }
.menu-gear .ic { width: 26px; height: 26px; }
.menu-gear:active { transform: translateY(3px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(255, 255, 255, .4), 0 1px 0 var(--ink); }
/* Decals off: no landmark line art on the tiles */
body.no-decals .board.radial .motif { display: none; }

/* ---------- hidden hands (spec 2026-11-02-settings-menu-guest, section 3) ---------- */
/* another seat's hand: a fan of small card backs in the Fortune blue with the count, on its player card and HUD dial */
.backs { display: inline-flex; align-items: center; margin-top: 3px; }
.backs .cb { width: 11px; height: 15px; margin-right: -5px; border-radius: 3px; background: repeating-linear-gradient(45deg, #3a2f86 0 3px, var(--fortune) 3px 6px); box-shadow: 0 0 0 1.5px var(--ink), inset 0 0 0 1.5px rgba(255, 255, 255, .55); transform: rotate(calc(var(--r, 0) * 1deg)); }
.backs .cb:nth-child(1) { --r: -8; } .backs .cb:nth-child(2) { --r: -2; } .backs .cb:nth-child(3) { --r: 5; }
.backs .cb.fortune { background: var(--yellow); }
.backs b { margin-left: 9px; font: 800 11px/1 var(--font); }
.backs.sm .cb { width: 8px; height: 11px; margin-right: -4px; }
.backs.sm b { margin-left: 7px; font-size: 10px; }
.backs.big .cb { width: 44px; height: 62px; margin-right: -16px; border-radius: 8px; box-shadow: 0 0 0 2px var(--ink), inset 0 0 0 3px rgba(255, 255, 255, .55), 0 4px 0 var(--ink); }
.backs.big b { display: none; }
/* hot-seat: the hand face down after a hand-over, until its player taps Show my cards */
.hand-hidden { display: grid; justify-items: center; gap: 14px; padding: 14px 8px; text-align: center; }
.hand-hidden p { margin: 0; }
.hand-hidden .backs.big { padding-right: 16px; }
.hand.peek .hand-hidden { gap: 8px; padding: 6px; }
/* (on a phone the peek floats over the board, often over a buy sign: the face-down hand sits on the same panel face as
   the face-up cards, so its line stays readable) */
body.mobile .hand.peek .hand-hidden { max-width: min(340px, calc(100vw - 32px)); padding: 12px 16px 14px; border-radius: var(--r-md);
  background: var(--block); color: var(--ink); box-shadow: 0 3px 0 var(--block-side), inset 0 0 0 2px rgba(255, 255, 255, .5); }
body.mobile.night .hand.peek .hand-hidden { background: #1d2643; color: var(--night-fg); box-shadow: 0 3px 0 #0e1328, inset 0 0 0 1px rgba(255, 255, 255, .12); }
.hand.peek .hand-hidden .backs.big .cb { width: 30px; height: 42px; margin-right: -11px; }

/* ---------- the profile box and the customisation popup (spec 2026-11-02-settings-menu-guest, section 1) ---------- */
/* under the logo: a raised block with your pawn and name; a guest's adds Sign in in small */
.profile-box { display: inline-flex; align-items: center; gap: 10px; min-height: 52px; max-width: 100%; padding: 6px 18px 6px 8px; border: 0; border-radius: 99px; cursor: pointer;
  background: var(--block); color: var(--ink); font: inherit; box-shadow: 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .55), 0 5px 0 var(--ink); transition: transform .15s var(--ease-out); }
body.night .profile-box { color: var(--night-fg); }
.profile-box:hover { transform: translateY(-1px); }
.profile-box:active { transform: translateY(4px); box-shadow: 0 0 0 2px var(--ink), inset 0 2px 0 rgba(0, 0, 0, .12), 0 1px 0 var(--ink); }
.profile-box:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.profile-box .pb-pawn { width: 38px; height: 38px; flex: none; }
.pb-name { display: grid; text-align: left; min-width: 0; }
.pb-name b { font-weight: 800; font-size: 1.05rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pb-name small { font-size: .75rem; font-weight: 700; color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.pp-card .me-account { margin-bottom: 14px; }
.pp-lock { justify-items: center; text-align: center; }
.pp-lock > .ic { width: 26px; height: 26px; }
.me-look.locked :is(.tk, .shp, .sw, .cue-pick):disabled:not(.on) { opacity: .45; }
/* (the look a guest wears stays at full strength; a locked swatch is its plain colour, not struck through: the stripe
   means "too close to the primary", which has a title) */
.me-look.locked :is(.tk, .shp, .sw, .cue-pick).on:disabled { opacity: 1; cursor: default; }
.me-look.locked .sw:disabled:not([title]) { background: var(--c); }
.me-look.locked input:disabled { opacity: .7; }
/* the part tabs: four equal blocks in a row, raised off the popup's face by day as by night */
.pp-card .look-tabs { display: grid; grid-template-columns: repeat(4, 1fr); }
.pp-card .look-tabs .chip { padding-inline: 4px; white-space: nowrap; }
body:not(.night) .pp-card .look-tabs .chip:not(.on) { background: #fff; box-shadow: inset 0 0 0 2px var(--ink), inset 0 -3px 0 rgba(21, 26, 51, .08), 0 3px 0 var(--ink); }
/* a guest's Your decks: the lock, the reason and Google's button */
.lib-lock { display: grid; justify-items: center; gap: 8px; padding: 28px 16px; text-align: center; }
.lib-lock > .ic { width: 34px; height: 34px; }
.lib-lock p { margin: 0; }

/* ---------- the welcome and the guest warning (spec 2026-11-02-settings-menu-guest, section 1) ---------- */
#welcome { position: fixed; inset: 0; z-index: var(--z-draft); display: grid; place-items: center; overflow: auto; padding: calc(var(--safe-top) + 20px) 16px calc(var(--safe-bottom) + 20px);
  background: rgba(10, 15, 35, .5); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
#welcome[hidden] { display: none; }
/* the welcome card carries the logo: the menu's own big logo hides behind it (its space kept), back once the welcome closes */
body:has(#welcome:not([hidden])) .menu-logo { visibility: hidden; }
.welcome-card { width: min(400px, 100%); display: grid; justify-items: center; gap: 16px; padding: 22px 20px 24px; border-radius: var(--r-lg); text-align: center;
  background: var(--block); color: var(--ink); box-shadow: 0 0 0 2px var(--ink), inset 0 3px 0 rgba(255, 255, 255, .55), 0 7px 0 var(--ink), 0 30px 50px -20px rgba(10, 15, 35, .6);
  --from: scale(.94) translateY(10px); animation: enter .4s var(--ease-out); }
body.night .welcome-card { color: var(--night-fg); box-shadow: 0 0 0 2px #05070f, inset 0 3px 0 rgba(255, 255, 255, .12), 0 7px 0 #05070f, 0 30px 50px -20px rgba(0, 0, 0, .8); }
.welcome-card h2 { margin: 0; font: 500 26px/1.1 var(--font); }
.welcome-card p { margin: 0; }
.wl-logo { width: 92%; margin-top: 2px; filter: drop-shadow(0 6px 0 rgba(13, 10, 36, .16)); }
.wl-logo .arc-logo { width: 100%; height: auto; }
.wl-sub { font-weight: 600; }
.wl-gsi { display: grid; justify-items: center; min-height: 44px; }
.wl-guest { width: min(300px, 100%); min-height: 44px; padding: 10px 18px; font-size: .95rem; }
/* (day: the ghost button's white face would vanish into the white card; a cool grey face keeps it a button) */
body:not(.night) .welcome-card .btn.ghost { --face: #e9edf7; --side: rgba(30, 37, 64, .22); }
.wl-warn .row { display: flex; gap: 8px; width: 100%; }
.wl-warn .row .btn { flex: 1; min-height: 48px; }

/* ---------- forfeiting: the seat's pawn, player card and HUD dial grey out for the 3-second moment ---------- */
body[data-forfeit="0"] :is(.token[data-pid="0"], .pcard[data-pid="0"], .hud-p[data-pid="0"]),
body[data-forfeit="1"] :is(.token[data-pid="1"], .pcard[data-pid="1"], .hud-p[data-pid="1"]),
body[data-forfeit="2"] :is(.token[data-pid="2"], .pcard[data-pid="2"], .hud-p[data-pid="2"]),
body[data-forfeit="3"] :is(.token[data-pid="3"], .pcard[data-pid="3"], .hud-p[data-pid="3"]) { filter: grayscale(1) brightness(.8); opacity: .55; transition: filter .5s, opacity .5s; }
#forfeit-note { position: absolute; left: 50%; top: 42%; z-index: 15; transform: translate(-50%, -50%); padding: 12px 22px; border-radius: 99px; pointer-events: none;
  background: var(--ink); color: #fff; font: 800 1.1rem/1 var(--font); box-shadow: 0 0 0 2px #000, 0 5px 0 #000; --from: translate(-50%, -50%) scale(.85); animation: enter .3s var(--ease-out); }
/* The username in the profile popup with its pencil (src/menu.js usernameRow), and the username window (src/main.js openNameWindow) */
.pf-name p { display: flex; align-items: center; gap: 10px; }
.pf-name b { font-size: 1.15rem; overflow-wrap: anywhere; }
.pf-pencil { display: grid; place-items: center; flex: none; width: 44px; height: 44px; padding: 0; border: 2px solid var(--ink); border-radius: 50%; background: var(--yellow); color: var(--ink); box-shadow: 0 3px 0 var(--ink); cursor: pointer; }
.pf-pencil .ic { width: 20px; height: 20px; }
.pf-pencil:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--ink); }
.pf-pencil:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
body .modal.name-win { width: min(360px, 100%); display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; zoom: 1; max-height: none; overflow: visible; padding: 18px; } /* (sized for the phone as it is: no UI zoom — `body` outranks body.mobile .modal — one column that never grows past the window, never a scrollbar) */
.name-win h2, .name-win p { margin: 0; }
.modal.name-win h2 { font-size: 24px; }
.name-win .row { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
.nw-row { display: flex; align-items: center; gap: 10px; }
.nw-row input { flex: 1; min-width: 0; height: 48px; padding: 0 12px; border: 2px solid var(--ink); border-radius: var(--r-sm); font: 800 18px var(--font); background: #fff; color: var(--ink); }
.nw-mark { flex: none; min-width: 5.5em; font-size: 13px; font-weight: 800; }
.nw-mark > span { display: inline-flex; align-items: center; gap: 4px; }
.nw-mark .ic { flex: none; width: 20px; height: 20px; }
.nw-ok { color: var(--good); }
.nw-bad { color: var(--bad); }
.nw-wait { opacity: .6; }
body.night .nw-row input { background: #1d2643; color: var(--night-fg); border-color: #3a4670; }
body.night .nw-ok { color: #5fd38a; }
body.night .nw-bad { color: #ff7b8a; }
.slot-name.fixed { display: block; font-size: 1.1rem; overflow-wrap: anywhere; }
/* a toast while the menu shows: the game's stage is hidden, so it sits on the page */
.toast.on-menu { position: fixed; top: calc(var(--safe-top) + 18px); z-index: var(--z-popover); }
/* Friends tab (part 4): section chips, the online light, token icons, the request count, and the tab bar's dot */
.fr-tabs { margin-bottom: 12px; }
.fr-count { display: inline-grid; place-items: center; min-width: 20px; height: 20px; margin-left: 4px; padding: 0 5px; border-radius: 999px; background: var(--bad); color: #fff; font-size: 12px; }
.fr-light { flex: none; width: 10px; height: 10px; border-radius: 50%; border: 1px solid var(--ink); background: #9aa1b5; }
.fr-light.on { background: #2fbf5b; }
.fr-tok { display: grid; place-items: center; flex: none; width: 32px; height: 32px; border-radius: 50%; border: 2px solid var(--ink); background: var(--pc); color: var(--pc2); }
.fr-tok .ic { width: 18px; height: 18px; }
.fr-list li > .fr-tok { flex: none; display: grid; } /* (the row's name span grows to fill; the round token must not) */
.fr-list li > span { min-width: 0; overflow-wrap: anywhere; }
.fr-list .btn.sm { flex: none; min-height: 36px; }
.fr-more { min-width: 36px; }
.fr-state { flex: none; font-size: 13px; font-weight: 800; opacity: .7; }
.fr-sec h3 + .fr-list { margin-bottom: 14px; }
.fr-search input { width: 100%; height: 48px; margin-bottom: 12px; padding: 0 14px; border: 2px solid var(--ink); border-radius: var(--r-md); font: 700 17px var(--font); background: #fff; color: var(--ink); }
body.night .fr-search input { background: #1d2643; color: var(--night-fg); border-color: #3a4670; }
.fr-signin { display: grid; justify-items: start; gap: 10px; padding: 12px 14px; border: 2px solid var(--ink); border-radius: var(--r-md); }
.fr-signin p { margin: 0; font-weight: 700; }
body.night .fr-signin { border-color: #3a4670; }
.menu-tabs [role="tab"] { position: relative; }
.menu-tabs [role="tab"].has-dot::after { content: ''; position: absolute; top: 5px; left: calc(50% + 8px); width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--ink); background: var(--bad); }

/* Terms and Privacy links: the welcome's small print and the foot of Settings */
.wl-legal, .set-legal { margin: 4px 0 0; font-size: 12px; text-align: center; color: var(--muted); }
.wl-legal a, .set-legal a { color: inherit; text-decoration: underline; }
body.night .wl-legal, body.night .set-legal { color: #b8b4d8; }

/* Settings → Delete account: a quiet red link, and its confirm window's typed check */
.set-delete { margin: 6px 0 0; }
#overlay-root .set-delete .danger-link { color: var(--bad); }
body.night #overlay-root .set-delete .danger-link { color: #ff7a8a; }
.del-field { display: grid; gap: 6px; font-size: 14px; }
.del-field input { height: 46px; padding: 0 12px; border: 2px solid var(--ink); border-radius: var(--r-sm); font: 700 17px var(--font); background: #fff; color: var(--ink); }
body.night .del-field input { background: #1d2643; color: var(--night-fg); border-color: #3a4670; }
body .modal.del-win { zoom: 1; max-height: none; overflow: visible; grid-template-columns: minmax(0, 1fr); width: min(380px, 100%); }
