Increase horizontal padding on game-table (4px to 10px) and header
(8px to 12px) to prevent edge clipping. Change opponents-row overflow
to visible so dealer chips aren't cut off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The swap animation defers state updates to pendingGameState, which
bypassed checkForNewPairs entirely. Now pair detection runs when the
deferred state is applied after the swap animation completes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sound was gated behind element check which may fail during swap
animation when card DOM elements are replaced by overlays.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bottom bar is hidden when the hole results modal opens and restored
when dismissed. Also adds mobile-specific compact styles for the
scoresheet: smaller cards, tighter spacing, reduced padding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
firePairCelebration was only doing the visual animation but not playing
the pair sound. The sound was only played during score tallying.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove position:fixed from the bottom bar and make it a flex-shrink:0
child of the game screen flex column. This guarantees the game layout
gets exactly the remaining viewport height with no overlap, regardless
of how the browser calculates viewport units.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set --app-height CSS custom property from window.innerHeight via JS,
which is the only reliable way to get the actual visible viewport on
Chrome Android. Falls back to 100vh if JS hasn't loaded.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use position:fixed with inset:0 for the game screen instead of
height-based sizing. This bypasses the Chrome Android 100vh bug where
vh includes space behind the dynamic URL bar. Also adds
-webkit-fill-available fallback on body.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 100vh fallback before 100dvh, max-height constraints on every flex
container in the layout chain, and explicit flex-basis 0% to prevent
Chrome from letting flex children grow beyond viewport bounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces fixed 120px width with calc((100% - 20px) / 3) so 3 opponents
always fit per row regardless of viewport width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Also fix opponent areas shifting between rows on mobile by giving them
a fixed 120px width so name/score changes don't cause reflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces from 38px to 22px and pulls offset from -10px to -4px so it
no longer overlaps the bottom bar buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add bottom padding to game-table to reserve space for the fixed bottom
bar, and overflow:hidden on player-row so content respects flex bounds.
Also centers draw pile with equal spacing and adds dealer chip clearance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove transform: scale(0.75) from the bar container which broke the
full-width layout and margin-auto pinning. Instead shrink font sizes
and padding on individual buttons and round info by ~25%.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bumps z-index from 500 to 900 so the bottom bar stays above side panel
drawers (600) but below card animation overlays (1000). Scales the bar
to 75% in mobile portrait to reduce visual footprint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces card sizes from 72×101 to 64×90 on mobile portrait to prevent
overlap with bottom bar when opponents wrap to 2 rows. Increases
horizontal gap between opponent hands from 4px to 10px for better
readability of player chips.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace onclick attributes with data-action/data-id attributes and
use event delegation. CSP script-src 'self' blocks inline handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin panel gets "Copy Link" button on active invites that copies
a signup URL with ?invite= param. Client auto-opens signup form
with invite code pre-filled when visiting that link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Forgot password form in auth modal with email input
- Reset password form handles token from email link
- /reset-password route serves index.html for SPA
- EMAIL_FROM env var in docker-compose
- Success/error feedback for both flows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hole indicator: margin-right auto, pill background, brighter text (0.9 opacity)
- End Game: margin-left auto, pinned to right edge
- Standings/Scores stay centered between them
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add round info and leave button to mobile-bottom-bar HTML
- Hide .round-info and #leave-game-btn from header on mobile
- Style round info as subtle text, leave button as red-tinted pill
- Slim down bottom bar: smaller gaps/padding to fit 4 items
- Sync round numbers and leave text via JS (renderGame + bindEvents)
- Frees up header space, reduces mobile crowding
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove excessive 44px bottom padding on game-table (was eating vertical space)
- Tighten opponents-row: reduce gap 6px->4px, side padding 8px->4px
- Reduce opponent-area side padding 5px->4px
- Allow opponent areas to shrink (remove flex-shrink: 0)
- 3 opponents now fit in ~367px, well within 412px Pixel 10 Pro
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Position fixed bottom:0 so buttons are always at the very bottom
- Remove dark background that was picking up the green felt color
- Add bottom padding to game-table so player cards aren't hidden behind bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Redesign bottom bar buttons as pill-shaped with subtle glass border
- Active state: warm gradient fill with glow shadow
- Tap feedback: scale(0.95) press effect
- Drawer panels: iOS-style cubic-bezier spring curve, drop shadow
- Backdrop transition matches drawer timing
- Darker bottom bar background with softer border for depth
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change opponents-row from nowrap to flex-wrap: wrap (max 3+2 layout)
- Opponent cards: 32x45px -> 35x49px, font 0.6 -> 0.65rem
- Short screen: 26x36px -> 29x40px, font 0.45 -> 0.5rem
- 3 opponents at 35px fits 369px, well within 375px iPhone width
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix animation overlay cards rendering at wrong size: base .card CSS
(clamp 65px min) was overriding the inline dimensions set by JS.
Add !important to .draw-anim-front/.draw-anim-back width/height: 100%
so overlays always match their parent container size.
- Size opponent swap held card to match opponent card dimensions instead
of defaulting to deck size (looked oversized on mobile)
- Shrink dealer chip on mobile (38px -> 20px) to fit opponent areas
- Make header more compact: smaller fonts, tighter gaps, nowrap on badges
- Bump deck/discard to 72x101px to match player card size on mobile
- Add spacing between header/opponents, and between deck area/player cards
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add renderGame() guard during deal animation to prevent DOM destruction
mid-animation causing cards to pile up at wrong positions
- Push lobby content below fixed auth-bar (padding 15px -> 50px top)
- Scale player card font-size to 1.5rem/1.3rem for readable text on mobile
- Add full mobile portrait layout: bottom drawers, compact header, responsive
card grid sizing, safe-area insets, and mobile detection via matchMedia
- Add cardFontSize() helper for consistent proportional font scaling
- Add mobile bottom bar with drawer toggles for standings/scores
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add _intentionalClose flag to suppress error when server closes
WebSocket after game_ended broadcast. Clean transition to lobby.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Enforce invite codes on registration (INVITE_ONLY=true by default)
- Bootstrap admin account for first-time setup
- Require authentication for WebSocket connections and room creation
- Add Glicko-2 rating system with multiplayer pairwise comparisons
- Add Redis-backed matchmaking queue with expanding rating window
- Auto-start matched games with standard rules after countdown
- Add "Find Game" button and matchmaking UI to client
- Add rating column to leaderboard
- Scale down docker-compose.prod.yml for 512MB droplet
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove scale(1.15) size jump on held card, keep gold border/glow highlight.
Set animation card font-size proportionally to card width so text matches
across deck, hand, and opponent card sizes. Animate font-size during swaps
so text scales smoothly as cards travel between different-sized positions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only standard-rules games now count toward leaderboard stats. Games
with any house rule variant are marked "Unranked" in the active rules
bar, and a notice appears in the lobby when house rules are selected.
Also fixes game_logger duplicate options dicts (now uses dataclasses.asdict,
capturing all options including previously missing ones) and refactors
duplicated achievement-checking logic into shared helpers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client-side scoring (points badge and score tally animation) ignored
house rules that modify pair behavior. Extract shared
calculateColumnScores() helper that mirrors server logic for
eagle_eye, negative_pairs_keep_value, wolfpack, four_of_a_kind,
and one_eyed_jacks rules. Server now sends scoring_rules flags
in game state.
Also fix opponent flip animation card font-size matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename "New Variants" to "Game Variants", fix descriptions that
contradicted game mechanics (impossible card scenarios, misleading
value assessments), and clarify Underdog Bonus catch-up intent.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cut reveal/tally/celebration timings by ~50% for snappier round end
- Add dealAnimationInProgress flag to suppress flip prompts during deal
- Stop deck/discard pulse animation when round ends
- Update CLAUDE.md with animation race condition documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix discard pile "do-si-do" race condition when CPU draws from discard
- Add isDrawAnimating flag for opponent draw animations
- Skip STEP 2 (discard detection) when draw from discard detected
- Fix deal animation using wrong rect (was using whole player area)
- Add player area highlight when it's their turn (green glow)
- Clear opponent animation flags when your_turn message received
- Hide discard pile during draw-from-discard animation
- Add comprehensive debug logging for animation flags
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- client/ANIMATIONS.md: Full documentation of the CardAnimations API, timing config, CSS rules, and common patterns
- CLAUDE.md: Project context for AI assistants with architecture overview and development guidelines
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace CSS transitions with anime.js for all card animations
- Create card-animations.js as single source for all animation logic
- Remove draw-animations.js (merged into card-animations.js)
- Strip CSS transitions from card elements to prevent conflicts
- Fix held card appearing before draw animation completes
- Make opponent/CPU animations match local player behavior
- Add subtle shake effect for turn indicator (replaces brightness pulse)
- Speed up flip animations by 30% for snappier feel
- Remove unnecessary pulse effects after draws/swaps
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>