@font-face {
  font-family: 'Fredoka';
  src: url('../vendor/fonts/fredoka-latin-500-normal.woff2') format('woff2');
  font-weight: 400 500;
  font-display: swap;
}
@font-face {
  font-family: 'Fredoka';
  src: url('../vendor/fonts/fredoka-latin-700-normal.woff2') format('woff2');
  font-weight: 600 800;
  font-display: swap;
}

:root {
  --ink: #3d2e4f;
  --ink-soft: #6c5a80;
  --paper: #fffaf0;
  --paper-2: #fff3dc;
  --line: #f0dfc0;
  --sky: #5fb8f4;
  --sky-dark: #3a8fd0;
  --grass: #6cc24a;
  --grass-dark: #4a9a31;
  --sun: #ffd23f;
  --sun-dark: #e0a800;
  --pink: #ff7fb2;
  --pink-dark: #e0588f;
  --select: #fff3b0;
  --shadow: 0 6px 18px rgba(61, 46, 79, 0.22);
  --radius: 20px;
  --radius-lg: 22px;
  --radius-md: 16px;
  --radius-sm: 12px;
  --glass: rgba(255, 250, 240, 0.62);
  --glass-blur: blur(10px) saturate(1.4);
  --font: 'Fredoka', ui-rounded, 'SF Pro Rounded', 'Arial Rounded MT Bold', 'Nunito', system-ui, sans-serif;
  --tool: 58px;
  --slot: 56px;
  --talk: 58px;
  --touch: 60px;
  --stick: 124px;
  /* Clear of the talk buttons, which sit halfway down the right side. */
  --map: clamp(108px, calc(50vh - 142px), 156px);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #9fd8ff;
  color: var(--ink);
  font-family: var(--font);
  font-weight: 500;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
  overscroll-behavior: none;
}

[hidden] {
  display: none !important;
}

#world {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
  outline: none;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: none;
  background: none;
  -webkit-tap-highlight-color: transparent;
}

button:focus-visible {
  outline: 4px solid var(--sun);
  outline-offset: 2px;
}

/* ------------------------------------------------ toy buttons */

.big,
.chip,
.round,
.tool,
.slot,
.pill,
.choice {
  transition:
    transform 0.08s ease,
    box-shadow 0.08s ease,
    filter 0.15s ease;
}

.big {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  padding: 16px 22px;
  border-radius: 22px;
  font-size: 1.5rem;
  font-weight: 700;
  color: white;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.15);
  box-shadow:
    0 5px 0 var(--shade, #0003),
    var(--shadow);
}

.big .emoji {
  font-size: 1.8rem;
}

/* On a pointer you can hover with, the toys lift a little to meet it. */
@media (hover: hover) {
  .big:hover {
    filter: brightness(1.06);
    transform: translateY(-1px);
  }

  .chip:hover,
  .round:hover,
  .pill:hover {
    filter: brightness(1.04);
    transform: translateY(-1px);
  }
}

.big:active,
.chip:active,
.round:active,
.tool:active,
.slot:active,
.choice:active {
  transform: translateY(3px);
  box-shadow: 0 2px 0 var(--shade, #0003);
}

.green {
  background: var(--grass);
  --shade: var(--grass-dark);
}

.blue {
  background: var(--sky);
  --shade: var(--sky-dark);
}

.yellow {
  background: var(--sun);
  --shade: var(--sun-dark);
  color: var(--ink);
  text-shadow: none;
}

.pink {
  background: var(--pink);
  --shade: var(--pink-dark);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 16px;
  border-radius: 999px;
  background: white;
  font-size: 1.05rem;
  font-weight: 600;
  box-shadow:
    0 4px 0 var(--line),
    0 4px 10px rgba(61, 46, 79, 0.12);
  --shade: var(--line);
}

.chip.on {
  background: var(--sun);
}

.round {
  display: inline-grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: white;
  font-size: 1.35rem;
  box-shadow:
    0 4px 0 var(--line),
    0 3px 10px rgba(61, 46, 79, 0.18);
  --shade: var(--line);
}

/* Line icons, for what no emoji shows. */
.line-icon {
  width: 1.15em;
  height: 1.15em;
  flex: none;
  vertical-align: -0.22em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.full-icon {
  color: var(--sky-dark);
}

/* Corners point out to go full screen, and in to come back. */
.full-icon .leave,
body.fullscreen .full-icon .enter {
  display: none;
}

body.fullscreen .full-icon .leave {
  display: inline;
}

.share-icon {
  color: #0a84ff;
}

/* ------------------------------------------------ title */

.screen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  overflow-y: auto;
}

.title-top,
.title-bottom {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.title-bottom {
  gap: 14px;
}


.logo {
  margin: 0;
  font-size: clamp(3rem, 11vw, 6rem);
  font-weight: 800;
  letter-spacing: 1px;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
}

.logo span {
  display: inline-block;
  color: white;
  -webkit-text-stroke: 2.5px var(--ink);
  paint-order: stroke fill;
  text-shadow:
    0 5px 0 var(--ink),
    0 14px 28px rgba(61, 46, 79, 0.3);
  animation: bob 2.4s ease-in-out infinite;
}

.logo span:nth-child(1) { color: #ff6b6b; animation-delay: 0s; }
.logo span:nth-child(2) { color: #ffa94d; animation-delay: 0.1s; }
.logo span:nth-child(3) { color: #ffd43b; animation-delay: 0.2s; }
.logo span:nth-child(4) { color: #69db7c; animation-delay: 0.3s; }
.logo span:nth-child(5) { color: #4dabf7; animation-delay: 0.4s; }
.logo span:nth-child(6) { color: #9775fa; animation-delay: 0.5s; }
.logo span:nth-child(7) { color: #f783ac; animation-delay: 0.6s; }
.logo span:nth-child(8) { color: #ff8787; animation-delay: 0.7s; }
.logo span:nth-child(9) { color: #63e6be; animation-delay: 0.8s; }

@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

.tagline {
  margin: 0;
  font-size: 1.35rem;
  font-weight: 600;
  background: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 4px 14px rgba(61, 46, 79, 0.14);
  padding: 6px 18px;
  border-radius: 999px;
  text-align: center;
}

@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .tagline {
    background: rgba(255, 255, 255, 0.8);
  }
}

.me-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

.me-name {
  font-size: 1.2rem;
  font-weight: 700;
  background: white;
  padding: 8px 16px;
  border-radius: 999px;
  box-shadow: var(--shadow);
}

.big-buttons {
  display: grid;
  gap: 12px;
  width: min(420px, 100%);
}

/* The shared isle, first and right across: the one island everyone
   conquers together (only where the list of open islands is). */
.isle-button {
  grid-column: 1 / -1;
}

@media (min-width: 900px) and (min-height: 600px) {
  .big-buttons {
    grid-template-columns: repeat(3, 1fr);
    width: min(900px, 100%);
  }
}

/* Build or Adventure on the title screen: your worlds, each with its own
   level, stickers, shop and ranking (the shared isle's apart from the rest). */
.mode-switch {
  justify-content: center;
  margin-bottom: 0;
}

.mode-switch .chip {
  font-size: 1.1rem;
  padding: 10px 20px;
}

.isle-away {
  grid-column: 1 / -1;
  font-size: 1.05rem;
}

.small-buttons {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}

/* ------------------------------------------------ HUD */

#hud {
  position: fixed;
  inset: 0;
  pointer-events: none;
}

#hud > * {
  pointer-events: auto;
}

#hud > #overlays,
#hud > .chatlog,
#hud > .aim-hint {
  pointer-events: none;
}

/* The bottom bar is as wide as its widest row, the hotbar: beside a narrower
   row above it (the basket) and between the rows, what shows is the world,
   and a tap there is for the world. */
#hud > #bottom {
  pointer-events: none;
}

#bottom > * {
  pointer-events: auto;
}

#topbar {
  position: absolute;
  top: max(10px, env(safe-area-inset-top));
  left: max(10px, env(safe-area-inset-left));
  right: max(10px, env(safe-area-inset-right));
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: none;
}

#topbar > * {
  pointer-events: auto;
}

.island-badge {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 6px 16px;
  border-radius: var(--radius-md);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
  text-align: left;
  min-width: 0;
}

.island-name {
  font-weight: 700;
  font-size: 1.1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 40vw;
}

.island-code {
  font-size: 0.9rem;
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A connection message takes only the room that is left (before the
   friends' faces do), so the island's code, which kids read out to friends,
   never gives way to it. A long one wraps onto a second line and ends in an
   ellipsis after that. Narrow screens have no room for it here: see the
   small screens below. */
.status {
  flex: 1000 1 0;
  min-width: 0;
  max-width: max-content;
  font-size: 0.85rem;
  line-height: 1.3;
  /* Room around the words in a see-through border, not padding: the lines
     after the second would show through padding. */
  border: solid transparent;
  border-width: 7px 12px;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.7);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.status:empty {
  display: none;
}

.friends {
  display: flex;
  gap: 4px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.friend {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: white;
  border: 3px solid var(--c, white);
  font-size: 1.2rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  flex: none;
}

.top-buttons {
  display: flex;
  flex: none;
  gap: 8px;
  align-items: center;
  margin-left: auto;
}

/* The buttons and the clock keep their size; the island's name gives way. */
.top-buttons > * {
  flex: none;
}

/* No room for it beside the island code on the narrowest phones: Settings has it there. */
@media (max-width: 400px) {
  #btn-view {
    display: none;
  }
}

.clock {
  font-size: 1.6rem;
  white-space: nowrap;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.2));
}

#toolbar {
  position: absolute;
  left: max(10px, env(safe-area-inset-left));
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px;
  border-radius: 24px;
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
}

.tool {
  display: grid;
  place-items: center;
  width: var(--tool);
  height: var(--tool);
  border-radius: 18px;
  font-size: 1.7rem;
  background: white;
  box-shadow: 0 4px 0 var(--line);
  --shade: var(--line);
  position: relative;
}

.tool small {
  position: absolute;
  bottom: 2px;
  font-size: 0.62rem;
  font-weight: 700;
  color: var(--ink-soft);
}

.tool.on {
  background: var(--sun);
  box-shadow: 0 4px 0 var(--sun-dark);
  --shade: var(--sun-dark);
}

.tool.undo {
  background: var(--paper-2);
}

#toolopts {
  position: absolute;
  left: calc(max(10px, env(safe-area-inset-left)) + var(--tool) + 30px);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

#toolopts:empty {
  display: none;
}

.opt-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px;
  border-radius: var(--radius-md);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
}

.pill {
  display: grid;
  place-items: center;
  min-width: 46px;
  height: 40px;
  padding: 0 8px;
  border-radius: 14px;
  background: white;
  font-size: 1.1rem;
  font-weight: 700;
  box-shadow: 0 3px 0 var(--line);
}

.pill.on {
  background: var(--sky);
  color: white;
  box-shadow: 0 3px 0 var(--sky-dark);
}

.dot {
  display: inline-block;
  border-radius: 4px;
  background: currentColor;
}

#bottom {
  position: absolute;
  left: 50%;
  bottom: max(10px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  /* A width of its own: shrinking to fit, it would only get the half of the
     screen right of left: 50%, and cut off the last slot on screens under
     twice its width. */
  width: max-content;
  max-width: calc(100vw - 20px);
}

.hotrow {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
}

#hotbar {
  min-width: 0;
  display: flex;
  gap: 6px;
  padding: 7px;
  border-radius: var(--radius-lg);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow);
  overflow-x: auto;
  max-width: 100%;
  scrollbar-width: none;
}

.slot {
  position: relative;
  flex: none;
  width: var(--slot);
  height: var(--slot);
  border-radius: 14px;
  background: white;
  box-shadow: 0 3px 0 var(--line);
  --shade: var(--line);
  padding: 4px;
}

.slot img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
}

.slot .num {
  position: absolute;
  top: 2px;
  left: 5px;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--ink-soft);
}

.slot.on {
  background: var(--select);
  box-shadow:
    0 0 0 3px var(--sun),
    0 3px 0 var(--sun-dark);
}

.slot.toybox {
  width: auto;
  height: calc(var(--slot) + 14px);
  padding: 4px 14px;
  border-radius: 20px;
  font-size: 1rem;
  font-weight: 700;
  background: var(--pink);
  color: white;
  box-shadow: 0 3px 0 var(--pink-dark);
  --shade: var(--pink-dark);
  display: flex;
  align-items: center;
  gap: 6px;
}

.slot.toybox .emoji {
  font-size: 1.5rem;
}

/* Your HP, while the island has monsters: a number and a bar. */
.hearts {
  display: flex;
  gap: 2px;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.6);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
  font-size: 1.15rem;
  line-height: 1.3;
  pointer-events: none;
}

.hearts[hidden] {
  display: none;
}

.hearts .hp-label,
.hearts .hp-num {
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
}

.hearts .hp-num {
  min-width: 4.2em;
  font-variant-numeric: tabular-nums;
}

/* Green while there is plenty, amber at half, red when it runs low. */
.hearts .hp-bar {
  align-self: center;
  width: 84px;
  height: 10px;
  margin: 0 4px;
  border-radius: 999px;
  background: rgba(61, 46, 79, 0.18);
  overflow: hidden;
}

.hearts .hp-bar > span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: #4cc46a;
  transition: width 0.25s;
}

.hearts .hp-bar.half > span {
  background: #f2b233;
}

.hearts .hp-bar.low > span {
  background: #ef5a5a;
}

/* On a tower defense island: the wave, the Star Stone's hearts and the bricks. */
.defense-bar {
  gap: 10px;
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
}

.defense-bar .muted {
  font-weight: 600;
}

/* Build and Start: like Ride, in the island's sky blue; greyed when the bricks are short. */
.defend-button {
  background: #8fd8ff;
  box-shadow:
    0 4px 0 #4aa6d6,
    0 3px 10px rgba(61, 46, 79, 0.25);
}

.defend-button.short {
  filter: grayscale(0.7);
  opacity: 0.8;
}

/* On an adventure island, how many camps are free. */
.hearts .camps {
  margin-left: 6px;
  font-size: 0.95rem;
  font-weight: 700;
  white-space: nowrap;
}

.hearts.hurt {
  animation: hearts-hurt 0.45s;
}

@keyframes hearts-hurt {
  25% {
    transform: translateX(-5px);
  }
  50% {
    transform: translateX(5px);
  }
  75% {
    transform: translateX(-3px);
  }
}

/* The HP bar, with the 🧪 potion button beside it (shop.js): the row shows
   only while one of them does. */
.hp-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.hp-row[hidden] {
  display: none;
}

/* A potion to drink, while some HP is missing and you have one: a little
   white pill with the count beside the flask. */
.potion-button {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 12px;
  border-radius: 999px;
  background: white;
  font-size: 1.05rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  box-shadow:
    0 3px 0 var(--line),
    0 3px 10px rgba(61, 46, 79, 0.15);
  --shade: var(--line);
  transition:
    transform 0.08s ease,
    box-shadow 0.08s ease,
    filter 0.15s ease;
}

.potion-button[hidden] {
  display: none;
}

@media (hover: hover) {
  .potion-button:hover {
    filter: brightness(1.04);
    transform: translateY(-1px);
  }
}

.potion-button:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 var(--shade);
}

/* Where the glass panels float, a blur behind them needs support for it:
   without one they go back to more solid paper, still easy to read. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .island-badge,
  #toolbar,
  .opt-group,
  #hotbar {
    background: rgba(255, 250, 240, 0.92);
  }

  .status {
    background: rgba(255, 255, 255, 0.85);
  }

  .hearts {
    background: rgba(255, 255, 255, 0.75);
  }
}

.basket {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center;
}

.basket:empty {
  display: none;
}

.basket button {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.basket button.on {
  background: var(--sun);
}

.basket img {
  width: 22px;
  height: 22px;
}

#talk {
  position: absolute;
  right: max(10px, env(safe-area-inset-right));
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Two classes, so it still outranks .round where small screens restyle that. */
.round.big-round {
  width: var(--talk);
  height: var(--talk);
  font-size: 1.7rem;
}

#touch-buttons {
  position: absolute;
  right: max(14px, env(safe-area-inset-right));
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + 100px);
  display: none;
  grid-template-areas:
    'down jump'
    'fly jump';
  gap: 10px;
  align-items: end;
}

/* The bop button, bottom left of them, only while a monster is about. */
#touch-buttons:has(> #btn-attack:not([hidden])) {
  grid-template-areas:
    'attack down jump'
    '. fly jump';
}

#btn-down {
  grid-area: down;
}

#btn-fly {
  grid-area: fly;
}

#btn-attack {
  grid-area: attack;
}

body.touch #touch-buttons {
  display: grid;
}

/* Two classes, so it still outranks .round where small screens restyle that,
   and leaves <body> alone, which has a touch class of its own on touch screens. */
.round.touch {
  width: var(--touch);
  height: var(--touch);
  font-size: 1.6rem;
  opacity: 0.92;
}

/* Three classes, so the small-screen .round.touch rule leaves it alone. */
.round.touch.jump {
  width: 78px;
  height: 78px;
  font-size: 2rem;
  grid-area: jump;
}

.round.touch.attack[hidden] {
  display: none;
}

/* On the shared isle (Adventure Isle) nobody builds and nobody flies on
   their own: its tools, its toy box and its fly button are not there. */
#toolbar[hidden],
#toolopts[hidden],
#hotbar[hidden],
#btn-toybox[hidden],
#btn-fly[hidden] {
  display: none;
}

.touch.on {
  background: var(--sun);
}

/* The thumbstick sits in the bottom-left corner on touch screens; touches
   anywhere else aim and build. */
#joystick {
  position: fixed;
  left: calc(max(14px, env(safe-area-inset-left)) + 6px);
  bottom: calc(max(12px, env(safe-area-inset-bottom)) + 8px);
  width: var(--stick);
  height: var(--stick);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  border: 4px solid rgba(255, 255, 255, 0.75);
  box-shadow: 0 4px 14px rgba(61, 46, 79, 0.18);
  pointer-events: none;
  z-index: 5;
  display: none;
}

body.touch.playing #joystick {
  display: block;
}

#joystick.active {
  background: rgba(255, 255, 255, 0.42);
}

#joystick .knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
  transform: translate(-50%, -50%);
}

/* ------------------------------------------------ the little map */

#minimap {
  position: absolute;
  top: calc(max(10px, env(safe-area-inset-top)) + 58px);
  right: max(10px, env(safe-area-inset-right));
  display: block;
  width: var(--map);
  height: var(--map);
  padding: 4px;
  border-radius: 20px;
  background: rgba(255, 250, 240, 0.92);
  box-shadow: var(--shadow);
  transition: transform 0.08s ease;
}

#minimap:active {
  transform: scale(0.96);
}

#minimap canvas {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 16px;
}

/* The big map, in a dialog: as big as the screen allows, and square. */
.big-map {
  display: block;
  width: min(100%, calc(88vh - 130px));
  aspect-ratio: 1;
  margin: 0 auto;
  border-radius: 18px;
  background: rgb(44, 118, 206);
}

.panel .map-note {
  margin-top: 10px;
  text-align: center;
}

/* ------------------------------------------------ name tags and speech bubbles */

#overlays {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* A breath of shade in the corners of the world, drawing the eye to the
   middle. The tags and bubbles come after it and stay bright. */
#overlays::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 42%, transparent 62%, rgba(35, 24, 58, 0.16) 100%);
  pointer-events: none;
}

@media (prefers-reduced-transparency: reduce) {
  #overlays::before {
    display: none;
  }
}

.tag {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(-50%, -100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  will-change: transform;
}

.tag .name {
  max-width: 16em;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.88);
  font-size: 0.85rem;
  font-weight: 700;
  white-space: nowrap;
  border: 2px solid var(--c, white);
}

.bubble {
  position: relative;
  max-width: 220px;
  overflow-wrap: anywhere;
  padding: 8px 14px;
  border-radius: 18px;
  background: white;
  font-size: 1.05rem;
  font-weight: 600;
  box-shadow: 0 4px 12px rgba(61, 46, 79, 0.25);
  text-align: center;
  animation: pop-in 0.25s cubic-bezier(0.3, 1.6, 0.5, 1);
}

.bubble.sticker {
  font-size: 2.2rem;
  padding: 2px 10px;
}

.bubble::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -9px;
  border: 9px solid transparent;
  border-bottom: 0;
  border-top-color: white;
  transform: translateX(-50%);
}

@keyframes pop-in {
  from { transform: scale(0.4); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

/* Ride, over the big animal beside you (and Get off, over your own head
   while you ride), following it about the way name tags do: a big target for
   small fingers. */
.ride-button {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 4px 18px;
  border: 3px solid white;
  border-radius: 999px;
  background: var(--sun);
  box-shadow:
    0 4px 0 var(--sun-dark),
    0 3px 10px rgba(61, 46, 79, 0.25);
  font-size: 1.15rem;
  font-weight: 700;
  white-space: nowrap;
  will-change: transform;
}

.ride-button kbd {
  background: rgba(255, 255, 255, 0.7);
  border-color: var(--sun-dark);
}

.critter-tag .name {
  background: rgba(255, 243, 176, 0.92);
}

/* Over an adventure island's camps, how their flags are going, and over King
   Grumble, his hearts: a little card with a bar, following them about as the
   name tags do. */
.adv-tag {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 3px 10px 4px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 2px 8px rgba(61, 46, 79, 0.22);
  font-size: 0.85rem;
  font-weight: 700;
  white-space: nowrap;
  will-change: transform;
}

.adv-tag .bar {
  width: 96px;
  height: 8px;
  border-radius: 999px;
  background: rgba(61, 46, 79, 0.15);
  overflow: hidden;
}

.adv-tag .bar span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: #5cc3f2;
  transition: width 0.2s;
}

.adv-tag .bar.king span {
  background: #ff5f8f;
}

.adv-tag .bar.stone span {
  background: #ffd84d;
}

/* A monster's hearts: just the bar, small, over its head. */
.adv-tag.mon {
  padding: 2px;
  border-radius: 999px;
  pointer-events: none;
}

.adv-tag.mon .bar {
  width: 40px;
  height: 6px;
  background: rgba(61, 46, 79, 0.4);
}

.adv-tag.mon .bar.monster span {
  background: #ff5f8f;
}

/* What you got for popping a monster (game.js): a gold pill over where it
   happened, rising away and fading as ui.js moves it with the world. The
   span is what animates, so the placing transform stays ui.js's own. */
.float-reward {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

.float-reward span {
  display: block;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--sun);
  border: 2px solid white;
  box-shadow: 0 2px 8px rgba(61, 46, 79, 0.3);
  font-size: 0.95rem;
  font-weight: 800;
  white-space: nowrap;
  animation: pop-in 0.25s cubic-bezier(0.3, 1.6, 0.5, 1);
}

/* The ⭐ Stickers button, pinging as the XP of a pop goes in: the ring on it
   fills the same moment (renderLevel, off the profile's count). */
.level-ring.gain {
  animation: level-gain 0.6s;
}

@keyframes level-gain {
  35% {
    transform: scale(1.22);
  }
}

@media (prefers-reduced-motion: reduce) {
  .float-reward span,
  .level-ring.gain {
    animation: none;
  }
}

.aim-hint {
  position: absolute;
  left: 50%;
  top: 70px;
  transform: translateX(-50%);
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  font-weight: 600;
}

/* Chat lines stand on the hotbar and the basket over it (--bottom-height is
   the height of both together, kept by the UI), left of the talk buttons and
   under the little map: the log is the room between them. The newest line is
   at the bottom, and a line that does not fit whole goes (see chatRoom in the
   UI), so the oldest go first. Smaller screens give it other room between
   the buttons; on the shortest there may be none. */
.chatlog {
  position: absolute;
  top: calc(max(10px, env(safe-area-inset-top)) + 68px + var(--map));
  right: calc(max(10px, env(safe-area-inset-right)) + 70px);
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 70px) + 26px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  gap: 4px;
  max-width: 300px;
  overflow: hidden;
}

/* Three lines at most, the rest is in the speech bubble. The space inside is
   a transparent border, not padding, which the clipped lines would show
   through under the ellipsis. */
.chatlog .line {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  overflow-wrap: anywhere;
  border: solid transparent;
  border-width: 4px 12px;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.85);
  font-size: 0.9rem;
  animation: fade-out 8s forwards;
}

/* Korean wraps at spaces, as English does, not between any two syllables. */
.bubble:lang(ko),
.chatlog .line:lang(ko) {
  word-break: keep-all;
  overflow-wrap: break-word;
}

/* What has been said, to read again and copy: a few lines, scrolling, the
   newest at the bottom. The words can be selected, unlike the rest of the game. */
.chat-history {
  max-height: min(30vh, 220px);
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  margin-bottom: 12px;
  padding: 6px;
  border-radius: 14px;
  border: 2px solid var(--line);
  background: white;
}

.chat-history .said {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding: 3px 4px;
  border-radius: 10px;
}

.chat-history .said.mine {
  background: rgba(159, 216, 255, 0.3);
}

.chat-history .said-text {
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
  -webkit-user-select: text;
  user-select: text;
}

.chat-history .said-text:lang(ko) {
  word-break: keep-all;
  overflow-wrap: break-word;
}

.chat-history .copy {
  flex: none;
  width: 34px;
  height: 30px;
  border-radius: 10px;
  background: none;
  font-size: 1rem;
}

.chat-history .copy:hover {
  background: rgba(0, 0, 0, 0.06);
}

.say-row {
  flex-wrap: nowrap;
  margin-bottom: 14px;
}

@keyframes fade-out {
  0%, 80% { opacity: 1; }
  100% { opacity: 0; }
}

/* The camera flash when you take a photo. */
#flash {
  position: fixed;
  inset: 0;
  background: white;
  z-index: 35;
  pointer-events: none;
  animation: flash 0.5s ease-out forwards;
}

@keyframes flash {
  from { opacity: 0.9; }
  to { opacity: 0; }
}

/* ------------------------------------------------ toasts */

#toasts {
  position: fixed;
  top: max(64px, calc(env(safe-area-inset-top) + 58px));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 30;
  pointer-events: none;
  width: min(92vw, 520px);
}

.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px;
  border-radius: 18px;
  background: var(--paper);
  box-shadow: var(--shadow);
  font-weight: 600;
  animation: toast 4s forwards;
  text-align: left;
}

.toast .icon {
  font-size: 1.6rem;
}

.toast.sticker {
  background: var(--select);
  border: 3px solid var(--sun);
}

.toast.warn {
  background: #ffe3e3;
}

/* Invitations to a friend's island, over everything but the loading screen,
   until you answer them. */
#invitations {
  position: fixed;
  top: max(22vh, calc(env(safe-area-inset-top) + 120px));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  z-index: 32;
  width: min(calc(100vw - 32px), 440px);
  pointer-events: none;
}

.invitation {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 10px 12px;
  padding: 14px 16px;
  border-radius: 22px;
  background: var(--paper);
  border: 4px solid var(--pink);
  box-shadow: var(--shadow);
  pointer-events: auto;
  animation: pop-in 0.22s cubic-bezier(0.3, 1.5, 0.5, 1);
}

.invitation .words {
  margin: 0;
  font-size: 1.1rem;
  overflow-wrap: anywhere;
}

.invitation .words b:lang(ko) {
  word-break: keep-all;
}

.invitation .row {
  grid-column: 1 / -1;
  justify-content: flex-end;
}

.invitation .avatar,
.player-item .avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--c);
  font-size: 1.6rem;
}

.player-item:not(.online) .avatar {
  filter: saturate(0.4);
  opacity: 0.75;
}

.player-item .chip:disabled {
  opacity: 0.7;
}

@keyframes toast {
  0% { transform: translateY(-20px) scale(0.9); opacity: 0; }
  8%, 85% { transform: none; opacity: 1; }
  100% { transform: translateY(-10px); opacity: 0; }
}

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

.modal {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  /* Clear of the clock and the notch, which the game draws under on an iPhone's Home Screen. */
  padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  background: rgba(45, 32, 66, 0.45);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  z-index: 20;
}

@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .modal {
    background: rgba(45, 32, 66, 0.55);
  }
}

.modal.see-through {
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  pointer-events: none;
}

.modal.see-through .panel {
  pointer-events: auto;
}

/* See-through dialogs step aside so you can watch your character. */
@media (min-width: 900px) {
  .modal.see-through .panel {
    justify-self: start;
    margin-left: 2vw;
    width: min(560px, 50vw);
  }
}

@media (max-width: 899px) {
  .modal.see-through {
    align-items: end;
  }

  .modal.see-through .panel {
    max-height: 58vh;
  }

  /* Choosing how you look: the camera puts you above the sheet, so the title
     and the buttons step out of the way. */
  body.posing #title,
  body.posing #hud,
  body.posing #joystick {
    visibility: hidden;
  }
}

.panel {
  position: relative;
  width: min(760px, 100%);
  max-height: min(88vh, 900px, 100%);
  overflow-y: auto;
  padding: 24px 22px 22px;
  border-radius: 28px;
  background: var(--paper);
  box-shadow:
    0 24px 60px rgba(61, 46, 79, 0.4),
    0 4px 14px rgba(61, 46, 79, 0.18),
    inset 0 0 0 2px rgba(255, 255, 255, 0.75);
  animation: panel-in 0.26s cubic-bezier(0.3, 1.4, 0.5, 1);
}

@keyframes panel-in {
  from {
    transform: scale(0.92) translateY(10px);
    opacity: 0;
  }
  60% {
    transform: scale(1.01) translateY(0);
    opacity: 1;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

.panel.narrow {
  width: min(460px, 100%);
}

.panel.side {
  align-self: end;
  justify-self: end;
}

.close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--paper-2);
  font-size: 1.1rem;
  z-index: 1;
}

.panel h2 {
  margin: 0 44px 14px 0;
  font-size: 1.7rem;
  font-weight: 700;
}

.panel h3 {
  margin: 18px 0 8px;
  font-size: 1.15rem;
}

.panel p {
  margin: 6px 0;
  line-height: 1.4;
}

.muted {
  color: var(--ink-soft);
  font-size: 0.95rem;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 10px;
}

.grid.wide {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.grid.sizes {
  grid-template-columns: repeat(3, 1fr);
}

.choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 78px;
  padding: 8px 4px;
  border-radius: 18px;
  background: white;
  box-shadow: 0 4px 0 var(--line);
  --shade: var(--line);
  font-size: 0.8rem;
  font-weight: 600;
  text-align: center;
  line-height: 1.1;
}

.choice img,
.choice .hair-icon {
  width: 46px;
  height: 46px;
  object-fit: contain;
}

.choice .emoji {
  font-size: 2rem;
  line-height: 1.1;
}

.choice.on {
  background: var(--select);
  box-shadow:
    0 0 0 3px var(--sun),
    0 4px 0 var(--sun-dark);
}

.choice.big-choice {
  min-height: 120px;
  font-size: 1rem;
}

.choice.big-choice .emoji {
  font-size: 2.8rem;
}

.choice small {
  font-weight: 500;
  color: var(--ink-soft);
}

.choice:disabled {
  opacity: 0.45;
  cursor: default;
}

.tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.tabs .chip.on {
  background: var(--sky);
  color: white;
  box-shadow: 0 4px 0 var(--sky-dark);
}

.swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.swatch {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 4px solid white;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
}

.swatch.on {
  box-shadow:
    0 0 0 4px var(--ink),
    0 2px 6px rgba(0, 0, 0, 0.2);
}

.row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

.row.spread {
  justify-content: space-between;
}

.code-input {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin: 16px 0;
}

.code-input input {
  width: 52px;
  height: 64px;
  border-radius: 14px;
  border: 3px solid var(--line);
  background: white;
  text-align: center;
  font: inherit;
  font-size: 2rem;
  font-weight: 700;
  color: var(--ink);
  -webkit-user-select: text;
  user-select: text;
}

.code-input input:focus {
  outline: none;
  border-color: var(--sky);
}

.big-code {
  font-size: clamp(2.6rem, 10vw, 4rem);
  font-weight: 800;
  letter-spacing: 6px;
  text-align: center;
  margin: 10px 0;
  color: var(--sky-dark);
}

/* An adventure island's camps, in its card: one row each, the free ones in
   the island's colours. */
.adventure-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 6px 0;
}

.adventure-list .camp {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 12px;
  background: rgba(123, 79, 208, 0.12);
  font-weight: 700;
}

.adventure-list .camp.free {
  background: rgba(92, 195, 242, 0.18);
}

.adventure-list .camp .muted {
  margin-left: auto;
  font-weight: 600;
}

.setting {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 2px dashed var(--line);
}

.setting:last-child {
  border-bottom: none;
}

.setting input[type='range'] {
  width: 160px;
  accent-color: var(--sky);
}

.switch {
  width: 64px;
  height: 36px;
  border-radius: 999px;
  background: #d9d2e3;
  position: relative;
  flex: none;
}

.switch::after {
  content: '';
  position: absolute;
  top: 4px;
  left: 4px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  transition: transform 0.15s ease;
}

.switch.on {
  background: var(--grass);
}

.switch.on::after {
  transform: translateX(28px);
}

.island-list {
  display: grid;
  gap: 10px;
}

.island-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-radius: 18px;
  background: white;
  box-shadow: 0 3px 0 var(--line);
}

.island-item .emoji {
  font-size: 2rem;
}

.island-item .info {
  flex: 1;
  min-width: 0;
}

.island-item .info b {
  display: block;
  font-size: 1.15rem;
  overflow-wrap: anywhere;
}

/* Korean wraps at spaces, but a long word still breaks rather than overflow. */
.island-item .info b:lang(ko) {
  word-break: keep-all;
}

/* The islands open now, under the code in Visit a friend. */
.open-section {
  margin-top: 18px;
  padding-top: 6px;
  border-top: 3px dashed var(--line);
}

.island-item .chip:disabled {
  opacity: 0.55;
}

.wrong-passcode {
  color: var(--pink-dark);
  font-weight: 700;
}

.passcode {
  letter-spacing: 3px;
}

.passcode-row {
  flex-wrap: nowrap;
  margin: -4px 0 8px;
}

.song-row {
  margin: -4px 0 8px;
}

.song-name {
  overflow-wrap: anywhere;
}

.passcode-input {
  flex: 0 0 auto;
  width: 7.5em;
  text-align: center;
  letter-spacing: 6px;
}

.sticker-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 6px;
  border-radius: 18px;
  background: white;
  text-align: center;
  font-size: 0.8rem;
  box-shadow: 0 3px 0 var(--line);
}

.sticker-card .emoji {
  font-size: 2.3rem;
}

.sticker-card.locked .emoji {
  filter: grayscale(1) opacity(0.35);
}

.sticker-card b {
  font-size: 0.9rem;
}

.shop-grid {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.gear-grid {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.shop-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 8px;
  border-radius: 18px;
  background: white;
  text-align: center;
  font-size: 0.85rem;
  box-shadow: 0 3px 0 var(--line);
}

.shop-card img {
  width: 40px;
  height: 40px;
}

.shop-card .emoji {
  font-size: 2.3rem;
}

.shop-card.locked .emoji {
  filter: grayscale(1) opacity(0.45);
}

.shop-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  margin-top: 4px;
}

.shop-buttons .chip:disabled {
  opacity: 0.45;
}

.shop-empty {
  grid-column: 1 / -1;
}

/* On a phone held upright the island's code needs the room: the shop is in
   ⭐ Stickers there. */
@media (max-width: 399px) {
  #btn-shop-hud {
    display: none;
  }
}

/* Your level (levels.js): on the title screen, at the top of the screen on
   an island with a bar filling up to the next, at the top of ⭐ Stickers,
   and on friends' name tags. */
.level-chip {
  background: var(--select);
}

/* On an island: a ring round ⭐ Stickers filling up to the next level, and
   your level on its corner. */
.level-ring {
  position: relative;
}

.level-ring::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(var(--sun-dark) var(--xp, 0%), transparent 0);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3.5px));
  pointer-events: none;
}

.level-pip {
  position: absolute;
  right: -3px;
  bottom: -3px;
  min-width: 19px;
  height: 19px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--sun);
  border: 2px solid white;
  font-size: 0.7rem;
  font-weight: 800;
  line-height: 15px;
  text-align: center;
  pointer-events: none;
}

.level-pip:empty {
  display: none;
}

.level-bar {
  display: block;
  height: 6px;
  min-width: 40px;
  border-radius: 999px;
  background: rgba(61, 46, 79, 0.15);
  overflow: hidden;
}

.level-bar > span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--sun);
  transition: width 0.4s;
}

.level-bar.wide {
  height: 12px;
  width: min(320px, 100%);
}

.level-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 18px;
  background: #fff8d6;
  text-align: center;
}

.level-big {
  font-size: 1.4rem;
}

/* Another player's level before their name: on the tag over them in the
   world, and in the ranking rows, the players list, invitations, and the
   friends on an island (ui.js levelTag). */
.tag-level {
  margin-right: 6px;
  font-size: 0.75rem;
}

.coins {
  padding: 3px 12px;
  border-radius: 999px;
  background: var(--sun);
  font-weight: 700;
}

/* A dialog's title with a button beside it, clear of the close button. */
.dialog-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 0 44px 14px 0;
}

.panel .dialog-head h2 {
  margin: 0;
}

.ranking {
  display: grid;
  gap: 8px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.rank-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px 8px 8px;
  border-radius: 18px;
  background: white;
  box-shadow: 0 3px 0 var(--line);
}

.rank-row.you {
  background: var(--select);
  box-shadow:
    0 0 0 3px var(--sun),
    0 3px 0 var(--sun-dark);
}

.rank-row .place {
  flex: none;
  width: 2.2rem;
  font-size: 1.25rem;
  font-weight: 700;
  text-align: center;
}

.rank-row .avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--c);
  font-size: 1.5rem;
}

.rank-row .who {
  flex: 1;
  min-width: 0;
  font-size: 1.1rem;
  overflow-wrap: anywhere;
}

.rank-row .who:lang(ko) {
  word-break: keep-all;
}

.rank-row .score {
  flex: none;
  font-size: 1.15rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.rank-row .score.bump {
  animation: score-pop 0.7s ease-out;
}

@keyframes score-pop {
  30% {
    transform: scale(1.3);
    color: var(--grass-dark);
  }
}

.rank-about {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
}

/* The ranking is being watched: what changes shows up as it happens. */
.live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 9px;
  border-radius: 999px;
  background: #e3f6da;
  color: var(--grass-dark);
  font-size: 0.8rem;
  font-weight: 700;
}

.live[hidden] {
  display: none;
}

.live::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--grass);
  animation: live-pulse 1.6s ease-in-out infinite;
}

@keyframes live-pulse {
  50% {
    opacity: 0.3;
  }
}

@media (prefers-reduced-motion: reduce) {
  .live::before,
  .rank-row .score.bump {
    animation: none;
  }
}

.rank-gap {
  text-align: center;
  color: var(--ink-soft);
  line-height: 0.6;
}

.rank-empty {
  padding: 8px 4px;
}

.ranking-foot {
  margin-top: 14px;
}

.ranking-foot .check-row {
  margin: 8px 0 2px;
}

/* Says something only while asking the keeper, or when it could not answer. */
.rank-note .login-note:empty {
  min-height: 0;
  margin: 0;
}

/* On a phone, the five boards in one row, each a picture over its name. */
@media (max-width: 479px) {
  .ranking-tabs {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 6px;
  }

  .ranking-tabs .chip {
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    padding: 6px 2px;
    border-radius: 16px;
    font-size: 0.72rem;
    line-height: 1.15;
  }

  .ranking-tabs .chip .emoji {
    font-size: 1.3rem;
  }
}

.help-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 10px;
}

.help-card {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: 16px;
  background: white;
}

.help-card .emoji {
  font-size: 1.8rem;
}

.steps {
  margin: 10px 0 14px;
  padding-left: 1.6em;
  font-size: 1.1rem;
  line-height: 1.5;
}

.steps li {
  padding: 3px 0;
}

kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 1px 6px;
  border-radius: 6px;
  background: var(--paper-2);
  border: 2px solid var(--line);
  font: inherit;
  font-size: 0.85rem;
  text-align: center;
}

.phrases {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.phrases .chip {
  font-size: 1rem;
}

.stickers-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}

.stickers-row button {
  font-size: 1.9rem;
  width: 54px;
  height: 54px;
  border-radius: 14px;
  background: white;
  box-shadow: 0 3px 0 var(--line);
}

.player-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
}

.player-row .who {
  flex: 1;
  font-weight: 600;
}

/* ------------------------------------------------ logins */

.login-form {
  margin-top: 6px;
}

.password-box {
  display: block;
  margin: 12px 0;
}

.password-box > span:first-child {
  display: block;
  margin-bottom: 6px;
  font-weight: 700;
}

.password-box .row {
  flex-wrap: nowrap;
}

/* 16px or more, or an iPhone zooms in on the box. */
.text-input {
  flex: 1;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 14px;
  border: 3px solid var(--line);
  background: white;
  font: inherit;
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--ink);
  -webkit-user-select: text;
  user-select: text;
}

.text-input:focus {
  outline: none;
  border-color: var(--sky);
}

.chip.eye {
  flex: none;
  padding: 10px 12px;
}

.name-row {
  flex-wrap: nowrap;
}

.panel h3.name-label {
  margin-top: 4px;
}

.same-row {
  margin: 10px 0 0;
}

.name-input {
  font-size: 1.3rem;
  font-weight: 700;
}

.check-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: -2px 0 6px;
  font-weight: 600;
}

.check-row input {
  width: 22px;
  height: 22px;
  accent-color: var(--grass);
}

.login-answers {
  display: grid;
  gap: 10px;
  margin-top: 12px;
}

.login-answers .chip {
  justify-content: center;
}

/* There for password managers, not to be seen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.known-players .emoji {
  font-size: 1.3rem;
}

.login-note {
  min-height: 1.4em;
  font-weight: 600;
}

.login-note.warn {
  color: var(--pink-dark);
}

.login-note.good {
  color: var(--grass-dark);
}

.login-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 2px dashed var(--line);
}

/* ------------------------------------------------ loading */

.loading {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: linear-gradient(#8fd3ff, #c9f0ff);
  z-index: 40;
  text-align: center;
  padding: 20px;
}

.loading p {
  font-size: 1.3rem;
  font-weight: 600;
  margin: 0;
}

.spinner {
  font-size: 3.5rem;
  animation: hop 0.8s ease-in-out infinite;
}

@keyframes hop {
  0%, 100% { transform: translateY(0) rotate(0); }
  50% { transform: translateY(-24px) rotate(15deg); }
}

.noscript {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 1.4rem;
}

/* ------------------------------------------------ small screens */

@media (max-width: 760px), (max-height: 560px) {
  :root {
    --tool: 48px;
    --slot: 46px;
    --talk: 50px;
    --touch: 50px;
  }

  .tool {
    font-size: 1.4rem;
    border-radius: 14px;
  }

  .tool small,
  .toybox .label {
    display: none;
  }

  .island-name {
    font-size: 0.95rem;
  }

  .round.big-round {
    font-size: 1.45rem;
  }

  .round.touch {
    font-size: 1.35rem;
  }

  .round {
    width: 40px;
    height: 40px;
    font-size: 1.1rem;
  }

  #talk {
    top: auto;
    transform: none;
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + 220px);
    flex-direction: row;
  }

  /* On computers, over the right end of the hotbar, and of the basket over it
     as that fills up: --bottom-height is the height of both together, kept by
     the UI. */
  body:not(.touch) #talk {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + max(80px, var(--bottom-height, 60px) + 10px));
  }

  .panel {
    padding: 20px 14px 16px;
    border-radius: 22px;
  }

  .panel h2 {
    font-size: 1.35rem;
  }

  .friends {
    display: none;
  }

  .code-input input {
    width: 42px;
    height: 56px;
    font-size: 1.6rem;
  }

  /* At the right edge, over the hotbar and the basket, and over the talk
     buttons' place by the hotbar on computers. */
  .chatlog {
    right: max(10px, env(safe-area-inset-right));
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + max(var(--bottom-height, 60px), 80px + var(--talk)) + 10px);
    max-width: 60vw;
  }

  /* On computers the talk buttons rise with the basket, and chat lines with
     them. No more specific than .chatlog (:where counts for nothing), so short
     and upright screens below still place it as they do. */
  :where(body:not(.touch)) .chatlog {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + max(80px, var(--bottom-height, 60px) + 10px) + var(--talk) + 10px);
  }
}

/* Narrow phones held upright: the island's name and code need the room,
   so the top bar packs tighter and full screen is in Settings instead. */
@media (max-width: 479px) {
  #btn-fullscreen-hud {
    display: none;
  }

  #topbar {
    gap: 6px;
  }

  .island-badge {
    padding: 6px 10px;
    border-radius: 16px;
  }

  .island-name {
    max-width: none;
  }

  .top-buttons {
    gap: 5px;
  }

  /* The weather sits on the sun or moon instead of beside it. */
  .clock {
    position: relative;
    font-size: 1.35rem;
  }

  .clock .weather {
    position: absolute;
    right: -0.15em;
    bottom: -0.35em;
    font-size: 0.62em;
  }
}

/* The narrowest phones (320 px): the code still needs about 20px more, so the
   clock goes. It is the only thing in the top bar that is not a button, and the
   sky shows the time of day and the weather too. */
@media (max-width: 359px) {
  .clock {
    display: none;
  }
}

/* Narrow screens have no room for a connection message beside the island's
   name, so it gets a spot of its own: here under the top bar, beside the
   toolbar and clear of the little map. Toasts make room under it
   (--status-room is set by the UI). Taps go through it to the island. */
@media (max-width: 760px), (max-aspect-ratio: 3/4) {
  #topbar > .status {
    position: fixed;
    top: calc(max(10px, env(safe-area-inset-top)) + 58px);
    left: calc(max(10px, env(safe-area-inset-left)) + var(--tool) + 26px);
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(10px, env(safe-area-inset-right)) - var(--tool) - var(--map) - 36px);
    -webkit-line-clamp: none;
    pointer-events: none;
  }

  #toasts {
    top: calc(max(64px, calc(env(safe-area-inset-top) + 58px)) + var(--status-room, 0px));
  }
}

/* Screens a little too short for the column of tools, such as a small
   laptop's: centred, its 470px need 80px clear below it for the hotbar, and
   so as much again above, 630px in all; any less and it reaches over the
   hotbar and the island name. Here the tools go in a row under the island
   name instead, still full size, with their options in a row under them.
   Narrower screens have smaller tools, which fit the column, and short
   screens (next) restyle the row. */
@media (min-width: 761px) and (max-height: 629px) {
  #toolbar {
    flex-direction: row;
    top: calc(max(10px, env(safe-area-inset-top)) + 58px);
    transform: none;
  }

  #toolopts {
    top: calc(max(10px, env(safe-area-inset-top)) + 58px + var(--tool) + 26px);
    left: max(10px, env(safe-area-inset-left));
    transform: none;
    flex-direction: row;
  }

  .opt-group {
    flex-direction: row;
  }

  /* Halfway down the right side, the talk buttons reach into the touch
     buttons' box below 606px (by 22.5px at 1000x561), and the box takes the
     touches on the bottom of the emotes button. The touch buttons go down
     into the corner instead, as on short screens: the hotbar held sideways
     already stops short of them there. */
  body.touch #touch-buttons {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + 10px);
  }
}

/* Touch screens a little taller still: the thumbstick in the bottom-left
   corner reaches up into the bottom of the column below 758px (by 7px at
   1133x744, an iPad mini held sideways, and 29px at 1280x700), so the tools go
   in the row there too. */
@media (min-width: 761px) and (min-height: 630px) and (max-height: 757px) {
  body.touch #toolbar {
    flex-direction: row;
    top: calc(max(10px, env(safe-area-inset-top)) + 58px);
    transform: none;
  }

  body.touch #toolopts {
    top: calc(max(10px, env(safe-area-inset-top)) + 58px + var(--tool) + 26px);
    left: max(10px, env(safe-area-inset-left));
    transform: none;
    flex-direction: row;
  }

  body.touch .opt-group {
    flex-direction: row;
  }
}

/* Narrow touch screens held sideways: the column of smaller tools, 400px
   tall, reaches the thumbstick below 688px (by 44px at 720x600 and 24px at
   760x640), so the tools go in the row there too, with their options under
   them. The row covers the spot beside the column where a connection message
   goes, so the message goes under the options instead, as on short screens:
   the toasts stay above it, and chat lines go under it. The little map
   shrinks to stay 10px clear of the row, which ends 410px from the left,
   down to 108px at 538px wide. Narrower screens held sideways, from 3:4 to
   square, keep the column: the row would reach the map there. */
@media (min-width: 538px) and (max-width: 760px) and (min-height: 561px) and (max-height: 687px) {
  body.touch {
    --map: clamp(108px, min(50vh - 142px, 100vw - 430px), 156px);
  }

  body.touch #toolbar {
    flex-direction: row;
    top: calc(max(10px, env(safe-area-inset-top)) + 58px);
    transform: none;
  }

  body.touch #toolopts {
    top: calc(max(10px, env(safe-area-inset-top)) + 58px + var(--tool) + 26px);
    left: max(10px, env(safe-area-inset-left));
    transform: none;
    flex-direction: row;
  }

  body.touch .opt-group {
    flex-direction: row;
  }

  /* 10px under the options, which are 52px tall. */
  body.touch #topbar > .status {
    top: calc(max(10px, env(safe-area-inset-top)) + 58px + var(--tool) + 88px);
    left: max(10px, env(safe-area-inset-left));
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(10px, env(safe-area-inset-right)) - var(--map) - 10px);
  }

  body.touch #toasts {
    top: max(64px, calc(env(safe-area-inset-top) + 58px));
  }

  /* Under the little map, and under the options or a message, whichever is
     lower: --status-room is its height and 8px, kept by the UI. */
  body.touch .chatlog {
    top: calc(max(10px, env(safe-area-inset-top)) + 68px + max(var(--map), var(--tool) + 78px + var(--status-room, 0px)));
  }
}

/* Short screens (phones held sideways): tools in a row under the island name. */
@media (max-height: 560px) {
  :root {
    --tool: 40px;
    --slot: 42px;
    --map: clamp(96px, 28vh, 124px);
    --stick: 112px;
  }

  #toolbar {
    flex-direction: row;
    top: calc(max(8px, env(safe-area-inset-top)) + 58px);
    transform: none;
    gap: 4px;
    padding: 5px;
    border-radius: 16px;
  }

  .tool {
    font-size: 1.2rem;
    border-radius: 12px;
  }

  #toolopts {
    top: calc(max(8px, env(safe-area-inset-top)) + 58px + var(--tool) + 20px);
    left: max(10px, env(safe-area-inset-left));
    transform: none;
    flex-direction: row;
  }

  .opt-group {
    flex-direction: row;
  }

  .pill {
    min-width: 38px;
    height: 34px;
  }

  #talk {
    top: calc(max(8px, env(safe-area-inset-top)) + 58px);
    transform: none;
    bottom: auto !important;
    flex-direction: column !important;
  }

  /* Beside the talk buttons, which fill the right edge from there down to the jump buttons. */
  #minimap {
    top: calc(max(8px, env(safe-area-inset-top)) + 58px);
    right: calc(max(10px, env(safe-area-inset-right)) + var(--talk) + 10px);
  }

  body.touch #touch-buttons {
    bottom: calc(max(8px, env(safe-area-inset-bottom)) + 10px);
  }

  /* Under the little map and a row of tool options (46px), and left of the
     talk buttons beside the map. */
  .chatlog {
    top: calc(max(8px, env(safe-area-inset-top)) + 68px + max(var(--map), var(--tool) + 66px));
    right: calc(max(10px, env(safe-area-inset-right)) + var(--talk) + 10px);
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 56px) + 10px);
  }

  .big {
    padding: 10px 18px;
    font-size: 1.2rem;
  }

  .logo {
    font-size: clamp(2.4rem, 9vh, 4rem);
  }

  .tagline {
    font-size: 1rem;
  }
}

/* Narrow and held sideways: a connection message goes under the tool
   options, clear of the little map; the toasts stay above it. */
@media (max-width: 760px) and (max-height: 560px) {
  #topbar > .status {
    top: calc(max(8px, env(safe-area-inset-top)) + 58px + var(--tool) + 72px);
    left: max(10px, env(safe-area-inset-left));
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(10px, env(safe-area-inset-right)) - var(--talk) - var(--map) - 20px);
  }

  #toasts {
    top: max(64px, calc(env(safe-area-inset-top) + 58px));
  }

  /* Chat lines keep under the message too: --status-room is its height and 8px, kept by the UI. */
  .chatlog {
    top: calc(max(8px, env(safe-area-inset-top)) + 68px + max(var(--map), var(--tool) + 66px, var(--tool) + 62px + var(--status-room, 0px)));
  }
}

/* Narrow and held sideways, under 400px tall: the thumbstick can reach up
   into the message, at 568x320 even the short one. It is drawn under the
   buttons and the message, so the message covers the top of its ring instead
   of the ring crossing its words, as on the shortest upright screens. */
@media (max-width: 760px) and (max-height: 399px) {
  #joystick {
    z-index: auto;
  }
}

/* Under 340px tall, between the tool options and the basket (in one row here,
   see below) there is no room for the longest message in two lines of the
   usual type: at 568x320 it would reach 7px into the basket. Here it is
   smaller, and clear of it. */
@media (max-width: 760px) and (max-height: 339px) {
  #topbar > .status {
    font-size: 0.75rem;
    line-height: 1.25;
    border-width: 5px 10px;
  }
}

/* Touch screens held sideways: the hotbar stays between the thumbstick and
   the jump buttons, scrolling if it has to, so nothing covers anything.
   Sideways is anything not upright: (min-aspect-ratio: 3/4) would also match
   exactly 3:4, like 375x500 and most iPads held upright, where the buttons
   are above the hotbar. (aspect-ratio > 3/4) would do, but Safari before
   16.4, as on iPads stuck on iPadOS 15, never matches it. */
@media not all and (max-aspect-ratio: 3/4) {
  body.touch #bottom {
    max-width: calc(100vw - 340px);
  }

  /* With the bop button showing too, left of the touch buttons, it keeps as
     much further from the right, and moves over that way to make room. */
  body.touch:has(#btn-attack:not([hidden])) #bottom {
    left: calc(50% - (var(--touch) + 10px) / 2);
    max-width: calc(100vw - 350px - var(--touch));
  }

  /* Chat lines keep between them too, 10px clear of either. */
  body.touch .chatlog {
    left: calc(max(14px, env(safe-area-inset-left)) + 16px + var(--stick));
    right: calc(max(14px, env(safe-area-inset-right)) + var(--touch) + 98px);
    margin-left: auto;
  }

  /* And clear of the bop button, left of the others, while it shows. */
  body.touch:has(#btn-attack:not([hidden])) .chatlog {
    right: calc(max(14px, env(safe-area-inset-right)) + 2 * var(--touch) + 108px);
  }
}

/* Tall, narrow screens (phones held upright, and iPads, most of them exactly
   3:4 that way): tools go in a row along the top. */
@media (max-aspect-ratio: 3/4) {
  #toolbar {
    flex-direction: row;
    top: calc(max(8px, env(safe-area-inset-top)) + 62px);
    left: 50%;
    transform: translateX(-50%);
    padding: 5px;
    gap: 5px;
    border-radius: 18px;
  }

  /* It stops 10px short of the talk buttons beside it, and a group with no room
     left there wraps onto a second row. The box is wider than its groups, so
     touches pass through it to the island. */
  #toolopts {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px);
    left: max(10px, env(safe-area-inset-left));
    right: calc(max(10px, env(safe-area-inset-right)) + 2 * var(--talk) + 20px);
    transform: none;
    flex-direction: row;
    flex-wrap: wrap;
    pointer-events: none;
  }

  #toolopts > * {
    pointer-events: auto;
  }

  .opt-group {
    flex-direction: row;
  }

  #talk {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px);
    bottom: auto !important;
    transform: none;
    flex-direction: row !important;
  }

  :root {
    --map: clamp(96px, min(30vw, 100vh - 440px), 156px);
  }

  #minimap {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + var(--talk) + 12px);
    right: max(10px, env(safe-area-inset-right));
  }

  /* Above the hotbar and the basket over it, however many rows that wraps
     to: --bottom-height is the height of both together, kept by the UI. */
  body.touch #touch-buttons {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 24px);
  }

  #joystick {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 34px);
  }

  /* A connection message: under the tool options, beside the little map. */
  #topbar > .status {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + var(--talk) + 12px);
    left: max(10px, env(safe-area-inset-left));
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(10px, env(safe-area-inset-right)) - var(--map) - 10px);
  }

  #toasts {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 90px + var(--status-room, 0px));
  }

  /* Chat lines go on the left, under the tool options and a connection
     message there, and stand on the hotbar and the basket, or on touch screens
     on the thumbstick: the right has the little map, with the touch buttons
     not far under it, and on phones there is little room left between them. */
  .chatlog {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + var(--talk) + 12px + var(--status-room, 0px));
    left: max(10px, env(safe-area-inset-left));
    right: auto;
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 10px);
    align-items: flex-start;
  }

  body.touch .chatlog {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 44px + var(--stick));
  }
}

/* Upright phones with Hills picked: its two groups of tool options take two
   rows, so a connection message goes a row further down, and toasts and chat
   lines with it. */
@media (max-aspect-ratio: 3/4) and (max-width: 479px) {
  #hud:has(> #toolopts > :nth-child(2)) > #topbar > .status {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + var(--talk) + 72px);
  }

  #hud:has(> #toolopts > :nth-child(2)) > .chatlog {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + var(--talk) + 72px + var(--status-room, 0px));
  }

  #hud:has(> #toolopts > :nth-child(2)):has(#status:not(:empty)) ~ #toasts {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 150px + var(--status-room, 0px));
  }
}

/* Seven 48px tools are 376px wide: on narrower upright phones they shrink, and
   close up, to stay 10px from both edges. Short screens already have 40px tools. */
@media (max-aspect-ratio: 3/4) and (max-width: 379px) and (min-height: 561px) {
  :root {
    --tool: 44px;
  }

  #toolbar {
    gap: 4px;
    padding: 5px 4px;
  }
}

@media (max-aspect-ratio: 3/4) and (max-width: 359px) {
  :root {
    --tool: 40px;
  }

  #toolbar {
    gap: 2px;
    padding: 5px 4px;
  }

  /* No room beside the touch buttons for the bop button, left of them, where
     the thumbstick is: it goes over the jump button instead, in the room under
     the talk buttons. */
  #touch-buttons:has(> #btn-attack:not([hidden])) {
    grid-template-areas:
      'down jump'
      'fly jump';
  }

  #btn-attack {
    position: absolute;
    right: calc((78px - var(--touch)) / 2);
    bottom: 88px;
  }
}

/* Upright screens under 640px tall have no room for the basket to grow: a
   second row of treasures would push the touch buttons and the thumbstick
   into the little map, Hills' options or a connection message. Nor do narrow
   screens held sideways under 400px tall: between the thumbstick and the jump
   buttons a full basket wraps into two rows, three at 568px wide, and grows
   into a message under the tool options, or into the options themselves;
   from 400px they fit under the longest message. Here it keeps to one row,
   scrolling sideways like the hotbar under it. Its padding keeps the pills'
   shadows inside it, where scrolling would cut them off, and its margins
   take that room back. */
@media (max-aspect-ratio: 3/4) and (max-height: 639px), (max-width: 760px) and (max-height: 399px) {
  .basket {
    flex-wrap: nowrap;
    justify-content: flex-start;
    max-width: calc(100% + 12px);
    padding: 4px 6px 8px;
    margin: -4px -6px -8px;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .basket button {
    flex: none;
  }
}

/* Upright, the touch buttons and the thumbstick stand closer on it, and so
   chat lines on the thumbstick. */
@media (max-aspect-ratio: 3/4) and (max-height: 639px) {
  body:has(#basket:not(:empty)) #touch-buttons,
  body:has(#basket:not(:empty)) #joystick {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 10px);
  }

  body.touch:has(#basket:not(:empty)) .chatlog {
    bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 60px) + 20px + var(--stick));
  }
}

/* An upright screen this short has no room for the map between the buttons,
   nor for a connection message between the talk buttons and the thumbstick in
   the usual type: here it is smaller, so the longest message takes two lines
   across the screen. */
@media (max-aspect-ratio: 3/4) and (max-height: 520px) {
  #minimap {
    display: none;
  }

  #topbar > .status {
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(10px, env(safe-area-inset-right)));
    font-size: 0.75rem;
    line-height: 1.25;
    border-width: 5px 10px;
  }

  /* Hills' second group of options goes under the talk buttons rather than
     under the first group, so that a message can go under the first group, a
     row higher than on taller phones: further down, the thumbstick and the
     touch buttons leave no room for it. */
  #toolopts {
    right: max(10px, env(safe-area-inset-right));
    flex-direction: column;
    align-items: flex-start;
  }

  #toolopts > :nth-child(2) {
    align-self: flex-end;
  }

  /* Level with the second group, 8px under the first (46px tall), and as
     wide as the touch buttons below it leave it. Chat lines go under it, as
     wide, clear of the second group. */
  #hud:has(> #toolopts > :nth-child(2)) > #topbar > .status {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + 54px);
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(14px, env(safe-area-inset-right)) - var(--touch) - 10px - 78px - 4px);
  }

  #hud:has(> #toolopts > :nth-child(2)) > .chatlog {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 22px + 54px + var(--status-room, 0px));
    max-width: calc(100% - max(10px, env(safe-area-inset-left)) - max(14px, env(safe-area-inset-right)) - var(--touch) - 10px - 78px - 4px);
  }

  #hud:has(> #toolopts > :nth-child(2)):has(#status:not(:empty)) ~ #toasts {
    top: calc(max(8px, env(safe-area-inset-top)) + 62px + var(--tool) + 82px + var(--status-room, 0px));
  }

  /* With Hills, the longest message still reaches the top of the thumbstick's
     ring. The thumbstick is drawn under the buttons and the message, so the
     message covers the edge of the ring instead of the ring crossing its words. */
  #joystick {
    z-index: auto;
  }
}

@media (max-width: 760px), (max-height: 560px) {
  #toasts {
    width: min(86vw, 440px);
  }

  .toast {
    font-size: 0.92rem;
    padding: 8px 14px;
  }

  .toast .icon {
    font-size: 1.3rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .logo span,
  .spinner {
    animation: none;
  }
}

/* ------------------------------------------------ the video arcade */

/* The window a machine's game plays in: how it is going up top, the holes
   or the cards in the middle, who is at the machine, and Play. */
.arcade-status {
  min-height: 1.6em;
  margin: 2px 0 12px;
  font-size: 1.25rem;
  font-weight: 700;
  text-align: center;
}

.arcade-grid {
  display: grid;
  gap: 10px;
  justify-content: center;
  margin: 0 auto;
}

.arcade-grid.holes {
  grid-template-columns: repeat(3, minmax(64px, 92px));
}

.arcade-grid.cards {
  grid-template-columns: repeat(4, minmax(56px, 78px));
}

/* The holes the blobs pop out of, each a dark bowl. */
.hole {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border: none;
  border-radius: 50% / 46%;
  background: radial-gradient(ellipse at 50% 42%, #4c3d66 0 58%, #3a2c50 68%, #2d2242);
  box-shadow:
    inset 0 6px 10px rgba(0, 0, 0, 0.45),
    0 3px 0 rgba(0, 0, 0, 0.12);
  font-size: clamp(1.6rem, 6vw, 2.4rem);
  line-height: 1;
  cursor: pointer;
}

.hole:disabled {
  cursor: default;
}

/* A blob springing up out of its hole (a golden one with it). */
.hole.up,
.hole.gold {
  animation: arcade-pop 0.18s cubic-bezier(0.3, 1.6, 0.5, 1);
}

.hole:not(:disabled):active {
  transform: translateY(2px);
}

@keyframes arcade-pop {
  from {
    transform: scale(0.4);
  }
}

/* The cards of Picture Pairs: face down with a patterned back and a ?,
   or face up in white; a pair found keeps its outline of grass. */
.card {
  display: grid;
  place-items: center;
  aspect-ratio: 3 / 4;
  border: none;
  border-radius: 12px;
  background: repeating-linear-gradient(45deg, #8c5bd6 0 8px, #7d50c8 8px 16px);
  box-shadow: 0 4px 0 #4a3a86, 0 4px 10px rgba(61, 46, 79, 0.18);
  color: #fffaf0;
  font-size: clamp(1.4rem, 5vw, 2rem);
  line-height: 1;
  cursor: pointer;
}

.card:disabled {
  cursor: default;
}

.card.up,
.card.won {
  background: #fffaf0;
  box-shadow: 0 4px 0 var(--line), 0 4px 10px rgba(61, 46, 79, 0.18);
  color: var(--ink);
}

.card.won {
  outline: 3px solid var(--grass);
  outline-offset: -3px;
}

.card:not(:disabled):active {
  transform: translateY(2px);
  box-shadow: 0 2px 0 #4a3a86;
}

.arcade-players {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin: 14px 0 4px;
}

.arc-player {
  padding: 6px 12px;
  font-size: 0.95rem;
}

.arc-player.turn {
  background: var(--sun);
}

.arcade-play {
  max-width: 340px;
  margin: 10px auto 0;
}

.arcade-how {
  text-align: center;
}

/* ------------------------------------------------ extra-credit quizzes */

/* The 🎓 by a conquered island's flag, there to be tapped (the overlays it
   floats in let nothing else take a tap). */
.adv-tag.quiz {
  pointer-events: auto;
  cursor: pointer;
  background: rgba(255, 246, 214, 0.95);
}

@media (hover: hover) {
  .adv-tag.quiz:hover {
    filter: brightness(1.03);
  }
}

/* The two quizzes to pick from, a name and what each pays in one big button. */
.quiz-level {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  line-height: 1.2;
}

.quiz-sub {
  font-size: 0.8rem;
  font-weight: 600;
  opacity: 0.85;
  text-shadow: none;
}

/* A quiz's window: how far it has gone, the question, and its answers in a
   column of buttons — one column, for the answers can be a sentence long. */
.quiz-status {
  min-height: 1.6em;
  margin: 2px 0 12px;
  font-size: 1.1rem;
  font-weight: 700;
  text-align: center;
}

.quiz-question {
  margin: 6px 0 14px;
  font-size: 1.3rem;
  font-weight: 700;
  text-align: center;
}

.quiz-answers {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.quiz-answer {
  padding: 13px 18px;
  border: 2px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--paper);
  box-shadow: 0 4px 0 var(--line);
  color: var(--ink);
  font-size: 1.15rem;
  font-weight: 700;
  cursor: pointer;
  transition:
    transform 0.08s ease,
    box-shadow 0.08s ease,
    filter 0.15s ease;
}

@media (hover: hover) {
  .quiz-answer:not(:disabled):hover {
    filter: brightness(1.03);
    transform: translateY(-1px);
  }
}

.quiz-answer:not(:disabled):active {
  transform: translateY(2px);
  box-shadow: 0 2px 0 var(--line);
}

.quiz-answer:disabled {
  cursor: default;
}

/* An answer given: the right one outlined in grass, a wrong pick in pink,
   the rest faded back. */
.quiz-answer.right {
  outline: 4px solid var(--grass);
}

.quiz-answer.wrong {
  outline: 4px solid var(--pink-dark);
}

.quiz-answer.dim {
  opacity: 0.55;
}

.quiz-verdict {
  margin: 12px 0;
  font-weight: 700;
  text-align: center;
}

/* The end of a quiz: the score, and the extra credit it earned. */
.quiz-result {
  margin: 10px 0 4px;
  font-size: 1.6rem;
  font-weight: 800;
  text-align: center;
}

.quiz-credit {
  margin: 0 0 18px;
  font-weight: 700;
  text-align: center;
}


/* A conquered stage of the shared isle: the countdown to the next stage,
   standing on the bar of HP and the hotbar (clear of the toasts up top),
   which a tap cuts short. */
.ride-button.next-stage {
  top: auto;
  left: 50%;
  bottom: calc(max(10px, env(safe-area-inset-bottom)) + var(--bottom-height, 70px) + 16px);
  transform: translateX(-50%);
  background: #ffd36e;
}

.next-stage .go {
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.75);
  font-size: 0.95rem;
}

/* Telling of a problem (ui.js reportDialog). */
.report-text {
  display: block;
  width: 100%;
  margin-top: 8px;
  resize: vertical;
  font-size: 1.05rem;
  font-weight: 500;
}

.report-picture {
  border-bottom: none;
}

.report-shot {
  flex: none;
  width: 112px;
  max-height: 84px;
  object-fit: cover;
  border-radius: 10px;
  border: 3px solid var(--line);
  transition: opacity 0.2s;
}

.report-shot.off {
  opacity: 0.3;
}

.report-picture > div {
  flex: 1;
  min-width: 0;
}

.panel .report-button {
  display: block;
  margin: 12px auto 0;
}
