:root {
  --tg-bg: var(--tg-theme-bg-color, #ffffff);
  --tg-secondary-bg: var(--tg-theme-secondary-bg-color, #efeff4);
  --tg-section-bg: var(--tg-theme-section-bg-color, #ffffff);
  --tg-text: var(--tg-theme-text-color, #000000);
  --tg-hint: var(--tg-theme-hint-color, #8e8e93);
  --tg-link: var(--tg-theme-link-color, #007aff);
  --tg-button: var(--tg-theme-button-color, #007aff);
  --tg-button-text: var(--tg-theme-button-text-color, #ffffff);
  --tg-separator: rgba(60, 60, 67, 0.29);
  --win: #34c759;
  --lose: #ff3b30;

  /* Floating glass dock tokens (light), matched to the Telegram Mini App
     reference tab bar: blurred glass pill with a sliding selection. */
  --dock-glass: rgba(242, 242, 242, .6);
  --dock-glass-shadow: 0 8px 30px rgba(0, 0, 0, .09), 0 2px 8px rgba(0, 0, 0, .045);
  --dock-glass-rim: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 0 0 .8px rgba(255, 255, 255, .35), inset 0 0 0 1.6px rgba(0, 0, 0, .02);
  --dock-selection: rgba(0, 0, 0, .05);
  --dock-label: #1a1a1a;
  --dock-accent: #008bff;
  --dock-h: calc(78px + max(25px, env(safe-area-inset-bottom, 0px)));

  /* Segmented tab control (e.g. "Что выпадет?" 1-6 picker): light mode shows
     a white track with a grey active pill, matching the quick-amount chips. */
  --segment-track-bg: #ffffff;
  --segment-active-bg: rgba(118, 118, 128, 0.12);
}

:root[data-theme="dark"] {
  --dock-glass: rgba(29, 29, 29, .6);
  --dock-glass-shadow: 0 8px 30px rgba(0, 0, 0, .34), 0 2px 8px rgba(0, 0, 0, .2);
  --dock-glass-rim: inset 0 1px 0 rgba(255, 255, 255, .08), inset 0 0 0 .8px rgba(255, 255, 255, .08);
  --dock-selection: rgba(255, 255, 255, .1);
  --dock-label: #f5f5f5;
  --dock-accent: #0091ff;

  /* Dark mode: active tab uses the exact same chip tone as the 50/100/250/500
     quick-amount buttons (rgba(118, 118, 128, 0.12), same as light mode). */
  --segment-track-bg: rgba(118, 118, 128, 0.16);
  --segment-active-bg: rgba(118, 118, 128, 0.12);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; scrollbar-width: none; -ms-overflow-style: none; }
*::-webkit-scrollbar { display: none; width: 0; height: 0; }

html, body {
  margin: 0;
  background: var(--tg-secondary-bg);
  color: var(--tg-text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  padding-bottom: var(--dock-h);
  /* The viewport meta's user-scalable=no isn't always honored by the
     WKWebView Telegram embeds on iOS — this is the part that actually
     blocks the two-finger pinch gesture there. Still allows normal one-
     finger scroll/pan (pan-x pan-y), just not the zoom gesture itself. */
  touch-action: pan-x pan-y;
}

/* Background scroll lock while any sheet is open — see updateBodyScrollLock()
   in app.js. overflow:hidden alone is enough here since the page's only
   scroll container is the document body itself (no independent inner
   scroller to also freeze). */
body.modal-open {
  overflow: hidden;
  touch-action: none;
}

#pages {
  padding-top: 16px;
}

.page {
  display: none;
}

.page.active {
  display: block;
}

/* Турниры is a placeholder page for now — just the illustration centered in
   the whole screen. Needs the ID selector (beats .page.active's specificity
   regardless of source order) so it doesn't fall back to display:block. */
#page-tournaments.active {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: calc(100vh - 16px - var(--dock-h));
}

.balance-card {
  margin: 0 16px 12px;
  background: var(--tg-section-bg);
  border-radius: 30px;
  padding: 14px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.balance-label {
  font-size: 15px;
  color: var(--tg-hint);
}

.balance-value {
  font-size: 17px;
  font-weight: 600;
  color: var(--tg-link);
}

.stage-card {
  margin: 0 16px 12px;
  background: var(--tg-section-bg);
  border-radius: 22px;
  padding: 28px 16px 22px;
  text-align: center;
}

.result-emoji {
  font-size: 64px;
  line-height: 1;
  transition: transform 0.15s;
}

.result-emoji.spinning {
  animation: spin 0.08s linear infinite;
}

@keyframes spin {
  0% { transform: scale(1) rotate(0deg); }
  50% { transform: scale(1.12) rotate(8deg); }
  100% { transform: scale(1) rotate(-8deg); }
}

.result-text {
  margin-top: 10px;
  font-size: 14px;
  color: var(--tg-hint);
  min-height: 18px;
}

.result-text.win { color: var(--win); font-weight: 600; }
.result-text.lose { color: var(--lose); font-weight: 600; }

.section {
  margin: 0 16px 12px;
}

.section-header {
  font-size: 13px;
  font-weight: 400;
  color: var(--tg-hint);
  letter-spacing: 0.2px;
  padding: 0 4px 6px;
}

.segmented {
  position: relative;
  display: flex;
  background: var(--segment-track-bg);
  border-radius: 999px;
  padding: 3px;
  gap: 3px;
  overflow: hidden;
}

/* Sliding selection pill — same mechanism and easing as the bottom dock's
   .tabbar__sel: a single absolutely-positioned element whose width/position
   are set in JS from the active button's bounding rect, instead of each
   button toggling its own background (which just crossfades in place). */
.segmented__sel {
  position: absolute;
  top: 3px;
  left: 0;
  height: calc(100% - 6px);
  border-radius: 999px;
  background: var(--segment-active-bg);
  transition: transform .3s cubic-bezier(.4, 0, .2, 1), width .3s cubic-bezier(.4, 0, .2, 1);
  pointer-events: none;
}

.segment {
  position: relative;
  z-index: 1;
  flex: 1;
  background: transparent;
  border: none;
  border-radius: 999px;
  font-size: 20px;
  padding: 7px 0;
  cursor: pointer;
  color: var(--tg-text);
}

.list-card {
  background: var(--tg-section-bg);
  border-radius: 22px;
  overflow: hidden;
}

.list-row {
  padding: 12px 16px;
  border-bottom: 1px solid var(--tg-separator);
}

.list-row:last-child {
  border-bottom: none;
}

.quick-row {
  display: flex;
  gap: 8px;
}

#depositPresets {
  margin-bottom: 12px;
}

.quick {
  flex: 1;
  background: rgba(118, 118, 128, 0.12);
  border: none;
  color: var(--tg-text);
  padding: 8px 0;
  border-radius: 14px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}

.action-area {
  margin: 4px 16px 20px;
}

.play-btn {
  width: 100%;
  background: var(--tg-button);
  color: var(--tg-button-text);
  border: none;
  padding: 14px;
  border-radius: 999px;
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
}

.play-btn:disabled {
  opacity: 0.5;
}

.history-item {
  padding: 10px 16px;
  border-bottom: 1px solid var(--tg-separator);
  display: flex;
  justify-content: space-between;
  font-size: 14px;
}

.history-item:last-child {
  border-bottom: none;
}

.history-item.win { color: var(--win); }
.history-item.lose { color: var(--tg-hint); }

.history-empty {
  padding: 16px;
  text-align: center;
  color: var(--tg-hint);
  font-size: 13px;
}

/* Profile page */

.profile-card {
  text-align: center;
  padding: 24px 16px 8px;
}

.profile-avatar {
  width: 72px;
  height: 72px;
  margin: 0 auto 10px;
  border-radius: 50%;
  background: var(--tg-section-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
}

.profile-name {
  font-size: 20px;
  font-weight: 600;
}

.profile-username {
  font-size: 14px;
  color: var(--tg-hint);
  margin-top: 2px;
}

/* Settings-style rows — ported 1:1 from nftshniy.ru's settings panel
   (icon badge + label + value + chevron, exact sizes/offsets from its CSS),
   with our own profile items dropped into the same row template. */

.pf-title {
  margin: 0 0 6px 4px;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.2px;
  font-family: inherit;
  color: var(--tg-hint);
  text-transform: uppercase;
}

.pf-group {
  background: var(--tg-section-bg);
  border-radius: 30px;
  overflow: hidden;
}

.pf-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 16px;
}

.pf-row:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 89px;
  right: 21px;
  bottom: 0;
  height: 1px;
  background: var(--tg-separator);
}

.pf-row.stepper-row {
  gap: 24px;
  justify-content: center;
}

.pf-icon {
  flex: none;
  margin-left: 10px;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pf-icon svg {
  width: 18px;
  height: 18px;
}

.pf-label {
  flex: 1;
  font-size: 15px;
  min-width: 0;
}

input.pf-label {
  border: none;
  background: transparent;
  color: var(--tg-text);
  font-family: inherit;
  outline: none;
}

input.pf-label::placeholder {
  color: var(--tg-hint);
}

.pf-value {
  flex: none;
  font-size: 15px;
  color: var(--tg-hint);
}

.pf-chevron {
  flex: none;
  color: var(--tg-hint);
  display: flex;
  align-items: center;
}

:root[data-theme="light"] .pf-chevron {
  color: #cbcbcb;
}

.stat-row {
  display: flex;
  justify-content: space-between;
  font-size: 15px;
}

.stat-value {
  font-weight: 600;
  color: var(--tg-link);
}

/* Vertical spacing lives in the margin (not padding) so it's symmetric and
   self-contained — it used to rely on whatever margin-bottom the block above
   happened to have (10-14px) plus its own 8px top padding, with nothing
   matching that below, so the gap above was consistently bigger than below. */
.hint-text {
  margin: 14px 0;
  padding: 0 20px;
  text-align: center;
  color: var(--tg-hint);
  font-size: 12px;
}

/* Floating glass dock — matches the bottom tab bar pattern used by
   nftshniy's Telegram Mini App (blurred pill + sliding selection). */

.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 20;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 16px 25px max(25px, env(safe-area-inset-bottom, 0px));
  pointer-events: none;
  transition: opacity .15s, transform .15s;
}

/* While a text/number field is focused, the on-screen keyboard pushes the fixed
   viewport up — hide the dock instead of letting it jump mid-screen. */
.tabbar.keyboard-editing {
  opacity: 0;
  transform: translateY(16px);
  pointer-events: none;
}

.tabbar__pill {
  position: relative;
  flex: 1;
  display: flex;
  padding: 3px 4px;
  border-radius: 31px;
  overflow: hidden;
  background: var(--dock-glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.7);
  backdrop-filter: blur(18px) saturate(1.7);
  box-shadow: var(--dock-glass-shadow), var(--dock-glass-rim);
  pointer-events: auto;
}

.tabbar__sel {
  position: absolute;
  top: 4px;
  left: 0;
  height: 54px;
  border-radius: 28px;
  background: var(--dock-selection);
  transition: transform .3s cubic-bezier(.4, 0, .2, 1), width .3s cubic-bezier(.4, 0, .2, 1), opacity .2s;
}

.tab {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 6.5px 8px;
  border: none;
  background: none;
  color: var(--dock-label);
  cursor: pointer;
  transition: color .2s;
}

.tab--active {
  color: var(--dock-accent);
}

.tab__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 30px;
}

.tab__icon svg {
  width: 30px;
  height: 30px;
  display: block;
}

/* Кубик/Комнаты use solid (fill="currentColor") glyphs on a 28x28 viewBox,
   stretched to the shared 30px box — same convention as every tab icon in
   @the_nfts_bot's own dock, so those two are left alone. Режимы/Подарки are
   thin-stroke outline icons on a 24x24 viewBox: stretching a 24-box up to a
   30px render (a 1.25x blow-up) enlarges their outer silhouette — and
   stroke-width right along with it, so the lines get visibly thicker too —
   well past how big the filled pair actually reads. Rendered closer to
   their native 24px instead of being force-stretched to match the other
   icons' box. The icon *box* (.tab__icon) stays the shared 30px height for
   every tab regardless — only the svg inside it shrinks, still centered by
   the box's own flex centering — so every label sits at the same height
   below it. Shrinking the box itself here was the earlier bug that caused
   a staircase: each tab's label ended up starting from a different offset. */
.tab[data-page="modes"] .tab__icon svg,
.tab[data-page="gifts"] .tab__icon svg {
  width: 25px;
  height: 25px;
}

.tab__label {
  max-width: 100%;
  font-size: 10px;
  font-weight: 700;
  line-height: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Top-up button + deposit bottom sheet */

.topup-btn {
  background: var(--tg-button);
  color: var(--tg-button-text);
  border: none;
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(0, 0, 0, 0.4);
  display: none;
  align-items: flex-end;
}

.sheet-overlay.open {
  display: flex;
}

.sheet {
  width: 100%;
  background: var(--tg-secondary-bg);
  border-radius: 28px 28px 0 0;
  padding: 10px 16px calc(24px + env(safe-area-inset-bottom));
  max-height: 80vh;
  overflow-y: auto;
}

.sheet-handle {
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--tg-separator);
  margin: 2px auto 14px;
}

.sheet-title {
  font-size: 17px;
  font-weight: 600;
  text-align: center;
  margin-bottom: 14px;
}

/* "Создать игру" modal — ported 1:1 (chrome + animation, not its content)
   from @the_nfts_bot's Owners → Open App sheet (tg.nftshniy.org): the
   slide-up spring, the backdrop fade, and the bottom corner radius that
   matches the actual device's screen corners (via --sheet-bottom-radius,
   computed in app.js — see deviceSheetRadius()). Layered on top of
   .sheet/.sheet-overlay (keeps their padding/list rules), not applied to any
   other sheet in the app. */
.modal-overlay {
  display: flex;
  background: none;
  /* Always display:flex now (not display:none) so the sheet/backdrop can
     transition instead of popping — but that makes this a permanent
     full-viewport box sitting over the whole app. Without this, it swallows
     every click/tap everywhere (the dock, every button) even while visually
     empty and "closed", since pointer-events defaults to auto. .modal-sheet
     and .modal-backdrop explicitly re-enable it for themselves below. */
  pointer-events: none;
}

/* The dimmed scrim fades on its own, separately from the sheet — putting
   opacity on a true ancestor of .modal-sheet instead (as the overlay wrapper
   itself used to be) group-fades every descendant, including the already
   fully-opaque sheet: it would cross-fade in *underneath* its own slide, on
   top of the pure translateY, which reads as the card "materializing"
   mid-air instead of one solid block sliding up/down. .modal-sheet never
   touches opacity — position (on/off screen) is its only state. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1;
  background: rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s cubic-bezier(0.42, 0, 0.58, 1);
}

.modal-overlay.open .modal-backdrop {
  opacity: 1;
  pointer-events: auto;
}

.modal-sheet {
  position: fixed;
  left: 6px;
  right: 6px;
  bottom: 6px;
  z-index: 2;
  pointer-events: auto;
  width: auto;
  max-height: 85vh;
  border-radius: 42px 42px var(--sheet-bottom-radius, 58px) var(--sheet-bottom-radius, 58px);
  box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.05);
  padding-top: 78px;
  transform: translateY(calc(100% + 6px));
  transition: transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
}

.modal-overlay.open .modal-sheet {
  transform: translateY(0);
  transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}

/* Same slide/backdrop animation as .modal-sheet, just without the close/menu
   buttons (wait screens, the parity side-picker) — their 78px top padding
   exists only to clear those floating buttons, so it'd otherwise leave a
   big empty gap above the title. */
.modal-sheet--compact {
  padding-top: 20px;
}

/* Close (✕) and menu (⋯) — pinned to the sheet's own corners, moving rigidly
   with it as one solid unit. Earlier this used a frosted-glass look
   (translucent layers + backdrop-filter blur) — on WebKit that blur fights a
   fast CSS transform and visibly lags in after the slide settles, instead of
   already being there. Flat, same track color as the segment tabs (white in
   light, that tab-track gray in dark): no blur, no lag, no separate reveal. */
.modal-sheet__close,
.modal-sheet__menu {
  position: absolute;
  top: 16px;
  width: 44px;
  height: 44px;
  z-index: 2;
  border: 0;
  padding: 0;
  border-radius: 999px;
  cursor: pointer;
  background: var(--segment-track-bg);
  color: var(--tg-text);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-sheet__close {
  left: 16px;
}

.modal-sheet__menu {
  right: 16px;
}

/* Filter-sheet title (Коллекция/Модель/Фон/Узор/Фильтры) — a rounded chip
   centered in the same row as .modal-sheet__close, instead of a second
   heading floating below it. */
.modal-sheet__title-chip {
  position: absolute;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  height: 44px;
  padding: 0 20px;
  display: flex;
  align-items: center;
  border-radius: 999px;
  background: var(--segment-track-bg);
  color: var(--tg-text);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
}

.modal-sheet__search {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--tg-section-bg);
  margin-bottom: 12px;
}

.modal-sheet__search-icon {
  flex: none;
  display: flex;
  color: var(--tg-hint);
}

.modal-sheet__search-icon svg {
  width: 18px;
  height: 18px;
}

.modal-sheet__search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--tg-text);
  font-size: 17px;
  font-family: inherit;
  outline: none;
}

.modal-sheet__search-input::placeholder {
  color: var(--tg-hint);
}

/* 3x3 grid below the search field — the row of 3 squares spans the same
   width as the search field (the sheet's own content box, which already
   runs edge to edge with the close/menu buttons), with one equal gap value
   used for both directions so top/bottom/left/right spacing between squares
   matches. */
.modal-sheet__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.modal-sheet__grid-item {
  /* padding-top:100% (not aspect-ratio) forces the square shape — some
     WebViews Telegram embeds (older Android system WebView, some desktop
     builds) don't support aspect-ratio yet, which collapses these to 0
     height and leaves only the sheet's own flat background visible. The
     percentage-padding trick is supported everywhere. */
  position: relative;
  border-radius: 16px;
  background: var(--tg-section-bg);
}

.modal-sheet__grid-item::before {
  content: "";
  display: block;
  padding-top: 100%;
}

/* Коллекция only: the ✕/chip/?/search row stays put while only the grid
   scrolls underneath it — .sheet's own overflow-y:auto would otherwise
   scroll that whole row away with the grid, since they share one scroll
   container. Splits scrolling into just .modal-sheet__scroll instead. */
#collectionOverlay .modal-sheet {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* Bottom spacing is now entirely owned by .modal-sheet__actions below
     (matches the reference sheet, which has no bottom padding of its own
     either — only its button wrapper does). */
  padding-bottom: 0;
}

#collectionOverlay .modal-sheet__search {
  flex: none;
}

#collectionOverlay .modal-sheet__scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  /* Without this, scrolling past the top/bottom edge triggers iOS's elastic
     "rubber-band" overscroll, which — since this container has no
     background of its own — briefly reveals whatever sits behind the sheet
     (the page's gray background) as a flat block right at that edge,
     directly under the search field and under the "Выбрать" button. */
  overscroll-behavior: contain;
  background: var(--tg-secondary-bg);
}

/* "Выбрать" button placement — pulled 1:1 from @the_nfts_bot's own Open App
   sheet (tg.nftshniy.org bundle, the button wrapper inside its z1() sheet
   content: paddingTop:4, paddingLeft:28, paddingRight:28, paddingBottom:28,
   button height:52). The sheet itself already carries 16px of left/right
   padding (from the shared .sheet rule) for the search field/grid above, so
   this wrapper only adds the remaining 12px (16 + 12 = 28) to match that
   inset exactly, rather than restating it from scratch. */
#collectionOverlay .modal-sheet__actions {
  flex: none;
  padding: 4px 12px 28px;
}

#collectionOverlay .modal-sheet__actions .play-btn {
  height: 52px;
}

.deposit-pane {
  margin-top: 14px;
}

.text-input {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--tg-text);
  font-size: 15px;
  font-family: inherit;
  outline: none;
}

.text-input::placeholder {
  color: var(--tg-hint);
}

.referral-link {
  font-size: 13px;
  color: var(--tg-link);
  word-break: break-all;
}

/* Cell — ported from the TelegramUI kit (telegram-mini-apps-dev/TelegramUI)
   Cell component: before/middle/after slots, same gap/padding logic as its
   --ios variant. Used for every row in Режимы/Комнаты (open rooms, open
   games, the player list inside a match's wait/result sheets). */
.tui-cell {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--tg-separator);
}

.tui-cell:last-child {
  border-bottom: none;
}

.tui-cell--compact {
  padding: 10px 16px;
  gap: 10px;
}

/* Avatar with acronym — same treatment as the kit's Avatar.withAcronym:
   secondary-fill circle, link-colored initial, so every room/duel row shows
   *who* it is instead of the same dice emoji repeated down the list. */
.tui-cell__avatar {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(118, 118, 128, 0.12);
  color: var(--tg-link);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  font-weight: 600;
}

.tui-cell--compact .tui-cell__avatar {
  width: 30px;
  height: 30px;
  font-size: 13px;
}

/* Mode icon — a colored circle per game type (same palette the create sheet
   uses), at list-row scale. */
.tui-cell__icon {
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tui-cell__icon svg {
  width: 18px;
  height: 18px;
}

.tui-cell__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.tui-cell__title {
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tui-cell__subtitle {
  font-size: 13px;
  color: var(--tg-hint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tui-cell__trailing {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Badge — same pill as the kit's Badge (secondary variant): a quiet counter
   or amount, never competing with the primary "Войти" action next to it. */
.tui-badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 7px;
  border-radius: 20px;
  background: rgba(118, 118, 128, 0.12);
  color: var(--tg-text);
  font-size: 12px;
  font-weight: 600;
}

.tui-badge--win {
  background: rgba(52, 199, 89, 0.15);
  color: var(--win);
}

.tui-badge--muted {
  color: var(--tg-hint);
}

/* Placeholder — ported from the kit's Placeholder: centered icon + title +
   description, used wherever a list has nothing to show instead of one line
   of gray text. */
.tui-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  padding: 36px 24px;
}

.tui-empty__icon {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: rgba(118, 118, 128, 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
}

/* Комнаты' empty state uses a real animated Telegram custom emoji (fetched
   once via the Bot API and saved as a plain Lottie JSON, same as the dice
   animations) instead of the plain icon chip the other tui-empty screens
   use — a bigger, un-backgrounded illustration rather than a small icon. */
.tui-empty__lottie {
  width: 110px;
  height: 110px;
}

.tui-empty__title {
  font-size: 15px;
  font-weight: 600;
}

.tui-empty__desc {
  font-size: 13px;
  color: var(--tg-hint);
  line-height: 1.4;
  max-width: 230px;
}

/* Native (squarish) segmented control — the kit's real iOS SegmentedControl
   uses a ~9px radius, not a full pill: applied only to the mode/target/guess
   switchers inside the create & match sheets (Режимы/Комнаты), the "Что
   выпадет?" 1-6 picker on Кубик is untouched and keeps its original pill. */
.segmented--native {
  border-radius: 10px;
  padding: 2px;
}

.segmented--native .segmented__sel {
  top: 2px;
  height: calc(100% - 4px);
  border-radius: 8px;
}

.segmented--native .segment {
  border-radius: 8px;
}

.room-join-btn {
  background: var(--tg-button);
  color: var(--tg-button-text);
  border: none;
  padding: 7px 14px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.result-lottie {
  width: 120px;
  height: 120px;
  margin: 0 auto;
  display: none;
}

.result-lottie.active {
  display: block;
}


/* Bet input row */

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

.bet-input {
  flex: 1;
  font-size: 22px;
  font-weight: 600;
  text-align: center;
  -moz-appearance: textfield;
}

.bet-input::-webkit-outer-spin-button,
.bet-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.max-btn {
  flex: none;
  background: var(--tg-button);
  color: var(--tg-button-text);
  border: none;
  padding: 10px 16px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  /* Row padding is 12px top / 16px right — nudge right by the 4px
     difference so the button sits the same distance from both edges. */
  margin-right: -4px;
}

/* Coefficient chips */

.coef-row {
  display: flex;
  gap: 6px;
}

.coef-chip {
  flex: 1;
  min-width: 0;
  background: rgba(118, 118, 128, 0.12);
  border: none;
  color: var(--tg-text);
  padding: 10px 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
}

.coef-chip.active {
  background: var(--tg-button);
  color: var(--tg-button-text);
}

/* Used where chips stand in for actual play-btn-sized choices (e.g. picking
   a side before joining a Чёт/Нечет match) instead of small filter pills —
   same height as .play-btn's 14px padding + 17px text. */
.coef-row--lg .coef-chip {
  padding: 14px 0;
  font-size: 15px;
}

.pf-row--link {
  cursor: pointer;
}

/* Bottom-sheet overlays reuse page-level blocks (.stage-card, .list-card) but
   the sheet itself already has 16px horizontal padding — stop those blocks
   from adding their own margin on top of it, and always leave breathing room
   before whatever follows (another block or the sheet's closing button). */
.sheet .stage-card {
  margin-left: 0;
  margin-right: 0;
}

.sheet .list-card {
  margin-bottom: 14px;
}

/* Tournament/guess matches can hold up to 24 players — without a cap here,
   a long player list pushes "Отменить"/"Закрыть" past the sheet's own
   max-height (80vh), so it reads as if the button vanished. Capped height +
   internal scroll instead, so the action button always stays in view below. */
#matchPlayersList,
#matchResultList {
  max-height: 38vh;
  overflow-y: auto;
}

/* Button hierarchy — ported from nftshniy's Fill/Bezeled set. .play-btn stays
   Fill (primary, solid) by default; .play-btn--secondary is Bezeled (tinted,
   low-emphasis) for dismissive actions like "Закрыть"/"Отменить" that sit
   alone in a sheet, so the one actually-proactive action on screen keeps the
   strongest visual weight. */
.play-btn--secondary {
  background: rgba(0, 122, 255, 0.12);
  color: var(--tg-link);
}

:root[data-theme="dark"] .play-btn--secondary {
  background: rgba(10, 132, 255, 0.18);
}

/* History row — ported from nftshniy's Wallet transaction list: round icon
   badge + title/subtitle on the left, a colored amount + status word on the
   right, instead of one flat line of text. */
.history-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  box-sizing: border-box;
}

/* Same inset-divider convention as .pg-row--icon in Профиль (padding + icon
   + gap), instead of a full-bleed border. */
.history-row + .history-row::before {
  content: "";
  position: absolute;
  left: 56px;
  right: 0;
  top: 0;
  height: 0.5px;
  background: var(--tg-separator);
}

.history-row__avatar {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
}

.history-row__body {
  flex: 1;
  min-width: 0;
}

.history-row__title {
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.history-row__sub {
  font-size: 13px;
  color: var(--tg-hint);
  margin-top: 1px;
}

.history-row__right {
  flex: none;
  text-align: right;
}

.history-row__amount {
  font-size: 15px;
  font-weight: 600;
}

.history-row__amount.win { color: var(--win); }
.history-row__amount.lose { color: var(--tg-text); }

.history-row__status {
  font-size: 12px;
  color: var(--tg-hint);
  margin-top: 1px;
}

/* Promo banner — ported from nftshniy's Playground "Introducing TON Space"
   card: round icon badge, title + subtitle, optional dismiss button. */
.promo-banner {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--tg-section-bg);
  border-radius: 22px;
  padding: 16px;
}

.promo-banner__icon {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--tg-button);
  color: var(--tg-button-text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}

.promo-banner__body {
  flex: 1;
  min-width: 0;
  padding-right: 8px;
}

.promo-banner__title {
  font-size: 15px;
  font-weight: 600;
}

.promo-banner__sub {
  font-size: 13px;
  color: var(--tg-hint);
  margin-top: 3px;
  line-height: 1.35;
}

.promo-banner__close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(118, 118, 128, 0.16);
  color: var(--tg-hint);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}

/* Select field — ported from nftshniy's Playground SELECT control: a rounded
   list-card row with a native <select> and a chevron, used wherever a range
   of choices is too wide for a stepper (e.g. up to 24 tournament players). */
.select-field {
  position: relative;
  display: flex;
  align-items: center;
}

.select-field select {
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  border: none;
  background: transparent;
  color: var(--tg-text);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  padding: 2px 28px;
  outline: none;
}

.select-field::after {
  content: "";
  position: absolute;
  right: 16px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--tg-hint);
  border-bottom: 2px solid var(--tg-hint);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

/* Комнаты toolbar — rounded search field + round filter/create buttons,
   sitting above the open-games list on the same page. */
.rooms-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 16px 12px;
}

/* Поиск's open-games box with no empty-state copy left inside it would
   collapse to 0 height — keep it visible as a placeholder surface. */
#modesRoomsList {
  min-height: 230px;
}

.rooms-toolbar__search {
  flex: 1;
  min-width: 0;
}

.rooms-toolbar .list-row {
  padding: 10px 16px;
}

.rooms-icon-btn {
  flex: none;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(118, 118, 128, 0.12);
  color: var(--tg-text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}

.rooms-icon-btn--accent {
  background: var(--tg-button);
  color: var(--tg-button-text);
}

.rooms-icon-btn--sm {
  width: 36px;
  height: 36px;
}

/* The dice button sits inside the field's own rounded pill, not beside it —
   same visual language as a search bar with a trailing icon. */
.room-name-field {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--tg-section-bg);
  border-radius: 22px;
  padding: 4px 4px 4px 16px;
}

.room-name-field .text-input {
  flex: 1;
  min-width: 0;
}

.sel-menu__item--active {
  color: var(--tg-link);
  font-weight: 600;
}

/* Playground settings screen — ported 1:1 from web.nftshniy.org (class names
   and every rule below pulled straight from its live DOM/CSSOM: pg-list,
   pg-section, pg-card, pg-row, pg-input, pg-slider, pg-switch). Only the
   color values were swapped from their --tgui--* tokens to ours so the block
   follows our own light/dark theme instead of theirs. Used for Profile →
   Настройки. */

.pg-list {
  margin-top: -4px;
  padding: 0 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.pg-section {
  display: flex;
  flex-direction: column;
}

/* A pg-section used standalone on a page (not nested in a .pg-list, which
   already supplies its own 16px side padding + 12px inter-section gap) needs
   that same spacing applied directly. */
.page > .pg-section {
  margin: 0 16px 12px;
}

.pg-section--lead {
  padding-top: 12px;
}

.pg-section__header {
  height: 40px;
  padding: 16px 16px 8px;
  box-sizing: border-box;
  font-size: 13px;
  line-height: 16px;
  text-transform: uppercase;
  color: var(--tg-hint);
}

.pg-section__footer {
  padding: 8px 16px 0;
  font-size: 13px;
  line-height: 16px;
  color: var(--tg-hint);
}

.pg-section__footer--center {
  padding-top: 16px;
  text-align: center;
}

.pg-card {
  padding: 2px 0;
  border-radius: 12px;
  background: var(--tg-section-bg);
  overflow: hidden;
}

.pg-row {
  position: relative;
  height: 46px;
  padding: 0 16px;
  display: flex;
  align-items: center;
  gap: 16px;
  box-sizing: border-box;
}

.pg-row--lead {
  height: 44px;
}

.pg-row + .pg-row::before {
  content: "";
  position: absolute;
  left: 16px;
  right: 0;
  top: 0;
  height: 0.5px;
  background: var(--tg-separator);
}

.pg-row--icon + .pg-row--icon::before {
  left: 60px;
}

.pg-row__icon {
  flex: none;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  color: var(--tg-link);
}

.pg-row__title {
  flex: 1 1 0%;
  min-width: 0;
  font-size: 17px;
  line-height: 22px;
  color: var(--tg-text);
}

.pg-row__title--link {
  color: var(--tg-link);
}

.pg-row__value {
  font-size: 17px;
  line-height: 22px;
  color: var(--tg-hint);
}

/* Поиск filter rows (Коллекция/Модель/Фон/Узор/Номер/Фильтры) — pulled 1:1
   from tg.nftshniy.org's own CSSOM (assets/index-e5qK98Db.css, the
   .gr-card/.gr-row/.gr-add family behind @the_nfts_bot's Mints → Add Members
   cell): current native Telegram iOS grouped-cell sizing and type. */
.gift-filters {
  margin: 0 16px 12px;
  background: var(--tg-section-bg);
  border-radius: 26px;
  overflow: hidden;
}

.gift-filter-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 52px;
  padding: 0 16px;
  width: 100%;
  border: 0;
  background: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}

.gift-filter-row + .gift-filter-row::before {
  content: "";
  position: absolute;
  top: 0;
  left: 68px;
  right: 16px;
  height: .5px;
  background: var(--tg-separator);
}

.gift-filter-row__icon {
  width: 42px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding-left: 6px;
  color: var(--tg-link);
}

.gift-filter-row__icon svg {
  width: 30px;
  height: 30px;
}

.gift-filter-row__label {
  flex: 1;
  min-width: 0;
  font-size: 17px;
  font-weight: 510;
  line-height: 22px;
  letter-spacing: -0.43px;
  color: var(--tg-text);
}

.gift-filter-row__chevron {
  flex: none;
  margin-left: 8px;
  display: grid;
  place-items: center;
  color: var(--tg-hint);
}

.gift-filter-row__input {
  flex: none;
  width: 100px;
  border: none;
  background: transparent;
  color: var(--tg-hint);
  font-size: 17px;
  font-weight: 510;
  line-height: 22px;
  letter-spacing: -0.43px;
  text-align: right;
  font-family: inherit;
  outline: none;
}

.gift-filter-row__input::placeholder {
  color: var(--tg-hint);
}

.pg-wallet-link {
  flex: none;
  color: var(--tg-link);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  background: none;
  border: none;
  font: inherit;
  padding: 0;
  cursor: pointer;
}

/* Floating dropdown menu — ported from nftshniy's "SELECT" control on
   web.nftshniy.org/Playground: a rounded floating panel, no dividers, each
   row a plain text button. */
.sel-menu-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
}

.sel-menu-overlay.open {
  display: block;
}

.sel-menu {
  position: absolute;
  min-width: 192px;
  background: var(--tg-section-bg);
  border-radius: 20px;
  box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.05), 0 32px 64px rgba(0, 0, 0, 0.12);
  overflow: hidden;
}

.sel-menu__item {
  display: flex;
  align-items: center;
  width: 100%;
  height: 48px;
  padding: 0 16px;
  font-size: 17px;
  line-height: 22px;
  color: var(--tg-text);
  background: transparent;
  border: none;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}

.sel-menu__item--danger {
  color: var(--lose);
}

.pg-row__chevron {
  flex: none;
  margin-left: 8px;
  display: grid;
  place-items: center;
  color: var(--tg-hint);
  opacity: 0.5;
}

.pg-input {
  height: 52px;
  padding: 0 16px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  border-radius: 12px;
  background: var(--tg-section-bg);
  font-size: 17px;
  line-height: 22px;
  color: var(--tg-hint);
}

/* Slider — same container/track dimensions as nftshniy's custom pg-slider,
   built on a native <input type=range> instead of their pointer-drag div so
   dragging, keyboard and accessibility all work for free. */
.pg-slider {
  height: 66px;
  padding: 0 16px 0 20px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 16px;
  border-radius: 12px;
  background: var(--tg-section-bg);
}

.pg-slider__track {
  position: relative;
  flex: 1 1 0%;
  display: flex;
  align-items: center;
}

.pg-slider__input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 28px;
  background: transparent;
  margin: 0;
  outline: none;
  cursor: pointer;
}

.pg-slider__input::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 4px;
  background: linear-gradient(to right, var(--tg-link) 0%, var(--tg-link) var(--pg-fill, 50%), var(--segment-active-bg) var(--pg-fill, 50%));
}

.pg-slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 28px;
  height: 28px;
  margin-top: -12px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  cursor: pointer;
}

.pg-slider__input::-moz-range-track {
  height: 4px;
  border-radius: 4px;
  background: var(--segment-active-bg);
}

.pg-slider__input::-moz-range-progress {
  height: 4px;
  border-radius: 4px;
  background: var(--tg-link);
}

.pg-slider__input::-moz-range-thumb {
  width: 28px;
  height: 28px;
  border: none;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  cursor: pointer;
}

.pg-slider__value {
  flex: none;
  font-size: 17px;
  line-height: 22px;
  color: var(--tg-text);
}

/* Switch — their demo only ever renders the "on" state (a static div with
   the knob pinned right); this adds the real off state so it can work as an
   actual toggle, using the same 51×31/27×27 sizing and shadow. */
.pg-switch {
  flex: none;
  position: relative;
  width: 51px;
  height: 31px;
  border-radius: 100px;
  background: rgba(118, 118, 128, 0.32);
  transition: background 0.2s;
}

.pg-switch__input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.pg-switch__knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 27px;
  height: 27px;
  border-radius: 100px;
  background: #fff;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  transition: left 0.2s;
}

.pg-switch:has(.pg-switch__input:checked) {
  background: var(--tg-link);
}

.pg-switch:has(.pg-switch__input:checked) .pg-switch__knob {
  left: 22px;
}
