ChessNut/public/styles/style.css
2025-12-08 13:55:57 +01:00

734 lines
15 KiB
CSS

/* 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.dark {
background: linear-gradient(180deg, #fff8f4, #fff1ec);
}
.square.light {
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;
}