Inital Commit

This commit is contained in:
Alex Emmet 2026-04-21 21:35:28 +02:00
commit a309e824be
29 changed files with 2856 additions and 0 deletions

View file

@ -0,0 +1,32 @@
[
{
"name": "horse_fog",
"destructive": false
},
{
"name": "horse_rainbow",
"destructive": false
},
{
"name": "campsite",
"destructive": false
},
{
"name": "village_sunset",
"destructive": false
},
{
"name": "outpost",
"destructive": true,
"time": 8
},
{
"name": "tower_small",
"destructive": true,
"time": 8
},
{
"name": "tower_large",
"destructive": false
}
]

11
website/api/posts.json Normal file
View file

@ -0,0 +1,11 @@
[
{
"date": "2026-04-01",
"head_img": "village_sunset.png",
"file": "CoolPost123.md",
"title": "This is a cool post",
"description": "Look at this text"
}
]

50
website/api/team.json Normal file
View file

@ -0,0 +1,50 @@
[
{
"icon": "morice.png",
"name": "MoriceMC",
"priority": 0,
"role": "Owner & Lead Developer"
},
{
"icon": "ninivx.png",
"name": "NiniVX",
"priority": 1,
"role": "Administrator"
},
{
"name": "Burrata",
"priority": 1,
"role": "Administrator"
},
{
"name": "Pitrex",
"priority": 2,
"role": "Moderator & Developer"
},
{
"name": "Litus",
"priority": 2,
"role": "Moderator"
},
{
"name": "Ahnyokatzin",
"priority": 2,
"role": "Moderator"
},
{
"name": "T1X",
"priority": 2,
"role": "Moderator"
},
{
"name": "Harrpy",
"priority": 2,
"role": "Moderator"
},
{
"icon": "alexemmet.png",
"name": "AlexEmmet",
"priority": 3,
"role": "Web-Developer & Critic (Professional Hater)"
}
]

249
website/app.js Normal file
View file

@ -0,0 +1,249 @@
// Smooth scroll for nav links
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute("href"));
if (target) {
target.scrollIntoView({ behavior: "smooth" });
}
});
});
// ─── Parallax ───
function initParallax() {
const sections = document.querySelectorAll(".bg-image-section:not(#hero)");
const heroLayer = document.getElementById("hero-slideshow");
function update() {
sections.forEach((section) => {
const rect = section.getBoundingClientRect();
const yPos = -(rect.top * 0.4);
section.style.backgroundPositionY = `${yPos}px`;
});
if (heroLayer) {
const hero = document.getElementById("hero");
if (hero) {
const rect = hero.getBoundingClientRect();
const yPos = -(rect.top * 0.4);
heroLayer.style.transform = `translateY(${yPos}px) scale(1.1)`;
}
}
}
window.addEventListener("scroll", update, { passive: true });
update();
}
// ─── Hero Slideshow with Destructive Theme ───
let currentBackdrop = null;
const NEAR_TOP_THRESHOLD = 600;
function checkDestructiveTheme() {
if (!currentBackdrop) return;
const nearTop = window.scrollY < NEAR_TOP_THRESHOLD;
if (currentBackdrop.destructive && nearTop) {
document.body.classList.add("destructive-mode");
} else {
document.body.classList.remove("destructive-mode");
}
}
function initHeroSlideshow(allBackdrops, usedNames) {
const hero = document.getElementById("hero");
const layer = document.getElementById("hero-slideshow");
if (!hero || !layer) return;
const slides = allBackdrops.filter((b) => !usedNames.includes(b.name));
if (slides.length === 0) {
console.warn("No unused backdrops for hero slideshow");
return;
}
let idx = 0;
function showSlide(index) {
const backdrop = slides[index];
currentBackdrop = backdrop;
layer.style.opacity = "0";
setTimeout(() => {
layer.style.backgroundImage = `url('/assets/${backdrop.name}.png')`;
layer.style.opacity = "1";
checkDestructiveTheme();
}, 600);
const delayMs = (backdrop.time || 6) * 1000;
idx = (index + 1) % slides.length;
setTimeout(() => showSlide(idx), delayMs);
}
currentBackdrop = slides[0];
layer.style.backgroundImage = `url('/assets/${slides[0].name}.png')`;
layer.style.opacity = "1";
checkDestructiveTheme();
idx = 1;
const initialDelay = (slides[0].time || 6) * 1000;
setTimeout(() => showSlide(idx), initialDelay);
}
// ─── Load Backdrops ───
async function loadBackdrops() {
try {
const response = await fetch("/api/backdrops.json");
const backdrops = await response.json();
const safeBackdrops = backdrops.filter((b) => !b.destructive);
const sections = document.querySelectorAll(".bg-image-section:not(#hero)");
const used = [];
sections.forEach((section) => {
let pick;
let safety = 0;
do {
pick = safeBackdrops[Math.floor(Math.random() * safeBackdrops.length)];
safety++;
} while (
used.includes(pick.name) &&
used.length < safeBackdrops.length &&
safety < 50
);
used.push(pick.name);
section.style.backgroundImage = `url('/assets/${pick.name}.png')`;
});
initParallax();
initHeroSlideshow(backdrops, used);
window.addEventListener("scroll", checkDestructiveTheme, { passive: true });
} catch (err) {
console.error("Failed to load backdrops:", err);
}
}
// ─── Load Team ───
async function loadTeam() {
try {
const response = await fetch("/api/team.json");
const team = await response.json();
team.sort((a, b) => a.priority - b.priority);
const container = document.getElementById("team-grid");
if (!container) return;
container.innerHTML = team
.map(
(member) => `
<div class="team-card">
${
member.icon
? `<img src="/assets/${member.icon}" alt="${member.name}" onerror="this.style.display='none'">`
: '<div style="width:100px;height:100px;border-radius:50%;background:#2a2e33;margin:0 auto 1.2rem;border:3px solid #2a2e33;"></div>'
}
<div class="name">${member.name}</div>
<div class="role">${member.role}</div>
</div>
`,
)
.join("");
} catch (err) {
console.error("Failed to load team:", err);
}
}
// ─── Load Posts ───
async function loadPosts() {
try {
const response = await fetch("/api/posts.json");
const posts = await response.json();
const container = document.getElementById("posts-grid");
if (!container) return;
container.innerHTML = posts
.map(
(post) => `
<a href="/post/${post.file}" class="post-card">
<div class="post-date">${post.date}</div>
<div class="post-title">${post.title}</div>
<div class="post-desc">${post.description}</div>
</a>
`,
)
.join("");
} catch (err) {
console.error("Failed to load posts:", err);
}
}
// ─── Video Play/Pause ───
function initVideo() {
const playBtn = document.getElementById("play-btn");
const video = document.getElementById("trailer-video");
const container = document.querySelector(".video-container");
if (!playBtn || !video || !container) return;
playBtn.addEventListener("click", () => {
if (video.paused) {
video.play();
container.classList.add("playing");
} else {
video.pause();
container.classList.remove("playing");
}
});
video.addEventListener("ended", () => {
container.classList.remove("playing");
});
}
// ─── Scroll Effects ───
function initScrollEffects() {
const header = document.querySelector("header");
const footer = document.querySelector("footer");
const scrollThreshold = 200;
function update() {
const scrollY = window.scrollY;
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
const nearBottom = scrollY + winHeight >= docHeight - 80;
const shortPage = docHeight <= winHeight + 100;
if (scrollY > 10) {
header.classList.add("scrolled");
} else {
header.classList.remove("scrolled");
}
if (scrollY < scrollThreshold && !shortPage) {
footer.classList.remove("visible");
} else {
footer.classList.add("visible");
if (nearBottom || shortPage) {
footer.classList.remove("glass");
footer.classList.add("solid");
} else {
footer.classList.add("glass");
footer.classList.remove("solid");
}
}
}
window.addEventListener("scroll", update, { passive: true });
update();
}
// ─── Initialize ───
document.addEventListener("DOMContentLoaded", () => {
loadBackdrops();
loadTeam();
loadPosts();
initVideo();
initScrollEffects();
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
website/assets/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

BIN
website/assets/campsite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
website/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

BIN
website/assets/morice.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
website/assets/ninivx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
website/assets/outpost.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

BIN
website/assets/trailer.mp4 Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

156
website/index.html Normal file
View file

@ -0,0 +1,156 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Anarchy Phase</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<header>
<nav>
<a href="/" class="logo">Anarchy Phase</a>
<ul class="nav-links">
<li><a href="#concept">Concept</a></li>
<li><a href="#socials">Social</a></li>
<li><a href="#team">Team</a></li>
<li><a href="#posts">Posts</a></li>
</ul>
</nav>
</header>
<main>
<section id="hero" class="bg-image-section">
<div class="slideshow-layer" id="hero-slideshow"></div>
<div class="destructive-tint" id="hero-tint"></div>
<div class="hero-content">
<h2>Join us on:</h2>
<p>Anarchyphase.net</p>
<p>Bedrock & Java</p>
</div>
</section>
<section id="concept">
<div class="content-wrapper">
<h2>Concept</h2>
<div class="video-container">
<video
id="trailer-video"
src="/assets/trailer.mp4"
preload="metadata"
></video>
<div class="play-btn" id="play-btn"></div>
</div>
<div class="concept-text">
<h3>THE CORE IDEA</h3>
<ol>
<li>
With just a few text commands, players can
easily claim chunks and invite others. These
claims will offer complete protection, except
for
</li>
<li>
The Anarchy Phase. Monday to Thursday from
20-21:00CET and Friday to Sunday from
19-21:00CET claims can be raided. Even during
this time, bases can't be easily deleted, as
TNT, fire, and mining are nerfed inside claims.
Destroying bases requires effort, just like
building them.
</li>
<li>
Even when a base is pillaged, there is no
incentive to wipe it off the map. TNT and fire
are nerfed all over the overworld, so ruins may
be repaired or become historic.
</li>
</ol>
<h3>IMMERSION</h3>
<ol>
<li>
There are no GUIs, official currency, or complex
systems. Only a few text commands for claim
</li>
<li>
Instead of global chat, there is now local text
chat and SimpleVoiceChat support. Death messages
are also only local.
</li>
<li>
The world is limited, and elytras are disabled
to encourage spontaneous meetings between
players and building of infrastructure.
</li>
<li>
PvP is kept simple, fun, and impactful by
turning off totems, maces, and crystals.
</li>
</ol>
</div>
</div>
</section>
<section id="socials" class="bg-image-section">
<div class="content-wrapper">
<h2>Socials</h2>
<a
href="https://www.youtube.com/@MoriceMC"
target="_blank"
rel="noopener"
class="social-btn"
>
<svg
class="social-icon"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
/>
</svg>
Youtube
</a>
<a
href="https://discord.com/invite/Bq4GhxDwU5"
target="_blank"
rel="noopener"
class="social-btn"
>
<svg
class="social-icon"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"
/>
</svg>
Discord
</a>
</div>
</section>
<section id="team">
<div class="content-wrapper">
<h2>Team</h2>
<div id="team-grid" class="team-grid"></div>
</div>
</section>
<section id="posts" class="bg-image-section">
<div class="content-wrapper">
<h2>Posts</h2>
<div id="posts-grid" class="posts-grid"></div>
</div>
</section>
</main>
<footer>
<p>Imprint ....</p>
</footer>
<script src="/app.js"></script>
</body>
</html>

115
website/md-render.js Normal file
View file

@ -0,0 +1,115 @@
// Basic Markdown renderer
function renderMarkdown(md) {
let html = md
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/^### (.*$)/gim, "<h3>$1</h3>")
.replace(/^## (.*$)/gim, "<h2>$1</h2>")
.replace(/^# (.*$)/gim, "<h1>$1</h1>")
.replace(/\*\*\*(.*?)\*\*\*/g, "<strong><em>$1</em></strong>")
.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
.replace(/\*(.*?)\*/g, "<em>$1</em>")
.replace(/___(.*?)___/g, "<strong><em>$1</em></strong>")
.replace(/__(.*?)__/g, "<strong>$1</strong>")
.replace(/_(.*?)_/g, "<em>$1</em>")
.replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>")
.replace(/`([^`]+)`/g, "<code>$1</code>")
.replace(/^> (.*$)/gim, "<blockquote>$1</blockquote>")
.replace(/^\s*-\s+(.*$)/gim, "<li>$1</li>")
.replace(/^\s*\d+\.\s+(.*$)/gim, "<li>$1</li>")
.replace(
/\[([^\]]+)\]\(([^)]+)\)/g,
'<a href="$2" target="_blank" rel="noopener">$1</a>',
)
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">')
.replace(/^---$/gim, "<hr>")
.replace(/\n/g, "<br>");
html = html.replace(/(<li>.*?<\/li>(?:<br><li>.*?<\/li>)*)/gs, (match) => {
const clean = match.replace(/<br>/g, "");
return `<ul>${clean}</ul>`;
});
return html;
}
// Parallax for post hero
function initPostParallax() {
const hero = document.getElementById("post-hero");
if (!hero) return;
function update() {
const rect = hero.getBoundingClientRect();
const yPos = -(rect.top * 0.4);
hero.style.backgroundPositionY = `${yPos}px`;
}
window.addEventListener("scroll", update, { passive: true });
update();
}
// Load post hero image from posts.json head_img, fallback to random backdrop
async function loadPostHero(filename) {
try {
// Try to find the post metadata
const response = await fetch("/api/posts.json");
const posts = await response.json();
const post = posts.find((p) => p.file === filename);
const hero = document.getElementById("post-hero");
if (!hero) return;
if (post && post.head_img) {
hero.style.backgroundImage = `url('/assets/${post.head_img}')`;
} else {
// Fallback to random backdrop
const bdResponse = await fetch("/api/backdrops.json");
const backdrops = await response.json();
const random = backdrops[Math.floor(Math.random() * backdrops.length)];
hero.style.backgroundImage = `url('/assets/${random.name}.png')`;
}
initPostParallax();
} catch (err) {
console.error("Failed to load post hero:", err);
}
}
// Load post content
async function loadPostContent() {
const pathParts = window.location.pathname.split("/");
const filename = pathParts[pathParts.length - 1];
if (!filename) return;
loadPostHero(filename);
try {
const response = await fetch(`/api/post/${filename}`);
const md = await response.text();
let contentMd = md;
const titleMatch = md.match(/^#\s+(.+)$/m);
if (titleMatch) {
document.title = `${titleMatch[1]} - Anarchy Phase`;
const titleEl = document.getElementById("post-title");
if (titleEl) titleEl.textContent = titleMatch[1];
contentMd = md.replace(/^#\s+.+$/m, "").trim();
}
const container = document.getElementById("post-body");
if (container) {
container.innerHTML = renderMarkdown(contentMd);
}
} catch (err) {
console.error("Failed to load post:", err);
const container = document.getElementById("post-body");
if (container)
container.innerHTML =
'<p style="color:#d48a8a;">Failed to load post content.</p>';
}
}
document.addEventListener("DOMContentLoaded", () => {
loadPostContent();
});

41
website/post.html Normal file
View file

@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Post - Anarchy Phase</title>
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<header>
<nav>
<a href="/" class="logo">Anarchy Phase</a>
<ul class="nav-links">
<li><a href="/#concept">Concept</a></li>
<li><a href="/#socials">Social</a></li>
<li><a href="/#team">Team</a></li>
<li><a href="/#posts">Posts</a></li>
</ul>
</nav>
</header>
<main>
<section id="post-hero" class="bg-image-section">
<h1 id="post-title">Loading...</h1>
</section>
<section id="post-content">
<div id="post-body" class="post-content">
<p>Loading post content...</p>
</div>
</section>
</main>
<footer>
<p>Imprint ....</p>
</footer>
<script src="/app.js"></script>
<script src="/md-render.js"></script>
</body>
</html>

View file

@ -0,0 +1,7 @@
# This is a cool post!
Look at this text..
# somt
a

777
website/style.css Normal file
View file

@ -0,0 +1,777 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
/* ─── Theme Variables ─── */
:root {
--bg-body: #0a0c0e;
--bg-header: #14171a;
--bg-footer: #14171a;
--bg-solid: linear-gradient(180deg, #181a1d 0%, #14171a 100%);
--bg-card: linear-gradient(145deg, #1c1e21, #181a1d);
--bg-content: linear-gradient(145deg, #1a1d20, #14171a);
--bg-postcard: rgba(20, 23, 26, 0.92);
--border-base: #252a2e;
--border-hover: #3a424a;
--text-muted: #8a9eaa;
--text-dim: #6e7a80;
--accent: #5a7d8c;
--accent-light: #7ab8d4;
--accent-border: #4a5560;
--tint-color: rgba(90, 125, 140, 0.15);
--transition-theme:
background-color 0.8s ease, border-color 0.8s ease, color 0.8s ease;
}
body.destructive-mode {
--bg-body: #0e0a0a;
--bg-header: #1a1414;
--bg-footer: #1a1414;
--bg-solid: linear-gradient(180deg, #1d1818 0%, #1a1414 100%);
--bg-card: linear-gradient(145deg, #211c1c, #1d1818);
--bg-content: linear-gradient(145deg, #201a1a, #1a1414);
--bg-postcard: rgba(26, 20, 20, 0.92);
--border-base: #2e2525;
--border-hover: #4a3a3a;
--text-muted: #9a8a8a;
--text-dim: #806e6e;
--accent: #8c5a5a;
--accent-light: #d47a7a;
--accent-border: #604a4a;
--tint-color: rgba(160, 60, 60, 0.25);
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg-body);
color: #d0d0d0;
line-height: 1.6;
overflow-x: hidden;
transition: background-color 0.8s ease;
}
/* ─── Header ─── */
header {
position: fixed;
top: 0;
left: 0;
right: 0;
background: var(--bg-header);
border-bottom: 1px solid #1f2428;
z-index: 1000;
padding: 0 2rem;
transition:
background 0.4s ease,
backdrop-filter 0.4s ease,
border-color 0.4s ease,
box-shadow 0.4s ease,
background-color 0.8s ease;
}
header.scrolled {
background: rgba(20, 23, 26, 0.65);
backdrop-filter: blur(20px) saturate(1.4);
-webkit-backdrop-filter: blur(20px) saturate(1.4);
border-bottom-color: rgba(255, 255, 255, 0.06);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
body.destructive-mode header.scrolled {
background: rgba(26, 20, 20, 0.65);
}
nav {
display: flex;
align-items: center;
justify-content: space-between;
height: 60px;
width: 100%;
margin: 0 auto;
}
.logo {
font-size: 1.5rem;
font-weight: bold;
color: #fff;
text-decoration: none;
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}
.nav-links a {
color: #aaa;
text-decoration: none;
transition: color 0.3s;
cursor: pointer;
}
.nav-links a:hover {
color: #fff;
}
/* ─── Layout ─── */
main {
padding-top: 60px;
padding-bottom: 50px;
min-height: 100vh;
}
section {
padding: 4rem 2rem;
width: 100%;
position: relative;
}
/* ─── Backdrop Image Sections ─── */
.bg-image-section {
padding: 10rem 2rem;
min-height: 600px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
position: relative;
overflow: hidden;
}
.bg-image-section::before,
.bg-image-section::after {
content: "";
position: absolute;
left: 0;
right: 0;
height: 60px;
pointer-events: none;
z-index: 1;
}
.bg-image-section::before {
top: 0;
background: linear-gradient(
to bottom,
var(--bg-header) 0%,
transparent 100%
);
}
.bg-image-section::after {
bottom: 0;
background: linear-gradient(to top, var(--bg-header) 0%, transparent 100%);
}
#hero::before {
height: 100px;
}
.slideshow-layer {
position: absolute;
inset: 0;
background-size: cover;
background-position: center;
transition: opacity 1.2s ease-in-out;
z-index: 0;
}
.destructive-tint {
position: absolute;
inset: 0;
background: radial-gradient(
ellipse at center,
var(--tint-color),
transparent 70%
);
opacity: 0;
transition: opacity 1.2s ease;
z-index: 1;
pointer-events: none;
}
body.destructive-mode .destructive-tint {
opacity: 1;
}
/* ─── Solid Sections ─── */
section:not(.bg-image-section) {
background: var(--bg-solid);
position: relative;
padding: 6rem 2rem;
transition: background 0.8s ease;
}
.content-wrapper {
width: 100%;
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 2;
}
/* ─── Hero ─── */
#hero {
min-height: 700px;
}
.hero-content {
position: relative;
z-index: 2;
text-align: center;
}
#hero h2 {
font-size: 3.2rem;
margin-bottom: 1.2rem;
text-shadow: 0 3px 15px rgba(0, 0, 0, 0.9);
color: #fff;
}
#hero p {
font-size: 1.4rem;
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.9);
color: #e0e0e0;
margin: 0.3rem 0;
}
/* ─── Concept ─── */
#concept h2 {
text-align: center;
font-size: 2.2rem;
margin-bottom: 3rem;
color: #fff;
}
.video-container {
position: relative;
width: 100%;
max-width: 1000px;
margin: 0 auto 3rem;
background: #0a0c0e;
border-radius: 16px;
overflow: hidden;
aspect-ratio: 16/9;
border: 1px solid var(--border-base);
transition: border-color 0.8s ease;
}
.video-container video {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
background: rgba(255, 255, 255, 0.12);
border: 3px solid rgba(255, 255, 255, 0.9);
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s;
backdrop-filter: blur(6px);
z-index: 3;
}
.play-btn:hover {
background: rgba(255, 255, 255, 0.25);
transform: translate(-50%, -50%) scale(1.08);
}
.play-btn::after {
content: "";
width: 0;
height: 0;
border-left: 30px solid #fff;
border-top: 18px solid transparent;
border-bottom: 18px solid transparent;
margin-left: 8px;
}
.video-container.playing .play-btn {
opacity: 0;
pointer-events: none;
}
.video-container.playing:hover .play-btn {
opacity: 1;
pointer-events: auto;
}
.video-container.playing .play-btn::after {
border: none;
width: 30px;
height: 36px;
margin-left: 0;
background: linear-gradient(
to right,
#fff 35%,
transparent 35%,
transparent 65%,
#fff 65%
);
}
.concept-text {
max-width: 900px;
margin: 0 auto;
font-size: 1.1rem;
line-height: 1.9;
color: #bbb;
}
.concept-text h3 {
color: var(--accent-light);
font-size: 1.4rem;
margin-top: 2.5rem;
margin-bottom: 1rem;
border-left: 4px solid var(--accent);
padding-left: 1rem;
transition: var(--transition-theme);
}
.concept-text ol {
margin-left: 1.5rem;
margin-bottom: 1.5rem;
}
.concept-text li {
margin-bottom: 0.9rem;
padding-left: 0.5rem;
}
/* ─── Socials ─── */
#socials h2 {
text-align: center;
font-size: 2.2rem;
margin-bottom: 3rem;
text-shadow: 0 3px 15px rgba(0, 0, 0, 0.9);
color: #fff;
}
.social-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.8rem;
width: 260px;
margin: 1.5rem auto;
padding: 1.2rem 2rem;
background: rgba(10, 12, 14, 0.75);
border: 1px solid #2f333a;
border-radius: 12px;
color: #fff;
text-decoration: none;
text-align: center;
font-size: 1.15rem;
transition: all 0.3s;
backdrop-filter: blur(10px);
}
.social-btn:hover {
background: rgba(20, 23, 26, 0.9);
transform: translateY(-4px);
border-color: var(--accent-border);
}
.social-icon {
width: 24px;
height: 24px;
flex-shrink: 0;
opacity: 0.9;
}
/* ─── Team ─── */
#team h2 {
text-align: center;
font-size: 2.2rem;
margin-bottom: 3rem;
color: #fff;
}
.team-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 2rem;
margin-top: 2rem;
}
.team-card {
background: var(--bg-card);
border-radius: 16px;
padding: 2.5rem 1.5rem;
text-align: center;
border: 1px solid var(--border-base);
transition:
transform 0.3s,
border-color 0.8s ease,
background 0.8s ease;
}
.team-card:hover {
transform: translateY(-6px);
border-color: var(--border-hover);
}
.team-card img {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
margin-bottom: 1.2rem;
background: #2a2e33;
border: 3px solid #2a2e33;
transition: border-color 0.8s ease;
}
.team-card:hover img {
border-color: var(--accent-border);
}
.team-card .name {
font-size: 1.3rem;
font-weight: bold;
margin-bottom: 0.5rem;
color: #fff;
}
.team-card .role {
color: var(--text-muted);
transition: color 0.8s ease;
}
/* ─── Posts ─── */
#posts h2 {
text-align: center;
font-size: 2.2rem;
margin-bottom: 3rem;
text-shadow: 0 3px 15px rgba(0, 0, 0, 0.9);
color: #fff;
}
.posts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 2rem;
margin-top: 2rem;
}
.post-card {
background: var(--bg-postcard);
border-radius: 16px;
padding: 2.2rem;
border: 1px solid var(--border-base);
cursor: pointer;
transition: all 0.3s;
text-decoration: none;
color: inherit;
display: block;
backdrop-filter: blur(10px);
}
.post-card:hover {
transform: translateY(-6px);
border-color: var(--border-hover);
background: rgba(24, 27, 30, 0.95);
}
body.destructive-mode .post-card:hover {
background: rgba(30, 24, 24, 0.95);
}
.post-card .post-date {
color: var(--text-dim);
font-size: 0.9rem;
margin-bottom: 0.8rem;
}
.post-card .post-title {
font-size: 1.4rem;
font-weight: bold;
margin-bottom: 0.8rem;
color: #fff;
}
.post-card .post-desc {
color: #aaa;
line-height: 1.6;
}
/* ─── Post Page ─── */
#post-hero {
min-height: 450px;
display: flex;
align-items: center;
justify-content: center;
padding: 8rem 2rem;
}
#post-hero h1 {
font-size: 3rem;
text-shadow: 0 3px 20px rgba(0, 0, 0, 0.95);
text-align: center;
position: relative;
z-index: 2;
color: #fff;
}
#post-content {
padding: 5rem 2rem;
min-height: calc(100vh - 450px - 60px - 50px);
display: flex;
align-items: flex-start;
justify-content: center;
}
/* ─── Markdown Viewer Theme ─── */
.post-content {
width: 100%;
max-width: 900px;
margin: 0 auto;
background: var(--bg-content);
border: 1px solid var(--border-base);
border-radius: 20px;
padding: 3.5rem;
line-height: 1.9;
font-size: 1.1rem;
color: #ccc;
position: relative;
z-index: 2;
transition:
background 0.8s ease,
border-color 0.8s ease;
}
.post-content h1 {
color: #fff;
font-size: 2.4rem;
border-bottom: 3px solid var(--accent);
padding-bottom: 0.8rem;
margin-bottom: 2.5rem;
margin-top: 0;
transition: var(--transition-theme);
}
.post-content h2 {
color: var(--accent);
font-size: 1.8rem;
margin-top: 3rem;
margin-bottom: 1.2rem;
border-left: 5px solid var(--accent);
padding-left: 1.2rem;
transition: var(--transition-theme);
}
.post-content h3 {
color: var(--accent-light);
font-size: 1.5rem;
margin-top: 2.5rem;
margin-bottom: 1rem;
transition: var(--transition-theme);
}
.post-content p {
margin-bottom: 1.4rem;
}
.post-content a {
color: #66aaff;
text-decoration: none;
border-bottom: 1px dotted #66aaff;
transition: all 0.2s;
}
.post-content a:hover {
color: #99ccff;
border-bottom-style: solid;
}
.post-content code {
background: #0f1214;
color: #d48a8a;
padding: 0.25rem 0.6rem;
border-radius: 6px;
font-family: "Fira Code", "Courier New", monospace;
font-size: 0.9em;
border: 1px solid #1f2428;
}
.post-content pre {
background: #0f1214;
border: 1px solid #1f2428;
border-radius: 12px;
padding: 1.8rem;
overflow-x: auto;
margin: 2rem 0;
}
.post-content pre code {
background: transparent;
color: #ddd;
padding: 0;
border: none;
font-size: 0.95em;
}
.post-content blockquote {
border-left: 4px solid var(--accent);
background: #1a1d20;
padding: 1.5rem 1.8rem;
margin: 2rem 0;
border-radius: 0 12px 12px 0;
font-style: italic;
color: #bbb;
transition: var(--transition-theme);
}
body.destructive-mode .post-content blockquote {
background: #201a1a;
}
.post-content ul,
.post-content ol {
margin: 1.5rem 0;
padding-left: 2.5rem;
}
.post-content li {
margin-bottom: 0.7rem;
}
.post-content img {
max-width: 100%;
border-radius: 12px;
border: 1px solid var(--border-base);
margin: 2rem 0;
display: block;
transition: border-color 0.8s ease;
}
.post-content hr {
border: none;
border-top: 2px solid var(--border-base);
margin: 3rem 0;
transition: border-color 0.8s ease;
}
.post-content table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
}
.post-content th,
.post-content td {
border: 1px solid var(--border-base);
padding: 0.8rem;
text-align: left;
transition: border-color 0.8s ease;
}
.post-content th {
background: #1c1e21;
color: #fff;
}
body.destructive-mode .post-content th {
background: #211c1c;
}
.post-content tr:nth-child(even) {
background: #181a1d;
}
body.destructive-mode .post-content tr:nth-child(even) {
background: #1d1818;
}
/* ─── Footer ─── */
footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--bg-footer);
border-top: 1px solid #1f2428;
padding: 1rem 2rem;
text-align: center;
color: #5a6b72;
z-index: 1000;
font-size: 0.9rem;
transform: translateY(100%);
transition:
transform 0.4s ease,
background 0.4s ease,
backdrop-filter 0.4s ease,
border-color 0.4s ease,
box-shadow 0.4s ease,
background-color 0.8s ease;
}
footer.visible {
transform: translateY(0);
}
footer.glass {
background: rgba(20, 23, 26, 0.65);
backdrop-filter: blur(20px) saturate(1.4);
-webkit-backdrop-filter: blur(20px) saturate(1.4);
border-top-color: rgba(255, 255, 255, 0.06);
box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.4);
}
body.destructive-mode footer.glass {
background: rgba(26, 20, 20, 0.65);
}
footer.solid {
background: var(--bg-footer);
backdrop-filter: none;
border-top-color: #1f2428;
box-shadow: none;
}
footer a {
color: #7a8e9a;
text-decoration: none;
}
footer a:hover {
color: #fff;
}
/* ─── Scrollbar ─── */
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #0a0c0e;
}
::-webkit-scrollbar-thumb {
background: #2a2e33;
border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
background: #3a424a;
}