* { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; /* Dark emerald pool table felt */ background: linear-gradient(180deg, #0a4528 0%, #0d5030 50%, #0a4528 100%); min-height: 100vh; color: #fff; } #app { max-width: 1100px; margin: 0 auto; padding: 15px; min-height: 100vh; } /* Game screen uses full width */ #game-screen { max-width: none; width: 100vw; margin-left: calc(-50vw + 50%); padding: 0; box-sizing: border-box; } .screen { display: none; } .screen.active { display: block; } /* Lobby Screen */ #lobby-screen { max-width: 550px; margin: 0 auto; padding: 20px; text-align: center; } /* App footer (lobby & waiting room) */ .app-footer { margin-top: 2rem; padding: 1rem 0; font-size: 0.75rem; color: rgba(255, 255, 255, 0.35); text-align: center; } /* Golf title - golf ball with dimples and shine */ .golf-title { display: block; font-size: 1.05em; font-weight: 800; letter-spacing: 0.02em; /* Shiny gradient like a golf ball surface */ background: /* Dimple pattern - diagonal grid */ radial-gradient(circle at 3px 3px, rgba(0,0,0,0.18) 2px, transparent 2px), /* Shiny highlight gradient - whiter */ linear-gradient( 135deg, #ffffff 0%, #ffffff 25%, #f5f5f2 50%, #ffffff 75%, #f0f0ed 100% ); background-size: 10px 10px, 100% 100%; background-position: 0 0, 0 0; -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2), -1px -1px 0 rgba(255, 255, 255, 0.4); filter: drop-shadow(1px 1px 1px rgba(0,0,0,0.15)); } .golf-title-tld { font-size: 0.45em; font-weight: 600; letter-spacing: 0.15em; } /* Golf ball logo with card suits */ .golfball-logo { width: 1.1em; height: 1.1em; vertical-align: middle; margin-right: 8px; filter: drop-shadow(1px 2px 2px rgba(0,0,0,0.25)); } #lobby-screen h1 { display: inline-grid; grid-template-columns: auto; justify-items: start; text-align: left; row-gap: 0; } .logo-row { margin-bottom: 0; } #lobby-game-controls, #auth-prompt { max-width: 400px; margin-left: auto; margin-right: auto; } @media (max-width: 500px) { #lobby-screen h1 { display: block; text-align: center; text-indent: -18px; } .logo-row { display: inline; margin-bottom: 0; } .golf-title { display: inline; } .golfball-logo { margin-right: 6px; } .golfer-swing { margin-left: 0; margin-right: 10px; } .golfer-container { margin-left: 10px; } } /* Golfer + ball container */ .golfer-container { position: relative; display: inline-block; margin-left: 4px; } /* Golfer swing animation */ .golfer-swing { display: inline-block; transform: scaleX(-1); animation: golf-swing 0.8s cubic-bezier(0.4, 0, 0.2, 1) forwards; animation-delay: 0.3s; } @keyframes golf-swing { 0% { transform: scaleX(-1) translateX(0) rotate(0deg); } /* Wind up - pull back leg */ 30% { transform: scaleX(-1) translateX(-8px) rotate(-15deg); } /* Hold briefly */ 40% { transform: scaleX(-1) translateX(-8px) rotate(-15deg); } /* KICK! */ 55% { transform: scaleX(-1) translateX(8px) rotate(20deg); } /* Follow through */ 80% { transform: scaleX(-1) translateX(4px) rotate(12deg); } /* Final pose - freeze */ 100% { transform: scaleX(-1) translateX(3px) rotate(10deg); } } /* Kicked golf ball - parabolic trajectory */ .kicked-ball { display: inline-block; font-size: 0.2em; position: absolute; right: -8px; bottom: 30%; opacity: 0; animation: ball-kicked 0.7s linear forwards; animation-delay: 0.72s; } /* Trajectory: parabolic arc from golfer's front foot, up and to the right */ @keyframes ball-kicked { 0% { transform: translate(0, 0) scale(1); opacity: 1; } 15% { transform: translate(20px, -24px) scale(1); opacity: 1; } 30% { transform: translate(40px, -39px) scale(1); opacity: 1; } 45% { transform: translate(60px, -46px) scale(0.95); opacity: 1; } 55% { transform: translate(75px, -46px) scale(0.9); opacity: 1; } 70% { transform: translate(95px, -35px) scale(0.85); opacity: 0.9; } 85% { transform: translate(115px, -14px) scale(0.75); opacity: 0.6; } 100% { transform: translate(130px, 17px) scale(0.65); opacity: 0; } } #lobby-screen .form-group { text-align: left; } #lobby-screen input { text-align: center; font-size: 1.1rem; } #lobby-screen #room-code { text-transform: uppercase; letter-spacing: 0.3em; font-weight: 600; } /* Waiting Screen */ #waiting-screen { max-width: 1000px; margin: 0 auto; padding: 20px 40px; position: relative; } /* Desktop: side-by-side layout */ .waiting-layout { display: grid; grid-template-columns: 220px 1fr; gap: 25px; align-items: start; padding-top: 70px; } .waiting-left-col { display: flex; flex-direction: column; gap: 10px; } .waiting-left-col .players-list { background: rgba(0,0,0,0.2); border-radius: 10px; padding: 15px; margin-bottom: 0; } .waiting-left-col .players-list h3 { margin: 0; font-size: 1rem; } #waiting-screen .settings { background: rgba(0,0,0,0.2); border-radius: 10px; padding: 20px; } #waiting-screen .settings h3 { margin: 0 0 15px 0; } /* Basic settings in a row */ .basic-settings-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 15px; align-items: end; } .basic-settings-row .form-group { margin-bottom: 0; } .basic-settings-row .form-group label { font-size: 0.8rem; margin-bottom: 4px; display: block; } .basic-settings-row select { width: 100%; padding: 8px 4px; } /* Stepper Control */ .stepper-control { display: flex; align-items: center; justify-content: center; gap: 8px; background: rgba(0,0,0,0.3); border-radius: 6px; padding: 4px 8px; } .stepper-btn { width: 28px; height: 28px; border: none; border-radius: 4px; background: #4a5568; color: white; font-size: 1.2rem; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s; } .stepper-btn:hover { background: #5a6578; } .stepper-btn:active { background: #3a4558; } .stepper-value { min-width: 24px; text-align: center; font-weight: bold; font-size: 1.1rem; } /* Deck Color Selector */ .deck-color-selector { display: flex; align-items: center; gap: 10px; } .deck-color-selector select { flex: 1; } .deck-color-preview { display: flex; gap: 3px; padding: 4px; background: rgba(0,0,0,0.3); border-radius: 4px; } .preview-card { width: 16px; height: 22px; border-radius: 2px; border: 1px solid rgba(255,255,255,0.2); } /* Deck color classes for preview cards */ .deck-red { background: linear-gradient(135deg, #c41e3a 0%, #922b21 100%); } .deck-blue { background: linear-gradient(135deg, #2e5cb8 0%, #1a3a7a 100%); } .deck-green { background: linear-gradient(135deg, #228b22 0%, #145214 100%); } .deck-gold { background: linear-gradient(135deg, #daa520 0%, #b8860b 100%); } .deck-purple { background: linear-gradient(135deg, #6a0dad 0%, #4b0082 100%); } .deck-teal { background: linear-gradient(135deg, #008b8b 0%, #005f5f 100%); } .deck-pink { background: linear-gradient(135deg, #db7093 0%, #c04f77 100%); } .deck-slate { background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%); } .deck-orange { background: linear-gradient(135deg, #e67e22 0%, #d35400 100%); } .deck-cyan { background: linear-gradient(135deg, #00bcd4 0%, #0097a7 100%); } .deck-brown { background: linear-gradient(135deg, #8b4513 0%, #5d2f0d 100%); } /* Players List Header with inline CPU controls */ .players-list-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .cpu-ctrl-btn { width: 28px; height: 28px; border: none; border-radius: 50%; color: white; font-size: 1.1rem; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: opacity 0.15s; line-height: 1; } .cpu-ctrl-btn:hover { opacity: 0.85; } .cpu-ctrl-btn:active { opacity: 0.7; } #waiting-message { grid-column: 1 / -1; text-align: center; margin-top: 15px; } /* Mobile: stack vertically */ @media (max-width: 700px) { #waiting-screen { padding: 10px 15px; } .waiting-layout { grid-template-columns: 1fr; gap: 10px; padding-top: 72px; } .waiting-left-col { gap: 10px; } .waiting-left-col .players-list { padding: 12px; } .players-list li { padding: 8px 10px; margin-bottom: 6px; } #waiting-screen .settings { padding: 15px; } #waiting-screen .settings h3 { margin-bottom: 10px; } #leave-room-btn { padding: 10px 16px; font-size: 0.9rem; } .basic-settings-row { grid-template-columns: auto minmax(80px, auto) 1fr; gap: 8px; } .basic-settings-row .form-group label { font-size: 0.75rem; } .stepper-control { gap: 4px; padding: 4px 4px; } .stepper-btn { width: 24px; height: 24px; font-size: 1rem; } .stepper-value { min-width: 18px; font-size: 0.95rem; } .basic-settings-row select { padding: 6px 2px; font-size: 0.85rem; text-align: center; } .deck-color-selector select { min-width: 0; } } /* Room Code Banner - styled as a hanging ribbon/bookmark */ .room-code-banner { position: fixed; top: 0; left: 7px; z-index: 100; background: linear-gradient(180deg, #d4845a 0%, #c4723f 50%, #b8663a 100%); padding: 10px 14px 18px; display: flex; flex-direction: column; align-items: center; gap: 6px; box-shadow: 2px 4px 12px rgba(0, 0, 0, 0.3); /* Ribbon forked end (snake tongue style) */ clip-path: polygon(0 0, 100% 0, 100% 100%, 50% calc(100% - 10px), 0 100%); } .room-code-banner::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(180deg, rgba(255,255,255,0.3) 0%, transparent 100%); } .room-code-value { font-size: 1.5rem; font-weight: 800; font-family: 'Courier New', monospace; letter-spacing: 0.15em; color: #fff; text-shadow: 0 2px 2px rgba(0, 0, 0, 0.3); } .room-code-buttons { display: flex; gap: 5px; } .room-code-copy { background: rgba(255, 255, 255, 0.85); border: none; border-radius: 4px; padding: 4px 6px; cursor: pointer; font-size: 0.85rem; transition: all 0.2s; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); } .room-code-copy:hover { background: rgba(255, 255, 255, 0.35); transform: scale(1.1); } .room-code-copy:active { transform: scale(0.95); } h1 { font-size: 3rem; text-align: center; margin-bottom: 10px; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .subtitle { text-align: center; opacity: 0.8; margin-bottom: 20px; } .alpha-banner { text-align: center; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.05em; color: rgba(255, 200, 100, 0.9); background: rgba(244, 164, 96, 0.1); border: 1px solid rgba(244, 164, 96, 0.25); border-radius: 20px; padding: 5px 16px; margin: 0 auto 30px; max-width: 320px; } h2 { text-align: center; margin-bottom: 20px; } h3 { margin-bottom: 15px; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 5px; font-weight: 500; } input, select { width: 100%; padding: 12px; border: none; border-radius: 8px; font-size: 1rem; background: rgba(255,255,255,0.9); color: #333; } input::placeholder { color: #999; } .button-group { margin-bottom: 20px; } .btn { display: inline-block; padding: 12px 24px; border: none; border-radius: 8px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; width: 100%; } .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.3); } .btn:active { transform: translateY(0); } .btn-primary { background: #f4a460; color: #1a472a; } /* Pulsing glow for Next Hole button */ #next-round-btn:not(.hidden) { animation: glow-pulse 1.5s ease-in-out infinite; } @keyframes glow-pulse { 0%, 100% { box-shadow: 0 0 5px rgba(244, 164, 96, 0.4), 0 0 10px rgba(244, 164, 96, 0.2); } 50% { box-shadow: 0 0 15px rgba(244, 164, 96, 0.8), 0 0 30px rgba(244, 164, 96, 0.4), 0 0 45px rgba(244, 164, 96, 0.2); } } .btn-secondary { background: #fff; color: #1a472a; } .btn-danger { background: #c0392b; color: #fff; } .btn-success { background: #27ae60; color: #fff; } .btn-small { padding: 8px 16px; font-size: 0.9rem; width: auto; } .game-buttons .btn-next-round { padding: 10px 20px; font-size: 1rem; font-weight: 600; width: 100%; background: #f4a460; color: #1a472a; } .btn.disabled, .btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; box-shadow: none; } /* Waiting state for non-host next hole button */ #next-round-btn.waiting { animation: none; background: rgba(244, 164, 96, 0.4); color: rgba(255, 255, 255, 0.8); box-shadow: none; } .divider { text-align: center; margin: 30px 0; opacity: 0.6; } .error { color: #e74c3c; text-align: center; margin-top: 15px; } .info { text-align: center; opacity: 0.8; margin: 20px 0; } .recommendation { color: #f4a460; font-size: 0.8rem; margin-top: 6px; padding: 6px 8px; background: rgba(244, 164, 96, 0.15); border-radius: 4px; border-left: 3px solid #f4a460; } .hidden { display: none !important; } /* Players List */ .players-list { background: rgba(0,0,0,0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px; } .players-list ul { list-style: none; } .players-list li { padding: 10px; background: rgba(255,255,255,0.1); border-radius: 6px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; } .players-list .host-badge { background: #f4a460; color: #1a472a; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; } .players-list .cpu-badge { background: #3498db; color: #fff; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; } .cpu-style { font-size: 0.8rem; opacity: 0.7; font-style: italic; } .cpu-controls { display: flex; align-items: center; gap: 4px; } .cpu-controls-label { font-size: 0.8rem; color: #f4a460; font-weight: 600; margin-right: 2px; } .checkbox-group { display: flex; flex-direction: column; gap: 8px; } .checkbox-label { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 0.9rem; } .checkbox-label input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; } .radio-group { display: flex; flex-direction: column; gap: 6px; } .radio-label { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 0.95rem; font-weight: 500; } .radio-label input[type="radio"] { width: 18px; height: 18px; cursor: pointer; flex-shrink: 0; } .radio-label .rule-desc { width: auto; margin-left: 0; opacity: 0.6; font-weight: 400; font-size: 0.8rem; white-space: nowrap; } /* Settings */ .settings { background: rgba(0,0,0,0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px; } /* Game Screen */ .game-header { display: grid; grid-template-columns: auto 1fr auto; align-items: center; padding: 6px 12px; background: linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 0%, transparent 100%); font-size: 0.9rem; width: 100vw; margin-left: calc(-50vw + 50%); box-sizing: border-box; } .header-col { display: flex; align-items: center; } .header-col-left { justify-content: flex-start; gap: 12px; } .header-col-center { justify-content: center; display: flex; align-items: center; gap: 10px; } .header-col-right { display: flex; flex-direction: row; justify-content: flex-end; align-items: center; gap: 6px; flex-wrap: nowrap; min-width: max-content; } #game-logout-btn { padding: 4px 8px; font-size: 0.75rem; } .game-header .round-info { font-weight: 600; white-space: nowrap; } #leave-game-btn { padding: 6px 12px; font-size: 0.8rem; } .mute-btn { background: transparent; border: none; font-size: 1.1rem; cursor: pointer; padding: 2px 6px; border-radius: 4px; opacity: 0.8; transition: opacity 0.2s; } .mute-btn:hover { opacity: 1; background: rgba(255,255,255,0.1); } /* Active Rules (in header) */ .active-rules-bar { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; } .active-rules-bar.hidden { display: none; } .active-rules-bar .rules-label { color: rgba(255, 255, 255, 0.5); font-weight: 500; } .active-rules-bar .rules-list { display: flex; gap: 5px; flex-wrap: nowrap; } .active-rules-bar .rule-tag { background: rgba(244, 164, 96, 0.3); color: #f4a460; padding: 2px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 600; } .active-rules-bar .rule-tag.standard { background: rgba(255, 255, 255, 0.15); color: rgba(255, 255, 255, 0.7); } .active-rules-bar .rule-tag.rule-more { background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.6); cursor: help; border: 1px dashed rgba(255, 255, 255, 0.3); } .active-rules-bar .rule-tag.rule-more:hover { background: rgba(255, 255, 255, 0.2); color: rgba(255, 255, 255, 0.9); } .active-rules-bar .rule-tag.unranked { background: rgba(220, 80, 80, 0.3); color: #f08080; border: 1px solid rgba(220, 80, 80, 0.4); } /* Unranked notice in waiting room */ .unranked-notice { background: rgba(220, 80, 80, 0.15); border: 1px solid rgba(220, 80, 80, 0.3); color: #f0a0a0; font-size: 0.8rem; padding: 6px 12px; border-radius: 6px; margin: 8px 0; text-align: center; } .unranked-notice.hidden { display: none; } /* Card Styles */ .card { width: clamp(65px, 5.5vw, 100px); height: clamp(91px, 7.7vw, 140px); border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: clamp(2rem, 2.5vw, 3.2rem); font-weight: bold; cursor: pointer; /* No CSS transition - hover effects handled by anime.js */ position: relative; user-select: none; } /* Hover state set by anime.js - do not add CSS hover transform here */ .card-back { /* Bee-style diamond grid pattern - default red with white crosshatch */ background-color: #c41e3a; background-image: linear-gradient(45deg, rgba(255,255,255,0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(255,255,255,0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.25) 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0; border: 3px solid #8b1528; color: #fff; font-size: clamp(1.8rem, 2.5vw, 3rem); box-shadow: 0 4px 12px rgba(0,0,0,0.3); } /* Card back color variants */ .card-back.back-red { background-color: #c41e3a; border-color: #8b1528; } .card-back.back-blue { background-color: #2e5cb8; border-color: #1a3a7a; } .card-back.back-green { background-color: #228b22; border-color: #145214; } .card-back.back-gold { background-color: #daa520; border-color: #b8860b; } .card-back.back-purple { background-color: #6a0dad; border-color: #4b0082; } .card-back.back-teal { background-color: #008b8b; border-color: #005f5f; } .card-back.back-pink { background-color: #db7093; border-color: #c04f77; } .card-back.back-slate { background-color: #4a5568; border-color: #2d3748; } .card-back.back-orange { background-color: #e67e22; border-color: #d35400; } .card-back.back-cyan { background-color: #00bcd4; border-color: #0097a7; } .card-back.back-brown { background-color: #8b4513; border-color: #5d2f0d; } .card-front { background: #fff; border: 2px solid #ddd; color: #333; text-align: center; } .card-front.red { color: #c0392b; } .card-front.black { color: #2c3e50; } .card-front.joker { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; } .card-front.joker .joker-icon { font-size: 1.6em; line-height: 1; } .card-front.joker .joker-label { font-size: 0.45em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #9b59b6; } /* Unknown card placeholder (locally flipped, server hasn't confirmed yet) */ .card-front .unknown-card { font-size: 1.8em; color: #7f8c8d; opacity: 0.6; } .card.clickable { cursor: pointer; box-shadow: 0 0 0 2px rgba(244, 164, 96, 0.5); } .card.clickable:hover { box-shadow: 0 0 0 3px #f4a460; } /* Disable hover effects when not player's turn */ #game-screen.not-my-turn .card { cursor: default; } #game-screen.not-my-turn .card:hover { transform: none; box-shadow: none; } #game-screen.not-my-turn #deck, #game-screen.not-my-turn #discard { cursor: default; } #game-screen.not-my-turn #deck:hover, #game-screen.not-my-turn #discard:hover { transform: none; box-shadow: none; } .card.selected, .card.clickable.selected { box-shadow: 0 0 0 4px #fff, 0 0 12px 4px #f4a460; transform: scale(1.08); } /* Card Grid */ .card-grid { display: grid; grid-template-columns: repeat(3, clamp(65px, 5.5vw, 100px)); gap: clamp(8px, 0.8vw, 14px); justify-content: center; } /* Game Table Layout */ .game-table { display: flex; flex-direction: column; align-items: center; gap: 25px; width: 100%; } /* Player row - deck/discard and player cards side by side */ .player-row { display: flex; justify-content: center; align-items: center; gap: 25px; width: 100%; flex-wrap: wrap; } .opponents-row { display: flex; flex-wrap: nowrap; justify-content: center; align-items: flex-end; gap: clamp(12px, 1.8vw, 35px); min-height: clamp(120px, 14vw, 200px); padding: 8px 20px 0; width: 100%; } /* Arch layout - middle items higher, edges lower with rotation for "around the table" feel */ .opponents-row .opponent-area { flex-shrink: 0; transition: transform 0.3s ease; } /* 2 opponents: slight rotation toward center */ .opponents-row .opponent-area:first-child:nth-last-child(2) { margin-bottom: 15px; transform: rotate(-4deg); } .opponents-row .opponent-area:first-child:nth-last-child(2) ~ .opponent-area { margin-bottom: 15px; transform: rotate(4deg); } /* 3 opponents: middle higher, edges rotated toward center */ .opponents-row .opponent-area:first-child:nth-last-child(3) { margin-bottom: 0; transform: rotate(-6deg); } .opponents-row .opponent-area:first-child:nth-last-child(3) ~ .opponent-area:not(:last-child) { margin-bottom: 35px; transform: rotate(0deg); } .opponents-row .opponent-area:first-child:nth-last-child(3) ~ .opponent-area:last-child { margin-bottom: 0; transform: rotate(6deg); } /* 4 opponents: arch shape with rotation toward center */ .opponents-row .opponent-area:first-child:nth-last-child(4) { margin-bottom: 0; transform: rotate(-8deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:nth-child(2) { margin-bottom: 30px; transform: rotate(-3deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:nth-child(3) { margin-bottom: 30px; transform: rotate(3deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:last-child { margin-bottom: 0; transform: rotate(8deg); } /* 5 opponents: deeper arch with graduated rotation toward center */ .opponents-row .opponent-area:first-child:nth-last-child(5) { margin-bottom: 0; transform: rotate(-10deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(2) { margin-bottom: 25px; transform: rotate(-5deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(3) { margin-bottom: 40px; transform: rotate(0deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(4) { margin-bottom: 25px; transform: rotate(5deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:last-child { margin-bottom: 0; transform: rotate(10deg); } .table-center { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; background: rgba(0,0,0,0.15); padding: 15px 20px; border-radius: 12px; } .deck-area { display: flex; gap: 15px; align-items: flex-start; } .pile-wrapper { display: flex; flex-direction: column; align-items: center; } .pile-label { font-size: 0.55rem; font-weight: 700; letter-spacing: 0.1em; color: rgba(255, 255, 255, 0.4); margin-bottom: 3px; } /* Gentle pulse when it's your turn to draw - handled by anime.js */ /* The .your-turn-to-draw class triggers anime.js startTurnPulse() */ /* Held card slot - hidden, using floating card over discard instead */ /* Draw animation card (Anime.js powered) */ .draw-anim-card { position: fixed; z-index: 200; perspective: 800px; pointer-events: none; } .draw-anim-inner { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; } .draw-anim-front, .draw-anim-back { position: absolute; width: 100% !important; height: 100% !important; backface-visibility: hidden; border-radius: 8px; } .draw-anim-front { transform: rotateY(0deg); } .draw-anim-back { transform: rotateY(180deg); } .held-card-slot { display: none !important; } /* Held card floating above and between deck and discard (larger, closer to viewer) */ .held-card-floating { position: fixed; top: 0; left: 0; z-index: 100; border: 3px solid #f4a460 !important; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 20px rgba(244, 164, 96, 0.6) !important; pointer-events: none; /* No transition - anime.js handles animations */ } .held-card-floating.hidden { opacity: 0; pointer-events: none; } /* Pop-in animation - now handled by anime.js popIn() */ /* Keeping class for backwards compatibility */ .held-card-floating.pop-in { /* Animation handled by JS */ } /* Animate floating card dropping to discard pile (when drawn from discard) */ .held-card-floating.dropping { border-color: transparent !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; /* transition removed - anime.js handles animations */ } /* Swoop animation for deck → immediate discard */ .held-card-floating.swooping { /* transition removed - anime.js handles animations */ } .held-card-floating.swooping.landed { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; } .deck-area .card { width: clamp(80px, 7vw, 120px); height: clamp(112px, 9.8vw, 168px); font-size: clamp(2.4rem, 3.2vw, 4rem); } #discard { background: rgba(255,255,255,0.1); border: 2px dashed rgba(255,255,255,0.3); } #discard.has-card { background: #fff; border: 2px solid #ddd; } /* Holding state - when player has drawn a card */ #discard.holding { background: #fff; border: 3px solid #f4a460; box-shadow: 0 0 15px rgba(244, 164, 96, 0.6); transform: scale(1.05); } /* Picked-up state - dimmed when someone is holding a card */ #discard.picked-up { opacity: 0.5; filter: grayscale(40%); } .discard-stack { display: flex; flex-direction: column; align-items: center; gap: 8px; } .discard-stack .btn { white-space: nowrap; } /* Discard button as a tab attached to right side of held card */ #discard-btn { position: fixed; z-index: 101; writing-mode: vertical-rl; text-orientation: mixed; padding: 16px 8px; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.05em; border-radius: 0 8px 8px 0; background: linear-gradient(90deg, #e8914d 0%, #f4a460 100%); color: #1a472a; box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3); border: none; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s, opacity 0.15s; } #discard-btn:hover { transform: scale(1.05); box-shadow: 3px 3px 12px rgba(0, 0, 0, 0.4); } #discard-btn:active { transform: scale(0.98); } #deck.disabled, #discard.disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(50%); } #deck.disabled:hover, #discard.disabled:hover { transform: none; box-shadow: none; } /* Highlight flash when drawing from a pile - uses ::after for guaranteed visibility */ #deck.draw-pulse, #discard.draw-pulse { position: relative; z-index: 250; } #deck.draw-pulse::after, #discard.draw-pulse::after { content: ''; position: absolute; top: -8px; left: -8px; right: -8px; bottom: -8px; border: 4px solid gold; border-radius: 10px; animation: draw-highlight-ring 0.4s ease-out forwards; pointer-events: none; z-index: 999; } @keyframes draw-highlight-ring { 0% { opacity: 1; transform: scale(0.9); border-width: 4px; } 30% { opacity: 1; transform: scale(1.1); border-width: 6px; } 100% { opacity: 0; transform: scale(1.2); border-width: 2px; } } /* Deck "dealing" effect when drawing from deck */ #deck.dealing { animation: deck-deal 0.15s ease-out; } @keyframes deck-deal { 0% { transform: scale(1); } 30% { transform: scale(0.97) translateY(2px); } 100% { transform: scale(1); } } /* Card appearing on discard pile */ .card-flip-in { animation: cardFlipIn 0.25s ease-out; } @keyframes cardFlipIn { from { opacity: 0.5; } to { opacity: 1; } } /* Discard pile pulse when card lands - handled by anime.js pulseDiscard() */ /* The .discard-land class is kept for backwards compatibility */ /* CPU considering discard pile - handled by anime.js startCpuThinking() */ /* The .cpu-considering class is still used as a flag, but animation is via JS */ /* Discard pickup animation - simple dim */ #discard.discard-pickup { animation: discardPickup 0.25s ease-out; } @keyframes discardPickup { 0% { opacity: 1; } 50% { opacity: 0.6; } 100% { opacity: 1; } } /* Swap animation overlay */ .swap-animation { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1000; } .swap-animation.hidden { display: none; } .swap-card { position: absolute; width: 70px; height: 98px; perspective: 800px; } .swap-card.hidden { display: none; } .swap-card-inner { position: relative; width: 100%; height: 100%; border-radius: 8px; transform-style: preserve-3d; /* transition removed - anime.js handles all flip animations */ } .swap-card.flipping .swap-card-inner { transform: rotateY(180deg); } .swap-card-front, .swap-card-back { position: absolute; width: 100%; height: 100%; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; box-shadow: 0 4px 15px rgba(0,0,0,0.4); backface-visibility: hidden; } .swap-card-back { background: linear-gradient(135deg, #c0392b 0%, #922b21 100%); color: rgba(255,255,255,0.4); font-size: 2rem; } /* Swap card back color variants */ .swap-card-back.back-red { background: linear-gradient(135deg, #c41e3a 0%, #922b21 100%); } .swap-card-back.back-blue { background: linear-gradient(135deg, #2e5cb8 0%, #1a3a7a 100%); } .swap-card-back.back-green { background: linear-gradient(135deg, #228b22 0%, #145214 100%); } .swap-card-back.back-gold { background: linear-gradient(135deg, #daa520 0%, #b8860b 100%); } .swap-card-back.back-purple { background: linear-gradient(135deg, #6a0dad 0%, #4b0082 100%); } .swap-card-back.back-teal { background: linear-gradient(135deg, #008b8b 0%, #005f5f 100%); } .swap-card-back.back-pink { background: linear-gradient(135deg, #db7093 0%, #c04f77 100%); } .swap-card-back.back-slate { background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%); } .swap-card-back.back-orange { background: linear-gradient(135deg, #e67e22 0%, #d35400 100%); } .swap-card-back.back-cyan { background: linear-gradient(135deg, #00bcd4 0%, #0097a7 100%); } .swap-card-back.back-brown { background: linear-gradient(135deg, #8b4513 0%, #5d2f0d 100%); } .swap-card-front { background: linear-gradient(145deg, #fff 0%, #f5f5f5 100%); border: 2px solid #ddd; font-size: clamp(1.8rem, 2.2vw, 2.8rem); flex-direction: column; color: #333; line-height: 1.1; font-weight: bold; transform: rotateY(180deg); } .swap-card-front.red { color: #c0392b; } .swap-card-front.black { color: #2c3e50; } .swap-card-front.joker { color: #9b59b6; } .swap-card-front .joker-icon { font-size: 1.5em; line-height: 1; } .swap-card-front .joker-label { font-size: 0.4em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; } .swap-card-front.unknown { color: #7f8c8d; } .swap-card-front .unknown-icon { font-size: 2em; opacity: 0.6; } .swap-card.moving { /* transition removed - anime.js handles animations */ } /* Card in hand fading during swap */ .card.swap-out { opacity: 0; /* transition removed - anime.js handles animations */ } /* Discard fading during swap */ #discard.swap-to-hand { opacity: 0; /* transition removed - anime.js handles animations */ } /* Subtle swap pulse for face-to-face swaps - handled by anime.js pulseSwap() */ /* Keeping the class for backwards compatibility */ /* Fade transitions for swap animation */ .card.fade-out, .held-card-floating.fade-out, .anim-card.fade-out { opacity: 0; /* transition removed - anime.js handles animations */ } .card.fade-in, .held-card-floating.fade-in, .anim-card.fade-in { opacity: 1; /* transition removed - anime.js handles animations */ } /* Pulse animation for clickable cards during initial flip phase */ /* Now handled by anime.js startInitialFlipPulse() for consistency */ /* Keeping the class as a hook but animation is via JS */ .card.clickable.initial-flip-pulse { /* Fallback static glow if JS doesn't start animation */ box-shadow: 0 0 0 2px rgba(244, 164, 96, 0.5); } /* Held card pulse glow for local player's turn */ /* Keeping CSS animation for this as it's a simple looping effect */ .held-card-floating.your-turn-pulse { animation: heldCardPulse 1.5s ease-in-out infinite; } @keyframes heldCardPulse { 0%, 100% { box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 20px rgba(244, 164, 96, 0.6); } 50% { box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4), 0 0 30px rgba(244, 164, 96, 0.9), 0 0 45px rgba(244, 164, 96, 0.4); } } /* Player Area */ .player-section { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0; } .player-area { position: relative; background: rgba(0,0,0,0.2); border-radius: 8px; padding: 10px 15px; text-align: center; } /* Opponent Areas */ .opponent-area { position: relative; background: rgba(0,0,0,0.2); border-radius: 8px; padding: clamp(4px, 0.5vw, 10px) clamp(6px, 0.7vw, 14px) clamp(6px, 0.7vw, 14px); text-align: center; } .opponent-area h4 { font-size: clamp(0.7rem, 0.8vw, 1rem); margin: 0 0 6px 0; padding: clamp(3px, 0.35vw, 6px) clamp(8px, 0.9vw, 14px); background: rgba(244, 164, 96, 0.5); border-radius: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; justify-content: space-between; align-items: center; } .opponent-showing, .player-showing { font-weight: 700; color: rgba(255, 255, 255, 0.9); background: rgba(0, 0, 0, 0.25); padding: 1px 6px; border-radius: 3px; font-size: 0.9em; margin-left: 8px; } /* Player area header - matches opponent style */ .player-area h4 { font-size: clamp(0.8rem, 1vw, 1.1rem); margin: 0 0 8px 0; padding: clamp(4px, 0.4vw, 8px) clamp(10px, 1vw, 16px); background: rgba(244, 164, 96, 0.6); border-radius: 4px; display: flex; justify-content: space-between; align-items: center; } .opponent-area .card-grid { display: grid; grid-template-columns: repeat(3, clamp(45px, 4vw, 75px)); gap: clamp(4px, 0.4vw, 8px); } .opponent-area .card { width: clamp(45px, 4vw, 75px); height: clamp(63px, 5.6vw, 105px); font-size: clamp(1.3rem, 1.5vw, 2.2rem); border-radius: 5px; } .opponent-area.current-turn { background: rgba(244, 164, 96, 0.3); box-shadow: 0 0 0 2px #f4a460; } /* Local player turn highlight - green tint to match "your turn" status */ .player-area.current-turn { background: rgba(181, 212, 132, 0.25); box-shadow: 0 0 0 2px #9ab973; } /* Round winner highlight */ .opponent-area.round-winner h4, .player-area.round-winner h4 { background: rgba(180, 255, 80, 0.85); color: #1a1a1a; } .winner-crown { filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5)); margin-right: 3px; } /* Status message in header */ .status-message { padding: 6px 16px; border-radius: 4px; font-size: 0.9rem; font-weight: 600; text-align: center; white-space: nowrap; color: #fff; background: linear-gradient(135deg, #4a6741 0%, #3d5a35 100%); } /* Empty status - hide completely */ .status-message:empty { display: none; } .status-message.your-turn { background: linear-gradient(135deg, #c8e6a0 0%, #8fbf5a 100%); color: #2d3436; } /* Opponent turn status - subtle purple/slate for other player's turn */ .status-message.opponent-turn { background: linear-gradient(135deg, #8b7eb8 0%, #6b5b95 100%); color: #fff; } /* CPU action status - subtle blue to indicate CPU is doing something */ .status-message.cpu-action { background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%); color: #fff; } /* Round/game over status */ .status-message.round-over, .status-message.game-over { background: linear-gradient(135deg, #f0c040 0%, #d4a017 100%); color: #2d3436; } /* Reveal status */ .status-message.reveal { background: linear-gradient(135deg, #8b7eb8 0%, #6b5b95 100%); color: #fff; } /* Final turn badge - enhanced V3 with countdown */ .final-turn-badge { display: flex; align-items: center; gap: 6px; background: linear-gradient(135deg, #ff6b35 0%, #d63031 100%); color: #fff; padding: 6px 16px; border-radius: 4px; font-weight: 700; letter-spacing: 0.05em; white-space: nowrap; box-shadow: 0 4px 20px rgba(214, 48, 49, 0.4); animation: final-turn-pulse 1.5s ease-in-out infinite; } .final-turn-badge .final-turn-text { font-size: 0.9rem; } .final-turn-badge.hidden { display: none; } @keyframes final-turn-pulse { 0%, 100% { box-shadow: 0 2px 12px rgba(214, 48, 49, 0.4); } 50% { box-shadow: 0 2px 20px rgba(214, 48, 49, 0.6); } } @keyframes toastIn { from { opacity: 0; } to { opacity: 1; } } /* Flip prompt */ .flip-prompt { background: linear-gradient(135deg, #f4a460 0%, #e8914d 100%); color: #1a472a; padding: 6px 16px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; text-align: center; white-space: nowrap; } .flip-prompt.hidden { display: none; } /* Game screen layout */ #game-screen.active { display: flex; flex-direction: column; align-items: center; position: relative; padding: 0; } .game-layout { display: flex; justify-content: center; width: 100%; align-items: flex-start; } .game-main { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; } /* Side Panels - positioned in bottom corners */ .side-panel { position: fixed; bottom: 15px; background: linear-gradient(145deg, rgba(15, 50, 35, 0.92) 0%, rgba(8, 30, 20, 0.95) 100%); border-radius: 10px; padding: 10px 12px; width: 200px; z-index: 100; backdrop-filter: blur(10px); border: 1px solid rgba(244, 164, 96, 0.25); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); } .side-panel.left-panel { left: 15px; } .side-panel.right-panel { right: 15px; } .side-panel > h4 { font-size: 0.7rem; text-align: center; margin-bottom: 8px; color: #f4a460; text-transform: uppercase; letter-spacing: 0.15em; font-weight: 700; border-bottom: 1px solid rgba(244, 164, 96, 0.2); padding-bottom: 6px; } /* Standings list - two sections, top 4 each */ .standings-section { margin-bottom: 6px; } .standings-section:last-child { margin-bottom: 0; } .standings-title { font-size: 0.6rem; color: rgba(255,255,255,0.5); text-transform: uppercase; letter-spacing: 0.1em; padding-bottom: 2px; margin-bottom: 2px; border-bottom: 1px solid rgba(255,255,255,0.1); } .standings-list .rank-row { display: grid; grid-template-columns: 18px 1fr 30px; gap: 3px; font-size: 0.7rem; padding: 1px 0; align-items: center; } .standings-list .rank-pos { text-align: center; font-size: 0.65rem; } .standings-list .rank-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .standings-list .rank-val { text-align: right; font-size: 0.65rem; color: rgba(255,255,255,0.7); } .standings-list .rank-row.leader { color: #f4a460; } .standings-list .rank-row.leader .rank-val { color: #f4a460; } /* Score table */ .side-panel table { width: 100%; border-collapse: collapse; font-size: 0.75rem; } .side-panel th, .side-panel td { padding: 4px 3px; text-align: center; border-bottom: 1px solid rgba(255,255,255,0.08); } .side-panel th { font-weight: 600; background: rgba(0,0,0,0.25); font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.03em; color: rgba(255, 255, 255, 0.6); } .side-panel td:first-child { text-align: left; font-weight: 500; } .side-panel tr.winner { background: linear-gradient(90deg, rgba(244, 164, 96, 0.35) 0%, rgba(244, 164, 96, 0.15) 100%); } .side-panel tr.current-player { background: rgba(244, 164, 96, 0.15); box-shadow: inset 3px 0 0 #f4a460; } .game-buttons { margin-bottom: 10px; display: flex; flex-direction: column; gap: 8px; } .game-buttons .scores-divider { border: none; border-top: 1px solid rgba(255, 255, 255, 0.2); margin: 4px 0 0 0; width: 100%; } .game-buttons .btn { font-size: 0.8rem; padding: 6px 8px; width: 100%; } /* Rankings Announcement */ .rankings-announcement { background: linear-gradient(135deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.25) 100%); border-radius: 10px; padding: 10px; margin-bottom: 12px; border: 1px solid rgba(244, 164, 96, 0.3); overflow: hidden; } .rankings-announcement h3 { font-size: 0.95rem; text-align: center; margin: 0 0 10px 0; color: #f4a460; } .rankings-announcement h4 { font-size: 0.8rem; text-align: center; margin: 0 0 6px 0; opacity: 0.8; } .rankings-columns { display: flex; gap: 8px; } .ranking-section { flex: 1; min-width: 0; background: rgba(0,0,0,0.2); border-radius: 6px; padding: 6px; overflow: hidden; } .rank-row { display: flex; align-items: center; font-size: 0.8rem; padding: 3px 0; gap: 3px; flex-wrap: nowrap; } .rank-row.leader { color: #f4a460; font-weight: 600; } .rank-pos { width: 18px; text-align: center; flex-shrink: 0; } .rank-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } .rank-val { font-size: 0.7rem; opacity: 0.9; flex-shrink: 0; white-space: nowrap; text-align: right; } /* Double Victory */ .double-victory { background: linear-gradient(135deg, #ffd700 0%, #f4a460 50%, #ffd700 100%); color: #1a472a; text-align: center; padding: 10px; border-radius: 8px; font-weight: 700; font-size: 1rem; margin-bottom: 10px; animation: victoryPulse 1s ease-in-out infinite alternate; text-shadow: 0 1px 0 rgba(255,255,255,0.3); } @keyframes victoryPulse { from { box-shadow: 0 0 5px rgba(255, 215, 0, 0.5); } to { box-shadow: 0 0 15px rgba(255, 215, 0, 0.8); } } /* Responsive */ @media (max-width: 700px) { .game-layout { flex-direction: column; } .scoreboard-panel { width: 100%; order: -1; margin-bottom: 8px; padding: 8px; } .scoreboard-panel > h4 { cursor: pointer; user-select: none; padding: 4px; margin: -4px -4px 0 -4px; border-radius: 4px; } .scoreboard-panel > h4:hover { background: rgba(255,255,255,0.1); } .scoreboard-panel > h4::after { content: ' ▼'; font-size: 0.6rem; } .scoreboard-panel.collapsed > h4::after { content: ' ▶'; } .scoreboard-panel.collapsed > *:not(h4):not(.game-buttons) { display: none; } .scoreboard-panel table { max-width: 100%; margin: 8px auto 0; } .rankings-announcement { padding: 8px; margin-bottom: 8px; } .rankings-columns { flex-direction: row; gap: 6px; } .ranking-section { padding: 5px; } .game-buttons { flex-direction: row; justify-content: center; } } @media (max-width: 500px) { #app { padding: 6px; } h1 { font-size: 2rem; } .card { width: 55px; height: 77px; font-size: 1.2rem; } .card-grid { grid-template-columns: repeat(3, 55px); gap: 6px; } .opponent-area .card { width: 38px; height: 53px; font-size: 0.75rem; } .opponent-area .card-grid { grid-template-columns: repeat(3, 38px); gap: 3px; } .opponents-row { min-height: 100px; gap: 8px; } /* Reduce arch heights and rotations on mobile */ .opponents-row .opponent-area:first-child:nth-last-child(2), .opponents-row .opponent-area:first-child:nth-last-child(2) ~ .opponent-area { transform: rotate(0deg); } .opponents-row .opponent-area:first-child:nth-last-child(3) { transform: rotate(-4deg); } .opponents-row .opponent-area:first-child:nth-last-child(3) ~ .opponent-area:not(:last-child) { margin-bottom: 22px; } .opponents-row .opponent-area:first-child:nth-last-child(3) ~ .opponent-area:last-child { transform: rotate(4deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) { transform: rotate(-5deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:nth-child(2), .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:nth-child(3) { margin-bottom: 18px; transform: rotate(0deg); } .opponents-row .opponent-area:first-child:nth-last-child(4) ~ .opponent-area:last-child { transform: rotate(5deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) { transform: rotate(-6deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(2), .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(4) { margin-bottom: 15px; transform: rotate(0deg); } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:nth-child(3) { margin-bottom: 25px; } .opponents-row .opponent-area:first-child:nth-last-child(5) ~ .opponent-area:last-child { transform: rotate(6deg); } .game-header { display: flex; flex-direction: column; text-align: center; gap: 3px; } .header-col-right { justify-content: center; } #game-logout-btn, #leave-game-btn { padding: 3px 6px; font-size: 0.7rem; } .game-username { font-size: 0.7rem; max-width: 60px; } .table-center { padding: 10px 15px; } .player-row { flex-direction: column; gap: 10px; } } /* Suit symbols */ .suit-hearts::after { content: "♥"; } .suit-diamonds::after { content: "♦"; } .suit-clubs::after { content: "♣"; } .suit-spades::after { content: "♠"; } /* ============================================ New Card System - Persistent Card Elements ============================================ */ /* Card Layer - container for all persistent cards */ #card-layer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 500; perspective: 1000px; } #card-layer .real-card { pointer-events: auto; } /* Card Slot - only used when USE_NEW_CARD_SYSTEM is true */ .card-slot { display: none; } /* Real Card - persistent card element with 3D flip */ .real-card { position: fixed; border-radius: 6px; z-index: 501; cursor: pointer; transition: box-shadow 0.3s ease-out, opacity 0.3s ease-out; perspective: 800px; } .real-card:hover { z-index: 510; } .real-card .card-inner { position: relative; width: 100%; height: 100%; border-radius: 6px; transform-style: preserve-3d; /* transition removed - anime.js handles all flip animations */ } .real-card .card-inner.flipped { transform: rotateY(180deg); } .real-card .card-face { position: absolute; width: 100%; height: 100%; border-radius: 6px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: bold; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); backface-visibility: hidden; } /* Card Front */ .real-card .card-face-front { background: linear-gradient(145deg, #fff 0%, #f5f5f5 100%); border: 2px solid #ddd; color: #333; font-size: clamp(1.8rem, 2.2vw, 2.8rem); line-height: 0.95; } .real-card .card-face-front.red { color: #c0392b; } .real-card .card-face-front.black { color: #2c3e50; } .real-card .card-face-front.joker { color: #9b59b6; } .real-card .card-face-front .joker-icon { font-size: 1.5em; line-height: 1; } .real-card .card-face-front .joker-label { font-size: 0.4em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; } /* Card Back */ .real-card .card-face-back { background-color: #c41e3a; background-image: linear-gradient(45deg, rgba(255,255,255,0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(255,255,255,0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255,255,255,0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(255,255,255,0.25) 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0; border: 3px solid #8b1528; color: rgba(255, 255, 255, 0.5); font-size: clamp(1.8rem, 2.5vw, 3rem); transform: rotateY(180deg); } /* Card States */ .real-card.moving, .real-card.anim-card.moving { z-index: 600; /* transition removed - anime.js handles animations */ } /* Animation card - temporary cards used for animations */ .real-card.anim-card { z-index: 700; pointer-events: none; } .real-card.anim-card .card-inner { /* transition removed - anime.js handles all flip animations */ } .real-card.holding { z-index: 550; box-shadow: 0 0 20px rgba(244, 164, 96, 0.6), 0 4px 15px rgba(0, 0, 0, 0.4); } .real-card.clickable { box-shadow: 0 0 0 2px rgba(244, 164, 96, 0.5); } .real-card.clickable:hover { box-shadow: 0 0 0 3px #f4a460, 0 4px 12px rgba(0, 0, 0, 0.3); } /* Disable hover effects when not player's turn */ #game-screen.not-my-turn .real-card { cursor: default; } #game-screen.not-my-turn .real-card:hover { transform: none; } } .real-card.selected { box-shadow: 0 0 0 4px #fff, 0 0 15px 5px #f4a460; z-index: 520; } .real-card.drawing { z-index: 590; } /* Deck card styling in new system */ #deck.new-system { cursor: pointer; position: relative; } /* Discard styling for new system */ #discard.new-system.holding { box-shadow: none; background: rgba(255, 255, 255, 0.1); border: 2px dashed rgba(244, 164, 96, 0.5); } /* Modal */ .modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center; z-index: 200; } .modal.hidden { display: none; } .modal-content { background: linear-gradient(135deg, #1a472a 0%, #2d5a3d 100%); border-radius: 12px; padding: 15px; max-width: 700px; width: 95%; max-height: 90vh; overflow-y: auto; } .modal-content h3 { text-align: center; margin-bottom: 10px; font-size: 1.1rem; } /* CPU Profile Grid */ .profiles-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 12px; } .profile-card { background: rgba(255, 255, 255, 0.1); border: 2px solid transparent; border-radius: 6px; padding: 8px 6px; cursor: pointer; transition: all 0.2s; text-align: center; position: relative; } .profile-card:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(244, 164, 96, 0.5); } .profile-card.unavailable { opacity: 0.4; cursor: not-allowed; } .profile-card.unavailable:hover { background: rgba(255, 255, 255, 0.1); border-color: transparent; } .profile-card.selected { background: rgba(244, 164, 96, 0.3); border-color: #f4a460; box-shadow: 0 0 8px rgba(244, 164, 96, 0.5); } .profile-card.selected:hover { background: rgba(244, 164, 96, 0.4); } .profile-checkbox { position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; border: 2px solid rgba(255,255,255,0.4); border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: bold; color: #1a472a; background: rgba(255,255,255,0.1); } .profile-card.selected .profile-checkbox { background: #f4a460; border-color: #f4a460; } .profile-avatar { width: 50px; height: 50px; margin: 0 auto 8px; border-radius: 50%; background: rgba(255,255,255,0.15); overflow: hidden; } .profile-avatar svg { width: 100%; height: 100%; } .profile-card .profile-name { font-size: 1.1rem; font-weight: 600; margin-bottom: 4px; } .profile-card .profile-style { font-size: 0.85rem; opacity: 0.8; font-style: italic; } .profile-card .profile-in-game { font-size: 0.75rem; color: #f4a460; margin-top: 4px; } .modal-buttons { display: flex; gap: 10px; justify-content: center; } .modal-buttons .btn { min-width: 100px; } /* Advanced Options Section */ .advanced-options-section { background: rgba(0, 0, 0, 0.15); border-radius: 8px; margin: 15px 0; overflow: hidden; } .advanced-options-section summary { padding: 12px 15px; cursor: pointer; font-weight: 600; font-size: 0.95rem; background: rgba(0, 0, 0, 0.2); list-style: none; display: flex; align-items: center; gap: 8px; } .advanced-options-section summary::-webkit-details-marker { display: none; } .advanced-options-section summary::before { content: "▸"; font-size: 0.8rem; transition: transform 0.2s; } .advanced-options-section[open] summary::before { transform: rotate(90deg); } .advanced-options-section summary:hover { background: rgba(0, 0, 0, 0.3); } /* Two-column grid for options */ .advanced-options-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; } .options-column { padding: 8px 12px; } .options-column:first-child { border-right: 1px solid rgba(255, 255, 255, 0.1); } .options-category { padding: 8px 0; border-top: 1px solid rgba(255, 255, 255, 0.1); } .options-category:first-child { border-top: none; } .options-category h4 { font-size: 0.8rem; margin-bottom: 8px; opacity: 0.9; color: #f4a460; } .options-category .checkbox-group { gap: 4px; } .options-category .checkbox-label { font-size: 0.95rem; font-weight: 500; padding: 3px 0; flex-wrap: wrap; } /* Inline checkbox labels - description on same line */ .checkbox-label.inline { flex-wrap: nowrap; } .checkbox-label.inline .rule-desc { width: auto; margin-left: 0; } /* Suit separators for rule descriptions */ .suit { font-size: 0.95em; margin-right: 6px; } .suit-red { color: #e74c3c; } .suit-black { color: #888; } /* Combo note for stacking rules */ .combo-note { font-size: 0.8rem; color: #ffd700; background: rgba(255, 215, 0, 0.1); border-left: 2px solid #ffd700; padding: 4px 8px; margin: 4px 0 8px 0; border-radius: 0 4px 4px 0; } .combo-note.hidden { display: none; } /* Rule description */ .rule-desc { width: 100%; font-size: 0.8rem; opacity: 0.6; margin-left: 30px; margin-top: 1px; } /* Compact form group for options */ .options-category .form-group.compact { margin: 0; } .options-category .form-group.compact select { width: 100%; font-size: 0.75rem; padding: 5px 6px; } /* Eagle Eye option under joker dropdown */ .eagle-eye-option { margin-top: 6px; } /* Disabled checkbox styling */ .checkbox-label:has(input:disabled) { opacity: 0.5; cursor: not-allowed; } .checkbox-label input:disabled { cursor: not-allowed; } /* Mobile: stack columns */ @media (max-width: 500px) { .advanced-options-grid { grid-template-columns: 1fr; } .options-column:first-child { border-right: none; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } } /* Final Results Modal */ .final-results-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.85); display: flex; align-items: center; justify-content: center; z-index: 300; animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .final-results-content { background: linear-gradient(145deg, #1a472a 0%, #0d3320 100%); border-radius: 20px; padding: 30px 40px; max-width: 550px; width: 90%; text-align: center; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 80px rgba(244, 164, 96, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1); border: 2px solid rgba(244, 164, 96, 0.3); animation: modalSlideIn 0.4s ease; } @keyframes modalSlideIn { from { opacity: 0; transform: scale(0.9) translateY(-20px); } to { opacity: 1; transform: scale(1) translateY(0); } } .final-results-content h2 { font-size: 2rem; margin-bottom: 20px; color: #f4a460; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } .double-victory-banner { background: linear-gradient(135deg, #ffd700 0%, #f4a460 50%, #ffd700 100%); color: #1a472a; padding: 12px 20px; border-radius: 10px; font-size: 1.2rem; font-weight: 700; margin-bottom: 20px; animation: victoryPulse 1s ease-in-out infinite alternate; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4); } .final-rankings { display: flex; gap: 20px; margin-bottom: 25px; } .final-ranking-section { flex: 1; background: rgba(0, 0, 0, 0.25); border-radius: 12px; padding: 15px; border: 1px solid rgba(255, 255, 255, 0.1); } .final-ranking-section h3 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.1em; color: rgba(255, 255, 255, 0.6); margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .final-rank-row { display: flex; align-items: center; padding: 8px 10px; margin-bottom: 4px; border-radius: 6px; font-size: 1rem; transition: background 0.2s; } .final-rank-row:nth-child(2) { background: linear-gradient(90deg, rgba(244, 164, 96, 0.3) 0%, rgba(244, 164, 96, 0.1) 100%); font-weight: 600; color: #f4a460; } .final-rank-row:nth-child(3) { background: rgba(192, 192, 192, 0.15); } .final-rank-row:nth-child(4) { background: rgba(205, 127, 50, 0.12); } .final-rank-row .rank-pos { width: 28px; font-weight: 700; font-size: 1.1rem; } .final-rank-row .rank-name { flex: 1; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .final-rank-row .rank-val { font-weight: 600; font-size: 0.95rem; opacity: 0.9; } .final-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } .final-actions .btn { min-width: 140px; padding: 14px 24px; font-size: 1rem; } .final-actions .btn-primary { box-shadow: 0 4px 15px rgba(244, 164, 96, 0.4); } /* Mobile adjustments for final results modal */ @media (max-width: 500px) { .final-results-content { padding: 15px 12px; width: 95%; } .final-results-content h2 { font-size: 1.3rem; margin-bottom: 10px; } .double-victory-banner { padding: 8px 12px; font-size: 0.95rem; margin-bottom: 12px; } .final-rankings { flex-direction: row; gap: 8px; margin-bottom: 15px; } .final-ranking-section { padding: 8px; } .final-ranking-section h3 { font-size: 0.7rem; margin-bottom: 6px; padding-bottom: 4px; } .final-rank-row { font-size: 0.8rem; padding: 4px 5px; margin-bottom: 2px; } .final-rank-row .rank-pos { width: 22px; font-size: 0.9rem; } .final-rank-row .rank-val { font-size: 0.8rem; } .final-actions { flex-direction: row; gap: 8px; padding-bottom: 60px; } .final-actions .btn { min-width: 0; flex: 1; padding: 10px 12px; font-size: 0.9rem; } } /* =========================================== RULES SCREEN =========================================== */ #rules-screen { max-width: 800px; margin: 0 auto; padding: 10px 20px; width: auto; margin-left: auto; margin-right: auto; } #rules-screen.active { display: block; } #rules-screen h1 { margin-top: 0; } .rules-container { position: relative; background: rgba(0, 0, 0, 0.3); border-radius: 12px; padding: 20px 35px; border: 1px solid rgba(255, 255, 255, 0.1); margin-top: 0; scroll-behavior: smooth; } /* Rules back button */ .rules-back-btn { position: absolute; left: 0; top: 0; width: auto; padding: 4px 12px; font-size: 0.8rem; background: transparent; border: 1px solid rgba(255, 255, 255, 0.3); color: rgba(255, 255, 255, 0.7); } .rules-back-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; border-color: rgba(255, 255, 255, 0.5); } .golfer-logo { display: inline-block; transform: scaleX(-1); } /* Rules header */ .rules-header { position: relative; text-align: center; margin-bottom: 25px; padding-bottom: 20px; border-bottom: 2px solid rgba(244, 164, 96, 0.3); } .rules-header h1 { color: #f4a460; font-size: 2rem; margin-bottom: 8px; } .rules-subtitle { color: rgba(255, 255, 255, 0.7); font-size: 1rem; margin: 0; } /* Table of Contents */ .rules-toc { background: linear-gradient(135deg, rgba(244, 164, 96, 0.15) 0%, rgba(244, 164, 96, 0.05) 100%); border: 1px solid rgba(244, 164, 96, 0.3); border-radius: 10px; padding: 18px 22px; margin-bottom: 30px; } .toc-title { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 1.5px; color: rgba(244, 164, 96, 0.9); margin-bottom: 14px; font-weight: 600; } .toc-links { display: flex; flex-wrap: wrap; gap: 10px; } .toc-link { display: flex; align-items: center; gap: 6px; padding: 8px 14px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 20px; color: rgba(255, 255, 255, 0.85); text-decoration: none; font-size: 0.9rem; transition: all 0.2s ease; } .toc-link:hover { background: rgba(244, 164, 96, 0.25); border-color: rgba(244, 164, 96, 0.4); color: #fff; transform: translateY(-1px); } .toc-icon { font-size: 1rem; } .toc-text { font-weight: 500; } .rules-section { margin-bottom: 35px; padding-bottom: 25px; border-bottom: 1px solid rgba(255, 255, 255, 0.15); scroll-margin-top: 20px; } .rules-section:last-child { border-bottom: none; margin-bottom: 0; } .rules-section h2 { color: #f4a460; font-size: 1.4rem; margin-bottom: 15px; padding-bottom: 8px; border-bottom: 2px solid rgba(244, 164, 96, 0.3); } .rules-section h3 { color: #e8d8c8; font-size: 1.1rem; margin: 20px 0 10px 0; } .rules-section h4 { color: #d4c4b4; font-size: 1rem; margin: 15px 0 8px 0; } .rules-section p { line-height: 1.7; margin-bottom: 12px; color: rgba(255, 255, 255, 0.9); } .rules-section ul { margin-left: 20px; margin-bottom: 15px; } .rules-section li { line-height: 1.7; margin-bottom: 8px; color: rgba(255, 255, 255, 0.85); } /* Rules table */ .rules-table { width: 100%; border-collapse: collapse; margin: 15px 0; background: rgba(0, 0, 0, 0.2); border-radius: 8px; overflow: hidden; } .rules-table th, .rules-table td { padding: 12px 15px; text-align: left; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .rules-table th { background: rgba(244, 164, 96, 0.2); color: #f4a460; font-weight: 600; } .rules-table tr:last-child td { border-bottom: none; } .value-negative { color: #4ade80; font-weight: 700; } .value-low { color: #86efac; } .value-zero { color: #fbbf24; } .value-high { color: #f87171; font-weight: 600; } /* Rules example box */ .rules-example { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 8px; padding: 15px 20px; margin: 15px 0; } .rules-example h4 { margin-top: 0; color: #f4a460; } .rules-example pre { font-family: 'Courier New', monospace; font-size: 0.9rem; line-height: 1.5; color: rgba(255, 255, 255, 0.9); white-space: pre-wrap; margin: 0; } .rules-warning { background: rgba(239, 68, 68, 0.15); border: 1px solid rgba(239, 68, 68, 0.3); border-radius: 6px; padding: 12px 15px; color: #fca5a5; } /* Rules case boxes */ .rules-case { background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 15px; margin: 15px 0; border-left: 3px solid rgba(244, 164, 96, 0.5); } .rules-case h4 { margin-top: 0; } /* Flip mode boxes */ .rules-mode { background: rgba(0, 0, 0, 0.2); border-radius: 10px; padding: 20px; margin: 20px 0; border: 1px solid rgba(255, 255, 255, 0.1); } .rules-mode h3 { margin-top: 0; color: #f4a460; } .mode-summary { background: rgba(244, 164, 96, 0.15); border-radius: 6px; padding: 10px 15px; font-weight: 600; color: #f4a460; margin-bottom: 15px; } /* House rule items */ .house-rule { background: rgba(0, 0, 0, 0.15); border-radius: 6px; padding: 12px 16px; margin: 12px 0; border-left: 3px solid rgba(244, 164, 96, 0.5); } .house-rule h4 { margin: 0 0 6px 0; color: #f4a460; font-size: 1rem; } .house-rule p { margin: 0 0 8px 0; line-height: 1.5; } .house-rule p:last-child { margin-bottom: 0; } .strategic-impact { font-size: 0.9rem; color: rgba(255, 255, 255, 0.75); font-style: italic; } .combo-note { background: rgba(244, 164, 96, 0.1); border-radius: 4px; padding: 10px 14px; margin-top: 15px; font-size: 0.9rem; color: rgba(255, 255, 255, 0.8); } /* FAQ items */ .faq-item { background: rgba(0, 0, 0, 0.2); border-radius: 8px; padding: 15px 20px; margin: 15px 0; border-left: 3px solid #3b82f6; } .faq-item h4 { margin: 0 0 10px 0; color: #93c5fd; } .faq-item p { margin: 0; color: rgba(255, 255, 255, 0.85); } /* Rules button in lobby */ .btn-rules { background: rgba(244, 164, 96, 0.2); border: 1px solid #f4a460; color: #ffb366; cursor: pointer; font-size: 0.65rem; padding: 2px 8px; margin-left: 8px; vertical-align: middle; border-radius: 3px; font-weight: 600; transition: background 0.2s, border-color 0.2s; } .btn-rules:hover { background: rgba(244, 164, 96, 0.35); border-color: #ffb366; color: #ffc880; } /* Select option styling in advanced options */ .select-option { margin-bottom: 12px; } .select-option label { display: block; margin-bottom: 5px; color: #f4a460; font-size: 0.9rem; } .select-option select { width: 100%; padding: 8px 10px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 6px; color: white; font-size: 0.85rem; } .select-option .rule-desc { display: block; margin-top: 4px; font-size: 0.75rem; color: rgba(255, 255, 255, 0.5); } /* Mobile adjustments for rules */ @media (max-width: 600px) { .rules-container { padding: 15px; } .rules-header h1 { font-size: 1.5rem; } .rules-subtitle { font-size: 0.9rem; } .rules-toc { padding: 14px 16px; } .toc-title { font-size: 0.75rem; } .toc-links { gap: 8px; } .toc-link { padding: 6px 10px; font-size: 0.8rem; } .toc-icon { font-size: 0.9rem; } .rules-section h2 { font-size: 1.2rem; } .rules-table th, .rules-table td { padding: 8px 10px; font-size: 0.9rem; } .rules-example pre { font-size: 0.8rem; } } /* =========================================== AUTH COMPONENTS =========================================== */ /* Auth bar (top right when logged in) */ .auth-bar { position: fixed; top: 10px; right: 7px; display: flex; align-items: center; gap: 10px; background: rgba(0, 0, 0, 0.4); padding: 6px 12px; border-radius: 20px; font-size: 0.85rem; z-index: 100; } .auth-bar.hidden { display: none; } /* Hide global auth-bar and remove top padding when game screen is active */ #app:has(#game-screen.active) { padding-top: 0; } #app:has(#game-screen.active) > .auth-bar { display: none !important; } #auth-username { color: #f4a460; font-weight: 500; } /* Username in game header */ .game-username { color: #f4a460; font-weight: 500; font-size: 0.75rem; max-width: 80px; overflow: hidden; text-overflow: ellipsis; } .game-username.hidden { display: none; } /* Auth prompt in lobby (shown when not logged in) */ .auth-prompt { text-align: center; margin: 20px 0; padding: 20px; border-radius: 10px; background: rgba(255, 255, 255, 0.05); } .auth-prompt p { margin-bottom: 15px; color: #ccc; font-size: 1.1em; } .auth-prompt .button-group { display: flex; justify-content: center; gap: 12px; } .auth-prompt.hidden { display: none; } /* Auth modal */ .modal-auth { max-width: 320px; padding: 25px; } .modal-auth h3 { text-align: center; margin-bottom: 20px; color: #f4a460; font-size: 1.3rem; } .modal-auth .form-group { margin-bottom: 15px; } .modal-auth input { width: 100%; padding: 12px 15px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 8px; color: white; font-size: 1rem; } .modal-auth input::placeholder { color: rgba(255, 255, 255, 0.4); } .modal-auth input:focus { outline: none; border-color: #f4a460; } .btn-full { width: 100%; } .auth-switch { text-align: center; margin-top: 15px; font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); } .auth-switch a { color: #f4a460; text-decoration: none; } .auth-switch a:hover { text-decoration: underline; } .modal-close-btn { position: absolute; top: 10px; right: 12px; background: none; border: none; color: rgba(255, 255, 255, 0.5); font-size: 1.5rem; cursor: pointer; line-height: 1; padding: 0; } .modal-close-btn:hover { color: white; } .modal-auth .error { color: #f87171; font-size: 0.85rem; margin: 10px 0; text-align: center; } .modal-auth .success { color: #4ade80; font-size: 0.85rem; margin: 10px 0; text-align: center; } .modal-auth .auth-hint { color: #94a3b8; font-size: 0.85rem; margin-bottom: 15px; text-align: center; } /* =========================================== MATCHMAKING SCREEN =========================================== */ #matchmaking-screen { text-align: center; padding: 40px 20px; } #matchmaking-screen h2 { color: #f4a460; margin-bottom: 20px; } .matchmaking-spinner { width: 48px; height: 48px; border: 4px solid rgba(255, 255, 255, 0.1); border-top-color: #f4a460; border-radius: 50%; margin: 20px auto; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .matchmaking-timer { font-size: 2em; font-weight: bold; color: #fff; margin: 15px 0; font-variant-numeric: tabular-nums; } .matchmaking-info { color: rgba(255, 255, 255, 0.6); font-size: 0.9em; margin: 10px 0 20px; } /* =========================================== LEADERBOARD COMPONENTS =========================================== */ /* Leaderboard button in lobby */ .leaderboard-btn { background: rgba(244, 164, 96, 0.2); border: 1px solid #f4a460; color: #ffb366; cursor: pointer; font-size: 0.65rem; padding: 2px 8px; margin-left: 8px; vertical-align: middle; border-radius: 3px; font-weight: 600; transition: background 0.2s, border-color 0.2s; } .leaderboard-btn:hover { background: rgba(244, 164, 96, 0.35); border-color: #ffb366; color: #ffc880; } /* Leaderboard Screen */ #leaderboard-screen { max-width: 800px; margin: 0 auto; padding: 10px 20px; } .leaderboard-container { background: rgba(0, 0, 0, 0.3); border-radius: 12px; padding: 20px 25px; border: 1px solid rgba(255, 255, 255, 0.1); margin-top: 0; } .leaderboard-header { position: relative; text-align: center; margin-bottom: 20px; padding-bottom: 20px; border-bottom: 2px solid rgba(244, 164, 96, 0.3); } .leaderboard-header h1 { color: #f4a460; font-size: 1.8rem; margin-bottom: 5px; } .leaderboard-subtitle { color: rgba(255, 255, 255, 0.6); font-size: 0.9rem; margin: 0; } /* Leaderboard back button */ .leaderboard-back-btn { position: absolute; left: 0; top: 0; width: auto; padding: 4px 12px; font-size: 0.8rem; background: transparent; border: 1px solid rgba(255, 255, 255, 0.3); color: rgba(255, 255, 255, 0.7); } .leaderboard-back-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; border-color: rgba(255, 255, 255, 0.5); } /* Metric tabs */ .leaderboard-tabs { display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; justify-content: center; } .leaderboard-tab { padding: 10px 18px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 8px; color: rgba(255, 255, 255, 0.7); cursor: pointer; font-size: 0.9rem; font-weight: 500; transition: all 0.2s; } .leaderboard-tab:hover { background: rgba(244, 164, 96, 0.15); border-color: rgba(244, 164, 96, 0.3); color: #fff; } .leaderboard-tab.active { background: rgba(244, 164, 96, 0.25); border-color: #f4a460; color: #f4a460; font-weight: 600; } /* Leaderboard table */ .leaderboard-table { width: 100%; border-collapse: collapse; } .leaderboard-table th, .leaderboard-table td { padding: 12px 15px; text-align: left; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .leaderboard-table th { background: rgba(244, 164, 96, 0.15); color: #f4a460; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.5px; } .leaderboard-table tbody tr:hover { background: rgba(255, 255, 255, 0.05); } .leaderboard-table .rank-col { width: 50px; text-align: center; font-weight: 700; font-size: 1rem; } .leaderboard-table .rank-col .medal { font-size: 1.2rem; } .leaderboard-table .username-col { font-weight: 500; } .leaderboard-table .value-col { text-align: right; font-weight: 600; color: #f4a460; } .leaderboard-table .games-col { text-align: right; color: rgba(255, 255, 255, 0.6); font-size: 0.85rem; } /* Player profile link */ .player-link { color: inherit; text-decoration: none; cursor: pointer; } .player-link:hover { color: #f4a460; text-decoration: underline; } /* Empty state */ .leaderboard-empty { text-align: center; padding: 40px 20px; color: rgba(255, 255, 255, 0.5); } .leaderboard-empty p { margin-bottom: 10px; } /* Loading state */ .leaderboard-loading { text-align: center; padding: 40px 20px; color: rgba(255, 255, 255, 0.6); } .leaderboard-loading::after { content: ''; display: inline-block; width: 20px; height: 20px; border: 2px solid rgba(244, 164, 96, 0.3); border-top-color: #f4a460; border-radius: 50%; animation: spin 1s linear infinite; margin-left: 10px; vertical-align: middle; } @keyframes spin { to { transform: rotate(360deg); } } /* Player Stats Modal */ .player-stats-modal .modal-content { max-width: 450px; } .player-stats-header { text-align: center; margin-bottom: 20px; padding-bottom: 15px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .player-stats-header h3 { color: #f4a460; margin: 0 0 5px 0; } .player-stats-header .rank-badge { font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); } .stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-bottom: 20px; } .stat-item { background: rgba(0, 0, 0, 0.2); border-radius: 8px; padding: 12px; text-align: center; } .stat-value { font-size: 1.4rem; font-weight: 700; color: #f4a460; margin-bottom: 4px; } .stat-label { font-size: 0.75rem; color: rgba(255, 255, 255, 0.6); text-transform: uppercase; letter-spacing: 0.5px; } /* Achievements section in player stats */ .achievements-section { margin-top: 15px; padding-top: 15px; border-top: 1px solid rgba(255, 255, 255, 0.1); } .achievements-section h4 { font-size: 0.9rem; color: rgba(255, 255, 255, 0.7); margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.5px; } .achievements-grid { display: flex; flex-wrap: wrap; gap: 8px; } .achievement-badge { display: flex; align-items: center; gap: 6px; background: rgba(244, 164, 96, 0.15); border: 1px solid rgba(244, 164, 96, 0.3); border-radius: 20px; padding: 6px 12px; font-size: 0.85rem; } .achievement-badge .icon { font-size: 1rem; } .achievement-badge .name { color: #f4a460; font-weight: 500; } .achievement-badge.locked { background: rgba(0, 0, 0, 0.2); border-color: rgba(255, 255, 255, 0.1); opacity: 0.5; } .achievement-badge.locked .icon { filter: grayscale(1); } .achievement-badge.locked .name { color: rgba(255, 255, 255, 0.5); } /* My stats badge in leaderboard */ .my-row { background: rgba(244, 164, 96, 0.1) !important; border-left: 3px solid #f4a460; } /* Mobile adjustments */ @media (max-width: 600px) { #leaderboard-screen { padding: 10px; } .leaderboard-container { padding: 15px; } .leaderboard-tabs { gap: 6px; } .leaderboard-tab { padding: 8px 14px; font-size: 0.85rem; } .leaderboard-table th, .leaderboard-table td { padding: 10px 8px; font-size: 0.9rem; } .stats-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; } .stat-item { padding: 10px 8px; } .stat-value { font-size: 1.2rem; } } /* =========================================== REPLAY VIEWER =========================================== */ #replay-screen { max-width: 900px; margin: 0 auto; padding: 15px 20px; } .replay-header { text-align: center; margin-bottom: 20px; } #replay-title { color: #f4a460; font-size: 1.5rem; margin-bottom: 8px; } .replay-meta { color: rgba(255, 255, 255, 0.7); font-size: 0.9rem; } .replay-meta span { display: inline-block; } /* Replay Board */ .replay-board-container { background: rgba(0, 0, 0, 0.3); border-radius: 12px; padding: 20px; margin-bottom: 15px; min-height: 300px; } .replay-players { display: flex; flex-wrap: wrap; gap: 20px; justify-content: center; margin-bottom: 20px; } .replay-player { background: rgba(255, 255, 255, 0.05); border-radius: 10px; padding: 12px; min-width: 180px; border: 2px solid transparent; transition: border-color 0.2s; } .replay-player.is-current { border-color: #f4a460; box-shadow: 0 0 15px rgba(244, 164, 96, 0.3); } .replay-player-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); } .replay-player-name { font-weight: 600; color: #fff; } .replay-player-score { font-size: 0.8rem; color: rgba(255, 255, 255, 0.6); } .replay-cards-grid { display: flex; flex-direction: column; gap: 4px; } .replay-cards-row { display: flex; gap: 4px; justify-content: center; } /* Replay cards - smaller version */ .replay-board-container .card { width: 45px; height: 63px; font-size: 0.9rem; border-radius: 4px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: bold; } .replay-board-container .card-back { background-color: #c41e3a; background-image: linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%), linear-gradient(-45deg, rgba(255,255,255,0.15) 25%, transparent 25%); background-size: 6px 6px; border: 2px solid #8b1528; } .replay-board-container .card-red { background: linear-gradient(145deg, #fff 0%, #f5f5f5 100%); border: 1px solid #ddd; color: #c0392b; } .replay-board-container .card-black { background: linear-gradient(145deg, #fff 0%, #f5f5f5 100%); border: 1px solid #ddd; color: #2c3e50; } .replay-board-container .card-empty { background: rgba(255, 255, 255, 0.1); border: 1px dashed rgba(255, 255, 255, 0.2); } /* Replay center area */ .replay-center { display: flex; justify-content: center; align-items: center; gap: 30px; padding: 20px; background: rgba(0, 0, 0, 0.2); border-radius: 8px; margin-bottom: 15px; } .replay-deck .card, .replay-discard .card { width: 55px; height: 77px; } .replay-deck .deck-count { position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); font-size: 0.75rem; color: rgba(255, 255, 255, 0.6); } .replay-deck { position: relative; } .replay-drawn { display: flex; align-items: center; gap: 8px; } .drawn-label { font-size: 0.8rem; color: #f4a460; } /* Replay info */ .replay-info { display: flex; justify-content: center; gap: 20px; font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); } /* Event description */ .event-description { text-align: center; padding: 12px; margin-bottom: 15px; background: rgba(0, 0, 0, 0.2); border-radius: 8px; min-height: 50px; display: flex; align-items: center; justify-content: center; gap: 15px; } .event-time { font-family: monospace; color: rgba(255, 255, 255, 0.5); font-size: 0.85rem; } .event-text { font-size: 1rem; color: #fff; } /* Replay Controls */ .replay-controls { display: flex; align-items: center; gap: 12px; padding: 15px; background: rgba(0, 0, 0, 0.3); border-radius: 10px; flex-wrap: wrap; justify-content: center; margin-bottom: 15px; } .replay-btn { width: 40px; height: 40px; border-radius: 50%; border: none; background: rgba(244, 164, 96, 0.2); color: #f4a460; cursor: pointer; font-size: 1rem; display: flex; align-items: center; justify-content: center; transition: all 0.2s; } .replay-btn:hover { background: rgba(244, 164, 96, 0.4); transform: scale(1.05); } .replay-btn-play { width: 50px; height: 50px; font-size: 1.3rem; background: #f4a460; color: #1a472a; } .replay-btn-play:hover { background: #ffb366; } /* Timeline */ .timeline { flex: 1; min-width: 200px; display: flex; align-items: center; gap: 10px; } .timeline-slider { flex: 1; height: 8px; -webkit-appearance: none; appearance: none; background: rgba(255, 255, 255, 0.2); border-radius: 4px; cursor: pointer; } .timeline-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; background: #f4a460; border-radius: 50%; cursor: pointer; transition: transform 0.1s; } .timeline-slider::-webkit-slider-thumb:hover { transform: scale(1.2); } .timeline-slider::-moz-range-thumb { width: 18px; height: 18px; background: #f4a460; border-radius: 50%; cursor: pointer; border: none; } .frame-counter { font-family: monospace; min-width: 70px; text-align: right; color: rgba(255, 255, 255, 0.7); font-size: 0.85rem; } /* Speed control */ .speed-control { display: flex; align-items: center; gap: 8px; font-size: 0.85rem; color: rgba(255, 255, 255, 0.7); } .speed-select { padding: 6px 10px; border-radius: 6px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); color: #fff; cursor: pointer; } /* Replay Actions */ .replay-actions { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; } /* Replay Error */ .replay-error { text-align: center; padding: 60px 20px; color: rgba(255, 255, 255, 0.7); } .replay-error p { margin-bottom: 20px; font-size: 1.1rem; } /* Share link container */ .share-link-container { display: flex; gap: 10px; margin-top: 10px; } .share-link-container input { flex: 1; padding: 10px 12px; background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 6px; color: #fff; font-size: 0.9rem; } /* Modal actions */ .modal-actions { display: flex; gap: 12px; justify-content: center; margin-top: 20px; } /* Spectator badge */ .spectator-count { position: fixed; top: 10px; right: 10px; background: rgba(0, 0, 0, 0.7); color: white; padding: 8px 16px; border-radius: 20px; display: flex; align-items: center; gap: 8px; font-size: 0.9rem; z-index: 100; } .spectator-count::before { content: '👁'; } /* Mobile adjustments for replay */ @media (max-width: 600px) { #replay-screen { padding: 10px; } .replay-board-container { padding: 12px; } .replay-players { gap: 12px; } .replay-player { min-width: 150px; padding: 10px; } .replay-board-container .card { width: 38px; height: 53px; font-size: 0.75rem; } .replay-center { gap: 15px; padding: 12px; } .replay-controls { padding: 10px; gap: 8px; } .replay-btn { width: 36px; height: 36px; font-size: 0.9rem; } .replay-btn-play { width: 44px; height: 44px; font-size: 1.1rem; } .timeline { min-width: 150px; } .replay-actions { flex-direction: column; align-items: stretch; } .replay-actions .btn { width: 100%; } } /* ============================================================ V3 FEATURES ============================================================ */ /* --- V3_01: Dealer Indicator --- */ .dealer-chip { position: absolute; bottom: -10px; left: -10px; width: 38px; height: 38px; background: linear-gradient(145deg, #ffc078 0%, #f4a460 40%, #d4884a 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: bold; color: #1a1a2e; border: 3px solid rgba(255, 255, 255, 0.9); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.3), inset 0 2px 4px rgba(255, 255, 255, 0.4), inset 0 -2px 4px rgba(0, 0, 0, 0.2); z-index: 10; pointer-events: none; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.3); } .player-area .dealer-chip { width: 38px; height: 38px; font-size: 18px; border-width: 2px; bottom: -22px; left: -22px; } /* --- V3_03: Round End Reveal --- */ .reveal-prompt { position: fixed; top: 20%; left: 50%; transform: translateX(-50%); background: linear-gradient(135deg, #f4a460 0%, #d4845a 100%); color: white; padding: 15px 30px; border-radius: 12px; text-align: center; z-index: 200; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); animation: prompt-entrance 0.3s ease-out; } .reveal-prompt.fading { animation: prompt-fade 0.3s ease-out forwards; } @keyframes prompt-entrance { 0% { transform: translateX(-50%) translateY(-20px); opacity: 0; } 100% { transform: translateX(-50%) translateY(0); opacity: 1; } } @keyframes prompt-fade { 0% { opacity: 1; } 100% { opacity: 0; } } .reveal-prompt-text { font-size: 1.1em; margin-bottom: 8px; } .reveal-prompt-countdown { font-size: 2em; font-weight: bold; } /* Cards clickable during voluntary reveal */ .player-area.voluntary-flip .card.can-flip { cursor: pointer; } /* Player area highlight during reveal */ .player-area.revealing, .opponent-area.revealing { box-shadow: 0 0 10px 5px rgba(244, 164, 96, 0.3); transition: box-shadow 0.2s ease-out; } /* --- V3_05: Final Turn Urgency --- */ .final-turn-icon { font-size: 1.1em; } .final-turn-remaining { font-size: 0.85em; opacity: 0.9; } /* Game area border pulse during final turn */ #game-screen.final-turn-active { animation: game-area-urgency 2s ease-in-out infinite; } @keyframes game-area-urgency { 0%, 100% { box-shadow: inset 0 0 0 0 rgba(255, 107, 53, 0); } 50% { box-shadow: inset 0 0 30px 0 rgba(255, 107, 53, 0.12); } } /* Knocker highlight */ .player-area.is-knocker, .opponent-area.is-knocker { border: 2px solid #ff6b35; border-radius: 8px; box-shadow: 0 0 12px 3px rgba(255, 107, 53, 0.4); animation: knocker-glow 2s ease-in-out infinite; } @keyframes knocker-glow { 0%, 100% { box-shadow: 0 0 12px 3px rgba(255, 107, 53, 0.4); } 50% { box-shadow: 0 0 20px 6px rgba(255, 107, 53, 0.6); } } .knocker-badge { position: absolute; top: -10px; right: -10px; background: #ff6b35; color: white; padding: 2px 8px; border-radius: 10px; font-size: 0.7em; font-weight: bold; z-index: 10; pointer-events: none; } /* --- V3_08: Card Hover Selection Preview --- */ .player-area.can-swap .card { cursor: pointer; } /* Swap card hover state - anime.js handles transform, CSS handles box-shadow only */ @media (hover: hover) { .player-area.can-swap .card:hover { /* Transform handled by anime.js cardHover methods */ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); } .player-area.can-swap .card.card-back:hover { box-shadow: 0 8px 20px rgba(244, 164, 96, 0.4); } } /* --- V3_09: Knock Early Drama --- */ .knock-confirm-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center; z-index: 300; animation: modal-fade-in 0.2s ease-out; } @keyframes modal-fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } .knock-confirm-content { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); padding: 30px; border-radius: 15px; text-align: center; max-width: 320px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); animation: modal-scale-in 0.2s ease-out; } @keyframes modal-scale-in { 0% { transform: scale(0.9); } 100% { transform: scale(1); } } .knock-confirm-icon { font-size: 3em; margin-bottom: 10px; } .knock-confirm-content h3 { margin: 0 0 15px; color: #f4a460; } .knock-confirm-content p { margin: 0 0 10px; color: rgba(255, 255, 255, 0.8); } .knock-warning { color: #e74c3c !important; font-size: 0.9em; } .knock-confirm-buttons { display: flex; gap: 10px; margin-top: 20px; } .knock-confirm-buttons .btn { flex: 1; } /* V3_17: Knock status message - golden gradient with pulsing glow */ .status-message.knock { background: linear-gradient(135deg, #f4a460 0%, #e67e22 50%, #d4750e 100%); color: #1a1a2e; font-size: 1.3em; font-weight: 900; letter-spacing: 0.08em; text-transform: uppercase; animation: knock-pulse 0.6s ease-in-out 3; box-shadow: 0 0 15px rgba(244, 164, 96, 0.5); } @keyframes knock-pulse { 0%, 100% { box-shadow: 0 0 15px rgba(244, 164, 96, 0.5); } 50% { box-shadow: 0 0 25px rgba(244, 164, 96, 0.8), 0 0 40px rgba(230, 126, 34, 0.3); } } @keyframes screen-shake { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-3px); } 40% { transform: translateX(3px); } 60% { transform: translateX(-2px); } 80% { transform: translateX(2px); } } body.screen-shake { animation: screen-shake 0.3s ease-out; } /* opponent-knock-banner removed in V3_17 - knock uses status bar now */ /* --- V3_07: Score Tallying Animation --- */ .card-value-overlay { position: fixed; transform: translate(-50%, -50%) scale(0.5); background: rgba(20, 20, 36, 0.95); color: #fff; padding: 6px 12px; border-radius: 6px; font-size: 1.3em; font-weight: 800; letter-spacing: 0.02em; opacity: 0; transition: transform 0.15s ease-out, opacity 0.12s ease-out; z-index: 200; pointer-events: none; border: 2px solid rgba(255, 255, 255, 0.25); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); } .card-value-overlay.visible { transform: translate(-50%, -50%) scale(1); opacity: 1; } .card-value-overlay.negative { background: linear-gradient(135deg, #1b944f 0%, #166b3a 100%); border-color: rgba(39, 174, 96, 0.5); } .card-value-overlay.zero { background: linear-gradient(135deg, #8b6914 0%, #6b5010 100%); border-color: rgba(180, 140, 40, 0.5); color: #f5e6b8; } .card.tallying { box-shadow: 0 0 15px rgba(244, 164, 96, 0.6) !important; transform: scale(1.05); /* No CSS transition - tallying effect handled by JS */ } .pair-cancel-overlay { position: fixed; transform: translate(-50%, -50%); font-size: 1.1em; font-weight: 800; color: #ffe082; background: rgba(20, 20, 36, 0.92); padding: 5px 12px; border-radius: 6px; border: 2px solid rgba(255, 215, 0, 0.4); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); animation: pair-cancel 0.5s ease-out forwards; z-index: 200; pointer-events: none; } @keyframes pair-cancel { 0% { transform: translate(-50%, -50%) scale(0.5); opacity: 0; } 25% { transform: translate(-50%, -50%) scale(1.1); opacity: 1; } 100% { transform: translate(-50%, -60%) scale(1); opacity: 0; } } .pair-cancel-overlay.negative { color: #81d4fa; border-color: rgba(100, 181, 246, 0.4); } /* --- V3_10: Column Pair Indicator --- */ .card.paired { box-shadow: 0 0 8px rgba(244, 164, 96, 0.3); } .card.pair-top { border-bottom: 2px solid rgba(244, 164, 96, 0.5); border-bottom-left-radius: 0; border-bottom-right-radius: 0; } .card.pair-bottom { border-top: 2px solid rgba(244, 164, 96, 0.5); border-top-left-radius: 0; border-top-right-radius: 0; } .opponent-area .card.paired { box-shadow: 0 0 5px rgba(244, 164, 96, 0.2); } .opponent-area .card.pair-top { border-bottom-width: 1px; } .opponent-area .card.pair-bottom { border-top-width: 1px; } /* --- V3_06: Opponent Thinking Indicator --- */ .thinking-indicator { display: inline-block; margin-right: 4px; font-size: 0.9em; } .thinking-indicator.hidden { display: none; } /* --- V3_15: Discard Pile History Depth --- */ #discard[data-depth="2"] { box-shadow: 2px 2px 0 0 rgba(255, 255, 255, 0.08), 0 4px 12px rgba(0, 0, 0, 0.3); } #discard[data-depth="3"] { box-shadow: 2px 2px 0 0 rgba(255, 255, 255, 0.08), 4px 4px 0 0 rgba(255, 255, 255, 0.04), 0 4px 12px rgba(0, 0, 0, 0.3); } /* --- V3_14: Active Rules Context --- */ .rule-tag.rule-highlighted { background: rgba(244, 164, 96, 0.3); box-shadow: 0 0 10px rgba(244, 164, 96, 0.4); animation: rule-pulse 0.5s ease-out; } @keyframes rule-pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .rule-message { margin-left: 8px; padding-left: 8px; border-left: 1px solid rgba(255, 255, 255, 0.3); font-weight: bold; color: #f4a460; animation: rule-message-in 0.3s ease-out; } @keyframes rule-message-in { 0% { opacity: 0; transform: translateX(-5px); } 100% { opacity: 1; transform: translateX(0); } } /* --- V3_13: Card Value Tooltips --- */ .card-value-tooltip { position: fixed; transform: translateX(-50%); background: rgba(26, 26, 46, 0.95); color: white; padding: 6px 12px; border-radius: 8px; font-size: 0.85em; text-align: center; z-index: 500; pointer-events: none; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); transition: opacity 0.15s; } .card-value-tooltip.hidden { opacity: 0; } .card-value-tooltip::before { content: ''; position: absolute; top: -6px; left: 50%; transform: translateX(-50%); border: 6px solid transparent; border-bottom-color: rgba(26, 26, 46, 0.95); } .tooltip-value { display: block; font-size: 1.2em; font-weight: bold; } .tooltip-value.negative { color: #27ae60; } .tooltip-note { display: block; font-size: 0.85em; color: rgba(255, 255, 255, 0.7); margin-top: 2px; } /* --- V3_17: Scoresheet Modal --- */ .scoresheet-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.6); z-index: 300; animation: fadeInBg 0.3s ease; } @keyframes fadeInBg { from { opacity: 0; } to { opacity: 1; } } .scoresheet-content { background: linear-gradient(145deg, #1a472a 0%, #0d3320 100%); border-radius: 16px; padding: 14px 18px; max-width: 520px; width: 92%; max-height: 90vh; overflow-y: auto; box-shadow: 0 16px 50px rgba(0, 0, 0, 0.6), 0 0 60px rgba(244, 164, 96, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.1); border: 2px solid rgba(244, 164, 96, 0.25); animation: modalSlideIn 0.4s ease; } .ss-header { text-align: center; font-size: 1rem; font-weight: 700; color: #f4a460; margin-bottom: 10px; letter-spacing: 0.05em; } .ss-players { display: flex; flex-direction: column; gap: 8px; } .ss-player-row { background: rgba(0, 0, 0, 0.2); border-radius: 10px; padding: 8px 10px; border: 1px solid rgba(255, 255, 255, 0.06); } .ss-player-header { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; } .ss-player-name { font-weight: 700; font-size: 0.95rem; color: #e8e8e8; } .ss-badge { font-size: 0.65rem; font-weight: 800; padding: 2px 7px; border-radius: 4px; letter-spacing: 0.05em; text-transform: uppercase; } .ss-badge-knock { background: linear-gradient(135deg, #f4a460 0%, #e67e22 100%); color: #1a1a2e; } .ss-badge-low { background: linear-gradient(135deg, #27ae60 0%, #1e8449 100%); color: #fff; } .ss-columns { display: flex; gap: 8px; justify-content: center; margin-bottom: 6px; } .ss-column { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 4px 6px; border-radius: 6px; background: rgba(255, 255, 255, 0.03); } .ss-column-paired { background: rgba(244, 164, 96, 0.08); border: 1px solid rgba(244, 164, 96, 0.15); } .ss-column-paired.ss-pair-glow { animation: ss-pair-glow-pulse 0.5s ease-out; } @keyframes ss-pair-glow-pulse { 0% { box-shadow: 0 0 0 rgba(244, 164, 96, 0); } 50% { box-shadow: 0 0 12px rgba(244, 164, 96, 0.4); } 100% { box-shadow: 0 0 0 rgba(244, 164, 96, 0); } } .ss-mini-card { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 24px; border-radius: 3px; font-size: 0.68rem; font-weight: 700; line-height: 1; background: #f5f0e8; color: #1a1a2e; border: 1px solid rgba(0, 0, 0, 0.15); letter-spacing: -0.02em; } .ss-mini-card.ss-red { color: #c0392b; } .ss-mini-card.ss-black { color: #1a1a2e; } .ss-mini-card.ss-mini-paired { opacity: 0.5; text-decoration: line-through; } .ss-mini-card.ss-mini-back { background: linear-gradient(135deg, #2c5f8a 0%, #1a3a5c 100%); color: transparent; } .ss-col-score { font-size: 0.7rem; font-weight: 700; color: rgba(255, 255, 255, 0.7); text-align: center; margin-top: 1px; } .ss-col-score.ss-pair { color: #f4a460; } .ss-col-score.ss-negative { color: #27ae60; } .ss-bonuses { margin: 4px 0 2px; text-align: center; } .ss-bonus { display: inline-block; font-size: 0.7rem; font-weight: 800; color: #81d4fa; background: rgba(100, 181, 246, 0.15); padding: 2px 8px; border-radius: 4px; margin: 0 4px; } .ss-scores { display: flex; justify-content: flex-end; gap: 16px; font-size: 0.8rem; color: rgba(255, 255, 255, 0.6); margin-top: 4px; } .ss-scores strong { color: #fff; } .ss-next-btn { display: block; width: 100%; margin-top: 10px; padding: 8px; font-size: 0.9rem; } /* --- V3_11: Swap Animation --- */ .traveling-card { position: fixed; border-radius: 6px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4); } /* ============================================ MOBILE PORTRAIT LAYOUT ============================================ All rules scoped under body.mobile-portrait. Triggered by JS matchMedia on narrow portrait screens. Desktop layout is completely untouched. ============================================ */ /* Mobile bottom bar - hidden on desktop */ #mobile-bottom-bar { display: none; } body.mobile-portrait { overscroll-behavior: contain; touch-action: manipulation; } body.mobile-portrait #app { padding: 0; } /* Lock viewport only when game screen is active (allow scrolling on rules, lobby, etc.) */ body.mobile-portrait:has(#game-screen.active) { height: var(--app-height, 100vh); overflow: hidden; } body.mobile-portrait:has(#game-screen.active) #app { height: var(--app-height, 100vh); overflow: hidden; } /* --- Mobile: Game screen fills viewport --- */ /* IMPORTANT: Must include .active to avoid overriding .screen { display: none } */ body.mobile-portrait #game-screen.active { height: var(--app-height, 100vh); max-height: var(--app-height, 100vh); overflow: hidden; margin-left: 0; width: 100%; padding: 0; display: flex; flex-direction: column; } body.mobile-portrait .game-layout { flex: 1 1 0%; flex-direction: column; overflow: hidden; min-height: 0; max-height: 100%; } body.mobile-portrait .game-main { flex: 1 1 0%; gap: 0; justify-content: flex-start; overflow: hidden; min-height: 0; max-height: 100%; } /* --- Mobile: Compact header (single row) --- */ body.mobile-portrait .game-header { display: flex; flex-direction: row; align-items: center; padding: 6px 8px; padding-top: calc(6px + env(safe-area-inset-top, 0px)); font-size: 0.75rem; min-height: 0; width: 100%; margin-left: 0; gap: 4px; margin-bottom: 4px; background: linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 0%, transparent 100%); } body.mobile-portrait .header-col-left { flex: 0 0 auto; gap: 6px; } body.mobile-portrait .header-col-center { flex: 1; min-width: 0; } body.mobile-portrait .header-col-right { flex: 0 0 auto; gap: 4px; } /* Hide items moved to bottom bar on mobile */ body.mobile-portrait .active-rules-bar, body.mobile-portrait .game-username, body.mobile-portrait #game-logout-btn, body.mobile-portrait .game-header .round-info, body.mobile-portrait .game-header #leave-game-btn { display: none !important; } body.mobile-portrait .rules-container, body.mobile-portrait .leaderboard-container, body.mobile-portrait #matchmaking-screen { margin-top: 50px; } body.mobile-portrait .header-col-center { justify-content: flex-start; } body.mobile-portrait .status-message { font-size: 1.02rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } body.mobile-portrait .round-info { font-size: 0.75rem; white-space: nowrap; } body.mobile-portrait #leave-game-btn { padding: 2px 6px; font-size: 0.6rem; white-space: nowrap; } body.mobile-portrait .mute-btn { font-size: 0.95rem; padding: 2px; } body.mobile-portrait .final-turn-badge { padding: 6px 16px; white-space: nowrap; } body.mobile-portrait .final-turn-badge .final-turn-text { font-size: 1.02rem; } /* --- Mobile: Game table — opponents pinned top, rest centered in remaining space --- */ body.mobile-portrait .game-table { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 0 !important; flex: 1 1 0%; overflow-x: clip; overflow-y: hidden; padding: 0 10px; min-height: 0; max-height: 100%; } /* --- Mobile: Opponents wrap at 3 per row (max 5 opponents = 3+2) --- */ body.mobile-portrait .opponents-row { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; gap: 9px 10px; min-height: 0 !important; padding: 2px 4px 12px; overflow: visible; flex-shrink: 0; } /* --- Mobile: Player row gets remaining space, centered vertically --- */ body.mobile-portrait .player-row { display: flex; flex-direction: column; align-items: center; justify-content: space-evenly; gap: 10px; width: 100%; flex: 1 1 0%; min-height: 0; max-height: 100%; overflow: hidden; } /* Remove all arch rotation and margin on mobile */ body.mobile-portrait .opponents-row .opponent-area { margin-bottom: 0 !important; transform: none !important; } body.mobile-portrait .opponent-area { padding: 3px 4px 4px; border-radius: 6px; min-width: 0; flex: 0 0 calc((100% - 20px) / 3); position: relative; overflow: visible; } body.mobile-portrait .opponent-area .dealer-chip { width: 20px; height: 20px; font-size: 10px; border-width: 2px; bottom: -6px; left: -6px; } body.mobile-portrait .opponent-area h4 { font-size: 0.85rem; margin: 0 0 2px 0; padding: 2px 4px; width: 100%; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; } body.mobile-portrait .opponent-area .card-grid { grid-template-columns: repeat(3, 35px) !important; gap: 2px !important; } body.mobile-portrait .opponent-area .card { width: 35px !important; height: 49px !important; font-size: 1.05rem !important; line-height: 1.05; border-radius: 3px; } body.mobile-portrait .opponent-area .knocker-badge { top: auto; bottom: -10px; } body.mobile-portrait .opponent-showing { font-size: 0.85rem; padding: 0px 3px; margin-left: 3px; } /* --- Mobile: Deck/Discard area centered --- */ body.mobile-portrait .table-center { padding: 20px 10px 5px; border-radius: 8px; } body.mobile-portrait .deck-area { gap: 10px; align-items: flex-start; } body.mobile-portrait .deck-area .card, body.mobile-portrait #deck, body.mobile-portrait #discard { width: 64px !important; height: 90px !important; font-size: 1.4rem !important; } /* Held card floating should NOT be constrained to deck/discard size */ body.mobile-portrait .held-card-floating { width: 64px !important; height: 90px !important; } body.mobile-portrait .discard-stack { gap: 6px; } /* Discard button - horizontal on mobile instead of vertical tab */ body.mobile-portrait #discard-btn { position: fixed; writing-mode: horizontal-tb; text-orientation: initial; width: auto; padding: 6px 18px; font-size: 0.8rem; border-radius: 8px; } /* --- Mobile: Player cards — explicit sizes for reliable layout --- */ body.mobile-portrait .player-section { width: auto; padding: 0; } body.mobile-portrait .player-area { padding: 5px 8px 9px; border-radius: 8px; width: auto; display: inline-block; margin-bottom: 6px; } body.mobile-portrait .player-area .dealer-chip { width: 22px; height: 22px; font-size: 11px; border-width: 2px; top: auto; bottom: -8px; left: -8px; } body.mobile-portrait .player-area h4 { font-size: 0.8rem; padding: 3px 8px; margin-bottom: 4px; } body.mobile-portrait .player-showing { font-size: 0.75rem; } /* Player hand: fixed-size cards */ body.mobile-portrait .player-section .card-grid { grid-template-columns: repeat(3, 64px) !important; gap: 5px !important; justify-content: center; } body.mobile-portrait .player-section .card { width: 64px !important; height: 90px !important; font-size: 1.4rem !important; } /* Real cards: font-size is now set inline by card-manager.js (proportional to card width). Override the desktop clamp values to inherit from the element. */ body.mobile-portrait .real-card .card-face-front, body.mobile-portrait .real-card .card-face-back { font-size: inherit; line-height: 1; } /* --- Mobile: Side panels become bottom drawers --- */ body.mobile-portrait .side-panel { position: fixed; bottom: 0; left: 0; right: 0; width: 100%; max-height: 55vh; border-radius: 16px 16px 0 0; padding: 12px 16px; padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 600; transform: translateY(100%); transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1); overflow-y: auto; -webkit-overflow-scrolling: touch; box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.4); } body.mobile-portrait .side-panel.left-panel, body.mobile-portrait .side-panel.right-panel { left: 0; right: 0; } body.mobile-portrait .side-panel.drawer-open { transform: translateY(0); } /* Drawer handle */ body.mobile-portrait .side-panel::before { content: ''; display: block; width: 40px; height: 4px; background: rgba(255, 255, 255, 0.3); border-radius: 2px; margin: 0 auto 10px; } /* Drawer backdrop */ body.mobile-portrait .drawer-backdrop { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 599; opacity: 0; pointer-events: none; transition: opacity 0.3s cubic-bezier(0.32, 0.72, 0, 1); } body.mobile-portrait .drawer-backdrop.visible { opacity: 1; pointer-events: auto; } /* Score table in drawer: full width */ body.mobile-portrait .side-panel table { width: 100%; font-size: 0.85rem; } body.mobile-portrait .side-panel th, body.mobile-portrait .side-panel td { padding: 4px 8px; } /* Standings list in drawer */ body.mobile-portrait .standings-list .rank-row { font-size: 0.85rem; padding: 3px 0; } /* Game buttons in drawer */ body.mobile-portrait .game-buttons { display: flex; gap: 8px; justify-content: center; padding: 8px 0; } /* --- Mobile: Bottom bar --- */ body.mobile-portrait #mobile-bottom-bar { display: flex; justify-content: space-between; align-items: center; align-self: stretch; gap: 8px; background: none; flex-shrink: 0; padding: 6px 12px; padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px)); z-index: 900; } /* Hole indicator — pinned left */ body.mobile-portrait #mobile-bottom-bar .mobile-round-info { margin-right: auto; color: rgba(255, 255, 255, 0.9); font-size: 0.77rem; font-weight: 700; white-space: nowrap; letter-spacing: 0.03em; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.15); border-radius: 20px; padding: 4px 9px; } /* End Game — pinned right */ body.mobile-portrait #mobile-bottom-bar .mobile-leave-btn { margin-left: auto; background: rgba(180, 60, 60, 0.3) !important; border-color: rgba(220, 80, 80, 0.4) !important; color: rgba(255, 120, 120, 0.9) !important; } body.mobile-portrait #mobile-bottom-bar .mobile-leave-btn:active { background: rgba(180, 60, 60, 0.5) !important; } body.mobile-portrait #mobile-bottom-bar .mobile-bar-btn { background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.65); font-size: 0.7rem; font-weight: 600; padding: 5px 10px; cursor: pointer; text-transform: uppercase; letter-spacing: 0.1em; border-radius: 20px; transition: all 0.25s ease; position: relative; -webkit-tap-highlight-color: transparent; } body.mobile-portrait #mobile-bottom-bar .mobile-bar-btn:active { transform: scale(0.95); } body.mobile-portrait #mobile-bottom-bar .mobile-bar-btn.active { color: #1a1a2e; background: linear-gradient(135deg, #f4a460, #e8935a); border-color: transparent; box-shadow: 0 2px 12px rgba(244, 164, 96, 0.4); } /* --- Mobile: Rules indicator button --- */ body.mobile-portrait #mobile-bottom-bar .mobile-rules-btn { padding: 4px 9px; font-size: 0.77rem; font-weight: 700; min-width: unset; background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.15); color: rgba(255, 255, 255, 0.7); } body.mobile-portrait #mobile-bottom-bar .mobile-rules-btn.house-rules { background: rgba(244, 164, 96, 0.25); border-color: rgba(244, 164, 96, 0.4); color: #f4a460; } /* --- Mobile: Rules drawer content --- */ #rules-drawer { display: none; } body.mobile-portrait #rules-drawer { display: block; } body.mobile-portrait .rules-drawer-panel .mobile-rules-content-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } body.mobile-portrait .rules-drawer-panel .rule-tag { background: rgba(244, 164, 96, 0.3); color: #f4a460; padding: 4px 10px; border-radius: 4px; font-size: 0.8rem; font-weight: 600; } body.mobile-portrait .rules-drawer-panel .rule-tag.standard { background: rgba(255, 255, 255, 0.15); color: rgba(255, 255, 255, 0.7); } body.mobile-portrait .rules-drawer-panel .rule-tag.unranked { background: rgba(220, 80, 80, 0.3); color: #f08080; border: 1px solid rgba(220, 80, 80, 0.4); } /* --- Mobile: Non-game screens --- */ body.mobile-portrait #lobby-screen { padding: 55px 12px 15px; overflow-y: auto; max-height: 100dvh; } body.mobile-portrait #waiting-screen { padding: 10px 15px; overflow-y: auto; max-height: 100dvh; } /* --- Mobile: Compact scoresheet modal --- */ body.mobile-portrait .scoresheet-content { padding: 14px 16px; max-height: 90vh; max-height: var(--app-height, 90vh); } body.mobile-portrait .ss-header { font-size: 0.95rem; margin-bottom: 10px; } body.mobile-portrait .ss-players { gap: 8px; } body.mobile-portrait .ss-player-row { padding: 8px 10px; } body.mobile-portrait .ss-player-header { margin-bottom: 4px; } body.mobile-portrait .ss-player-name { font-size: 0.8rem; } body.mobile-portrait .ss-mini-card { width: 30px; height: 22px; font-size: 0.6rem; } body.mobile-portrait .ss-columns { gap: 6px; margin-bottom: 4px; } body.mobile-portrait .ss-column { gap: 2px; padding: 3px 4px; } body.mobile-portrait .ss-col-score { font-size: 0.6rem; } body.mobile-portrait .ss-scores { font-size: 0.7rem; gap: 12px; margin-top: 2px; } body.mobile-portrait .ss-next-btn { margin-top: 10px; padding: 8px; font-size: 0.85rem; } /* --- Mobile: Very short screens (e.g. iPhone SE) --- */ @media (max-height: 600px) { body.mobile-portrait .opponents-row { padding: 2px 8px 0; } body.mobile-portrait .opponent-area .card-grid { grid-template-columns: repeat(3, 29px) !important; gap: 1px !important; } body.mobile-portrait .opponent-area .card { width: 29px !important; height: 40px !important; font-size: 0.8rem !important; line-height: 1.05; } body.mobile-portrait .table-center { padding: 3px 8px; } body.mobile-portrait .deck-area .card, body.mobile-portrait #deck, body.mobile-portrait #discard { width: 60px !important; height: 84px !important; font-size: 1.3rem !important; } body.mobile-portrait .held-card-floating { width: 60px !important; height: 84px !important; } body.mobile-portrait .player-row { gap: 6px; } body.mobile-portrait .player-area { padding: 3px 5px; } body.mobile-portrait .player-section .card-grid { grid-template-columns: repeat(3, 60px) !important; gap: 4px !important; } body.mobile-portrait .player-section .card { width: 60px !important; height: 84px !important; font-size: 1.3rem !important; } body.mobile-portrait .player-area h4 { font-size: 0.7rem; padding: 2px 6px; margin-bottom: 3px; } }