diff --git a/assets/css/homepage/_animations.scss b/assets/css/homepage/_animations.scss new file mode 100644 index 0000000..7f42902 --- /dev/null +++ b/assets/css/homepage/_animations.scss @@ -0,0 +1,9 @@ +@keyframes appear { + from { opacity: 0; transform: scale(0.94); } + to { opacity: 1; transform: scale(1); } +} + +@keyframes rise { + from { opacity: 0; transform: translateY(16px); } + to { opacity: 1; transform: translateY(0); } +} \ No newline at end of file diff --git a/assets/css/homepage/_auth-bar.scss b/assets/css/homepage/_auth-bar.scss new file mode 100644 index 0000000..d858b1d --- /dev/null +++ b/assets/css/homepage/_auth-bar.scss @@ -0,0 +1,80 @@ +.hero-auth { + position: absolute; + top: 28px; + right: 36px; + display: flex; + align-items: center; + gap: 10px; + z-index: 10; +} + +.hero-auth-user { + font: 600 13px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.75); + letter-spacing: 0.5px; + display: flex; + align-items: center; + gap: 6px; + + i { font-size: 15px; } +} + +.hero-auth-btn { + display: inline-flex; + align-items: center; + gap: 6px; + font: 600 12px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 1.5px; + text-decoration: none; + color: rgba(255, 255, 255, 0.6); + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 4px; + padding: 7px 14px; + cursor: pointer; + transition: all 200ms ease; + + &:hover { + color: #fff; + background: rgba(255, 255, 255, 0.12); + border-color: rgba(255, 255, 255, 0.25); + } + + &--register { + color: rgba(149, 207, 245, 0.8); + border-color: rgba(35, 111, 135, 0.4); + background: rgba(35, 111, 135, 0.12); + + &:hover { + color: #fff; + background: rgba(35, 111, 135, 0.28); + border-color: rgba(149, 207, 245, 0.5); + } + } + + &--out { + background: transparent; + border-color: rgba(173, 10, 5, 0.3); + color: rgba(246, 125, 82, 0.7); + + &:hover { + background: rgba(173, 10, 5, 0.15); + border-color: rgba(246, 125, 82, 0.5); + color: #f67d52; + } + } + + &--profile { + color: rgba(149, 207, 245, 0.8); + border-color: rgba(35, 111, 135, 0.35); + background: rgba(35, 111, 135, 0.08); + text-decoration: none; + + &:hover { + color: #fff; + background: rgba(35, 111, 135, 0.22); + border-color: rgba(149, 207, 245, 0.5); + } + } +} \ No newline at end of file diff --git a/assets/css/homepage/_auth.scss b/assets/css/homepage/_auth.scss new file mode 100644 index 0000000..6a60d6b --- /dev/null +++ b/assets/css/homepage/_auth.scss @@ -0,0 +1,219 @@ +.auth-page { + display: flex; + flex-direction: column; + align-items: center; + padding: 40px 20px 80px; +} + +.auth-flash { + width: 100%; + max-width: 420px; + padding: 12px 18px; + border-radius: 5px; + font: 600 14px 'Rajdhani', sans-serif; + letter-spacing: 0.5px; + margin-bottom: 20px; + display: flex; + align-items: center; + gap: 8px; + + &--success { + background: rgba(26, 104, 68, 0.25); + border: 1px solid rgba(42, 158, 96, 0.4); + color: #a0f0c0; + } + + &--error { + background: rgba(173, 10, 5, 0.18); + border: 1px solid rgba(173, 10, 5, 0.4); + color: #f6a090; + } +} + +// "Check your inbox" confirmation card +.auth-card--sent { + text-align: center; + padding: 48px 40px; +} + +.auth-sent-icon { + font-size: 52px; + color: rgba(149, 207, 245, 0.6); + margin-bottom: 20px; + filter: drop-shadow(0 0 16px rgba(35, 111, 135, 0.4)); +} + +.auth-sent-email { + font: 700 16px 'Rajdhani', sans-serif; + color: #95cff5; + letter-spacing: 0.5px; + margin: 0 0 20px; + word-break: break-all; +} + +.auth-sent-note { + font: 400 14px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.5); + line-height: 1.7; + margin-bottom: 0; + + strong { color: rgba(255, 255, 255, 0.75); } +} + +.auth-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(35, 111, 135, 0.2); + border-radius: 10px; + padding: 44px 48px 40px; + width: 100%; + max-width: 420px; + backdrop-filter: blur(4px); + box-shadow: 0 8px 48px rgba(0, 0, 0, 0.5); +} + +.auth-title { + font: 800 30px 'Rajdhani', sans-serif; + color: #ffffff; + letter-spacing: 1px; + margin-bottom: 6px; +} + +.auth-sub { + font: 400 14px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.6); + letter-spacing: 0.5px; + margin-bottom: 32px; +} + +.auth-error { + background: rgba(173, 10, 5, 0.18); + border: 1px solid rgba(173, 10, 5, 0.4); + border-radius: 5px; + padding: 10px 14px; + font: 600 13px 'Rajdhani', sans-serif; + color: #f6a090; + margin-bottom: 24px; + display: flex; + align-items: center; + gap: 8px; +} + +.auth-form { + display: flex; + flex-direction: column; + gap: 20px; +} + +.auth-field { + display: flex; + flex-direction: column; + gap: 7px; +} + +.auth-label { + font: 700 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 2px; + color: rgba(255, 255, 255, 0.45); +} + +.auth-input-wrap { + position: relative; + display: flex; + align-items: center; +} + +.auth-input-icon { + position: absolute; + left: 11px; + color: rgba(149, 207, 245, 0.4); + font-size: 13px; + pointer-events: none; +} + +.auth-input { + width: 100%; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(35, 111, 135, 0.3); + border-radius: 5px; + padding: 11px 14px 11px 34px; + font: 500 15px 'Rajdhani', sans-serif; + color: #ffffff; + letter-spacing: 0.5px; + transition: border-color 200ms ease, background 200ms ease; + + &::placeholder { color: rgba(255, 255, 255, 0.2); } + + &:focus { + outline: none; + background: rgba(35, 111, 135, 0.1); + border-color: rgba(149, 207, 245, 0.5); + } + + &--error { + border-color: rgba(173, 10, 5, 0.6) !important; + } +} + +.auth-field-error { + font: 500 12px 'Rajdhani', sans-serif; + color: #f6a090; + letter-spacing: 0.3px; +} + +.auth-remember { + display: flex; + align-items: center; + gap: 8px; + font: 500 13px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.45); + cursor: pointer; + user-select: none; + margin-top: -4px; + + input[type="checkbox"] { accent-color: #236f87; } +} + +.auth-submit { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + background: linear-gradient(to bottom, #ad0a05 0%, #d4401a 55%, #f67d52 100%); + border: 1px solid rgba(246, 125, 82, 0.3); + border-radius: 5px; + color: #ffffff; + font: 700 16px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 3px; + padding: 14px; + cursor: pointer; + margin-top: 6px; + box-shadow: 0 4px 20px rgba(173, 10, 5, 0.35); + transition: all 220ms ease; + + &:hover { + background: linear-gradient(to bottom, #c91008 0%, #e5521e 55%, #ff8c61 100%); + box-shadow: 0 6px 28px rgba(173, 10, 5, 0.6); + transform: translateY(-2px); + } + + &:active { transform: translateY(0); } +} + +.auth-switch { + font: 400 13px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.35); + text-align: center; + margin-top: 24px; + letter-spacing: 0.3px; + + a { + color: #95cff5; + text-decoration: none; + font-weight: 600; + transition: color 180ms; + + &:hover { color: #c5e8ff; } + } +} \ No newline at end of file diff --git a/assets/css/homepage/_content.scss b/assets/css/homepage/_content.scss new file mode 100644 index 0000000..e0ce921 --- /dev/null +++ b/assets/css/homepage/_content.scss @@ -0,0 +1,35 @@ +main div.txt { + color: rgba(255, 255, 255, 0.85); + max-width: 900px; + margin: 0 auto; + padding: 60px 40px 80px; +} + +main div.txt h2 { + font: bold 28px 'Rajdhani', sans-serif; + color: #ffffff; + margin-bottom: 30px; + letter-spacing: 1px; +} + +main div.txt h3 { + font: bold 17px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.9); + margin: 28px 0 10px; + letter-spacing: 0.5px; +} + +main div.txt p, +main div.txt li { + font: 400 15px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.72); + line-height: 1.75; +} + +main div.txt a { + color: #95cff5; + text-decoration: none; + transition: color 180ms; + + &:hover { color: #c5e8ff; } +} \ No newline at end of file diff --git a/assets/css/homepage/_cta.scss b/assets/css/homepage/_cta.scss new file mode 100644 index 0000000..f2d0d77 --- /dev/null +++ b/assets/css/homepage/_cta.scss @@ -0,0 +1,75 @@ +.hero-cta { + position: relative; + display: inline-block; + font: 800 28px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 6px; + text-decoration: none; + color: #ffffff; + padding: 22px 100px 20px; + border-radius: 4px; + border: 1px solid rgba(246, 125, 82, 0.25); + + background: linear-gradient(to bottom, #b30c06 0%, #d63d15 50%, #f67d52 100%); + + box-shadow: + 0 0 0 1px rgba(173, 10, 5, 0.2), + 0 0 30px rgba(173, 10, 5, 0.35), + 0 6px 24px rgba(0, 0, 0, 0.5), + inset 0 1px 0 rgba(255, 255, 255, 0.12); + + transition: transform 220ms ease, box-shadow 220ms ease, letter-spacing 220ms ease; + animation: rise 0.8s 0.42s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +// Outer glow layer (blurred duplicate, always visible) +.hero-cta::before { + content: ''; + position: absolute; + inset: -4px; + border-radius: 7px; + background: linear-gradient(to bottom, #ad0a05, #f67d52); + filter: blur(18px); + opacity: 0.3; + z-index: -1; + transition: opacity 220ms ease; +} + +.hero-cta:hover { + transform: translateY(-4px); + letter-spacing: 8px; + box-shadow: + 0 0 0 1px rgba(246, 125, 82, 0.3), + 0 0 50px rgba(173, 10, 5, 0.65), + 0 10px 32px rgba(0, 0, 0, 0.45), + inset 0 1px 0 rgba(255, 255, 255, 0.15); +} + +.hero-cta:hover::before { + opacity: 0.55; +} + +.hero-cta:active { + transform: translateY(-1px); +} + +// Version / copyright line +.hero-meta { + position: relative; + z-index: 1; + font: 400 12px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.5); + letter-spacing: 0.5px; + margin-top: 58px; + animation: rise 0.8s 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +.hero-meta a { + color: rgba(149, 207, 245, 0.65); + text-decoration: none; + transition: color 180ms; +} + +.hero-meta a:hover { + color: #95cff5; +} \ No newline at end of file diff --git a/assets/css/homepage/_features.scss b/assets/css/homepage/_features.scss new file mode 100644 index 0000000..e9729a4 --- /dev/null +++ b/assets/css/homepage/_features.scss @@ -0,0 +1,202 @@ +.feature-block { + width: 100%; + padding: 80px 40px; + position: relative; + + &:first-of-type { + border-top: 1px solid rgba(35, 111, 135, 0.12); + } + + & + & { + border-top: 1px solid rgba(255, 255, 255, 0.05); + } +} + +.feature-block__inner { + display: flex; + align-items: center; + gap: 80px; + max-width: 1100px; + margin: 0 auto; +} + +.feature-block--reverse .feature-block__inner { + flex-direction: row-reverse; +} + +// Visual side +.feature-block__visual { + flex: 0 0 340px; + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +// Stats icons cluster +.feature-block__visual--stats { + height: 260px; + gap: 0; + + i { + position: absolute; + color: rgba(35, 111, 135, 0.5); + transition: color 300ms ease; + } + + // Bar chart — large, centre + i.fa-bar-chart { + font-size: 140px; + color: rgba(35, 111, 135, 0.35); + filter: drop-shadow(0 0 30px rgba(35, 111, 135, 0.3)); + } + + // Trophy — top right + i.fa-trophy { + font-size: 64px; + top: 12px; + right: 30px; + color: rgba(246, 125, 82, 0.5); + filter: drop-shadow(0 0 16px rgba(246, 125, 82, 0.25)); + } + + // History — bottom left + i.fa-history { + font-size: 52px; + bottom: 18px; + left: 30px; + color: rgba(149, 207, 245, 0.4); + filter: drop-shadow(0 0 12px rgba(149, 207, 245, 0.2)); + } + + &:hover i.fa-bar-chart { color: rgba(35, 111, 135, 0.6); } + &:hover i.fa-trophy { color: rgba(246, 125, 82, 0.75); } + &:hover i.fa-history { color: rgba(149, 207, 245, 0.65); } +} + +// MSN visual +.feature-block__visual--msn { + flex-direction: column; + align-items: center; + gap: 20px; + position: relative; +} + +.msn-logo { + width: 90px; + height: 90px; + object-fit: contain; + filter: drop-shadow(0 0 18px rgba(149, 207, 245, 0.3)) brightness(1.1); + flex-shrink: 0; + z-index: 1; +} + +.msn-screenshot { + width: 340px; + max-width: 100%; + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.08); + box-shadow: + 0 8px 40px rgba(0, 0, 0, 0.6), + 0 0 0 1px rgba(35, 111, 135, 0.12); + filter: saturate(0.85) brightness(0.9); + transition: filter 300ms ease; + + &:hover { + filter: saturate(1) brightness(1); + } +} + +// Text side +.feature-block__text { + flex: 1; + min-width: 0; +} + +.feature-block__label { + font: 700 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 4px; + color: rgba(149, 207, 245, 0.55); + margin-bottom: 12px; +} + +.feature-block__title { + font: 800 40px 'Rajdhani', sans-serif; + color: #ffffff; + line-height: 1.1; + letter-spacing: 0.5px; + margin-bottom: 18px; +} + +.feature-block__body { + font: 400 16px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.62); + line-height: 1.8; + margin-bottom: 0; +} + +.feature-block__cta { + display: inline-flex; + align-items: center; + gap: 8px; + margin-top: 28px; + font: 700 14px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 2px; + text-decoration: none; + color: rgba(149, 207, 245, 0.85); + border: 1px solid rgba(35, 111, 135, 0.4); + background: rgba(35, 111, 135, 0.1); + padding: 11px 24px; + border-radius: 4px; + transition: all 200ms ease; + + &:hover { + background: rgba(35, 111, 135, 0.25); + border-color: rgba(149, 207, 245, 0.55); + color: #fff; + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(35, 111, 135, 0.25); + } +} + +@media screen and (max-width: 900px) { + .feature-block__inner, + .feature-block--reverse .feature-block__inner { + flex-direction: column; + gap: 48px; + text-align: center; + } + + .feature-block__visual { + flex: none; + width: 100%; + } + + .feature-block__visual--stats { + height: 200px; + } + + .feature-block__visual--msn { + flex-direction: row; + justify-content: center; + flex-wrap: wrap; + } + + .msn-screenshot { + width: 100%; + } + + .feature-block__label, + .feature-block__cta { + margin-left: auto; + margin-right: auto; + } + + .feature-block__title { font-size: 32px; } + + .feature-block { + padding: 60px 24px; + } +} \ No newline at end of file diff --git a/assets/css/homepage/_footer.scss b/assets/css/homepage/_footer.scss new file mode 100644 index 0000000..ecb3348 --- /dev/null +++ b/assets/css/homepage/_footer.scss @@ -0,0 +1,115 @@ +footer { + background: #040608; + border-top: 1px solid rgba(35, 111, 135, 0.12); + width: 100%; +} + +.footer-inner { + display: flex; + align-items: flex-start; + justify-content: space-between; + max-width: 1100px; + margin: 0 auto; + padding: 60px 60px 52px; + gap: 40px; +} + +// Left: brand block +.footer-brand { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; +} + +.footer-logo { + width: 72px; + height: 72px; + opacity: 0.55; + filter: + drop-shadow(0 0 12px rgba(35, 111, 135, 0.4)) + brightness(1.1); + transition: opacity 250ms ease, filter 250ms ease; + + &:hover { + opacity: 0.9; + filter: + drop-shadow(0 0 20px rgba(35, 111, 135, 0.65)) + brightness(1.2); + } +} + +.footer-name { + font: 700 22px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.75); + letter-spacing: 2px; + text-transform: uppercase; + margin-top: 4px; +} + +.footer-tagline { + font: 400 13px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.7); + letter-spacing: 0.5px; + max-width: 240px; + line-height: 1.5; +} + +// Right: navigation +.footer-nav-label { + font: 700 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 4px; + color: rgba(255, 255, 255, 0.5); + margin-bottom: 18px; + text-align: left; +} + +.footer-nav ul { + list-style: none; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 6px; + min-width: 180px; +} + +.footer-nav ul li a { + display: block; + font: 500 15px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.7); + text-decoration: none; + text-transform: uppercase; + letter-spacing: 1.5px; + white-space: nowrap; + padding: 6px 0; + transition: color 180ms ease, letter-spacing 180ms ease; + + &:hover { + color: #95cff5; + letter-spacing: 2px; + } +} + +// Bottom copyright bar +.footer-copy { + border-top: 1px solid rgba(255, 255, 255, 0.05); + padding: 16px 60px; + max-width: 1100px; + margin: 0 auto; + + p { + font: 400 11px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.45); + letter-spacing: 0.5px; + text-align: center; + } + + a { + color: rgba(149, 207, 245, 0.6); + text-decoration: none; + transition: color 180ms; + + &:hover { color: #95cff5; } + } +} \ No newline at end of file diff --git a/assets/css/homepage/_header.scss b/assets/css/homepage/_header.scss new file mode 100644 index 0000000..a4226bd --- /dev/null +++ b/assets/css/homepage/_header.scss @@ -0,0 +1,39 @@ +header { + position: relative; + width: 100%; + overflow: hidden; + + // Minesweeper grid texture + background-color: #07090d; + background-image: + linear-gradient(rgba(35, 111, 135, 0.1) 1px, transparent 1px), + linear-gradient(90deg, rgba(35, 111, 135, 0.1) 1px, transparent 1px); + background-size: 46px 46px; +} + +// Deep radial vignette – grid fades toward the centre +header::before { + content: ''; + position: absolute; + inset: 0; + background: radial-gradient( + ellipse 85% 75% at 50% 50%, + #07090d 10%, + transparent 75% + ); + z-index: 0; + pointer-events: none; +} + +// Smoke at the bottom so header bleeds into body +header::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 160px; + background: linear-gradient(to bottom, transparent, #07090d); + z-index: 1; + pointer-events: none; +} \ No newline at end of file diff --git a/assets/css/homepage/_hero-compact.scss b/assets/css/homepage/_hero-compact.scss new file mode 100644 index 0000000..ea71fd7 --- /dev/null +++ b/assets/css/homepage/_hero-compact.scss @@ -0,0 +1,49 @@ +.hero--compact { + min-height: unset; + padding: 36px 60px 48px; + flex-direction: row; + align-items: center; + justify-content: center; + text-align: left; + gap: 52px; + + &::before, &::after { display: none; } + + .hero-logo { + flex-shrink: 0; + margin-bottom: 0; + + img { width: 180px; } + } + + .hero-body { + align-items: flex-start; + } + + .hero-sub { + font-size: 14px; + letter-spacing: 2px; + margin-bottom: 10px; + } + + h1 { + font-size: 26px; + margin-bottom: 24px; + letter-spacing: 0; + } + + .hero-cta { + padding: 12px 52px 10px; + font-size: 18px; + letter-spacing: 4px; + } + + .hero-meta { + margin-top: 20px; + } +} + +// Also shrink the bottom fade on sub-pages +header:has(.hero--compact)::after { + height: 60px; +} \ No newline at end of file diff --git a/assets/css/homepage/_hero.scss b/assets/css/homepage/_hero.scss new file mode 100644 index 0000000..942e6b8 --- /dev/null +++ b/assets/css/homepage/_hero.scss @@ -0,0 +1,90 @@ +.hero { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + min-height: 100vh; + padding: 80px 40px 160px; + gap: 0; +} + +// Decorative glow blobs in opposite corners +.hero::before { + content: ''; + position: absolute; + top: -60px; + left: -60px; + width: 420px; + height: 420px; + border-radius: 50%; + background: radial-gradient(circle, rgba(173, 10, 5, 0.09) 0%, transparent 65%); + pointer-events: none; + z-index: 0; +} + +.hero::after { + content: ''; + position: absolute; + bottom: 100px; + right: -60px; + width: 380px; + height: 380px; + border-radius: 50%; + background: radial-gradient(circle, rgba(35, 111, 135, 0.1) 0%, transparent 65%); + pointer-events: none; + z-index: 0; +} + +// Logo +.hero-logo { + display: block; + margin-bottom: 72px; + position: relative; + z-index: 1; + animation: appear 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +.hero-logo img { + width: 400px; + max-width: 82vw; + filter: + drop-shadow(0 0 40px rgba(35, 111, 135, 0.35)) + drop-shadow(0 6px 20px rgba(0, 0, 0, 0.8)); +} + +// Body text block +.hero-body { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 0; +} + +.hero-sub { + font: 300 17px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.9); + letter-spacing: 3px; + text-transform: uppercase; + margin-bottom: 18px; + animation: rise 0.8s 0.15s cubic-bezier(0.22, 1, 0.36, 1) both; +} + +.hero-sub strong { + font-weight: 600; + color: #95cff5; +} + +.hero h1 { + font: 800 58px 'Rajdhani', sans-serif; + color: #ffffff; + line-height: 1.1; + letter-spacing: 1px; + margin-bottom: 56px; + text-shadow: 0 4px 30px rgba(0, 0, 0, 0.7); + animation: rise 0.8s 0.28s cubic-bezier(0.22, 1, 0.36, 1) both; +} \ No newline at end of file diff --git a/assets/css/homepage/_profile.scss b/assets/css/homepage/_profile.scss new file mode 100644 index 0000000..e0d14ba --- /dev/null +++ b/assets/css/homepage/_profile.scss @@ -0,0 +1,266 @@ +.profile-page { + max-width: 760px; + margin: 0 auto; + padding: 48px 24px 80px; + display: flex; + flex-direction: column; + gap: 32px; +} + +.profile-header { + display: flex; + align-items: center; + gap: 28px; + padding: 32px 36px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(35, 111, 135, 0.2); + border-radius: 10px; + backdrop-filter: blur(4px); + box-shadow: 0 8px 48px rgba(0, 0, 0, 0.4); +} + +.profile-avatar { + width: 80px; + height: 80px; + flex-shrink: 0; + border-radius: 50%; + background: linear-gradient(135deg, rgba(35, 111, 135, 0.45) 0%, rgba(173, 10, 5, 0.3) 100%); + border: 2px solid rgba(35, 111, 135, 0.45); + display: flex; + align-items: center; + justify-content: center; + font: 800 28px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.9); + letter-spacing: 2px; + box-shadow: + 0 0 0 4px rgba(35, 111, 135, 0.08), + 0 0 24px rgba(35, 111, 135, 0.2); +} + +.profile-info { + display: flex; + flex-direction: column; + gap: 6px; + min-width: 0; +} + +.profile-name { + font: 800 32px 'Rajdhani', sans-serif; + color: #ffffff; + letter-spacing: 1px; + line-height: 1; +} + +.profile-email { + font: 400 14px 'Rajdhani', sans-serif; + color: rgba(149, 207, 245, 0.6); + letter-spacing: 0.5px; + display: flex; + align-items: center; + gap: 7px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + i { font-size: 11px; opacity: 0.7; } +} + +.profile-role { + font: 600 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 2.5px; + color: rgba(255, 255, 255, 0.25); + display: flex; + align-items: center; + gap: 6px; + + i { font-size: 10px; } +} + +.profile-stats { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 14px; +} + +.profile-stat { + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.07); + border-radius: 8px; + padding: 24px 16px 20px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + transition: border-color 200ms ease, background 200ms ease; + + &:hover { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(35, 111, 135, 0.3); + } + + &--win { + border-color: rgba(42, 158, 96, 0.18); + &:hover { border-color: rgba(42, 158, 96, 0.45); } + } + + &--loss { + border-color: rgba(173, 10, 5, 0.18); + &:hover { border-color: rgba(173, 10, 5, 0.45); } + } + + &--bomb { + border-color: rgba(246, 125, 82, 0.18); + &:hover { border-color: rgba(246, 125, 82, 0.45); } + } +} + +.profile-stat__icon { + font-size: 18px; + color: rgba(255, 255, 255, 0.15); + margin-bottom: 2px; + + .profile-stat--win & { color: rgba(94, 232, 154, 0.3); } + .profile-stat--loss & { color: rgba(246, 125, 82, 0.3); } + .profile-stat--bomb & { color: rgba(246, 125, 82, 0.25); } +} + +.profile-stat__value { + display: block; + font: 800 40px 'Rajdhani', sans-serif; + color: #ffffff; + line-height: 1; + + .profile-stat--win & { color: #5ee89a; } + .profile-stat--loss & { color: #f67d52; } + .profile-stat--bomb & { color: rgba(246, 125, 82, 0.8); } +} + +.profile-stat__label { + font: 600 10px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 2px; + color: rgba(255, 255, 255, 0.3); +} + +.profile-section { + display: flex; + flex-direction: column; + gap: 14px; +} + +.profile-section__title { + font: 700 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 4px; + color: rgba(149, 207, 245, 0.45); + display: flex; + align-items: center; + gap: 8px; + + i { opacity: 0.7; } +} + +.profile-games { + display: flex; + flex-direction: column; + gap: 6px; +} + +.profile-game { + display: grid; + grid-template-columns: 26px 76px 22px 1fr 18px auto; + align-items: center; + gap: 10px; + padding: 11px 16px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.025); + border: 1px solid rgba(255, 255, 255, 0.055); + border-left-width: 3px; + font: 500 14px 'Rajdhani', sans-serif; + transition: background 180ms ease; + + &:hover { background: rgba(255, 255, 255, 0.045); } + + &--win { border-left-color: rgba(42, 158, 96, 0.55); } + &--loss { border-left-color: rgba(173, 10, 5, 0.55); } + &--draw { border-left-color: rgba(149, 207, 245, 0.25); } +} + +.profile-game__badge { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + border-radius: 4px; + font: 800 10px 'Rajdhani', sans-serif; + letter-spacing: 0; + + .profile-game--win & { background: rgba(42, 158, 96, 0.18); color: #5ee89a; } + .profile-game--loss & { background: rgba(173, 10, 5, 0.18); color: #f67d52; } + .profile-game--draw & { background: rgba(149, 207, 245, 0.1); color: rgba(149, 207, 245, 0.65); } +} + +.profile-game__score { + font: 700 14px 'Rajdhani', sans-serif; + color: #fff; + letter-spacing: 1px; +} + +.profile-game__vs { + font: 400 10px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.22); + text-transform: uppercase; + letter-spacing: 1px; + text-align: center; +} + +.profile-game__opponent { + color: rgba(149, 207, 245, 0.7); + letter-spacing: 0.5px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.profile-game__color { + font-size: 10px; + opacity: 0.6; +} + +.profile-game__date { + font: 400 11px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.25); + letter-spacing: 0.5px; + text-align: right; + white-space: nowrap; +} + +.profile-empty { + text-align: center; + padding: 48px 20px; + color: rgba(255, 255, 255, 0.25); + + i { + font-size: 40px; + display: block; + margin-bottom: 16px; + opacity: 0.4; + } + + p { + font: 400 15px 'Rajdhani', sans-serif; + letter-spacing: 0.5px; + } + + a { + color: #95cff5; + text-decoration: none; + font-weight: 600; + transition: color 180ms; + + &:hover { color: #c5e8ff; } + } +} \ No newline at end of file diff --git a/assets/css/homepage/_reset.scss b/assets/css/homepage/_reset.scss new file mode 100644 index 0000000..9c43d4e --- /dev/null +++ b/assets/css/homepage/_reset.scss @@ -0,0 +1,23 @@ +* { + outline: none; + padding: 0; + margin: 0; + box-sizing: border-box; +} + +html { + // Grid lives on html so it tiles across all pages including content pages + background-color: #07090d; + background-image: + linear-gradient(rgba(35, 111, 135, 0.1) 1px, transparent 1px), + linear-gradient(90deg, rgba(35, 111, 135, 0.1) 1px, transparent 1px); + background-size: 46px 46px; + width: 100%; + height: 100%; +} + +body { + background: transparent; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/assets/css/homepage/_responsive.scss b/assets/css/homepage/_responsive.scss new file mode 100644 index 0000000..2c3b465 --- /dev/null +++ b/assets/css/homepage/_responsive.scss @@ -0,0 +1,100 @@ +@media screen and (max-width: 900px) { + .hero h1 { + font-size: 44px; + } + + .hero-cta { + padding: 20px 72px 18px; + font-size: 24px; + letter-spacing: 5px; + } +} + +@media screen and (max-width: 768px) { + .hero--compact { + flex-direction: column; + text-align: center; + padding: 36px 24px 44px; + gap: 28px; + + .hero-body { align-items: center; } + } + + .profile-stats { + grid-template-columns: repeat(2, 1fr); + } + + .profile-header { + flex-direction: column; + text-align: center; + padding: 28px 24px; + } + + .profile-email, + .profile-role { + justify-content: center; + } + + .profile-game { + grid-template-columns: 26px 64px 18px 1fr 14px; + + .profile-game__date { display: none; } + } + + .footer-inner { + flex-direction: column; + align-items: center; + text-align: center; + padding: 48px 30px 36px; + } + + .footer-brand { + align-items: center; + } + + .footer-tagline { + text-align: center; + } + + .footer-nav-label { + text-align: center; + } + + .footer-nav ul { + align-items: center; + } + + .footer-copy { + padding: 16px 30px; + } +} + +@media screen and (max-width: 550px) { + .hero { + padding: 60px 24px 140px; + } + + .hero-logo img { + width: 260px; + } + + .hero-logo { + margin-bottom: 52px; + } + + .hero h1 { + font-size: 32px; + margin-bottom: 40px; + } + + .hero-sub { + font-size: 14px; + letter-spacing: 2px; + } + + .hero-cta { + padding: 18px 48px 16px; + font-size: 20px; + letter-spacing: 4px; + } +} \ No newline at end of file diff --git a/assets/css/homepage/_tech.scss b/assets/css/homepage/_tech.scss new file mode 100644 index 0000000..fdd23ed --- /dev/null +++ b/assets/css/homepage/_tech.scss @@ -0,0 +1,60 @@ +main { + background: #07090d; +} + +.tech-section { + padding: 48px 20px 72px; + text-align: center; + border-top: 1px solid rgba(255, 255, 255, 0.04); +} + +.tech-label { + font: 600 11px 'Rajdhani', sans-serif; + text-transform: uppercase; + letter-spacing: 6px; + color: rgba(255, 255, 255, 0.14); + margin-bottom: 28px; +} + +.tech-link { + display: inline-block; + line-height: 0; +} + +.tech-logos img { + display: inline-block; + width: 52px; + height: 52px; + object-fit: contain; + margin: 8px 24px; + // Force all logos to white, then tint with the game's blue on hover + filter: brightness(0) invert(1) opacity(0.35); + transition: filter 220ms ease, transform 220ms ease; +} + +.tech-logos img:hover { + filter: + brightness(0) invert(1) + sepia(1) saturate(3) hue-rotate(175deg) brightness(1.1) + opacity(0.9); + transform: translateY(-4px); +} + +.tech-oss { + margin-top: 36px; + font: 400 15px 'Rajdhani', sans-serif; + color: rgba(255, 255, 255, 0.7); + letter-spacing: 0.5px; + max-width: 680px; + margin-left: auto; + margin-right: auto; + padding: 0 24px; + line-height: 1.7; + text-align: center; + + i { + color: rgba(220, 60, 50, 0.85); + margin-right: 6px; + font-size: 13px; + } +} \ No newline at end of file diff --git a/assets/css/mineseeker/_back-button.scss b/assets/css/mineseeker/_back-button.scss new file mode 100644 index 0000000..6a213c2 --- /dev/null +++ b/assets/css/mineseeker/_back-button.scss @@ -0,0 +1,24 @@ +.back-from-game { + display: inline-block; + position: fixed; + top: 20px; + left: 20px; + + -ms-transform: scale(1); + -webkit-transform: scale(1); + transform: scale(1); + -webkit-transition: all 250ms cubic-bezier(.17, .67, .83, .67); + transition: all 250ms cubic-bezier(.17, .67, .83, .67); +} + +.back-from-game img { + width: 100px; +} + +.back-from-game:hover { + -ms-transform: scale(1.2); + -webkit-transform: scale(1.2); + transform: scale(1.2); + -webkit-transition: all 250ms cubic-bezier(.17, .67, .83, .67); + transition: all 250ms cubic-bezier(.17, .67, .83, .67); +} \ No newline at end of file diff --git a/assets/css/mineseeker/_base.scss b/assets/css/mineseeker/_base.scss new file mode 100644 index 0000000..58f169c --- /dev/null +++ b/assets/css/mineseeker/_base.scss @@ -0,0 +1,57 @@ +html { + height: 100%; + padding: 0; + margin: 0; +} + +body { + height: 100%; + min-height: 100%; + padding: 0; + margin: 0; +} + +main { + width: 100%; + height: 100%; +} + +.mine-container { + background: url("/images/bg-mineseeker-0-outbg.jpg") no-repeat; + background-size: cover; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + margin: 0; + padding: 0; +} + +.clear { + clear: both +} + +#mine-wrapper, +#mine-wrapper * { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +#mine-wrapper { + display: table; + width: 842px; + margin: 0 auto; +} + +#mine-wrapper .game-wrapper { + background: #000; + position: relative; + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 10px; + + -webkit-border-radius: 10px; + border-radius: 10px; +} \ No newline at end of file diff --git a/assets/css/mineseeker/_bomb.scss b/assets/css/mineseeker/_bomb.scss new file mode 100644 index 0000000..86c0329 --- /dev/null +++ b/assets/css/mineseeker/_bomb.scss @@ -0,0 +1,225 @@ +#mine-wrapper .game-wrapper .users .user-container .user-control { + background: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); + background: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); + background: linear-gradient(135deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#007db9e8', GradientType=1); + position: relative; + padding: 5px; + + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#mine-wrapper .game-wrapper .users .user-container .user-control > img { + position: absolute; + width: 55px; + left: -5px; + bottom: 10px; + + -ms-transform: rotate(-15deg); + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .user-control-mines { + display: inline-block; + background: #FFFFFF; + font-size: 25px; + text-align: center; + width: 45px; + height: 35px; + margin-left: 25px; + margin-top: 5px; + + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-control .user-control-mines { + color: #1a3955; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-control .user-control-mines { + color: #b10000; +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container { + display: inline-block; + float: right; + width: 65px; + height: 45px; + border: 1px solid #000; + + -webkit-border-radius: 7px; + border-radius: 7px; + -webkit-transform: translateZ(0); + transform: translateZ(0); + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -moz-osx-font-smoothing: grayscale; + box-shadow: 0 0 1px rgba(0, 0, 0, 0); +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container.buzz:hover { + -webkit-animation-name: hvr-buzz-out; + animation-name: hvr-buzz-out; + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; +} + +@-webkit-keyframes hvr-buzz-out { + 10% { -webkit-transform: translateX(3px) rotate(2deg); transform: translateX(3px) rotate(2deg); } + 20% { -webkit-transform: translateX(-3px) rotate(-2deg); transform: translateX(-3px) rotate(-2deg); } + 30% { -webkit-transform: translateX(3px) rotate(2deg); transform: translateX(3px) rotate(2deg); } + 40% { -webkit-transform: translateX(-3px) rotate(-2deg); transform: translateX(-3px) rotate(-2deg); } + 50% { -webkit-transform: translateX(2px) rotate(1deg); transform: translateX(2px) rotate(1deg); } + 60% { -webkit-transform: translateX(-2px) rotate(-1deg); transform: translateX(-2px) rotate(-1deg); } + 70% { -webkit-transform: translateX(2px) rotate(1deg); transform: translateX(2px) rotate(1deg); } + 80% { -webkit-transform: translateX(-2px) rotate(-1deg); transform: translateX(-2px) rotate(-1deg); } + 90% { -webkit-transform: translateX(1px) rotate(0); transform: translateX(1px) rotate(0); } + 100% { -webkit-transform: translateX(-1px) rotate(0); transform: translateX(-1px) rotate(0); } +} + +@keyframes hvr-buzz-out { + 10% { -webkit-transform: translateX(3px) rotate(2deg); transform: translateX(3px) rotate(2deg); } + 20% { -webkit-transform: translateX(-3px) rotate(-2deg); transform: translateX(-3px) rotate(-2deg); } + 30% { -webkit-transform: translateX(3px) rotate(2deg); transform: translateX(3px) rotate(2deg); } + 40% { -webkit-transform: translateX(-3px) rotate(-2deg); transform: translateX(-3px) rotate(-2deg); } + 50% { -webkit-transform: translateX(2px) rotate(1deg); transform: translateX(2px) rotate(1deg); } + 60% { -webkit-transform: translateX(-2px) rotate(-1deg); transform: translateX(-2px) rotate(-1deg); } + 70% { -webkit-transform: translateX(2px) rotate(1deg); transform: translateX(2px) rotate(1deg); } + 80% { -webkit-transform: translateX(-2px) rotate(-1deg); transform: translateX(-2px) rotate(-1deg); } + 90% { -webkit-transform: translateX(1px) rotate(0); transform: translateX(1px) rotate(0); } + 100% { -webkit-transform: translateX(-1px) rotate(0); transform: translateX(-1px) rotate(0); } +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb { + width: 100%; + height: 100%; + text-align: center; + cursor: pointer; +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb img { + display: inline-block; + height: 100%; +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container:hover .bomb img { + -webkit-animation-name: hvr-buzz; + animation-name: hvr-buzz; + -webkit-animation-duration: 0.15s; + animation-duration: 0.15s; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} + +#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb { + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-control .bomb-container .bomb { + background: rgb(131, 194, 245); + background: -moz-linear-gradient(top, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); + background: -webkit-linear-gradient(top, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); + background: linear-gradient(to bottom, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#83c2f5', endColorstr='#ddfffc', GradientType=0); + border: 3px solid #0b538e; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-control .bomb-container .bomb { + background: rgb(255, 175, 159); + background: -moz-linear-gradient(top, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); + background: -webkit-linear-gradient(top, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); + background: linear-gradient(to bottom, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffaf9f', endColorstr='#edac10', GradientType=0); + border: 3px solid #c9221c; +} + +// Resign button + +#mine-wrapper .game-wrapper .users .resign { + background: rgba(70, 73, 66, 1); + background: -moz-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); + background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(70, 73, 66, 1)), color-stop(69%, rgba(140, 138, 139, 1)), color-stop(100%, rgba(96, 89, 97, 1))); + background: -webkit-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); + background: -o-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); + background: -ms-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); + background: linear-gradient(to bottom, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#464942', endColorstr='#605961', GradientType=0); + display: block; + position: relative; + width: 95%; + height: 50px; + font-family: 'Open Sans', sans-serif; + font-weight: bold; + font-size: 22px; + text-transform: uppercase; + text-align: center; + line-height: 40px; + border: 3px solid #484742; + color: #fff; + margin: 10px auto 0 auto; + + outline: none; + cursor: pointer; + + -webkit-border-radius: 5px; + border-radius: 5px; + -webkit-transition: all 250ms ease-in-out; + -moz-transition: all 250ms ease-in-out; + -o-transition: all 250ms ease-in-out; + transition: all 250ms ease-in-out; +} + +#mine-wrapper .game-wrapper .users .resign:hover { + background: rgba(70, 73, 66, 1); + color: #FFFFFF; + transition: all 250ms ease-in-out; +} + +#mine-wrapper .game-wrapper .users .resign.disabled { + background: rgba(70, 73, 66, 1); + color: #848484; + cursor: default; +} + +#mine-wrapper .game-wrapper .users .resign.disabled:hover { + background: rgba(70, 73, 66, 1); + color: #848484; +} + +#mine-wrapper .game-wrapper .users .resign .resign-shine { + background: rgba(255, 255, 255, 1); + background: -moz-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); + background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(0, 0, 0, 0))); + background: -webkit-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); + background: -o-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); + background: -ms-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); + background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#000000', GradientType=0); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 33%; + + opacity: 0.7; + + -webkit-border-radius: 5px; + border-radius: 5px; + transition: all 250ms ease-in-out; +} + +#mine-wrapper .game-wrapper .users .resign:hover .resign-shine, +#mine-wrapper .game-wrapper .users .resign.disabled .resign-shine { + display: none; + transition: all 250ms ease-in-out; +} \ No newline at end of file diff --git a/assets/css/mineseeker/_grid.scss b/assets/css/mineseeker/_grid.scss new file mode 100644 index 0000000..ad1558d --- /dev/null +++ b/assets/css/mineseeker/_grid.scss @@ -0,0 +1,209 @@ +#mine-wrapper .grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: center; + width: 643px; + border: 1px solid #cac3e5; + + cursor: none; +} + +#mine-wrapper .grid-container { + background: #4E4E4E; + padding: 15px 10px; + + -webkit-border-radius: 5px; + border-radius: 5px; +} + +#mine-wrapper .grid .field-wrapper { + position: relative; +} + +#mine-wrapper .grid .field-wrapper > img.field-target { + position: absolute; + display: none; + width: 45px; + top: -2.5px; + left: -2.5px; + + z-index: 100; +} + +#mine-wrapper .grid .field-wrapper:hover > img.field-target { + display: block; +} + +#mine-wrapper .grid .field-wrapper > img.field-bomb-target { + position: absolute; + display: block; + top: 0; + left: 0; + width: 100%; + + z-index: 100; +} + +#mine-wrapper .grid .field-wrapper > img.field-blue-last, +#mine-wrapper .grid .field-wrapper > img.field-red-last { + position: absolute; + display: none; + width: 100%; + top: 0; + left: 0; + z-index: 99; +} + +#mine-wrapper .grid .field-wrapper > img.field-blue-last.last-clicked, +#mine-wrapper .grid .field-wrapper > img.field-red-last.last-clicked { + display: block; +} + +#mine-wrapper .grid .field-wrapper .field { + background: #61defa; + background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); + background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); + background: linear-gradient(to right, #61defa 0%, #119dec 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); + width: 40px; + height: 40px; + border: 2px solid #51c2fe; + font-family: 'Open Sans', sans-serif; + font-weight: bold; + font-size: 35px; + text-align: center; + line-height: 35px; +} + +#mine-wrapper .grid .field-wrapper .field .field-corner { + background: url('/images/bg-corner-outbg.png') no-repeat top left; + background-size: 100%; + width: 100%; + height: 100%; +} + +#mine-wrapper .grid .field-wrapper .field.active { + background: #fde717; + background: -moz-linear-gradient(left, #fde717 0%, #f5b807 100%); + background: -webkit-linear-gradient(left, #fde717 0%, #f5b807 100%); + background: linear-gradient(to right, #fde717 0%, #f5b807 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fde717', endColorstr='#f5b807', GradientType=1); + border: 2px solid #f6d762; + color: #000; +} + +#mine-wrapper .grid .field-wrapper .field.active .flag-number { + -webkit-animation: bubbleNumber 500ms cubic-bezier(.36, .07, .19, .97) both; + animation: bubbleNumber 500ms cubic-bezier(.36, .07, .19, .97) both; + -webkit-transform: scale(1); + transform: scale(1); +} + +@keyframes bubbleNumber { + 0% { + background: #61defa; + background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); + background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); + background: linear-gradient(to right, #61defa 0%, #119dec 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); + + -webkit-border-radius: 50%; + border-radius: 50%; + -webkit-transform: scale(1); + transform: scale(1); + } + 50% { + -webkit-border-radius: 50%; + border-radius: 50%; + -webkit-transform: scale(0); + transform: scale(0); + } + 100% { + -webkit-border-radius: 0; + border-radius: 0; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +#mine-wrapper .grid .field-wrapper .field.active .flag-mine { + position: relative; + overflow: hidden; +} + +#mine-wrapper .grid .field-wrapper .field.active .flag-mine > img { + width: 75%; + margin-left: 15px; + + -ms-transform: rotate(7deg); + -webkit-transform: rotate(7deg); + transform: rotate(7deg); + -webkit-animation: mineFlagLoad 500ms cubic-bezier(.36, .07, .19, .97) both; + animation: mineFlagLoad 500ms cubic-bezier(.36, .07, .19, .97) both; +} + +@keyframes mineFlagLoad { + 0% { + margin-bottom: 0; + margin-left: 15px; + -ms-transform: rotate(9deg); + -webkit-transform: rotate(9deg); + transform: rotate(9deg); + } + 50% { + margin-bottom: -5px; + margin-left: 7px; + } + 100% { + margin-bottom: 3px; + margin-left: 0; + -ms-transform: rotate(-9deg); + -webkit-transform: rotate(-9deg); + transform: rotate(-9deg); + } +} + +#mine-wrapper .grid .field-wrapper .field.active .flag-mine .flag-mine-base { + position: absolute; + background: #000000; + width: 25px; + height: 22px; + bottom: -12px; + left: 50%; + margin-left: -10.5px; + + -webkit-border-radius: 50%; + border-radius: 50%; + -webkit-animation: mineBaseLoad 500ms cubic-bezier(.36, .07, .19, .97) both; + animation: mineBaseLoad 500ms cubic-bezier(.36, .07, .19, .97) both; +} + +@keyframes mineBaseLoad { + 0% { margin-bottom: 0; } + 50% { margin-bottom: -5px; } + 100% { margin-bottom: 0; } +} + +#mine-wrapper .grid .field-wrapper .field.active.mine { + background: #61defa; + background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); + background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); + background: linear-gradient(to right, #61defa 0%, #119dec 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); + border: 2px solid #51c2fe; +} + +#mine-wrapper .grid .field-wrapper .field.active.color-1 { color: #0000ff; } +#mine-wrapper .grid .field-wrapper .field.active.color-2 { color: #079433; } +#mine-wrapper .grid .field-wrapper .field.active.color-3 { color: #fd1400; } +#mine-wrapper .grid .field-wrapper .field.active.color-4 { color: #0c099e; } +#mine-wrapper .grid .field-wrapper .field.active.color-5 { color: #7b4c01; } +#mine-wrapper .grid .field-wrapper .field.active.color-6 { color: #008388; } +#mine-wrapper .grid .field-wrapper .field.active.color-7 { color: #000000; } +#mine-wrapper .grid .field-wrapper .field.active.color-8 { color: #ff0000; } + +#mine-wrapper .grid .field-wrapper .field img { + width: 80%; +} \ No newline at end of file diff --git a/assets/css/mineseeker/_mine-counter.scss b/assets/css/mineseeker/_mine-counter.scss new file mode 100644 index 0000000..d0368cf --- /dev/null +++ b/assets/css/mineseeker/_mine-counter.scss @@ -0,0 +1,90 @@ +#mine-wrapper .game-wrapper .users .active-mines-container { + background: -moz-radial-gradient(center, ellipse cover, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); + background: -webkit-radial-gradient(center, ellipse cover, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); + background: radial-gradient(ellipse at center, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcfc', endColorstr='#006a6a6a', GradientType=1); + background-repeat: no-repeat; + background-position: center center; + background-size: 72% 179%; + position: relative; + height: 30px; +} + +#mine-wrapper .game-wrapper .users .active-mines-container i { + font-size: 27px; + color: #b1b1b3; + margin-top: 3px; + + text-shadow: 0 0 3px #000000; +} + +#mine-wrapper .game-wrapper .users .active-mines-container i:first-child { + float: left; + margin-left: 20px; +} + +#mine-wrapper .game-wrapper .users .active-mines-container i:last-child { + float: right; + margin-right: 20px; +} + +#mine-wrapper .game-wrapper .users .active-mines-container .active-mines { + background: -moz-linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); + background: -webkit-linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); + background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3e3f41', endColorstr='#878883', GradientType=0); + position: absolute; + width: 50px; + height: 50px; + top: -7.5px; + left: 50%; + font-family: 'Open Sans', sans-serif; + font-size: 25px; + line-height: 39px; + text-align: center; + color: #FFFFFF; + border: 5px solid #000000; + margin-left: -25px; + + z-index: 100; + + -webkit-border-radius: 50%; + border-radius: 50%; +} + +#mine-wrapper .game-wrapper .users .active-mines-container .active-mines.found-mine { + -webkit-animation: bubbleLeftMine 750ms cubic-bezier(.36, .07, .19, .97) both; + animation: bubbleLeftMine 750ms cubic-bezier(.36, .07, .19, .97) both; +} + +@keyframes bubbleLeftMine { + 0% { -webkit-transform: scale(1); transform: scale(1); } + 50% { border-color: #2e3337; -webkit-transform: scale(2); transform: scale(2); } + 100% { -webkit-transform: scale(1); transform: scale(1); } +} + +#mine-wrapper .game-wrapper .users .active-mines-container .active-mines .active-mines-shine { + background: -moz-linear-gradient(top, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); + background: -webkit-linear-gradient(top, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); + background: linear-gradient(to bottom, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d5d6d8', endColorstr='#6a6a6a', GradientType=0); + position: absolute; + top: 0; + left: 50%; + width: 30px; + height: 20px; + margin-left: -14.5px; + + z-index: 101; + + -webkit-border-radius: 50%; + border-radius: 50%; +} + +#mine-wrapper .game-wrapper .users .active-mines-container .active-mines .active-mines-nbr { + position: absolute; + top: 0; + width: 100%; + + z-index: 102; +} \ No newline at end of file diff --git a/assets/css/mineseeker/_overlay.scss b/assets/css/mineseeker/_overlay.scss new file mode 100644 index 0000000..84167ca --- /dev/null +++ b/assets/css/mineseeker/_overlay.scss @@ -0,0 +1,137 @@ +#mine-wrapper .game-wrapper .game-overlay { + background: rgba(255, 255, 255, 0.2); + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + + z-index: 200; + + -webkit-border-radius: 10px; + border-radius: 10px; +} + +#mine-wrapper .game-wrapper .game-overlay.hide { + display: none; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window { + background: rgba(204, 204, 204, 0.8); + border: 5px solid rgba(255, 255, 255, 0.5); + font-family: 'Open Sans', sans-serif; + text-align: center; + color: #354d6a; + width: 660px; + padding: 10px; + + -webkit-border-radius: 10px; + border-radius: 10px; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h1 { + font-weight: bold; + font-size: 26px; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h2 { + font-size: 18px; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h3 { + font-size: 16px; + color: #386e8c; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-invite { + padding: 0 4px 4px; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-invite-label { + font-size: 13px; + color: #386e8c; + margin: 0 0 8px; + font-style: italic; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-box { + display: flex; + align-items: center; + background: #d0e8f5; + border: 1px solid #7ab8d8; + border-radius: 6px; + padding: 0 12px; + margin-bottom: 12px; + cursor: text; + transition: border-color 200ms ease; + + &:hover { + border-color: #236f87; + } +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-icon { + color: #236f87; + font-size: 13px; + flex-shrink: 0; + margin-right: 8px; + opacity: 0.7; +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-input { + flex: 1; + background: transparent; + border: 0; + outline: 0; + height: 40px; + color: #1a4a6a; + font-family: 'Courier New', monospace; + font-size: 13px; + font-weight: bold; + letter-spacing: 0.3px; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + cursor: text; + min-width: 0; + + &::selection { + background: rgba(35, 111, 135, 0.2); + } +} + +#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-copy-btn { + display: inline-flex; + align-items: center; + gap: 7px; + background: linear-gradient(to bottom, #236f87 0%, #1a5068 100%); + border: 1px solid #2e7a9a; + color: #e0f4ff; + font-family: 'Rajdhani', sans-serif; + font-size: 15px; + font-weight: bold; + letter-spacing: 0.5px; + padding: 9px 32px; + border-radius: 5px; + cursor: pointer; + transition: all 220ms ease; + + &:hover { + background: linear-gradient(to bottom, #2d8aa8 0%, #236f87 100%); + border-color: #5ba4d4; + color: #fff; + box-shadow: 0 0 10px rgba(35, 111, 135, 0.5); + } + + &.copied { + background: linear-gradient(to bottom, #1a6844 0%, #135233 100%); + border-color: #2a9e60; + color: #a0f0c0; + box-shadow: 0 0 8px rgba(26, 104, 68, 0.5); + } +} \ No newline at end of file diff --git a/assets/css/mineseeker/_responsive.scss b/assets/css/mineseeker/_responsive.scss new file mode 100644 index 0000000..17b72a5 --- /dev/null +++ b/assets/css/mineseeker/_responsive.scss @@ -0,0 +1,41 @@ +@media screen and (max-width: 900px) { + #mine-wrapper .game-wrapper .users { + visibility: hidden; + display: none; + } + + #mine-wrapper { + display: block; + width: 100%; + } + + #mine-wrapper .game-wrapper { + width: 100%; + flex-direction: column-reverse; + } + + #mine-wrapper .grid-container { + width: 100%; + padding: 0; + } + + #mine-wrapper .grid { + width: 100%; + } + + #mine-wrapper .grid .field-wrapper { + width: 6.25%; + aspect-ratio: 1; + } + + #mine-wrapper .grid .field-wrapper > img.field-target { + width: 105%; + top: -2.5%; + left: -2.5%; + } + + #mine-wrapper .grid .field-wrapper .field { + width: 100%; + height: auto; + } +} \ No newline at end of file diff --git a/assets/css/mineseeker/_timer.scss b/assets/css/mineseeker/_timer.scss new file mode 100644 index 0000000..fbf07f1 --- /dev/null +++ b/assets/css/mineseeker/_timer.scss @@ -0,0 +1,72 @@ +#mine-wrapper .game-timer-container { + display: flex; + gap: 12px; + justify-content: center; + margin-bottom: 10px; +} + +#mine-wrapper .game-timer { + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + min-width: 115px; + border-radius: 8px; + padding: 8px 18px; + font-family: 'Rajdhani', sans-serif; + font-weight: bold; + border: 2px solid transparent; + transition: all 0.4s ease; +} + +// Red – waiting +#mine-wrapper .game-timer.red-timer { + background: linear-gradient(to bottom, #4a0603 0%, #6b2515 100%); + border-color: #7a1e10; + color: rgba(246, 125, 82, 0.55); +} + +// Red – active (thinking) +#mine-wrapper .game-timer.red-timer.active { + background: linear-gradient(to bottom, #ad0a05 0%, #f67d52 100%); + border-color: #ff9b6b; + color: #fff; + box-shadow: 0 0 16px rgba(173, 10, 5, 0.75), 0 0 5px rgba(246, 125, 82, 0.5); +} + +// Blue – waiting +#mine-wrapper .game-timer.blue-timer { + background: linear-gradient(to bottom, #0b2530 0%, #163d55 100%); + border-color: #173650; + color: rgba(149, 207, 245, 0.55); +} + +// Blue – active (thinking) +#mine-wrapper .game-timer.blue-timer.active { + background: linear-gradient(to bottom, #236f87 0%, #95cff5 100%); + border-color: #b8e5ff; + color: #fff; + box-shadow: 0 0 16px rgba(35, 111, 135, 0.75), 0 0 5px rgba(149, 207, 245, 0.5); +} + +#mine-wrapper .game-timer .timer-icon { + font-size: 15px; + opacity: 0.7; + flex-shrink: 0; +} + +#mine-wrapper .game-timer.active .timer-icon { + opacity: 1; + animation: timer-icon-pulse 1.6s ease-in-out infinite; +} + +@keyframes timer-icon-pulse { + 0%, 100% { transform: scale(1); opacity: 0.85; } + 50% { transform: scale(1.2); opacity: 1; } +} + +#mine-wrapper .game-timer .timer-display { + font-family: 'Courier New', monospace; + font-size: 20px; + letter-spacing: 2px; +} \ No newline at end of file diff --git a/assets/css/mineseeker/_users.scss b/assets/css/mineseeker/_users.scss new file mode 100644 index 0000000..e3ca6af --- /dev/null +++ b/assets/css/mineseeker/_users.scss @@ -0,0 +1,153 @@ +#mine-wrapper .game-wrapper .users { + width: 180px; + padding: 0 10px 0 0; +} + +#mine-wrapper .game-wrapper .users .user-container { + background: #FFFFFF; + height: 40%; + font-family: 'Open Sans', sans-serif; + padding: 5px; + margin: 5px; + + z-index: 99; + + -webkit-border-radius: 10px; + border-radius: 10px; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue { + background: rgb(35, 111, 135); + background: -moz-linear-gradient(top, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); + background: -webkit-linear-gradient(top, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); + background: linear-gradient(to bottom, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#236f87', endColorstr='#95cff5', GradientType=0); + + margin-top: 0; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red { + background: rgb(173, 10, 5); + background: -moz-linear-gradient(top, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); + background: -webkit-linear-gradient(top, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); + background: linear-gradient(to bottom, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ad0a05', endColorstr='#f67d52', GradientType=0); +} + +#mine-wrapper .game-wrapper .users .user-container .user-header { + background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); + background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); + background: linear-gradient(to bottom, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#00000000', GradientType=0); + position: relative; + font: bolder 25px 'Changa One', cursive; + letter-spacing: 5px; + text-transform: uppercase; + text-align: center; + padding: 6px 5px 20px 5px; + margin-bottom: 40px; + + -webkit-border-radius: 5px; + border-radius: 5px; + -webkit-text-shadow: 1px 1px 0 #FFF; + text-shadow: 1px 1px 0 #FFF; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-header { + color: #236f87; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-header { + color: #AD0A05; +} + +#mine-wrapper .game-wrapper .users .user-container .user-header > img { + position: absolute; + left: 50%; + bottom: 0; + width: 40%; + margin-left: -20%; + margin-bottom: -25%; +} + +#mine-wrapper .game-wrapper .users .user-container .user-header > img.user-cursor { + display: block; + width: 30%; + top: 20px; + left: 10px; + margin-left: 0; + + -webkit-animation: cursorJumping 1.2s cubic-bezier(.36, .07, .19, .97) infinite; + animation: cursorJumping 1.2s cubic-bezier(.36, .07, .19, .97) infinite; +} + +#mine-wrapper .game-wrapper .users .user-container .user-header > img.user-cursor::after { + content: ''; + width: 50px; + height: 50px; + background: #1A6844; + animation: animate .5s linear infinite; + position: absolute; + top: 0; + left: 0; + border-radius: 3px; +} + +@keyframes cursorJumping { + 0% { top: 15px; } + 50% { top: 25px; } + 100% { top: 15px; } +} + +#mine-wrapper .game-wrapper .users .user-container .user-name { + min-height: 30px; + font-weight: normal; + text-align: center; + white-space: nowrap; + text-overflow: ellipsis; + padding: 3px 0; + margin: 0 5px; + + overflow: hidden; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-name { + border-top: 1px dashed #0b3776; + border-bottom: 1px dashed #0b3776; + color: #0b3776; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-name { + color: #fdf612; + border-top: 1px dashed #fdf612; + border-bottom: 1px dashed #fdf612; +} + +#mine-wrapper .game-wrapper .users .user-container .user-caret { + height: 30px; + font-size: 30px; + text-align: center; + line-height: 15px; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-caret > i { + color: #0b3776; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-caret > i { + color: #fdf612; +} + +#mine-wrapper .game-wrapper .users .user-container .user-desc { + height: 65px; + font-size: 14px; + text-align: center; +} + +#mine-wrapper .game-wrapper .users .user-container.user-blue .user-desc { + color: #0b3776; +} + +#mine-wrapper .game-wrapper .users .user-container.user-red .user-desc { + color: #fdf612; +} \ No newline at end of file diff --git a/assets/css/style.homepage.scss b/assets/css/style.homepage.scss index 2094ef5..99657f0 100644 --- a/assets/css/style.homepage.scss +++ b/assets/css/style.homepage.scss @@ -1,592 +1,14 @@ -// ── Reset ──────────────────────────────────────────────────────────────────── - -* { - outline: none; - padding: 0; - margin: 0; - box-sizing: border-box; -} - -html { - // Grid lives on html so it tiles across all pages including content pages - background-color: #07090d; - background-image: - linear-gradient(rgba(35, 111, 135, 0.1) 1px, transparent 1px), - linear-gradient(90deg, rgba(35, 111, 135, 0.1) 1px, transparent 1px); - background-size: 46px 46px; - width: 100%; - height: 100%; -} - -body { - background: transparent; - width: 100%; - height: 100%; -} - -// ── Hero ───────────────────────────────────────────────────────────────────── - -header { - position: relative; - width: 100%; - overflow: hidden; - - // Minesweeper grid texture - background-color: #07090d; - background-image: - linear-gradient(rgba(35, 111, 135, 0.1) 1px, transparent 1px), - linear-gradient(90deg, rgba(35, 111, 135, 0.1) 1px, transparent 1px); - background-size: 46px 46px; -} - -// Deep radial vignette – grid fades toward the centre -header::before { - content: ''; - position: absolute; - inset: 0; - background: radial-gradient( - ellipse 85% 75% at 50% 50%, - #07090d 10%, - transparent 75% - ); - z-index: 0; - pointer-events: none; -} - -// Smoke at the bottom so header bleeds into body -header::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 160px; - background: linear-gradient(to bottom, transparent, #07090d); - z-index: 1; - pointer-events: none; -} - -// ── Hero section ───────────────────────────────────────────────────────────── - -.hero { - position: relative; - z-index: 2; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - min-height: 100vh; - padding: 80px 40px 160px; - gap: 0; -} - -// Decorative glow blobs in opposite corners -.hero::before { - content: ''; - position: absolute; - top: -60px; - left: -60px; - width: 420px; - height: 420px; - border-radius: 50%; - background: radial-gradient(circle, rgba(173, 10, 5, 0.09) 0%, transparent 65%); - pointer-events: none; - z-index: 0; -} - -.hero::after { - content: ''; - position: absolute; - bottom: 100px; - right: -60px; - width: 380px; - height: 380px; - border-radius: 50%; - background: radial-gradient(circle, rgba(35, 111, 135, 0.1) 0%, transparent 65%); - pointer-events: none; - z-index: 0; -} - -// Logo -.hero-logo { - display: block; - margin-bottom: 72px; - position: relative; - z-index: 1; - animation: appear 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; -} - -.hero-logo img { - width: 400px; - max-width: 82vw; - filter: - drop-shadow(0 0 40px rgba(35, 111, 135, 0.35)) - drop-shadow(0 6px 20px rgba(0, 0, 0, 0.8)); -} - -// Body text block -.hero-body { - position: relative; - z-index: 1; - display: flex; - flex-direction: column; - align-items: center; - gap: 0; -} - -.hero-sub { - font: 300 17px 'Rajdhani', sans-serif; - color: rgba(149, 207, 245, 0.9); - letter-spacing: 3px; - text-transform: uppercase; - margin-bottom: 18px; - animation: rise 0.8s 0.15s cubic-bezier(0.22, 1, 0.36, 1) both; -} - -.hero-sub strong { - font-weight: 600; - color: #95cff5; -} - -.hero-avatar { - width: 36px; - height: 36px; - border-radius: 50%; - border: 2px solid rgba(149, 207, 245, 0.25); - vertical-align: middle; - margin-right: 10px; - margin-bottom: 2px; -} - -.hero h1 { - font: 800 58px 'Rajdhani', sans-serif; - color: #ffffff; - line-height: 1.1; - letter-spacing: 1px; - margin-bottom: 56px; - text-shadow: 0 4px 30px rgba(0, 0, 0, 0.7); - animation: rise 0.8s 0.28s cubic-bezier(0.22, 1, 0.36, 1) both; -} - -// ── CTA button ─────────────────────────────────────────────────────────────── - -.hero-cta { - position: relative; - display: inline-block; - font: 800 28px 'Rajdhani', sans-serif; - text-transform: uppercase; - letter-spacing: 6px; - text-decoration: none; - color: #ffffff; - padding: 22px 100px 20px; - border-radius: 4px; - border: 1px solid rgba(246, 125, 82, 0.25); - - background: linear-gradient(to bottom, #b30c06 0%, #d63d15 50%, #f67d52 100%); - - box-shadow: - 0 0 0 1px rgba(173, 10, 5, 0.2), - 0 0 30px rgba(173, 10, 5, 0.35), - 0 6px 24px rgba(0, 0, 0, 0.5), - inset 0 1px 0 rgba(255, 255, 255, 0.12); - - transition: transform 220ms ease, box-shadow 220ms ease, letter-spacing 220ms ease; - animation: rise 0.8s 0.42s cubic-bezier(0.22, 1, 0.36, 1) both; -} - -// Outer glow layer (blurred duplicate, always visible) -.hero-cta::before { - content: ''; - position: absolute; - inset: -4px; - border-radius: 7px; - background: linear-gradient(to bottom, #ad0a05, #f67d52); - filter: blur(18px); - opacity: 0.3; - z-index: -1; - transition: opacity 220ms ease; -} - -.hero-cta:hover { - transform: translateY(-4px); - letter-spacing: 8px; - box-shadow: - 0 0 0 1px rgba(246, 125, 82, 0.3), - 0 0 50px rgba(173, 10, 5, 0.65), - 0 10px 32px rgba(0, 0, 0, 0.45), - inset 0 1px 0 rgba(255, 255, 255, 0.15); -} - -.hero-cta:hover::before { - opacity: 0.55; -} - -.hero-cta:active { - transform: translateY(-1px); -} - -// Version / copyright line -.hero-meta { - position: relative; - z-index: 1; - font: 400 12px 'Rajdhani', sans-serif; - color: rgba(255, 255, 255, 0.5); - letter-spacing: 0.5px; - margin-top: 58px; - animation: rise 0.8s 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; -} - -.hero-meta a { - color: rgba(149, 207, 245, 0.65); - text-decoration: none; - transition: color 180ms; -} - -.hero-meta a:hover { - color: #95cff5; -} - -// ── Compact hero (sub-pages) ───────────────────────────────────────────────── - -.hero--compact { - min-height: unset; - padding: 36px 60px 48px; - flex-direction: row; - align-items: center; - justify-content: center; - text-align: left; - gap: 52px; - - &::before, &::after { display: none; } - - .hero-logo { - flex-shrink: 0; - margin-bottom: 0; - - img { width: 180px; } - } - - .hero-body { - align-items: flex-start; - } - - .hero-sub { - font-size: 14px; - letter-spacing: 2px; - margin-bottom: 10px; - } - - h1 { - font-size: 26px; - margin-bottom: 24px; - letter-spacing: 0; - } - - .hero-cta { - padding: 12px 52px 10px; - font-size: 18px; - letter-spacing: 4px; - } - - .hero-meta { - margin-top: 20px; - } -} - -// Also shrink the bottom fade on sub-pages -header:has(.hero--compact)::after { - height: 60px; -} - -// ── Animations ─────────────────────────────────────────────────────────────── - -@keyframes appear { - from { opacity: 0; transform: scale(0.94); } - to { opacity: 1; transform: scale(1); } -} - -@keyframes rise { - from { opacity: 0; transform: translateY(16px); } - to { opacity: 1; transform: translateY(0); } -} - -// ── Content pages (terms, privacy, contact) ────────────────────────────────── - -main div.txt { - color: rgba(255, 255, 255, 0.85); - max-width: 900px; - margin: 0 auto; - padding: 60px 40px 80px; -} - -main div.txt h2 { - font: bold 28px 'Rajdhani', sans-serif; - color: #ffffff; - margin-bottom: 30px; - letter-spacing: 1px; -} - -main div.txt h3 { - font: bold 17px 'Rajdhani', sans-serif; - color: rgba(149, 207, 245, 0.9); - margin: 28px 0 10px; - letter-spacing: 0.5px; -} - -main div.txt p, -main div.txt li { - font: 400 15px 'Rajdhani', sans-serif; - color: rgba(255, 255, 255, 0.72); - line-height: 1.75; -} - -main div.txt a { - color: #95cff5; - text-decoration: none; - transition: color 180ms; - - &:hover { color: #c5e8ff; } -} - -// ── Technologies strip ──────────────────────────────────────────────────────── - -main { - background: #07090d; -} - -.tech-section { - padding: 48px 20px 72px; - text-align: center; - border-top: 1px solid rgba(255, 255, 255, 0.04); -} - -.tech-label { - font: 600 11px 'Rajdhani', sans-serif; - text-transform: uppercase; - letter-spacing: 6px; - color: rgba(255, 255, 255, 0.14); - margin-bottom: 28px; -} - -.tech-logos img { - display: inline-block; - width: 52px; - height: 52px; - object-fit: contain; - margin: 8px 24px; - // Force all logos to white, then tint with the game's blue - filter: brightness(0) invert(1) opacity(0.35); - transition: filter 220ms ease, transform 220ms ease; -} - -.tech-logos img:hover { - // Bright white → blue-tinted on hover - filter: - brightness(0) invert(1) - sepia(1) saturate(3) hue-rotate(175deg) brightness(1.1) - opacity(0.9); - transform: translateY(-4px); -} - -// ── Footer ─────────────────────────────────────────────────────────────────── - -footer { - background: #040608; - border-top: 1px solid rgba(35, 111, 135, 0.12); - width: 100%; -} - -.footer-inner { - display: flex; - align-items: flex-start; - justify-content: space-between; - max-width: 1100px; - margin: 0 auto; - padding: 60px 60px 52px; - gap: 40px; -} - -// Left: brand block -.footer-brand { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 10px; -} - -.footer-logo { - width: 72px; - height: 72px; - opacity: 0.55; - filter: - drop-shadow(0 0 12px rgba(35, 111, 135, 0.4)) - brightness(1.1); - transition: opacity 250ms ease, filter 250ms ease; - - &:hover { - opacity: 0.9; - filter: - drop-shadow(0 0 20px rgba(35, 111, 135, 0.65)) - brightness(1.2); - } -} - -.footer-name { - font: 700 22px 'Rajdhani', sans-serif; - color: rgba(255, 255, 255, 0.75); - letter-spacing: 2px; - text-transform: uppercase; - margin-top: 4px; -} - -.footer-tagline { - font: 400 13px 'Rajdhani', sans-serif; - color: rgba(149, 207, 245, 0.7); - letter-spacing: 0.5px; - max-width: 240px; - line-height: 1.5; -} - -// Right: navigation -.footer-nav-label { - font: 700 11px 'Rajdhani', sans-serif; - text-transform: uppercase; - letter-spacing: 4px; - color: rgba(255, 255, 255, 0.5); - margin-bottom: 18px; - text-align: left; -} - -.footer-nav ul { - list-style: none; - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 6px; - min-width: 180px; -} - -.footer-nav ul li a { - display: block; - font: 500 15px 'Rajdhani', sans-serif; - color: rgba(255, 255, 255, 0.7); - text-decoration: none; - text-transform: uppercase; - letter-spacing: 1.5px; - white-space: nowrap; - padding: 6px 0; - transition: color 180ms ease, letter-spacing 180ms ease; - - &:hover { - color: #95cff5; - letter-spacing: 2px; - } -} - -// Bottom copyright bar -.footer-copy { - border-top: 1px solid rgba(255, 255, 255, 0.05); - padding: 16px 60px; - max-width: 1100px; - margin: 0 auto; - - p { - font: 400 11px 'Rajdhani', sans-serif; - color: rgba(255, 255, 255, 0.45); - letter-spacing: 0.5px; - text-align: center; - } - - a { - color: rgba(149, 207, 245, 0.6); - text-decoration: none; - transition: color 180ms; - - &:hover { color: #95cff5; } - } -} - -// ── Responsive ─────────────────────────────────────────────────────────────── - -@media screen and (max-width: 768px) { - .hero--compact { - flex-direction: column; - text-align: center; - padding: 36px 24px 44px; - gap: 28px; - - .hero-body { align-items: center; } - } - - .footer-inner { - flex-direction: column; - align-items: center; - text-align: center; - padding: 48px 30px 36px; - } - - .footer-brand { - align-items: center; - } - - .footer-tagline { - text-align: center; - } - - .footer-nav-label { - text-align: center; - } - - .footer-nav ul { - align-items: center; - } - - .footer-copy { - padding: 16px 30px; - } -} - -@media screen and (max-width: 900px) { - .hero h1 { - font-size: 44px; - } - - .hero-cta { - padding: 20px 72px 18px; - font-size: 24px; - letter-spacing: 5px; - } -} - -@media screen and (max-width: 550px) { - .hero { - padding: 60px 24px 140px; - } - - .hero-logo img { - width: 260px; - } - - .hero-logo { - margin-bottom: 52px; - } - - .hero h1 { - font-size: 32px; - margin-bottom: 40px; - } - - .hero-sub { - font-size: 14px; - letter-spacing: 2px; - } - - .hero-cta { - padding: 18px 48px 16px; - font-size: 20px; - letter-spacing: 4px; - } - - -} \ No newline at end of file +@use 'homepage/reset'; +@use 'homepage/animations'; +@use 'homepage/header'; +@use 'homepage/hero'; +@use 'homepage/hero-compact'; +@use 'homepage/cta'; +@use 'homepage/auth-bar'; +@use 'homepage/auth'; +@use 'homepage/content'; +@use 'homepage/features'; +@use 'homepage/tech'; +@use 'homepage/footer'; +@use 'homepage/profile'; +@use 'homepage/responsive'; diff --git a/assets/css/style.layout.scss b/assets/css/style.layout.scss index 1840f00..938181d 100644 --- a/assets/css/style.layout.scss +++ b/assets/css/style.layout.scss @@ -1,4 +1,5 @@ @import url('https://fonts.googleapis.com/css?family=Rajdhani:300,400,500,600,700&subset=latin-ext'); +@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css'); @import "style"; @import "style.homepage"; diff --git a/assets/css/style.mineseeker.scss b/assets/css/style.mineseeker.scss index 624a0a4..6b93d26 100644 --- a/assets/css/style.mineseeker.scss +++ b/assets/css/style.mineseeker.scss @@ -2,1149 +2,12 @@ @import url('https://fonts.googleapis.com/css?family=Changa+One|Open+Sans:700'); @import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css'); -html { - height: 100%; - padding: 0; - margin: 0; -} - -body { - height: 100%; - min-height: 100%; - padding: 0; - margin: 0; -} - -main { - width: 100%; - height: 100%; -} - -.mine-container { - background: url("/images/bg-mineseeker-0-outbg.jpg") no-repeat; - background-size: cover; - display: flex; - justify-content: center; - align-items: center; - width: 100%; - height: 100%; - margin: 0; - padding: 0; -} - -.clear { - clear: both -} - -#mine-wrapper, -#mine-wrapper * { - -webkit-box-sizing: border-box; - box-sizing: border-box; -} - -#mine-wrapper { - display: table; - width: 842px; - margin: 0 auto; -} - -#mine-wrapper .game-wrapper { - background: #000; - position: relative; - display: flex; - flex-direction: row; - align-items: flex-start; - padding: 10px; - - -webkit-border-radius: 10px; - border-radius: 10px; -} - -#mine-wrapper .game-wrapper .game-overlay { - background: rgba(255, 255, 255, 0.2); - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - - z-index: 200; - - -webkit-border-radius: 10px; - border-radius: 10px; -} - -#mine-wrapper .game-wrapper .game-overlay.hide { - display: none; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window { - background: rgba(204, 204, 204, 0.8); - border: 5px solid rgba(255, 255, 255, 0.5); - font-family: 'Open Sans', sans-serif; - text-align: center; - color: #354d6a; - width: 660px; - padding: 10px; - - -webkit-border-radius: 10px; - border-radius: 10px; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h1 { - font-weight: bold; - font-size: 26px; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h2 { - font-size: 18px; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window h3 { - font-size: 16px; - color: #386e8c; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-invite { - padding: 0 4px 4px; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-invite-label { - font-size: 13px; - color: #386e8c; - margin: 0 0 8px; - font-style: italic; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-box { - display: flex; - align-items: center; - background: #d0e8f5; - border: 1px solid #7ab8d8; - border-radius: 6px; - padding: 0 12px; - margin-bottom: 12px; - cursor: text; - transition: border-color 200ms ease; - - &:hover { - border-color: #236f87; - } -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-icon { - color: #236f87; - font-size: 13px; - flex-shrink: 0; - margin-right: 8px; - opacity: 0.7; -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-url-input { - flex: 1; - background: transparent; - border: 0; - outline: 0; - height: 40px; - color: #1a4a6a; - font-family: 'Courier New', monospace; - font-size: 13px; - font-weight: bold; - letter-spacing: 0.3px; - text-align: center; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - cursor: text; - min-width: 0; - - &::selection { - background: rgba(35, 111, 135, 0.2); - } -} - -#mine-wrapper .game-wrapper .game-overlay .game-overlay-window .share-copy-btn { - display: inline-flex; - align-items: center; - gap: 7px; - background: linear-gradient(to bottom, #236f87 0%, #1a5068 100%); - border: 1px solid #2e7a9a; - color: #e0f4ff; - font-family: 'Rajdhani', sans-serif; - font-size: 15px; - font-weight: bold; - letter-spacing: 0.5px; - padding: 9px 32px; - border-radius: 5px; - cursor: pointer; - transition: all 220ms ease; - - &:hover { - background: linear-gradient(to bottom, #2d8aa8 0%, #236f87 100%); - border-color: #5ba4d4; - color: #fff; - box-shadow: 0 0 10px rgba(35, 111, 135, 0.5); - } - - &.copied { - background: linear-gradient(to bottom, #1a6844 0%, #135233 100%); - border-color: #2a9e60; - color: #a0f0c0; - box-shadow: 0 0 8px rgba(26, 104, 68, 0.5); - } -} - -#mine-wrapper .game-wrapper .users { - width: 180px; - padding: 0 10px 0 0; -} - -#mine-wrapper .game-wrapper .users .user-container { - background: #FFFFFF; - height: 40%; - font-family: 'Open Sans', sans-serif; - padding: 5px; - margin: 5px; - - z-index: 99; - - -webkit-border-radius: 10px; - border-radius: 10px; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue { - background: rgb(35, 111, 135); - background: -moz-linear-gradient(top, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); - background: -webkit-linear-gradient(top, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); - background: linear-gradient(to bottom, rgba(35, 111, 135, 1) 0%, rgba(149, 207, 245, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#236f87', endColorstr='#95cff5', GradientType=0); - - margin-top: 0; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red { - background: rgb(173, 10, 5); - background: -moz-linear-gradient(top, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); - background: -webkit-linear-gradient(top, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); - background: linear-gradient(to bottom, rgba(173, 10, 5, 1) 0%, rgba(246, 125, 82, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ad0a05', endColorstr='#f67d52', GradientType=0); -} - -#mine-wrapper .game-wrapper .users .user-container .user-header { - background: -moz-linear-gradient(top, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); - background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); - background: linear-gradient(to bottom, rgba(255, 255, 255, 0.7) 39%, rgba(255, 255, 255, 0.21) 87%, rgba(0, 0, 0, 0) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#00000000', GradientType=0); - position: relative; - font: bolder 25px 'Changa One', cursive; - letter-spacing: 5px; - text-transform: uppercase; - text-align: center; - padding: 6px 5px 20px 5px; - margin-bottom: 40px; - - -webkit-border-radius: 5px; - border-radius: 5px; - -webkit-text-shadow: 1px 1px 0 #FFF; - text-shadow: 1px 1px 0 #FFF; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-header { - color: #236f87; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-header { - color: #AD0A05; -} - -#mine-wrapper .game-wrapper .users .user-container .user-header > img { - position: absolute; - left: 50%; - bottom: 0; - width: 40%; - margin-left: -20%; - margin-bottom: -25%; -} - -#mine-wrapper .game-wrapper .users .user-container .user-header > img.user-cursor { - display: block; - width: 30%; - top: 20px; - left: 10px; - margin-left: 0; - - -webkit-animation: cursorJumping 1.2s cubic-bezier(.36, .07, .19, .97) infinite; - animation: cursorJumping 1.2s cubic-bezier(.36, .07, .19, .97) infinite; - -} - -#mine-wrapper .game-wrapper .users .user-container .user-header > img.user-cursor::after { - content: ''; - width: 50px; - height: 50px; - background: #1A6844; - animation: animate .5s linear infinite; - position: absolute; - top: 0; - left: 0; - border-radius: 3px; -} - -@keyframes cursorJumping { - 0% { - top: 15px; - } - 50% { - top: 25px; - } - 100% { - top: 15px; - } -} - -#mine-wrapper .game-wrapper .users .user-container .user-name { - min-height: 30px; - font-weight: normal; - text-align: center; - white-space: nowrap; - text-overflow: ellipsis; - padding: 3px 0; - margin: 0 5px; - - overflow: hidden; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-name { - border-top: 1px dashed #0b3776; - border-bottom: 1px dashed #0b3776; - color: #0b3776; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-name { - color: #fdf612; - border-top: 1px dashed #fdf612; - border-bottom: 1px dashed #fdf612; -} - -#mine-wrapper .game-wrapper .users .user-container .user-caret { - height: 30px; - font-size: 30px; - text-align: center; - line-height: 15px; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-caret > i { - color: #0b3776; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-caret > i { - color: #fdf612; -} - -#mine-wrapper .game-wrapper .users .user-container .user-desc { - height: 65px; - font-size: 14px; - text-align: center; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-desc { - color: #0b3776; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-desc { - color: #fdf612; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control { - background: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); - background: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); - background: linear-gradient(135deg, rgba(255, 255, 255, 0.5) 0%, rgba(125, 185, 232, 0) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#007db9e8', GradientType=1); - position: relative; - padding: 5px; - - -webkit-border-radius: 5px; - border-radius: 5px; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control > img { - position: absolute; - width: 55px; - left: -5px; - bottom: 10px; - - -ms-transform: rotate(-15deg); - -webkit-transform: rotate(-15deg); - transform: rotate(-15deg); -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .user-control-mines { - display: inline-block; - background: #FFFFFF; - font-size: 25px; - text-align: center; - width: 45px; - height: 35px; - margin-left: 25px; - margin-top: 5px; - - -webkit-border-radius: 5px; - border-radius: 5px; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-control .user-control-mines { - color: #1a3955; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-control .user-control-mines { - color: #b10000; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container { - display: inline-block; - float: right; - width: 65px; - height: 45px; - border: 1px solid #000; - - -webkit-border-radius: 7px; - border-radius: 7px; - -webkit-border-radius: 7px; - border-radius: 7px; - -webkit-transform: translateZ(0); - transform: translateZ(0); - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -moz-osx-font-smoothing: grayscale; - box-shadow: 0 0 1px rgba(0, 0, 0, 0); -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container.buzz:hover { - -webkit-animation-name: hvr-buzz-out; - animation-name: hvr-buzz-out; - -webkit-animation-duration: 0.75s; - animation-duration: 0.75s; - -webkit-animation-timing-function: linear; - animation-timing-function: linear; - -webkit-animation-iteration-count: 1; - animation-iteration-count: 1; -} - -@-webkit-keyframes hvr-buzz-out { - 10% { - -webkit-transform: translateX(3px) rotate(2deg); - transform: translateX(3px) rotate(2deg); - } - 20% { - -webkit-transform: translateX(-3px) rotate(-2deg); - transform: translateX(-3px) rotate(-2deg); - } - 30% { - -webkit-transform: translateX(3px) rotate(2deg); - transform: translateX(3px) rotate(2deg); - } - 40% { - -webkit-transform: translateX(-3px) rotate(-2deg); - transform: translateX(-3px) rotate(-2deg); - } - 50% { - -webkit-transform: translateX(2px) rotate(1deg); - transform: translateX(2px) rotate(1deg); - } - 60% { - -webkit-transform: translateX(-2px) rotate(-1deg); - transform: translateX(-2px) rotate(-1deg); - } - 70% { - -webkit-transform: translateX(2px) rotate(1deg); - transform: translateX(2px) rotate(1deg); - } - 80% { - -webkit-transform: translateX(-2px) rotate(-1deg); - transform: translateX(-2px) rotate(-1deg); - } - 90% { - -webkit-transform: translateX(1px) rotate(0); - transform: translateX(1px) rotate(0); - } - 100% { - -webkit-transform: translateX(-1px) rotate(0); - transform: translateX(-1px) rotate(0); - } -} - -@keyframes hvr-buzz-out { - 10% { - -webkit-transform: translateX(3px) rotate(2deg); - transform: translateX(3px) rotate(2deg); - } - 20% { - -webkit-transform: translateX(-3px) rotate(-2deg); - transform: translateX(-3px) rotate(-2deg); - } - 30% { - -webkit-transform: translateX(3px) rotate(2deg); - transform: translateX(3px) rotate(2deg); - } - 40% { - -webkit-transform: translateX(-3px) rotate(-2deg); - transform: translateX(-3px) rotate(-2deg); - } - 50% { - -webkit-transform: translateX(2px) rotate(1deg); - transform: translateX(2px) rotate(1deg); - } - 60% { - -webkit-transform: translateX(-2px) rotate(-1deg); - transform: translateX(-2px) rotate(-1deg); - } - 70% { - -webkit-transform: translateX(2px) rotate(1deg); - transform: translateX(2px) rotate(1deg); - } - 80% { - -webkit-transform: translateX(-2px) rotate(-1deg); - transform: translateX(-2px) rotate(-1deg); - } - 90% { - -webkit-transform: translateX(1px) rotate(0); - transform: translateX(1px) rotate(0); - } - 100% { - -webkit-transform: translateX(-1px) rotate(0); - transform: translateX(-1px) rotate(0); - } -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb { - width: 100%; - height: 100%; - text-align: center; - cursor: pointer; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb img { - display: inline-block; - height: 100%; -} - -#mine-wrapper .game-wrapper .users .resign { - background: rgba(70, 73, 66, 1); - background: -moz-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); - background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(70, 73, 66, 1)), color-stop(69%, rgba(140, 138, 139, 1)), color-stop(100%, rgba(96, 89, 97, 1))); - background: -webkit-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); - background: -o-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); - background: -ms-linear-gradient(top, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); - background: linear-gradient(to bottom, rgba(70, 73, 66, 1) 0%, rgba(140, 138, 139, 1) 69%, rgba(96, 89, 97, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#464942', endColorstr='#605961', GradientType=0); - display: block; - position: relative; - width: 95%; - height: 50px; - font-family: 'Open Sans', sans-serif; - font-weight: bold; - font-size: 22px; - text-transform: uppercase; - text-align: center; - line-height: 40px; - border: 3px solid #484742; - color: #fff; - margin: 10px auto 0 auto; - - outline: none; - cursor: pointer; - - -webkit-border-radius: 5px; - border-radius: 5px; - -webkit-transition: all 250ms ease-in-out; - -moz-transition: all 250ms ease-in-out; - -o-transition: all 250ms ease-in-out; - transition: all 250ms ease-in-out; -} - -#mine-wrapper .game-wrapper .users .resign:hover { - background: rgba(70, 73, 66, 1); - color: #FFFFFF; - - -webkit-transition: all 250ms ease-in-out; - -moz-transition: all 250ms ease-in-out; - -o-transition: all 250ms ease-in-out; - transition: all 250ms ease-in-out; -} - -#mine-wrapper .game-wrapper .users .resign.disabled { - background: rgba(70, 73, 66, 1); - color: #848484; - - cursor: default; -} - -#mine-wrapper .game-wrapper .users .resign.disabled:hover { - background: rgba(70, 73, 66, 1); - color: #848484; -} - -#mine-wrapper .game-wrapper .users .resign .resign-shine { - background: rgba(255, 255, 255, 1); - background: -moz-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); - background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(255, 255, 255, 1)), color-stop(100%, rgba(0, 0, 0, 0))); - background: -webkit-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); - background: -o-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); - background: -ms-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); - background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 0%, rgba(0, 0, 0, 0) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#000000', GradientType=0); - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 33%; - - opacity: 0.7; - - -webkit-border-radius: 5px; - border-radius: 5px; - -webkit-transition: all 250ms ease-in-out; - -moz-transition: all 250ms ease-in-out; - -o-transition: all 250ms ease-in-out; - transition: all 250ms ease-in-out; -} - -#mine-wrapper .game-wrapper .users .resign:hover .resign-shine, -#mine-wrapper .game-wrapper .users .resign.disabled .resign-shine { - display: none; - - -webkit-transition: all 250ms ease-in-out; - -moz-transition: all 250ms ease-in-out; - -o-transition: all 250ms ease-in-out; - transition: all 250ms ease-in-out; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container:hover .bomb img { - -webkit-animation-name: hvr-buzz; - animation-name: hvr-buzz; - -webkit-animation-duration: 0.15s; - animation-duration: 0.15s; - -webkit-animation-timing-function: linear; - animation-timing-function: linear; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - -#mine-wrapper .game-wrapper .users .user-container .user-control .bomb-container .bomb { - -webkit-border-radius: 5px; - border-radius: 5px; -} - -#mine-wrapper .game-wrapper .users .user-container.user-blue .user-control .bomb-container .bomb { - background: rgb(131, 194, 245); - background: -moz-linear-gradient(top, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); - background: -webkit-linear-gradient(top, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); - background: linear-gradient(to bottom, rgba(131, 194, 245, 1) 0%, rgba(108, 190, 230, 1) 39%, rgba(221, 255, 252, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#83c2f5', endColorstr='#ddfffc', GradientType=0); - border: 3px solid #0b538e; -} - -#mine-wrapper .game-wrapper .users .user-container.user-red .user-control .bomb-container .bomb { - background: rgb(255, 175, 159); - background: -moz-linear-gradient(top, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); - background: -webkit-linear-gradient(top, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); - background: linear-gradient(to bottom, rgba(255, 175, 159, 1) 0%, rgba(231, 113, 7, 1) 54%, rgba(231, 113, 7, 1) 54%, rgba(237, 172, 16, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffaf9f', endColorstr='#edac10', GradientType=0); - border: 3px solid #c9221c; -} - -#mine-wrapper .game-wrapper .users .active-mines-container { - background: -moz-radial-gradient(center, ellipse cover, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); - background: -webkit-radial-gradient(center, ellipse cover, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); - background: radial-gradient(ellipse at center, rgba(255, 252, 252, 1) 0%, rgba(255, 252, 252, 0.99) 1%, rgba(106, 106, 106, 0.39) 61%, rgba(106, 106, 106, 0) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcfc', endColorstr='#006a6a6a', GradientType=1); - background-repeat: no-repeat; - background-position: center center; - background-size: 72% 179%; - position: relative; - height: 30px; -} - -#mine-wrapper .game-wrapper .users .active-mines-container i { - font-size: 27px; - color: #b1b1b3; - margin-top: 3px; - - text-shadow: 0 0 3px #000000; -} - -#mine-wrapper .game-wrapper .users .active-mines-container i:first-child { - float: left; - margin-left: 20px; -} - -#mine-wrapper .game-wrapper .users .active-mines-container i:last-child { - float: right; - margin-right: 20px; -} - -#mine-wrapper .game-wrapper .users .active-mines-container .active-mines { - background: -moz-linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); - background: -webkit-linear-gradient(top, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); - background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(135, 136, 131, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#3e3f41', endColorstr='#878883', GradientType=0); - position: absolute; - width: 50px; - height: 50px; - top: -7.5px; - left: 50%; - font-family: 'Open Sans', sans-serif; - font-size: 25px; - line-height: 39px; - text-align: center; - color: #FFFFFF; - border: 5px solid #000000; - margin-left: -25px; - - z-index: 100; - - -webkit-border-radius: 50%; - border-radius: 50%; -} - -#mine-wrapper .game-wrapper .users .active-mines-container .active-mines.found-mine { - -webkit-animation: bubbleLeftMine 750ms cubic-bezier(.36, .07, .19, .97) both; - animation: bubbleLeftMine 750ms cubic-bezier(.36, .07, .19, .97) both; -} - -@keyframes bubbleLeftMine { - 0% { - -webkit-transform: scale(1); - transform: scale(1); - } - 50% { - border-color: #2e3337; - -webkit-transform: scale(2); - transform: scale(2); - } - 100% { - -webkit-transform: scale(1); - transform: scale(1); - } -} - -#mine-wrapper .game-wrapper .users .active-mines-container .active-mines .active-mines-shine { - background: -moz-linear-gradient(top, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); - background: -webkit-linear-gradient(top, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); - background: linear-gradient(to bottom, rgba(213, 214, 216, 1) 0%, rgba(106, 106, 106, 1) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#d5d6d8', endColorstr='#6a6a6a', GradientType=0); - position: absolute; - top: 0; - left: 50%; - width: 30px; - height: 20px; - margin-left: -14.5px; - - z-index: 101; - - -webkit-border-radius: 50%; - border-radius: 50%; -} - -#mine-wrapper .game-wrapper .users .active-mines-container .active-mines .active-mines-nbr { - position: absolute; - top: 0; - width: 100%; - - z-index: 102; -} - -/** game grid */ - -#mine-wrapper .grid { - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: center; - justify-content: center; - width: 643px; - border: 1px solid #cac3e5; - - cursor: none; -} - -#mine-wrapper .grid-container { - background: #4E4E4E; - padding: 15px 10px; - - -webkit-border-radius: 5px; - border-radius: 5px; -} - -#mine-wrapper .grid .field-wrapper { - position: relative; -} - -#mine-wrapper .grid .field-wrapper > img.field-target { - position: absolute; - display: none; - width: 45px; - top: -2.5px; - left: -2.5px; - - z-index: 100; -} - -#mine-wrapper .grid .field-wrapper:hover > img.field-target { - display: block; -} - -/*#mine-wrapper .grid .field-wrapper.targeted > img.field-target {*/ -/*display: block;*/ -/*}*/ - -/** width = 4 x .field */ -#mine-wrapper .grid .field-wrapper > img.field-bomb-target { - position: absolute; - display: block; - top: 0; - left: 0; - width: 100%; - - z-index: 100; -} - -#mine-wrapper .grid .field-wrapper > img.field-blue-last, -#mine-wrapper .grid .field-wrapper > img.field-red-last { - position: absolute; - display: none; - width: 100%; - top: 0; - left: 0; - z-index: 99; -} - -#mine-wrapper .grid .field-wrapper > img.field-blue-last.last-clicked, -#mine-wrapper .grid .field-wrapper > img.field-red-last.last-clicked { - display: block; -} - -#mine-wrapper .grid .field-wrapper .field { - background: #61defa; - background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); - background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); - background: linear-gradient(to right, #61defa 0%, #119dec 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); - width: 40px; - height: 40px; - border: 2px solid #51c2fe; - font-family: 'Open Sans', sans-serif; - font-weight: bold; - font-size: 35px; - text-align: center; - line-height: 35px; -} - -#mine-wrapper .grid .field-wrapper .field .field-corner { - background: url('/images/bg-corner-outbg.png') no-repeat top left; - background-size: 100%; - width: 100%; - height: 100%; -} - -#mine-wrapper .grid .field-wrapper .field.active { - background: #fde717; - background: -moz-linear-gradient(left, #fde717 0%, #f5b807 100%); - background: -webkit-linear-gradient(left, #fde717 0%, #f5b807 100%); - background: linear-gradient(to right, #fde717 0%, #f5b807 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fde717', endColorstr='#f5b807', GradientType=1); - border: 2px solid #f6d762; - color: #000; -} - -#mine-wrapper .grid .field-wrapper .field.active .flag-number { - -webkit-animation: bubbleNumber 500ms cubic-bezier(.36, .07, .19, .97) both; - animation: bubbleNumber 500ms cubic-bezier(.36, .07, .19, .97) both; - -webkit-transform: scale(1); - transform: scale(1); -} - -@keyframes bubbleNumber { - 0% { - background: #61defa; - background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); - background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); - background: linear-gradient(to right, #61defa 0%, #119dec 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); - - -webkit-border-radius: 50%; - border-radius: 50%; - -webkit-transform: scale(1); - transform: scale(1); - } - 50% { - -webkit-border-radius: 50%; - border-radius: 50%; - -webkit-transform: scale(0); - transform: scale(0); - } - 100% { - -webkit-border-radius: 0; - border-radius: 0; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -#mine-wrapper .grid .field-wrapper .field.active .flag-mine { - position: relative; - overflow: hidden; -} - -#mine-wrapper .grid .field-wrapper .field.active .flag-mine > img { - width: 75%; - margin-left: 15px; - - -ms-transform: rotate(7deg); - -webkit-transform: rotate(7deg); - transform: rotate(7deg); - -webkit-animation: mineFlagLoad 500ms cubic-bezier(.36, .07, .19, .97) both; - animation: mineFlagLoad 500ms cubic-bezier(.36, .07, .19, .97) both; -} - -@keyframes mineFlagLoad { - 0% { - margin-bottom: 0; - margin-left: 15px; - - -ms-transform: rotate(9deg); - -webkit-transform: rotate(9deg); - transform: rotate(9deg); - } - 50% { - margin-bottom: -5px; - margin-left: 7px; - } - 100% { - margin-bottom: 3px; - margin-left: 0; - - -ms-transform: rotate(-9deg); - -webkit-transform: rotate(-9deg); - transform: rotate(-9deg); - } -} - -#mine-wrapper .grid .field-wrapper .field.active .flag-mine .flag-mine-base { - position: absolute; - background: #000000; - width: 25px; - height: 22px; - bottom: -12px; - left: 50%; - margin-left: -10.5px; - - -webkit-border-radius: 50%; - border-radius: 50%; - -webkit-animation: mineBaseLoad 500ms cubic-bezier(.36, .07, .19, .97) both; - animation: mineBaseLoad 500ms cubic-bezier(.36, .07, .19, .97) both; -} - -@keyframes mineBaseLoad { - 0% { - margin-bottom: 0; - } - 50% { - margin-bottom: -5px; - } - 100% { - margin-bottom: 0; - } -} - -#mine-wrapper .grid .field-wrapper .field.active.mine { - background: #61defa; - background: -moz-linear-gradient(left, #61defa 0%, #119dec 100%); - background: -webkit-linear-gradient(left, #61defa 0%, #119dec 100%); - background: linear-gradient(to right, #61defa 0%, #119dec 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#61defa', endColorstr='#119dec', GradientType=1); - border: 2px solid #51c2fe; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-1 { - color: #0000ff; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-2 { - color: #079433; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-3 { - color: #fd1400; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-4 { - color: #0c099e; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-5 { - color: #7b4c01; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-6 { - color: #008388; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-7 { - color: #000000; -} - -#mine-wrapper .grid .field-wrapper .field.active.color-8 { - color: #ff0000; -} - -#mine-wrapper .grid .field-wrapper .field img { - width: 80%; -} - -.back-from-game { - display: inline-block; - position: fixed; - top: 20px; - left: 20px; - - -ms-transform: scale(1); /* IE 9 */ - -webkit-transform: scale(1); /* Safari */ - transform: scale(1); - -webkit-transition: all 250ms cubic-bezier(.17, .67, .83, .67); - transition: all 250ms cubic-bezier(.17, .67, .83, .67); -} - -.back-from-game img { - width: 100px; -} - -.back-from-game:hover { - -ms-transform: scale(1.2); /* IE 9 */ - -webkit-transform: scale(1.2); /* Safari */ - transform: scale(1.2); - -webkit-transition: all 250ms cubic-bezier(.17, .67, .83, .67); - transition: all 250ms cubic-bezier(.17, .67, .83, .67); -} - -@media screen and (max-width: 900px) { - #mine-wrapper .game-wrapper .users { - visibility: hidden; - display: none; - } - - #mine-wrapper { - display: block; - width: 100%; - } - - #mine-wrapper .game-wrapper { - width: 100%; - flex-direction: column-reverse; - } - - #mine-wrapper .grid-container { - width: 100%; - padding: 0; - } - - #mine-wrapper .grid { - width: 100%; - } - - #mine-wrapper .grid .field-wrapper { - width: 6.25%; - aspect-ratio: 1; - } - - #mine-wrapper .grid .field-wrapper > img.field-target { - width: 105%; - top: -2.5%; - left: -2.5%; - } - - #mine-wrapper .grid .field-wrapper .field { - width: 100%; - height: auto; - } -} - -// ── Game Timer ──────────────────────────────────────────────────────────── - -#mine-wrapper .game-timer-container { - display: flex; - gap: 12px; - justify-content: center; - margin-bottom: 10px; -} - -#mine-wrapper .game-timer { - display: flex; - gap: 10px; - align-items: center; - justify-content: center; - min-width: 115px; - border-radius: 8px; - padding: 8px 18px; - font-family: 'Rajdhani', sans-serif; - font-weight: bold; - border: 2px solid transparent; - transition: all 0.4s ease; -} - -// Red – waiting -#mine-wrapper .game-timer.red-timer { - background: linear-gradient(to bottom, #4a0603 0%, #6b2515 100%); - border-color: #7a1e10; - color: rgba(246, 125, 82, 0.55); -} - -// Red – active (thinking) -#mine-wrapper .game-timer.red-timer.active { - background: linear-gradient(to bottom, #ad0a05 0%, #f67d52 100%); - border-color: #ff9b6b; - color: #fff; - box-shadow: 0 0 16px rgba(173, 10, 5, 0.75), 0 0 5px rgba(246, 125, 82, 0.5); -} - -// Blue – waiting -#mine-wrapper .game-timer.blue-timer { - background: linear-gradient(to bottom, #0b2530 0%, #163d55 100%); - border-color: #173650; - color: rgba(149, 207, 245, 0.55); -} - -// Blue – active (thinking) -#mine-wrapper .game-timer.blue-timer.active { - background: linear-gradient(to bottom, #236f87 0%, #95cff5 100%); - border-color: #b8e5ff; - color: #fff; - box-shadow: 0 0 16px rgba(35, 111, 135, 0.75), 0 0 5px rgba(149, 207, 245, 0.5); -} - -#mine-wrapper .game-timer .timer-icon { - font-size: 15px; - opacity: 0.7; - flex-shrink: 0; -} - -#mine-wrapper .game-timer.active .timer-icon { - opacity: 1; - animation: timer-icon-pulse 1.6s ease-in-out infinite; -} - -@keyframes timer-icon-pulse { - 0%, 100% { transform: scale(1); opacity: 0.85; } - 50% { transform: scale(1.2); opacity: 1; } -} - -#mine-wrapper .game-timer .timer-display { - font-family: 'Courier New', monospace; - font-size: 20px; - letter-spacing: 2px; -} - +@import 'mineseeker/base'; +@import 'mineseeker/overlay'; +@import 'mineseeker/users'; +@import 'mineseeker/bomb'; +@import 'mineseeker/mine-counter'; +@import 'mineseeker/grid'; +@import 'mineseeker/back-button'; +@import 'mineseeker/timer'; +@import 'mineseeker/responsive'; \ No newline at end of file diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 44174d3..99e67ec 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -1,27 +1,35 @@ security: - # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers + password_hashers: + App\Entity\User: + algorithm: auto + providers: app_user_provider: entity: class: App\Entity\User property: username + firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: lazy: true + provider: app_user_provider + user_checker: App\Security\UserChecker + form_login: + login_path: MineSeekerBundle_login + check_path: MineSeekerBundle_login + default_target_path: MineSeekerBundle_homepage + username_parameter: _username + password_parameter: _password + enable_csrf: true + logout: + path: MineSeekerBundle_logout + target: MineSeekerBundle_homepage + remember_me: + secret: '%kernel.secret%' + lifetime: 604800 + remember_me_parameter: _remember_me - # activate different ways to authenticate - - # http_basic: true - # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate - - # form_login: true - # https://symfony.com/doc/current/security/form_login_setup.html - - # Easy way to control access for large sections of your site - # Note: Only the *first* access control that matches will be used access_control: - # - { path: ^/admin, roles: ROLE_ADMIN } - # - { path: ^/profile, roles: ROLE_USER } diff --git a/public/images/beta-logo-png-2.png b/public/images/beta-logo-png-2.png deleted file mode 100644 index cd5b209..0000000 Binary files a/public/images/beta-logo-png-2.png and /dev/null differ diff --git a/public/images/msn-minesweeper.png b/public/images/msn-minesweeper.png new file mode 100644 index 0000000..0b79a2b Binary files /dev/null and b/public/images/msn-minesweeper.png differ diff --git a/public/images/technologies/archlinux.svg b/public/images/technologies/archlinux.svg new file mode 100644 index 0000000..3b89ff6 --- /dev/null +++ b/public/images/technologies/archlinux.svg @@ -0,0 +1 @@ +Arch Linux \ No newline at end of file diff --git a/public/images/technologies/howler.svg b/public/images/technologies/howler.svg index bf9ea0a..6b1220e 100644 --- a/public/images/technologies/howler.svg +++ b/public/images/technologies/howler.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/images/technologies/mercure.svg b/public/images/technologies/mercure.svg index dbd2da3..df8f7e1 100644 --- a/public/images/technologies/mercure.svg +++ b/public/images/technologies/mercure.svg @@ -1,18 +1,12 @@ - - - + + - - + + - - - - - + + \ No newline at end of file diff --git a/src/Controller/ProfileController.php b/src/Controller/ProfileController.php new file mode 100644 index 0000000..c32703e --- /dev/null +++ b/src/Controller/ProfileController.php @@ -0,0 +1,83 @@ + + * @category Class + * @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License + * @link www.splendidbear.org + * @since 2026. 04. 11. + */ +class ProfileController extends AbstractController +{ + #[Route('/profile', name: 'MineSeekerBundle_profile')] + public function index(EntityManagerInterface $em): Response + { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); + + /** @var User $user */ + $user = $this->getUser(); + + $finished = '(g.redPoints IS NOT NULL OR g.resign IS NOT NULL)'; + + $total = (int) $em->createQuery( + "SELECT COUNT(g.id) FROM App\Entity\PlayedGame g + WHERE (g.red = :u OR g.blue = :u) AND {$finished}" + )->setParameter('u', $user)->getSingleScalarResult(); + + $wins = (int) $em->createQuery( + "SELECT COUNT(g.id) FROM App\Entity\PlayedGame g WHERE ( + (g.red = :u AND g.redPoints > g.bluePoints AND g.resign IS NULL) OR + (g.blue = :u AND g.bluePoints > g.redPoints AND g.resign IS NULL) OR + (g.red = :u AND g.resign = 'blue') OR + (g.blue = :u AND g.resign = 'red') + )" + )->setParameter('u', $user)->getSingleScalarResult(); + + $losses = (int) $em->createQuery( + "SELECT COUNT(g.id) FROM App\Entity\PlayedGame g WHERE ( + (g.red = :u AND g.bluePoints > g.redPoints AND g.resign IS NULL) OR + (g.blue = :u AND g.redPoints > g.bluePoints AND g.resign IS NULL) OR + (g.red = :u AND g.resign = 'red') OR + (g.blue = :u AND g.resign = 'blue') + )" + )->setParameter('u', $user)->getSingleScalarResult(); + + $bombs = (int) $em->createQuery( + "SELECT COUNT(g.id) FROM App\Entity\PlayedGame g WHERE + (g.red = :u AND g.redExplodedBomb = true) OR + (g.blue = :u AND g.blueExplodedBomb = true)" + )->setParameter('u', $user)->getSingleScalarResult(); + + $recent = $em->createQuery( + "SELECT g FROM App\Entity\PlayedGame g + LEFT JOIN g.red rr LEFT JOIN g.blue bb + LEFT JOIN g.redAnon ra LEFT JOIN g.blueAnon ba + WHERE (g.red = :u OR g.blue = :u) AND {$finished} + ORDER BY g.updated DESC" + )->setParameter('u', $user)->setMaxResults(10)->getResult(); + + return $this->render('Security/profile.html.twig', [ + 'stats' => compact('total', 'wins', 'losses', 'bombs'), + 'recent' => $recent, + ]); + } +} diff --git a/src/Controller/SecurityController.php b/src/Controller/SecurityController.php new file mode 100644 index 0000000..d5f6f9b --- /dev/null +++ b/src/Controller/SecurityController.php @@ -0,0 +1,155 @@ + + * @category Class + * @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License + * @link www.splendidbear.org + * @since 2026. 04. 11. + */ +class SecurityController extends AbstractController +{ + #[Route('/login', name: 'MineSeekerBundle_login')] + public function login(AuthenticationUtils $authenticationUtils): Response + { + if ($this->getUser()) { + return $this->redirectToRoute('MineSeekerBundle_homepage'); + } + + return $this->render('Security/login.html.twig', [ + 'last_username' => $authenticationUtils->getLastUsername(), + 'error' => $authenticationUtils->getLastAuthenticationError(), + ]); + } + + #[Route('/logout', name: 'MineSeekerBundle_logout', methods: ['POST'])] + public function logout(): void + { + // Intercepted by the security firewall — never executed. + } + + #[Route('/register', name: 'MineSeekerBundle_register')] + public function register( + Request $request, + UserPasswordHasherInterface $hasher, + EntityManagerInterface $em, + MailerInterface $mailer, + ): Response { + if ($this->getUser()) { + return $this->redirectToRoute('MineSeekerBundle_homepage'); + } + + $errors = []; + + if ($request->isMethod('POST')) { + $username = trim((string) $request->request->get('_username', '')); + $email = trim((string) $request->request->get('_email', '')); + $password = (string) $request->request->get('_password', ''); + $passwordConfirm = (string) $request->request->get('_password_confirm', ''); + + if (mb_strlen($username) < 3) { + $errors['username'] = 'Username must be at least 3 characters.'; + } elseif ($em->getRepository(User::class)->findOneBy(['username' => $username])) { + $errors['username'] = 'This username is already taken.'; + } + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $errors['email'] = 'Please enter a valid email address.'; + } elseif ($em->getRepository(User::class)->findOneBy(['email' => $email])) { + $errors['email'] = 'This email address is already registered.'; + } + + if (mb_strlen($password) < 6) { + $errors['password'] = 'Password must be at least 6 characters.'; + } elseif ($password !== $passwordConfirm) { + $errors['password_confirm'] = 'Passwords do not match.'; + } + + if (empty($errors)) { + $token = bin2hex(random_bytes(32)); + + $user = (new User()) + ->setUsername($username) + ->setEmail($email) + ->setIsVerified(false) + ->setVerificationToken($token); + + $user->setPassword($hasher->hashPassword($user, $password)); + + $em->persist($user); + $em->flush(); + + $activationUrl = $this->generateUrl( + 'MineSeekerBundle_activate', + ['token' => $token], + UrlGeneratorInterface::ABSOLUTE_URL, + ); + + $mailer->send( + (new TemplatedEmail()) + ->from('noreply@mineseeker.ninja') + ->to($email) + ->subject('Activate your MineSeeker account') + ->htmlTemplate('emails/activation.html.twig') + ->context([ + 'username' => $username, + 'activation_url' => $activationUrl, + ]) + ); + + $this->addFlash('verify_email', $email); + + return $this->redirectToRoute('MineSeekerBundle_register'); + } + } + + return $this->render('Security/register.html.twig', [ + 'errors' => $errors, + 'last_username' => $request->request->get('_username', ''), + 'last_email' => $request->request->get('_email', ''), + ]); + } + + #[Route('/activate/{token}', name: 'MineSeekerBundle_activate')] + public function activate(string $token, EntityManagerInterface $em): Response + { + $user = $em->getRepository(User::class)->findOneBy(['verificationToken' => $token]); + + if (!$user) { + $this->addFlash('error', 'This activation link is invalid or has already been used.'); + return $this->redirectToRoute('MineSeekerBundle_login'); + } + + $user->setIsVerified(true)->setVerificationToken(null); + $em->flush(); + + $this->addFlash('success', 'Your account is now active. Welcome, ' . $user->getUsername() . '!'); + + return $this->redirectToRoute('MineSeekerBundle_login'); + } +} \ No newline at end of file diff --git a/src/Entity/User.php b/src/Entity/User.php index 89ec171..4fab311 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -15,8 +15,10 @@ use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\GeneratedValue; use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\Table; use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Validator\Constraints as Assert; /** * Class User @@ -28,6 +30,7 @@ use Symfony\Component\Security\Core\User\UserInterface; * @link www.splendidbear.org * @since 2026. 04. 09. */ +#[Table(name: 'app_user')] #[Entity(repositoryClass: UserRepository::class)] class User implements UserInterface, PasswordAuthenticatedUserInterface { @@ -43,6 +46,15 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface #[Column(nullable: true)] private ?string $password = null; + #[Column(length: 254, unique: true, nullable: true)] + private ?string $email = null; + + #[Column] + private bool $isVerified = false; + + #[Column(length: 64, nullable: true)] + private ?string $verificationToken = null; + public function getId(): ?int { @@ -92,4 +104,37 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface public function eraseCredentials(): void { } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(?string $email): self + { + $this->email = $email; + return $this; + } + + public function isVerified(): bool + { + return $this->isVerified; + } + + public function setIsVerified(bool $isVerified): self + { + $this->isVerified = $isVerified; + return $this; + } + + public function getVerificationToken(): ?string + { + return $this->verificationToken; + } + + public function setVerificationToken(?string $verificationToken): self + { + $this->verificationToken = $verificationToken; + return $this; + } } diff --git a/src/Migrations/2026/04/Version20260411180138.php b/src/Migrations/2026/04/Version20260411180138.php new file mode 100644 index 0000000..457461d --- /dev/null +++ b/src/Migrations/2026/04/Version20260411180138.php @@ -0,0 +1,87 @@ + + * @category Class + * @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License + * @link www.splendidbear.org + * @since 2026. 04. 11. + */ +final class Version20260411180138 extends AbstractMigration +{ + public function getDescription(): string + { + return 'Initialize the Mineseeker'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE app_user_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE gamer_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE grid_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE grid_row_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE played_game_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE SEQUENCE step_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE app_user (id INT NOT NULL, username VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) DEFAULT NULL, email VARCHAR(254) DEFAULT NULL, is_verified BOOLEAN NOT NULL, verification_token VARCHAR(64) DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_88BDF3E9F85E0677 ON app_user (username)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_88BDF3E9E7927C74 ON app_user (email)'); + $this->addSql('CREATE TABLE gamer (id INT NOT NULL, user_name VARCHAR(100) NOT NULL, ip VARCHAR(20) DEFAULT NULL, country VARCHAR(100) DEFAULT NULL, user_agent VARCHAR(255) DEFAULT NULL, conn_timestamp TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE grid (id INT NOT NULL, played_game_id INT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_2E20D9375AA11DBB ON grid (played_game_id)'); + $this->addSql('CREATE TABLE grid_row (id INT NOT NULL, grid INT DEFAULT NULL, grid_col JSON NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_6FAD08EB2E20D937 ON grid_row (grid)'); + $this->addSql('CREATE TABLE played_game (id INT NOT NULL, red_id INT DEFAULT NULL, red_anon INT DEFAULT NULL, blue_id INT DEFAULT NULL, blue_anon INT DEFAULT NULL, game_assoc VARCHAR(50) NOT NULL, red_points INT DEFAULT NULL, blue_points INT DEFAULT NULL, red_exploded_bomb BOOLEAN DEFAULT NULL, blue_exploded_bomb BOOLEAN DEFAULT NULL, resign VARCHAR(7) DEFAULT NULL, created TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updated TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_54BE80398BBE8922 ON played_game (red_id)'); + $this->addSql('CREATE INDEX IDX_54BE8039F24372EB ON played_game (red_anon)'); + $this->addSql('CREATE INDEX IDX_54BE80395AB9393F ON played_game (blue_id)'); + $this->addSql('CREATE INDEX IDX_54BE8039C64E7C7C ON played_game (blue_anon)'); + $this->addSql('CREATE TABLE step (id INT NOT NULL, played_game_id INT DEFAULT NULL, row INT NOT NULL, col INT NOT NULL, w_bomb BOOLEAN DEFAULT NULL, player VARCHAR(10) DEFAULT NULL, revealed_cells JSON DEFAULT NULL, created TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_43B9FE3C5AA11DBB ON step (played_game_id)'); + $this->addSql('ALTER TABLE grid ADD CONSTRAINT FK_2E20D9375AA11DBB FOREIGN KEY (played_game_id) REFERENCES played_game (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE grid_row ADD CONSTRAINT FK_6FAD08EB2E20D937 FOREIGN KEY (grid) REFERENCES grid (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE played_game ADD CONSTRAINT FK_54BE80398BBE8922 FOREIGN KEY (red_id) REFERENCES app_user (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE played_game ADD CONSTRAINT FK_54BE8039F24372EB FOREIGN KEY (red_anon) REFERENCES gamer (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE played_game ADD CONSTRAINT FK_54BE80395AB9393F FOREIGN KEY (blue_id) REFERENCES app_user (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE played_game ADD CONSTRAINT FK_54BE8039C64E7C7C FOREIGN KEY (blue_anon) REFERENCES gamer (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE step ADD CONSTRAINT FK_43B9FE3C5AA11DBB FOREIGN KEY (played_game_id) REFERENCES played_game (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP SEQUENCE app_user_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE gamer_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE grid_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE grid_row_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE played_game_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE step_id_seq CASCADE'); + $this->addSql('ALTER TABLE grid DROP CONSTRAINT FK_2E20D9375AA11DBB'); + $this->addSql('ALTER TABLE grid_row DROP CONSTRAINT FK_6FAD08EB2E20D937'); + $this->addSql('ALTER TABLE played_game DROP CONSTRAINT FK_54BE80398BBE8922'); + $this->addSql('ALTER TABLE played_game DROP CONSTRAINT FK_54BE8039F24372EB'); + $this->addSql('ALTER TABLE played_game DROP CONSTRAINT FK_54BE80395AB9393F'); + $this->addSql('ALTER TABLE played_game DROP CONSTRAINT FK_54BE8039C64E7C7C'); + $this->addSql('ALTER TABLE step DROP CONSTRAINT FK_43B9FE3C5AA11DBB'); + $this->addSql('DROP TABLE app_user'); + $this->addSql('DROP TABLE gamer'); + $this->addSql('DROP TABLE grid'); + $this->addSql('DROP TABLE grid_row'); + $this->addSql('DROP TABLE played_game'); + $this->addSql('DROP TABLE step'); + } +} diff --git a/src/Security/UserChecker.php b/src/Security/UserChecker.php new file mode 100644 index 0000000..11f53e5 --- /dev/null +++ b/src/Security/UserChecker.php @@ -0,0 +1,44 @@ + + * @category Class + * @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License + * @link www.splendidbear.org + * @since 2026. 04. 11. + */ +final class UserChecker implements UserCheckerInterface +{ + public function checkPreAuth(UserInterface $user): void + { + if (!$user instanceof User) { + return; + } + + if (!$user->isVerified()) { + throw new CustomUserMessageAuthenticationException( + 'Please verify your email address before signing in. Check your inbox for the activation link.' + ); + } + } + + public function checkPostAuth(UserInterface $user): void { } +} diff --git a/templates/Game/index.html.twig b/templates/Game/index.html.twig index 81356a1..34baebb 100644 --- a/templates/Game/index.html.twig +++ b/templates/Game/index.html.twig @@ -15,6 +15,28 @@
+
+ {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %} + + + {{ app.user.username }} + +
+ + +
+ {% else %} + + Sign in + + + Register + + {% endif %} +
+ @@ -22,12 +44,7 @@
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}

- {% if app.user.facebookId is defined and app.user.facebookId is not null %} - - {% endif %} - Welcome back, {{ app.user.realName is not null ? app.user.realName : app.user.username }} + Welcome back, {{ app.user.username }}

Ready for another round?

{% else %} @@ -41,17 +58,82 @@ {% endblock %} {% block body %} +
+
+
+ + + +
+
+

For registered players

+

Track your legacy

+

+ Create a free account and every game you play gets recorded. + Watch your win rate climb, revisit past battles, and prove your dominance + on the board — one detonation at a time. +

+ {% if not is_granted("IS_AUTHENTICATED_REMEMBERED") %} + + Create free account + + {% endif %} +
+
+
+ +
+
+
+ + MSN Messenger Minesweeper +
+
+

Our inspiration

+

Born from a legend

+

+ Remember the minesweeper hidden inside Microsoft's MSN Messenger? + That tiny two-player gem sparked countless friendships and rivalries + in the early 2000s. We loved it — so we rebuilt it for today. + Real-time, multiplayer, and no MSN account required. +

+
+
+
+

Built with

+

+ + This game would not exist without the incredible open-source community.
+ Thank you to every contributor, maintainer, and creator behind these projects. +

{% endblock %} diff --git a/templates/Security/login.html.twig b/templates/Security/login.html.twig new file mode 100644 index 0000000..d5e0451 --- /dev/null +++ b/templates/Security/login.html.twig @@ -0,0 +1,83 @@ +{% extends 'Game/index.html.twig' %} + +{% block title %} - Sign In{% endblock %} + +{% block body %} +
+ + {% for message in app.flashes('success') %} +
+ {{ message }} +
+ {% endfor %} + + {% for message in app.flashes('error') %} +
+ {{ message }} +
+ {% endfor %} + +
+

Sign In

+

Welcome back, commander

+ + {% if error %} +
+ + {{ error.messageKey|trans(error.messageData, 'security') }} +
+ {% endif %} + +
+ + +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ + + + +
+ +

+ No account yet? + Create one +

+
+ +
+{% endblock %} \ No newline at end of file diff --git a/templates/Security/profile.html.twig b/templates/Security/profile.html.twig new file mode 100644 index 0000000..cd185bd --- /dev/null +++ b/templates/Security/profile.html.twig @@ -0,0 +1,110 @@ +{% extends 'Game/index.html.twig' %} + +{% block title %} - Profile{% endblock %} + +{% block body %} +
+ +
+
+ {{ app.user.username|slice(0, 2)|upper }} +
+
+

{{ app.user.username }}

+ {% if app.user.email %} +

+ + {{ app.user.email }} +

+ {% endif %} +

+ Registered commander +

+
+
+ +
+
+ + {{ stats.total }} + Games played +
+
+ + {{ stats.wins }} + Victories +
+
+ + {{ stats.losses }} + Defeats +
+
+ + {{ stats.bombs }} + Mines hit +
+
+ + {% if recent|length > 0 %} +
+

+ Recent battles +

+
+ {% for game in recent %} + {% set is_red = game.red and game.red.id == app.user.id %} + {% set my_points = is_red ? game.redPoints : game.bluePoints %} + {% set opp_points = is_red ? game.bluePoints : game.redPoints %} + {% set opp = is_red ? game.blue : game.red %} + {% set opp_anon = is_red ? game.blueAnon : game.redAnon %} + + {% set result = 'draw' %} + {% if game.resign == (is_red ? 'red' : 'blue') %} + {% set result = 'loss' %} + {% elseif game.resign == (is_red ? 'blue' : 'red') %} + {% set result = 'win' %} + {% elseif my_points is not null and opp_points is not null %} + {% if my_points > opp_points %} + {% set result = 'win' %} + {% elseif my_points < opp_points %} + {% set result = 'loss' %} + {% endif %} + {% endif %} + +
+ + {{ result == 'win' ? 'W' : (result == 'loss' ? 'L' : 'D') }} + + + {{ my_points ?? '—' }} : {{ opp_points ?? '—' }} + + vs + + {% if opp %} + {{ opp.username }} + {% elseif opp_anon %} + {{ opp_anon.userName }} + {% else %} + Guest + {% endif %} + + + + + + {{ game.updated ? game.updated|date('Y-m-d') : '' }} + +
+ {% endfor %} +
+
+ {% else %} +
+ +

No games recorded yet. Start playing!

+
+ {% endif %} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/Security/register.html.twig b/templates/Security/register.html.twig new file mode 100644 index 0000000..0d97c2e --- /dev/null +++ b/templates/Security/register.html.twig @@ -0,0 +1,120 @@ +{% extends 'Game/index.html.twig' %} + +{% block title %} - Register{% endblock %} + +{% block body %} +
+ + {% for email in app.flashes('verify_email') %} +
+
+

Check your inbox

+

We sent an activation link to

+

{{ email }}

+

+ Click the link in the email to activate your account.
+ The link expires in 24 hours. +

+ + Go to Sign In + +
+ {% else %} + +
+

Create Account

+

Join the battle — no subscription required

+ +
+ +
+ +
+ + +
+ {% if errors.username is defined %} +

{{ errors.username }}

+ {% endif %} +
+ +
+ +
+ + +
+ {% if errors.email is defined %} +

{{ errors.email }}

+ {% endif %} +
+ +
+ +
+ + +
+ {% if errors.password is defined %} +

{{ errors.password }}

+ {% endif %} +
+ +
+ +
+ + +
+ {% if errors.password_confirm is defined %} +

{{ errors.password_confirm }}

+ {% endif %} +
+ + +
+ +

+ Already have an account? + Sign in +

+
+ + {% endfor %} +
+{% endblock %} \ No newline at end of file diff --git a/templates/base.html.twig b/templates/base.html.twig index db7e85c..79e62eb 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -1,39 +1,37 @@ - - - - - - - - - - - - - - {% block metas %}{% endblock %} - MineSeeker{% block title %}{% endblock %} - {% block stylesheets %}{% endblock %} + + + + + + + + + + + + + + {% block metas %}{% endblock %} + MineSeeker{% block title %}{% endblock %} + {% block stylesheets %}{% endblock %} - Beta version + {% block bodyTop %}{% endblock %} - {% block bodyTop %}{% endblock %} +
+ {% block header %}{% endblock %} +
+
+ {% block body %}{% endblock %} +
+
+ {% block footer %}{% endblock %} +
-
- {% block header %}{% endblock %} -
-
- {% block body %}{% endblock %} -
-
- {% block footer %}{% endblock %} -
- - {% block javascripts %}{% endblock %} + {% block javascripts %}{% endblock %} diff --git a/templates/emails/activation.html.twig b/templates/emails/activation.html.twig new file mode 100644 index 0000000..fe858b2 --- /dev/null +++ b/templates/emails/activation.html.twig @@ -0,0 +1,103 @@ + + + + + + Activate your MineSeeker account + + + +
+ +
+

One step to go

+

Activate your account, commander

+

+ Hi {{ username }},
+ Thanks for registering on MineSeeker. Click the button below to verify your + email address and activate your account. +

+

+ Activate account +

+

+ If the button doesn't work, copy and paste this link into your browser:
+ {{ activation_url }} +

+
+ +
+ + \ No newline at end of file