- Replace the flat dither backdrop with a lit, rotating torus drawn the way donut.c does it: a z-buffer per cell and a luminance ramp from a dot to a solid block, sized against the shorter viewport axis. The dither field stays underneath as dust. It leads on the landing page and fades back where there is reading to do, and a scrim keeps the projects heading legible over it. - Thicken the glass: one .surface treatment with a heavier blur, more transparency and an SVG film grain, shared by the header, hero, cards, panels and footer. - Give the landing page labelled contact cards for LinkedIn, Gitea and email in place of three bare icons. - Drop the status chips from project cards and entry headers. - Remove the light theme, its toggle and theme.js outright. - Add restrained motion: underlines growing from the left on links and nav items, a lift on cards, buttons and contact cards, and tags brightening with their card. All of it is off under prefers-reduced-motion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
718 lines
14 KiB
CSS
Executable File
718 lines
14 KiB
CSS
Executable File
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap");
|
|
|
|
:root {
|
|
--theme: #0b0c0f;
|
|
--surface: rgba(20, 22, 27, 0.34);
|
|
--surface-raised: rgba(28, 31, 38, 0.46);
|
|
--bar: rgba(255, 255, 255, 0.04);
|
|
--primary: #ccd0d9;
|
|
--bright: #f2f4f8;
|
|
--secondary: #eb5234;
|
|
--accent: #ff005a;
|
|
--muted: #7d8492;
|
|
--border: rgba(255, 255, 255, 0.1);
|
|
--border-strong: rgba(255, 255, 255, 0.2);
|
|
--glow: rgba(235, 82, 52, 0.16);
|
|
--shadow: 0 20px 54px rgba(0, 0, 0, 0.4);
|
|
--selection: rgba(235, 82, 52, 0.3);
|
|
--ascii-base: #99a2b4;
|
|
--ascii-accent: #eb5234;
|
|
--ascii-dim: #5f6675;
|
|
--radius: 7px;
|
|
--ease: cubic-bezier(0.2, 0.7, 0.3, 1);
|
|
--mono:
|
|
"JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo,
|
|
Consolas, "Liberation Mono", monospace;
|
|
|
|
/* Fine film grain that sits on every frosted surface. */
|
|
--grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
::selection {
|
|
background: var(--selection);
|
|
color: var(--bright);
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: var(--mono);
|
|
font-size: 15px;
|
|
line-height: 1.65;
|
|
font-variant-ligatures: none;
|
|
color: var(--primary);
|
|
background-color: var(--theme);
|
|
word-break: break-word;
|
|
min-height: 100vh;
|
|
position: relative;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* Soft light behind the ASCII field, so the page has depth without gloss. */
|
|
body::before {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 0;
|
|
pointer-events: none;
|
|
background:
|
|
radial-gradient(circle at 18% 12%, var(--glow), transparent 42%),
|
|
radial-gradient(circle at 82% 8%, rgba(255, 0, 90, 0.07), transparent 38%),
|
|
radial-gradient(
|
|
circle at 50% 95%,
|
|
rgba(255, 255, 255, 0.035),
|
|
transparent 46%
|
|
);
|
|
filter: blur(28px);
|
|
}
|
|
|
|
#ascii-bg {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 0;
|
|
pointer-events: none;
|
|
opacity: 0.15;
|
|
}
|
|
|
|
body[data-page="home"] #ascii-bg {
|
|
opacity: 0.34;
|
|
}
|
|
|
|
header,
|
|
main,
|
|
.page-shell {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* ------------------------------------------------------- frosted surfaces */
|
|
|
|
.surface {
|
|
position: relative;
|
|
isolation: isolate;
|
|
background: var(--surface);
|
|
backdrop-filter: blur(26px) saturate(150%);
|
|
-webkit-backdrop-filter: blur(26px) saturate(150%);
|
|
border: 1px solid var(--border);
|
|
box-shadow:
|
|
var(--shadow),
|
|
inset 0 1px 0 rgba(255, 255, 255, 0.07);
|
|
}
|
|
|
|
.surface::after {
|
|
content: "";
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: -1;
|
|
border-radius: inherit;
|
|
pointer-events: none;
|
|
background-image: var(--grain);
|
|
background-size: 180px 180px;
|
|
opacity: 0.22;
|
|
mix-blend-mode: soft-light;
|
|
}
|
|
|
|
a,
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
p,
|
|
li,
|
|
dd,
|
|
dt {
|
|
color: var(--primary);
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4 {
|
|
font-weight: 700;
|
|
letter-spacing: -0.015em;
|
|
color: var(--bright);
|
|
}
|
|
|
|
a {
|
|
color: var(--primary);
|
|
text-decoration: none;
|
|
transition:
|
|
color 0.2s var(--ease),
|
|
background-color 0.2s var(--ease),
|
|
border-color 0.2s var(--ease),
|
|
box-shadow 0.2s var(--ease),
|
|
transform 0.2s var(--ease);
|
|
}
|
|
|
|
a:hover {
|
|
cursor: pointer;
|
|
color: var(--secondary);
|
|
}
|
|
|
|
ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
code,
|
|
kbd,
|
|
samp,
|
|
pre {
|
|
font-family: var(--mono);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- header */
|
|
|
|
.header {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1000;
|
|
border: 0;
|
|
border-bottom: 1px solid var(--border);
|
|
box-shadow: none;
|
|
}
|
|
|
|
.nav {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
width: min(1120px, calc(100% - 32px));
|
|
margin: 0 auto;
|
|
min-height: 54px;
|
|
}
|
|
|
|
.logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.logo a {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 9px;
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
color: var(--bright);
|
|
}
|
|
|
|
.logo a::before {
|
|
content: "~/";
|
|
color: var(--secondary);
|
|
font-weight: 400;
|
|
}
|
|
|
|
.logo a img {
|
|
display: block;
|
|
pointer-events: none;
|
|
border-radius: 3px !important;
|
|
width: 22px;
|
|
height: 22px;
|
|
border: 1px solid var(--border);
|
|
transition: border-color 0.2s var(--ease);
|
|
}
|
|
|
|
.logo a:hover {
|
|
color: var(--secondary);
|
|
}
|
|
|
|
.logo a:hover img {
|
|
border-color: rgba(235, 82, 52, 0.5);
|
|
}
|
|
|
|
#menu {
|
|
display: flex;
|
|
align-items: center;
|
|
list-style: none;
|
|
gap: 24px;
|
|
white-space: nowrap;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
#menu a {
|
|
display: block;
|
|
position: relative;
|
|
font-size: 13.5px;
|
|
color: var(--muted);
|
|
padding: 2px 0;
|
|
}
|
|
|
|
/* Underline grows out from the left on hover. */
|
|
#menu a::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: 0;
|
|
height: 1px;
|
|
width: 100%;
|
|
background: var(--secondary);
|
|
transform: scaleX(0);
|
|
transform-origin: left;
|
|
transition: transform 0.24s var(--ease);
|
|
}
|
|
|
|
#menu a:hover {
|
|
color: var(--primary);
|
|
}
|
|
|
|
#menu a:hover::after {
|
|
transform: scaleX(1);
|
|
}
|
|
|
|
body[data-page="home"] #home-link a,
|
|
body[data-page="about"] #about-link a,
|
|
body[data-page="projects"] #projects-link a {
|
|
color: var(--bright);
|
|
}
|
|
|
|
body[data-page="home"] #home-link a::after,
|
|
body[data-page="about"] #about-link a::after,
|
|
body[data-page="projects"] #projects-link a::after {
|
|
transform: scaleX(1);
|
|
}
|
|
|
|
.menu.cta {
|
|
display: none;
|
|
margin: 0;
|
|
padding: 4px 10px;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
color: var(--muted);
|
|
background: var(--bar);
|
|
transition:
|
|
color 0.2s var(--ease),
|
|
border-color 0.2s var(--ease);
|
|
}
|
|
|
|
.menu.cta:hover {
|
|
color: var(--secondary);
|
|
border-color: var(--border-strong);
|
|
}
|
|
|
|
/* --------------------------------------------------------------- overlay */
|
|
|
|
.overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 2147483647;
|
|
isolation: isolate;
|
|
background: rgba(11, 12, 15, 0.84);
|
|
backdrop-filter: blur(20px) saturate(140%);
|
|
-webkit-backdrop-filter: blur(20px) saturate(140%);
|
|
overflow: hidden;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
pointer-events: none;
|
|
transition:
|
|
opacity 0.22s var(--ease),
|
|
visibility 0.22s var(--ease);
|
|
}
|
|
|
|
.overlay--active {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
pointer-events: auto;
|
|
}
|
|
|
|
.overlay__content {
|
|
position: relative;
|
|
z-index: 2;
|
|
display: flex;
|
|
min-height: 100%;
|
|
width: 100%;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 4px;
|
|
}
|
|
|
|
.overlay a {
|
|
color: var(--primary);
|
|
padding: 12px 20px;
|
|
font-size: 1.4rem;
|
|
display: block;
|
|
text-align: center;
|
|
width: min(300px, 80%);
|
|
}
|
|
|
|
.overlay a:hover,
|
|
.overlay a:focus {
|
|
color: var(--secondary);
|
|
}
|
|
|
|
.overlay .close {
|
|
position: absolute;
|
|
z-index: 3;
|
|
top: 14px;
|
|
right: 18px;
|
|
font-size: 28px;
|
|
line-height: 1;
|
|
font-family: var(--mono);
|
|
color: var(--muted);
|
|
cursor: pointer;
|
|
border: 0;
|
|
background: transparent;
|
|
padding: 0 8px;
|
|
transition: color 0.2s var(--ease);
|
|
}
|
|
|
|
.overlay .close:hover {
|
|
color: var(--secondary);
|
|
}
|
|
|
|
body.menu-open {
|
|
overflow: hidden;
|
|
}
|
|
|
|
body.menu-open main,
|
|
body.menu-open .page-shell,
|
|
body.menu-open .container,
|
|
body.menu-open .projects-page,
|
|
body.menu-open .entry-page,
|
|
body.menu-open .footer {
|
|
pointer-events: none;
|
|
}
|
|
|
|
body.menu-open .header,
|
|
body.menu-open .overlay,
|
|
body.menu-open .overlay * {
|
|
pointer-events: auto;
|
|
}
|
|
|
|
/* ------------------------------------------------------------ page shell */
|
|
|
|
.page-shell {
|
|
width: min(1120px, calc(100% - 32px));
|
|
margin: 0 auto;
|
|
padding-bottom: 36px;
|
|
}
|
|
|
|
/* ------------------------------------------------------- terminal window */
|
|
|
|
.main {
|
|
width: min(880px, calc(100% - 32px));
|
|
margin: 0 auto;
|
|
padding: 0 0 36px;
|
|
display: flex;
|
|
align-items: center;
|
|
min-height: calc(100vh - 54px);
|
|
}
|
|
|
|
.term {
|
|
width: 100%;
|
|
border-radius: var(--radius);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.term__bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
padding: 9px 14px;
|
|
background: var(--bar);
|
|
border-bottom: 1px solid var(--border);
|
|
font-size: 12px;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.term__dot {
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
background: var(--border-strong);
|
|
flex: none;
|
|
}
|
|
|
|
.term__dot:first-child {
|
|
background: rgba(235, 82, 52, 0.75);
|
|
}
|
|
|
|
.term__title {
|
|
margin-left: 8px;
|
|
}
|
|
|
|
.term__body {
|
|
display: grid;
|
|
grid-template-columns: auto 1fr;
|
|
gap: 30px;
|
|
padding: 32px 30px;
|
|
align-items: center;
|
|
}
|
|
|
|
.term__avatar {
|
|
width: 148px;
|
|
height: 148px;
|
|
object-fit: cover;
|
|
border-radius: var(--radius);
|
|
border: 1px solid var(--border-strong);
|
|
box-shadow:
|
|
var(--shadow),
|
|
0 0 0 6px rgba(235, 82, 52, 0.05);
|
|
}
|
|
|
|
.term__stream {
|
|
min-width: 0;
|
|
}
|
|
|
|
.cmd {
|
|
margin: 0 0 18px;
|
|
color: var(--muted);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.cmd::before {
|
|
content: "$ ";
|
|
color: var(--secondary);
|
|
}
|
|
|
|
.name {
|
|
font-size: clamp(1.7rem, 3.6vw, 2.4rem);
|
|
font-weight: 700;
|
|
margin: 0;
|
|
line-height: 1.15;
|
|
color: var(--bright);
|
|
}
|
|
|
|
.des {
|
|
margin: 10px 0 0;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.hero-description-secondary {
|
|
color: var(--muted);
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.hero-badges {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.badge {
|
|
border: 1px solid var(--border);
|
|
background: var(--bar);
|
|
color: var(--muted);
|
|
border-radius: var(--radius);
|
|
padding: 3px 10px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.hero-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
margin-top: 22px;
|
|
}
|
|
|
|
.button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--bar);
|
|
color: var(--primary);
|
|
padding: 8px 18px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.button:hover {
|
|
color: var(--bright);
|
|
border-color: var(--border-strong);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.button-primary {
|
|
border-color: rgba(235, 82, 52, 0.5);
|
|
color: var(--bright);
|
|
background: rgba(235, 82, 52, 0.14);
|
|
box-shadow: 0 6px 22px rgba(235, 82, 52, 0.14);
|
|
}
|
|
|
|
.button-primary:hover {
|
|
border-color: var(--secondary);
|
|
background: rgba(235, 82, 52, 0.22);
|
|
box-shadow: 0 10px 30px rgba(235, 82, 52, 0.26);
|
|
}
|
|
|
|
.caret {
|
|
display: inline-block;
|
|
width: 0.55em;
|
|
height: 1em;
|
|
vertical-align: -0.15em;
|
|
background: var(--secondary);
|
|
animation: caret-blink 1.1s steps(1, end) infinite;
|
|
}
|
|
|
|
@keyframes caret-blink {
|
|
0%,
|
|
49% {
|
|
opacity: 1;
|
|
}
|
|
50%,
|
|
100% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------- contact */
|
|
|
|
.social-icons {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
margin-top: 24px;
|
|
}
|
|
|
|
.social-icons a {
|
|
color: var(--muted);
|
|
display: inline-flex;
|
|
}
|
|
|
|
.social-icons a svg {
|
|
height: 16px;
|
|
width: 16px;
|
|
display: block;
|
|
}
|
|
|
|
.icon:hover {
|
|
color: var(--secondary);
|
|
}
|
|
|
|
/* The landing page gets labelled contact cards instead of bare icons. */
|
|
.hero-social {
|
|
gap: 12px;
|
|
flex-wrap: wrap;
|
|
margin-top: 28px;
|
|
}
|
|
|
|
.hero-social .social-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 10px 16px;
|
|
font-size: 13.5px;
|
|
color: var(--primary);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--bar);
|
|
}
|
|
|
|
.hero-social .social-link svg {
|
|
height: 18px;
|
|
width: 18px;
|
|
color: var(--muted);
|
|
transition:
|
|
color 0.2s var(--ease),
|
|
transform 0.2s var(--ease);
|
|
}
|
|
|
|
.hero-social .social-link:hover {
|
|
color: var(--bright);
|
|
border-color: rgba(235, 82, 52, 0.45);
|
|
background: rgba(235, 82, 52, 0.08);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 26px rgba(235, 82, 52, 0.16);
|
|
}
|
|
|
|
.hero-social .social-link:hover svg {
|
|
color: var(--secondary);
|
|
transform: scale(1.08);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- footer */
|
|
|
|
.footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 16px;
|
|
padding: 14px 18px;
|
|
border-radius: var(--radius);
|
|
font-size: 13px;
|
|
}
|
|
|
|
.footer p {
|
|
margin: 0;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.footer .social-icons {
|
|
margin-top: 0;
|
|
}
|
|
|
|
.footer .social-icons a:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.loading-state {
|
|
color: var(--muted);
|
|
}
|
|
|
|
/* ------------------------------------------------------------ responsive */
|
|
|
|
@media only screen and (max-width: 860px) {
|
|
#menu,
|
|
.term__avatar-wrap {
|
|
display: none;
|
|
}
|
|
|
|
.menu.cta {
|
|
display: block;
|
|
}
|
|
|
|
.main {
|
|
min-height: auto;
|
|
margin-top: 28px;
|
|
width: min(880px, calc(100% - 20px));
|
|
}
|
|
|
|
.term__body {
|
|
grid-template-columns: 1fr;
|
|
gap: 0;
|
|
padding: 26px 20px;
|
|
}
|
|
|
|
.page-shell {
|
|
width: min(1120px, calc(100% - 20px));
|
|
}
|
|
|
|
.hero-social .social-link {
|
|
padding: 9px 14px;
|
|
}
|
|
|
|
.footer {
|
|
display: block;
|
|
}
|
|
|
|
.footer .social-icons {
|
|
margin-top: 12px;
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.caret {
|
|
animation: none;
|
|
}
|
|
|
|
*,
|
|
*::after,
|
|
*::before {
|
|
transition: none !important;
|
|
transform: none !important;
|
|
}
|
|
}
|