/* ================================================================ TABLE
   The game on one screen. The map takes every spare pixel; your hand sits big
   at the bottom with the action row under it; nothing ever scrolls. Build,
   Trade and Cards open trays upward over the bottom of the map, and prompts
   stop above your hand, so your cards are always in view.

   Loaded last on purpose: it settles the layout that app.css and kakure.css
   grew in layers. */

/* ---------------------------------------------------------------- frame */
body:has(#view-game:not([hidden])) { overflow: hidden; }
body:has(#view-game:not([hidden])) .app { height: 100svh; }

.game {
  flex: 1; min-height: 0; overflow: hidden;
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--side-w);
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas: "board side" "dock side";
}
.game .side { grid-area: side; }

/* ---------------------------------------------------------------- the sea
   The water around the island is your colour, so you never forget whose
   pieces are yours. Watching a game, it stays night blue. */
#view-game .board-wrap {
  background:
    radial-gradient(ellipse 62% 58% at 50% 46%, rgba(0, 0, 0, 0), rgba(4, 6, 12, .58) 82%),
    var(--pattern-seigaiha),
    linear-gradient(180deg,
      color-mix(in srgb, var(--you-color, #1d3560) 78%, #0b1426) 0%,
      color-mix(in srgb, var(--you-color, #1d3560) 50%, #070c18) 100%);
  background-size: auto, 80px 40px, auto;
}
/* The turn message sits in the dock, a slim line above your hand, so
   nothing hangs over the map. */
#view-game .dock > .banner {
  position: static; transform: none; z-index: auto; animation: none;
  display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 10px;
  width: auto; max-width: none; margin: 0 auto; padding: 4px 14px;
  font-size: 15px; line-height: 1.25; text-align: center; white-space: normal;
  box-shadow: none; border-radius: 999px; min-height: 30px;
}
#view-game .dock > .banner[hidden] { display: none; }
#view-game .dock > .banner::before, #view-game .dock > .banner::after { display: none; }
#view-game .dock > .banner .btn { min-height: 26px; padding: 2px 12px; }

/* ---------------------------------------------------------------- dice on the map */
.board-wrap > .dice-tray {
  position: absolute; left: 12px; bottom: 12px; top: auto; z-index: 6;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  font: inherit; color: inherit; cursor: default;
}
.board-wrap > .dice-tray:disabled { opacity: 1; }
.board-wrap > .dice-tray.guide-pulse { position: absolute; }
.dice-tray__hint {
  font-family: var(--font-display, var(--font)); font-size: 12.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--kin-pale, #f2d48a);
}
.dice-tray__hint[hidden] { display: none; }
.board-wrap > .dice-tray.is-ready {
  cursor: pointer; padding: 10px 14px 8px;
  border-color: var(--kin, #d6a84c);
  animation: dice-call 1.8s ease-in-out infinite;
}
.board-wrap > .dice-tray.is-ready img { width: 58px; height: 58px; }
.board-wrap > .dice-tray.is-ready img:first-child { transform: rotate(-12deg); }
.board-wrap > .dice-tray.is-ready img:nth-child(2) { transform: rotate(9deg) translateY(-3px); }
.board-wrap > .dice-tray.is-ready:hover img:first-child { transform: rotate(-20deg) scale(1.06); }
.board-wrap > .dice-tray.is-ready:hover img:nth-child(2) { transform: rotate(16deg) translateY(-5px) scale(1.06); }
.board-wrap > .dice-tray.is-ready:active { transform: scale(.96); }
.board-wrap > .dice-tray.is-rolling img { width: 58px; height: 58px; }
.board-wrap > .dice-tray img { transition: transform .2s var(--ease-swell, ease); }
@keyframes dice-call {
  0%, 100% { box-shadow: inset 0 2px 8px rgba(0, 0, 0, .6), 0 10px 26px rgba(0, 0, 0, .5), 0 0 0 0 rgba(242, 212, 138, 0); }
  50%      { box-shadow: inset 0 2px 8px rgba(0, 0, 0, .6), 0 10px 26px rgba(0, 0, 0, .5), 0 0 0 9px rgba(242, 212, 138, .22); }
}

/* Grandmother Ine's card pops up in front of the board, on every screen,
   and goes away on "OK" until the next move. The one card allowed over
   the map. */
#view-game .board-wrap > .guide {
  left: 50%; top: 50%; right: auto; bottom: auto; z-index: 9;
  transform: translate(-50%, -50%);
  width: min(380px, calc(100% - 28px)); max-height: calc(100% - 20px); overflow-y: auto;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .6), inset 0 0 0 3px rgba(255, 255, 255, .35);
}
#view-game .board-wrap > .guide.is-new { animation: guide-pop .4s cubic-bezier(.2, .8, .2, 1); }
@keyframes guide-pop {
  from { opacity: 0; transform: translate(-50%, -46%) scale(.97); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}
.guide__ok {
  display: block; width: 100%; min-height: 46px; margin-top: 12px;
  background: var(--sumi, #1d1712); color: var(--washi, #f4ecd8);
  border: 0; border-radius: 10px; cursor: pointer;
  font: 700 16px/1 var(--font-display); letter-spacing: .08em;
}
.guide__ok:hover { filter: brightness(1.15); }
.guide__ok:focus-visible { outline: 3px solid var(--gold, #d6a84c); outline-offset: 2px; }

/* ---------------------------------------------------------------- the dock */
.game .dock {
  grid-area: dock; position: relative; z-index: 3;
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  max-height: none; overflow: visible;
  padding: 12px 14px calc(10px + env(safe-area-inset-bottom, 0px));
}
/* A stripe of your colour along the table edge, under your cards. */
.game .dock::after {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  background: var(--you-color, transparent); opacity: .9; pointer-events: none;
}

/* Your hand: the five goods, big enough to read at a glance. */
.game .dock__hand {
  justify-content: center; flex-wrap: nowrap; gap: 16px;
  overflow: visible; padding: 6px 0 0;
}
.game .hand { gap: 10px; flex: none; overflow: visible; }
.game .rescard { width: clamp(58px, 16.5vw, 88px); }
.game .rescard:not(.is-zero):hover { transform: translateY(-6px) rotate(-1.5deg); }
.game .rescard__n { min-width: 26px; height: 26px; font-size: 14px; }
.game .devhand { flex: none; }
.game .devhand.is-empty .empty-hand { white-space: nowrap; }

/* A card leaving your hand dips, and says how many went. */
.rescard.is-lost { animation: card-lost .9s ease-out; }
@keyframes card-lost {
  0% { transform: none; }
  20% { transform: translateY(8px) rotate(-3deg); box-shadow: 0 0 0 3px rgba(226, 90, 59, .9), 0 6px 14px rgba(0, 0, 0, .5); }
  100% { transform: none; }
}
.rescard__lost {
  position: absolute; left: 50%; bottom: 30%; transform: translateX(-50%);
  padding: 2px 9px; border-radius: 999px;
  background: rgba(142, 33, 22, .95); color: #fff3e4;
  font: 700 15px/1.3 var(--font-display, var(--font));
  box-shadow: 0 3px 10px rgba(0, 0, 0, .5);
  animation: lost-rise 1.8s ease-out forwards; pointer-events: none;
}
@keyframes lost-rise {
  0% { opacity: 0; transform: translate(-50%, 6px); }
  15%, 70% { opacity: 1; transform: translate(-50%, -6px); }
  100% { opacity: 0; transform: translate(-50%, -18px); }
}

/* The action row: the same big buttons all game. */
.game .dock__actions {
  display: flex; flex-wrap: nowrap; gap: 8px; justify-content: center;
  width: 100%; max-width: 46rem; margin: 0 auto;
}
.game .dock__actions .btn {
  flex: 1 1 0; min-width: 0; max-width: none; min-height: 54px;
  flex-direction: row; gap: 8px; padding: 8px 10px;
  white-space: nowrap;
}
.game .dock__actions .btn > span:first-child { font-size: 15px; letter-spacing: .1em; }
.game .dock__actions .btn.action-turn { flex-grow: 1.35; font-size: 15px; letter-spacing: .1em; }
.game .dock__actions .react-btn { flex: none; width: 54px; height: 54px; margin: 0; }
.game .dock__actions .results-panel { flex: 1 1 100%; max-width: none; }
.game .dock__actions:has(.results-panel) { flex-wrap: wrap; }

.action-toggle { position: relative; }
.action-toggle__chev {
  width: 9px; height: 9px; flex: none;
  border-left: 2px solid currentColor; border-top: 2px solid currentColor;
  transform: translateY(2px) rotate(45deg); transition: transform .2s ease; opacity: .8;
}
.action-toggle.is-open .action-toggle__chev { transform: translateY(-2px) rotate(225deg); }
.action-toggle.is-open, .action-toggle.is-active {
  border-color: var(--kin, #d6a84c);
  box-shadow: 0 0 0 1px var(--kin, #d6a84c), 0 6px 16px rgba(0, 0, 0, .4);
}
.action-toggle__count {
  position: absolute; top: -7px; right: -5px;
  min-width: 22px; height: 22px; padding: 0 5px; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
  font: 700 12px/1 var(--font-display, var(--font)); letter-spacing: 0;
}
.action-toggle.is-ready .action-toggle__count { background: var(--shu, #c8432b); color: #fff3e4; border-color: transparent; }

/* While a prompt is open, the row rests; your hand stays readable. */
body.has-modal .game .dock__actions { pointer-events: none; opacity: .45; }

/* ---------------------------------------------------------------- trays + offers */
.dock__above {
  position: absolute; left: 10px; right: 10px; bottom: calc(100% + 8px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none; z-index: 20;
}
.dock__above > * { pointer-events: auto; width: min(100%, 30rem); }
.dock__above > #trade-slot { max-height: 38svh; overflow: auto; box-shadow: 0 12px 30px rgba(0, 0, 0, .5); }
/* A short phone has little board above the hand: the offer may reach over the players' row. */
@media (max-height: 700px) { .dock__above > #trade-slot { max-height: 54svh; } }
/* Your own offer: the deal on one line, then one line per player with any
   counter and its buttons beside it, so everything fits without scrolling. */
#trade-slot .trade-line { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; }
#trade-slot .trade-status { align-items: center; flex-wrap: wrap; row-gap: 4px; }
#trade-slot .trade-withdraw { margin-left: auto; }
#trade-slot .trade-status.has-actions {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; column-gap: 6px;
}
#trade-slot .trade-status.has-actions > .trade-status__name { grid-area: 1 / 1; }
#trade-slot .trade-status.has-actions > :is(.trade-status__deal, .trade-status__value) { grid-area: 2 / 1; }
#trade-slot .trade-status.has-actions > .btn { grid-row: 1 / span 2; grid-column: 2; }
#trade-slot .trade-status.has-actions > .btn ~ .btn { grid-column: 3; }
#trade-slot .trade-status__name { font-weight: 650; }
#trade-slot .trade-status__deal { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
#trade-slot .trade-status__deal .trade-side { gap: 3px; }
#trade-slot .trade-status__deal img { width: 26px; }
#trade-slot .trade-status .btn--small { min-height: 34px; padding: 4px 12px; }
:root[data-game="kakure"] .dock__above > #trade-slot {
  background: linear-gradient(180deg, rgba(246, 238, 219, .98), rgba(236, 223, 194, .98)); color: var(--sumi);
}

.tray {
  padding: 10px 12px 12px; border-radius: 10px;
  background: linear-gradient(180deg, #281c12, #160f09);
  border: 1px solid rgba(214, 168, 76, .5);
  box-shadow: 0 -6px 30px rgba(0, 0, 0, .55);
  animation: tray-up .22s var(--ease-ink, ease-out);
  transform-origin: bottom center;
}
.tray[hidden] { display: none; }
@keyframes tray-up { from { opacity: 0; transform: translateY(14px) scaleY(.92); } }
.tray__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.tray__head strong {
  font-family: var(--font-display, var(--font)); font-size: 15px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--kin-pale, #f2d48a);
}
.tray__close {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(214, 168, 76, .35);
  color: var(--washi, #f1e6cf); font-size: 20px; line-height: 1;
}
.tray__items { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
.tray .tray-item:disabled { opacity: .6; }
.tray[data-tray="cards"] .tray__items { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.tray[data-tray="cards"] .devcard { width: 72px; }
/* Each choice is a row: its name and why on the left, its cost on the right. */
.tray .tray-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-auto-flow: dense;
  align-items: center; column-gap: 10px; row-gap: 2px;
  min-height: 58px; padding: 8px 12px; white-space: normal; text-align: left;
}
.tray .tray-item > span:first-child { grid-column: 1; font-size: 14px; line-height: 1.15; }
.tray .tray-item .cost { grid-column: 2; grid-row: 1 / span 2; justify-content: flex-end; flex-wrap: nowrap; gap: 6px; margin: 0; }
.tray .tray-item .btn-reason {
  grid-column: 1; display: block; width: auto; margin: 0; text-align: left;
  font-size: 11.5px; line-height: 1.25; text-transform: none; letter-spacing: .02em; opacity: .8;
}
.tray .tray-item .cost-item { gap: 1px; }
.tray .tray-item .cost-item__icon { width: 22px; height: 22px; }
.tray .tray-item .cost-item__n { font-size: 12px; }

/* ---------------------------------------------------------------- prompts stop above your hand */
body:has(#view-game:not([hidden])) .modal-back { bottom: var(--dock-live-h, 0px); }
body:has(#view-game:not([hidden])) .modal {
  max-height: calc(100svh - var(--dock-live-h, 0px) - 20px);
}
/* On a short window the space above the hand can get too small for a
   prompt; then the prompt may sit over the hand rather than scroll. */
@media (max-height: 640px) {
  body:has(#view-game:not([hidden])) .modal-back { bottom: 0; place-items: center; }
  body:has(#view-game:not([hidden])) .modal { max-height: calc(100svh - 20px); }
}

/* Too tall for the room above the hand (ui.js measures it): over the hand, then. */
body:has(#view-game:not([hidden])) .modal-back.modal-back--over { bottom: 0; place-items: center; }
body:has(#view-game:not([hidden])) .modal-back--over .modal { max-height: calc(100svh - 20px); }

/* Prompts are laid out to fit without scrolling: the five goods sit in one
   row of small cards, each with its own − n + underneath. */
.modal .picker {
  grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 5px;
  overflow: visible; max-width: none;
}
.modal .picker__cell { padding: 5px 2px 6px; gap: 3px; min-width: 0; }
.modal .picker__cell img { width: min(40px, 100%); }
.modal .picker__cell .name { font-size: 10.5px; line-height: 1.1; text-align: center; overflow-wrap: anywhere; }
.modal .stepper { gap: 1px; width: 100%; justify-content: center; }
.modal .stepper button { width: 24px; height: 28px; flex: none; }
.modal .stepper span { min-width: 12px; text-align: center; font-weight: 700; }
.modal .user-row { gap: 6px; }
body:has(#view-game:not([hidden])) .modal .row { flex-wrap: wrap; gap: 6px 12px; }
@media (max-width: 400px) {
  .modal .picker { gap: 3px; }
  .modal .stepper button { width: 21px; }
  .modal .picker__cell img { width: min(34px, 100%); }
}
/* Windows opened from the table (Account, Sites) take the whole screen
   height and are laid out to fit it: nothing inside them scrolls. */
body:has(#view-game:not([hidden])) .modal-back.modal-back--full {
  bottom: 0; place-items: center; padding: 10px;
  background: radial-gradient(ellipse at center, rgba(8, 13, 24, .6), rgba(4, 6, 12, .88));
}
.modal-back--full .modal,
body:has(#view-game:not([hidden])) .modal-back--full .modal {
  max-height: calc(100svh - 20px); width: min(30rem, 100%); gap: 9px; padding: 14px 16px;
}
.modal--account .account-who { display: flex; align-items: center; gap: 12px; }
.modal--account .account-face {
  flex: none; padding: 0; border: 1px solid var(--line); border-radius: 50%;
  background: var(--panel-2); cursor: pointer; display: grid; place-items: center;
  width: 58px; height: 58px; overflow: hidden;
}
.modal--account .account-face[aria-expanded="true"] { border-color: var(--gold); }
.modal--account .account-face .avatar { width: 56px; height: 56px; font-size: 26px; }
.modal--account .account-name,
.modal--account .account-field { display: grid; gap: 3px; flex: 1 1 auto; min-width: 0; }
.modal--account .account-pw-head { display: flex; }
.modal--account .account-pw { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.modal--account .account-pw[hidden] { display: none; }
.modal--account .avatar-grid {
  grid-template-columns: repeat(auto-fill, minmax(52px, 1fr)); grid-auto-rows: auto;
  min-height: 0; max-height: none; overflow: visible; gap: 5px;
}
.modal--account .avatar-cell { min-height: 0; aspect-ratio: 1; overflow: hidden; padding: 2px; }
.modal--account .avatar-cell .player-portrait { width: 100%; height: 100%; }
.modal--account .account-face .player-portrait { width: 56px; height: 56px; }
/* While the portraits are open they take the place of the other fields. */
.modal--account.is-picking > :not(.account-who):not(.avatar-grid):not(.modal__actions):not(h3) { display: none; }
.modal--account .avatar-grid[hidden] { display: none; }
.modal--account input { padding-block: 7px; }
.modal--account h4 { margin: 2px 0 0; }
.modal--sites .site-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.modal--sites .site-chip { border-left: 4px solid var(--seat); }
.modal--sites .site-chip.is-on { border-color: var(--seat); background: color-mix(in srgb, var(--seat) 26%, transparent); }
.modal--sites .site-list { display: grid; gap: 0; }
.modal--sites .site-status { padding: 6px 0; }
.modal--sites .site-status h4 { font-size: 14px; margin: 0; flex-wrap: wrap; }
.modal--sites .site-status p { margin: 2px 0 0; line-height: 1.3; }
.modal--sites .site-status__nums { color: var(--muted); font-weight: 500; margin-left: 4px; }
/* An action card opens in front of the board to be read before it acts. */
.modal-back--full .modal.modal--card { width: min(20rem, 100%); justify-items: center; text-align: center; gap: 10px; }
.modal--card .card-explain__art {
  width: min(150px, 42vw); aspect-ratio: 1; object-fit: cover; border-radius: 10px;
  box-shadow: 0 10px 22px rgba(0, 0, 0, .35);
}
.modal--card .card-explain__text { margin: 0; font-size: 16px; line-height: 1.4; }
.modal--card .modal__actions { justify-content: center; width: 100%; }
.modal--card .card-explain__ok { min-width: 60%; min-height: 46px; font-size: 18px; }
.devcard.is-idle { opacity: .6; }

body:has(#view-game:not([hidden])) .toasts { bottom: calc(var(--dock-live-h, 0px) + 12px); }
/* While an offer or a tray sits above the hand, notes drop in under the top bar
   instead, so they never cover Accept, Decline or Counter. */
body:has(#view-game:not([hidden])):has(#dock-above > #trade-slot, #dock-above > #tray:not([hidden])) .toasts { bottom: auto; top: calc(var(--top-live-h, 64px) + 8px); }

/* ---------------------------------------------------------------- phones */
@media (max-width: 860px) {
  .game { display: flex; flex-direction: column; overflow: hidden; }
  .game .board-wrap { flex: 1 1 auto; order: 1; height: auto; min-height: 0; }
  .game .dock { flex: none; order: 2; gap: 8px; padding: 10px 8px calc(8px + env(safe-area-inset-bottom, 0px)); }
  .game .dock__hand { gap: 10px; }
  .game .hand { gap: 7px; flex: none; }
  .game .dock__actions { gap: 6px; }
  .game .dock__actions .btn { min-height: 52px; padding: 6px 6px; gap: 6px; }
  .game .dock__actions .btn > span:first-child { font-size: 14px; letter-spacing: .08em; }
  .game .dock__actions .btn.action-turn { font-size: 14px; letter-spacing: .06em; }
  .game .dock__actions .react-btn { width: 48px; height: 52px; border-radius: 12px; font-size: 21px; }
  .board-wrap > .dice-tray { left: 8px; bottom: 8px; }
  .board-wrap > .dice-tray.is-ready img, .board-wrap > .dice-tray.is-rolling img { width: 48px; height: 48px; }
  .board-wrap > .dice-tray img { width: 30px; height: 30px; }
  .dock__above { left: 6px; right: 6px; }
}
@media (max-width: 620px) {
  .game .rescard { width: calc((100vw - 16px - 4 * 7px) / 5); max-width: 76px; }
  .game .devhand { display: none; }
  .game .awards { display: none; }
  .tray__items { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .tray .tray-item { min-height: 52px; }
}
/* A phone on its side: the map gets the height, the table stays one row. */
@media (orientation: landscape) and (max-height: 500px) {
  .game .rescard { width: 52px; }
  .game .dock { gap: 6px; padding-top: 6px; }
  .game .dock__actions .btn { min-height: 44px; }
  #view-game .board-wrap > .guide .guide__why { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .board-wrap > .dice-tray.is-ready, .tray, .rescard.is-lost, .rescard__lost,
  #view-game .board-wrap > .guide.is-new { animation: none; }
}

/* ---------------------------------------------------------------- "Your turn" band
   The ink band grows with what it carries, so a wrapped line is never cut off. */
.fx-turn { padding: 16px 16px 18px; }
.fx-turn__band { top: 0; bottom: 0; height: auto; transform: none; }
.fx-turn__text { text-align: center; max-width: calc(100vw - 32px); line-height: 1.35; }
@media (max-width: 620px) {
  .fx-turn__text { letter-spacing: .16em; text-indent: .16em; font-size: 17px; }
}

@media (max-width: 620px) {
  #view-game .dock > .banner { font-size: 13.5px; padding: 3px 12px; min-height: 26px; }
  #view-game .board-wrap > .guide { padding: 10px 12px; }
  #view-game .board-wrap > .guide .guide__why { display: none; }
}

/* ---------------------------------------------------------------- who goes first */
#view-game .board-wrap > .opening-roll {
  position: absolute; left: 50%; top: 50%; z-index: 10; transform: translate(-50%, -50%);
  width: min(360px, calc(100% - 28px)); max-height: calc(100% - 20px); overflow-y: auto;
  padding: 14px 16px 12px; color: var(--sumi, #1d1712);
  background: linear-gradient(180deg, #f6eedb, #ecdfc2);
  border: 1px solid rgba(140, 100, 40, .45); border-radius: 12px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .6), inset 0 0 0 3px rgba(255, 255, 255, .35);
  animation: guide-pop .35s cubic-bezier(.2, .8, .2, 1);
}
.opening-roll h3 { margin: 0 0 8px; font: 700 18px/1.2 var(--font-display); text-align: center; letter-spacing: .04em; }
.opening-roll__round { display: grid; gap: 6px; }
.opening-roll__round + .opening-roll__round { margin-top: 8px; }
.opening-roll__tie { margin: 2px 0 0; font: 600 12.5px/1.3 var(--font-body); color: #8a5a2b; text-align: center; }
.opening-roll__row {
  display: grid; grid-template-columns: 32px minmax(0, 1fr) auto 26px; align-items: center; gap: 8px;
  padding: 4px 8px; border-radius: 9px; border-left: 4px solid var(--seat);
  background: rgba(255, 255, 255, .35);
}
.opening-roll__row .avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; font-size: 16px; display: grid; place-items: center; }
.opening-roll__name { font: 600 14.5px/1.2 var(--font-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.opening-roll__dice { display: flex; gap: 4px; }
.opening-roll__dice img { width: 30px; height: 30px; }
.opening-roll__total { font: 700 17px/1 var(--font-display); text-align: right; }
.opening-roll.is-rolling .opening-roll__total { visibility: hidden; }
.opening-roll.is-rolling .opening-roll__dice img { animation: die-wobble .18s linear infinite alternate; }
.opening-roll:not(.is-rolling) .opening-roll__row.is-first { background: rgba(214, 168, 76, .35); box-shadow: 0 0 0 2px rgba(180, 120, 30, .6); }
.opening-roll.is-rolling .opening-roll__result { visibility: hidden; }
.opening-roll__result { margin: 10px 0 0; font: 700 16px/1.2 var(--font-display); text-align: center; }
.opening-roll__ok {
  display: block; width: 100%; min-height: 42px; margin-top: 10px; border: 0; border-radius: 10px; cursor: pointer;
  background: var(--sumi, #1d1712); color: var(--washi, #f4ecd8); font: 700 15px/1 var(--font-display); letter-spacing: .08em;
}
@keyframes die-wobble { from { transform: rotate(-14deg); } to { transform: rotate(14deg) translateY(-2px); } }
@media (prefers-reduced-motion: reduce) {
  #view-game .board-wrap > .opening-roll, .opening-roll .opening-roll__dice img { animation: none; }
}

/* The land the Magistrate (or robber) sits on: greyed and a touch darker. */
.layer-robber-shade .robber-wash { fill: #808080; mix-blend-mode: saturation; opacity: .85; pointer-events: none; }
.layer-robber-shade .robber-dim { fill: #10141f; opacity: .28; pointer-events: none; }
.layer-event-shade { pointer-events: none; }
.layer-event-shade .event-flood { fill: #1d3d5c; opacity: .62; }
.layer-event-shade .event-blight { fill: #3b2f1c; opacity: .6; }
.layer-event-shade .event-hex-label { fill: #f1e6cf; font-family: var(--font-display, serif); letter-spacing: .04em; paint-order: stroke; stroke: #10141f; stroke-width: .03; }

/* ---------------------------------------------------------------- choose your colour */
.color-pick { display: flex; gap: 10px; flex-wrap: wrap; }
.color-pick__swatch {
  width: 34px; height: 34px; border-radius: 50%; padding: 0; cursor: pointer;
  background: var(--swatch); border: 2px solid rgba(22, 19, 15, .25);
  box-shadow: inset 0 0 0 2px rgba(255, 250, 238, .5);
}
.color-pick__swatch.is-on { border-color: var(--shu, #c8432b); box-shadow: inset 0 0 0 3px #fffaf0, 0 0 0 2px var(--shu, #c8432b); }
.color-pick__swatch:disabled { opacity: .25; cursor: not-allowed; }
.modal--account .account-color { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.seat.has-color .seat__avatar { box-shadow: 0 0 0 3px var(--seat-color); }
.seat-color { list-style: none; display: flex; align-items: center; justify-content: center; gap: 12px; width: 100%; flex-wrap: wrap; margin-top: 4px; }

/* ---------------------------------------------------------------- named sites */
.board-host .site-name { cursor: pointer; pointer-events: auto; font-family: var(--font-display, serif); letter-spacing: .02em; }
.modal h3 { white-space: normal; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------- every pop-up has rounded corners */
.modal, :root[data-game="kakure"] .modal,
.board-wrap > .guide, .dock__above > #trade-slot, .trade-offer, .tray, .toast,
.rules-scroll__sheet, .opening-roll { border-radius: 16px; }
.modal::before { border-radius: inherit; }

/* ---------------------------------------------------------------- your sites beside your hand */
.game .my-sites { display: grid; gap: 4px; flex: none; align-content: center; max-width: 220px; }
.my-site {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 3px 10px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 13px; line-height: 1.2;
  background: rgba(241, 230, 207, .92); color: #16130f; border: 1px solid rgba(120, 80, 30, .35);
}
.my-site__name { font-family: var(--font-display, serif); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.my-site__dots { display: inline-flex; gap: 3px; flex: none; }
.my-site__dots i { width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid #8E2116; }
.my-site__dots i.is-on { background: #8E2116; }
.my-site.is-due { border-color: #8E2116; box-shadow: 0 0 0 2px rgba(142, 33, 22, .35); }
.my-site.is-hidden { background: rgba(20, 17, 15, .85); color: #e9d9a6; border-color: rgba(176, 141, 63, .6); }
.my-site__hidden { font-size: 12px; white-space: nowrap; color: #B08D3F; }
@media (max-width: 860px) {
  .game .dock__hand { flex-wrap: wrap; row-gap: 6px; }
  .game .my-sites { order: -1; width: 100%; max-width: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; }
  .my-site { font-size: 12px; padding: 2px 8px; gap: 5px; }
  .my-site__dots i { width: 7px; height: 7px; }
}
.game .my-sites[hidden] { display: none; }

/* ---------------------------------------------------------------- scoreboard on Home */
.scoreboard[hidden] { display: none; }
.score-me { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.score-tile {
  display: grid; justify-items: center; gap: 2px; padding: 10px 6px; border-radius: 14px; text-align: center;
  background: linear-gradient(180deg, rgba(244, 234, 212, .95), rgba(230, 214, 179, .95)); color: #16130f;
  box-shadow: 0 8px 20px rgba(0, 0, 0, .35);
}
.score-tile strong { font-family: var(--font-display, serif); font-size: 20px; line-height: 1.1; color: #8E2116; }
.score-tile span { font-size: 12px; color: #5d5242; }
.score-rank { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.score-rank[hidden] { display: none; }
.score-row {
  display: grid; grid-template-columns: 24px 32px 1fr auto; align-items: center; gap: 10px;
  padding: 6px 12px; border-radius: 999px; background: rgba(244, 234, 212, .9); color: #16130f;
}
.score-row.is-you { box-shadow: 0 0 0 2px #8E2116; }
.score-row__place { font-family: var(--font-display, serif); font-weight: 700; color: #8E2116; text-align: center; }
.score-row__name { font-family: var(--font-display, serif); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.score-row__rec { font-size: 13px; color: #5d5242; }
@media (max-width: 420px) { .score-me { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.rules-cards { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 4px; line-height: 1.45; }
.modal .picker__cell .name { text-transform: none; }

/* On a phone's Home Screen the page runs under the status bar (time, signal)
   and the home indicator. The painting stays full-bleed behind them; the
   page's own content starts below the status bar. */
.app {
  box-sizing: border-box;
  padding-top: env(safe-area-inset-top, 0px);
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}
.modal-back { top: env(safe-area-inset-top, 0px); }
@media (max-width: 860px) { .side { top: env(safe-area-inset-top, 0px); } }
body:has(#view-game:not([hidden])) .modal {
  max-height: calc(100svh - var(--dock-live-h, 0px) - 20px - env(safe-area-inset-top, 0px));
}
.signin { padding-top: max(24px, env(safe-area-inset-top, 0px)); padding-bottom: max(24px, env(safe-area-inset-bottom, 0px)); }
/* A pop-up's rows shrink to its width on narrow phones (an input's natural
   width otherwise pushes buttons past the right edge). */
.modal > * { min-width: 0; }
/* Phones: every player fits on the strip, no sideways scroll. Each chip takes
   an equal share; the colour is its left edge, and the name gets two lines. */
@media (max-width: 860px) {
  #view-game .mobile-players { overflow-x: hidden; gap: 5px; }
  #view-game .mobile-player {
    flex: 1 1 0; min-width: 0; max-width: none; gap: 5px; padding: 4px 6px 4px 5px;
    border-radius: 14px; border-left: 4px solid var(--pc, var(--line));
  }
  #view-game .mobile-player__pip { display: none; }
  #view-game .mobile-player .avatar { width: 26px; height: 26px; flex: none; }
  #view-game .mobile-player__text { display: flex; flex-direction: column; min-width: 0; line-height: 1.1; }
  #view-game .mobile-player__name {
    white-space: normal; overflow-wrap: anywhere; font-size: 11px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  #view-game .mobile-player__vp { font-size: 11px; }
}
.my-site--orasho { background: rgba(176, 141, 63, .95); color: #16130f; border-color: #8a6a2a; font-weight: 700; }
/* iPhone zooms the page into any field under 16px; keep fields at 16px. */
@media (pointer: coarse) { input, select, textarea { font-size: max(16px, 1em); } }
html { touch-action: manipulation; }   /* no double-tap zoom */

/* Top bar on phones: bell, Chat and More share one height and centre line. */
@media (max-width: 860px) {
  .topbar__right { align-items: center; }
  .topbar__right .icon-toggle { width: 40px; height: 40px; flex: none; }
  .topbar__right #btn-mobile-chat,
  .topbar__right #btn-more {
    display: inline-flex; align-items: center; justify-content: center; gap: 4px;
    box-sizing: border-box; height: 40px; min-height: 40px;
    padding: 0 11px; line-height: 1; vertical-align: middle;
  }
  .topbar__overflow { align-self: center; }
}

/* Zoomed-in panning: while a finger drags the board it travels as one
   picture, and that picture used to end at the SVG's own box, so the edges
   went blank until the finger lifted. Paint the whole island during the
   drag; the board area still clips it. */
.board-host { overflow: hidden; }
.board-host.is-gesturing svg { overflow: visible; }

/* Smoother on phones: nothing over or behind the board makes the phone
   repaint every frame. The sea pattern stays still (animating a background
   position redraws the whole board area each frame), and controls over the
   board drop their frosted-glass blur, which had to be redone on every frame
   of a pan or zoom; their backgrounds are already nearly opaque. */
.board-wrap, html[data-game-type="kakure"] .board-wrap, :root[data-game="kakure"] .board-wrap { animation: none; }
.board-wrap .icon-btn, .board-wrap > .dice-tray, .board-wrap > .banner, .side, .modal-back {
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.board-wrap .icon-btn { background: rgba(18, 26, 36, .9); }
/* "Oharu rolled" under the last throw: one short line that never widens the tray. */
.board-wrap > .dice-tray:not(.is-ready) .dice-tray__hint {
  max-width: 9.5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 11px; letter-spacing: .08em; text-transform: none;
}

/* Both dice tumble, plainly and evenly: one turn each per beat with a hop,
   the second turning the other way half a beat behind. The old spin was so
   fast (two turns in half a second) that on a phone's frame rate one die
   could look as if it barely moved. */
@keyframes die-tumble {
  0%   { transform: translateY(0) rotate(0deg); }
  25%  { transform: translateY(-9px) rotate(90deg) scale(1.08); }
  50%  { transform: translateY(0) rotate(180deg) scale(.96); }
  75%  { transform: translateY(-6px) rotate(270deg) scale(1.05); }
  100% { transform: translateY(0) rotate(360deg); }
}
.dice-tray.is-rolling img, .fx-dice.is-rolling img { animation: die-tumble .62s linear infinite; }
.dice-tray.is-rolling img:nth-child(2), .fx-dice.is-rolling img:nth-child(2) {
  animation-duration: .62s; animation-direction: reverse; animation-delay: -.31s;
}

/* Phone player strip: each chip is filled with its player's colour, not just an edge strip. */
@media (max-width: 860px) {
  #view-game .mobile-player {
    background: linear-gradient(160deg, color-mix(in srgb, var(--pc, #555) 82%, #fff 18%), var(--pc, #555) 55%, color-mix(in srgb, var(--pc, #555) 80%, #000 20%));
    border: 1.5px solid color-mix(in srgb, var(--pc, #555) 60%, #000 40%);
    color: #fff8ec;
  }
  #view-game .mobile-player .mobile-player__name,
  #view-game .mobile-player .mobile-player__vp { color: inherit; text-shadow: 0 1px 2px rgba(0, 0, 0, .55); }
  #view-game .mobile-player .mobile-player__vp { font-weight: 700; }
  #view-game .mobile-player .avatar { box-shadow: 0 0 0 1.5px rgba(255, 248, 236, .85); }
  #view-game .mobile-player[data-color="white"],
  #view-game .mobile-player[data-color="unbleached"] { color: #1d1a16; }
  #view-game .mobile-player[data-color="white"] .mobile-player__name,
  #view-game .mobile-player[data-color="white"] .mobile-player__vp,
  #view-game .mobile-player[data-color="unbleached"] .mobile-player__name,
  #view-game .mobile-player[data-color="unbleached"] .mobile-player__vp { text-shadow: none; }
  #view-game .mobile-player[data-color="white"] .avatar,
  #view-game .mobile-player[data-color="unbleached"] .avatar { box-shadow: 0 0 0 1.5px rgba(29, 26, 22, .5); }
  #view-game .mobile-player.is-turn { box-shadow: 0 0 0 2px #fff3d6, 0 0 10px 2px rgba(255, 220, 150, .55); }
}
@media (max-width: 360px) {
  #view-game .mobile-players { gap: 4px; }
  #view-game .mobile-player { gap: 3px; padding: 3px 4px 3px 3px; }
  #view-game .mobile-player .avatar { width: 22px; height: 22px; }
  #view-game .mobile-player__name { font-size: 10.5px; overflow-wrap: normal; word-break: normal; letter-spacing: -.01em; }
}

/* ---------------------------------------------------------------- Offer a trade */
body:has(#view-game:not([hidden])) .modal-back:has(.modal--offer) { top: var(--top-live-h, env(safe-area-inset-top, 0px)); padding-top: 8px; }
body:has(#view-game:not([hidden])) .modal--offer {
  max-height: calc(100svh - var(--dock-live-h, 0px) - var(--top-live-h, 0px) - 18px);
  gap: 6px; padding: 12px 14px 14px;
}
:is(.modal--offer, .modal--scroll) h3 { margin-bottom: 2px; }
:is(.modal--offer, .modal--scroll) .trade-label {
  margin: 4px 0 0; font-family: var(--font-display); font-size: 13px; letter-spacing: .06em;
  color: var(--shu-deep, #8e2116);
}
:is(.modal--offer, .modal--scroll) .picker { grid-template-columns: repeat(5, minmax(0, 1fr)); }
:is(.modal--offer, .modal--scroll) .picker__cell {
  padding: 5px 3px 5px; gap: 3px; border-radius: 12px;
  background: linear-gradient(180deg, rgba(255, 251, 241, .9), rgba(240, 229, 205, .9));
  border: 1px solid rgba(120, 80, 30, .25);
  transition: border-color .15s, background-color .15s, box-shadow .15s;
}
:is(.modal--offer, .modal--scroll) .picker__cell.is-selected {
  border-color: var(--shu); box-shadow: 0 0 0 1px var(--shu) inset;
  background: linear-gradient(180deg, rgba(255, 240, 228, .95), rgba(246, 220, 200, .95));
}
:is(.modal--offer, .modal--scroll) .picker__cell img { width: min(38px, 100%); border-radius: 6px; box-shadow: 0 1px 2px rgba(40, 25, 10, .3); display: block; }
:is(.modal--offer, .modal--scroll) .picker__art { position: relative; display: block; width: min(38px, 100%); }
:is(.modal--offer, .modal--scroll) .picker__art img { width: 100%; }
:is(.modal--offer, .modal--scroll) .picker__held {
  position: absolute; top: -6px; right: -7px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--shu); color: #fff8ec; font-size: 10.5px; font-weight: 700;
  line-height: 17px; text-align: center; box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
:is(.modal--offer, .modal--scroll) .picker__cell .name { text-transform: capitalize; color: #4a3f31; font-size: 11px; }
:is(.modal--offer, .modal--scroll) .stepper { gap: 2px; }
:is(.modal--offer, .modal--scroll) .stepper button {
  width: 24px; height: 24px; border-radius: 50%; padding: 0; display: grid; place-items: center;
  font-size: 15px; line-height: 1; color: var(--sumi, #1d1a16);
  background: #fffaf0; border: 1px solid rgba(120, 80, 30, .35); box-shadow: 0 1px 1px rgba(40, 25, 10, .15);
}
:is(.modal--offer, .modal--scroll) .stepper button:disabled { opacity: .3; box-shadow: none; }
:is(.modal--offer, .modal--scroll) .stepper span { min-width: 12px; font-family: var(--font-display); font-size: 14px; color: #4a3f31; }
:is(.modal--offer, .modal--scroll) .picker__cell.is-selected .stepper span { color: var(--shu-deep, #8e2116); }
:is(.modal--offer, .modal--scroll) .ask-row { display: flex; flex-wrap: wrap; gap: 6px; }
:is(.modal--offer, .modal--scroll) .ask-chip {
  flex: 1 1 0; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 38px; padding: 4px 10px 4px 5px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 14px; color: #4a3f31;
  background: rgba(255, 250, 238, .7); border: 1.5px dashed rgba(120, 80, 30, .4);
  transition: background-color .15s, color .15s, border-color .15s;
}
:is(.modal--offer, .modal--scroll) .ask-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:is(.modal--offer, .modal--scroll) .ask-chip .avatar { width: 28px; height: 28px; flex: none; opacity: .55; }
:is(.modal--offer, .modal--scroll) .ask-chip[aria-pressed="true"] {
  background: var(--pc); border: 1.5px solid color-mix(in srgb, var(--pc) 60%, #000 40%);
  color: #fff8ec; text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
}
:is(.modal--offer, .modal--scroll) .ask-chip[aria-pressed="true"] .avatar { opacity: 1; box-shadow: 0 0 0 1.5px rgba(255, 248, 236, .85); }
:is(.modal--offer, .modal--scroll) .ask-chip[aria-pressed="true"][data-color="white"],
:is(.modal--offer, .modal--scroll) .ask-chip[aria-pressed="true"][data-color="unbleached"] { color: #1d1a16; text-shadow: none; }
:is(.modal--offer, .modal--scroll) .modal__actions { margin-top: 4px; }
:is(.modal--offer, .modal--scroll) .modal__actions .btn { flex: 1 1 0; }
:is(.modal--offer, .modal--scroll) .btn--primary:disabled {
  opacity: 1; background: rgba(120, 80, 30, .14); border-color: rgba(120, 80, 30, .3);
  color: rgba(74, 63, 49, .6); box-shadow: none; text-shadow: none;
}
@media (max-width: 360px) {
  :is(.modal--offer, .modal--scroll) .stepper button { width: 21px; height: 22px; font-size: 13px; }
  :is(.modal--offer, .modal--scroll) .ask-chip { font-size: 12.5px; gap: 4px; padding-right: 7px; }
  :is(.modal--offer, .modal--scroll) .ask-chip .avatar { width: 24px; height: 24px; }
}
/* Kept compact so it fits between the top bar and the hand on an iPhone. */
:is(.modal--offer, .modal--scroll) h3 { margin: 0; font-size: 17px; }
:is(.modal--offer, .modal--scroll) .trade-label { margin: 2px 0 -1px; line-height: 1.15; }
:is(.modal--offer, .modal--scroll) .picker__cell img,
:is(.modal--offer, .modal--scroll) .picker__art { width: min(34px, 100%); }
:is(.modal--offer, .modal--scroll) .picker__art img { width: 100%; }
:is(.modal--offer, .modal--scroll) .picker__cell .name { font-size: 10.5px; line-height: 1.05; }
:is(.modal--offer, .modal--scroll) .ask-chip { min-height: 34px; }
:is(.modal--offer, .modal--scroll) .ask-chip .avatar { width: 26px; height: 26px; }
:is(.modal--offer, .modal--scroll) .modal__actions .btn { min-height: 40px; padding-block: 6px; }
/* On a short phone the space above the hand is too small: then it may sit over the hand rather than scroll. */
@media (max-height: 760px) {
  body:has(#view-game:not([hidden])) .modal-back:has(.modal--offer) { bottom: 0; place-items: center; }
  body:has(#view-game:not([hidden])) .modal--offer { max-height: calc(100svh - var(--top-live-h, 0px) - 18px); }
}
@media (max-width: 360px) {
  :is(.modal--offer, .modal--scroll) .picker { gap: 3px; }
  :is(.modal--offer, .modal--scroll) .picker__cell { padding-inline: 1px; }
  :is(.modal--offer, .modal--scroll) .stepper { gap: 0; }
  :is(.modal--offer, .modal--scroll) .stepper button { width: 19px; height: 21px; font-size: 12px; }
  :is(.modal--offer, .modal--scroll) .stepper span { min-width: 11px; font-size: 13px; }
}

/* When Ine's next step is a tap on the map, her card waits at the top of
   the board rather than over the middle of the island. */
#view-game .board-wrap > .guide[data-aim="board"] { top: 8px; transform: translateX(-50%); }
#view-game .board-wrap > .guide[data-aim="board"].is-new { animation: guide-drop .35s cubic-bezier(.2, .8, .2, 1); }
@keyframes guide-drop {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to   { opacity: 1; transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  #view-game .board-wrap > .guide[data-aim="board"].is-new { animation: none; }
}
/* Taps on the card itself (not its buttons) fall through to the map, so a
   spot under it can still be chosen; that tap also puts the card away. */
#view-game .board-wrap > .guide[data-aim="board"] { pointer-events: none; }
#view-game .board-wrap > .guide[data-aim="board"] button { pointer-events: auto; }

/* "Move the Magistrate": a card at the top of the map that never covers the
   lands you tap. OK or any tap elsewhere puts it away. */
.magistrate-call {
  position: fixed; z-index: 80; transform: translateX(-50%);
  width: min(22rem, calc(100vw - 24px)); display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 16px;
  background: linear-gradient(180deg, #f4ead4, #e6d6b3); color: var(--sumi, #1d1a16);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .55), inset 0 0 0 2px rgba(142, 33, 22, .55);
  animation: magistrate-call-in .45s cubic-bezier(.2, .9, .3, 1.2) both;
}
.magistrate-call__art { width: 44px; height: 56px; object-fit: contain; flex: none; }
.magistrate-call__words { display: grid; gap: 2px; flex: 1; min-width: 0; line-height: 1.25; }
.magistrate-call__words strong { font-family: var(--font-display, serif); font-size: 18px; color: var(--shu-deep, #8e2116); }
.magistrate-call__words span { font-size: 14px; }
.magistrate-call__ok { flex: none; min-width: 64px; min-height: 44px; font-size: 17px; }
@keyframes magistrate-call-in { from { opacity: 0; transform: translate(-50%, -14px) scale(.96); } }
@media (max-width: 360px) {
  .magistrate-call { gap: 8px; padding: 6px 8px; }
  .magistrate-call__art { width: 34px; height: 44px; }
  .magistrate-call__words strong { font-size: 16px; }
  .magistrate-call__words span { font-size: 13px; }
  .magistrate-call__ok { min-width: 54px; }
}
@media (prefers-reduced-motion: reduce) { .magistrate-call { animation: none; } }
/* Like Ine's card, a tap on the call (not its OK) reaches the land under it.
   While it shows, Ine's card for the same moment steps aside so they never stack. */
.magistrate-call { pointer-events: none; }
.magistrate-call__ok { pointer-events: auto; }
body:has(.magistrate-call) #view-game .board-wrap > .guide { visibility: hidden; }

/* Heard by screen readers, never seen. */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Re-emerge: the label, with its cost on a small line under it. */
.game .dock__actions .btn.btn--stack { flex-direction: column; gap: 0; line-height: 1.15; }

/* While others play, Ine's one tip for the wait sits along the top of the
   map, clear of the dice, the map tools and the middle of the island, and stays put until
   your turn so it can be read at any pace. Taps pass through to the map. */
#view-game .board-wrap > .guide[data-aim="wait"] {
  top: 6px; bottom: auto; transform: translateX(-50%);
  pointer-events: none; padding: 8px 12px 8px;
}
#view-game .board-wrap > .guide[data-aim="wait"] button { pointer-events: auto; }
/* A slim strip, not a card: Ine, the tip, and an OK at the side. */
#view-game .board-wrap > .guide[data-aim="wait"]:not([hidden]) {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-rows: auto auto;
  column-gap: 10px; row-gap: 1px; align-items: center; padding: 7px 8px 7px 10px;
}
#view-game .board-wrap > .guide[data-aim="wait"] .guide__head { display: contents; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__seal { grid-row: 1 / 3; grid-column: 1; width: 34px; height: 42px; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__who { grid-row: 1; grid-column: 2; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__who small { display: none; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__title { font-size: 12.5px; letter-spacing: .04em; color: #7a5a2c; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__text { grid-row: 2; grid-column: 2; margin: 0; font-size: 13.5px; line-height: 1.3; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__why,
#view-game .board-wrap > .guide[data-aim="wait"] .guide__hide { display: none; }
#view-game .board-wrap > .guide[data-aim="wait"] .guide__ok {
  grid-row: 1 / 3; grid-column: 3; width: auto; min-width: 52px; min-height: 44px; margin: 0; padding: 0 12px; font-size: 15px;
}
#view-game .board-wrap > .guide[data-aim="wait"].is-new { animation: guide-rise .4s cubic-bezier(.2, .8, .2, 1); }
@keyframes guide-rise {
  from { opacity: 0; transform: translate(-50%, -10px); }
  to   { opacity: 1; transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  #view-game .board-wrap > .guide[data-aim="wait"].is-new { animation: none; }
}

/* ---------------------------------------------------------------- the story so far */
.story {
  position: fixed; inset: 0; z-index: 120; display: grid; place-items: center;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  background: rgba(8, 10, 20, .55);
  animation: story-in .22s ease-out both;
}
.story.is-closing { animation: story-out .2s ease-in both; }
@keyframes story-in { from { opacity: 0; } }
@keyframes story-out { to { opacity: 0; } }
.story__paper {
  width: min(26rem, 100%); max-height: 100%; overflow: hidden;
  display: grid; gap: 10px; padding: 16px 16px 12px; border-radius: 18px;
  background: linear-gradient(180deg, #f6eedb, #ead9b5); color: var(--sumi, #1d1712);
  box-shadow: 0 20px 60px rgba(0, 0, 0, .6), inset 0 0 0 3px rgba(142, 33, 22, .35);
  animation: story-paper .3s cubic-bezier(.2, .8, .2, 1) both;
}
@keyframes story-paper { from { transform: translateY(12px) scale(.98); } }
.story__paper h2 { margin: 0; display: flex; align-items: center; gap: 10px; font: 700 21px/1.2 var(--font-display, serif); }
.story__kanji {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px;
  background: #b5301f; color: #fff3e4; font: 400 20px/1 var(--font-kanji, serif);
}
.story__turns { display: grid; gap: 8px; }
.story__turn {
  padding: 8px 10px 8px 12px; border-radius: 12px;
  background: rgba(255, 255, 255, .5); border-left: 5px solid var(--seat);
}
.story__who { display: flex; align-items: center; gap: 8px; font: 700 16px/1.2 var(--font-display, serif); }
.story__face { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: none; }
.story__lines { margin: 4px 0 0; padding: 0 0 0 18px; display: grid; gap: 2px; font-size: 14.5px; line-height: 1.35; }
.story__nav { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.story__nav .btn { min-height: 44px; min-width: 7.5rem; color: var(--sumi, #1d1712); border-color: rgba(29, 23, 18, .35); }
.story__nav .btn[disabled] { opacity: .35; }
.story__page { font-size: 13px; opacity: .7; }
.story__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.story__dice { min-height: 40px; padding: 0 14px; color: var(--sumi, #1d1712); border-color: rgba(29, 23, 18, .35); }
.dice-chart { display: grid; gap: 10px; }
.dice-chart__cols { display: grid; grid-template-columns: repeat(11, 1fr); gap: 4px; align-items: end; }
.dice-chart__col { display: grid; justify-items: center; gap: 3px; }
.dice-chart__n { font-size: 12px; opacity: .75; }
.dice-chart__well { position: relative; width: 100%; height: min(34svh, 220px); border-bottom: 1px solid rgba(29, 23, 18, .35); }
.dice-chart__bar { position: absolute; left: 12%; right: 12%; bottom: 0; border-radius: 4px 4px 0 0; background: #6b4f2a; transition: height .5s ease; }
.dice-chart__fair { position: absolute; left: 0; right: 0; height: 0; border-top: 2px dashed rgba(29, 23, 18, .6); }
.dice-chart__total { font: 700 15px/1 var(--font-display, serif); }
.dice-chart__note { margin: 0; font-size: 14px; line-height: 1.4; }
@media (max-height: 700px) {
  .story__lines { font-size: 13.5px; }
  .story__turn { padding: 6px 8px 6px 10px; }
}
@media (prefers-reduced-motion: reduce) { .story, .story.is-closing, .story__paper { animation: none; } }

/* A tapped land: its painting beside what it pays and to whom. */
.land-info { display: flex; gap: 12px; align-items: flex-start; }
.land-info__art { width: 64px; flex: none; aspect-ratio: 700 / 808; object-fit: cover;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
.land-info__words { display: grid; gap: 6px; min-width: 0; }
.land-info__words p { margin: 0; font-size: 15px; line-height: 1.35; }

/* A player's points, line by line. */
.score-rows { display: grid; gap: 6px; border-left: 5px solid var(--seat); padding-left: 10px; }
.score-rows .score-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.score-row__what { display: grid; min-width: 0; }
.score-row__what b { font-family: var(--font-display, serif); font-size: 16px; }
.score-row__what small { font-size: 12.5px; opacity: .75; line-height: 1.3; }
.score-row__pts { font: 700 20px/1 var(--font-display, serif); color: var(--shu-deep, #8e2116); min-width: 2ch; text-align: right; }
.mobile-player[role="button"] { cursor: pointer; }

/* Something worth building, or a card ready to play: a gold edge and a seal
   dot on the button, still, so it reads at a glance without flashing. */
.dock__actions .action-toggle.is-ready { position: relative; box-shadow: inset 0 0 0 2px rgba(242, 212, 138, .9), 0 0 14px rgba(242, 212, 138, .35); }
.dock__actions .action-toggle[data-tray-toggle="build"].is-ready::after {
  content: ''; position: absolute; top: 6px; right: 6px; width: 9px; height: 9px; border-radius: 50%;
  background: #f2d48a; box-shadow: 0 0 6px rgba(242, 212, 138, .9);
}
/* ---------------------------------------------------------------- Home on a phone
 * One screen, no page scroll: the ways to play as tiles, then one list at a
 * time under Games, Friends and Scores. Wider screens keep the long page. */
.home-tabs { display: none; }
.home-games, .home-more { display: contents; }
@media (max-width: 600px) {
  .lobby { overflow: hidden; display: flex; flex-direction: column; padding: 10px 12px max(10px, env(safe-area-inset-bottom, 0px)); }
  .lobby__inner { display: flex; flex-direction: column; gap: 10px; width: 100%; flex: 1; min-height: 0; }
  .lobby-hero { display: none; }
  .keep-card { margin: 0; padding: 8px 10px; gap: 10px; }
  .keep-card__seal { width: 34px; height: 34px; font-size: 20px; }
  .keep-card b { font-size: 15px; }
  .keep-card span { font-size: 12px; }

  .ways { grid-template-columns: 1fr 1fr; gap: 8px; animation: none; flex: none; }
  .way, .way--tutorial, .way.way--classic { min-height: 0; padding: 40px 10px 10px; border-radius: 10px; }
  .way--tutorial { grid-column: auto; }
  .way--bots, .way--classic { grid-column: 1 / -1; }
  .way__body { gap: 4px; }
  .way__body p { display: none; }
  .way__body h3 { font-size: 17px; letter-spacing: .04em; }
  .way__seal { width: 28px; height: 28px; font-size: 16px; top: 8px; left: 8px; border-radius: 7px; }
  .way__body .btn, .way__actions .btn { margin-top: 2px; padding: 8px 12px; min-height: 40px; font-size: 14.5px; }
  .way--tutorial .way__body .btn, .way--friends .way__body .btn { width: 100%; }
  .way__actions { flex-wrap: nowrap; gap: 8px; width: 100%; }
  .way__actions .btn { flex: 1; }
  .way--tutorial .way__art { background-size: auto 100%, cover, auto; background-position: right -18px bottom 0, center 40%, center; }
  .way--tutorial::after { background: linear-gradient(90deg, rgba(8, 13, 24, .9) 0%, rgba(8, 13, 24, .55) 60%, rgba(8, 13, 24, .2) 100%); }
  .way--bots .way__body h3 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .way--bots { padding-top: 44px; }
  .way.way--classic .way__art { background-size: 150px auto, 0 0, 0 0, 0 0, 0 0, 0 0, auto; background-position: right 8px center, 0 0, 0 0, 0 0, 0 0, 0 0, center; }

  .home-tabs {
    display: grid; grid-template-columns: repeat(3, 1fr); flex: none;
    border-bottom: 1px solid var(--line);
  }
  .home-tab {
    background: none; border: 0; border-bottom: 2px solid transparent; color: var(--washi-dim);
    font-family: var(--font-display); font-size: 15px; letter-spacing: .06em; padding: 8px 4px; min-height: 42px; cursor: pointer;
  }
  .home-tab[hidden] { display: none; }
  .home-tab.is-on { color: var(--washi); border-bottom-color: var(--shu); }
  .home-tab__count {
    display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 5px; margin-left: 4px;
    border-radius: 10px; background: var(--shu); color: #fff6e6; font-family: var(--font-body, inherit); font-size: 12px;
  }
  .home-tab__count[hidden] { display: none; }

  /* Only the chosen tab's lists show; the one showing takes the rest of the screen. */
  .lobby #home-games, .lobby #friends, .lobby #home-more, .lobby #home-more > * { animation: none; }
  .lobby:not([data-tab="games"]) #home-games,
  .lobby:not([data-tab="friends"]) #friends,
  .lobby:not([data-tab="more"]) #home-more { display: none; }
  .home-more { display: grid; gap: 10px; align-content: start; }
  .home-more > [hidden] { display: none; }
  .home-more .lobby__head { padding-bottom: 4px; }
  .home-more .lobby__head h2 { font-size: 16px; }
  .lobby #challenge { padding: 10px 12px; gap: 10px; grid-template-columns: 40px 1fr; }
  .lobby #challenge .circle-card__seal { width: 40px; height: 40px; font-size: 20px; }
  .lobby #challenge h3 { font-size: 16px; }
  .lobby #challenge .challenge__kicker { display: none; }
  .lobby #challenge .btn { min-height: 38px; padding: 6px 14px; }
  .lobby #challenge .challenge__goal { font-size: 13px; line-height: 1.4; margin: 0; }
  .lobby[data-tab="games"] #home-games, .lobby[data-tab="friends"] #friends, .lobby[data-tab="more"] #home-more {
    flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; align-content: start;
  }
  .home-games { display: grid; gap: 8px; align-content: start; }
  .my-games, .open-tables { display: grid; gap: 8px; align-content: start; }
  .open-tables[hidden] { display: none; }
  .home-games .lobby__head { display: none; }
  .friends__head h2 { display: none; }
  .friends__head { border-bottom: 0; padding-bottom: 0; justify-content: flex-end; }
  .friends__list { flex-wrap: wrap; overflow: visible; }
  /* Turn alerts sit under the games, small, until they are on. */
  .lobby #alerts { padding: 8px 10px; gap: 4px 10px; grid-template-columns: auto 1fr; align-items: center; }
  .lobby #alerts .circle-card__seal { width: 32px; height: 32px; font-size: 18px; }
  .lobby #alerts .circle-card__body { gap: 4px; }
  .lobby #alerts h3 { font-size: 14.5px; letter-spacing: .03em; }
  .lobby #alerts .invite, .lobby #alerts .invite p { font-size: 12.5px; line-height: 1.35; margin: 0; }
  .lobby #alerts .btn { min-height: 36px; padding: 6px 12px; }
  /* A game is a slim row: its painting a strip at the left. */
  .game-list { gap: 8px; grid-template-columns: 1fr; }
  .game-card { grid-template-columns: 64px 1fr; align-items: center; min-height: 66px; animation: none; }
  .game-card:hover { transform: none; }
  .game-card__art, .game-card__art.is-kakure { grid-row: 1 / span 3; width: 64px; height: 100%; min-height: 66px; mask-image: none; -webkit-mask-image: none; }
  .game-card__main { margin: 0; padding: 8px 64px 8px 12px; }
  .game-card__name { font-size: 16px; }
  .game-card__with, .game-card__meta { font-size: 12.5px; }
  .game-card .seats, .game-card__badge { display: none; }
  .game-card.is-yours::before { top: 8px; right: -30px; font-size: 9.5px; padding: 3px 34px; }
  .game-card__delete { right: 8px; bottom: 6px; padding: 3px 8px; font-size: 12px; }
  .way, .way--tutorial, .way.way--classic { padding-top: 34px; }
  .way--bots { padding-top: 40px; }
  .way__body h3 { font-size: 16px; }
}
@media (max-width: 600px) and (max-height: 620px) {
  .way, .way--tutorial, .way--bots { padding-top: 30px; }
  .way__seal { width: 24px; height: 24px; font-size: 14px; top: 6px; left: 6px; }
  .keep-card span { display: none; }
}

/* Narrow phones: the game name and "5 of 15 points" never get cut off.
   The buttons on the right slim down, and the name and status line may take
   a second line instead of ending in "…". */
@media (max-width: 430px) and (orientation: portrait) {
  html body:has(#view-game:not([hidden])) .topbar { gap: 6px; padding-left: 6px; padding-right: 6px; max-height: none; }
  html body:has(#view-game:not([hidden])) .topbar__right { gap: 4px; }
  html body:has(#view-game:not([hidden])) .topbar__right #btn-mobile-chat,
  html body:has(#view-game:not([hidden])) .topbar__right #btn-more { padding: 0 9px; letter-spacing: .02em; font-size: 12.5px; }
  html body:has(#view-game:not([hidden])) .topbar__right .icon-toggle { width: 34px; height: 34px; }
  html body:has(#view-game:not([hidden])) .topbar__home img { width: 38px; height: 38px; }
  html body:has(#view-game:not([hidden])) .topbar__title h1,
  html body:has(#view-game:not([hidden])) .topbar__title p {
    white-space: normal; text-overflow: clip; overflow: hidden;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    line-height: 1.15; overflow-wrap: anywhere;
  }
  html body:has(#view-game:not([hidden])) .topbar__title h1 { font-size: 14.5px; }
  html body:has(#view-game:not([hidden])) .topbar__title p { font-size: 11px; }
}
