/* Compiled CSS (from style.scss) - included directly so no build step is required */ * { box-sizing: border-box; } html, body { height: 100%; } body { font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; margin: 0; padding: 28px; background: linear-gradient(180deg, #fff7f0 0%, #f3f6f9 60%); color: #0b1220; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .page { max-width: 1100px; margin: 0 auto; } header h2 { margin: 0 0 12px 0; color: #0b1220; } .card { background: linear-gradient(180deg, #fffaf6, #ffffff); border: 1px solid rgba(11, 18, 32, 0.06); padding: 18px; border-radius: 14px; box-shadow: 0 10px 30px rgba(11, 18, 32, 0.06); } button { background: linear-gradient(90deg, #ff7a59, #ffb199); color: #1b1b1f; border: none; padding: 10px 14px; border-radius: 12px; cursor: pointer; font-weight: 700; box-shadow: 0 8px 20px rgba(255, 122, 89, 0.12); transition: transform 160ms ease, box-shadow 160ms ease; } button[disabled] { opacity: 0.6; cursor: not-allowed; } input[type="text"], input[type="search"] { padding: 8px; border-radius: 8px; border: 1px solid rgba(11, 18, 32, 0.06); background: transparent; color: inherit; } a { color: #2563eb; text-decoration: none; } a:hover { text-decoration: underline; } #log { white-space: pre-wrap; border-radius: 8px; background: #f3f6f9; padding: 8px; height: 280px; overflow: auto; color: #0b1220; } #board { width: 800px; height: 800px; display: grid; grid-template-columns: repeat(8, 1fr); border-radius: 6px; overflow: hidden; background-size: cover; } @media (max-width: 900px) { #board { width: min(92vw, 680px); height: min(92vw, 680px); } } .muted { opacity: 0.9; color: #475569; } .controls { display: flex; gap: 8px; align-items: center; } #players { margin: 6px 0; padding-left: 18px; } /* invite button - dark text for light theme */ #copyInviteBtn { background: transparent; border: 1px solid rgba(11, 18, 32, 0.06); color: #0b1220; padding: 6px 10px; border-radius: 8px; } #youAreHost { background: rgba(255, 255, 255, 0.04); padding: 6px 8px; border-radius: 6px; margin-left: 6px; } /* layout helpers used from game.html */ .layout-row { display: flex; gap: 20px; align-items: flex-start; } #turnBanner { color: #5a2b12; background: linear-gradient(90deg, #fff1e6, #ffe6da); padding: 10px 14px; border-radius: 12px; font-weight: 800; display: none; border: 1px solid rgba(90, 43, 18, 0.06); box-shadow: 0 6px 18px rgba(90, 43, 18, 0.04); } #turnBanner.show { display: inline-block; } /* board tweaks */ #board { border: 1px solid rgba(11, 18, 32, 0.06); position: relative; background-image: url("/assets/chess-pieces/boards/8x8_wood.svg"); background-size: cover; } /* square cells and piece images (used by renderFen) */ .square { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; } .square img, .piece { max-width: 78%; max-height: 78%; user-select: none; position: relative; z-index: 3; } /* marker shown on target squares for legal moves */ .square { position: relative; } .square .move-marker { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 18%; height: 18%; border-radius: 50%; pointer-events: auto; cursor: pointer; background: rgba(37, 99, 235, 0.95); box-shadow: 0 2px 6px rgba(11, 18, 32, 0.06); z-index: 3; transition: transform 120ms ease, opacity 120ms ease; } .square .move-marker:hover { transform: translate(-50%, -50%) scale(1.12); opacity: 0.95; } /* square highlight when selecting a target for a card: a small hollow ring strictly inside the square */ .square.targetable { outline: none; box-shadow: none; } .square.targetable::after { content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 36%; height: 36%; border-radius: 50%; border: 2px solid rgba(255, 121, 63, 0.98); box-shadow: 0 6px 18px rgba(255, 121, 63, 0.1) inset; pointer-events: none; z-index: 3; } /* small circular mine marker strictly inside the square */ .square .mine-dot { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 36%; height: 36%; border-radius: 50%; background: radial-gradient( circle at 30% 30%, #fff2ea 0%, #ff9a76 30%, #c94b2b 100% ); box-shadow: inset 0 2px 8px rgba(255, 255, 255, 0.28), 0 4px 12px rgba(0, 0, 0, 0.2); pointer-events: none; z-index: 2; } /* image-based mine: prefer SVG with transparent background for crisp edges */ .square .mine-img { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 40%; height: auto; max-height: 42%; pointer-events: none; z-index: 2; image-rendering: -webkit-optimize-contrast; } /* When a square is veiled by brouillard, hide its piece images to ensure full concealment This is a robust fallback in case stacking context / transform interactions make an overlay not fully cover the image. Hiding the image guarantees the piece is not visible. */ .square.veiled img, .square.veiled .piece { visibility: hidden !important; opacity: 0 !important; } /* highlighted/selected square when a player selects a piece */ .square.selected { outline: 3px solid rgba(245, 158, 11, 0.95); /* amber */ box-shadow: inset 0 0 0 3px rgba(245, 158, 11, 0.06), 0 8px 20px rgba(11, 18, 32, 0.04); z-index: 4; } .square.selected .piece { transform: scale(1.04); transition: transform 140ms ease; } /* hide the visual selection outline for a square while keeping the piece visible */ .square.hide-selection.selected, .square.hide-selection.selected-remote { outline: none !important; box-shadow: none !important; } .square.hide-selection { transition: background 120ms ease; } /* remote selection (other player's selection) */ .square.selected-remote { outline: 3px solid rgba(37, 99, 235, 0.95); /* blue */ box-shadow: inset 0 0 0 3px rgba(37, 99, 235, 0.06), 0 6px 16px rgba(11, 18, 32, 0.04); z-index: 3; } .square.selected-remote .piece { transform: scale(1.02); transition: transform 140ms ease; } /* basic checkerboard coloring */ .square.light { background: linear-gradient(180deg, #fff8f4, #fff1ec); } .quare.dark { background: linear-gradient(180deg, #fdeee2, #f6d9c5); } .square.dark { background: linear-gradient(180deg, #fdeee2, #f6d9c5); } .square { border: 1px solid rgba(0, 0, 0, 0.06); } /* flipped board for black perspective */ #board.flipped { transform: rotate(180deg); } #board.flipped .square img { transform: rotate(180deg); } /* Lobby / hero styles - decorative and fun */ .hero { display: flex; align-items: center; justify-content: space-between; padding: 28px; border-radius: 12px; margin-bottom: 18px; overflow: hidden; position: relative; border: 1px solid rgba(11, 18, 32, 0.04); background: linear-gradient( 135deg, rgba(99, 102, 241, 0.06), rgba(99, 102, 241, 0.03) ); } .hero .title { font-size: 28px; font-weight: 800; letter-spacing: -0.5px; } .hero .subtitle { color: rgba(11, 18, 32, 0.65); margin-top: 6px; font-weight: 500; } .hero .decor { position: absolute; right: -80px; top: -60px; opacity: 0.06; width: 420px; height: 420px; filter: blur(6px); transform: rotate(20deg); } .card.lobby { display: flex; gap: 12px; align-items: center; justify-content: space-between; padding: 14px; } /* buttons variants */ .btn-ghost { background: transparent; border: 1px solid rgba(11, 18, 32, 0.06); padding: 8px 10px; border-radius: 8px; color: inherit; } .btn-cta { background: linear-gradient(90deg, #3b82f6, #60a5fa); box-shadow: 0 8px 20px rgba(59, 130, 246, 0.18); } /* draw button: compact rectangular CTA used in the cards area */ .btn-draw { background: linear-gradient(90deg, #ff7a59, #ffb199); /* warm gradient */ color: #1b1b1f; padding: 10px 14px; border-radius: 12px; border: none; cursor: pointer; font-weight: 900; font-size: 14px; min-width: 140px; height: 46px; display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 10px 22px rgba(255, 122, 89, 0.12); } .btn-draw[disabled] { opacity: 0.6; cursor: not-allowed; } /* cancel button shown during pending card selection: white background, red text for clear contrast */ .btn-cancel { background: #ffffff; color: #b91c1c; /* red */ border: 1px solid rgba(185, 28, 28, 0.14); padding: 6px 8px; border-radius: 6px; cursor: pointer; font-weight: 700; } .btn-cancel:hover { background: #fff5f5; } /* explosion animation used when a mine detonates */ .explosion { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0.6); width: 64%; height: 64%; border-radius: 50%; pointer-events: none; z-index: 6; background: radial-gradient( circle at 30% 30%, rgba(255, 255, 200, 0.98) 0%, rgba(255, 160, 60, 0.95) 40%, rgba(220, 40, 40, 0.95) 60%, rgba(120, 10, 10, 0.85) 100% ); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35), inset 0 6px 18px rgba(255, 255, 255, 0.08); opacity: 1; transform-origin: 50% 50%; transform: translate(-50%, -50%) scale(0.2); } .explosion.play { animation: explode 520ms ease-out forwards; } @keyframes explode { 0% { transform: translate(-50%, -50%) scale(0.2); opacity: 1; filter: blur(0px); } 60% { transform: translate(-50%, -50%) scale(1.15); opacity: 0.95; filter: blur(1px); } 100% { transform: translate(-50%, -50%) scale(1.6); opacity: 0; filter: blur(6px); } } /* small debris puffs for a subtle effect */ .explosion::after { content: ""; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 120%; height: 120%; border-radius: 50%; background: radial-gradient( circle, rgba(255, 200, 100, 0.6) 0%, rgba(255, 200, 100, 0) 40% ); opacity: 0; animation: debris 520ms ease-out forwards; } @keyframes debris { 0% { opacity: 0.9; transform: translate(-50%, -50%) scale(0.8); } 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.8); } } /* video-based explosion: used when a .mov/mp4 file is provided in /assets/media/ */ .explosion-video { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 7; pointer-events: none; width: 160%; height: auto; max-width: 220px; max-height: 220px; display: block; object-fit: contain; } /* floating small piece icons */ .floating-piece { position: absolute; opacity: 0.06; width: 160px; height: 160px; pointer-events: none; transform: translate(-10%, -10%); } /* subtle button hover */ button:hover { transform: translateY(-3px); transition: all 180ms ease; } /* players area */ .players-list { list-style: none; padding-left: 0; margin: 0; display: flex; gap: 10px; } .players-list li { background: rgba(11, 18, 32, 0.03); padding: 6px 10px; border-radius: 8px; } /* card hand UI */ .player-hand { border: 1px solid rgba(11, 18, 32, 0.06); padding: 8px; border-radius: 8px; background: #fff; } .card-item { display: flex; gap: 8px; align-items: flex-start; background: #f8fafc; padding: 8px; border-radius: 8px; border: 1px solid rgba(11, 18, 32, 0.04); } .card-art { width: 64px; height: 60px; background: linear-gradient(180deg, #eef2ff, #ffffff); display: flex; align-items: center; justify-content: center; color: #475569; border-radius: 6px; font-size: 12px; } .card-meta { display: flex; flex-direction: column; } .card-title { font-weight: 700; color: #0b1220; } .card-desc { color: #475569; font-size: 13px; } /* Pokemon-style horizontal card hand */ .pokemon-hand { padding: 10px; border-radius: 10px; background: linear-gradient(180deg, #ffffff, #fbfdff); border: 1px solid rgba(11, 18, 32, 0.04); } .pokemon-hand-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } .pokemon-hand-title { font-weight: 800; } .pokemon-hand-counts { display: flex; gap: 6px; align-items: center; } .opponent-count { background: rgba(11, 18, 32, 0.03); padding: 4px 8px; border-radius: 8px; font-size: 12px; } .cards-row { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 6px; } .pokemon-card { flex: 0 0 180px; height: 350px; border-radius: 12px; background: linear-gradient(180deg, #fff, #f6f8ff); box-shadow: 0 10px 24px rgba(11, 18, 32, 0.06); border: 1px solid rgba(11, 18, 32, 0.04); display: flex; flex-direction: column; cursor: pointer; } .pokemon-card-top { flex: 0 0 120px; padding: 8px; } .pokemon-card-art { width: 100%; height: 100%; background: linear-gradient(135deg, #f0f9ff, #eef2ff); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #475569; font-weight: 700; } .pokemon-card-mid { padding: 8px; flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; } .pokemon-card-title { font-weight: 800; color: #0b1220; } .pokemon-card-desc { color: #475569; font-size: 13px; } .pokemon-card-footer { padding: 8px; border-top: 1px solid rgba(11, 18, 32, 0.02); display: flex; justify-content: flex-end; } .card-play-btn { background: linear-gradient(90deg, #3b82f6, #60a5fa); color: white; border: none; padding: 6px 10px; border-radius: 8px; cursor: pointer; } .card-play-btn:hover { transform: translateY(-2px); } /* small responsive tweak */ @media (max-width: 700px) { .pokemon-card { flex: 0 0 140px; height: 220px; } } /* shuffle animation: quick jitter + opacity pulse to emphasize randomization */ #board.shuffle-play { transition: transform 700ms cubic-bezier(0.2, 0.9, 0.2, 1), opacity 700ms ease; transform: translateY(-6px) rotate(-1deg) scale(0.995); opacity: 0.9; } #board.shuffle-play .square img { transition: transform 700ms cubic-bezier(0.2, 0.9, 0.2, 1); transform: rotate(2deg) scale(0.995); filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.06)); } .square.targeted::after { content: ""; position: absolute; left: 0; top: 0; right: 0; bottom: 0; background: rgb(255, 201, 201); pointer-events: none; z-index: 2; } .square.last-move-dest::after { content: ""; position: absolute; left: 0; top: 0; right: 0; bottom: 0; background: rgb(212, 255, 241); pointer-events: none; z-index: 2; } .square.last-move-source::after { content: ""; position: absolute; left: 0; top: 0; right: 0; bottom: 0; background: rgb(212, 255, 241); pointer-events: none; z-index: 2; }