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:
andreandClaude Sonnet 5.5 committed 2026-10-13 18:18:17 +01:00
1 parent 251644c393
commit acac3a191a
1 file changed
+58 -25
+58 -25
View File
@@ -354,48 +354,81 @@ section[id] {
color: var(--fitme-accent); color: var(--fitme-accent);
} }
/* ── 3D neon extrusion on hover ──────────────────────────────────────────────── /* ── 3D "pushable" neon button ─────────────────────────────────────────────────
The button lifts off the "wall" toward the viewer; the faces it leaves behind The element itself is the face. On hover it lifts straight up by --depth and
(the extruded sides) are drawn with stacked hard shadows in the brand colour a ::before strip, hanging off the face's bottom edge, grows to fill the gap:
and lit like neon tubes (glow on top). Colours come from the gym's brand that strip is the extruded wall, lit in the brand colour with a neon glow
tokens, so each gym glows in its own colour. */ (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, .site-btn,
.gym-switch-btn { .gym-switch-btn {
--neon: color-mix(in srgb, var(--fitme-accent) 70%, #fff); --depth: 5px;
--neon-edge: var(--fitme-accent-dark); --bw: 0px; /* the element's own border, so the wall starts below it */
--depth: 4px; --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) { @media (hover: hover) and (prefers-reduced-motion: no-preference) {
.site-btn, .site-btn,
.gym-switch-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:hover,
.site-btn:focus-visible, .site-btn:focus-visible,
.gym-switch-btn:hover, .gym-switch-btn:hover,
.gym-switch-btn:focus-visible { .gym-switch-btn:focus-visible {
transform: translate(calc(var(--depth) * -1), calc(var(--depth) * -1)); transform: translateY(calc(var(--depth) * -1));
/* The extruded sides ARE the neon: three lit steps (bright at the face, box-shadow: 0 0 18px 2px rgba(var(--fitme-accent-rgb), .35);
settling toward the wall) and a soft glow round the whole solid. The transition-duration: 250ms, 250ms, var(--fitme-transition), var(--fitme-transition);
face itself stays plain — no second outline, so nothing reads as a copy. */ transition-timing-function: cubic-bezier(.3, .7, .4, 1.5);
box-shadow: }
inset 1px 1px 0 rgba(var(--fitme-accent-rgb), .55), /* lit top-left bevel on the face */ .site-btn:hover::before,
1px 1px 0 var(--neon), .site-btn:focus-visible::before,
2px 2px 0 var(--fitme-accent), .gym-switch-btn:hover::before,
3px 3px 0 color-mix(in srgb, var(--fitme-accent) 75%, #000), .gym-switch-btn:focus-visible::before {
4px 4px 0 color-mix(in srgb, var(--fitme-accent) 50%, #000), transform: scaleY(1);
0 0 18px 3px rgba(var(--fitme-accent-rgb), .4), transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5);
4px 4px 22px 2px rgba(var(--fitme-accent-rgb), .3);
} }
.site-btn:active, .site-btn:active,
.gym-switch-btn:active { .gym-switch-btn:active {
transform: translate(-1px, -1px); transform: translateY(-1px);
box-shadow: transition-duration: 34ms;
1px 1px 0 var(--neon), }
0 0 10px 1px rgba(var(--fitme-accent-rgb), .5); .site-btn:active::before,
.gym-switch-btn:active::before {
transform: scaleY(.2);
transition-duration: 34ms;
} }
} }