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>
LOG_LEVEL and ENVIRONMENT were hardcoded, overriding .env values.
Now uses ${VAR:-default} so .env settings are respected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Support LOG_LEVEL_{MODULE} env vars (GAME, AI, HANDLERS, ROOM, AUTH,
STORES) to override the global log level for specific modules. Active
overrides are logged at startup. Includes staging/production presets
in .env.example files and a V3.18 stub doc for PostgreSQL storage
efficiency investigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default gradient on base .status-message (dark green)
- Add round-over/game-over (gold) and reveal (purple) gradient styles
- Tag action prompts (swap, flip, discard) as your-turn type
- Match final-turn badge font size and padding to status message on mobile
- Hide status message when empty
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align header-col-center to flex-start on mobile so the status and
final-turn badges sit flush left. Match final-turn-badge border-radius
and padding to status-message for consistent shape.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mute button in header-right throws off visual centering of the status
text. Left-aligning looks intentional rather than off-center.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
overflow:hidden on body.mobile-portrait was blocking scroll on all
screens. Scope it to only when the game screen is active using :has().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
game_ended, queue_left, and cancelMatchmaking were calling
showScreen('lobby') directly, bypassing the cancelAll() cleanup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tag deal container with class so cleanup() can find and remove it
- Remove .traveling-card and .deal-anim-container overlays in cleanup()
- Restore opacity/visibility on cards hidden mid-animation
- Reset all animation flags (dealAnimationInProgress, etc.) in showLobby()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Let overlay card start at deck size and smoothly scale down to opponent
card size during the arc, instead of instantly shrinking before animating.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parent #game-screen has align-items: center which shrink-wraps flex
children. Adding align-self: stretch makes the bottom bar span the
full screen width so space-between can distribute items properly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all flush-edge styling (negative margins, half-pills, border
removal). Restore original padding, justify-content, and pill shapes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zero padding was breaking game layout. Keep 12px padding for layout
stability and use margin-left: -12px / margin-right: -12px on the
edge items to push them flush against screen edges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zero horizontal padding on bottom bar, remove border on flush side,
use half-rounded pill shape so they sit against the screen edges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts flush-edge pill styling and restores horizontal padding to prevent
clipping. Rules drawer is now a sibling of bottom-bar, not inside game-layout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shows "S" (standard) or "!" (house rules) in the mobile bottom bar.
Tapping opens a drawer with the full active rules list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
markKnocker() was called before opponent areas were rebuilt by
innerHTML='', so the is-knocker class and OUT badge were immediately
destroyed. Move markKnocker to after opponent areas are created.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Makes the red border on the knocker's area more visible, especially
for opponents on mobile where the area is small.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Final results modal: keep BY POINTS and BY HOLES side-by-side on
mobile, compact spacing, buttons side-by-side, bottom padding for
mobile bar overlay.
Turn shake: delay 5s before first shake, 300ms every 2s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Less aggressive draw hint: waits 5 seconds before first shake,
then shakes for 300ms every 2 seconds with slightly less movement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Position the button centered beneath the held card instead of to the
right side. Reset writing-mode to horizontal and add width:auto.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce overlap offset from 1.15 to 0.65 so the held card sits at the
DRAW/DISCARD label level rather than up in the opponents area.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Position the held card a full card height above the deck (1.15x offset)
so it sits in the space between opponents and the draw/discard piles.
All three position calculations (app.js x2, card-animations.js) are
synced so draw animations land at the correct held position.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap each pile in a .pile-wrapper with a small label above it.
Fix direct child selectors that broke with the new wrapper nesting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Increase top padding from 5px to 20px so the deck/discard sit lower,
giving the held card more breathing room from the opponents row above.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update getHoldingRect() in card-animations.js and the second held card
positioning path in app.js to use the same reduced overlap offset on
mobile portrait. All three places that compute the held position now
use 0.15 on mobile-portrait vs 0.35 on desktop/landscape.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduce held card overlap offset from 0.35 to 0.15 on mobile portrait
so it doesn't cover the second row of opponents. Increase bottom
padding on opponents row from 6px to 12px for more breathing room.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>