add rickroll

This commit is contained in:
Semyon 2026-08-10 18:01:10 +03:00
parent 13a67bbf8d
commit d07dbeb61f
6 changed files with 1350 additions and 407 deletions

View file

@ -1,73 +1,206 @@
<header class="border-b border-[var(--border)]"> <header class="relative z-50 border-b border-[var(--border)]">
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-5 lg:px-8"> <div
class="mx-auto flex h-16 max-w-7xl items-center justify-between px-6 lg:px-8"
>
<!-- Logo -->
<a <a
href="/" href="/"
class="font-mono text-sm font-bold tracking-tight" class="group flex items-center gap-3 font-mono text-sm font-bold tracking-tight"
> >
SEMYON<span class="text-[var(--accent)]">.</span>DEV <span
</a> class="flex h-7 w-7 items-center justify-center border border-[var(--border)] text-[10px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
<nav class="hidden items-center gap-7 font-mono text-[11px] md:flex">
<a
href="/projects"
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
> >
WORK >
</span>
```
<span>
ALASTOR<span class="text-[var(--accent)]">.</span>LOL
</span>
</a>
<!-- Desktop navigation -->
<nav class="hidden items-center md:flex">
<div class="flex items-center gap-1">
<a
href="/#projects"
class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
>
<span>PROJECTS</span>
<span
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
></span>
</a> </a>
<a <a
href="#lab" href="/#lab"
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]" class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
> >
LAB <span>LAB</span>
<span
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
></span>
</a> </a>
<a <a
href="/blog" href="/blog"
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]" class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
> >
BLOG <span>BLOG</span>
<span
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
></span>
</a> </a>
<a <a
href="#about" href="/#about"
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]" class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
> >
ABOUT <span>ABOUT</span>
<span
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
></span>
</a> </a>
</div>
<span class="h-4 w-px bg-[var(--border)]"></span> <div class="mx-4 h-5 w-px bg-[var(--border)]"></div>
<!-- TODO: заменить # на реальную ссылку DonationAlerts --> <div class="flex items-center gap-2">
<a <a
href="https://www.donationalerts.com/r/alastor3301" href="https://www.donationalerts.com/r/alastor3301"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="text-[var(--accent)] transition-opacity hover:opacity-70" class="group flex items-center gap-2 border border-[var(--border)] px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--accent)] transition-all duration-200 hover:border-[var(--accent)] hover:bg-[var(--accent)] hover:text-black"
> >
SUPPORT ↗ <span>SUPPORT</span>
<span
class="transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5"
>
↗
</span>
</a> </a>
<!-- TODO: заменить # на GitHub -->
<a <a
href="https://github.com/Trytonottry" href="https://github.com/Trytonottry"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]" aria-label="GitHub"
class="group flex h-8 w-8 items-center justify-center border border-[var(--border)] font-mono text-[10px] text-[var(--muted)] transition-colors hover:border-[var(--text)] hover:text-[var(--text)]"
> >
GITHUB ↗ <span class="transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5">
↗
</span>
</a>
</div>
</nav>
<!-- Mobile menu button -->
<button
id="mobile-menu-button"
type="button"
class="flex items-center gap-3 border border-[var(--border)] px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:border-[var(--text)] hover:text-[var(--text)] md:hidden"
aria-expanded="false"
aria-controls="mobile-menu"
>
<span id="mobile-menu-label">MENU</span>
<span class="flex flex-col gap-1">
<span
id="menu-line-1"
class="block h-px w-3 bg-current transition-transform duration-200"
></span>
<span
id="menu-line-2"
class="block h-px w-3 bg-current transition-transform duration-200"
></span>
</span>
</button>
</div>
<!-- Mobile navigation -->
<div
id="mobile-menu"
class="hidden border-t border-[var(--border)] bg-[var(--bg)] md:hidden"
>
<nav class="mx-auto max-w-7xl px-6 py-4 lg:px-8">
<div class="grid border border-[var(--border)]">
<a
href="/#projects"
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
>
01 / PROJECTS
</a> </a>
</nav> <a
href="/#lab"
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
>
02 / LAB
</a>
<button <a
class="font-mono text-xs text-[var(--muted)] md:hidden" href="/blog"
aria-label="Open menu" class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
> >
MENU 03 / BLOG
</button> </a>
<a
href="/#about"
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
>
04 / ABOUT
</a>
<div class="grid grid-cols-2">
<a
href="https://www.donationalerts.com/r/alastor3301"
target="_blank"
rel="noopener noreferrer"
class="border-r border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--accent)] transition-colors hover:bg-[var(--accent)] hover:text-black"
>
SUPPORT ↗
</a>
<a
href="https://github.com/Trytonottry"
target="_blank"
rel="noopener noreferrer"
class="px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
>
GITHUB ↗
</a>
</div>
</div>
</nav>
</div>
```
</div>
</header> </header>
<script>
const button = document.querySelector("#mobile-menu-button");
const menu = document.querySelector("#mobile-menu");
const label = document.querySelector("#mobile-menu-label");
const line1 = document.querySelector("#menu-line-1");
const line2 = document.querySelector("#menu-line-2");
button?.addEventListener("click", () => {
const isOpen = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", String(!isOpen));
menu?.classList.toggle("hidden", isOpen);
if (label) {
label.textContent = isOpen ? "MENU" : "CLOSE";
}
if (!isOpen) {
line1?.classList.add("translate-y-[3px]", "rotate-45");
line2?.classList.add("-translate-y-[3px]", "-rotate-45");
} else {
line1?.classList.remove("translate-y-[3px]", "rotate-45");
line2?.classList.remove("-translate-y-[3px]", "-rotate-45");
}
});
</script>

View file

@ -1,81 +1,130 @@
<section class="relative overflow-hidden"> <div
class="relative overflow-hidden border-b border-[var(--border)]"
>
<!-- Background grid -->
<div <div
class="mx-auto grid min-h-[calc(100vh-73px)] max-w-7xl gap-16 px-6 py-20 lg:grid-cols-[minmax(0,1fr)_380px] lg:px-8 lg:py-24" class="pointer-events-none absolute inset-0 opacity-40"
style="
background-image:
linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px);
background-size: 48px 48px;
mask-image: linear-gradient(to bottom, black, transparent);
"
></div>
<!-- Accent glow -->
<div
class="pointer-events-none absolute -right-40 -top-40 h-[500px] w-[500px] rounded-full bg-[var(--accent)] opacity-[0.035] blur-3xl"
></div>
<div
class="relative mx-auto grid max-w-7xl gap-16 px-6 py-24 lg:grid-cols-[minmax(0,1fr)_360px] lg:px-8 lg:py-36"
> >
<!-- LEFT -->
<div class="flex flex-col justify-center"> <div class="flex flex-col justify-center">
<!-- Status -->
<div class="mb-8 flex items-center gap-3 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]"> <div
class="mb-8 flex items-center gap-3 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]"
>
<span class="relative flex h-2 w-2"> <span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent)] opacity-40"></span> <span
<span class="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent)]"></span> class="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent)] opacity-50"
></span>
<span
class="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent)]"
></span>
</span> </span>
SYSTEM ONLINE SYSTEM ONLINE
<span class="text-[var(--border)]">/</span>
<span>ALASTOR.LOL</span>
</div> </div>
<div class="mb-6 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]"> <!-- Main title -->
SYSTEMS / AUTOMATION / INFRASTRUCTURE
</div>
<h1 <h1
class="max-w-5xl text-[4rem] font-bold leading-[0.88] tracking-[-0.065em] sm:text-[5.5rem] lg:text-[7.5rem]" class="max-w-5xl text-5xl font-black uppercase leading-[0.88] tracking-[-0.065em] sm:text-7xl lg:text-[6.8rem]"
> >
BUILD. <span class="block">BUILD.</span>
<br />
BREAK. <span class="block text-[var(--muted)]">
<br /> BREAK.
<span class="text-[var(--accent)]">UNDERSTAND.</span> </span>
<br />
REPEAT. <span class="block">
<span class="text-[var(--accent)]">
UNDERSTAND.
</span>
</span>
<span class="block">REPEAT.</span>
</h1> </h1>
<div class="mt-10 flex flex-col gap-8 sm:flex-row sm:items-end sm:justify-between"> <!-- Description -->
<p
<p class="max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg"> class="mt-10 max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg"
Systems administrator and infrastructure engineer. >
I build infrastructure, automate systems and investigate Systems administrator and infrastructure engineer.
things when they inevitably break. I build infrastructure, automate systems and investigate
</p> things when they inevitably break.
</p>
<div class="hidden font-mono text-right text-[10px] leading-5 text-[var(--muted)] sm:block">
<div>ALASTOR.LOL</div>
<div>SYS / 001</div>
</div>
</div>
<!-- Actions -->
<div class="mt-10 flex flex-wrap gap-3"> <div class="mt-10 flex flex-wrap gap-3">
<a <a
href="#projects" href="#projects"
class="group border border-[var(--text)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider transition-all duration-200 hover:bg-[var(--text)] hover:text-black" class="group relative overflow-hidden border border-[var(--text)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider transition-colors duration-200 hover:bg-[var(--text)] hover:text-black"
> >
<span>View projects</span> <span class="relative z-10">
<span class="ml-3 transition-transform duration-200 group-hover:translate-x-1"> VIEW PROJECTS
</span>
<span
class="ml-2 inline-block transition-transform duration-200 group-hover:translate-x-1"
>
→ →
</span> </span>
</a> </a>
<a <a
href="/blog" href="/blog"
class="border border-[var(--border)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider text-[var(--muted)] transition-all duration-200 hover:border-[var(--text)] hover:text-[var(--text)]" class="group border border-[var(--border)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider text-[var(--muted)] transition-colors duration-200 hover:border-[var(--text)] hover:text-[var(--text)]"
> >
Read blog → READ BLOG
</a>
<span
class="ml-2 inline-block transition-transform duration-200 group-hover:translate-x-1"
>
→
</span>
</a>
</div> </div>
<!-- Small metadata -->
<div
class="mt-14 flex flex-wrap gap-x-6 gap-y-2 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"
>
<span>LINUX</span>
<span>NETWORKING</span>
<span>AUTOMATION</span>
<span>HOMELAB</span>
</div>
</div> </div>
<!-- RIGHT -->
<div class="flex items-end"> <div class="flex items-end">
<div
<div class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs"> class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs shadow-2xl shadow-black/20"
>
<div class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3"> <!-- Terminal header -->
<div
class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3"
>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="h-1.5 w-1.5 rounded-full bg-[var(--accent)]"></span> <span class="h-2 w-2 rounded-full bg-[var(--accent)]"></span>
<span class="text-[var(--muted)]"> <span class="text-[var(--muted)]">
SYSTEM STATUS SYSTEM STATUS
@ -85,102 +134,108 @@
<span class="text-[var(--accent)]"> <span class="text-[var(--accent)]">
OPERATIONAL OPERATIONAL
</span> </span>
</div> </div>
<div class="p-5"> <div class="p-5">
<!-- Terminal prompt -->
<div class="mb-6 text-[10px] uppercase tracking-[0.2em] text-[var(--muted)]"> <div class="mb-7 text-[var(--muted)]">
CAPABILITIES <span class="text-[var(--accent)]">$</span>
&nbsp; ./check-system.sh
</div> </div>
<div class="space-y-4"> <!-- Systems -->
<div class="space-y-5">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-[var(--muted)]">Linux</span> <span class="text-[var(--muted)]">
<span class="text-[var(--accent)]">●</span> Linux
</span>
<span class="text-[var(--accent)]">
● OK
</span>
</div> </div>
<div class="h-px bg-[var(--border)]"></div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-[var(--muted)]">Infrastructure</span> <span class="text-[var(--muted)]">
<span class="text-[var(--accent)]">●</span> Infrastructure
</span>
<span class="text-[var(--accent)]">
● OK
</span>
</div> </div>
<div class="h-px bg-[var(--border)]"></div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-[var(--muted)]">Networking</span> <span class="text-[var(--muted)]">
<span class="text-[var(--accent)]">●</span> Networking
</span>
<span class="text-[var(--accent)]">
● OK
</span>
</div> </div>
<div class="h-px bg-[var(--border)]"></div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-[var(--muted)]">Automation</span> <span class="text-[var(--muted)]">
<span class="text-[var(--accent)]">●</span> Automation
</div> </span>
<span class="text-[var(--accent)]">
● OK
</span>
</div>
</div> </div>
<div class="mt-8 border-t border-[var(--border)] pt-6"> <!-- Homelab -->
<div class="mt-8 border-t border-[var(--border)] pt-5">
<div class="mb-3 flex items-center justify-between"> <div class="mb-3 flex items-center justify-between">
<span class="text-[var(--muted)]">HOMELAB</span> <span class="text-[var(--muted)]">
<span class="text-[var(--accent)]">87%</span> HOMELAB
</span>
<span class="text-[var(--accent)]">
87%
</span>
</div> </div>
<div class="h-1 bg-[var(--border)]"> <div class="h-1 overflow-hidden bg-[var(--border)]">
<div class="h-full w-[87%] bg-[var(--accent)]"></div> <div
class="h-full w-[87%] bg-[var(--accent)]"
></div>
</div> </div>
</div> </div>
<div class="mt-8 grid grid-cols-2 gap-4 border-t border-[var(--border)] pt-6"> <!-- Footer -->
<div
<div> class="mt-7 border-t border-[var(--border)] pt-5 text-[10px] text-[var(--muted)]"
<div class="text-[10px] text-[var(--muted)]">HOSTS</div> >
<div class="mt-2 text-xl">06</div>
</div>
<div>
<div class="text-[10px] text-[var(--muted)]">SERVICES</div>
<div class="mt-2 text-xl">30+</div>
</div>
</div>
<div class="mt-8 border-t border-[var(--border)] pt-5 text-[10px] text-[var(--muted)]">
<div class="flex justify-between"> <div class="flex justify-between">
<span>UPTIME</span> <span>HOSTS</span>
<span class="text-[var(--text)]">99.9%</span> <span>06</span>
</div> </div>
<div class="mt-2 flex justify-between"> <div class="mt-2 flex justify-between">
<span>STATUS</span> <span>SERVICES</span>
<span class="text-[var(--accent)]">BUILDING</span> <span>30+</span>
</div> </div>
<div class="mt-2 flex justify-between">
<span>UPTIME</span>
<span class="text-[var(--accent)]">
99.9%
</span>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mx-auto hidden max-w-7xl px-6 pb-6 lg:block lg:px-8"> <!-- Bottom coordinate -->
<div
<div class="flex items-center justify-between font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]"> class="pointer-events-none absolute bottom-5 left-1/2 hidden -translate-x-1/2 font-mono text-[9px] uppercase tracking-[0.3em] text-[var(--muted)] opacity-50 md:block"
<span>SCROLL TO EXPLORE</span> >
<span>ALASTOR.LOL / 2026</span> SCROLL TO EXPLORE
</div>
</div> </div>
</div>
</section>

View file

@ -1,166 +1,273 @@
<div class="border-y border-[var(--border)]"> <div class="border-y border-[var(--border)]">
<div class="mx-auto max-w-7xl px-6 lg:px-8"> <div class="mx-auto max-w-7xl px-6 lg:px-8">
<div class="flex items-center justify-between border-b border-[var(--border)] py-4"> ```
<div class="font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]"> <!-- Header -->
<div class="flex items-center justify-between border-b border-[var(--border)] py-4">
<div class="flex items-center gap-3">
<span class="font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
01 / NOW 01 / NOW
</span>
<span class="hidden h-px w-8 bg-[var(--border)] sm:block"></span>
<span class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--muted)] sm:block">
LIVE ACTIVITY
</span>
</div>
<div
id="now-status"
class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"
>
<span
id="status-dot"
class="h-1.5 w-1.5 rounded-full bg-[var(--muted)]"
></span>
<span id="status-text">SYNCING</span>
</div>
</div>
<!-- Activity grid -->
<div class="grid md:grid-cols-4">
<!-- Current state -->
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:pr-8">
<div class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
CURRENT STATE
</div> </div>
<div <div class="mt-4 flex items-start gap-3">
id="now-status" <span class="mt-2 h-1 w-1 shrink-0 bg-[var(--accent)]"></span>
class="flex items-center gap-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]"
>
<span
id="status-dot"
class="h-1.5 w-1.5 rounded-full bg-[var(--muted)]"
></span>
<span id="status-text">SYNCING</span> <div>
<div class="text-sm leading-6">
Building things,
<br />
breaking things,
<br />
understanding why.
</div>
<div class="mt-4 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
ALASTOR.LOL
</div>
</div>
</div> </div>
</div> </div>
<div class="grid divide-y divide-[var(--border)] md:grid-cols-4 md:divide-x md:divide-y-0"> <!-- Spotify -->
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:border-l md:px-8">
<div class="py-7 md:pr-8"> <div class="flex items-center justify-between">
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]"> <div class="flex items-center gap-2">
CURRENT STATE <span class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
</div>
<div class="mt-3 text-sm leading-relaxed">
Building things,<br />
break fixing things.
</div>
</div>
<div class="py-7 md:px-8">
<div class="flex items-center justify-between">
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
♪ LISTENING ♪ LISTENING
</div> </span>
<div <span
id="spotify-indicator" id="spotify-indicator"
class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--accent)]" class="hidden font-mono text-[8px] uppercase tracking-widest text-[var(--accent)]"
> >
LIVE LIVE
</div> </span>
</div> </div>
<a <span class="font-mono text-[8px] text-[var(--muted)]">
id="spotify-link" 01
href="#" </span>
target="_blank"
rel="noopener noreferrer"
class="mt-3 block text-sm font-medium transition-colors hover:text-[var(--accent)]"
>
<span id="spotify-title">Loading...</span>
</a>
<div
id="spotify-artist"
class="mt-1 text-xs text-[var(--muted)]"
>
Spotify
</div>
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
SPOTIFY
</div>
</div> </div>
<div class="py-7 md:px-8"> <a
<div class="flex items-center justify-between"> id="spotify-link"
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]"> href="#"
PLAYING target="_blank"
</div> rel="noopener noreferrer"
class="group mt-5 block"
>
<div class="flex items-start gap-3">
<div <div
id="steam-indicator" class="mt-1 flex h-8 w-8 shrink-0 items-center justify-center border border-[var(--border)] text-[11px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--accent)]"
> >
LIVE ♪
</div>
<div class="min-w-0">
<div
id="spotify-title"
class="truncate text-sm font-medium transition-colors group-hover:text-[var(--accent)]"
>
Loading...
</div>
<div
id="spotify-artist"
class="mt-1 truncate text-xs text-[var(--muted)]"
>
Spotify
</div>
</div> </div>
</div> </div>
</a>
<a <div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
id="steam-link" <span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
href="#" SPOTIFY
target="_blank" </span>
rel="noopener noreferrer"
class="mt-3 block text-sm font-medium transition-colors hover:text-[var(--accent)]"
>
<span id="steam-game">Loading...</span>
</a>
<div class="mt-1 text-xs text-[var(--muted)]"> <span class="font-mono text-[8px] text-[var(--muted)]">
Steam 30s
</span>
</div>
</div>
<!-- Steam -->
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:border-l md:px-8">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<span class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
PLAYING
</span>
<span
id="steam-indicator"
class="hidden font-mono text-[8px] uppercase tracking-widest text-[var(--accent)]"
>
LIVE
</span>
</div> </div>
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"> <span class="font-mono text-[8px] text-[var(--muted)]">
STEAM 02
</div> </span>
</div> </div>
<div class="py-7 md:pl-8"> <a
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]"> id="steam-link"
href="#"
target="_blank"
rel="noopener noreferrer"
class="group mt-5 block"
>
<div class="flex items-start gap-3">
<div
class="mt-1 flex h-8 w-8 shrink-0 items-center justify-center border border-[var(--border)] text-[10px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
>
▶
</div>
<div class="min-w-0">
<div
id="steam-game"
class="truncate text-sm font-medium transition-colors group-hover:text-[var(--accent)]"
>
Loading...
</div>
<div class="mt-1 truncate text-xs text-[var(--muted)]">
Steam
</div>
</div>
</div>
</a>
<div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
<span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
STEAM
</span>
<span class="font-mono text-[8px] text-[var(--muted)]">
60s
</span>
</div>
</div>
<!-- Building -->
<div class="py-7 md:border-l md:pl-8">
<div class="flex items-center justify-between">
<div class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
BUILDING BUILDING
</div> </div>
<div class="mt-3 text-sm font-medium"> <span class="font-mono text-[8px] text-[var(--muted)]">
alastor.lol 03
</div> </span>
</div>
<div class="mt-1 text-xs text-[var(--muted)]"> <div class="mt-5">
This website <div class="flex items-center gap-3">
</div> <div class="relative flex h-8 w-8 items-center justify-center border border-[var(--border)]">
<span class="h-1.5 w-1.5 bg-[var(--accent)]"></span>
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"> <span class="absolute inset-1 border border-[var(--border)]"></span>
ASTRO · TYPESCRIPT </div>
<div>
<div class="text-sm font-medium">
alastor.lol
</div>
<div class="mt-1 text-xs text-[var(--muted)]">
This website
</div>
</div>
</div> </div>
</div> </div>
<div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
<span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
ASTRO · TS
</span>
<span class="font-mono text-[8px] text-[var(--accent)]">
ACTIVE
</span>
</div>
</div>
</div>
<!-- Bottom telemetry -->
<div class="flex flex-col gap-2 border-t border-[var(--border)] py-3 font-mono text-[8px] uppercase tracking-widest text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between">
<div class="flex items-center gap-3">
<span>ACTIVITY FEED</span>
<span class="h-px w-6 bg-[var(--border)]"></span>
<span id="last-update">WAITING FOR SYNC</span>
</div> </div>
<div>
SPOTIFY / STEAM / LOCAL
</div>
</div> </div>
</div> </div>
```
</div>
<script> <script>
const spotifyTitle = const spotifyTitle = document.querySelector("#spotify-title");
document.querySelector("#spotify-title"); const spotifyArtist = document.querySelector("#spotify-artist");
const spotifyArtist =
document.querySelector("#spotify-artist");
const spotifyLink = const spotifyLink =
document.querySelector("#spotify-link") as HTMLAnchorElement | null; document.querySelector("#spotify-link") as HTMLAnchorElement | null;
const spotifyIndicator = document.querySelector("#spotify-indicator");
const spotifyIndicator = const steamGame = document.querySelector("#steam-game");
document.querySelector("#spotify-indicator");
const steamGame =
document.querySelector("#steam-game");
const steamLink = const steamLink =
document.querySelector("#steam-link") as HTMLAnchorElement | null; document.querySelector("#steam-link") as HTMLAnchorElement | null;
const steamIndicator = document.querySelector("#steam-indicator");
const steamIndicator = const statusText = document.querySelector("#status-text");
document.querySelector("#steam-indicator"); const statusDot = document.querySelector("#status-dot");
const lastUpdate = document.querySelector("#last-update");
const statusText =
document.querySelector("#status-text");
const statusDot =
document.querySelector("#status-dot");
function updateOverallStatus() { function updateOverallStatus() {
const spotifyLive = const spotifyLive =
spotifyIndicator?.classList.contains("inline"); spotifyIndicator?.classList.contains("inline");
const steamLive = const steamLive =
steamIndicator?.classList.contains("inline"); steamIndicator?.classList.contains("inline");
if (spotifyLive || steamLive) { if (spotifyLive || steamLive) {
statusText!.textContent = "LIVE"; statusText!.textContent = "LIVE";
statusDot!.classList.remove("bg-[var(--muted)]"); statusDot!.classList.remove("bg-[var(--muted)]");
statusDot!.classList.add( statusDot!.classList.add(
"bg-[var(--accent)]", "bg-[var(--accent)]",
@ -168,6 +275,7 @@
); );
} else { } else {
statusText!.textContent = "IDLE"; statusText!.textContent = "IDLE";
statusDot!.classList.remove( statusDot!.classList.remove(
"bg-[var(--accent)]", "bg-[var(--accent)]",
"animate-pulse", "animate-pulse",
@ -176,6 +284,18 @@
} }
} }
function updateTimestamp() {
const now = new Date();
lastUpdate!.textContent =
"LAST SYNC " +
now.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
}
async function updateSpotify() { async function updateSpotify() {
try { try {
const response = await fetch("/api/spotify", { const response = await fetch("/api/spotify", {
@ -197,6 +317,7 @@
spotifyIndicator?.classList.add("hidden"); spotifyIndicator?.classList.add("hidden");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
return; return;
} }
@ -211,6 +332,7 @@
spotifyIndicator?.classList.add("inline"); spotifyIndicator?.classList.add("inline");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
} catch { } catch {
spotifyTitle!.textContent = "Unavailable"; spotifyTitle!.textContent = "Unavailable";
spotifyArtist!.textContent = "Spotify"; spotifyArtist!.textContent = "Spotify";
@ -220,6 +342,7 @@
spotifyIndicator?.classList.add("hidden"); spotifyIndicator?.classList.add("hidden");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
} }
} }
@ -243,6 +366,7 @@
steamIndicator?.classList.add("hidden"); steamIndicator?.classList.add("hidden");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
return; return;
} }
@ -256,6 +380,7 @@
steamIndicator?.classList.add("inline"); steamIndicator?.classList.add("inline");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
} catch { } catch {
steamGame!.textContent = "Unavailable"; steamGame!.textContent = "Unavailable";
steamLink?.removeAttribute("href"); steamLink?.removeAttribute("href");
@ -264,6 +389,7 @@
steamIndicator?.classList.add("hidden"); steamIndicator?.classList.add("hidden");
updateOverallStatus(); updateOverallStatus();
updateTimestamp();
} }
} }

View file

@ -1,4 +1,3 @@
--- ---
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
@ -11,83 +10,116 @@ const projects = await getCollection("projects", ({ data }) => {
id="projects" id="projects"
class="border-t border-[var(--border)]" class="border-t border-[var(--border)]"
> >
<div class="mx-auto max-w-7xl px-6 py-28 lg:px-8"> <div class="mx-auto max-w-7xl px-6 py-28 lg:px-8 lg:py-36">
<!-- Header --> <!-- Header -->
<div class="grid gap-10 lg:grid-cols-[1fr_360px] lg:items-end">
<div class="flex flex-col gap-8 md:flex-row md:items-end md:justify-between">
<div> <div>
<div class="font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]"> <div class="flex items-center gap-3 font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]">
02 / PROJECTS <span class="text-[var(--accent)]">02</span>
<span>/</span>
<span>PROJECTS</span>
</div> </div>
<h2 class="mt-6 text-4xl font-bold tracking-tight sm:text-6xl"> <h2 class="mt-6 max-w-3xl text-5xl font-bold leading-[0.95] tracking-[-0.045em] sm:text-6xl lg:text-7xl">
Things I build. Things I
<span class="text-[var(--muted)]"> build.</span>
</h2> </h2>
</div> </div>
<p class="max-w-md text-sm leading-7 text-[var(--muted)]"> <div class="lg:pb-1">
Infrastructure, automation, networking and experiments. <p class="text-sm leading-7 text-[var(--muted)]">
Some are production systems. Some are glorified Infrastructure, automation, networking and experiments.
learning exercises. Some are production systems. Some are glorified learning
</p> exercises.
</p>
</div>
</div> </div>
<!-- Projects --> <!-- Project grid -->
<div class="mt-20 grid gap-px border border-[var(--border)] bg-[var(--border)] md:grid-cols-2">
<div class="mt-16 border-t border-[var(--border)]">
{ {
projects.map((project, index) => ( projects.map((project, index) => (
<a <a
href={`/projects/${project.id}`} href={`/projects/${project.id}`}
class="group block border-b border-[var(--border)] transition-colors duration-200 hover:bg-[var(--surface)]" class="group relative min-h-[320px] overflow-hidden bg-[var(--bg)] transition-colors duration-300 hover:bg-[var(--surface)]"
> >
<div class="grid gap-6 px-0 py-8 md:grid-cols-[64px_minmax(0,1fr)_220px_110px] md:items-center"> <!-- Background number -->
<div
<!-- Number --> class="pointer-events-none absolute -right-3 -top-8 select-none font-mono text-[9rem] font-bold leading-none tracking-[-0.08em] text-[var(--surface-hover)] transition-colors duration-300 group-hover:text-[var(--border)]"
>
<div class="font-mono text-[10px] text-[var(--muted)]"> {String(index + 1).padStart(2, "0")}
{String(index + 1).padStart(2, "0")} </div>
</div>
<!-- Project --> <div class="relative flex h-full flex-col justify-between p-7 sm:p-9">
<div class="min-w-0"> <!-- Top -->
<div>
<div class="flex items-center gap-3"> <div class="flex items-center justify-between">
<h3 class="truncate text-2xl font-semibold tracking-tight transition-colors duration-200 group-hover:text-[var(--accent)]"> <div class="font-mono text-[10px] tracking-[0.2em] text-[var(--muted)]">
{project.data.title} PROJECT {String(index + 1).padStart(2, "0")}
</h3> </div>
<span class="font-mono text-xs text-[var(--muted)] transition-transform duration-200 group-hover:translate-x-1"> <div class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-[0.15em]">
→
</span> <span
class:list={[
"h-1.5 w-1.5 rounded-full",
project.data.status === "RUNNING"
? "bg-[var(--accent)]"
: "bg-[var(--muted)]",
]}
></span>
<span
class:list={[
project.data.status === "RUNNING"
? "text-[var(--accent)]"
: "text-[var(--muted)]",
]}
>
{project.data.status}
</span>
</div>
</div> </div>
<p class="mt-3 max-w-2xl text-sm leading-6 text-[var(--muted)]">
{project.data.description} <!-- Title -->
</p> <div class="mt-12 max-w-xl">
<h3 class="text-3xl font-semibold leading-tight tracking-[-0.025em] transition-colors duration-200 group-hover:text-[var(--accent)] sm:text-4xl">
{project.data.title}
</h3>
<p class="mt-5 max-w-lg text-sm leading-7 text-[var(--muted)]">
{project.data.description}
</p>
</div>
</div> </div>
<!-- Stack + status --> <!-- Bottom -->
<div class="mt-12">
<div class="flex flex-col gap-3">
<div class="flex flex-wrap gap-1.5"> <div class="flex flex-wrap gap-1.5">
{ {
project.data.stack.map((item) => ( project.data.stack.map((item) => (
<span class="border border-[var(--border)] px-2 py-1 font-mono text-[9px] uppercase tracking-wider text-[var(--muted)]"> <span
class="border border-[var(--border)] px-2.5 py-1.5 font-mono text-[9px] uppercase tracking-wider text-[var(--muted)] transition-colors duration-200 group-hover:border-[var(--muted)] group-hover:text-[var(--text)]"
>
{item} {item}
</span> </span>
)) ))
@ -95,42 +127,21 @@ const projects = await getCollection("projects", ({ data }) => {
</div> </div>
<div class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-widest">
<span <div class="mt-7 flex items-center justify-between border-t border-[var(--border)] pt-4">
class:list={[
"h-1.5 w-1.5 rounded-full",
project.data.status === "RUNNING"
? "bg-[var(--accent)]"
: "bg-[var(--muted)]",
]}
></span>
<span <span class="font-mono text-[9px] uppercase tracking-[0.18em] text-[var(--muted)]">
class:list={[ EXPLORE PROJECT
project.data.status === "RUNNING" </span>
? "text-[var(--accent)]"
: "text-[var(--muted)]", <span class="font-mono text-sm text-[var(--muted)] transition-all duration-200 group-hover:translate-x-1 group-hover:text-[var(--accent)]">
]} →
>
{project.data.status}
</span> </span>
</div> </div>
</div> </div>
<!-- View -->
<div class="hidden text-right font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] md:block">
<span class="transition-colors group-hover:text-[var(--text)]">
VIEW →
</span>
</div>
</div> </div>
</a> </a>
@ -141,18 +152,22 @@ const projects = await getCollection("projects", ({ data }) => {
<!-- Footer --> <!-- Footer -->
<div class="mt-7 flex flex-col gap-4 font-mono text-[10px] uppercase tracking-[0.18em] text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between">
<div class="mt-8 flex flex-col gap-4 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between"> <div class="flex items-center gap-3">
<span class="h-1.5 w-1.5 rounded-full bg-[var(--accent)]"></span>
<span> <span>{projects.length} PROJECTS</span>
{projects.length} PROJECTS </div>
</span>
<a <a
href="/projects" href="/projects"
class="transition-colors hover:text-[var(--accent)]" class="group flex items-center gap-2 transition-colors hover:text-[var(--accent)]"
> >
VIEW ALL PROJECTS → VIEW ALL PROJECTS
<span class="transition-transform duration-200 group-hover:translate-x-1">
→
</span>
</a> </a>
</div> </div>
@ -161,3 +176,5 @@ const projects = await getCollection("projects", ({ data }) => {
</section> </section>

88
src/pages/rickroll.astro Normal file
View file

@ -0,0 +1,88 @@
---
import Layout from "../layouts/Layout.astro";
---
<Layout>
<main
class="relative flex min-h-screen items-center justify-center overflow-hidden bg-black px-6"
>
<div
class="absolute inset-0 opacity-20"
style="
background-image:
linear-gradient(rgba(184,255,0,.08) 1px, transparent 1px),
linear-gradient(90deg, rgba(184,255,0,.08) 1px, transparent 1px);
background-size: 40px 40px;
"
></div>
<div class="relative z-10 w-full max-w-5xl">
<div
class="overflow-hidden border border-[var(--border)] bg-[var(--surface)]"
>
<div
class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3 font-mono text-[10px] uppercase tracking-widest"
>
<span class="text-[var(--muted)]">
SECURITY INCIDENT
</span>
<span class="flex items-center gap-2 text-[var(--accent)]">
<span class="h-1.5 w-1.5 animate-pulse rounded-full bg-[var(--accent)]"></span>
CRITICAL
</span>
</div>
<div class="p-6 sm:p-10 lg:p-14">
<div
class="mb-8 font-mono text-[10px] uppercase tracking-[0.3em] text-[var(--muted)]"
>
ERR / 0x1337 / ALASTOR.LOL
</div>
<h1
class="max-w-4xl text-5xl font-black uppercase leading-[0.9] tracking-[-0.06em] sm:text-7xl lg:text-8xl"
>
Внимание!
<br />
<span class="text-[var(--accent)]">
Вас зарикроллили!
</span>
</h1>
<div class="mt-10 aspect-video w-full overflow-hidden border border-[var(--border)] bg-black">
<iframe
class="h-full w-full"
src="https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0"
title="Never Gonna Give You Up"
frameborder="0"
allow="autoplay; encrypted-media"
allowfullscreen
></iframe>
</div>
<div
class="mt-8 flex flex-col gap-4 border-t border-[var(--border)] pt-6 font-mono text-xs text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between"
>
<span>
STATUS: YOU SHOULD HAVE KNOWN BETTER
</span>
<a
href="/"
class="text-[var(--text)] transition-colors hover:text-[var(--accent)]"
>
← RETURN TO SAFETY
</a>
</div>
</div>
</div>
<div
class="mt-4 text-center font-mono text-[9px] uppercase tracking-[0.25em] text-[var(--muted)]"
>
No systems were harmed during this incident.
</div>
</div>
</main>
</Layout>

View file

@ -1,119 +1,643 @@
@import "tailwindcss"; @import "tailwindcss";
:root { :root {
--bg: #090909; --bg: #090909;
--surface: #0e0e0e; --surface: #0e0e0e;
--surface-hover: #131313; --surface-hover: #131313;
--text: #e7e7e7; --text: #e7e7e7;
--muted: #777; --muted: #777;
--border: #242424; --border: #242424;
--accent: #b8ff00; --accent: #b8ff00;
} }
html { html {
background: var(--bg); background: var(--bg);
color: var(--text); color: var(--text);
scroll-behavior: smooth; scroll-behavior: smooth;
} }
body { body {
margin: 0; margin: 0;
min-width: 320px; min-width: 320px;
background: background: var(--bg);
linear-gradient(
rgba(255, 255, 255, 0.012) 1px,
transparent 1px
),
linear-gradient(
90deg,
rgba(255, 255, 255, 0.012) 1px,
transparent 1px
),
var(--bg);
background-size: 48px 48px; font-family:
Inter,
font-family: ui-sans-serif,
Inter, system-ui,
ui-sans-serif, -apple-system,
system-ui, BlinkMacSystemFont,
-apple-system, "Segoe UI",
BlinkMacSystemFont, sans-serif;
"Segoe UI",
sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
} }
::selection { ::selection {
background: var(--accent); background: var(--accent);
color: #000; color: #000;
} }
a { a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
}
button,
a {
-webkit-tap-highlight-color: transparent;
}
:focus-visible {
outline: 1px solid var(--accent);
outline-offset: 4px;
} }
.font-mono { .font-mono {
font-family: font-family:
"JetBrains Mono", "JetBrains Mono",
"SFMono-Regular", "SFMono-Regular",
Consolas, Consolas,
"Liberation Mono", "Liberation Mono",
monospace; monospace;
} }
/* Scrollbar */
::-webkit-scrollbar { /* ─────────────────────────────────────────
width: 8px; Markdown / Article typography
───────────────────────────────────────── */
.prose {
max-width: 760px;
color: var(--text);
font-size: 0.95rem;
line-height: 1.85;
} }
::-webkit-scrollbar-track { .prose > *:first-child {
background: var(--bg); margin-top: 0;
} }
::-webkit-scrollbar-thumb { .prose > *:last-child {
background: #292929; margin-bottom: 0;
} }
::-webkit-scrollbar-thumb:hover {
background: #3a3a3a; /* Headings */
.prose h1 {
margin-top: 3rem;
margin-bottom: 1.25rem;
font-size: 2.25rem;
line-height: 1.15;
font-weight: 700;
letter-spacing: -0.035em;
} }
/* Firefox */ .prose h2 {
margin-top: 3rem;
margin-bottom: 1rem;
* { font-size: 1.65rem;
scrollbar-width: thin; line-height: 1.25;
scrollbar-color: #292929 var(--bg); font-weight: 650;
letter-spacing: -0.025em;
} }
/* Motion */ .prose h3 {
margin-top: 2.25rem;
margin-bottom: 0.75rem;
@media (prefers-reduced-motion: reduce) { font-size: 1.2rem;
html { line-height: 1.35;
scroll-behavior: auto; font-weight: 600;
} }
*, .prose h4 {
*::before, margin-top: 1.75rem;
*::after { margin-bottom: 0.5rem;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important; font-size: 1rem;
transition-duration: 0.01ms !important; font-weight: 600;
} }
/* Paragraphs */
.prose p {
margin-top: 1.25rem;
margin-bottom: 1.25rem;
}
/* Links */
.prose a {
color: var(--accent);
text-decoration: underline;
text-decoration-color: color-mix(
in srgb,
var(--accent) 40%,
transparent
);
text-underline-offset: 3px;
transition:
color 150ms ease,
text-decoration-color 150ms ease;
}
.prose a:hover {
color: var(--text);
text-decoration-color: var(--text);
}
/* Lists */
.prose ul,
.prose ol {
margin-top: 1.25rem;
margin-bottom: 1.25rem;
padding-left: 1.5rem;
}
.prose ul {
list-style-type: disc;
}
.prose ol {
list-style-type: decimal;
}
.prose li {
margin-top: 0.45rem;
padding-left: 0.25rem;
}
.prose li::marker {
color: var(--accent);
}
.prose li > ul,
.prose li > ol {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
/* Blockquotes */
.prose blockquote {
margin: 2rem 0;
padding: 0.75rem 0 0.75rem 1.25rem;
border-left: 2px solid var(--accent);
color: var(--muted);
font-style: italic;
}
.prose blockquote p {
margin: 0;
}
/* Inline code */
.prose :not(pre) > code {
padding: 0.15rem 0.4rem;
border: 1px solid var(--border);
background: var(--surface);
color: var(--accent);
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
monospace;
font-size: 0.82em;
}
/* Code blocks */
.prose pre {
position: relative;
margin: 2rem 0;
padding: 1.25rem 1.5rem;
overflow-x: auto;
border: 1px solid var(--border);
background: #070707;
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
monospace;
font-size: 0.8rem;
line-height: 1.7;
scrollbar-width: thin;
}
.prose pre code {
padding: 0;
border: 0;
background: transparent;
color: var(--text);
font-size: inherit;
}
/* Horizontal rule */
.prose hr {
margin: 3rem 0;
border: 0;
border-top: 1px solid var(--border);
}
/* Images */
.prose img {
display: block;
width: 100%;
height: auto;
margin: 2rem 0;
border: 1px solid var(--border);
}
/* Tables */
.prose table {
width: 100%;
margin: 2rem 0;
border-collapse: collapse;
font-size: 0.85rem;
}
.prose th,
.prose td {
padding: 0.75rem 1rem;
border: 1px solid var(--border);
text-align: left;
}
.prose th {
background: var(--surface);
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
monospace;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.prose td {
color: var(--muted);
}
/* Strong / emphasis */
.prose strong {
color: var(--text);
font-weight: 650;
}
.prose em {
color: var(--muted);
}
/* Definition-style spacing */
.prose dl {
margin: 1.5rem 0;
}
.prose dt {
margin-top: 1rem;
font-weight: 600;
}
.prose dd {
margin-left: 1.5rem;
color: var(--muted);
}
/* Mobile */
@media (max-width: 640px) {
.prose {
font-size: 0.9rem;
line-height: 1.8;
}
.prose h1 {
font-size: 1.9rem;
}
.prose h2 {
font-size: 1.4rem;
}
.prose h3 {
font-size: 1.1rem;
}
.prose pre {
margin-left: -0.5rem;
margin-right: -0.5rem;
padding: 1rem;
}
.prose table {
display: block;
overflow-x: auto;
}
}
/* ─────────────────────────────────────────────
Markdown / Article typography
───────────────────────────────────────────── */
.markdown {
max-width: none;
color: var(--text);
font-size: 0.95rem;
line-height: 1.8;
}
.markdown > *:first-child {
margin-top: 0;
}
.markdown > *:last-child {
margin-bottom: 0;
}
/* Headings */
.markdown h1,
.markdown h2,
.markdown h3,
.markdown h4 {
color: var(--text);
font-weight: 700;
letter-spacing: -0.025em;
line-height: 1.2;
}
.markdown h1 {
margin-top: 3rem;
margin-bottom: 1.25rem;
font-size: 2.25rem;
}
.markdown h2 {
margin-top: 3rem;
margin-bottom: 1rem;
padding-bottom: 0.65rem;
border-bottom: 1px solid var(--border);
font-size: 1.65rem;
}
.markdown h3 {
margin-top: 2.25rem;
margin-bottom: 0.75rem;
font-size: 1.25rem;
}
.markdown h4 {
margin-top: 1.75rem;
margin-bottom: 0.65rem;
font-size: 1rem;
}
/* Paragraphs */
.markdown p {
margin: 1.15rem 0;
color: #c4c4c4;
}
/* Strong / emphasis */
.markdown strong {
color: var(--text);
font-weight: 650;
}
.markdown em {
color: #d0d0d0;
}
/* Links */
.markdown a {
color: var(--accent);
text-decoration: underline;
text-decoration-color: color-mix(
in srgb,
var(--accent) 35%,
transparent
);
text-underline-offset: 3px;
transition:
text-decoration-color 150ms ease,
opacity 150ms ease;
}
.markdown a:hover {
text-decoration-color: var(--accent);
}
/* Lists */
.markdown ul,
.markdown ol {
margin: 1.25rem 0;
padding-left: 1.5rem;
color: #c4c4c4;
}
.markdown ul {
list-style-type: disc;
}
.markdown ol {
list-style-type: decimal;
}
.markdown li {
margin: 0.45rem 0;
padding-left: 0.25rem;
}
.markdown li::marker {
color: var(--muted);
}
.markdown li > ul,
.markdown li > ol {
margin-top: 0.45rem;
margin-bottom: 0.45rem;
}
/* Inline code */
.markdown :not(pre) > code {
border: 1px solid var(--border);
background: var(--surface);
padding: 0.15rem 0.4rem;
color: var(--accent);
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
"Liberation Mono",
monospace;
font-size: 0.82em;
}
/* Code blocks */
.markdown pre {
position: relative;
overflow-x: auto;
margin: 1.75rem 0;
border: 1px solid var(--border);
background: #050505;
padding: 1.25rem 1.35rem;
color: #d8d8d8;
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
"Liberation Mono",
monospace;
font-size: 0.8rem;
line-height: 1.7;
}
.markdown pre code {
font-family: inherit;
font-size: inherit;
}
/* Blockquotes */
.markdown blockquote {
margin: 1.75rem 0;
border-left: 2px solid var(--accent);
background: var(--surface);
padding: 1rem 1.25rem;
color: #bdbdbd;
}
.markdown blockquote p {
margin: 0;
}
/* Horizontal rule */
.markdown hr {
margin: 3rem 0;
border: 0;
border-top: 1px solid var(--border);
}
/* Tables */
.markdown table {
width: 100%;
margin: 1.75rem 0;
border-collapse: collapse;
font-size: 0.85rem;
}
.markdown thead {
background: var(--surface);
}
.markdown th,
.markdown td {
border: 1px solid var(--border);
padding: 0.7rem 0.8rem;
text-align: left;
}
.markdown th {
color: var(--text);
font-family:
"JetBrains Mono",
"SFMono-Regular",
Consolas,
monospace;
font-size: 0.7rem;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.markdown td {
color: #bdbdbd;
}
/* Images */
.markdown img {
display: block;
max-width: 100%;
height: auto;
margin: 2rem auto;
border: 1px solid var(--border);
}
/* Small screens */
@media (max-width: 640px) {
.markdown {
font-size: 0.9rem;
}
.markdown h1 {
font-size: 1.8rem;
}
.markdown h2 {
font-size: 1.4rem;
}
.markdown pre {
margin-left: -1rem;
margin-right: -1rem;
border-left: 0;
border-right: 0;
padding: 1rem;
border-radius: 0;
}
.markdown table {
display: block;
overflow-x: auto;
}
} }