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:
+314
-21
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user