.app-shell { position: relative; max-width: var(--app-max-w); margin: 0 auto; height: 100%; display: flex; flex-direction: column; background: var(--bg); box-shadow: 0 0 40px rgba(0, 0, 0, 0.5); } /* Шапка вне прокручиваемой области по построению — sticky ей больше не нужен. */ .top-bar { flex: none; display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: var(--surface); border-bottom: 1px solid var(--border); } .top-bar .title { font-weight: 700; font-size: 17px; } /* Единственная прокручиваемая область приложения. */ .app-main { flex: 1; min-height: 0; /* без этого flex-элемент не сжимается и прокрутка уходит в body */ overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding: 14px; /* Подвал теперь в потоке — компенсировать нужно только выступающий купол FAB. */ padding-bottom: 24px; } /* Панель — обычный элемент флекс-колонки, не fixed: в мобильных браузерах со скрывающейся адресной строкой fixed-подвал дёргается при прокрутке. position: relative обязателен — на нём держится absolute-позиционирование .fab. */ .bottom-bar { position: relative; flex: none; height: var(--bottombar-height); background: var(--surface); border-top: 1px solid var(--border); display: flex; align-items: stretch; z-index: 20; } .bottom-bar .slot { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; color: var(--text-muted); background: none; border: none; font-size: 12px; touch-action: manipulation; /* без задержки/отмены тапа на мобильных */ } .bottom-bar .slot .name { color: var(--text); font-weight: 600; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .bottom-bar .spacer { width: var(--fab-width); flex: 0 0 var(--fab-width); } /* Круг создания партии: полукруг-купол, по центру разделяет слоты, базой стоит на нижнем крае экрана и поднят на передний план (z-index выше панели). Ширина вдвое больше высоты (140x70) — над кромкой панели купол выступает на 6px. */ .fab { position: absolute; left: 50%; transform: translateX(-50%); bottom: 0; width: var(--fab-width); height: var(--fab-height); border: 1px solid var(--accent); border-bottom: none; /* Радиус = половина ширины → ровный полукруг (ширина = 2× высоты). */ border-top-left-radius: calc(var(--fab-width) / 2); border-top-right-radius: calc(var(--fab-width) / 2); border-bottom-left-radius: 0; border-bottom-right-radius: 0; display: grid; place-items: center; background: var(--accent); color: #fff; box-shadow: 0 -4px 16px rgba(224, 83, 61, 0.5); z-index: 25; } .fab svg { margin-top: 8px; } .fab[aria-disabled="true"] { background: var(--surface-2); border-color: var(--border); color: var(--text-muted); box-shadow: none; } /* Таблицы / списки лидерборда */ .lb-row { display: grid; grid-template-columns: 28px 32px 1fr auto; align-items: center; gap: 10px; padding: 8px 4px; border-bottom: 1px solid var(--border); } .lb-row:last-child { border-bottom: none; } .lb-rank { font-weight: 700; color: var(--text-muted); text-align: center; } .lb-rank.top { color: var(--gold); } .lb-metrics { display: flex; gap: 12px; font-size: 13px; color: var(--text-muted); } .lb-score { font-weight: 700; color: var(--accent-2); } /* Рейтинг новичков (мало игр) — серебряный, не золотой. */ .lb-score.provisional { color: var(--silver); } /* Таблица общей статистики (сортируемая, кликабельные строки) */ .st-row, .st-head { display: grid; grid-template-columns: 26px 1fr 40px 48px 60px; align-items: center; gap: 8px; padding: 8px 2px; border-bottom: 1px solid var(--border); } .st-head { color: var(--text-muted); font-size: 12px; } .st-head button { background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 0; text-align: right; } .st-row:last-child { border-bottom: none; } .st-num { text-align: right; font-variant-numeric: tabular-nums; font-size: 14px; } .st-num.gold { color: var(--gold); font-weight: 700; } .st-player { display: flex; align-items: center; gap: 8px; min-width: 0; font-weight: 600; } .st-player .nick { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Вкладки админки: горизонтальная карусель (не ломают вёрстку при переполнении) */ .admin-tabs { flex: none; display: flex; gap: 8px; padding: 10px 14px; overflow-x: auto; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; /* Firefox */ } .admin-tabs::-webkit-scrollbar { display: none; } /* WebKit */ .admin-tabs > * { flex: 0 0 auto; white-space: nowrap; } /* Сетка медиа (фото партии) */ .media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 8px; } .media-item { position: relative; } .media-item img { width: 100%; height: 88px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border); display: block; } .media-del { position: absolute; top: 4px; right: 4px; width: 22px; height: 22px; border-radius: 50%; border: none; background: rgba(0, 0, 0, 0.6); color: #fff; display: grid; place-items: center; font-size: 12px; line-height: 1; } .participant-row { display: grid; grid-template-columns: 1fr; gap: 8px; padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); margin-bottom: 10px; /* Палитра как у карточек страницы группы: блок — surface, а surface-2 — только интерактивные элементы внутри (поля, кнопки, выпадашки). */ background: var(--surface); } .place-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 24px; padding: 0 6px; border-radius: 6px; background: var(--surface); border: 1px solid var(--border); color: var(--text); /* номер места — белым для контраста */ font-weight: 700; font-size: 13px; } .place-badge.first { background: var(--gold); color: #1a1a1a; border-color: var(--gold); } .place-badge.eliminated { background: transparent; color: var(--danger); border-color: var(--danger); } /* ─── Боковое меню (выезжает справа) ─────────────────────────────────────────── */ .drawer-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); opacity: 0; pointer-events: none; transition: opacity 0.2s ease; z-index: 60; } .drawer-overlay.open { opacity: 1; pointer-events: auto; } .side-menu { position: fixed; top: 0; right: 0; height: 100dvh; width: min(300px, 84vw); background: var(--surface); border-left: 1px solid var(--border); box-shadow: -10px 0 30px rgba(0, 0, 0, 0.5); transform: translateX(100%); transition: transform 0.22s ease; z-index: 61; display: flex; flex-direction: column; } .side-menu.open { transform: translateX(0); } .side-account { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; padding: 16px; background: none; border: none; border-bottom: 1px solid var(--border); color: var(--text); } .side-account-info { display: flex; flex-direction: column; min-width: 0; } .side-account-info b { font-size: 16px; overflow: hidden; text-overflow: ellipsis; } .side-menu-items { display: flex; flex-direction: column; padding: 8px; } .side-menu-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 12px 14px; background: none; border: none; border-radius: var(--radius-sm); color: var(--text); font-weight: 600; } .side-menu-item.danger { color: var(--danger); }