- Single Esc: goes back one step (signup→login, lobby→connect, room→lobby)
- Double Esc: still quits the app
- Footer bar shows [Esc] Back and [Esc][Esc] Quit hints on all screens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add signup with invite code support, remove guest login
- Add quit confirmation (q), help screen (h), standings tab
- Unified footer: [h]elp [q]uit | action text | [tab] standings
- Amber card highlighting persists through entire initial flip phase
- Player box border only highlights on turn (green) or knock (red)
- Play area gold border only during player's actual turn
- Game end returns to lobby create/join instead of login screen
- Lobby reset_to_pre_room for replayability without reconnecting
- Dynamic opponent layout fits all in one row when terminal is wide enough
- Hole emoji (⛳) in status bar, branded title with suits on connect screen
- DECK label spacing, Hole terminology in scoreboard
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Lobby: collapsible Game Settings, House Rules, Deck Style sections
- Lobby: CPU profile picker via [+], random CPU via [?], remove via [-]
- Lobby: all settings (rounds, decks, flip mode, house rules, deck colors)
sent to server on start_game instead of hardcoded defaults
- Game: clickable cards (hand positions, deck, discard pile)
- Game: immediate visual feedback on initial card flips
- Game: action bar shows escaped keyboard hints (Keyboard: Choose [d]eck...)
- Game: play area uses fixed-width rounded box instead of horizontal lines
- Game: position numbers on card top-left corner (replacing ┌) on all states
- Game: deck color preview swatches next to style dropdown
- Fix opponent box height mismatch when match connectors present
- Rebrand to GolfCards.club
- Add spacing between status bar/opponents and above local hand
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enables public beta signup metering: DAILY_OPEN_SIGNUPS env var controls
how many users can register without an invite code per day (0=disabled,
-1=unlimited, N=daily cap). Invite codes always bypass the limit.
Also adds per-IP signup throttling (DAILY_SIGNUPS_PER_IP, default 3/day)
and fail-closed rate limiting on auth endpoints when Redis is down.
Client dynamically fetches /api/auth/signup-info to show invite field
as optional with remaining slots when open signups are enabled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update version across pyproject.toml, FastAPI app, HTML footers,
and V3.17 doc. Mark kicked-ball bug as resolved in docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Base .golfer-container rule was after the mobile @media override,
clobbering it. Moved base rule before the media query. Landscape
gets -2px (snug), mobile gets 12px.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce golfer-container margin from 10px to 4px in landscape (2-row)
mode while keeping 10px on mobile. Swap bottom suits to checkerboard
pattern: club/diamond on top, heart/spade on bottom.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap golfer+ball in a positioned container so the ball is absolutely
anchored to the golfer's front foot, independent of inline flow/viewport.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rearrange golf ball SVG suits from single row to 2x2 grid
- Add even spacing between logo, golfer, and title in mobile view
- Remove row-gap between logo row and title row in landscape view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The 749px media query was triggering at mid-range widths, collapsing
the two-row logo+title into a single line. Fix by:
- Using inline-grid on h1 for bulletproof two-row layout
- Lowering single-line breakpoint from 749px to 500px
- Widening lobby container to 550px for title to fit naturally
- Constraining game controls to 400px max-width
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change .logo-row from inline-block to block so the golf ball logo
always left-aligns flush with the G, regardless of viewport width.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The h1 shrinks to its widest child (GolfCards.club), centers via
margin auto, and text-align left aligns both lines within it.
No breakpoint-dependent transforms needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Logo and title naturally left-align within the centered lobby box.
Mobile (<480px) gets text-align center + inline display for single line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cut lastPlayPause to 2s and increase shake interval by 80% (3s→5.4s)
so the draw/discard nudge feels less nagging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase post_draw_settle timing (1.1s→1.3s) and swap retry delay
(100ms→350ms) to prevent draw animation from being cut short by the
arriving swap animation. Also make CPU go-out decisions consider
opponent scores and avoid swapping high cards (8+) into hidden slots.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tighten padding, gaps, card sizes, and margins across all scoresheet
elements so the full modal fits without scrolling on most viewports.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two issues fixed:
1. renderGame() was called before the lastPlayPause delay, causing the
board to jump to final card positions while the swap animation was
still visually playing. Moved renderGame() to after the wait+pause.
2. When the local player makes the final play, their swap animation
defers the round_over game_state to pendingGameState. The deferred
state bypassed the round-end intercept, so preRevealState was never
set — causing the scoresheet to appear immediately without the
reveal animation. Now completeSwapAnimation checks for round_over
transitions and sets preRevealState. Also added a wait loop in
runRoundEndReveal for robustness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Force discard pile DOM update before draw animation starts to prevent
stale card display when previous swap animation blocked renderGame.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move CPU +/- buttons inline into Players header row with "CPU:" label
- Tighten vertical spacing for mobile stacked layout (≤700px)
- Fit Decks/Holes/Card Backs settings in single row on mobile
- Reduce room code banner and auth bar edge margins
- Consistent spacing across all stacked viewport widths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Style the flip overlay's front face to match player hand cards (gradient
background, proper border/shadow) instead of using generic card-front
styles. Hide the underlying card during the animation so the green table
shows through the flip rather than a white card peeking behind it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The turn pulse shake was targeting .discard-stack, which is an ancestor of
#held-card-floating. A CSS transform on any ancestor breaks position:fixed,
causing the held card to render far from the deck area. Now target #discard
directly instead.
Also fix duplicate getCardPointValue methods — the 3-arg scoring version
shadowed the 1-arg tooltip version, leaving cardValues undefined on hover.
Add staging deploy script (rsync working tree, no git pull needed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix dumb AI knocks (e.g. Maya knocking on 13 points) by adding opponent
threat checks and a hard cap of 10 to should_knock_early(). Remove dead
should_go_out_early() call whose return value was never used. Retune knock
chance tiers to be more conservative at higher projected scores.
On the client side, fix round-end reveal sequencing so the last player's
swap/discard animation plays before the reveal sequence starts, and prevent
re-renders from clobbering swap animations during reveals. Also make the
turn-pulse shake configurable via timing-config and target only cards.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mirrors production config with reduced memory limits (128M app, 96M
postgres, 32M redis, 48M traefik) and staging defaults. Rate limiting
disabled for easier testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>