/* Zeynep's Magic Pets — shared UI components.

   Loaded on EVERY page, after tokens.css and (on the story) before style.css,
   so the story's own stylesheet can still override anything for itself.

   These blocks were MOVED here from the story's style.css so the game pages
   get the same sheets, buttons, chat panel and presence chips. The story's
   markup keeps its ids, so the original id selectors are kept working here
   alongside the class equivalents the shared JS templates use (.zmp-*) —
   the story must render pixel-identically until it too moves onto the shared
   modules. */

/* The `hidden` attribute is only a UA `display:none`; any author display rule
   silently beats it. tokens.css already settles this, but this sheet styles
   panels whose whole lifecycle is the hidden attribute, so it carries its own
   copy rather than depending on load order. */
[hidden] { display: none !important; }

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

.icon-btn {
  width: 36px; height: 36px;
  font-size: 16px;
  border: 1px solid var(--stroke);
  border-radius: 11px;
  background: rgba(255, 255, 255, .07);
  color: var(--paper);
  cursor: pointer;
  transition: transform .12s ease, background .12s ease, opacity .12s ease;
}
.icon-btn:hover { background: rgba(255, 255, 255, .15); }
.icon-btn:active { transform: scale(.92); }
.icon-btn.off { opacity: .38; }
.icon-btn[hidden] { display: none; }

/* The gold action button. In the story this was written as two rules shared
   with #buttons button; combined here so the standalone class carries the
   same computed style on any page. */
.primary {
  font-family: var(--font);
  font-size: 15.5px; font-weight: 700;
  padding: 12px 20px;
  min-height: 48px;                 /* comfortable thumb target */
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, .2);
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  color: #3a2600;
  cursor: pointer;
  transition: transform .12s ease, filter .12s ease;
  box-shadow: 0 6px 18px rgba(224, 154, 28, .35);
}
.primary:hover { filter: brightness(1.07); }
.primary:active { transform: translateY(1px) scale(.98); }
.primary.wide { width: 100%; }
.primary:disabled {
  opacity: .45;
  cursor: not-allowed;
  filter: grayscale(.4);
}

.ghost {
  width: 100%;
  margin-top: 8px;
  padding: 11px 18px;
  min-height: 44px;
  font-family: var(--font);
  font-size: 14px;
  color: var(--paper);
  background: transparent;
  border: 1px solid var(--stroke);
  border-radius: 14px;
  cursor: pointer;
  opacity: .7;
}
.ghost:hover { opacity: 1; background: rgba(255, 255, 255, .06); }

/* ----------------------------------------------------------------- sheets */

.sheet {
  width: min(520px, 100%);
  max-height: min(82dvh, 640px);
  display: flex; flex-direction: column;
  border-radius: 22px;
  border: 1px solid var(--stroke);
  background: linear-gradient(180deg, var(--plum-700), var(--plum-800));
  box-shadow: var(--shadow);
  overflow: hidden;
}

.sheet header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 15px 17px;
  border-bottom: 1px solid var(--stroke);
}
.sheet header h2 { margin: 0; font-size: 19px; }

.sheet-body { padding: 14px 17px; overflow-y: auto; display: grid; gap: 16px; }

.field { display: grid; gap: 7px; font-size: 13.5px; }
.field > span { opacity: .85; }
.field small { font-size: 11px; opacity: .5; }

.field select {
  font-family: var(--font);
  font-size: 15px;
  padding: 11px 12px;
  min-height: 46px;
  width: 100%;
  border-radius: 12px;
  border: 1px solid var(--stroke);
  /* A light field regardless of page, so the text on it is the literal dark
     the story's --ink resolves to — the game pages redefine --ink as light. */
  background: rgba(255, 255, 255, .96);
  color: #241a33;
}

.field input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .18);
  outline: none;
}
.field input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  border: 2px solid rgba(255, 255, 255, .4);
  box-shadow: 0 3px 8px rgba(0, 0, 0, .4);
  cursor: pointer;
}
.field input[type="range"]::-moz-range-thumb {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--gold);
  border: 2px solid rgba(255, 255, 255, .4);
  cursor: pointer;
}

.switch {
  display: flex; align-items: center; gap: 12px;
  font-size: 14.5px;
  min-height: 44px;
  cursor: pointer;
}
.switch input { width: 22px; height: 22px; accent-color: var(--gold-deep); flex: none; }

.sheet-foot {
  margin: 0;
  padding: 12px 17px calc(14px + env(safe-area-inset-bottom));
  font-size: 11.5px; opacity: .5; text-align: center;
  border-top: 1px solid var(--stroke);
}

.note {
  margin: 0;
  padding: 11px 13px;
  font-size: 13px;
  line-height: 1.45;
  border-radius: 12px;
  background: rgba(255, 194, 71, .1);
  border: 1px solid rgba(255, 194, 71, .28);
}
.note[hidden] { display: none; }

.note-quiet {
  margin: 2px 0 0;
  font-size: 12px;
  opacity: .55;
  text-align: center;
}

/* The full-screen veil behind the name sheet. The story's markup keeps its
   #nameSheet id; the shared identity module renders .zmp-sheet-veil. */
#nameSheet, .zmp-sheet-veil {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  padding: 18px;
  background: rgba(10, 6, 20, .82);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
#nameSheet[hidden], .zmp-sheet-veil[hidden] { display: none; }
/* The story's rule was `#nameInput { … }`; the shared sheet's input carries a
   class instead, because the pet game has an unrelated #nameInput of its own. */
.zmp-name-input { text-align: center; font-size: 18px; }

/* Bubbles and toasts pop into place; used by chips and welcomes below. The
   story defines the same frames for its own use — they are identical. */
@keyframes pop { from { transform: scale(.9); opacity: 0 } to { transform: scale(1); opacity: 1 } }

/* --- who is playing ------------------------------------------------------ */

.player-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  /* Shrinks rather than pushing the controls off the screen, but only after the
     title has given up its space. The name truncates; it never collides. */
  flex: 0 1 auto;
  min-width: 0;
  margin-left: auto;
  margin-right: 6px;
  padding: 5px 12px 5px 8px;
  max-width: 46vw;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 700;
  color: var(--paper);
  background: rgba(255, 194, 71, .14);
  border: 1px solid rgba(255, 194, 71, .38);
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background .12s ease, transform .12s ease;
}
.player-chip[hidden] { display: none; }
.player-chip:hover { background: rgba(255, 194, 71, .24); }
.player-chip:active { transform: scale(.95); }
.player-avatar { font-size: 15px; line-height: 1; flex: none; }
/* The name is the part that gives — the avatar must not be squashed into it. */
#playerName { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- who else is playing --------------------------------------------------
   Its own bar under the picture rather than squeezed into the top bar: names
   wrap onto as many lines as they need, and it simply is not there when nobody
   else is around. The story's bar keeps its #othersBar id; the shared module
   renders .zmp-others. */

#othersBar, .zmp-others {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px 8px;
  padding: 0 0 8px;
}
#othersBar[hidden], .zmp-others[hidden] { display: none; }

.others-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  opacity: .62;
  white-space: nowrap;
}

.others-list { display: contents; }

.other-name {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  font-size: 13px;
  font-weight: 700;
  color: #cdf5e2;
  background: rgba(79, 209, 165, .15);
  border: 1px solid rgba(79, 209, 165, .42);
  border-radius: 999px;
  white-space: nowrap;
  animation: pop .25s ease;
}
.other-name small { font-size: 10.5px; font-weight: 600; opacity: .65; }

/* Shared chips are painted per person by paintWho(); the story's own bar sets
   no --who variables and keeps its original green through the fallbacks. */
.other-name {
  color: var(--who, #cdf5e2);
  background: var(--who-soft, rgba(79, 209, 165, .15));
  border-color: var(--who-line, rgba(79, 209, 165, .42));
}

.others-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #4fd1a5;
  animation: livedot 2s ease-out infinite;
  flex: none;
}
@keyframes livedot {
  0%   { box-shadow: 0 0 0 0 rgba(79, 209, 165, .6) }
  70%  { box-shadow: 0 0 0 7px rgba(79, 209, 165, 0) }
  100% { box-shadow: 0 0 0 0 rgba(79, 209, 165, 0) }
}

@media (max-width: 460px) {
  #othersBar, .zmp-others { padding: 0 0 6px; gap: 5px 6px; }
  .others-label { font-size: 11px; }
  .other-name { font-size: 12px; padding: 3px 9px; }
}

/* Landscape puts the story in a side column; the bar sits inside it, so it
   only needs to stop centring itself. */
@media (min-aspect-ratio: 1/1) and (max-height: 600px) {
  #othersBar { justify-content: flex-start; padding: 0 0 4px; }
}

/* The chapter or page another player is on: icon only, so a roomful of players
   still all fit. Hovering a chip gives it in full. */
.other-name small {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 11.5px; font-weight: 700;
  opacity: .9;
  padding-left: 3px;
  border-left: 1px solid rgba(79, 209, 165, .35);
}

/* With many players the bar scrolls sideways rather than eating the screen. */
#othersBar, .zmp-others {
  max-height: 4.6em;
  overflow-y: auto;
  scrollbar-width: thin;
}

/* Your own chip, so the bar always answers "who is playing" even alone. */
.other-name.is-you {
  color: #ffe9a8;
  background: rgba(255, 194, 71, .16);
  border-color: rgba(255, 194, 71, .45);
}
.other-name.is-you small { border-left-color: rgba(255, 194, 71, .38); }
.you-tag {
  margin-left: 5px;
  padding: 1px 6px;
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: #3a2600;
  background: var(--gold);
  border-radius: 999px;
}
.alone-note {
  font-size: 12px;
  opacity: .5;
  font-style: italic;
  white-space: nowrap;
}

/* --- chat ---------------------------------------------------------------- */

.chat-badge {
  position: absolute;
  top: -3px; right: -3px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  font-size: 10px; font-weight: 700; line-height: 16px;
  color: #3a2600;
  background: var(--gold);
  border-radius: 999px;
}
.chat-badge[hidden] { display: none; }
#btnChat { position: relative; }

#chatPanel, .zmp-chat-veil {
  position: fixed; inset: 0; z-index: 75;
  display: grid; place-items: center;
  padding: 16px;
  background: rgba(10, 6, 20, .8);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
#chatPanel[hidden], .zmp-chat-veil[hidden] { display: none; }

.chat-box {
  width: min(520px, 100%);
  height: min(76dvh, 620px);
  display: flex; flex-direction: column;
  border-radius: 22px;
  border: 1px solid var(--stroke);
  background: linear-gradient(180deg, var(--plum-700), var(--plum-800));
  box-shadow: var(--shadow);
  overflow: hidden;
}
.chat-box header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--stroke);
  flex: none;
}
/* The room name takes the slack so the leave and close buttons sit together on
   the right rather than being spread apart by space-between. */
.chat-box header h2 { margin: 0 auto 0 0; font-size: 18px; }
.chat-box header .icon-btn + .icon-btn { margin-left: 6px; }

/* The read-aloud toggle reads as off until it is on — same grammar as the
   story's muted top-bar buttons. */
.zmp-voice { opacity: .45; }
.zmp-voice.voice-on {
  opacity: 1;
  background: rgba(255, 194, 71, .18);
  border-color: rgba(255, 194, 71, .45);
}

/* Leaving costs the code, which a child cannot get back on their own, so the
   door button asks first rather than acting on the tap. */
.chat-confirm { padding: 16px; display: grid; gap: 10px; }
.chat-confirm p { margin: 0; }
.chat-confirm p:first-child { font-size: 17px; font-weight: 700; }
.chat-confirm .wide { margin-top: 2px; }

.chat-join { padding: 16px; display: grid; gap: 12px; }
.chat-error {
  margin: 0; padding: 9px 12px;
  font-size: 13px; color: #ffb3a0;
  background: rgba(255, 122, 89, .12);
  border: 1px solid rgba(255, 122, 89, .35);
  border-radius: 10px;
}
.chat-error[hidden] { display: none; }

#chatRoom, .zmp-chat-room { display: flex; flex-direction: column; min-height: 0; flex: 1; }

/* Who is in the room, above the messages. It wraps rather than scrolling — on a
   phone a second row of names is fine, a sideways-scrolling strip a child never
   finds is not. */
.chat-here {
  flex: none;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--stroke);
  background: rgba(255, 255, 255, .03);
  font-size: 12.5px;
}
.chat-here-label { opacity: .6; font-weight: 700; letter-spacing: .01em; }
.chat-here-list { display: contents; }
.chat-here .who-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  font-weight: 700;
  color: #1a1030;
  background: var(--who, #cdf5e2);
  border: 1px solid var(--who-line, rgba(79, 209, 165, .38));
  max-width: 40vw;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Your own chip keeps your colour — the "(you)" and the ring say it is you,
   so the colour still means the person. */
.chat-here .who-chip.me { box-shadow: 0 0 0 2px rgba(255, 255, 255, .22); }
.chat-here .alone-note { opacity: .65; font-style: italic; }

.chat-log {
  list-style: none; margin: 0; padding: 12px 14px;
  overflow-y: auto; flex: 1;
  display: flex; flex-direction: column; gap: 8px;
}
/* --who / --who-soft / --who-line are set per message from the sender's name,
   so each person keeps one colour everywhere. The fallbacks are what a bubble
   looks like if that ever fails to be set. */
/* The colour has to carry across the room at arm's length on a phone, so it is
   on the bubble and on a solid bar down the speaker's side — not just the small
   name label, which was too faint to tell anyone apart by. */
.chat-log li {
  max-width: 82%;
  padding: 8px 12px;
  font-size: 14.5px; line-height: 1.35;
  border-radius: 14px;
  background: var(--who-soft, rgba(255, 255, 255, .07));
  border: 1px solid var(--who-line, var(--stroke));
  border-left: 7px solid var(--who, var(--stroke));
  color: var(--who-text, var(--paper));
  align-self: flex-start;
  word-break: break-word;
}
/* Own messages keep their colour but sit on the right — position is what marks
   them as yours, so the colour stays free to identify the person. The bar
   follows to the side the bubble is on. */
.chat-log li.mine {
  align-self: flex-end;
  border-left: 1px solid var(--who-line, var(--stroke));
  border-right: 7px solid var(--who, var(--stroke));
}
.chat-log .who {
  display: block;
  font-size: 12px; font-weight: 800;
  letter-spacing: .02em;
  color: var(--who, #fff);
  margin-bottom: 2px;
}
.chat-empty { align-self: center !important; opacity: .5; font-style: italic; background: none !important; border: none !important; }

.chat-send { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--stroke); flex: none; }
.chat-send input {
  flex: 1; min-width: 0;
  font-family: var(--font); font-size: 16px;
  padding: 11px 14px; min-height: 46px;
  border-radius: 14px;
  border: 2px solid rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .96);
  /* Literal dark, not var(--ink): the field is light on every page, but the
     game pages define --ink as near-white. Same value the story computed. */
  color: #241a33;
}
.chat-send input:focus { outline: none; border-color: var(--gold); }
.chat-send .primary { min-height: 46px; padding: 0 18px; }
.chat-send input:disabled { background: rgba(255, 255, 255, .45); cursor: not-allowed; }

/* Confirmation that the code worked — joining used to happen in silence. */
.chat-welcome {
  margin: 0; padding: 10px 14px;
  font-size: 13.5px; text-align: center;
  color: #cdf5e2;
  background: rgba(79, 209, 165, .13);
  border-bottom: 1px solid rgba(79, 209, 165, .3);
  animation: pop .3s ease;
  flex: none;
}
.chat-welcome[hidden] { display: none; }

/* Once joined, the chat button becomes a chip naming the room — the same shape
   as the player's own chip, so it reads as "you are in here" at a glance
   rather than needing the panel opened to find out. (Story top bar only; the
   shared bar's button stays an icon and only its aria-label changes.) */
#btnChat.joined {
  width: auto;
  gap: 5px;
  display: inline-flex;
  align-items: center;
  padding: 5px 12px 5px 9px;
  max-width: 38vw;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 700;
  border-radius: 999px;
  color: #cdf5e2;
  background: rgba(79, 209, 165, .15);
  border-color: rgba(79, 209, 165, .42);
}
.chat-room-chip {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-room-chip[hidden] { display: none; }
#btnChat .chat-icon { font-size: 15px; line-height: 1; }
@media (max-width: 460px) { #btnChat.joined { max-width: 30vw; font-size: 12px; } }

/* On a phone the room name on the chat button costs about 90px — enough to
   push the exit button off the screen. The green tint already says "you are in
   a room", and the panel header names it, so below this width the button goes
   back to being an icon. */
@media (max-width: 600px) {
  /* Icon-only, so it has to look like the button beside it. The joined state
     used to recolour the whole control green, which was fine when it was a
     labelled pill but reads as a different KIND of button once it is just an
     icon in a row of icons. Same button, with a dot to say you are in a room. */
  #btnChat.joined {
    width: 36px;
    max-width: 36px;
    padding: 0;
    gap: 0;
    border-radius: 11px;
    background: rgba(255, 255, 255, .07);
    border-color: var(--stroke);
    color: var(--paper);
  }
  #btnChat.joined .chat-room-chip { display: none; }
  /* No "you are in a room" marker here. A dot on a chat icon means unread
     messages to everyone who has ever used a phone, so using one to mean
     something else just made it look like there was something to read. The
     gold unread badge is the ONLY thing that may appear on this button;
     which room you are in is answered by opening it. */
}

/* --- the shared top bar (game pages; the story keeps its own #topbar) ------

   One flow row at the top of the page container — never an overlay, the game
   area starts below it. Everything flexible SHRINKS and truncates; nothing
   wraps, so a 320px phone still gets a single row under 48px. */

.zmp-topbar {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 6px;
  flex: none;
  min-width: 0;
  padding: 5px 8px;
  min-height: 44px;
  max-height: 48px;
  background: var(--panel, var(--plum-800));
  border-bottom: 1px solid var(--line, var(--stroke));
}
.zmp-topbar .zmp-home {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none;
}
.zmp-brand {
  display: inline-flex; align-items: center; gap: 6px;
  flex: 0 1 auto; min-width: 0; overflow: hidden;
}
.zmp-brand-mark { font-size: 18px; line-height: 1; flex: none; }
.zmp-brand-title {
  font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zmp-spacer { flex: 1 1 0; min-width: 4px; }
.zmp-chat-btn { position: relative; flex: none; }
.zmp-chat-btn .chat-icon { font-size: 15px; line-height: 1; }
/* The shared bar has its own spacer; the chip must not double-push right. */
.zmp-name-chip { flex: 0 1 auto; margin-left: 0; margin-right: 0; }
.zmp-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Before anyone has said who they are the chip is an invitation, not a fact. */
.zmp-name-chip.anon { opacity: .8; font-weight: 600; }

/* Compact presence in the bar: coloured dots, names in the tooltips. */
.zmp-presence { display: inline-flex; align-items: center; gap: 4px; flex: none; }
.zmp-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--who, #4fd1a5);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35);
  flex: none;
  animation: pop .25s ease;
}
.zmp-dot.is-you { box-shadow: 0 0 0 1px rgba(0, 0, 0, .35), 0 0 0 2px rgba(255, 255, 255, .28); }
.zmp-more { font-size: 10px; font-weight: 700; opacity: .7; }

@media (max-width: 380px) {
  .zmp-brand-title { font-size: 13px; }
  .zmp-topbar { gap: 4px; padding: 4px 6px; }
}

/* --- score boards (shared/scores.js renders these) -------------------------
   APPENDED section — scores.js work; keep additions to this sheet above or
   below whole sections, not inside them.

   Same panel language as the sheets and the chat box: plum gradient, gold for
   the active tab. Names are painted per person via paintWho() — the same
   colour a child has in chat — through the --who custom properties. */

.zmp-board {
  display: flex; flex-direction: column;
  border-radius: 18px;
  border: 1px solid var(--stroke);
  background: linear-gradient(180deg, var(--plum-700), var(--plum-800));
  overflow: hidden;
}

.zmp-board-head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 6px 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--stroke);
}
.zmp-board-title { margin: 0; font-size: 15.5px; }

.zmp-board-tabs { display: inline-flex; gap: 4px; }
.zmp-board-tab {
  font-family: var(--font);
  font-size: 12px; font-weight: 700;
  padding: 5px 10px;
  min-height: 30px;
  border-radius: 999px;
  border: 1px solid var(--stroke);
  background: rgba(255, 255, 255, .06);
  color: var(--paper);
  opacity: .7;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s ease, opacity .12s ease;
}
.zmp-board-tab:hover { opacity: 1; background: rgba(255, 255, 255, .12); }
/* The active window looks like the gold buttons everywhere else — one visual
   grammar for "this is the one that is on". */
.zmp-board-tab.is-active {
  opacity: 1;
  color: #3a2600;
  background: linear-gradient(180deg, var(--gold), var(--gold-deep));
  border-color: rgba(0, 0, 0, .2);
}

.zmp-board-list {
  list-style: none;
  margin: 0; padding: 8px 10px 10px;
  display: flex; flex-direction: column; gap: 4px;
  overflow-y: auto;
}

.zmp-board-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  font-size: 14px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .04);
}
/* The podium reads as a podium without any extra markup: the first three rows
   of an <ol> are always ranks 1–3. */
.zmp-board-row:nth-child(1) { background: rgba(255, 194, 71, .14); }
.zmp-board-row:nth-child(2) { background: rgba(255, 255, 255, .09); }
.zmp-board-row:nth-child(3) { background: rgba(224, 154, 28, .09); }

.zmp-board-rank {
  flex: none;
  width: 22px;
  font-size: 12px; font-weight: 800;
  text-align: center;
  opacity: .65;
}
.zmp-board-row:nth-child(-n+3) .zmp-board-rank { opacity: 1; color: var(--gold, #ffc247); }

/* The name takes the slack and truncates — a 16-char name and a six-figure
   score must share one row on a 320px phone without wrapping. */
.zmp-board-name {
  flex: 1 1 auto; min-width: 0;
  font-weight: 700;
  color: var(--who, var(--paper));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.zmp-board-lv {
  flex: none;
  padding: 1px 7px;
  font-size: 10.5px; font-weight: 700;
  border-radius: 999px;
  color: var(--who, var(--paper));
  background: var(--who-soft, rgba(255, 255, 255, .08));
  border: 1px solid var(--who-line, var(--stroke));
  white-space: nowrap;
}

.zmp-board-score {
  flex: none;
  font-weight: 800;
  font-variant-numeric: tabular-nums;   /* scores line up down the column */
}

.zmp-board-empty {
  padding: 14px 8px;
  font-size: 13px;
  text-align: center;
  opacity: .55;
  font-style: italic;
}

@media (max-width: 380px) {
  .zmp-board-head { padding: 9px 10px; }
  .zmp-board-tab { padding: 4px 8px; font-size: 11px; }
  .zmp-board-row { font-size: 13px; }
}
