:root { --green: #2d6a4f; --green-light: #40916c; --green-dark: #1b4332; --bg: #1a1a2e; --surface: #16213e; --surface2: #0f3460; --text: #e8f5e9; --text-muted: #a8c5a0; --accent: #52b788; --danger: #e63946; --nav-height: 64px; } * { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; } html, body { height: 100%; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--text); font-size: 16px; } body { padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom)); } /* ── Layout ── */ .page { max-width: 480px; margin: 0 auto; padding: 1.5rem 1rem; } /* ── PWA Install Banner ── */ #pwa-banner { position: fixed; top: 0; left: 0; right: 0; z-index: 200; background: var(--green-dark); border-bottom: 1px solid var(--green-light); padding: 0.65rem 1rem; align-items: center; justify-content: space-between; gap: 0.75rem; font-size: 0.85rem; color: var(--text); } #pwa-banner-android, #pwa-banner-ios { width: 100%; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; } .pwa-banner-actions { display: flex; gap: 0.4rem; flex-shrink: 0; } .pwa-install-btn { padding: 0.35rem 0.75rem; border-radius: 0.4rem; border: 1px solid var(--green-light); background: transparent; color: var(--text); font-size: 0.8rem; cursor: pointer; } .pwa-install-primary { background: var(--accent); border-color: var(--accent); color: #000; font-weight: 600; } /* ── Bottom Nav ── */ .bottom-nav { position: fixed; bottom: 0; left: 0; right: 0; height: calc(var(--nav-height) + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom); background: var(--surface); border-top: 1px solid var(--surface2); display: flex; justify-content: space-around; align-items: center; z-index: 100; } .nav-item { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; flex: 1; height: var(--nav-height); text-decoration: none; color: var(--text-muted); font-size: 0.65rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.04em; transition: color 0.15s; min-width: 44px; } .nav-item:hover, .nav-item.active { color: var(--accent); } .nav-icon { font-size: 1.75rem; line-height: 1; display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; } .nav-icon svg { width: 26px; height: 26px; } .nav-avatar-img { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; } /* ── Cards ── */ .card { background: var(--surface); border-radius: 12px; padding: 1.25rem; margin-bottom: 1rem; } /* ── Forms ── */ .form-group { margin-bottom: 1.25rem; } label { display: block; font-size: 0.85rem; color: var(--text-muted); margin-bottom: 0.4rem; font-weight: 500; } input[type="text"], input[type="email"], input[type="number"] { width: 100%; padding: 0.75rem 1rem; border: 1px solid var(--surface2); border-radius: 8px; background: var(--bg); color: var(--text); font-size: 1rem; outline: none; transition: border-color 0.15s; } input:focus { border-color: var(--accent); } /* ── Buttons ── */ .btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.85rem 1.5rem; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; text-decoration: none; transition: opacity 0.15s; width: 100%; } .btn:active { opacity: 0.8; } .btn-primary { background: var(--green); color: #fff; } .btn-danger { background: var(--danger); color: #fff; } .btn-ghost { background: transparent; color: var(--accent); border: 1px solid var(--accent); } /* ── Alerts ── */ .alert { padding: 0.75rem 1rem; border-radius: 8px; margin-bottom: 1rem; font-size: 0.9rem; } .alert-error { background: rgba(230,57,70,0.15); color: #ff8fa3; border: 1px solid rgba(230,57,70,0.3); } .alert-success { background: rgba(82,183,136,0.15); color: var(--accent); border: 1px solid rgba(82,183,136,0.3); } /* ── Avatar picker ── */ .avatar-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.5rem; } .avatar-option input[type="radio"] { display: none; } .avatar-option label { display: flex; align-items: center; justify-content: center; font-size: 1.75rem; width: 100%; aspect-ratio: 1; border-radius: 8px; border: 2px solid transparent; background: var(--bg); cursor: pointer; transition: border-color 0.15s; } .avatar-option input[type="radio"]:checked + label { border-color: var(--accent); background: rgba(82,183,136,0.15); } /* ── Avatar tabs ── */ .avatar-tabs { display: flex; gap: 0.5rem; margin-bottom: 0.25rem; } .avatar-tab { flex: 1; padding: 0.5rem; border: 1px solid var(--surface2); border-radius: 6px; background: var(--bg); color: var(--text-muted); font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: color 0.15s, border-color 0.15s; } .avatar-tab.active { border-color: var(--accent); color: var(--accent); } .file-input { width: 100%; padding: 0.65rem; border: 1px dashed var(--surface2); border-radius: 8px; background: var(--bg); color: var(--text-muted); font-size: 0.9rem; cursor: pointer; } .file-input::-webkit-file-upload-button { background: var(--green); color: #fff; border: none; padding: 0.4rem 0.75rem; border-radius: 4px; cursor: pointer; margin-right: 0.75rem; } .avatar-preview { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; border: 2px solid var(--accent); } /* ── Page header ── */ .page-header { margin-bottom: 1.5rem; } .page-header h1 { font-size: 1.5rem; font-weight: 700; } .page-header p { color: var(--text-muted); font-size: 0.9rem; margin-top: 0.25rem; } /* ── Empty state ── */ .empty-state { text-align: center; padding: 3rem 1rem; color: var(--text-muted); } .empty-state .empty-icon { font-size: 3rem; margin-bottom: 1rem; } /* ── Table ── */ .data-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; } .data-table th { text-align: left; color: var(--text-muted); padding: 0.5rem 0; border-bottom: 1px solid var(--surface2); font-weight: 500; } .data-table td { padding: 0.6rem 0; border-bottom: 1px solid rgba(255,255,255,0.05); } /* ── Login page ── */ .login-container { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem 1.5rem; } .login-logo { font-size: 3rem; margin-bottom: 0.5rem; } .login-title { font-size: 1.75rem; font-weight: 700; margin-bottom: 0.25rem; } .login-subtitle { color: var(--text-muted); margin-bottom: 2rem; font-size: 0.9rem; } .login-card { width: 100%; max-width: 360px; } /* ── Game card (list) ── */ .game-card { transition: opacity 0.15s; } .game-card:active { opacity: 0.7; } .status-badge { font-size: 0.7rem; font-weight: 600; text-transform: uppercase; padding: 0.2rem 0.5rem; border-radius: 4px; letter-spacing: 0.05em; } .status-active { background: rgba(82,183,136,0.2); color: var(--accent); } .status-completed { background: rgba(255,255,255,0.08); color: var(--text-muted); } .status-lobby { background: rgba(255,200,80,0.15); color: #ffc850; } /* ── New game form ── */ .radio-card { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 0.35rem; padding: 0.75rem; border: 2px solid var(--surface2); border-radius: 10px; cursor: pointer; font-size: 1rem; font-weight: 600; transition: border-color 0.15s; } .radio-card input { display: none; } .radio-card:has(input:checked) { border-color: var(--accent); color: var(--accent); } .player-list { display: flex; flex-direction: column; gap: 0.5rem; } .player-option { display: flex; align-items: center; gap: 0.75rem; padding: 0.65rem 0.75rem; border: 2px solid var(--surface2); border-radius: 10px; cursor: pointer; transition: border-color 0.15s; } .player-option:has(input:checked) { border-color: var(--accent); } .player-option input { display: none; } .player-avatar { font-size: 1.5rem; } .player-name { flex: 1; font-weight: 500; } /* ── Game screen ── */ .game-header { padding: 0.75rem 1rem 0.5rem; background: var(--surface); border-bottom: 1px solid var(--surface2); flex-shrink: 0; } .hole-label { font-size: 1rem; font-weight: 700; } .icon-btn { background: none; border: none; color: var(--text); font-size: 1.75rem; padding: 0 0.5rem; cursor: pointer; line-height: 1; opacity: 0.8; } .icon-btn:disabled { opacity: 0.2; cursor: default; } .swipe-container { flex: 1; overflow: hidden; position: relative; } .swipe-panel { position: absolute; inset: 0; opacity: 0; pointer-events: none; transform: translateX(30px); transition: opacity 0.2s, transform 0.2s; } .swipe-panel.active { opacity: 1; pointer-events: all; transform: translateX(0); } .panel-scroll { height: 100%; overflow-y: auto; padding: 1rem; -webkit-overflow-scrolling: touch; } /* ── Score sections ── */ .score-section { margin-bottom: 1.25rem; } .score-label { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; } .score-badge { font-size: 0.65rem; font-weight: 800; letter-spacing: 0.08em; padding: 0.2rem 0.5rem; border-radius: 4px; } .bingo-badge { background: rgba(255,190,50,0.2); color: #ffbe32; } .bango-badge { background: rgba(82,183,136,0.2); color: var(--accent); } .bongo-badge { background: rgba(120,120,255,0.2); color: #9090ff; } .score-desc { color: var(--text-muted); font-size: 0.82rem; } .player-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; } .player-btn { display: flex; align-items: center; gap: 0.4rem; padding: 0.55rem 0.85rem; border: 2px solid var(--surface2); border-radius: 10px; background: var(--surface); color: var(--text); cursor: pointer; font-size: 0.9rem; transition: border-color 0.15s, background 0.15s; } .player-btn.selected { border-color: var(--accent); background: rgba(82,183,136,0.15); } .pbtn-avatar { font-size: 1.2rem; } .pbtn-name { font-weight: 500; } .pbtn-pts { color: var(--accent); font-weight: 700; font-size: 0.8rem; } .save-btn { margin-top: 0.5rem; } .save-btn.saved:not(.dirty) { background: var(--green-dark); opacity: 0.8; } .btn-skip { background: none; border: 1px solid var(--surface2); color: var(--text-muted); border-radius: 6px; padding: 0.3rem 0.75rem; font-size: 0.8rem; cursor: pointer; } .btn-skip.skipped { border-color: var(--danger); color: #ff8fa3; } /* ── Scorecard table ── */ .scorecard { width: 100%; border-collapse: collapse; font-size: 0.85rem; } .scorecard th { text-align: center; padding: 0.4rem 0.3rem; border-bottom: 1px solid var(--surface2); color: var(--text-muted); font-weight: 600; } .scorecard th:first-child { text-align: left; } .scorecard td { text-align: center; padding: 0.45rem 0.3rem; border-bottom: 1px solid rgba(255,255,255,0.04); } .hole-num { text-align: left; color: var(--text-muted); font-weight: 600; } .score-cell { font-weight: 500; } .hole-skipped td { opacity: 0.35; } .totals-row td { font-weight: 700; color: var(--accent); padding-top: 0.6rem; border-top: 1px solid var(--surface2); } /* ── View toggle ── */ .view-toggle { display: flex; border-top: 1px solid var(--surface2); background: var(--surface); flex-shrink: 0; } .view-toggle button { flex: 1; padding: 0.6rem; background: none; border: none; color: var(--text-muted); font-size: 0.85rem; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; transition: color 0.15s, border-color 0.15s; } .view-toggle button.active { color: var(--accent); border-bottom-color: var(--accent); } /* ── Avatar crop modal ── */ [x-cloak] { display: none !important; } .crop-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.8); z-index: 200; display: flex; align-items: center; justify-content: center; padding: 1rem; } .crop-modal { background: var(--surface); border-radius: 14px; width: 100%; max-width: 380px; overflow: hidden; } .crop-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 0.85rem 1rem; border-bottom: 1px solid var(--surface2); font-weight: 600; } .crop-container { width: 100%; aspect-ratio: 1; background: #000; overflow: hidden; } /* Circular crop preview overlay */ .crop-container .cropper-view-box, .crop-container .cropper-face { border-radius: 50%; } .crop-hint { text-align: center; color: var(--text-muted); font-size: 0.78rem; padding: 0.5rem 1rem; } .crop-modal-actions { display: flex; gap: 0.75rem; padding: 0.75rem 1rem 1rem; } /* ── File input button ── */ .file-input-label { display: inline-flex; align-items: center; justify-content: center; padding: 0.65rem 1rem; border: 1px dashed var(--surface2); border-radius: 8px; background: var(--bg); color: var(--text-muted); font-size: 0.9rem; cursor: pointer; width: 100%; transition: border-color 0.15s, color 0.15s; } .file-input-label:hover { border-color: var(--accent); color: var(--accent); } /* ── Per-player score card ── */ .player-score-card { display: flex; flex-direction: column; gap: 0.55rem; background: var(--surface); border-radius: 12px; padding: 0.75rem 0.85rem; margin-bottom: 0.6rem; } .psc-name { font-weight: 700; font-size: 1rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .psc-controls { display: flex; align-items: center; gap: 0.5rem; } .drag-handle { color: var(--text-muted); font-size: 1.1rem; cursor: grab; margin-right: 0.5rem; user-select: none; touch-action: none; } .drag-handle:active { cursor: grabbing; } /* ── Golf score markers ── */ .score-hio, .score-eagle, .score-birdie, .score-bogey, .score-double-bogey { display: inline-flex; align-items: center; justify-content: center; width: 1.6rem; height: 1.6rem; font-weight: 600; } .score-hio { background: gold; color: #000; border-radius: 50%; } .score-eagle { border: 2px solid #3b82f6; border-radius: 50%; outline: 2px solid #3b82f6; outline-offset: 2px; color: #3b82f6; } .score-birdie { border: 2px solid var(--green-light); border-radius: 50%; color: var(--green-light); } .score-bogey { border: 2px solid var(--danger); color: var(--danger); } .score-double-bogey { border: 2px solid #888; outline: 2px solid #888; outline-offset: 2px; color: #888; } .skin-winner { font-weight: 700; color: var(--accent); } .drag-source { opacity: 0.4; } .drag-over { outline: 2px solid var(--accent); border-radius: 0.65rem; } .stroke-controls { display: inline-flex; flex-direction: row; flex-wrap: nowrap; align-items: stretch; flex-shrink: 0; background: var(--bg); border: 1px solid var(--surface2); border-radius: 8px; overflow: hidden; vertical-align: middle; } .stroke-btn { width: 2.8rem; min-height: 3.2rem; border: none; background: none; color: var(--text); font-size: 1.25rem; font-weight: 700; cursor: pointer; user-select: none; display: flex; align-items: center; justify-content: center; transition: background 0.1s; } .stroke-btn:active { background: var(--surface2); } .stroke-val { min-width: 2.4rem; min-height: 3.2rem; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; font-weight: 700; user-select: none; flex-shrink: 0; } .bbb-btn { height: 3.2rem; padding: 0 0.75rem; border-radius: 8px; border: 2px solid transparent; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.03em; cursor: pointer; transition: background 0.15s, border-color 0.15s; background: var(--bg); color: var(--text-muted); white-space: nowrap; flex-shrink: 0; } .bbb-btn:active { opacity: 0.7; } .bingo-btn.active { background: rgba(255,190,50,0.15); border-color: #ffbe32; color: #ffbe32; } .bango-btn.active { background: rgba(82,183,136,0.15); border-color: var(--accent); color: var(--accent); } .bongo-btn.active { background: rgba(120,120,255,0.15); border-color: #9090ff; color: #9090ff; } .bingo-btn { border-color: rgba(255,190,50,0.3); } .bango-btn { border-color: rgba(82,183,136,0.3); } .bongo-btn { border-color: rgba(120,120,255,0.3); } /* ── Scorecard sub-toggle ── */ .scorecard-toggle { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; } .scorecard-toggle button { flex: 1; padding: 0.45rem; background: var(--bg); border: 1px solid var(--surface2); border-radius: 6px; color: var(--text-muted); font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: color 0.15s, border-color 0.15s; } .scorecard-toggle button.active { border-color: var(--accent); color: var(--accent); } /* ── Admin sub-navigation ── */ .admin-subnav { display: flex; gap: 0.5rem; margin-bottom: 1.25rem; } .admin-subnav-item { padding: 0.4rem 1rem; border-radius: 2rem; font-size: 0.85rem; font-weight: 500; text-decoration: none; color: var(--text-muted); border: 1px solid var(--border); transition: background 0.15s, color 0.15s; } .admin-subnav-item.active, .admin-subnav-item:hover { background: var(--accent); color: #fff; border-color: var(--accent); } /* ── Hole par grid (course admin) ── */ .hole-pars-grid { display: grid; grid-template-columns: repeat(9, 1fr); gap: 0.4rem; } .hole-par-cell { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; } .hole-par-label { font-size: 0.7rem; color: var(--text-muted); font-weight: 600; } .hole-par-select { width: 100%; padding: 0.35rem 0.1rem; text-align: center; border-radius: 0.4rem; border: 1px solid var(--border); background: var(--surface); color: var(--text); font-size: 0.9rem; } /* ── Table action buttons ── */ .btn-table-action { display: inline-block; padding: 0.25rem 0.6rem; border-radius: 5px; font-size: 0.78rem; font-weight: 600; cursor: pointer; text-decoration: none; border: 1px solid var(--surface2); background: var(--bg); color: var(--text-muted); margin-left: 0.25rem; } .btn-table-action.danger { border-color: rgba(230,57,70,0.4); color: #ff8fa3; } /* ── Dashboard stats ── */ .stats-row { display: flex; gap: 0.75rem; margin-bottom: 1.5rem; } .stat-card { flex: 1; background: var(--surface); border-radius: 12px; padding: 1rem 0.75rem; text-align: center; } .stat-value { font-size: 1.75rem; font-weight: 800; color: var(--accent); line-height: 1; } .stat-label { font-size: 0.7rem; color: var(--text-muted); margin-top: 0.3rem; text-transform: uppercase; letter-spacing: 0.05em; } /* ── Game result card ── */ .game-result-card { margin-bottom: 0.75rem; } .result-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0; font-size: 0.9rem; } .result-winner { color: var(--accent); font-weight: 600; } .result-rank { width: 1.4rem; text-align: center; font-size: 0.85rem; color: var(--text-muted); } .result-winner .result-rank { color: var(--accent); } .result-avatar { font-size: 1.1rem; line-height: 1; } .result-name { flex: 1; color: var(--text); font-weight: 500; } .result-winner .result-name { color: var(--accent); } .result-pts { font-weight: 600; font-size: 0.85rem; color: var(--text); } .result-winner .result-pts { color: var(--accent); }