fix(site): restore CSS lost in 6c14e64; gallery click-and-drag; no link underline + colour/glow hover; brand-colour CrossFit pill; lighter trial link; no gloss on team photos
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6c14e644b1
commit
3d2a696162
3 files changed
+871
-69
No files matched your search
+783
-56
@@ -391,27 +391,30 @@ section[id] {
|
||||
|
||||
/* ── CrossFit nav pill (follows the gym's brand colour) ─────────────────────────────────────────────────────── */
|
||||
.crossfit-nav-link {
|
||||
color: var(--fitme-accent-ink) !important;
|
||||
/* the gym's own brand colour (not the darker "ink" shade), filled so the text
|
||||
stays readable on the light navbar: dark/white text via --fitme-on-accent */
|
||||
background: var(--fitme-accent) !important;
|
||||
color: var(--fitme-on-accent) !important;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .5px;
|
||||
border: 2px solid var(--fitme-accent-ink);
|
||||
border: 2px solid var(--fitme-accent);
|
||||
border-radius: var(--fitme-radius);
|
||||
padding: 6px 14px !important;
|
||||
transition: background-color var(--fitme-transition), color var(--fitme-transition);
|
||||
transition: background-color .4s ease, color .4s ease, border-color .4s ease;
|
||||
}
|
||||
|
||||
.crossfit-nav-link:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hover and current-page state: filled pill, white text (must outrank the
|
||||
/* Hover and current-page state: near-black face with white text (outranks the
|
||||
generic .nav-item.active .nav-link transparent-background rule above) */
|
||||
.crossfit-nav-link:hover,
|
||||
.nav-item.active .crossfit-nav-link {
|
||||
background: var(--fitme-accent) !important;
|
||||
background: color-mix(in srgb, var(--fitme-accent) 10%, #000) !important;
|
||||
border-color: var(--fitme-accent);
|
||||
color: var(--fitme-on-accent) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ── Other-gym button (right end of the navbar) ────────────────────────────── */
|
||||
@@ -683,7 +686,8 @@ section[id] {
|
||||
padding: 4px 8px;
|
||||
color: #fff;
|
||||
font: inherit;
|
||||
font-weight: 600;
|
||||
font-weight: 300;
|
||||
letter-spacing: .02em;
|
||||
text-shadow: 0 1px 6px rgba(0, 0, 0, .6);
|
||||
cursor: pointer;
|
||||
transition: color .3s ease;
|
||||
@@ -691,8 +695,7 @@ section[id] {
|
||||
.hero-text-link:hover,
|
||||
.hero-text-link:focus-visible {
|
||||
color: var(--fitme-accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.hero-cta-row .site-btn {
|
||||
@@ -990,10 +993,7 @@ section[id] {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 0;
|
||||
background:
|
||||
radial-gradient(ellipse at 30% 20%, rgba(255, 255, 255, 0.25) 0%, transparent 50%),
|
||||
radial-gradient(ellipse at 70% 80%, rgba(255, 255, 255, 0.08) 0%, transparent 45%),
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 40%, rgba(0, 0, 0, 0.1) 100%);
|
||||
background: none; /* no gloss gradient over the member photos */
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -1013,13 +1013,6 @@ section[id] {
|
||||
transform: rotate(0deg) translateY(-8px) scale(1.05);
|
||||
}
|
||||
|
||||
.trainer-item .trainer-pic:hover:after {
|
||||
background:
|
||||
radial-gradient(ellipse at 30% 20%, rgba(255, 255, 255, 0.32) 0%, transparent 50%),
|
||||
radial-gradient(ellipse at 70% 80%, rgba(255, 255, 255, 0.10) 0%, transparent 45%),
|
||||
linear-gradient(135deg, rgba(255, 255, 255, 0.18) 0%, transparent 40%, rgba(0, 0, 0, 0.08) 100%);
|
||||
}
|
||||
|
||||
/* Same hover as the buttons / Mensalidades cards: the frame's 4px edge turns
|
||||
into a conic brand-colour sweep (--pc-a / pc-spin, shared) over a dimmed
|
||||
base of the same colour, with a soft glow round it. The photo covers the
|
||||
@@ -1996,7 +1989,7 @@ h3.contact-title {
|
||||
|
||||
.consent-check a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.consent-check a:hover {
|
||||
@@ -2769,7 +2762,7 @@ h3.contact-title {
|
||||
padding: 12px 4px;
|
||||
margin: -12px -4px;
|
||||
min-height: 44px;
|
||||
text-decoration: underline;
|
||||
text-decoration: none;
|
||||
transition: color var(--fitme-transition);
|
||||
}
|
||||
|
||||
@@ -3399,7 +3392,7 @@ h3.contact-title {
|
||||
cursor: pointer;
|
||||
}
|
||||
.event-consent input { margin-top: 3px; flex: 0 0 auto; }
|
||||
.event-consent a { color: var(--fitme-accent-ink); text-decoration: underline; }
|
||||
.event-consent a { color: var(--fitme-accent-ink); text-decoration: none; }
|
||||
@media (max-width: 575px) {
|
||||
.event-form-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
@@ -3563,29 +3556,756 @@ h3.contact-title {
|
||||
|
||||
.trainer-item.is-open { z-index: 31; }
|
||||
|
||||
/* ── Open detail cards (team + Modalidades): the same spinning brand edge ──────
|
||||
A 3px ring cut out of ::after with a mask, shown while the card is open, plus
|
||||
a soft brand glow added to the existing lift shadow. ─────────────────────── */
|
||||
.mod-detail::after,
|
||||
.trainer-detail::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 5;
|
||||
padding: 3px;
|
||||
border-radius: inherit;
|
||||
background: conic-gradient(from var(--pc-a), rgba(var(--fitme-accent-rgb), .35) 0deg, rgba(var(--fitme-accent-rgb), .35) 150deg,
|
||||
var(--fitme-accent) 250deg, #f4ff9c 300deg, var(--fitme-accent) 330deg,
|
||||
rgba(var(--fitme-accent-rgb), .35) 360deg);
|
||||
-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);
|
||||
opacity: 0;
|
||||
transition: opacity .45s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
.mod-detail.is-open::after,
|
||||
.trainer-item.is-open .trainer-detail::after { opacity: 1; animation: pc-spin 3.2s linear infinite; }
|
||||
.mod-detail.is-open {
|
||||
box-shadow: 0 12px 30px rgba(var(--fitme-dark-rgb), .16), 0 2px 6px rgba(var(--fitme-dark-rgb), .10),
|
||||
0 0 22px 2px rgba(var(--fitme-accent-rgb), .35);
|
||||
}
|
||||
.trainer-item.is-open .trainer-detail {
|
||||
box-shadow: 0 12px 30px rgba(0, 0, 0, .32), 0 2px 6px rgba(0, 0, 0, .18),
|
||||
0 0 22px 2px rgba(var(--fitme-accent-rgb), .35);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mod-detail.is-open::after,
|
||||
.trainer-item.is-open .trainer-detail::after { animation: none; }
|
||||
}
|
||||
|
||||
|
||||
.td-photo {
|
||||
flex: 0 0 var(--td-pw, 200px);
|
||||
box-sizing: border-box;
|
||||
border: 4px solid var(--fitme-accent);
|
||||
background: var(--fitme-surface-2);
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.td-photo img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: calc(var(--td-ph, 200px) - 8px);
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.td-body {
|
||||
flex: 1 1 auto;
|
||||
padding: 18px 22px 18px 20px;
|
||||
max-height: 340px;
|
||||
overflow-y: auto;
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
transition: opacity .12s ease, transform .12s ease;
|
||||
}
|
||||
|
||||
.td-flip .td-body { transform: translateX(10px); }
|
||||
|
||||
.trainer-item.is-open .td-body {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
transition: opacity .3s ease .18s, transform .35s ease .18s;
|
||||
}
|
||||
|
||||
.td-name {
|
||||
display: block;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 800;
|
||||
color: var(--fitme-dark);
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.td-title {
|
||||
display: block;
|
||||
font-size: .82rem;
|
||||
font-weight: 700;
|
||||
color: var(--fitme-accent-ink);
|
||||
margin-bottom: .6rem;
|
||||
}
|
||||
|
||||
.td-bio {
|
||||
font-size: .88rem;
|
||||
color: var(--fitme-text-soft);
|
||||
margin-bottom: .6rem;
|
||||
}
|
||||
|
||||
.td-bio p:last-child { margin-bottom: 0; }
|
||||
|
||||
.td-block + .td-block { margin-top: .55rem; }
|
||||
|
||||
.td-label {
|
||||
display: block;
|
||||
font-size: .68rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: .14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--fitme-text-muted);
|
||||
margin-bottom: .25rem;
|
||||
}
|
||||
|
||||
.td-block ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.td-block li {
|
||||
position: relative;
|
||||
padding-left: 14px;
|
||||
font-size: .87rem;
|
||||
line-height: 1.45;
|
||||
color: var(--fitme-text);
|
||||
}
|
||||
|
||||
.td-block li:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: .55em;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 1px;
|
||||
background: var(--fitme-accent);
|
||||
}
|
||||
|
||||
.td-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1;
|
||||
color: var(--fitme-text-muted);
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Touch / small screens: a centred fixed card over a dimmed page. The "grows
|
||||
out of the tile" move is done in main.js with a FLIP animation instead of
|
||||
the clip-path, since the card no longer sits on top of the tile. */
|
||||
@media (max-width: 767px), (hover: none) {
|
||||
.trainer-detail,
|
||||
.trainer-detail.td-flip {
|
||||
position: fixed;
|
||||
top: var(--td-top, 20vh);
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
width: auto;
|
||||
max-width: 560px;
|
||||
min-height: 0;
|
||||
margin: 0 auto;
|
||||
max-height: calc(100dvh - 48px);
|
||||
flex-direction: row;
|
||||
clip-path: none;
|
||||
transform: none;
|
||||
transform-origin: top left;
|
||||
transition: opacity .15s ease, visibility 0s linear .15s;
|
||||
}
|
||||
.trainer-item.is-open .trainer-detail {
|
||||
clip-path: none;
|
||||
transform: none;
|
||||
transition: opacity 0s, visibility 0s;
|
||||
}
|
||||
.trainer-item.is-open:after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 29;
|
||||
background: rgba(0, 0, 0, .55);
|
||||
}
|
||||
.td-close { display: flex; }
|
||||
.td-photo { flex-basis: 34%; border-width: 3px; }
|
||||
.td-photo img { min-height: 180px; }
|
||||
.td-body,
|
||||
.td-flip .td-body { max-height: calc(100dvh - 48px); padding: 16px 16px 16px 14px; transform: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
.trainer-detail,
|
||||
.trainer-detail.td-flip { flex-direction: column; }
|
||||
.td-photo { max-width: none; flex-basis: auto; }
|
||||
.td-photo img { min-height: 0; height: 160px; }
|
||||
}
|
||||
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
Mensalidades — cartões de preço
|
||||
══════════════════════════════════════════════════════════════════════════ */
|
||||
/* Same matte-black metal texture as the reviews section / footer, instead of
|
||||
the plain light surface — the two dark bands now bookend the page. */
|
||||
.pricing-section {
|
||||
padding: 90px 0 70px;
|
||||
background-color: #141517;
|
||||
background-image: var(--metal-layers);
|
||||
background-size: var(--metal-sizes);
|
||||
color: var(--fitme-ash);
|
||||
}
|
||||
|
||||
.pricing-section .section-title h2 { color: #fff; }
|
||||
.pricing-section .section-subtitle { color: var(--fitme-ash); }
|
||||
|
||||
.pricing-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
/* Spinning green edge (hover). --pc-a is a registered <angle>, so the conic
|
||||
gradient's start angle can be animated — an unregistered custom property
|
||||
would just jump. The gradient is centred on the mouse (--pc-x/--pc-y from
|
||||
main.js), so the sweep pivots around the pointer; the card also tilts and
|
||||
drifts toward it (--pc-rx/ry/mx/my), like the team cards.
|
||||
Layers behind the content: ::after = the blurred gradient (the glow),
|
||||
::before = the card face with a 2px border whose border-box shows the crisp
|
||||
gradient (padding-box/border-box backgrounds keep the rounded corners). */
|
||||
@property --pc-a {
|
||||
syntax: '<angle>';
|
||||
inherits: false;
|
||||
initial-value: 0deg;
|
||||
}
|
||||
|
||||
@keyframes pc-spin {
|
||||
to { --pc-a: 360deg; }
|
||||
}
|
||||
|
||||
.price-card {
|
||||
--pc-face: #fff;
|
||||
--pc-edge: var(--fitme-surface-2);
|
||||
--pc-bw: 1px;
|
||||
--pc-scale: 1;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
flex: 0 1 270px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--pc-face);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
padding: 30px 26px 26px;
|
||||
box-shadow: var(--fitme-shadow);
|
||||
transform: perspective(900px) rotateX(var(--pc-rx, 0deg)) rotateY(var(--pc-ry, 0deg))
|
||||
translate(var(--pc-mx, 0px), calc(var(--pc-my, 0px) + var(--pc-lift, 0px))) scale(var(--pc-scale));
|
||||
transition: transform .45s cubic-bezier(.34, 1.35, .64, 1), box-shadow var(--fitme-transition);
|
||||
}
|
||||
|
||||
/* While the pointer is on it, follow quickly instead of springing. */
|
||||
.price-card.pc-tracking {
|
||||
transition: transform .15s ease-out, box-shadow var(--fitme-transition);
|
||||
}
|
||||
|
||||
.price-card::before,
|
||||
.price-card::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.price-card::before {
|
||||
inset: calc(-1 * var(--pc-bw));
|
||||
z-index: -1;
|
||||
border-radius: calc(6px + var(--pc-bw));
|
||||
border: var(--pc-bw) solid transparent;
|
||||
background:
|
||||
linear-gradient(var(--pc-face), var(--pc-face)) padding-box,
|
||||
linear-gradient(var(--pc-edge), var(--pc-edge)) border-box;
|
||||
}
|
||||
|
||||
.price-card::after {
|
||||
inset: -3px;
|
||||
z-index: -2;
|
||||
border-radius: 10px;
|
||||
background: conic-gradient(from var(--pc-a) at var(--pc-x, 50%) var(--pc-y, 50%),
|
||||
rgba(var(--fitme-accent-rgb), 0) 0deg, rgba(var(--fitme-accent-rgb), 0) 150deg,
|
||||
var(--fitme-accent) 250deg, #f4ff9c 300deg, var(--fitme-accent) 330deg,
|
||||
rgba(var(--fitme-accent-rgb), 0) 360deg);
|
||||
filter: blur(12px);
|
||||
opacity: 0;
|
||||
transition: opacity .35s ease;
|
||||
}
|
||||
|
||||
.price-card:hover {
|
||||
--pc-lift: -4px;
|
||||
--pc-bw: 2px;
|
||||
box-shadow: var(--fitme-shadow-lg);
|
||||
}
|
||||
|
||||
.price-card:hover::before {
|
||||
background:
|
||||
linear-gradient(var(--pc-face), var(--pc-face)) padding-box,
|
||||
conic-gradient(from var(--pc-a) at var(--pc-x, 50%) var(--pc-y, 50%),
|
||||
rgba(var(--fitme-accent-rgb), 0) 0deg, rgba(var(--fitme-accent-rgb), 0) 150deg,
|
||||
var(--fitme-accent) 250deg, #f4ff9c 300deg, var(--fitme-accent) 330deg,
|
||||
rgba(var(--fitme-accent-rgb), 0) 360deg) border-box;
|
||||
animation: pc-spin 3.2s linear infinite;
|
||||
}
|
||||
|
||||
.price-card:hover::after {
|
||||
opacity: .75;
|
||||
animation: pc-spin 3.2s linear infinite;
|
||||
}
|
||||
|
||||
.price-card.is-featured {
|
||||
--pc-face: var(--fitme-dark-2);
|
||||
--pc-edge: var(--fitme-accent);
|
||||
--pc-bw: 2px;
|
||||
border-width: 2px;
|
||||
color: var(--fitme-ash);
|
||||
box-shadow: 0 18px 50px rgba(var(--fitme-dark-rgb), .28);
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.price-card.is-featured { --pc-scale: 1.04; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.price-card:hover::before,
|
||||
.price-card:hover::after { animation: none; }
|
||||
}
|
||||
|
||||
.pc-badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
white-space: nowrap;
|
||||
background: var(--fitme-accent);
|
||||
color: var(--fitme-dark);
|
||||
font-size: .72rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: .12em;
|
||||
text-transform: uppercase;
|
||||
padding: 6px 14px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.pc-badge i { font-size: .65rem; }
|
||||
|
||||
.price-card .pc-name {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 900;
|
||||
margin: 0 0 .35rem;
|
||||
color: var(--fitme-dark);
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-name { color: #fff; }
|
||||
|
||||
.pc-sub {
|
||||
font-size: .9rem;
|
||||
line-height: 1.45;
|
||||
color: var(--fitme-text-muted);
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-sub { color: var(--fitme-ash); }
|
||||
|
||||
.pc-price {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 4px 8px;
|
||||
padding: .9rem 0 1rem;
|
||||
border-top: 1px solid var(--fitme-surface-2);
|
||||
border-bottom: 1px solid var(--fitme-surface-2);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-price { border-color: rgba(255, 255, 255, .12); }
|
||||
|
||||
.pc-amount {
|
||||
font-size: 2.3rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
color: var(--fitme-dark);
|
||||
}
|
||||
|
||||
.pc-amount.is-text { font-size: 1.35rem; }
|
||||
|
||||
.price-card.is-featured .pc-amount { color: var(--fitme-accent); }
|
||||
|
||||
.pc-suffix {
|
||||
font-size: .88rem;
|
||||
color: var(--fitme-text-muted);
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-suffix { color: var(--fitme-ash); }
|
||||
|
||||
.pc-features {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 1.4rem;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.pc-features li {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: .92rem;
|
||||
line-height: 1.4;
|
||||
padding: 4px 0;
|
||||
color: var(--fitme-text-soft);
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-features li { color: #fff; }
|
||||
|
||||
.pc-features i {
|
||||
color: var(--fitme-accent-ink);
|
||||
margin-top: 3px;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.price-card.is-featured .pc-features i { color: var(--fitme-accent); }
|
||||
|
||||
.price-card .pc-cta {
|
||||
width: 100%;
|
||||
border: none;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.price-card:not(.is-featured) .pc-cta {
|
||||
background: var(--fitme-dark-2);
|
||||
color: var(--fitme-accent);
|
||||
}
|
||||
|
||||
.price-card:not(.is-featured) .pc-cta:hover {
|
||||
background: var(--fitme-dark-3);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
.pricing-section { padding: 60px 0 50px; }
|
||||
.price-card { flex-basis: 100%; }
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
Reviews Google
|
||||
══════════════════════════════════════════════════════════════════════════ */
|
||||
/* Matte black "gym machine" metal, shared by the reviews section and the
|
||||
footer: fine powder-coat grain (light + dark speckle from SVG turbulence),
|
||||
a soft diffuse sheen like light on a frame tube, and barely-there brushed
|
||||
streaks. All inline, no image requests. */
|
||||
:root {
|
||||
--metal-layers:
|
||||
radial-gradient(120% 70% at 22% 0%, rgba(255, 255, 255, .055), transparent 60%),
|
||||
linear-gradient(112deg, transparent 38%, rgba(255, 255, 255, .03) 50%, transparent 62%),
|
||||
repeating-linear-gradient(0deg, rgba(255, 255, 255, .012) 0 1px, transparent 1px 3px),
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .09 -.03'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='d'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='1' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .22 -.06'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23d)'/%3E%3C/svg%3E");
|
||||
--metal-sizes: 100% 100%, 100% 100%, 100% 3px, 180px 180px, 140px 140px;
|
||||
}
|
||||
|
||||
.reviews-section {
|
||||
padding: 90px 0 60px;
|
||||
background: var(--fitme-white);
|
||||
}
|
||||
|
||||
.reviews-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 6px 12px;
|
||||
margin: 1rem 0 0;
|
||||
color: var(--fitme-text-muted);
|
||||
}
|
||||
|
||||
.reviews-summary strong {
|
||||
font-size: 1.8rem;
|
||||
font-weight: 900;
|
||||
color: var(--fitme-text);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.rv-stars {
|
||||
color: #FBBC04;
|
||||
letter-spacing: 2px;
|
||||
font-size: .95rem;
|
||||
}
|
||||
|
||||
.reviews-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.review-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
background: var(--fitme-dark-2);
|
||||
border: 1px solid var(--fitme-dark-3);
|
||||
border-radius: 6px;
|
||||
padding: 28px 24px 24px;
|
||||
}
|
||||
|
||||
.rv-avatar {
|
||||
width: 84px;
|
||||
height: 84px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 3px solid var(--fitme-accent);
|
||||
background: var(--fitme-dark-3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: .8rem;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.rv-avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.rv-avatar span {
|
||||
font-size: 2rem;
|
||||
font-weight: 900;
|
||||
color: var(--fitme-accent);
|
||||
}
|
||||
|
||||
.rv-author {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.rv-author a { color: #fff; }
|
||||
.rv-author a:hover { color: var(--fitme-accent); }
|
||||
|
||||
.rv-author small {
|
||||
font-size: .78rem;
|
||||
font-weight: 400;
|
||||
color: var(--fitme-ash);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.rv-stars-lg {
|
||||
font-size: 1.3rem;
|
||||
letter-spacing: 3px;
|
||||
margin: .6rem 0 .2rem;
|
||||
}
|
||||
|
||||
.rv-text {
|
||||
margin: .6rem 0 0;
|
||||
font-size: .85rem;
|
||||
line-height: 1.55;
|
||||
color: var(--fitme-ash);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 6;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.reviews-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 18px;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
/* Plain text link — "Deixa a tua review" stays the one highlighted action
|
||||
(.site-btn), this is secondary. */
|
||||
.reviews-link {
|
||||
font-weight: 700;
|
||||
color: var(--fitme-text-soft);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.reviews-link:hover {
|
||||
color: var(--fitme-text);
|
||||
}
|
||||
|
||||
.reviews-attribution {
|
||||
margin: 1.2rem 0 0;
|
||||
text-align: center;
|
||||
font-size: .75rem;
|
||||
color: var(--fitme-text-muted);
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════════════
|
||||
Modalidades — animated icons
|
||||
The FitMe icon set is inlined as <svg class="mi" data-anim="…"> (see
|
||||
modalidade_icon_html()). Every drawable element has pathLength="1", so a
|
||||
stroke-dasharray of 1 lets the lines draw themselves: once when the card
|
||||
scrolls into view, again on hover / focus, and in the detail panel as it
|
||||
opens. On top of that each family has its own small movement:
|
||||
lift — weights going up (Pump, CrossFit, FBB, Core, Total Workout)
|
||||
punch — a jab (Fight, Bootcamp)
|
||||
breathe — slow in / out (Mind, Yoga, Pilates)
|
||||
bounce — hop with squash (Zumba, Jump, Pulse, Hybrid)
|
||||
flicker — flame (FitBurn)
|
||||
ride — pedalling rock (Cycling)
|
||||
run — running bob (Run3070, On Ramp, Localizada)
|
||||
══════════════════════════════════════════════════════════════════════════ */
|
||||
.ib-icon svg.mi {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
color: #141414;
|
||||
overflow: visible;
|
||||
transform-box: fill-box;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
|
||||
.mi [pathLength] {
|
||||
stroke-dasharray: 1;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
@keyframes mi-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
|
||||
@keyframes mi-draw-h { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
|
||||
|
||||
/* Draw-in once as the card appears (.revealed comes from the scroll observer). */
|
||||
.mod-card.revealed .mi [pathLength] {
|
||||
animation: mi-draw .9s cubic-bezier(.5, 0, .2, 1) both;
|
||||
}
|
||||
.mod-card.revealed .mi [pathLength]:nth-child(2) { animation-delay: .12s; }
|
||||
.mod-card.revealed .mi [pathLength]:nth-child(3) { animation-delay: .24s; }
|
||||
.mod-card.revealed .mi [pathLength]:nth-child(n+4) { animation-delay: .34s; }
|
||||
|
||||
/* Hover / focus / open panel: redraw (a second keyframe name restarts it). */
|
||||
.mod-card:hover .mi [pathLength],
|
||||
.mod-card:focus-visible .mi [pathLength],
|
||||
.mod-detail.is-open .mi [pathLength] {
|
||||
animation: mi-draw-h .6s cubic-bezier(.5, 0, .2, 1) both;
|
||||
}
|
||||
.mod-card:hover .mi [pathLength]:nth-child(2),
|
||||
.mod-detail.is-open .mi [pathLength]:nth-child(2) { animation-delay: .08s; }
|
||||
.mod-card:hover .mi [pathLength]:nth-child(n+3),
|
||||
.mod-detail.is-open .mi [pathLength]:nth-child(n+3) { animation-delay: .16s; }
|
||||
|
||||
@keyframes mi-lift {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
30% { transform: translateY(-6px); }
|
||||
55% { transform: translateY(1px); }
|
||||
75% { transform: translateY(-2px); }
|
||||
}
|
||||
@keyframes mi-punch {
|
||||
0%, 100% { transform: translateX(0) rotate(0); }
|
||||
25% { transform: translateX(-3px) rotate(-6deg); }
|
||||
45% { transform: translateX(7px) rotate(4deg); }
|
||||
65% { transform: translateX(-1px) rotate(0); }
|
||||
}
|
||||
@keyframes mi-breathe {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.13); }
|
||||
}
|
||||
@keyframes mi-bounce {
|
||||
0%, 100% { transform: translateY(0) scale(1, 1); }
|
||||
18% { transform: translateY(0) scale(1.12, .86); }
|
||||
50% { transform: translateY(-9px) scale(.94, 1.07); }
|
||||
80% { transform: translateY(0) scale(1.06, .94); }
|
||||
}
|
||||
@keyframes mi-flicker {
|
||||
0%, 100% { transform: scale(1) skewX(0); }
|
||||
20% { transform: scale(1.06, .93) skewX(-4deg); }
|
||||
40% { transform: scale(.95, 1.09) skewX(3deg); }
|
||||
60% { transform: scale(1.04, .97) skewX(-2deg); }
|
||||
80% { transform: scale(.98, 1.05) skewX(2deg); }
|
||||
}
|
||||
@keyframes mi-ride {
|
||||
0%, 100% { transform: translateX(0) rotate(0); }
|
||||
25% { transform: translateX(-2px) rotate(-5deg); }
|
||||
75% { transform: translateX(3px) rotate(3deg); }
|
||||
}
|
||||
@keyframes mi-run {
|
||||
0%, 100% { transform: translateY(0) rotate(0); }
|
||||
25% { transform: translateY(-4px) rotate(-6deg); }
|
||||
50% { transform: translateY(0) rotate(0); }
|
||||
75% { transform: translateY(-4px) rotate(6deg); }
|
||||
}
|
||||
|
||||
.mod-card:hover .mi, .mod-card:focus-visible .mi, .mod-detail.is-open .mi {
|
||||
animation-duration: .9s;
|
||||
animation-timing-function: cubic-bezier(.45, 0, .25, 1);
|
||||
animation-fill-mode: both;
|
||||
animation-delay: .1s;
|
||||
}
|
||||
.mod-card:hover .mi[data-anim="lift"], .mod-card:focus-visible .mi[data-anim="lift"], .mod-detail.is-open .mi[data-anim="lift"] { animation-name: mi-lift; }
|
||||
.mod-card:hover .mi[data-anim="punch"], .mod-card:focus-visible .mi[data-anim="punch"], .mod-detail.is-open .mi[data-anim="punch"] { animation-name: mi-punch; animation-duration: .7s; animation-iteration-count: 2; }
|
||||
.mod-card:hover .mi[data-anim="breathe"], .mod-card:focus-visible .mi[data-anim="breathe"], .mod-detail.is-open .mi[data-anim="breathe"] { animation-name: mi-breathe; animation-duration: 1.8s; animation-iteration-count: 2; }
|
||||
.mod-card:hover .mi[data-anim="bounce"], .mod-card:focus-visible .mi[data-anim="bounce"], .mod-detail.is-open .mi[data-anim="bounce"] { animation-name: mi-bounce; animation-duration: .75s; animation-iteration-count: 2; }
|
||||
.mod-card:hover .mi[data-anim="flicker"], .mod-card:focus-visible .mi[data-anim="flicker"], .mod-detail.is-open .mi[data-anim="flicker"] { animation-name: mi-flicker; animation-iteration-count: 3; transform-origin: 50% 100%; }
|
||||
.mod-card:hover .mi[data-anim="ride"], .mod-card:focus-visible .mi[data-anim="ride"], .mod-detail.is-open .mi[data-anim="ride"] { animation-name: mi-ride; animation-duration: .6s; animation-iteration-count: 3; }
|
||||
.mod-card:hover .mi[data-anim="run"], .mod-card:focus-visible .mi[data-anim="run"], .mod-detail.is-open .mi[data-anim="run"] { animation-name: mi-run; animation-duration: .6s; animation-iteration-count: 3; }
|
||||
|
||||
/* Detail panel (desktop): icon + name start where they sit on the card, then
|
||||
glide to the vertical centre of the taller panel column as it opens
|
||||
(--md-pad-open from main.js). Phones centre it with their own layout. */
|
||||
@media (min-width: 768px) and (hover: hover) {
|
||||
.md-card {
|
||||
transition: padding-top .38s cubic-bezier(.4, 0, .2, 1);
|
||||
}
|
||||
.mod-detail.is-open .md-card {
|
||||
padding-top: var(--md-pad-open, var(--md-pad, 0px));
|
||||
transition: padding-top .55s cubic-bezier(.2, .9, .25, 1) .05s;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.ib-icon svg.mi { width: 34px; height: 34px; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.mi, .mi [pathLength] { animation: none !important; }
|
||||
}
|
||||
|
||||
/* ── Galeria — endless horizontal strip + lightbox (site/includes/gallery.php) ──
|
||||
Full-height photos alternate with 2x2 grids of four. The strip is rendered
|
||||
--gal-copies times and slides by exactly one copy, so the loop is seamless;
|
||||
it pauses on hover / focus. With "reduce motion" it is a plain swipeable row. */
|
||||
Full-height photos alternate with 2x2 grids of four. The strip is four copies
|
||||
long; main.js auto-scrolls it, supports click-and-drag / swipe, and jumps by
|
||||
exactly one copy to loop. */
|
||||
.gal-wrap {
|
||||
--gal-h: 420px;
|
||||
--gal-gap: 12px;
|
||||
overflow: hidden;
|
||||
overflow-x: auto; /* scrolled by main.js (auto-advance + drag) and by touch */
|
||||
overflow-y: hidden;
|
||||
scrollbar-width: none;
|
||||
margin: 0 0 70px;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
|
||||
mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
|
||||
}
|
||||
.gal-track {
|
||||
display: flex;
|
||||
width: max-content;
|
||||
animation: gal-scroll var(--gal-dur, 60s) linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
.gal-marquee:hover .gal-track,
|
||||
.gal-marquee:focus-within .gal-track { animation-play-state: paused; }
|
||||
@keyframes gal-scroll {
|
||||
to { transform: translateX(calc(-100% / var(--gal-copies, 2))); }
|
||||
}
|
||||
.gal-wrap::-webkit-scrollbar { display: none; }
|
||||
.gal-wrap.is-dragging { cursor: grabbing; }
|
||||
.gal-wrap img { -webkit-user-drag: none; }
|
||||
.gal-track { display: flex; width: max-content; }
|
||||
.gal-set { display: flex; flex: 0 0 auto; }
|
||||
.gal-unit {
|
||||
flex: 0 0 auto;
|
||||
@@ -3603,11 +4323,6 @@ h3.contact-title {
|
||||
|
||||
@media (max-width: 991px) { .gal-wrap { --gal-h: 340px; } }
|
||||
@media (max-width: 575px) { .gal-wrap { --gal-h: 260px; --gal-gap: 8px; margin-bottom: 48px; } }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.gal-wrap { overflow-x: auto; -webkit-mask-image: none; mask-image: none; scrollbar-width: thin; }
|
||||
.gal-track { animation: none; }
|
||||
.gal-set[aria-hidden="true"] { display: none; }
|
||||
}
|
||||
|
||||
.gal-link {
|
||||
display: block;
|
||||
@@ -3680,26 +4395,16 @@ h3.contact-title {
|
||||
.gal-link:hover::after { animation: none; }
|
||||
}
|
||||
|
||||
/* ── Photos at rest: 10% desaturated (team photos also get a light brand-colour
|
||||
tint), both lifted on hover. ──────────────────────────────────────────── */
|
||||
/* ── Photos at rest: 10% desaturated + a discreet brand-colour tint (gallery: a
|
||||
gradient fading to transparent; team: a light multiply layer), both lifted on
|
||||
hover. The tint follows each gym's brand colour. ───────────────────────── */
|
||||
.gal-link img { filter: saturate(.9); }
|
||||
.gal-link:hover img,
|
||||
.gal-link:focus-visible img { filter: saturate(1) brightness(1.05); }
|
||||
|
||||
|
||||
.trainer-item .trainer-pic img { filter: saturate(.9); transition: filter .45s ease; }
|
||||
.trainer-item .trainer-pic::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
background: color-mix(in srgb, var(--fitme-accent) 14%, #fff);
|
||||
mix-blend-mode: multiply;
|
||||
transition: opacity .45s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
.trainer-item .trainer-pic:hover img { filter: saturate(1); }
|
||||
.trainer-item .trainer-pic:hover::before { opacity: 0; }
|
||||
|
||||
/* Official YOURFIT lock-ups are wide (≈4.5:1) PNGs. In the square icon box they
|
||||
were squeezed to 44px wide while keeping their height attribute, so they came
|
||||
@@ -3888,3 +4593,25 @@ h3.contact-title {
|
||||
.icon-box-item.is-centered .ib-icon::after,
|
||||
.price-card.is-centered::before, .price-card.is-centered::after { animation: none; }
|
||||
}
|
||||
|
||||
/* ── Links: never underlined; hover = colour shift + glow ─────────────────────────
|
||||
Bootstrap underlines every <a>. Links with their own hover colour keep it (their
|
||||
selectors are more specific than the :where() below) and still get the glow.
|
||||
--link-hover is the readable brand shade for the background it sits on: the
|
||||
dark olive on light sections, the bright brand colour on the dark ones. */
|
||||
:root { --link-hover: var(--fitme-accent-ink); }
|
||||
.hero-section, .trainers-section, .pricing-section, .contact-section, .footer-section,
|
||||
.map-section, .event-preview-bar { --link-hover: var(--fitme-accent); }
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:where(:not(.site-btn, .gym-switch-btn, .gal-link, .skip-link, .splide__arrow, .nav-link, .navbar-brand, .td-close)) {
|
||||
transition: color .3s ease, text-shadow .3s ease;
|
||||
}
|
||||
a:where(:not(.site-btn, .gym-switch-btn, .gal-link, .skip-link, .splide__arrow, .nav-link, .navbar-brand, .td-close)):is(:hover, :focus-visible) {
|
||||
color: var(--link-hover);
|
||||
text-decoration: none;
|
||||
text-shadow: 0 0 10px rgba(var(--fitme-accent-rgb), .6), 0 0 22px rgba(var(--fitme-accent-rgb), .3);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
a { transition: none !important; }
|
||||
}
|
||||
@@ -787,3 +787,79 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
requestAnimationFrame(tick);
|
||||
});
|
||||
|
||||
/* ── Galeria: auto-scroll + click-and-drag ───────────────────────────────────
|
||||
The strip (.gal-wrap) is four identical copies long. It advances by itself,
|
||||
follows a mouse drag (touch uses the native swipe), pauses while you hover or
|
||||
hold it and resumes a moment after, and whenever the position leaves the two
|
||||
middle copies it jumps by exactly one copy — invisible, since every copy is the
|
||||
same. A drag longer than a few px swallows the click, so it doesn't open the
|
||||
lightbox. */
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
document.querySelectorAll('.gal-marquee').forEach(function (strip) {
|
||||
var wrap = strip.parentElement;
|
||||
var set = strip.querySelector('.gal-set');
|
||||
if (!wrap || !set) return;
|
||||
var loop = 0, pos = null, hold = false, resumeAt = 0, dragging = false, moved = 0, startX = 0, startLeft = 0, last = 0;
|
||||
var SPEED = 40; // px per second
|
||||
|
||||
function measure() { loop = set.offsetWidth; }
|
||||
function normalise() {
|
||||
if (!loop) return;
|
||||
if (wrap.scrollLeft >= loop * 2) wrap.scrollLeft -= loop;
|
||||
else if (wrap.scrollLeft < loop) wrap.scrollLeft += loop;
|
||||
}
|
||||
function start() { measure(); wrap.scrollLeft = loop; }
|
||||
start();
|
||||
window.addEventListener('load', start);
|
||||
window.addEventListener('resize', measure, { passive: true });
|
||||
wrap.addEventListener('scroll', normalise, { passive: true });
|
||||
|
||||
wrap.addEventListener('mouseenter', function () { hold = true; });
|
||||
wrap.addEventListener('mouseleave', function () { if (!dragging) { hold = false; resumeAt = performance.now() + 600; } });
|
||||
wrap.addEventListener('focusin', function () { hold = true; });
|
||||
wrap.addEventListener('focusout', function () { hold = false; });
|
||||
wrap.addEventListener('touchstart', function () { hold = true; }, { passive: true });
|
||||
wrap.addEventListener('touchend', function () { hold = false; resumeAt = performance.now() + 1800; }, { passive: true });
|
||||
|
||||
wrap.addEventListener('pointerdown', function (e) {
|
||||
if (e.pointerType === 'touch' || e.button !== 0) return;
|
||||
dragging = true; moved = 0;
|
||||
startX = e.clientX; startLeft = wrap.scrollLeft;
|
||||
wrap.classList.add('is-dragging');
|
||||
wrap.setPointerCapture(e.pointerId);
|
||||
});
|
||||
wrap.addEventListener('pointermove', function (e) {
|
||||
if (!dragging) return;
|
||||
var dx = e.clientX - startX;
|
||||
moved = Math.max(moved, Math.abs(dx));
|
||||
wrap.scrollLeft = startLeft - dx;
|
||||
});
|
||||
function endDrag(e) {
|
||||
if (!dragging) return;
|
||||
dragging = false;
|
||||
wrap.classList.remove('is-dragging');
|
||||
try { wrap.releasePointerCapture(e.pointerId); } catch (err) {}
|
||||
resumeAt = performance.now() + 1200;
|
||||
}
|
||||
wrap.addEventListener('pointerup', endDrag);
|
||||
wrap.addEventListener('pointercancel', endDrag);
|
||||
// After a real drag, the click that follows must not open the lightbox.
|
||||
wrap.addEventListener('click', function (e) {
|
||||
if (moved > 5) { e.preventDefault(); e.stopPropagation(); moved = 0; }
|
||||
}, true);
|
||||
|
||||
function tick(now) {
|
||||
requestAnimationFrame(tick);
|
||||
var dt = last ? Math.min(now - last, 100) : 16; last = now;
|
||||
if (reduce || document.hidden || dragging || hold || now < resumeAt) { pos = null; return; }
|
||||
// scrollLeft only keeps whole pixels, so a ~0.6px/frame step would round
|
||||
// away: carry the fraction in our own float and write it back.
|
||||
if (pos === null || Math.abs(wrap.scrollLeft - pos) > 2) pos = wrap.scrollLeft;
|
||||
pos += SPEED * dt / 1000;
|
||||
wrap.scrollLeft = pos;
|
||||
}
|
||||
requestAnimationFrame(tick);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user