feat: binary glow effects, refined drawings and calls to action

Dark surfaces now carry light: frames glow along their edge and shed binary
digits (BitAura), dark sections open with a lit seam (BitSeam), the career
path is a line of light and "My work" became a dark stage. Buttons carry a
travelling light and a spot that follows the pointer (BitGlow).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 13:07:09 +02:00
co-authored by Claude Opus 5.5
parent e9f05b02fc
commit e89a248ca5
21 changed files with 1532 additions and 606 deletions
+314 -21
View File
@@ -321,26 +321,6 @@
/* Additional global styles from BaseLayout */
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f5f9;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
transition: background 0.2s ease;
}
::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* Selection color */
::selection {
background: #0f172a;
@@ -1079,8 +1059,72 @@ pre:has(code[class*="language-"]) {
transform: translate(0, 0);
}
/* Light that follows the pointer on a `data-glow` surface (see BitGlow). */
.bit-glow {
position: absolute;
inset: 0;
border-radius: inherit;
pointer-events: none;
opacity: 0;
transition: opacity 400ms ease;
}
@media (hover: hover) {
[data-glow]:hover > .bit-glow {
opacity: 1;
}
}
/* Dark surfaces: the dot grid lights up around the pointer. */
.bit-glow-dots {
background-image:
radial-gradient(
320px circle at var(--gx, 50%) var(--gy, 50%),
rgba(148, 163, 184, 0.22),
transparent 70%
),
radial-gradient(#e2e8f0 1.25px, transparent 1.25px);
background-size:
auto,
20px 20px;
-webkit-mask-image: radial-gradient(
280px circle at var(--gx, 50%) var(--gy, 50%),
#000,
transparent 75%
);
mask-image: radial-gradient(
280px circle at var(--gx, 50%) var(--gy, 50%),
#000,
transparent 75%
);
}
/* Cards: only the border lights up, in the card's text colour. */
.bit-glow-edge {
inset: -1px;
padding: 2px;
background: radial-gradient(
320px circle at var(--gx, 50%) var(--gy, 50%),
currentColor,
transparent 70%
);
-webkit-mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask:
linear-gradient(#000 0 0) content-box exclude,
linear-gradient(#000 0 0);
}
/* Dark buttons: a spot of light under the pointer. */
.bit-glow-spot {
background: radial-gradient(
90px circle at var(--gx, 50%) var(--gy, 50%),
rgba(129, 140, 248, 0.5),
transparent 70%
);
}
@media (prefers-reduced-motion: reduce) {
.bit-burst {
.bit-burst,
.bit-glow {
display: none;
}
.bit-card::before,
@@ -1088,3 +1132,252 @@ pre:has(code[class*="language-"]) {
transition: none;
}
}
/*
* Calls to action: a light travels round the edge of the pill and glows softly
* behind it; on hover the glow comes up. `bit-cta-light` is for white pills on
* dark surfaces, `bit-cta-quiet` only lights up on hover.
*/
@property --cta-angle {
syntax: "<angle>";
inherits: false;
initial-value: 0deg;
}
.bit-cta {
--cta-a: rgba(129, 140, 248, 0.95);
--cta-b: #ffffff;
position: relative;
isolation: isolate;
}
.bit-cta-light {
--cta-a: rgba(99, 102, 241, 0.95);
--cta-b: #312e81;
}
.bit-cta-quiet {
--cta-a: rgba(99, 102, 241, 0.9);
--cta-b: #0f172a;
}
.bit-cta::before,
.bit-cta::after {
content: "";
position: absolute;
border-radius: inherit;
pointer-events: none;
background: conic-gradient(
from var(--cta-angle),
transparent 0 58%,
var(--cta-a) 76%,
var(--cta-b) 86%,
var(--cta-a) 93%,
transparent 100%
);
animation: bit-cta-turn 6s linear infinite;
}
/* The edge itself. */
.bit-cta::before {
inset: -1px;
padding: 1.5px;
-webkit-mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask:
linear-gradient(#000 0 0) content-box exclude,
linear-gradient(#000 0 0);
}
/* The glow behind the edge. */
.bit-cta::after {
inset: -2px;
z-index: -1;
padding: 6px;
-webkit-mask:
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask:
linear-gradient(#000 0 0) content-box exclude,
linear-gradient(#000 0 0);
filter: blur(10px);
opacity: 0.55;
transition: opacity 300ms ease;
}
.bit-cta-quiet::before,
.bit-cta-quiet::after {
opacity: 0;
transition: opacity 300ms ease;
}
@media (hover: hover) {
.bit-cta:hover::after,
.group:hover > .bit-cta::after {
opacity: 1;
}
.bit-cta-quiet:hover::before {
opacity: 1;
}
.bit-cta-quiet:hover::after {
opacity: 0.6;
}
}
@keyframes bit-cta-turn {
to {
--cta-angle: 360deg;
}
}
/* Slow light drifting over a dark picture (see PortraitSection). */
.bit-aurora {
position: absolute;
inset: -10%;
pointer-events: none;
mix-blend-mode: screen;
background:
radial-gradient(
38% 46% at 38% 42%,
rgba(99, 102, 241, 0.55),
transparent 70%
),
radial-gradient(
30% 40% at 64% 72%,
rgba(129, 140, 248, 0.35),
transparent 70%
);
filter: blur(40px);
animation: bit-aurora-drift 16s ease-in-out infinite alternate;
}
@keyframes bit-aurora-drift {
from {
transform: translate3d(-4%, -3%, 0) scale(1);
}
to {
transform: translate3d(5%, 4%, 0) scale(1.12);
}
}
/* The current station on the career line: a node that breathes light. */
.bit-node-live {
animation: bit-node-breathe 3.2s ease-in-out infinite;
}
@keyframes bit-node-breathe {
0%,
100% {
box-shadow:
0 0 0 4px rgba(129, 140, 248, 0.22),
0 0 18px 2px rgba(129, 140, 248, 0.55);
}
50% {
box-shadow:
0 0 0 8px rgba(129, 140, 248, 0.12),
0 0 34px 8px rgba(129, 140, 248, 0.85);
}
}
/*
* Native feel: the page should behave like a well-made app on every input type.
*/
html {
color-scheme: light;
/* Anchor jumps stop below the fixed header. */
scroll-padding-top: 6rem;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
accent-color: #0f172a;
caret-color: #0f172a;
}
body {
text-rendering: optimizeLegibility;
font-kerning: normal;
}
/* Headlines break into even lines, running text avoids lonely last words. */
h1,
h2,
h3,
h4 {
text-wrap: balance;
}
p,
li,
dd,
summary {
text-wrap: pretty;
}
/* Controls react at once to a tap and are not selected like text. */
a,
button,
summary,
[role="tab"],
[role="button"] {
touch-action: manipulation;
}
button,
summary,
[role="tab"],
[role="button"],
a[href^="#"] {
-webkit-user-select: none;
user-select: none;
}
/* Decoration is neither selectable nor draggable. */
[aria-hidden="true"],
canvas,
img,
svg {
-webkit-user-select: none;
user-select: none;
}
img,
svg,
a {
-webkit-user-drag: none;
}
/* One visible keyboard focus, none for mouse and touch. */
:focus:not(:focus-visible) {
outline: none;
}
:focus-visible {
outline: 2px solid #0f172a;
outline-offset: 3px;
}
a:focus-visible,
button:focus-visible,
summary:focus-visible {
border-radius: 6px;
}
/* A short press-in on anything that can be pressed. */
@media (prefers-reduced-motion: no-preference) {
button:active,
[role="tab"]:active,
a[class*="rounded-full"]:active,
a:active > [class*="rounded-full"] {
scale: 0.97;
transition-duration: 80ms;
}
}
/* Dark surfaces: light selection, light focus ring, dark system controls. */
.bg-slate-900,
.bg-slate-950 {
color-scheme: dark;
}
.bg-slate-900 ::selection,
.bg-slate-950 ::selection {
background: #f8fafc;
color: #0f172a;
}
.bg-slate-900 :focus-visible,
.bg-slate-950 :focus-visible {
outline-color: #f8fafc;
}
/* Fixed controls stay clear of the home indicator and rounded corners. */
@supports (padding: env(safe-area-inset-bottom)) {
body {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
}