style(site): pushable 3D neon buttons (lifting face + ::before wall, spring curves)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
251644c393
commit
acac3a191a
1 file changed
+58
-25
+58
-25
@@ -354,48 +354,81 @@ section[id] {
|
||||
color: var(--fitme-accent);
|
||||
}
|
||||
|
||||
/* ── 3D neon extrusion on hover ────────────────────────────────────────────────
|
||||
The button lifts off the "wall" toward the viewer; the faces it leaves behind
|
||||
(the extruded sides) are drawn with stacked hard shadows in the brand colour
|
||||
and lit like neon tubes (glow on top). Colours come from the gym's brand
|
||||
tokens, so each gym glows in its own colour. */
|
||||
/* ── 3D "pushable" neon button ─────────────────────────────────────────────────
|
||||
The element itself is the face. On hover it lifts straight up by --depth and
|
||||
a ::before strip, hanging off the face's bottom edge, grows to fill the gap:
|
||||
that strip is the extruded wall, lit in the brand colour with a neon glow
|
||||
(darker at both ends like a rounded edge). Only transform / opacity animate
|
||||
(compositor-only). Lift springs (overshoot curve), release is slow, press is
|
||||
instant — same feel as a physical key. Colours come from --fitme-accent, so
|
||||
each gym glows in its own colour. */
|
||||
:where(.site-btn, .gym-switch-btn) { position: relative; }
|
||||
|
||||
.site-btn,
|
||||
.gym-switch-btn {
|
||||
--neon: color-mix(in srgb, var(--fitme-accent) 70%, #fff);
|
||||
--neon-edge: var(--fitme-accent-dark);
|
||||
--depth: 4px;
|
||||
--depth: 5px;
|
||||
--bw: 0px; /* the element's own border, so the wall starts below it */
|
||||
--wall-hi: color-mix(in srgb, var(--fitme-accent) 70%, #fff);
|
||||
--wall: var(--fitme-accent);
|
||||
--wall-lo: color-mix(in srgb, var(--fitme-accent) 45%, #000);
|
||||
}
|
||||
.site-btn.sb-line,
|
||||
.site-btn.sb-ghost { --bw: 2px; }
|
||||
|
||||
.site-btn::before,
|
||||
.gym-switch-btn::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: calc(100% + var(--bw));
|
||||
height: var(--depth);
|
||||
border-radius: 0 0 var(--fitme-radius) var(--fitme-radius);
|
||||
background: linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 10%, var(--wall-hi) 50%, var(--wall) 90%, var(--wall-lo) 100%);
|
||||
box-shadow: 0 2px 14px 1px rgba(var(--fitme-accent-rgb), .6);
|
||||
transform: scaleY(0);
|
||||
transform-origin: top;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
||||
.site-btn,
|
||||
.gym-switch-btn {
|
||||
transition: transform .18s ease, box-shadow .18s ease, background var(--fitme-transition), color var(--fitme-transition);
|
||||
will-change: transform;
|
||||
transition: transform 600ms cubic-bezier(.3, .7, .4, 1), box-shadow 600ms cubic-bezier(.3, .7, .4, 1),
|
||||
background var(--fitme-transition), color var(--fitme-transition);
|
||||
}
|
||||
.site-btn::before,
|
||||
.gym-switch-btn::before {
|
||||
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
|
||||
}
|
||||
|
||||
.site-btn:hover,
|
||||
.site-btn:focus-visible,
|
||||
.gym-switch-btn:hover,
|
||||
.gym-switch-btn:focus-visible {
|
||||
transform: translate(calc(var(--depth) * -1), calc(var(--depth) * -1));
|
||||
/* The extruded sides ARE the neon: three lit steps (bright at the face,
|
||||
settling toward the wall) and a soft glow round the whole solid. The
|
||||
face itself stays plain — no second outline, so nothing reads as a copy. */
|
||||
box-shadow:
|
||||
inset 1px 1px 0 rgba(var(--fitme-accent-rgb), .55), /* lit top-left bevel on the face */
|
||||
1px 1px 0 var(--neon),
|
||||
2px 2px 0 var(--fitme-accent),
|
||||
3px 3px 0 color-mix(in srgb, var(--fitme-accent) 75%, #000),
|
||||
4px 4px 0 color-mix(in srgb, var(--fitme-accent) 50%, #000),
|
||||
0 0 18px 3px rgba(var(--fitme-accent-rgb), .4),
|
||||
4px 4px 22px 2px rgba(var(--fitme-accent-rgb), .3);
|
||||
transform: translateY(calc(var(--depth) * -1));
|
||||
box-shadow: 0 0 18px 2px rgba(var(--fitme-accent-rgb), .35);
|
||||
transition-duration: 250ms, 250ms, var(--fitme-transition), var(--fitme-transition);
|
||||
transition-timing-function: cubic-bezier(.3, .7, .4, 1.5);
|
||||
}
|
||||
.site-btn:hover::before,
|
||||
.site-btn:focus-visible::before,
|
||||
.gym-switch-btn:hover::before,
|
||||
.gym-switch-btn:focus-visible::before {
|
||||
transform: scaleY(1);
|
||||
transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
|
||||
}
|
||||
|
||||
.site-btn:active,
|
||||
.gym-switch-btn:active {
|
||||
transform: translate(-1px, -1px);
|
||||
box-shadow:
|
||||
1px 1px 0 var(--neon),
|
||||
0 0 10px 1px rgba(var(--fitme-accent-rgb), .5);
|
||||
transform: translateY(-1px);
|
||||
transition-duration: 34ms;
|
||||
}
|
||||
.site-btn:active::before,
|
||||
.gym-switch-btn:active::before {
|
||||
transform: scaleY(.2);
|
||||
transition-duration: 34ms;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user