release: promote beta to main (gyms, brand colours, JPEG XL, SEO per gym) #3
+99
-46
@@ -358,22 +358,74 @@ section[id] {
|
|||||||
The element itself is the face. On hover it lifts toward the viewer — up by
|
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:
|
--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
|
::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
|
(clip-path) joining the face's edge to where the face used to be; they share
|
||||||
solid reads as an extruded block viewed from the right. Walls are lit in the
|
the diagonal from the face's corner, so the join has no gap and no overlap.
|
||||||
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
|
Light model (key light top-left, the walls are the neon tubes):
|
||||||
(overshoot curve), release is slow, press is instant. Colours come from
|
- Glow lives on the walls and spills onto the page under/around them. The
|
||||||
--fitme-accent, so each gym glows in its own colour. */
|
halo is an outer box-shadow offset toward the walls (never painted inside
|
||||||
|
the face, no drop-shadow, so no ghost copy of the text), blooming in with
|
||||||
|
the lift and tightening on press.
|
||||||
|
- Walls: hot near-white core in the middle of their length, saturated brand
|
||||||
|
colour on the falloff, darkest at the ends; across their thickness bright
|
||||||
|
where they meet the face, darker at the far edge. The right wall is one
|
||||||
|
step darker than the bottom; both reach the darkest value (ambient
|
||||||
|
occlusion) where they meet in the corner.
|
||||||
|
- Contact shadow: a tight dark line just past the walls' far edges.
|
||||||
|
- Face: only a faint rim light near the edges, a thin specular line on the
|
||||||
|
top-left edge, slightly darker toward the bottom/right. Centre untouched.
|
||||||
|
Colours derive from --fitme-accent with color-mix(), so any gym colour works. */
|
||||||
:where(.site-btn, .gym-switch-btn) { position: relative; }
|
:where(.site-btn, .gym-switch-btn) { position: relative; }
|
||||||
|
|
||||||
|
.site-btn,
|
||||||
|
.gym-switch-btn,
|
||||||
|
.trainer-item .trainer-pic {
|
||||||
|
--wall-hi: color-mix(in srgb, var(--fitme-accent) 40%, #fff); /* hot core of the tube */
|
||||||
|
--wall: var(--fitme-accent);
|
||||||
|
--wall-lo: color-mix(in srgb, var(--fitme-accent) 60%, #000);
|
||||||
|
--wall-ao: color-mix(in srgb, var(--fitme-accent) 30%, #000); /* corner / far ends */
|
||||||
|
/* bottom wall: across thickness (bright at the face, dark far edge) over along length */
|
||||||
|
--wall-bottom:
|
||||||
|
linear-gradient(to bottom, rgba(255, 255, 255, .28) 0%, rgba(255, 255, 255, 0) 40%, rgba(0, 0, 0, .4) 100%),
|
||||||
|
linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 18%, var(--wall-hi) 48%, var(--wall) 78%, var(--wall-ao) 100%);
|
||||||
|
/* right wall: one step darker, ends in the same --wall-ao at the corner */
|
||||||
|
--wall-right:
|
||||||
|
linear-gradient(to right, rgba(255, 255, 255, .14) 0%, rgba(0, 0, 0, .12) 45%, rgba(0, 0, 0, .5) 100%),
|
||||||
|
linear-gradient(to bottom, var(--wall-lo) 0%, var(--wall) 22%, color-mix(in srgb, var(--wall-hi) 60%, var(--wall)) 50%, var(--wall-lo) 82%, var(--wall-ao) 100%);
|
||||||
|
/* halo stacks (outer only): contact shadow, tight bloom, wide ambient spill */
|
||||||
|
--neon-on:
|
||||||
|
calc(var(--depth-x) + 1px) calc(var(--depth) + 1px) 2px rgba(0, 0, 0, .45),
|
||||||
|
calc(var(--depth-x) * .75) var(--depth) 7px 0 rgba(var(--fitme-accent-rgb), .5),
|
||||||
|
var(--depth-x) calc(var(--depth) * 1.6) 24px 2px rgba(var(--fitme-accent-rgb), .24);
|
||||||
|
--neon-dim:
|
||||||
|
calc(var(--depth-x) + 1px) calc(var(--depth) + 1px) 2px rgba(0, 0, 0, .45),
|
||||||
|
calc(var(--depth-x) * .75) var(--depth) 6px 0 rgba(var(--fitme-accent-rgb), .25),
|
||||||
|
var(--depth-x) calc(var(--depth) * 1.6) 20px 0 rgba(var(--fitme-accent-rgb), .1);
|
||||||
|
--neon-off:
|
||||||
|
calc(var(--depth-x) + 1px) calc(var(--depth) + 1px) 2px rgba(0, 0, 0, .45),
|
||||||
|
calc(var(--depth-x) * .75) var(--depth) 4px 0 rgba(var(--fitme-accent-rgb), .08),
|
||||||
|
var(--depth-x) calc(var(--depth) * 1.6) 16px 0 rgba(var(--fitme-accent-rgb), 0);
|
||||||
|
/* pressed: wall compressed to ~1px, glow pulled in close */
|
||||||
|
--neon-press:
|
||||||
|
1px 1px 1px rgba(0, 0, 0, .5),
|
||||||
|
1px 1px 4px 0 rgba(var(--fitme-accent-rgb), .55),
|
||||||
|
1px 2px 12px 0 rgba(var(--fitme-accent-rgb), .2);
|
||||||
|
/* face shading (inset): specular top-left, lit seam bottom-right, shade, faint rim */
|
||||||
|
--face-light:
|
||||||
|
inset 1px 1px 0 color-mix(in srgb, var(--wall-hi) 55%, transparent),
|
||||||
|
inset -1px -1px 0 rgba(var(--fitme-accent-rgb), .5),
|
||||||
|
inset -3px -4px 8px -2px rgba(0, 0, 0, .55),
|
||||||
|
inset 0 0 7px -3px rgba(var(--fitme-accent-rgb), .45);
|
||||||
|
}
|
||||||
|
|
||||||
.site-btn,
|
.site-btn,
|
||||||
.gym-switch-btn {
|
.gym-switch-btn {
|
||||||
--depth: 5px; /* lift (and bottom wall height) */
|
--depth: 5px; /* lift (and bottom wall height) */
|
||||||
--depth-x: 4px; /* shift to the left (and right wall width) */
|
--depth-x: 4px; /* shift to the left (and right wall width) */
|
||||||
--bw: 0px; /* the element's own border, so the walls start outside it */
|
--bw: 0px; /* the element's own border, so the walls start outside it */
|
||||||
--wall-hi: color-mix(in srgb, var(--fitme-accent) 45%, #fff); /* hot core of the tube */
|
--neon-face-on: var(--face-light), var(--neon-on);
|
||||||
--wall: var(--fitme-accent);
|
--neon-face-dim: var(--face-light), var(--neon-dim);
|
||||||
--wall-lo: color-mix(in srgb, var(--fitme-accent) 65%, #000);
|
--neon-face-off: var(--face-light), var(--neon-off);
|
||||||
}
|
}
|
||||||
.site-btn.sb-line,
|
.site-btn.sb-line,
|
||||||
.site-btn.sb-ghost { --bw: 2px; }
|
.site-btn.sb-ghost { --bw: 2px; }
|
||||||
@@ -395,7 +447,7 @@ section[id] {
|
|||||||
top: calc(100% + var(--bw));
|
top: calc(100% + var(--bw));
|
||||||
width: calc(100% + var(--bw) * 2 + var(--depth-x));
|
width: calc(100% + var(--bw) * 2 + var(--depth-x));
|
||||||
height: var(--depth);
|
height: var(--depth);
|
||||||
background: linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 1%, var(--wall-hi) 50%, var(--wall) 99%, var(--wall-lo) 100%);
|
background: var(--wall-bottom);
|
||||||
clip-path: polygon(0 0, calc(100% - var(--depth-x)) 0, 100% 100%, var(--depth-x) 100%);
|
clip-path: polygon(0 0, calc(100% - var(--depth-x)) 0, 100% 100%, var(--depth-x) 100%);
|
||||||
transform: scaleY(0);
|
transform: scaleY(0);
|
||||||
}
|
}
|
||||||
@@ -407,7 +459,7 @@ section[id] {
|
|||||||
top: calc(var(--bw) * -1);
|
top: calc(var(--bw) * -1);
|
||||||
width: var(--depth-x);
|
width: var(--depth-x);
|
||||||
height: calc(100% + var(--bw) * 2 + var(--depth));
|
height: calc(100% + var(--bw) * 2 + var(--depth));
|
||||||
background: linear-gradient(to bottom, var(--wall) 0%, var(--wall-lo) 100%);
|
background: var(--wall-right);
|
||||||
clip-path: polygon(0 0, 100% var(--depth), 100% 100%, 0 calc(100% - var(--depth)));
|
clip-path: polygon(0 0, 100% var(--depth), 100% 100%, 0 calc(100% - var(--depth)));
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
}
|
}
|
||||||
@@ -418,7 +470,7 @@ section[id] {
|
|||||||
will-change: transform;
|
will-change: transform;
|
||||||
/* the face colour fades slowly so the change to near-black never "pops" */
|
/* 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),
|
transition: transform 600ms cubic-bezier(.3, .7, .4, 1), box-shadow 600ms cubic-bezier(.3, .7, .4, 1),
|
||||||
background-color 450ms ease, border-color 450ms ease, color 450ms ease, filter 450ms ease;
|
background-color 450ms ease, border-color 450ms ease, color 450ms ease;
|
||||||
}
|
}
|
||||||
.site-btn::before,
|
.site-btn::before,
|
||||||
.site-btn::after,
|
.site-btn::after,
|
||||||
@@ -432,14 +484,10 @@ section[id] {
|
|||||||
.gym-switch-btn:hover,
|
.gym-switch-btn:hover,
|
||||||
.gym-switch-btn:focus-visible {
|
.gym-switch-btn:focus-visible {
|
||||||
transform: translate(calc(var(--depth-x) * -1), calc(var(--depth) * -1));
|
transform: translate(calc(var(--depth-x) * -1), calc(var(--depth) * -1));
|
||||||
/* inner glow on the face (the "lit from inside" look) + a halo round the
|
box-shadow: var(--neon-face-on);
|
||||||
whole solid; drop-shadow follows the clipped walls, box-shadow can't */
|
/* lift springs fast; the bloom eases in a little slower so it grows with the lift */
|
||||||
box-shadow: inset 0 0 14px 1px rgba(var(--fitme-accent-rgb), .4),
|
transition-duration: 250ms, 380ms, 450ms, 450ms, 450ms;
|
||||||
inset 0 0 3px 0 rgba(var(--fitme-accent-rgb), .6),
|
transition-timing-function: cubic-bezier(.3, .7, .4, 1.5), ease-out, ease, ease, ease;
|
||||||
0 0 12px 1px rgba(var(--fitme-accent-rgb), .25);
|
|
||||||
filter: drop-shadow(0 0 5px rgba(var(--fitme-accent-rgb), .9)) drop-shadow(0 0 14px rgba(var(--fitme-accent-rgb), .55));
|
|
||||||
transition-duration: 250ms, 250ms, 450ms, 450ms, 450ms, 450ms;
|
|
||||||
transition-timing-function: cubic-bezier(.3, .7, .4, 1.5), cubic-bezier(.3, .7, .4, 1.5), ease, ease, ease, ease;
|
|
||||||
}
|
}
|
||||||
.site-btn:hover::before,
|
.site-btn:hover::before,
|
||||||
.site-btn:focus-visible::before,
|
.site-btn:focus-visible::before,
|
||||||
@@ -451,7 +499,8 @@ section[id] {
|
|||||||
.gym-switch-btn:focus-visible::after { transform: scaleX(1); transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5); }
|
.gym-switch-btn:focus-visible::after { transform: scaleX(1); transition: transform 250ms cubic-bezier(.3, .7, .4, 1.5); }
|
||||||
|
|
||||||
/* Neon blink: after a moment of hovering, one short stutter — like a tube
|
/* Neon blink: after a moment of hovering, one short stutter — like a tube
|
||||||
that isn't quite seated — then steady again. Opacity + filter only. */
|
that isn't quite seated — then steady. Walls (opacity) and halo
|
||||||
|
(box-shadow) dim on the same keyframe times. */
|
||||||
.site-btn:hover,
|
.site-btn:hover,
|
||||||
.site-btn:focus-visible,
|
.site-btn:focus-visible,
|
||||||
.gym-switch-btn:hover,
|
.gym-switch-btn:hover,
|
||||||
@@ -468,6 +517,8 @@ section[id] {
|
|||||||
.site-btn:active,
|
.site-btn:active,
|
||||||
.gym-switch-btn:active {
|
.gym-switch-btn:active {
|
||||||
transform: translate(-1px, -1px);
|
transform: translate(-1px, -1px);
|
||||||
|
box-shadow: var(--face-light), var(--neon-press);
|
||||||
|
animation: none;
|
||||||
transition-duration: 34ms;
|
transition-duration: 34ms;
|
||||||
}
|
}
|
||||||
.site-btn:active::before,
|
.site-btn:active::before,
|
||||||
@@ -477,31 +528,29 @@ section[id] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes neon-flicker-tube {
|
@keyframes neon-flicker-tube {
|
||||||
0%, 100% { opacity: 1; }
|
0%, 30%, 65%, 100% { opacity: 1; }
|
||||||
15% { opacity: .3; }
|
15% { opacity: .3; }
|
||||||
30% { opacity: 1; }
|
|
||||||
50% { opacity: .55; }
|
50% { opacity: .55; }
|
||||||
65% { opacity: 1; }
|
|
||||||
}
|
}
|
||||||
@keyframes neon-flicker-glow {
|
@keyframes neon-flicker-glow {
|
||||||
0%, 100% { filter: drop-shadow(0 0 5px rgba(var(--fitme-accent-rgb), .9)) drop-shadow(0 0 14px rgba(var(--fitme-accent-rgb), .55)); }
|
0%, 30%, 65%, 100% { box-shadow: var(--neon-face-on); }
|
||||||
15% { filter: drop-shadow(0 0 1px rgba(var(--fitme-accent-rgb), .3)); }
|
15% { box-shadow: var(--neon-face-off); }
|
||||||
30% { filter: drop-shadow(0 0 5px rgba(var(--fitme-accent-rgb), .9)) drop-shadow(0 0 14px rgba(var(--fitme-accent-rgb), .55)); }
|
50% { box-shadow: var(--neon-face-dim); }
|
||||||
50% { filter: drop-shadow(0 0 2px rgba(var(--fitme-accent-rgb), .45)); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Team photo frames: the same neon extrusion ────────────────────────────────
|
/* ── Team photo frames: the same neon extrusion ────────────────────────────────
|
||||||
.trainer-pic is the face. Its ::before draws the L-shaped wall (bottom + right,
|
.trainer-pic is the face. Its ::before draws the L-shaped wall (bottom + right,
|
||||||
one clipped polygon, two gradients); ::after stays the existing gloss overlay
|
one clipped polygon, the same wall gradients); ::after stays the existing
|
||||||
and also carries the inner glow. The frame no longer clips its children
|
gloss overlay and also carries the face shading. The halo is the frame's
|
||||||
(overflow:hidden would cut the wall), the photo fills the padding box anyway. */
|
outer box-shadow only (no inset there, the photo covers it). The frame no
|
||||||
|
longer clips its children (overflow:hidden would cut the wall). */
|
||||||
.trainer-item .trainer-pic {
|
.trainer-item .trainer-pic {
|
||||||
--depth: 5px;
|
--depth: 5px;
|
||||||
--depth-x: 4px;
|
--depth-x: 4px;
|
||||||
--bw: 4px; /* the frame's own border */
|
--bw: 4px; /* the frame's own border */
|
||||||
--wall-hi: color-mix(in srgb, var(--fitme-accent) 45%, #fff);
|
--neon-face-on: var(--neon-on);
|
||||||
--wall: var(--fitme-accent);
|
--neon-face-dim: var(--neon-dim);
|
||||||
--wall-lo: color-mix(in srgb, var(--fitme-accent) 65%, #000);
|
--neon-face-off: var(--neon-off);
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,10 +564,15 @@ section[id] {
|
|||||||
z-index: -1;
|
z-index: -1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
/* the two gradient pairs, each sized to its wall's box (bottom strip, right strip) */
|
||||||
background:
|
background:
|
||||||
linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 1%, var(--wall-hi) 50%, var(--wall) 99%, var(--wall-lo) 100%)
|
linear-gradient(to bottom, rgba(255, 255, 255, .28) 0%, rgba(255, 255, 255, 0) 40%, rgba(0, 0, 0, .4) 100%)
|
||||||
0 100% / calc(100% - var(--depth-x)) var(--depth) no-repeat,
|
0 100% / calc(100% - var(--depth-x)) var(--depth) no-repeat,
|
||||||
linear-gradient(to bottom, var(--wall) 0%, var(--wall-lo) 100%)
|
linear-gradient(to right, var(--wall-lo) 0%, var(--wall) 18%, var(--wall-hi) 48%, var(--wall) 78%, var(--wall-ao) 100%)
|
||||||
|
0 100% / calc(100% - var(--depth-x)) var(--depth) no-repeat,
|
||||||
|
linear-gradient(to right, rgba(255, 255, 255, .14) 0%, rgba(0, 0, 0, .12) 45%, rgba(0, 0, 0, .5) 100%)
|
||||||
|
100% 0 / var(--depth-x) 100% no-repeat,
|
||||||
|
linear-gradient(to bottom, var(--wall-lo) 0%, var(--wall) 22%, color-mix(in srgb, var(--wall-hi) 60%, var(--wall)) 50%, var(--wall-lo) 82%, var(--wall-ao) 100%)
|
||||||
100% 0 / var(--depth-x) 100% no-repeat;
|
100% 0 / var(--depth-x) 100% no-repeat;
|
||||||
clip-path: polygon(0 calc(100% - var(--depth)), calc(100% - var(--depth-x)) calc(100% - var(--depth)),
|
clip-path: polygon(0 calc(100% - var(--depth)), calc(100% - var(--depth-x)) calc(100% - var(--depth)),
|
||||||
calc(100% - var(--depth-x)) 0, 100% var(--depth), 100% 100%, var(--depth-x) 100%);
|
calc(100% - var(--depth-x)) 0, 100% var(--depth), 100% 100%, var(--depth-x) 100%);
|
||||||
@@ -528,23 +582,22 @@ section[id] {
|
|||||||
.trainer-item .trainer-pic:hover,
|
.trainer-item .trainer-pic:hover,
|
||||||
#powerRotation>div:nth-child(even) .trainer-pic:hover {
|
#powerRotation>div:nth-child(even) .trainer-pic:hover {
|
||||||
transform: rotate(0deg) translate(calc(var(--depth-x) * -1), calc(var(--depth) * -1)) scale(1.03);
|
transform: rotate(0deg) translate(calc(var(--depth-x) * -1), calc(var(--depth) * -1)) scale(1.03);
|
||||||
box-shadow: 0 0 12px 1px rgba(var(--fitme-accent-rgb), .25);
|
box-shadow: var(--neon-face-on);
|
||||||
filter: drop-shadow(0 0 5px rgba(var(--fitme-accent-rgb), .9)) drop-shadow(0 0 14px rgba(var(--fitme-accent-rgb), .55));
|
|
||||||
}
|
}
|
||||||
.trainer-item .trainer-pic:hover::before { opacity: 1; }
|
.trainer-item .trainer-pic:hover::before { opacity: 1; }
|
||||||
.trainer-item .trainer-pic:hover::after {
|
.trainer-item .trainer-pic:hover::after { box-shadow: var(--face-light); }
|
||||||
box-shadow: inset 0 0 14px 1px rgba(var(--fitme-accent-rgb), .4), inset 0 0 3px 0 rgba(var(--fitme-accent-rgb), .6);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
||||||
.trainer-item .trainer-pic { transition: transform .25s cubic-bezier(.3, .7, .4, 1.5), box-shadow .45s ease, filter .45s ease; }
|
.trainer-item .trainer-pic { transition: transform .25s cubic-bezier(.3, .7, .4, 1.5), box-shadow .38s ease-out; }
|
||||||
.trainer-item .trainer-pic:hover { animation: neon-flicker-glow 600ms linear 1.4s 1; }
|
.trainer-item .trainer-pic:hover { animation: neon-flicker-glow 600ms linear 1.4s 1; }
|
||||||
.trainer-item .trainer-pic:hover::before { animation: neon-flicker-tube 600ms linear 1.4s 1; }
|
.trainer-item .trainer-pic:hover::before { animation: neon-flicker-tube 600ms linear 1.4s 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hover: white text on an almost-black face keeping ~10% of the brand colour —
|
/* Hover: white text on an almost-black face keeping ~10% of the brand colour
|
||||||
the bright neon faces around it then stand out against it. The dark and
|
(white on it is >= 15:1 for any brand colour, even pure white or black).
|
||||||
ghost variants keep their own backgrounds. */
|
The lettering gets a dark backing under the neon text-shadow so very light
|
||||||
|
brand colours never wash the letter edges out. The dark and ghost variants
|
||||||
|
keep their own backgrounds. */
|
||||||
.site-btn:not(.sb-dark):not(.sb-line):not(.sb-ghost):hover,
|
.site-btn:not(.sb-dark):not(.sb-line):not(.sb-ghost):hover,
|
||||||
.site-btn:not(.sb-dark):not(.sb-line):not(.sb-ghost):focus-visible,
|
.site-btn:not(.sb-dark):not(.sb-line):not(.sb-ghost):focus-visible,
|
||||||
.gym-switch-btn:hover,
|
.gym-switch-btn:hover,
|
||||||
@@ -552,7 +605,7 @@ section[id] {
|
|||||||
background: color-mix(in srgb, var(--fitme-accent) 10%, #000);
|
background: color-mix(in srgb, var(--fitme-accent) 10%, #000);
|
||||||
border-color: color-mix(in srgb, var(--fitme-accent) 10%, #000);
|
border-color: color-mix(in srgb, var(--fitme-accent) 10%, #000);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-shadow: 0 0 8px rgba(var(--fitme-accent-rgb), .9), 0 0 2px rgba(255, 255, 255, .6); /* neon lettering */
|
text-shadow: 0 0 1px rgba(0, 0, 0, .8), 0 0 7px rgba(var(--fitme-accent-rgb), .75); /* neon lettering */
|
||||||
}
|
}
|
||||||
.site-btn.sb-dark:hover,
|
.site-btn.sb-dark:hover,
|
||||||
.site-btn.sb-line:hover { color: #fff; }
|
.site-btn.sb-line:hover { color: #fff; }
|
||||||
|
|||||||
Reference in new issue
Block a user