dc051cbe45
Layout & engine borrowed from Shelem: waiting-room menu with seat swap and force-start, game menu with bar-to-bottom, escalating turn reminder, three hand modes defaulting to fan on touch, card-count badges instead of card backs, leave buttons inside phase overlays, version footer with tap-to-update. Seats now run clockwise from the viewer (left = +1, across = +2, right = +3) so play flows anti-clockwise on screen as the server advances it; the pass exchange was flipped to match, otherwise "pass left" delivered to the right. Game history: finished games are saved with a per-hand breakdown, readable from the profile and shown on the end-of-hand and end-of-game screens. Card flashing: the service worker precaches all 52 faces, each face is decoded once into a template image, and the renderers reconcile against existing DOM instead of rebuilding it, so card nodes and their images survive a re-render. Card-count integrity: a seat can no longer put two cards into one trick, and the server snapshots each trick start and rewinds to the last sound state if the four hands ever drift apart. Leaderboard: ranked by win rate with a 5-game minimum; below-threshold players are listed unranked. Moon shots are now recorded instead of always zero, and stat reads no longer create and persist a row per user on every request. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1292 lines
38 KiB
CSS
1292 lines
38 KiB
CSS
/* ── Reset & Base ──────────────────────────────── */
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
:root {
|
|
--felt: #1d6b3a;
|
|
--felt-dark: #133025;
|
|
--felt-light: #268847;
|
|
--card-w: 68px;
|
|
--card-h: 98px;
|
|
--radius: 8px;
|
|
--shadow: 0 2px 8px rgba(0,0,0,.4);
|
|
--gold: #f5c518;
|
|
--accent: #c8860a;
|
|
--red: #d32f2f;
|
|
--muted: rgba(255,255,255,.55);
|
|
--team-a: #4fc3f7; /* leading player highlight */
|
|
--team-b: #ef9a9a;
|
|
--black: #111;
|
|
--heart-red: #e53935;
|
|
}
|
|
|
|
html, body {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
font-family: 'Segoe UI', system-ui, sans-serif;
|
|
background: var(--felt-dark);
|
|
color: #fff;
|
|
touch-action: manipulation;
|
|
}
|
|
|
|
/* ── Screens ──────────────────────────────────── */
|
|
.screen { display: none; }
|
|
.screen.active {
|
|
display: flex; flex-direction: column;
|
|
height: 100vh; /* fallback */
|
|
height: 100dvh; /* modern: excludes browser chrome / address bar */
|
|
}
|
|
|
|
/* ── Lobby ────────────────────────────────────── */
|
|
#screen-lobby {
|
|
justify-content: center;
|
|
align-items: center;
|
|
background: radial-gradient(ellipse at center, #1d5c3a 0%, var(--felt-dark) 100%);
|
|
}
|
|
|
|
.lobby-box {
|
|
background: rgba(0,0,0,.5);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 16px;
|
|
padding: 28px 34px;
|
|
width: min(430px, 94vw);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
max-height: 96vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.logo {
|
|
font-size: 2.4rem;
|
|
text-align: center;
|
|
color: var(--gold);
|
|
text-shadow: 0 2px 12px rgba(200,130,10,.6);
|
|
letter-spacing: 2px;
|
|
}
|
|
|
|
.tagline {
|
|
text-align: center;
|
|
color: rgba(255,255,255,.55);
|
|
font-size: .85rem;
|
|
margin-top: -8px;
|
|
}
|
|
|
|
/* ── Auth bar ─────────────────────────────────── */
|
|
.auth-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 8px;
|
|
padding: 6px 10px;
|
|
background: rgba(255,255,255,.06);
|
|
border: 1px solid rgba(255,255,255,.1);
|
|
border-radius: 10px;
|
|
font-size: .8rem;
|
|
}
|
|
.auth-status { color: var(--muted); }
|
|
.auth-bar-actions { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
|
|
.btn-text {
|
|
background: none; border: none; color: var(--gold);
|
|
cursor: pointer; font-size: .78rem; padding: 2px 5px;
|
|
text-decoration: underline;
|
|
}
|
|
.btn-text:hover { color: #fff; }
|
|
|
|
/* ── Tabs ─────────────────────────────────────── */
|
|
.lobby-tabs { display: flex; gap: 6px; }
|
|
.tab-btn {
|
|
flex: 1;
|
|
padding: 7px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 8px;
|
|
color: var(--muted);
|
|
cursor: pointer;
|
|
font-size: .85rem;
|
|
transition: background .15s;
|
|
}
|
|
.tab-btn.active, .tab-btn:hover { background: rgba(255,255,255,.18); color: #fff; }
|
|
.tab-panel { display: none; flex-direction: column; gap: 10px; }
|
|
.tab-panel.active { display: flex; }
|
|
|
|
/* ── Fields & inputs ──────────────────────────── */
|
|
.field { display: flex; flex-direction: column; gap: 5px; }
|
|
.field label { font-size: .8rem; color: var(--muted); }
|
|
.field small { color: rgba(255,255,255,.4); font-size: .72rem; }
|
|
input[type=text], input[type=password], input[type=email] {
|
|
width: 100%;
|
|
padding: 9px 12px;
|
|
background: rgba(255,255,255,.09);
|
|
border: 1px solid rgba(255,255,255,.18);
|
|
border-radius: 8px;
|
|
color: #fff;
|
|
font-size: .9rem;
|
|
outline: none;
|
|
}
|
|
input:focus { border-color: var(--gold); }
|
|
|
|
/* ── Visibility toggle (Private / Public) ─────── */
|
|
.visibility-row { display: flex; gap: 6px; }
|
|
.visibility-btn {
|
|
flex: 1;
|
|
padding: 8px 6px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.14);
|
|
border-radius: 8px;
|
|
color: var(--muted);
|
|
cursor: pointer;
|
|
font-size: .82rem;
|
|
text-align: center;
|
|
transition: background .15s;
|
|
}
|
|
.visibility-btn.active, .visibility-btn:hover {
|
|
background: rgba(245,197,24,.2);
|
|
border-color: var(--gold);
|
|
color: var(--gold);
|
|
}
|
|
|
|
/* ── Mode / score buttons ─────────────────────── */
|
|
.mode-row, .score-row { display: flex; gap: 6px; }
|
|
.mode-btn, .score-btn {
|
|
flex: 1;
|
|
padding: 8px 6px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.14);
|
|
border-radius: 8px;
|
|
color: var(--muted);
|
|
cursor: pointer;
|
|
font-size: .82rem;
|
|
text-align: center;
|
|
transition: background .15s;
|
|
}
|
|
.mode-btn small { display: block; font-size: .72rem; color: rgba(255,255,255,.4); margin-top: 2px; }
|
|
.mode-btn.active, .mode-btn:hover,
|
|
.score-btn.active, .score-btn:hover {
|
|
background: rgba(245,197,24,.2);
|
|
border-color: var(--gold);
|
|
color: var(--gold);
|
|
}
|
|
|
|
/* ── Buttons ──────────────────────────────────── */
|
|
.btn-primary {
|
|
padding: 10px;
|
|
background: rgba(245,197,24,.25);
|
|
border: 1px solid rgba(245,197,24,.55);
|
|
border-radius: 10px;
|
|
color: var(--gold);
|
|
font-size: .95rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background .15s;
|
|
}
|
|
.btn-primary:hover { background: rgba(245,197,24,.38); }
|
|
.btn-primary:disabled { opacity: .4; cursor: default; }
|
|
|
|
.btn-secondary {
|
|
padding: 9px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.16);
|
|
border-radius: 10px;
|
|
color: var(--muted);
|
|
font-size: .9rem;
|
|
cursor: pointer;
|
|
transition: background .15s;
|
|
}
|
|
.btn-secondary:hover { background: rgba(255,255,255,.15); }
|
|
|
|
.divider { border: none; border-top: 1px solid rgba(255,255,255,.1); margin: 2px 0; }
|
|
.error-msg { color: #ff6b6b; font-size: .82rem; min-height: 16px; }
|
|
.hint { color: var(--muted); font-size: .82rem; text-align: center; }
|
|
|
|
/* ── Waiting Room ─────────────────────────────── */
|
|
#screen-waiting {
|
|
justify-content: center;
|
|
align-items: center;
|
|
background: radial-gradient(ellipse at center, #1d5c3a 0%, var(--felt-dark) 100%);
|
|
}
|
|
.waiting-box {
|
|
background: rgba(0,0,0,.48);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 16px;
|
|
padding: 28px 34px;
|
|
width: min(380px, 94vw);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
.btn-leave-screen {
|
|
align-self: flex-start;
|
|
background: none; border: none; color: var(--muted);
|
|
cursor: pointer; font-size: .85rem;
|
|
padding: 0; text-decoration: underline;
|
|
}
|
|
.btn-leave-screen:hover { color: #fff; }
|
|
|
|
.room-code-box {
|
|
display: flex; align-items: center; gap: 8px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.14);
|
|
border-radius: 10px;
|
|
padding: 8px 14px;
|
|
}
|
|
.room-code-box .label { font-size: .75rem; color: var(--muted); }
|
|
.room-code { font-size: 1.5rem; font-weight: 700; letter-spacing: 3px; color: var(--gold); }
|
|
.btn-copy {
|
|
background: none; border: none; color: var(--muted);
|
|
cursor: pointer; font-size: 1rem; padding: 2px 4px;
|
|
}
|
|
|
|
.waiting-seats {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 8px;
|
|
width: 100%;
|
|
}
|
|
.seat-slot {
|
|
display: flex; align-items: center; gap: 8px;
|
|
padding: 8px 12px;
|
|
background: rgba(255,255,255,.05);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 8px;
|
|
font-size: .85rem;
|
|
}
|
|
.seat-slot.partner-a { border-color: rgba(79,195,247,.3); }
|
|
.seat-slot.partner-b { border-color: rgba(239,154,154,.3); }
|
|
.seat-num { color: var(--muted); font-size: .75rem; min-width: 14px; }
|
|
.seat-name { font-weight: 600; color: #fff; }
|
|
.waiting-status { font-size: .88rem; color: var(--muted); }
|
|
.waiting-options { display: flex; gap: 10px; justify-content: center; }
|
|
.waiting-opt-label {
|
|
font-size: .78rem; color: var(--gold);
|
|
padding: 2px 8px;
|
|
background: rgba(245,197,24,.1);
|
|
border: 1px solid rgba(245,197,24,.25);
|
|
border-radius: 12px;
|
|
}
|
|
/* ── Public rooms list ────────────────────────── */
|
|
.public-rooms-section { display: flex; flex-direction: column; gap: 6px; width: 100%; }
|
|
.rooms-header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
font-size: .78rem; color: var(--muted);
|
|
}
|
|
.rooms-label { font-weight: 600; letter-spacing: .5px; }
|
|
.public-room-item {
|
|
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
padding: 8px 10px;
|
|
background: rgba(255,255,255,.05);
|
|
border: 1px solid rgba(255,255,255,.1);
|
|
border-radius: 8px;
|
|
}
|
|
.public-room-info { display: flex; flex-direction: column; gap: 2px; text-align: left; }
|
|
.public-room-host { font-size: .85rem; font-weight: 600; color: #fff; }
|
|
.public-room-meta { font-size: .72rem; color: var(--muted); }
|
|
.btn-join-pub { padding: 5px 14px; font-size: .82rem; flex-shrink: 0; }
|
|
|
|
/* ── Creator controls in waiting room ────────── */
|
|
.waiting-creator-controls {
|
|
display: flex; gap: 8px; width: 100%;
|
|
}
|
|
.btn-fill-bots {
|
|
flex: 1;
|
|
padding: 8px 10px;
|
|
background: rgba(255,255,255,.08);
|
|
border: 1px solid rgba(255,255,255,.16);
|
|
border-radius: 10px;
|
|
color: var(--muted);
|
|
cursor: pointer;
|
|
font-size: .82rem;
|
|
}
|
|
.btn-fill-bots:hover { background: rgba(255,255,255,.16); color: #fff; }
|
|
.btn-start-game {
|
|
flex: 1;
|
|
padding: 8px 10px;
|
|
background: rgba(100,200,100,.15);
|
|
border: 1px solid rgba(100,200,100,.35);
|
|
border-radius: 10px;
|
|
color: #a5d6a7;
|
|
cursor: pointer;
|
|
font-size: .82rem;
|
|
font-weight: 600;
|
|
}
|
|
.btn-start-game:hover { background: rgba(100,200,100,.28); color: #c8e6c9; }
|
|
|
|
/* ── Seat swap (creator taps to reorder) ─────── */
|
|
.seat-slot.seat-swappable { cursor: pointer; transition: background .12s, border-color .12s; }
|
|
.seat-slot.seat-swappable:hover { background: rgba(255,255,255,.1); }
|
|
.seat-slot.seat-swap-selected {
|
|
border-color: var(--gold);
|
|
background: rgba(245,197,24,.12);
|
|
}
|
|
|
|
/* ── Game screen ──────────────────────────────── */
|
|
#screen-game { background: var(--felt); overflow: hidden; position: relative; }
|
|
|
|
/* Info bar */
|
|
#info-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 6px 10px;
|
|
background: rgba(0,0,0,.35);
|
|
border-bottom: 1px solid rgba(0,0,0,.3);
|
|
flex-shrink: 0;
|
|
z-index: 10;
|
|
}
|
|
|
|
#score-block {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex: 1;
|
|
justify-content: center;
|
|
min-width: 0;
|
|
flex-wrap: wrap;
|
|
}
|
|
#score-display {
|
|
display: flex;
|
|
gap: 5px;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
min-width: 0;
|
|
}
|
|
.score-entry {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 4px;
|
|
font-size: .74rem;
|
|
padding: 2px 8px;
|
|
border-radius: 20px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
min-width: 0;
|
|
}
|
|
.score-entry .score-name {
|
|
max-width: 72px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
color: rgba(255,255,255,.75);
|
|
}
|
|
.score-entry .score-val { font-weight: 700; color: #fff; }
|
|
/* You */
|
|
.score-entry.my-score {
|
|
background: rgba(245,197,24,.16);
|
|
border-color: rgba(245,197,24,.4);
|
|
}
|
|
.score-entry.my-score .score-name { color: var(--gold); }
|
|
/* Currently lowest score = currently winning */
|
|
.score-entry.leading {
|
|
background: rgba(105,240,174,.15);
|
|
border-color: rgba(105,240,174,.4);
|
|
}
|
|
.score-entry.leading .score-val { color: #69f0ae; }
|
|
|
|
#game-meta { display: flex; gap: 6px; align-items: center; flex-shrink: 0; }
|
|
.hearts-broken {
|
|
font-size: .75rem; font-weight: 700;
|
|
padding: 2px 8px;
|
|
border-radius: 12px;
|
|
background: rgba(229,57,53,.22);
|
|
border: 1px solid rgba(229,57,53,.45);
|
|
color: #ff8a80;
|
|
white-space: nowrap;
|
|
}
|
|
.pass-dir-display {
|
|
font-size: .75rem; font-weight: 600;
|
|
padding: 2px 8px;
|
|
border-radius: 12px;
|
|
background: rgba(245,197,24,.18);
|
|
border: 1px solid rgba(245,197,24,.4);
|
|
color: var(--gold);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.game-menu-wrap { position: relative; }
|
|
.game-menu-dropdown {
|
|
position: absolute;
|
|
top: calc(100% + 6px);
|
|
right: 0;
|
|
background: #1a2e1a;
|
|
border: 1px solid rgba(255,255,255,.15);
|
|
border-radius: 10px;
|
|
min-width: 140px;
|
|
z-index: 200;
|
|
overflow: hidden;
|
|
}
|
|
.game-menu-item {
|
|
display: block; width: 100%; text-align: left;
|
|
padding: 9px 14px;
|
|
background: none; border: none;
|
|
color: #eee; font-size: .85rem; cursor: pointer;
|
|
}
|
|
.game-menu-item:hover { background: rgba(255,255,255,.1); }
|
|
.game-menu-exit { color: #ff8080; }
|
|
|
|
.spectator-banner {
|
|
background: rgba(0,0,0,.5);
|
|
text-align: center;
|
|
padding: 5px;
|
|
font-size: .8rem;
|
|
color: var(--muted);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── Table grid ───────────────────────────────── */
|
|
#table-grid {
|
|
flex: 1;
|
|
display: grid;
|
|
grid-template-columns: 90px 1fr 90px;
|
|
grid-template-rows: auto 1fr;
|
|
gap: 4px;
|
|
padding: 6px;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
.player-area { display: flex; flex-direction: column; align-items: center; gap: 4px; }
|
|
.area-top { grid-column: 2; grid-row: 1; }
|
|
.area-left { grid-column: 1; grid-row: 1 / 3; justify-content: center; }
|
|
.area-right { grid-column: 3; grid-row: 1 / 3; justify-content: center; }
|
|
|
|
#trick-area {
|
|
grid-column: 2;
|
|
grid-row: 2;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
position: relative;
|
|
}
|
|
|
|
.player-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
background: rgba(0,0,0,.3);
|
|
border-radius: 12px;
|
|
padding: 3px 8px;
|
|
}
|
|
.player-label.vertical { flex-direction: column; font-size: .72rem; }
|
|
|
|
.turn-dot { color: var(--gold); font-size: .6rem; animation: pulse 1s infinite; }
|
|
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.3} }
|
|
|
|
.player-score-badge {
|
|
font-size: .7rem; color: var(--gold);
|
|
padding: 1px 5px;
|
|
background: rgba(245,197,24,.12);
|
|
border-radius: 8px;
|
|
}
|
|
.tricks-badge {
|
|
font-size: .7rem; color: var(--muted);
|
|
padding: 1px 5px;
|
|
background: rgba(255,255,255,.08);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
/* ── Card back / face-down ────────────────────── */
|
|
.card-back {
|
|
width: 36px;
|
|
height: 52px;
|
|
background: linear-gradient(135deg, #1565c0 0%, #0d47a1 50%, #1565c0 100%);
|
|
border-radius: 4px;
|
|
border: 1px solid rgba(255,255,255,.25);
|
|
box-shadow: 0 1px 3px rgba(0,0,0,.4);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── Playing cards ────────────────────────────── */
|
|
.card {
|
|
width: var(--card-w);
|
|
height: var(--card-h);
|
|
border-radius: var(--radius);
|
|
box-shadow: var(--shadow);
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
transition: transform .12s, box-shadow .12s;
|
|
position: relative;
|
|
overflow: hidden;
|
|
border: 2px solid transparent;
|
|
background: #fff;
|
|
}
|
|
.card img { width: 100%; height: 100%; object-fit: contain; display: block; border-radius: 6px; }
|
|
.card:hover { transform: translateY(-8px); box-shadow: 0 8px 20px rgba(0,0,0,.5); }
|
|
.card.selected {
|
|
transform: translateY(-12px);
|
|
border-color: var(--gold);
|
|
box-shadow: 0 0 12px rgba(245,197,24,.6);
|
|
}
|
|
.card.illegal { cursor: default; }
|
|
.card.illegal::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: rgba(0,0,0,.55);
|
|
border-radius: 6px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Magnifier (drag mode, dense fan) */
|
|
.card.magnified {
|
|
transform: translateY(-34px) scale(1.5) !important;
|
|
z-index: 50 !important;
|
|
box-shadow: 0 14px 36px rgba(0,0,0,.75) !important;
|
|
border: 2px solid #fff !important;
|
|
transition: transform .1s, box-shadow .1s !important;
|
|
}
|
|
|
|
/* Joker identification badges */
|
|
|
|
/* ── Trick area ───────────────────────────────── */
|
|
.trick-slot {
|
|
width: var(--card-w);
|
|
height: var(--card-h);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
}
|
|
.trick-slot img {
|
|
width: var(--card-w);
|
|
height: var(--card-h);
|
|
border-radius: 6px;
|
|
box-shadow: var(--shadow);
|
|
display: block;
|
|
}
|
|
.trick-card-wrap {
|
|
position: relative;
|
|
width: var(--card-w);
|
|
height: var(--card-h);
|
|
flex-shrink: 0;
|
|
}
|
|
.trick-card-wrap img {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 6px;
|
|
box-shadow: var(--shadow);
|
|
display: block;
|
|
}
|
|
.trick-middle-row {
|
|
display: flex; align-items: center; justify-content: center; gap: 4px;
|
|
}
|
|
.trick-center-info {
|
|
flex: 0 0 80px;
|
|
text-align: center;
|
|
}
|
|
.phase-msg {
|
|
font-size: .72rem; color: rgba(255,255,255,.6);
|
|
line-height: 1.4;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
.phase-msg.your-turn {
|
|
color: var(--gold);
|
|
font-weight: 700;
|
|
font-size: .78rem;
|
|
animation: your-turn-flash .8s ease-in-out infinite alternate;
|
|
}
|
|
@keyframes your-turn-flash {
|
|
from { opacity: .7; }
|
|
to { opacity: 1; }
|
|
}
|
|
/* Escalating urgency — applied every 5 s while it's your turn */
|
|
.phase-msg.your-turn-lvl1 {
|
|
font-size: .96rem;
|
|
color: #ffc400;
|
|
animation: your-turn-flash .6s ease-in-out infinite alternate;
|
|
}
|
|
.phase-msg.your-turn-lvl2 {
|
|
font-size: 1.18rem;
|
|
color: #ffeb3b;
|
|
font-weight: 800;
|
|
text-shadow: 0 0 10px rgba(255, 220, 0, 0.6);
|
|
animation: your-turn-flash .4s ease-in-out infinite alternate;
|
|
}
|
|
.phase-msg.your-turn-lvl3 {
|
|
font-size: 1.4rem;
|
|
color: #fff;
|
|
font-weight: 800;
|
|
text-shadow: 0 0 22px rgba(255, 200, 0, 1), 0 0 6px rgba(255,255,255,.8);
|
|
animation: your-turn-flash .25s ease-in-out infinite alternate;
|
|
}
|
|
|
|
/* Drop-zone pulse when dragging */
|
|
#trick-area { position: relative; }
|
|
#trick-area.drag-active::before {
|
|
content: '';
|
|
position: absolute;
|
|
inset: -10px;
|
|
border: 2px dashed rgba(255,255,255,.4);
|
|
border-radius: 18px;
|
|
pointer-events: none;
|
|
animation: pulse-border .8s ease-in-out infinite alternate;
|
|
}
|
|
@keyframes pulse-border { from { opacity: .35; } to { opacity: 1; } }
|
|
|
|
/* Drag ghost */
|
|
.drag-ghost {
|
|
position: fixed;
|
|
pointer-events: none;
|
|
opacity: .92;
|
|
z-index: 9999;
|
|
transform: scale(1.15) rotate(-4deg);
|
|
box-shadow: 0 12px 32px rgba(0,0,0,.7);
|
|
border-radius: 6px;
|
|
width: var(--card-w);
|
|
height: var(--card-h);
|
|
overflow: hidden;
|
|
transition: none !important;
|
|
}
|
|
.drag-ghost img { width: 100%; height: 100%; display: block; }
|
|
|
|
/* ── My hand ──────────────────────────────────── */
|
|
#my-area {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
padding: 4px 8px calc(8px + env(safe-area-inset-bottom));
|
|
background: rgba(0,0,0,.2);
|
|
border-top: 1px solid rgba(0,0,0,.3);
|
|
}
|
|
#my-area.fan-active { overflow: visible; }
|
|
|
|
#my-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: .8rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Scroll mode (default) */
|
|
#my-hand {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
gap: 4px;
|
|
overflow-x: auto;
|
|
overflow-y: visible;
|
|
padding: 2px 0 4px;
|
|
scrollbar-width: none;
|
|
justify-content: safe center;
|
|
}
|
|
#my-hand::-webkit-scrollbar { display: none; }
|
|
|
|
/* Fan / overlap mode */
|
|
#my-hand.fan-mode {
|
|
gap: 0;
|
|
overflow: visible;
|
|
padding: 14px 4px 4px;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
/* Play / hand mode toggle buttons */
|
|
.btn-play-mode,
|
|
.btn-hand-mode {
|
|
margin-left: auto;
|
|
padding: 2px 8px;
|
|
background: rgba(255,255,255,.12);
|
|
border: 1px solid rgba(255,255,255,.25);
|
|
border-radius: 6px;
|
|
color: rgba(255,255,255,.8);
|
|
font-size: .72rem;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
}
|
|
.btn-play-mode:hover, .btn-hand-mode:hover { background: rgba(255,255,255,.22); }
|
|
.btn-play-mode.drag-mode {
|
|
background: rgba(100,200,100,.18);
|
|
border-color: #66bb6a;
|
|
color: #a5d6a7;
|
|
}
|
|
.btn-hand-mode.fan-mode {
|
|
background: rgba(100,180,255,.18);
|
|
border-color: rgba(100,180,255,.5);
|
|
color: rgba(180,220,255,.9);
|
|
}
|
|
|
|
/* ── Overlays ─────────────────────────────────── */
|
|
.overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,.72);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 100;
|
|
padding: 12px;
|
|
}
|
|
.overlay.hidden { display: none; }
|
|
|
|
.overlay-box {
|
|
background: #1a2e1a;
|
|
border: 1px solid rgba(255,255,255,.15);
|
|
border-radius: 16px;
|
|
padding: 26px 28px;
|
|
width: min(440px, 96vw);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
max-height: 92vh;
|
|
overflow-y: auto;
|
|
}
|
|
.overlay-box.small { max-width: 320px; }
|
|
.overlay-box h3 { font-size: 1.1rem; color: var(--gold); text-align: center; }
|
|
.overlay-leave-btn {
|
|
align-self: center;
|
|
margin-top: 4px;
|
|
background: none;
|
|
border: none;
|
|
color: rgba(255,128,128,.75);
|
|
font-size: .82rem;
|
|
cursor: pointer;
|
|
padding: 4px 8px;
|
|
}
|
|
.overlay-leave-btn:hover { color: #ff8080; text-decoration: underline; }
|
|
|
|
/* ── Pass overlay (3-card exchange) ───────────── */
|
|
.pass-box {}
|
|
.pass-hint { font-size: .82rem; color: var(--muted); text-align: center; }
|
|
|
|
/* One row per suit — matches Hearts pass overlay */
|
|
.pass-hand {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin-bottom: 4px;
|
|
width: 100%;
|
|
max-height: 55vh;
|
|
overflow-y: auto;
|
|
}
|
|
.pass-suit-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
.pass-suit-label {
|
|
font-size: 1.3rem;
|
|
width: 28px;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
line-height: 1;
|
|
}
|
|
.pass-suit-label.suit-h,
|
|
.pass-suit-label.suit-d { color: #ff8080; }
|
|
.pass-suit-label.suit-c,
|
|
.pass-suit-label.suit-s { color: #ddd; }
|
|
.pass-suit-cards {
|
|
display: flex;
|
|
gap: 4px;
|
|
flex-wrap: wrap;
|
|
}
|
|
.pass-hand .card { width: 58px; height: 82px; }
|
|
.pass-hand .card img { width: 58px; height: 82px; }
|
|
|
|
.pass-selected-row {
|
|
display: flex; align-items: center; gap: 8px;
|
|
min-height: 36px;
|
|
}
|
|
.pass-selected-label { font-size: .8rem; color: var(--muted); white-space: nowrap; }
|
|
.pass-selected-preview { display: flex; gap: 4px; flex-wrap: wrap; }
|
|
.pass-selected-preview .card { width: 48px; height: 68px; }
|
|
.pass-selected-preview .card img { width: 48px; height: 68px; }
|
|
.pass-placeholder {
|
|
width: 48px; height: 68px;
|
|
border: 2px dashed rgba(255,255,255,.2);
|
|
border-radius: 6px;
|
|
}
|
|
|
|
/* ── Hand / game over overlays ────────────────── */
|
|
.result-icon { font-size: 2.5rem; text-align: center; }
|
|
.result-icon.big { font-size: 3rem; }
|
|
|
|
.result-scores {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
.result-score-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 6px 12px;
|
|
background: rgba(255,255,255,.06);
|
|
border-radius: 8px;
|
|
font-size: .88rem;
|
|
}
|
|
.result-score-row.winner { background: rgba(245,197,24,.12); border: 1px solid rgba(245,197,24,.3); }
|
|
.result-score-row .team-label { font-weight: 600; }
|
|
.result-score-row .delta { font-weight: 700; }
|
|
.delta.pos { color: #69f0ae; }
|
|
.delta.neg { color: #ff6b6b; }
|
|
|
|
.gameover-scores {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
margin: 4px 0;
|
|
}
|
|
.gameover-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 8px 14px;
|
|
border-radius: 10px;
|
|
background: rgba(255,255,255,.06);
|
|
font-size: .9rem;
|
|
}
|
|
.gameover-row.winner { background: rgba(245,197,24,.15); border: 1px solid rgba(245,197,24,.4); }
|
|
|
|
/* ── Auth overlay ─────────────────────────────── */
|
|
.auth-box { max-width: 360px; }
|
|
.btn-close {
|
|
align-self: flex-end;
|
|
background: none; border: none;
|
|
color: var(--muted); font-size: 1rem; cursor: pointer;
|
|
line-height: 1;
|
|
}
|
|
.auth-tabs { display: flex; gap: 6px; }
|
|
.auth-tab {
|
|
flex: 1; padding: 7px;
|
|
background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 8px;
|
|
color: var(--muted);
|
|
cursor: pointer; font-size: .85rem;
|
|
}
|
|
.auth-tab.active { background: rgba(245,197,24,.15); border-color: rgba(245,197,24,.35); color: var(--gold); }
|
|
.auth-panel { display: none; flex-direction: column; gap: 10px; }
|
|
.auth-panel.active { display: flex; }
|
|
|
|
/* ── Profile & leaderboard ────────────────────── */
|
|
#screen-profile, #screen-leaderboard {
|
|
background: radial-gradient(ellipse at center, #1d5c3a 0%, var(--felt-dark) 100%);
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
overflow-y: auto;
|
|
padding: 16px;
|
|
}
|
|
.profile-wrap { width: 100%; display: flex; justify-content: center; }
|
|
.profile-box {
|
|
background: rgba(0,0,0,.48);
|
|
border: 1px solid rgba(255,255,255,.12);
|
|
border-radius: 16px;
|
|
padding: 24px 28px;
|
|
width: min(400px, 96vw);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
.btn-back {
|
|
background: none; border: none; color: var(--muted);
|
|
cursor: pointer; font-size: .85rem; align-self: flex-start;
|
|
text-decoration: underline;
|
|
}
|
|
.btn-back:hover { color: #fff; }
|
|
.profile-avatar { font-size: 2.5rem; text-align: center; }
|
|
.profile-name { font-size: 1.3rem; text-align: center; color: var(--gold); }
|
|
|
|
.stat-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 8px;
|
|
}
|
|
.stat-card {
|
|
display: flex; flex-direction: column;
|
|
align-items: center; gap: 2px;
|
|
padding: 10px;
|
|
background: rgba(255,255,255,.05);
|
|
border: 1px solid rgba(255,255,255,.1);
|
|
border-radius: 10px;
|
|
}
|
|
.stat-num { font-size: 1.4rem; font-weight: 700; color: var(--gold); }
|
|
.stat-label { font-size: .72rem; color: var(--muted); text-align: center; }
|
|
|
|
.points-legend {
|
|
background: rgba(255,255,255,.04);
|
|
border: 1px solid rgba(255,255,255,.1);
|
|
border-radius: 10px;
|
|
padding: 12px 14px;
|
|
}
|
|
.points-legend h4 { font-size: .85rem; color: var(--gold); margin-bottom: 8px; }
|
|
.points-legend ul { list-style: none; display: flex; flex-direction: column; gap: 4px; }
|
|
.points-legend li { font-size: .8rem; color: var(--muted); }
|
|
.points-legend strong { color: #fff; }
|
|
|
|
.profile-section { display: flex; flex-direction: column; gap: 8px; }
|
|
.admin-section {
|
|
background: rgba(255,100,0,.06);
|
|
border: 1px solid rgba(255,100,0,.2);
|
|
border-radius: 10px;
|
|
padding: 10px 14px;
|
|
}
|
|
.admin-title { font-size: .85rem; color: #ffaa55; margin-bottom: 6px; }
|
|
.admin-row { display: flex; justify-content: space-between; align-items: center; font-size: .85rem; }
|
|
.btn-admin-toggle { min-width: 80px; }
|
|
.btn-admin-toggle.signup-open { border-color: rgba(100,220,100,.6); color: #69f0ae; }
|
|
|
|
/* ── Leaderboard ──────────────────────────────── */
|
|
.lb-table { width: 100%; border-collapse: collapse; font-size: .82rem; }
|
|
.lb-table th, .lb-table td { padding: 7px 8px; text-align: left; }
|
|
.lb-table th { color: var(--muted); font-weight: 600; border-bottom: 1px solid rgba(255,255,255,.1); }
|
|
.lb-table td { border-bottom: 1px solid rgba(255,255,255,.05); }
|
|
.lb-table tr:hover td { background: rgba(255,255,255,.04); }
|
|
|
|
/* ── App version footer ───── */
|
|
.app-version {
|
|
text-align: center;
|
|
margin-top: 14px;
|
|
font-size: .72rem;
|
|
color: rgba(255,255,255,.35);
|
|
letter-spacing: .5px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.app-version:hover { color: rgba(255,255,255,.6); text-decoration: underline; }
|
|
.app-version:active { color: var(--gold); }
|
|
|
|
/* ── Round-by-round breakdown ───── */
|
|
.round-breakdown-wrap { margin: 6px 0 2px; }
|
|
.rb-scroll { max-height: 42vh; overflow: auto; -webkit-overflow-scrolling: touch; }
|
|
.round-breakdown {
|
|
border-collapse: collapse;
|
|
font-size: .82rem;
|
|
margin: 0 auto;
|
|
white-space: nowrap;
|
|
}
|
|
.round-breakdown th, .round-breakdown td {
|
|
padding: 4px 10px;
|
|
text-align: center;
|
|
}
|
|
/* Four players, so names have to stay narrow */
|
|
.round-breakdown thead th {
|
|
max-width: 70px;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
/* Best (lowest) score of the round */
|
|
.round-breakdown td.rb-best { color: #69f0ae; font-weight: 700; }
|
|
/* Moon shot */
|
|
.round-breakdown td.rb-moon { color: var(--gold); font-weight: 700; }
|
|
/* Sticky team-name header so it stays visible as rounds scroll */
|
|
.round-breakdown thead th {
|
|
color: var(--muted);
|
|
font-weight: 600;
|
|
position: sticky;
|
|
top: 0;
|
|
background: #1a2e1a;
|
|
border-bottom: 1px solid rgba(255,255,255,.12);
|
|
}
|
|
.round-breakdown .rb-round {
|
|
text-align: left;
|
|
color: var(--muted);
|
|
font-weight: 600;
|
|
}
|
|
.round-breakdown td.pos { color: #69f0ae; }
|
|
.round-breakdown td.neg { color: #ff6b6b; }
|
|
/* Horizontal line before the final totals row */
|
|
.round-breakdown .rb-final td {
|
|
border-top: 2px solid var(--gold);
|
|
font-weight: 700;
|
|
color: var(--gold);
|
|
}
|
|
.round-breakdown .rb-final .rb-round { color: var(--gold); }
|
|
|
|
/* ── Game history list ───── */
|
|
.history-list { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
|
|
.history-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
padding: 10px 12px;
|
|
border-radius: 10px;
|
|
background: rgba(255,255,255,.04);
|
|
border: 1px solid rgba(255,255,255,.08);
|
|
border-left: 4px solid rgba(255,255,255,.15);
|
|
cursor: pointer;
|
|
}
|
|
.history-item:hover { background: rgba(255,255,255,.07); }
|
|
.history-item.won { border-left-color: #69f0ae; }
|
|
.history-item.lost { border-left-color: #ff6b6b; }
|
|
.history-item-main { display: flex; gap: 10px; align-items: center; justify-content: space-between; }
|
|
.history-item-result { font-weight: 700; }
|
|
.history-item-teams { font-size: .82rem; color: rgba(255,255,255,.75); text-align: right; }
|
|
.history-item-meta { display: flex; justify-content: space-between; font-size: .78rem; color: var(--muted); }
|
|
|
|
/* ── Waiting room top row (Leave + ☰ menu) ───── */
|
|
.waiting-top-row {
|
|
display: flex;
|
|
width: 100%;
|
|
align-items: center;
|
|
}
|
|
|
|
/* ── Turn urgent reminder ──────────────────────── */
|
|
@keyframes turn-urgent-glow {
|
|
0%, 100% { border-top-color: rgba(0,0,0,.3); box-shadow: none; }
|
|
50% {
|
|
border-top-color: rgba(245,197,24,.7);
|
|
box-shadow: 0 -2px 16px rgba(245,197,24,.3);
|
|
}
|
|
}
|
|
#my-area.turn-urgent {
|
|
animation: turn-urgent-glow .65s ease-in-out 6;
|
|
}
|
|
|
|
/* ── Card count badge (replaces card backs) ──── */
|
|
.card-count-badge {
|
|
font-size: .65rem;
|
|
color: rgba(255,255,255,.55);
|
|
padding: 1px 5px;
|
|
background: rgba(255,255,255,.08);
|
|
border-radius: 8px;
|
|
min-width: 20px;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* ── AFK banner ───────────────────────────────── */
|
|
.afk-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 6px 12px;
|
|
background: rgba(200, 100, 0, 0.28);
|
|
border-bottom: 1px solid rgba(200, 120, 0, 0.45);
|
|
font-size: .82rem;
|
|
flex-shrink: 0;
|
|
flex-wrap: wrap;
|
|
}
|
|
.afk-banner.hidden { display: none !important; }
|
|
|
|
/* ── AI control banner ────────────────────────── */
|
|
.ai-control-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 5px 12px;
|
|
background: rgba(80, 0, 180, 0.3);
|
|
border-bottom: 1px solid rgba(120, 60, 220, 0.5);
|
|
font-size: .8rem;
|
|
flex-shrink: 0;
|
|
color: #ce93d8;
|
|
}
|
|
.ai-control-banner.is-me {
|
|
background: rgba(180, 0, 100, 0.35);
|
|
border-bottom-color: rgba(220, 60, 140, 0.55);
|
|
color: #f48fb1;
|
|
font-weight: 700;
|
|
}
|
|
.ai-control-banner.hidden { display: none !important; }
|
|
|
|
/* ── Util ─────────────────────────────────────── */
|
|
.hidden { display: none !important; }
|
|
|
|
/* ── Bar-at-bottom layout ─────────────────────── */
|
|
#screen-game.bar-bottom #info-bar {
|
|
order: 10;
|
|
border-bottom: none;
|
|
border-top: 1px solid rgba(0,0,0,.3);
|
|
}
|
|
#screen-game.bar-bottom .game-menu-dropdown {
|
|
top: auto;
|
|
bottom: calc(100% + 6px);
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════
|
|
MOBILE OVERHAUL (touch devices / small screens)
|
|
═══════════════════════════════════════════════ */
|
|
@media (pointer: coarse) {
|
|
|
|
/* Prevent text selection and system long-press menus on game elements */
|
|
#screen-game {
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
}
|
|
|
|
/* Allow horizontal scroll in scroll mode, block vertical pull-to-refresh */
|
|
#my-hand {
|
|
touch-action: pan-x;
|
|
overscroll-behavior-x: contain;
|
|
}
|
|
|
|
/* In fan mode cards need full touch control for drag */
|
|
#my-hand.fan-mode {
|
|
touch-action: none;
|
|
}
|
|
#my-hand.fan-mode .card {
|
|
touch-action: none;
|
|
}
|
|
|
|
/* ── Info bar: compact ─────────────────────── */
|
|
#info-bar { padding: 3px 8px; gap: 5px; }
|
|
.score-entry { font-size: .64rem; padding: 1px 6px; gap: 3px; }
|
|
.score-entry .score-name { max-width: 52px; }
|
|
.hearts-broken, .pass-dir-display { font-size: .66rem; padding: 1px 6px; }
|
|
.btn-leave-screen { font-size: .75rem; padding: 3px 7px; }
|
|
|
|
/* ── Table grid: narrow side columns ──────── */
|
|
#table-grid {
|
|
grid-template-columns: 36px 1fr 36px;
|
|
gap: 2px;
|
|
padding: 3px;
|
|
}
|
|
|
|
/* ── Top player label: minimal height ──────── */
|
|
.area-top .player-label {
|
|
font-size: .7rem;
|
|
padding: 2px 6px;
|
|
gap: 4px;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
}
|
|
.area-top .player-score-badge { display: none; }
|
|
|
|
/* ── Side player labels: vertical, very narrow */
|
|
.player-label.vertical {
|
|
font-size: .6rem;
|
|
padding: 3px 2px;
|
|
gap: 3px;
|
|
writing-mode: vertical-rl;
|
|
transform: rotate(180deg);
|
|
overflow: hidden;
|
|
max-height: 140px;
|
|
text-align: center;
|
|
}
|
|
/* Rotate back the children that shouldn't be rotated */
|
|
.player-label.vertical .turn-dot {
|
|
writing-mode: horizontal-tb;
|
|
transform: none;
|
|
font-size: .55rem;
|
|
}
|
|
.player-label.vertical .player-score-badge { display: none; }
|
|
.player-label.vertical .card-count-badge {
|
|
writing-mode: horizontal-tb;
|
|
transform: none;
|
|
font-size: .55rem;
|
|
min-width: 16px;
|
|
}
|
|
|
|
/* ── My area: ensure it's always fully visible */
|
|
#my-area {
|
|
padding: 3px 6px calc(6px + env(safe-area-inset-bottom));
|
|
gap: 3px;
|
|
flex-shrink: 0;
|
|
}
|
|
#my-label { font-size: .72rem; gap: 4px; }
|
|
.btn-hand-mode, .btn-play-mode { font-size: .65rem; padding: 2px 6px; }
|
|
|
|
/* ── Pass overlay: fill the screen so all 13 cards stay tappable ── */
|
|
#overlay-pass .overlay-box {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
max-height: 100dvh;
|
|
border-radius: 0;
|
|
padding: 10px 8px calc(10px + env(safe-area-inset-bottom));
|
|
}
|
|
.pass-box h3 { font-size: .95rem; margin-bottom: 2px; }
|
|
}
|
|
|
|
/* ── Small phones (≤ 390px wide) ─────────────── */
|
|
@media (pointer: coarse) and (max-width: 390px) {
|
|
:root { --card-w: 48px; --card-h: 70px; }
|
|
#table-grid { grid-template-columns: 32px 1fr 32px; }
|
|
.overlay-box { padding: 14px 12px; }
|
|
}
|
|
|
|
/* ── Desktop / mouse-pointer fallback tweaks ─── */
|
|
@media (max-width: 480px) and (pointer: fine) {
|
|
:root { --card-w: 54px; --card-h: 78px; }
|
|
#table-grid { grid-template-columns: 70px 1fr 70px; }
|
|
.overlay-box { padding: 18px 16px; }
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════
|
|
HEARTS-SPECIFIC
|
|
═══════════════════════════════════════════════ */
|
|
|
|
/* ── Card-count desync recovery notice ───────────────────────── */
|
|
.revert-banner {
|
|
background: rgba(245,197,24,.18);
|
|
border-bottom: 1px solid rgba(245,197,24,.45);
|
|
color: var(--gold);
|
|
text-align: center;
|
|
padding: 6px 10px;
|
|
font-size: .78rem;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
z-index: 12;
|
|
}
|
|
|
|
/* ── Leaderboard cells ───────────────────────────────────────── */
|
|
.lb-table tr.lb-top .lb-name { color: var(--gold); font-weight: 700; }
|
|
.lb-rank { width: 28px; }
|
|
.lb-name { text-align: left; }
|
|
.lb-btn {
|
|
background: none;
|
|
border: 1px solid rgba(255,255,255,.2);
|
|
border-radius: 6px;
|
|
color: rgba(255,255,255,.7);
|
|
cursor: pointer;
|
|
font-size: .8rem;
|
|
padding: 1px 6px;
|
|
}
|
|
.lb-btn:hover { background: rgba(255,255,255,.12); }
|
|
|
|
/* ── PWA install ─────────────────────────────────────────────── */
|
|
.btn-install {
|
|
padding: 8px 14px;
|
|
background: rgba(41,121,255,.9);
|
|
border: none;
|
|
border-radius: 8px;
|
|
color: #fff;
|
|
font-size: .85rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
}
|
|
.pwa-banner {
|
|
position: fixed;
|
|
bottom: 0; left: 0; right: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 12px 14px calc(14px + env(safe-area-inset-bottom));
|
|
background: #10321f;
|
|
border-top: 1px solid rgba(105,240,174,.25);
|
|
box-shadow: 0 -4px 24px rgba(0,0,0,.5);
|
|
z-index: 9999;
|
|
transform: translateY(100%);
|
|
transition: transform .35s cubic-bezier(.22,1,.36,1);
|
|
}
|
|
.pwa-banner.show { transform: translateY(0); }
|
|
.pwa-banner-icon { width: 44px; height: 44px; border-radius: 10px; flex-shrink: 0; }
|
|
.pwa-banner-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
|
|
.pwa-banner-text strong { color: #fff; font-size: .9rem; }
|
|
.pwa-banner-text span { color: rgba(255,255,255,.6); font-size: .75rem; line-height: 1.3; }
|
|
.pwa-banner-btn {
|
|
padding: 7px 16px; background: var(--gold); border: none; border-radius: 8px;
|
|
color: #000; font-size: .85rem; font-weight: 700; cursor: pointer;
|
|
white-space: nowrap; flex-shrink: 0;
|
|
}
|
|
.pwa-banner-close {
|
|
background: none; border: none; color: rgba(255,255,255,.45);
|
|
font-size: 1rem; cursor: pointer; padding: 4px; flex-shrink: 0;
|
|
}
|
|
|
|
/* ── Leaderboard: players below the minimum game count ────────── */
|
|
.lb-table tr.lb-divider td {
|
|
padding-top: 12px;
|
|
font-size: .7rem;
|
|
color: rgba(255,255,255,.4);
|
|
text-align: center;
|
|
border-bottom: 1px solid rgba(255,255,255,.12);
|
|
}
|
|
.lb-table tr.lb-provisional { opacity: .55; }
|
|
.lb-table tr.lb-provisional .lb-rank { color: rgba(255,255,255,.3); }
|
|
.lb-togo { color: var(--gold); font-size: .72em; }
|