diff --git a/chess/public/styles.css b/chess/public/styles.css new file mode 100644 index 0000000..64af9f2 --- /dev/null +++ b/chess/public/styles.css @@ -0,0 +1,1488 @@ +/* ========================================================= + CHESS APP — COMPLETE STYLES + Исправленная версия: + - шахматная доска не съезжает + - адаптивность PC / планшет / телефон + - Party Mode + - чат + - часы + - кнопки сдачи / ничьей / реванша + ========================================================= */ + +:root { + --bg: #0e0f13; + --bg-2: #15171d; + + --panel: rgba(25, 27, 34, 0.94); + --panel-2: rgba(31, 34, 42, 0.96); + + --border: rgba(255, 255, 255, 0.09); + --border-hover: rgba(255, 255, 255, 0.18); + + --text: #f1f1f1; + --text-soft: #a7abb5; + --text-muted: #727782; + + --accent: #d9a441; + --accent-hover: #edbb58; + + --danger: #d95c5c; + --success: #65b97c; + --warning: #d7a84b; + + --board-light: #e6d3ad; + --board-dark: #9b754c; + + --board-size: min(78vh, 720px); + + --radius: 12px; + + --shadow: + 0 18px 50px rgba(0, 0, 0, 0.35); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + width: 100%; + min-height: 100%; + background: var(--bg); + color: var(--text); + font-family: + Inter, + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + sans-serif; +} + +body { + width: 100%; + min-height: 100vh; + min-height: 100dvh; + + background: + radial-gradient( + circle at top left, + rgba(217, 164, 65, 0.055), + transparent 32% + ), + linear-gradient( + 145deg, + #0b0c10, + #111319 55%, + #0b0c10 + ); + + color: var(--text); + + overflow-x: hidden; +} + +button, +input, +textarea { + font: inherit; +} + +button { + border: 0; + outline: 0; +} + +button:focus-visible, +input:focus-visible, +textarea:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.hidden { + display: none !important; +} + +/* ========================================================= + APP + ========================================================= */ + +#app { + width: 100%; + min-height: 100vh; + min-height: 100dvh; + + display: flex; + flex-direction: column; +} + +/* ========================================================= + HEADER + ========================================================= */ + +.topbar, +header { + width: 100%; + min-height: 64px; + + display: flex; + align-items: center; + justify-content: space-between; + + padding: 10px 18px; + + background: rgba(16, 17, 22, 0.92); + border-bottom: 1px solid var(--border); + + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + + position: sticky; + top: 0; + z-index: 100; +} + +.logo { + display: flex; + align-items: center; + gap: 10px; + + color: var(--text); + font-size: 19px; + font-weight: 700; + letter-spacing: 0.4px; +} + +.logo span { + color: var(--accent); +} + +.header-actions { + display: flex; + align-items: center; + gap: 8px; +} + +/* ========================================================= + BUTTONS + ========================================================= */ + +.btn { + min-height: 40px; + + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; + + padding: 8px 14px; + + border: 1px solid var(--border); + border-radius: 8px; + + background: rgba(255, 255, 255, 0.045); + color: var(--text); + + cursor: pointer; + + transition: + background 0.18s ease, + border-color 0.18s ease, + transform 0.15s ease, + color 0.18s ease; +} + +.btn:hover { + background: rgba(255, 255, 255, 0.085); + border-color: var(--border-hover); +} + +.btn:active { + transform: translateY(1px); +} + +.btn-primary { + background: var(--accent); + border-color: var(--accent); + color: #17120a; + font-weight: 700; +} + +.btn-primary:hover { + background: var(--accent-hover); + border-color: var(--accent-hover); +} + +.btn-danger { + color: #fff; + background: rgba(217, 92, 92, 0.13); + border-color: rgba(217, 92, 92, 0.3); +} + +.btn-danger:hover { + background: rgba(217, 92, 92, 0.22); +} + +.btn-success { + color: #fff; + background: rgba(101, 185, 124, 0.13); + border-color: rgba(101, 185, 124, 0.3); +} + +.btn-success:hover { + background: rgba(101, 185, 124, 0.22); +} + +.btn-warning { + color: #fff; + background: rgba(215, 168, 75, 0.13); + border-color: rgba(215, 168, 75, 0.3); +} + +/* ========================================================= + MAIN LAYOUT + ========================================================= */ + +.main, +main { + width: 100%; + flex: 1; + + display: grid; + grid-template-columns: + minmax(0, 1fr) + minmax(260px, 350px); + + gap: 18px; + + padding: 18px; + + align-items: start; +} + +/* ========================================================= + GAME AREA + ========================================================= */ + +.game-area { + min-width: 0; + width: 100%; + + display: flex; + flex-direction: column; + align-items: center; +} + +/* ========================================================= + PLAYER + ========================================================= */ + +.player { + width: min(var(--board-size), 100%); + + display: flex; + align-items: center; + justify-content: space-between; + + min-height: 48px; + + margin: 0 auto 8px; + padding: 7px 10px; + + background: rgba(255, 255, 255, 0.035); + + border: 1px solid var(--border); + border-radius: 9px; +} + +.player-info { + min-width: 0; + + display: flex; + align-items: center; + gap: 9px; +} + +.player-avatar { + width: 32px; + height: 32px; + + flex: 0 0 32px; + + display: flex; + align-items: center; + justify-content: center; + + border-radius: 50%; + + background: rgba(255, 255, 255, 0.08); +} + +.player-name { + min-width: 0; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + font-weight: 600; +} + +.player-status { + color: var(--text-muted); + font-size: 12px; +} + +/* ========================================================= + CHESS CLOCK + ========================================================= */ + +.clock { + min-width: 82px; + + padding: 7px 10px; + + border-radius: 7px; + + background: #0a0b0e; + border: 1px solid rgba(255, 255, 255, 0.07); + + color: #fff; + + text-align: center; + + font-family: + "SFMono-Regular", + Consolas, + "Liberation Mono", + monospace; + + font-size: 19px; + font-weight: 700; + + letter-spacing: 1px; +} + +.clock.active { + background: rgba(217, 164, 65, 0.14); + border-color: rgba(217, 164, 65, 0.45); + color: var(--accent); +} + +.clock.low { + color: var(--danger); + border-color: rgba(217, 92, 92, 0.4); +} + +/* ========================================================= + BOARD WRAPPER + ========================================================= */ + +.board-wrapper { + width: min(var(--board-size), calc(100vw - 36px)); + + aspect-ratio: 1 / 1; + + position: relative; + + flex: 0 0 auto; + + margin: 0 auto; + + border-radius: 4px; + + box-shadow: + 0 15px 40px rgba(0, 0, 0, 0.38), + 0 0 0 1px rgba(255, 255, 255, 0.07); + + overflow: hidden; +} + +/* + ВАЖНО: + Доска всегда квадратная. + Не использовать width: 100% без aspect-ratio. +*/ + +#board, +.chessboard, +.board { + width: 100% !important; + height: 100% !important; + + aspect-ratio: 1 / 1; + + display: grid !important; + + grid-template-columns: + repeat(8, minmax(0, 1fr)) !important; + + grid-template-rows: + repeat(8, minmax(0, 1fr)) !important; + + position: relative; + + overflow: hidden; +} + +/* ========================================================= + CHESS SQUARE + ========================================================= */ + +.square, +.cell, +.board-square { + width: 100%; + height: 100%; + + min-width: 0; + min-height: 0; + + position: relative; + + display: flex; + align-items: center; + justify-content: center; + + user-select: none; + -webkit-user-select: none; + + touch-action: manipulation; + + cursor: pointer; +} + +.square.light, +.cell.light, +.board-square.light { + background: var(--board-light); +} + +.square.dark, +.cell.dark, +.board-square.dark { + background: var(--board-dark); +} + +.square:hover { + filter: brightness(1.05); +} + +/* ========================================================= + CHESS PIECES + ========================================================= */ + +.piece { + width: 90%; + height: 90%; + + display: flex; + align-items: center; + justify-content: center; + + position: relative; + z-index: 4; + + font-family: + "Noto Sans Symbols 2", + "Segoe UI Symbol", + "DejaVu Sans", + sans-serif; + + font-size: clamp( + 28px, + calc(var(--board-size) / 10), + 72px + ); + + line-height: 1; + + cursor: pointer; + + user-select: none; + -webkit-user-select: none; + + transition: + transform 0.1s ease; +} + +.square:active .piece { + transform: scale(0.95); +} + +/* белые фигуры */ + +.piece.white, +.piece[data-color="w"] { + color: #fff; + + text-shadow: + 0 1px 0 #777, + 0 2px 2px rgba(0, 0, 0, 0.5); +} + +/* чёрные фигуры */ + +.piece.black, +.piece[data-color="b"] { + color: #171717; + + text-shadow: + 0 1px 0 rgba(255,255,255,0.15), + 0 2px 2px rgba(0, 0, 0, 0.35); +} + +/* ========================================================= + SELECTED SQUARE + ========================================================= */ + +.square.selected { + box-shadow: + inset 0 0 0 4px rgba(217, 164, 65, 0.85); +} + +.square.last-move { + box-shadow: + inset 0 0 0 999px rgba(217, 164, 65, 0.16); +} + +.square.legal::after { + content: ""; + + width: 23%; + height: 23%; + + position: absolute; + + top: 50%; + left: 50%; + + transform: translate(-50%, -50%); + + border-radius: 50%; + + background: rgba(25, 25, 25, 0.28); + + pointer-events: none; +} + +.square.capture::after { + content: ""; + + position: absolute; + + inset: 8%; + + border-radius: 50%; + + border: 4px solid rgba(217, 164, 65, 0.75); + + pointer-events: none; +} + +/* ========================================================= + CHECK + ========================================================= */ + +.square.check { + background: + radial-gradient( + circle, + rgba(217, 70, 70, 0.9), + rgba(180, 40, 40, 0.5) 50%, + transparent 75% + ); +} + +/* ========================================================= + BOARD COORDINATES + ========================================================= */ + +.coordinate { + position: absolute; + + z-index: 8; + + font-size: clamp(8px, 1.2vw, 13px); + + font-weight: 700; + + pointer-events: none; + + opacity: 0.7; +} + +.coordinate.rank { + top: 3px; + left: 4px; +} + +.coordinate.file { + right: 4px; + bottom: 2px; +} + +/* ========================================================= + GAME CONTROLS + ========================================================= */ + +.game-controls { + width: min(var(--board-size), 100%); + + display: grid; + + grid-template-columns: + repeat(4, minmax(0, 1fr)); + + gap: 8px; + + margin-top: 12px; +} + +.game-controls .btn { + width: 100%; +} + +/* ========================================================= + SIDEBAR + ========================================================= */ + +.sidebar { + width: 100%; + min-width: 0; + + display: flex; + flex-direction: column; + + gap: 12px; +} + +.panel { + width: 100%; + + background: var(--panel); + + border: 1px solid var(--border); + + border-radius: var(--radius); + + box-shadow: var(--shadow); + + overflow: hidden; +} + +.panel-header { + min-height: 48px; + + display: flex; + align-items: center; + justify-content: space-between; + + padding: 10px 13px; + + border-bottom: 1px solid var(--border); + + font-weight: 700; +} + +.panel-title { + font-size: 14px; +} + +.panel-content { + padding: 12px; +} + +/* ========================================================= + GAME INFO + ========================================================= */ + +.game-info { + display: grid; + grid-template-columns: 1fr 1fr; + + gap: 8px; +} + +.info-item { + padding: 10px; + + background: rgba(255, 255, 255, 0.035); + + border: 1px solid var(--border); + + border-radius: 8px; +} + +.info-label { + color: var(--text-muted); + font-size: 11px; +} + +.info-value { + margin-top: 3px; + + font-weight: 700; +} + +/* ========================================================= + PARTY MODE + ========================================================= */ + +.party { + width: 100%; +} + +.party-users { + display: flex; + flex-direction: column; + gap: 7px; + + max-height: 250px; + overflow-y: auto; +} + +.party-user { + min-height: 40px; + + display: flex; + align-items: center; + gap: 9px; + + padding: 7px 9px; + + background: rgba(255, 255, 255, 0.035); + + border: 1px solid var(--border); + + border-radius: 8px; +} + +.party-user-avatar { + width: 28px; + height: 28px; + + flex: 0 0 28px; + + display: flex; + align-items: center; + justify-content: center; + + border-radius: 50%; + + background: rgba(255, 255, 255, 0.08); +} + +.party-user-name { + min-width: 0; + + flex: 1; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.party-user-status { + width: 8px; + height: 8px; + + border-radius: 50%; + + background: var(--success); +} + +/* ========================================================= + SPECTATORS + ========================================================= */ + +.spectators { + color: var(--text-soft); + font-size: 13px; +} + +.spectators strong { + color: var(--text); +} + +/* ========================================================= + CHAT + ========================================================= */ + +.chat { + display: flex; + flex-direction: column; + + height: 380px; + min-height: 280px; +} + +.chat-messages { + flex: 1; + + min-height: 0; + + overflow-y: auto; + + display: flex; + flex-direction: column; + + gap: 7px; + + padding: 10px; +} + +.chat-message { + max-width: 88%; + + padding: 7px 9px; + + background: rgba(255, 255, 255, 0.05); + + border: 1px solid var(--border); + + border-radius: 8px; + + font-size: 13px; + + overflow-wrap: anywhere; +} + +.chat-message.own { + align-self: flex-end; + + background: rgba(217, 164, 65, 0.12); + + border-color: rgba(217, 164, 65, 0.25); +} + +.chat-author { + margin-bottom: 2px; + + color: var(--accent); + + font-size: 11px; + font-weight: 700; +} + +.chat-input-area { + display: flex; + gap: 7px; + + padding: 9px; + + border-top: 1px solid var(--border); +} + +.chat-input { + min-width: 0; + flex: 1; + + height: 40px; + + padding: 0 10px; + + border: 1px solid var(--border); + + border-radius: 8px; + + background: rgba(0, 0, 0, 0.2); + + color: var(--text); + + outline: none; +} + +.chat-input::placeholder { + color: var(--text-muted); +} + +.chat-input:focus { + border-color: rgba(217, 164, 65, 0.5); +} + +.chat-send { + width: 40px; + height: 40px; + + flex: 0 0 40px; + + display: flex; + align-items: center; + justify-content: center; + + border-radius: 8px; + + background: var(--accent); + color: #17120a; + + cursor: pointer; +} + +/* ========================================================= + MODAL + ========================================================= */ + +.modal { + position: fixed; + + inset: 0; + + z-index: 1000; + + display: flex; + align-items: center; + justify-content: center; + + padding: 18px; + + background: rgba(0, 0, 0, 0.68); + + backdrop-filter: blur(7px); + -webkit-backdrop-filter: blur(7px); +} + +.modal.hidden { + display: none !important; +} + +.modal-content { + width: min(500px, 100%); + + max-height: calc(100vh - 36px); + max-height: calc(100dvh - 36px); + + overflow-y: auto; + + padding: 20px; + + background: var(--panel-2); + + border: 1px solid var(--border); + + border-radius: 12px; + + box-shadow: + 0 30px 80px rgba(0, 0, 0, 0.55); +} + +.modal-title { + margin-bottom: 14px; + + font-size: 20px; + font-weight: 700; +} + +.modal-actions { + display: flex; + justify-content: flex-end; + gap: 8px; + + margin-top: 18px; +} + +/* ========================================================= + GAME RESULT + ========================================================= */ + +.game-result { + position: absolute; + + inset: 0; + + z-index: 50; + + display: flex; + align-items: center; + justify-content: center; + + background: rgba(0, 0, 0, 0.58); + + backdrop-filter: blur(3px); +} + +.game-result-card { + width: min(350px, calc(100% - 30px)); + + padding: 22px; + + text-align: center; + + background: rgba(20, 21, 26, 0.96); + + border: 1px solid var(--border); + + border-radius: 12px; + + box-shadow: var(--shadow); +} + +.game-result-title { + font-size: 24px; + font-weight: 800; +} + +.game-result-text { + margin-top: 7px; + + color: var(--text-soft); +} + +.game-result-actions { + display: flex; + + gap: 8px; + + margin-top: 18px; +} + +.game-result-actions .btn { + flex: 1; +} + +/* ========================================================= + NOTIFICATIONS + ========================================================= */ + +.toast-container { + position: fixed; + + right: 16px; + bottom: 16px; + + z-index: 2000; + + display: flex; + flex-direction: column; + gap: 8px; + + width: min(350px, calc(100vw - 32px)); +} + +.toast { + padding: 11px 13px; + + background: rgba(27, 29, 36, 0.96); + + border: 1px solid var(--border); + + border-radius: 9px; + + box-shadow: var(--shadow); + + font-size: 13px; +} + +/* ========================================================= + SCROLLBARS + ========================================================= */ + +* { + scrollbar-width: thin; + scrollbar-color: rgba(255,255,255,0.15) transparent; +} + +::-webkit-scrollbar { + width: 7px; + height: 7px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: rgba(255,255,255,0.15); + border-radius: 10px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(255,255,255,0.25); +} + +/* ========================================================= + TABLET + ========================================================= */ + +@media (max-width: 1100px) { + + :root { + --board-size: min(72vw, 680px); + } + + .main, + main { + grid-template-columns: + minmax(0, 1fr) + 300px; + + gap: 12px; + + padding: 12px; + } + + .game-controls { + grid-template-columns: + repeat(2, minmax(0, 1fr)); + } + +} + +/* ========================================================= + SMALL TABLET / LARGE PHONE + ========================================================= */ + +@media (max-width: 820px) { + + :root { + --board-size: min( + calc(100vw - 24px), + 680px + ); + } + + .main, + main { + display: flex; + flex-direction: column; + + width: 100%; + + padding: 10px; + } + + .game-area { + width: 100%; + } + + .sidebar { + width: 100%; + + display: grid; + + grid-template-columns: + repeat(2, minmax(0, 1fr)); + + align-items: start; + } + + .sidebar .chat { + grid-column: 1 / -1; + } + + .board-wrapper { + width: min( + calc(100vw - 20px), + 680px + ); + } + + .game-controls { + width: min( + calc(100vw - 20px), + 680px + ); + } +} + +/* ========================================================= + PHONE + ========================================================= */ + +@media (max-width: 600px) { + + :root { + --board-size: calc(100vw - 16px); + } + + body { + overflow-x: hidden; + } + + .topbar, + header { + min-height: 54px; + + padding: + 8px 9px; + + position: relative; + } + + .logo { + font-size: 16px; + } + + .header-actions { + gap: 5px; + } + + .header-actions .btn { + min-height: 36px; + padding: 6px 9px; + + font-size: 12px; + } + + .main, + main { + width: 100%; + + padding: 8px; + + gap: 10px; + } + + .board-wrapper { + width: calc(100vw - 16px); + max-width: none; + + border-radius: 2px; + } + + #board, + .chessboard, + .board { + width: 100% !important; + height: 100% !important; + } + + .piece { + width: 94%; + height: 94%; + + font-size: calc( + (100vw - 16px) / 10 + ); + } + + .player { + width: calc(100vw - 16px); + + min-height: 43px; + + padding: 5px 7px; + + margin-bottom: 6px; + } + + .player-avatar { + width: 27px; + height: 27px; + + flex-basis: 27px; + } + + .player-name { + max-width: 150px; + + font-size: 13px; + } + + .player-status { + font-size: 10px; + } + + .clock { + min-width: 68px; + + padding: 5px 7px; + + font-size: 15px; + } + + .game-controls { + width: calc(100vw - 16px); + + grid-template-columns: + repeat(2, minmax(0, 1fr)); + + gap: 6px; + + margin-top: 8px; + } + + .game-controls .btn { + min-height: 40px; + + padding: 7px 8px; + + font-size: 12px; + } + + .sidebar { + display: flex; + + width: 100%; + } + + .panel { + border-radius: 9px; + } + + .chat { + height: 330px; + } + + .modal { + padding: 10px; + } + + .modal-content { + padding: 16px; + + border-radius: 10px; + } + + .modal-actions { + flex-direction: column; + } + + .modal-actions .btn { + width: 100%; + } + + .game-result-actions { + flex-direction: column; + } + + .game-result-actions .btn { + width: 100%; + } +} + +/* ========================================================= + VERY SMALL PHONES + ========================================================= */ + +@media (max-width: 380px) { + + .main, + main { + padding: 5px; + } + + .board-wrapper, + .player, + .game-controls { + width: calc(100vw - 10px); + } + + .piece { + font-size: calc( + (100vw - 10px) / 10 + ); + } + + .clock { + min-width: 62px; + + font-size: 14px; + } + + .player-name { + max-width: 105px; + } + + .game-controls .btn { + font-size: 11px; + padding: 6px; + } +} + +/* ========================================================= + LANDSCAPE PHONE + ========================================================= */ + +@media (max-height: 600px) and (orientation: landscape) { + + :root { + --board-size: min( + calc(100vh - 90px), + calc(100vw - 250px) + ); + } + + .topbar, + header { + min-height: 46px; + padding: 5px 10px; + } + + .main, + main { + display: flex; + flex-direction: row; + + align-items: flex-start; + + padding: 8px; + } + + .game-area { + flex: 1; + } + + .sidebar { + width: 280px; + + flex: 0 0 280px; + + max-height: calc(100vh - 62px); + + overflow-y: auto; + } + + .board-wrapper { + width: var(--board-size); + } + + .player, + .game-controls { + width: var(--board-size); + } + + .chat { + height: 260px; + } +} + +/* ========================================================= + SAFE AREA — ANDROID / IOS + ========================================================= */ + +@supports (padding: env(safe-area-inset-bottom)) { + + .topbar, + header { + padding-top: + max( + 8px, + env(safe-area-inset-top) + ); + } + + body { + padding-bottom: + env(safe-area-inset-bottom); + } + +} + +/* ========================================================= + REDUCED MOTION + ========================================================= */ + +@media (prefers-reduced-motion: reduce) { + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} \ No newline at end of file