style(site): angled 3D button (bottom + right walls), slower colour fade on hover

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
andreandClaude Sonnet 5.5 committed 2026-10-13 18:20:01 +01:00
1 parent acac3a191a
commit 7bf2a8542e
1 file changed
+58 -34
+58 -34
View File
@@ -354,20 +354,23 @@ section[id] {
color: var(--fitme-accent);
}
/* ── 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. */
/* ── 3D "pushable" neon button (seen at an angle) ──────────────────────────────
The element itself is the face. On hover it lifts toward the viewer — up by
--depth and left by --depth-x — and two pseudo-elements grow to fill the gap:
::before is the bottom wall, ::after the right wall. Each is a parallelogram
(clip-path) joining the face's edge to where the face used to be, so the
solid reads as an extruded block viewed from the right. Walls are lit in the
brand colour with a neon glow; the right one is a shade darker (light comes
from the top-left). Only transform animates (compositor-only): lift springs
(overshoot curve), release is slow, press is instant. 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 {
--depth: 5px;
--bw: 0px; /* the element's own border, so the wall starts below it */
--depth: 5px; /* lift (and bottom wall height) */
--depth-x: 4px; /* shift to the left (and right wall width) */
--bw: 0px; /* the element's own border, so the walls start outside 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);
@@ -376,30 +379,51 @@ section[id] {
.site-btn.sb-ghost { --bw: 2px; }
.site-btn::before,
.gym-switch-btn::before {
.site-btn::after,
.gym-switch-btn::before,
.gym-switch-btn::after {
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;
transform-origin: top left;
}
/* bottom wall */
.site-btn::before,
.gym-switch-btn::before {
left: calc(var(--bw) * -1);
top: calc(100% + var(--bw));
width: calc(100% + var(--bw) * 2 + var(--depth-x));
height: var(--depth);
background: linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 12%, var(--wall-hi) 50%, var(--wall) 88%, var(--wall-lo) 100%);
clip-path: polygon(0 0, calc(100% - var(--depth-x)) 0, 100% 100%, var(--depth-x) 100%);
transform: scaleY(0);
}
/* right wall */
.site-btn::after,
.gym-switch-btn::after {
left: calc(100% + var(--bw));
top: calc(var(--bw) * -1);
width: var(--depth-x);
height: calc(100% + var(--bw) * 2 + var(--depth));
background: linear-gradient(to bottom, var(--wall) 0%, var(--wall-lo) 100%);
clip-path: polygon(0 0, 100% var(--depth), 100% 100%, 0 calc(100% - var(--depth)));
transform: scaleX(0);
}
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
.site-btn,
.gym-switch-btn {
will-change: transform;
/* the face colour fades slowly so the change to near-black never "pops" */
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);
background-color 450ms ease, border-color 450ms ease, color 450ms ease;
}
.site-btn::before,
.gym-switch-btn::before {
.site-btn::after,
.gym-switch-btn::before,
.gym-switch-btn::after {
transition: transform 600ms cubic-bezier(.3, .7, .4, 1);
}
@@ -407,29 +431,29 @@ section[id] {
.site-btn:focus-visible,
.gym-switch-btn:hover,
.gym-switch-btn:focus-visible {
transform: translateY(calc(var(--depth) * -1));
transform: translate(calc(var(--depth-x) * -1), 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);
transition-duration: 250ms, 250ms, 450ms, 450ms, 450ms;
transition-timing-function: cubic-bezier(.3, .7, .4, 1.5), cubic-bezier(.3, .7, .4, 1.5), ease, ease, ease;
}
.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);
}
.gym-switch-btn:focus-visible::before { transform: scaleY(1); transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5); }
.site-btn:hover::after,
.site-btn:focus-visible::after,
.gym-switch-btn:hover::after,
.gym-switch-btn:focus-visible::after { transform: scaleX(1); transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5); }
.site-btn:active,
.gym-switch-btn:active {
transform: translateY(-1px);
transform: translate(-1px, -1px);
transition-duration: 34ms;
}
.site-btn:active::before,
.gym-switch-btn:active::before {
transform: scaleY(.2);
transition-duration: 34ms;
}
.gym-switch-btn:active::before { transform: scaleY(.2); transition-duration: 34ms; }
.site-btn:active::after,
.gym-switch-btn:active::after { transform: scaleX(.25); transition-duration: 34ms; }
}
/* Hover: white text on an almost-black face keeping ~10% of the brand colour —