Files
fitme3070.pt/site/assets/css/style.css
T
andre 725f5b9c26 feat(site): per-gym SEO texts, event gym selector, hero/navbar polish
- Generated SEO titles/descriptions per gym; gym seo fields override each on its own
- Keywords, author, og:site_name, favicon and JSON-LD logo follow the gym
- CrossFit page 404s before output for gyms without a box
- Events: «Mostrar em» gym selector; event page uses its gym's brand
- Hero event button text colour from the event colour (--ev-on)
- Navbar bottom line stops at the other-gym head (--switch-w)
- Diagonal hero blur mask; remove the trial link
2026-10-26 12:15:37 +00:00

4959 lines
146 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ==========================================================================
FitMe 3070 — Bootstrap 5 Override Stylesheet
Base: Bootstrap 5.3.3 (vendor/bootstrap5/)
Palette: Neon Moss (#C2D500) accent over a Void Black (#0B0B0D) → Charcoal
Slate (#3D403E) dark ramp, with Ash Silver (#B8B9BE) + Arctic White
(#F7F8FA) for light/secondary. Treat the green as a spotlight (~10%).
========================================================================== */
/* Roboto, self-hosted (variable font, latin subset) — no Google Fonts request. */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url('../fonts/roboto/roboto-latin.woff2') format('woff2');
}
/* ── Design Tokens ─────────────────────────────────────────────────────────────
Brand palette — "Neon Moss" on a Void-Black → Charcoal-Slate dark ramp, with
an Ash-Silver / Arctic-White light toolkit. Darks carry a cool, greenish-
neutral undertone so they sit flush with the vibrant green. */
:root {
/* The Hero — Neon Moss. Spotlight only (≈10%): CTAs, active states, accents. */
--fitme-accent: #C2D500;
--fitme-accent-rgb: 194, 213, 0;
--fitme-accent-dark: #A6B600;
/* Text-on-light variant: #C2D500/#A6B600 are only ~1.6–2.1:1 on white/surface
(WCAG AA needs 4.5:1), so text uses this darker olive. Bright accent stays
for dark sections and button backgrounds. */
--fitme-accent-ink: #667000;
/* readable text colour on top of --fitme-accent (a gym's brand colour may be dark) */
--fitme-on-accent: #0B0B0D;
/* deeper moss for hover / active */
/* The Anchor — Void Black, and a cool ramp lifting toward Charcoal Slate. */
--fitme-dark: #0B0B0D;
/* Void Black — primary dark canvas */
--fitme-dark-2: #16181A;
/* lifted void (sections / overlays) */
--fitme-dark-3: #26292A;
/* structural dark (frames, pills) */
--fitme-mid: #3D403E;
/* Charcoal Slate — cards / structure */
--fitme-slate: #3D403E;
/* Charcoal Slate (alias) */
--fitme-dark-rgb: 11, 11, 13;
/* Ash Silver — secondary text, borders, inactive UI on dark backgrounds. */
--fitme-ash: #B8B9BE;
--fitme-ash-rgb: 184, 185, 190;
/* Arctic White light toolkit (cool, crisp). */
--fitme-white: #ffffff;
--fitme-surface: #F7F8FA;
/* Arctic White — light section canvas */
--fitme-surface-2: #ECEEF2;
--fitme-surface-dark: #DDE0E6;
/* Text on light surfaces. */
--fitme-text: #0B0B0D;
/* Void Black */
--fitme-text-soft: #3D403E;
/* Charcoal Slate */
--fitme-text-muted: #6B6E73;
/* readable muted gray */
--fitme-nav-bg: rgba(247, 248, 250, 0.68);
--fitme-shadow: 0 2px 20px rgba(11, 11, 13, .07);
--fitme-shadow-lg: 0 8px 40px rgba(11, 11, 13, .13);
--fitme-radius: 2px;
--fitme-transition: 0.15s ease;
}
/* ── Bootstrap 4 Overrides ─────────────────────────────────────────────────── */
/* Make Bootstrap rows use our gutters */
.row {
margin-left: 0;
margin-right: 0;
}
.container>.row {
margin-left: -0.75rem;
margin-right: -0.75rem;
}
/* Remove default outlines, use our focus ring */
input:focus,
select:focus,
button:focus,
textarea:focus {
outline: none;
}
a:hover,
a:focus {
text-decoration: none;
outline: none;
}
ul,
ol {
padding: 0;
margin: 0;
}
img {
max-width: 100%;
}
/* ── Skip to content (accessibility) ───────────────────────────────────────── */
.skip-link {
position: absolute;
top: 8px;
left: 16px;
z-index: 9999;
background: var(--fitme-accent);
color: var(--fitme-dark);
padding: 12px 20px;
border-radius: var(--fitme-radius);
font-weight: 700;
font-size: .9rem;
text-decoration: none;
transform: translateY(-108px);
transition: transform .2s;
}
.skip-link:focus {
transform: translateY(0);
}
/* ── Focus ring (accessibility) ────────────────────────────────────────────── */
:focus-visible {
outline: 3px solid var(--fitme-accent) !important;
outline-offset: 2px;
}
/* Reset for elements with their own focus styles */
.site-btn:focus-visible,
.cta-btn:focus-visible {
outline-color: var(--fitme-dark) !important;
}
/* ── Touch target minimum (WCAG 2.5.5) ─────────────────────────────────────── */
@media (pointer: coarse) {
.nav-link,
.footer-menu li a,
.contact-info-warp a,
.footer-widget a {
min-height: 44px;
display: inline-flex;
align-items: center;
}
}
/* ── Base & Typography ─────────────────────────────────────────────────────── */
html {
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: 'Roboto', 'PT Sans', -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 1rem;
font-weight: 400;
line-height: 1.6;
color: var(--fitme-text);
background: var(--fitme-white);
overflow-x: hidden;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 .5em;
color: var(--fitme-text);
font-weight: 700;
line-height: 1.15;
text-transform: uppercase;
letter-spacing: -.02em;
}
h1 {
font-size: 4.375rem;
}
/* 70px */
h2 {
font-size: 2.25rem;
}
/* 36px */
h3 {
font-size: 1.875rem;
}
/* 30px */
h4 {
font-size: 1.5rem;
}
/* 24px */
h5 {
font-size: 1.125rem;
}
/* 18px */
h6 {
font-size: 1rem;
}
p {
font-size: 1rem;
color: var(--fitme-text-soft);
line-height: 1.8;
margin-bottom: 1rem;
}
/* ── Utility Classes ───────────────────────────────────────────────────────── */
.float_right {
float: right;
}
.section-title {
margin-bottom: 1.5rem;
}
.section-title h2 {
/* Fluid: replaces 3 step values (2rem @768-991, 1.6rem @<=767, 1.4rem @<=479)
with one clamp anchored at 768px (2rem) -> 992px (2.5rem, the old desktop
value), audit 4.5. */
font-size: clamp(1.4rem, calc(.2857rem + 3.5714vw), 2.5rem);
line-height: 1.2;
margin-bottom: .5rem;
}
.section-title h2 span {
color: var(--fitme-accent);
}
.section-title p {
color: var(--fitme-text-muted);
}
.set-bg {
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
.text-white h1,
.text-white h2,
.text-white h3,
.text-white h4,
.text-white h5,
.text-white h6,
.text-white p,
.text-white span,
.text-white li,
.text-white a {
color: #fff;
}
/* Section anchor offset for sticky nav */
section[id] {
scroll-margin-top: 72px;
}
/* ── Fade-in animation (used by preloader + hero) ──────────────────────────── */
.fade-in {
animation: fitmeFadeIn .8s ease forwards;
opacity: 0;
}
/* Reveal on scroll (IntersectionObserver) */
.revealed {
animation: fitmeReveal .6s ease forwards;
opacity: 0;
}
@keyframes fitmeFadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fitmeReveal {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ── Buttons ───────────────────────────────────────────────────────────────── */
.site-btn {
position: relative;
z-index: 0;
text-decoration: none; /* Bootstrap underlines every <a>; buttons never */
display: inline-block;
border: none;
font-size: 1rem;
font-weight: 700;
min-width: 200px;
padding: 16px 36px;
background: var(--fitme-accent);
color: var(--fitme-on-accent);
text-align: center;
cursor: pointer;
border-radius: var(--fitme-radius);
transition: background var(--fitme-transition), transform var(--fitme-transition);
text-transform: uppercase;
letter-spacing: .5px;
}
.site-btn:hover {
background: var(--fitme-accent-dark);
color: var(--fitme-on-accent);
transform: translateY(-1px);
box-shadow: 0 4px 16px rgba(var(--fitme-accent-rgb), .35);
}
.site-btn.sb-dark {
background: var(--fitme-dark-2);
color: var(--fitme-accent);
}
.site-btn.sb-dark:hover {
background: var(--fitme-dark-3);
}
.site-btn.sb-line {
background: transparent;
border: 2px solid var(--fitme-dark-2);
color: var(--fitme-dark-2);
padding: 14px 36px;
}
.site-btn.sb-line:hover {
background: var(--fitme-dark-2);
color: var(--fitme-accent);
}
/* ── Bootstrap Nav Overrides ───────────────────────────────────────────────── */
.nav-link {
font-weight: 700;
font-size: .875rem;
letter-spacing: .02em;
color: var(--fitme-text);
margin: 0 .6rem !important;
transition: color var(--fitme-transition);
position: relative;
}
/* ── Brand slash (template) ──────────────────────────────────────────────────
The cut of the "in" box in the FitMe in logo: top-left and bottom-right
corners sliced off. Put class="fx-slash" on any element (or add a pseudo
element to this list) instead of writing the polygon again; --slash sets the
cut size. .fx-slash-start cuts the left side only (open to the right edge). */
:root { --slash: 4px; }
.fx-slash,
.nav-link::after,
.section-title.deco h2::after {
clip-path: polygon(var(--slash) 0, 100% 0, calc(100% - var(--slash)) 100%, 0 100%);
}
.fx-slash-start {
clip-path: polygon(var(--slash) 0, 100% 0, 100% 100%, 0 100%);
}
/* Underline: a short bar with the brand slash, tucked right under the text. */
.nav-link:after {
content: '';
position: absolute;
bottom: 3px;
left: var(--bs-navbar-nav-link-padding-x, .5rem);
right: var(--bs-navbar-nav-link-padding-x, .5rem);
height: 4px;
background: var(--fitme-accent);
transform: scaleX(0);
transform-origin: left;
transition: transform var(--fitme-transition);
}
.nav-link:hover:after,
.nav-item.active .nav-link:after {
transform: scaleX(1);
}
.nav-link:hover,
.nav-item.active .nav-link {
color: var(--fitme-dark);
background: transparent !important;
}
/* ── CrossFit nav pill (follows the gym's brand colour) ─────────────────────────────────────────────────────── */
.crossfit-nav-link {
/* 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);
--slash: 8px; /* shape: .fx-slash on the link (navbar.php) */
padding: 6px 16px !important;
transition: background-color .4s ease, color .4s ease, border-color .4s ease;
}
.crossfit-nav-link:after {
display: none;
}
/* 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: color-mix(in srgb, var(--fitme-accent) 10%, #000) !important;
border-color: var(--fitme-accent);
color: #fff !important;
}
/* ── Other-gym button (right end of the navbar) ────────────────────────────── */
.gym-switch-btn {
position: relative;
z-index: 0;
display: inline-block;
background: var(--fitme-accent);
color: var(--fitme-on-accent);
font-weight: 700;
text-transform: uppercase;
letter-spacing: .5px;
text-decoration: none;
white-space: nowrap;
border: 2px solid var(--fitme-accent);
border-radius: var(--fitme-radius);
padding: 6px 16px;
transition: background-color var(--fitme-transition), color var(--fitme-transition);
}
.gym-switch-btn { display: inline-flex; align-items: center; gap: .5rem; }
.gym-switch-logo {
display: block;
height: 30px;
width: auto;
max-width: 130px;
object-fit: contain;
}
/* ── Button hover: the same spinning edge as the Mensalidades cards ───────────
Reuses their registered --pc-a angle + pc-spin keyframes. On hover the face
turns near-black (10% brand colour) with WHITE text, lifts a few px, and a
conic brand-colour edge sweeps round it with a soft blurred glow behind.
::before = the face + 2px edge, ::after = the glow. --elb is the element's own
border (sb-line / sb-ghost), so the ring always sits outside it. */
:is(.site-btn, .gym-switch-btn) {
--btn-face: color-mix(in srgb, var(--fitme-accent) 10%, #000);
--elb: 0px;
--ring: 2px;
}
.site-btn.sb-line, .site-btn.sb-ghost { --elb: 2px; }
/* Slower, softer lift (the face colour fades with it). */
.site-btn.site-btn,
.gym-switch-btn {
transition: transform .5s cubic-bezier(.22, .8, .3, 1), background-color .4s ease, color .4s ease, border-color .4s ease;
}
.site-btn::before, .site-btn::after,
.gym-switch-btn::before, .gym-switch-btn::after {
content: '';
position: absolute;
pointer-events: none;
border-radius: calc(var(--fitme-radius) + var(--ring) + var(--elb));
opacity: 0;
transition: opacity .45s ease;
}
.site-btn::before, .gym-switch-btn::before {
inset: calc(-1 * (var(--ring) + var(--elb)));
z-index: -1;
border: var(--ring) solid transparent;
background:
var(--noise) 0 0 / 155px padding-box,
linear-gradient(var(--btn-face), var(--btn-face)) padding-box,
conic-gradient(from var(--pc-a), 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;
background-blend-mode: overlay, normal, normal;
}
.site-btn::after, .gym-switch-btn::after {
inset: calc(-1 * (var(--ring) + var(--elb)) - 2px);
z-index: -2;
background: conic-gradient(from var(--pc-a), 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(10px);
}
.site-btn.site-btn:is(:hover, :focus-visible),
.gym-switch-btn:is(:hover, :focus-visible) {
background: var(--btn-face);
border-color: transparent;
color: #fff;
transform: translateY(-3px);
box-shadow: none;
}
.site-btn:is(:hover, :focus-visible)::before,
.gym-switch-btn:is(:hover, :focus-visible)::before { opacity: 1; animation: pc-spin 3.2s linear infinite; }
.site-btn:is(:hover, :focus-visible)::after,
.gym-switch-btn:is(:hover, :focus-visible)::after { opacity: .75; animation: pc-spin 3.2s linear infinite; }
@media (prefers-reduced-motion: reduce) {
.site-btn:is(:hover, :focus-visible)::before, .site-btn:is(:hover, :focus-visible)::after,
.gym-switch-btn:is(:hover, :focus-visible)::before, .gym-switch-btn:is(:hover, :focus-visible)::after { animation: none; }
}
/* With a logo the button shows the gym's wordmark in its own colours straight
on the navbar (no face, like the main logo), framed by a thin brand-colour
outline; the name is the image's alt. On hover nothing fills in behind the
logo: ::before is masked down to just its ring, so only the spinning edge
shows. */
.gym-switch-btn--logo,
.gym-switch-btn--logo:is(:hover, :focus-visible) {
background: transparent;
}
.gym-switch-btn--logo {
padding: 4px 12px;
border-width: 1px;
}
.gym-switch-btn--logo::before {
background: conic-gradient(from var(--pc-a), 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;
-webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#000 0 0) padding-box exclude, linear-gradient(#000 0 0);
}
/* No glow either: blurred brand colour behind a dark-red wordmark muddies it.
A thin light halo keeps the logo legible over whatever shows through the
frosted navbar. */
.gym-switch-btn--logo::after,
.gym-switch-btn--logo:is(:hover, :focus-visible)::after { display: none; }
/* Thin dark outline, not a white halo: a white glow washed out the lime FitMe 3070 logo. */
.gym-switch-btn--logo .gym-switch-logo { filter: url(#pt-noise) drop-shadow(0 0 .6px rgba(0, 0, 0, .55)) drop-shadow(0 1px 1px rgba(0, 0, 0, .18)); }
/* ── Sticky Navbar ─────────────────────────────────────────────────────────── */
.navbar-toggler {
min-width: 44px;
min-height: 44px;
}
.header-section {
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
-webkit-backdrop-filter: blur(14px) saturate(180%) brightness(1.06);
backdrop-filter: blur(14px) saturate(180%) brightness(1.06);
background: var(--fitme-nav-bg);
border-bottom: 1px solid rgba(0, 0, 0, .04);
/* glass edge: a bright specular line on top, a faint inner rim below */
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7), inset 0 -1px 0 rgba(255, 255, 255, .25);
}
/* Liquid glass (Chromium only: the only engine that runs an SVG filter in
backdrop-filter). #nav-glass (include.php) bends the page behind the bar
with smooth low-frequency displacement before the blur, so it reads as
rippled glass, not just frost; the tint is lighter so the bending shows.
-webkit-app-region is a Chromium-only property, used as the engine test;
Safari/Firefox keep the plain frosted blur above. */
@supports (-webkit-app-region: drag) {
.header-section {
backdrop-filter: url(#nav-glass) blur(6px) saturate(180%) brightness(1.06);
background: rgba(247, 248, 250, .5);
}
}
/* Bottom edge: the Mensalidades sweep in the current gym's colour (:root
--fitme-accent from gym_brand_css()), always on and much slower. A wide
gradient slides along a 2px line (::after); ::before is the same strip
blurred, the soft glow under it. Same peak/fade shape as the cards. */
.header-section::before,
.header-section::after {
content: '';
position: absolute;
left: 0;
right: var(--switch-w, 0px); /* ends where the other-gym head starts (navbar.php JS) */
bottom: -1px;
height: 2px;
pointer-events: none;
background: linear-gradient(90deg,
rgba(var(--fitme-accent-rgb), .15) 0%, rgba(var(--fitme-accent-rgb), .15) 30%,
var(--fitme-accent) 42%, color-mix(in srgb, var(--fitme-accent) 45%, #fff) 50%, var(--fitme-accent) 58%,
rgba(var(--fitme-accent-rgb), .15) 70%, rgba(var(--fitme-accent-rgb), .15) 100%)
0 0 / 300% 100% repeat-x;
animation: nav-sweep 14s linear infinite;
}
.header-section::before {
height: 6px;
bottom: -4px;
filter: blur(6px);
opacity: .6;
}
@keyframes nav-sweep {
to { background-position: 150% 0; }
}
/* Bar layout. Desktop: the links are centred on the full bar width, the logo
sits out of flow at the left and the other-gym buttons out of flow at the
right, vertically centred on the whole header. On the home page
(.has-center-logo) the header starts taller with a big centred copy of the
logo (.navbar-brand-hero, .is-top); on scroll the bar shrinks, the big logo
fades out and the left one fades in (navbar.php toggles .is-top). */
.header-section .navbar { padding: 0 0 0 1rem; }
.navbar-brand img {
width: 150px;
height: auto;
}
.navbar-brand-hero { display: none; }
/* Match head paint, shared by the desktop bar end and the mobile menu band
(geometry per breakpoint below): everything in the OTHER gym's brand (its
vars are inline on .gym-switch): a strip in its accent on the slashed edge,
a face a shade darker so the strip reads, its logo in that gym's on-accent
ink. */
.header-section .gym-switch::before,
.header-section .gym-switch::after {
content: '';
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
}
.header-section .gym-switch::before { background: var(--fitme-accent); }
/* the logo in that gym's on-accent ink (dark on lime, white on red) */
.header-section .gym-switch .gym-switch-btn--logo .gym-switch-logo {
filter: url(#pt-noise) brightness(0) drop-shadow(0 1px 0 rgba(255, 255, 255, .25));
}
.header-section .gym-switch--light-ink .gym-switch-btn--logo .gym-switch-logo {
filter: url(#pt-noise) brightness(0) invert(1) drop-shadow(0 1px 1px rgba(0, 0, 0, .35));
}
/* the hover ring would vanish on its own accent: draw it in the ink */
.header-section .gym-switch .gym-switch-btn--logo { border-color: rgba(11, 11, 13, .35); }
.header-section .gym-switch--light-ink .gym-switch-btn--logo { border-color: rgba(255, 255, 255, .45); }
@media (min-width: 992px) {
.header-section .navbar {
padding: 0;
transition: padding-top .5s cubic-bezier(.4, 0, .2, 1);
}
.header-section .navbar-brand {
position: absolute;
z-index: 1;
left: 1rem;
top: 50%;
margin: 0;
transform: translate(0, -50%);
}
.header-section .navbar-brand,
.navbar-brand-hero {
transition: opacity .45s ease, visibility .45s;
}
.has-center-logo .navbar-brand-hero {
display: block;
position: absolute;
z-index: 1;
left: 50%;
top: 12px;
transform: translateX(-50%);
opacity: 0;
visibility: hidden;
}
/* capped height too: the CrossFit logo is taller and would cover the links */
.navbar-brand-hero img { width: auto; height: 52px; max-width: none; }
.header-section .navbar-collapse {
min-height: 58px;
align-items: center;
}
.header-section .gym-switch { position: absolute; } /* the match head, below */
.header-section.is-top .navbar { padding-top: 62px; } /* room for the 180px logo */
/* Match head: the right end of the bar is a block behind the other-gym
button, its left side cut on the same slash as the underlines (the bar is
the matchstick, this is the head). It is painted in the OTHER gym's brand
(navbar.php puts its vars on .gym-switch), a glimpse into that site: its
accent strip on the cut, a face a shade darker and a shadow just inside it.
::before = strip, ::after = head. */
.header-section .gym-switch {
--slash: 22px;
top: 0;
bottom: 0;
right: 0;
transform: none;
z-index: 1;
align-items: center;
padding: 0 .85rem 0 calc(var(--slash) + .85rem) !important;
}
.header-section .gym-switch::before,
.header-section .gym-switch::after {
clip-path: polygon(var(--slash) 0, 100% 0, 100% 100%, 0 100%); /* .fx-slash-start */
}
.header-section .gym-switch::before { left: -5px; }
.header-section .gym-switch::after {
background:
radial-gradient(70% 90% at 10% 50%, rgba(0, 0, 0, .28), transparent 70%),
linear-gradient(180deg, var(--fitme-accent-dark), color-mix(in srgb, var(--fitme-accent-dark) 82%, #000));
}
.header-section.is-top .navbar-brand { opacity: 0; visibility: hidden; }
.header-section.is-top .navbar-brand-hero { opacity: 1; visibility: visible; }
/* keep the centred hero content (event card) clear of the taller top bar */
.hero-section { padding-top: 120px; }
}
@media (prefers-reduced-motion: reduce) {
.header-section .navbar, .header-section .navbar-brand, .navbar-brand-hero { transition: none; }
}
/* Mobile/tablet menu: the open collapse fills the screen below the bar, links
and gym buttons centred both ways, fading in and out. It is position:absolute
(top:100% of the .navbar), not fixed: the header's backdrop-filter makes the
header the containing block for fixed children anyway. Links shrink to their
text so the underline is only as wide as the word. */
@media (max-width: 991.98px) {
.header-section .navbar-collapse {
position: absolute;
top: 100%;
left: 0;
right: 0;
height: calc(100dvh - var(--nav-h, 60px)) !important;
overflow-y: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 1.5rem;
transition: opacity .3s ease;
}
.header-section .navbar-collapse:not(.show):not(.collapsing) { display: none; }
.header-section .navbar-collapse.collapsing { opacity: 0; transition: opacity .3s ease; }
.header-section .navbar-nav { align-items: center; gap: .25rem; }
.header-section .navbar-nav .nav-link { font-size: 1.25rem; margin: 0 !important; }
.header-section .navbar-nav .nav-link::after { left: 0; right: 0; } /* no side padding here */
/* the match head as a band across the bottom of the menu, its top edge on the slash */
.header-section .navbar-collapse { padding-bottom: 96px; }
.header-section .gym-switch {
--slash: 18px;
justify-content: center;
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
padding: calc(var(--slash) + .9rem) 1rem 1.1rem !important;
}
.header-section .gym-switch::before,
.header-section .gym-switch::after { clip-path: polygon(0 var(--slash), 100% 0, 100% 100%, 0 100%); }
.header-section .gym-switch::before { top: -5px; }
.header-section .gym-switch::after {
background:
radial-gradient(90% 80% at 50% 0, rgba(0, 0, 0, .28), transparent 70%),
linear-gradient(180deg, var(--fitme-accent-dark), color-mix(in srgb, var(--fitme-accent-dark) 82%, #000));
}
}
@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) {
.header-section .navbar-collapse, .header-section .navbar-collapse.collapsing { transition: none; }
}
@media (prefers-reduced-motion: reduce) {
.header-section::before, .header-section::after { animation: none; }
}
.site-logo {
max-width: 150px;
padding: 12px 0;
}
.header-right {
float: right;
padding: 0 !important;
width: auto;
}
.header-right .hr-box {
display: flex;
align-items: center;
gap: .5rem;
padding: 0 1.2rem;
height: 10vh;
background: rgba(var(--fitme-accent-rgb), .12);
color: var(--fitme-text);
font-size: .85rem;
border-radius: 0;
transition: background var(--fitme-transition);
}
.header-right .hr-box:hover {
background: rgba(var(--fitme-accent-rgb), .22);
}
.header-right .hr-box .icon {
font-size: 1.5rem;
color: var(--fitme-accent);
}
.header-right .hr-box h6 {
margin: 0;
font-size: .8rem;
font-weight: 700;
color: var(--fitme-text);
overflow: hidden;
}
.header-right a {
color: var(--fitme-text);
}
/* ── Hero ──────────────────────────────────────────────────────────────────── */
.hero-section {
position: relative;
min-height: 100dvh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
background-color: var(--fitme-dark);
overflow: hidden;
}
/* Depth gradient — darkens top for nav readability, lifts mid-section */
.hero-section:before {
content: '';
position: absolute;
inset: 0;
z-index: 1;
background:
linear-gradient(180deg,
rgba(0, 0, 0, 0.65) 0%,
rgba(0, 0, 0, 0.40) 25%,
rgba(0, 0, 0, 0.15) 50%,
rgba(0, 0, 0, 0.30) 75%,
rgba(0, 0, 0, 0.55) 100%);
}
/* Neon-Moss grounding accent at the base of the hero. One clean diagonal edge
(no jagged peak) echoes the brand's straight-line language; the colour fades
upward and stays low-opacity so the green reads as a spotlight, not a wash. */
.hero-section:after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 72%;
z-index: 1;
pointer-events: none;
background:
/* soft glow grounding the base, slightly left of centre */
radial-gradient(62% 62% at 30% 104%, rgba(var(--fitme-accent-rgb), 0.22) 0%, transparent 70%),
/* gentle upward fade so only the lower hero is tinted */
linear-gradient(180deg, transparent 46%, rgba(var(--fitme-accent-rgb), 0.13) 100%);
/* single straight diagonal top edge, rising to the right */
clip-path: polygon(0 28%, 100% 0, 100% 100%, 0 100%);
}
.hero-section .container {
z-index: 2;
}
/* Frosted band: the hero photo is blurred at full strength along a horizontal
line through the text and fades to sharp (0) outward, up and down — a backdrop
blur masked by a vertical gradient. ::before is the blur, ::after the frost:
a faint brand-colour (green) veil plus fine grain, same mask. Both sit behind the text
(z-index -1 in the container's stacking context) and above the photo. */
.hero-section .container::before,
.hero-section .container::after {
content: '';
position: absolute; /* the container is static, so these fill the hero */
inset: 0;
z-index: -1;
pointer-events: none;
-webkit-mask-image: linear-gradient(to bottom, transparent 18%, rgba(0, 0, 0, .55) 36%, #000 50%, rgba(0, 0, 0, .55) 64%, transparent 82%);
mask-image: linear-gradient(to bottom, transparent 18%, rgba(0, 0, 0, .55) 36%, #000 50%, rgba(0, 0, 0, .55) 64%, transparent 82%);
}
/* The blur fades in diagonally: lightest at the top left, full at the bottom
right (second mask layer, intersected with the band above). */
.hero-section .container::before {
-webkit-mask-image: linear-gradient(to bottom, transparent 18%, rgba(0, 0, 0, .55) 36%, #000 50%, rgba(0, 0, 0, .55) 64%, transparent 82%),
linear-gradient(135deg, rgba(0, 0, 0, .15) 15%, #000 75%);
mask-image: linear-gradient(to bottom, transparent 18%, rgba(0, 0, 0, .55) 36%, #000 50%, rgba(0, 0, 0, .55) 64%, transparent 82%),
linear-gradient(135deg, rgba(0, 0, 0, .15) 15%, #000 75%);
-webkit-mask-composite: source-in;
mask-composite: intersect;
-webkit-backdrop-filter: blur(22px) saturate(1.1);
backdrop-filter: blur(22px) saturate(1.1);
opacity: .8;
}
.hero-section .container::after {
background:
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='f' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.15' numOctaves='3' seed='12' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.6' intercept='-.2'/%3E%3CfeFuncG type='linear' slope='1.6' intercept='-.2'/%3E%3CfeFuncB type='linear' slope='1.6' intercept='-.2'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)' opacity='.34'/%3E%3C/svg%3E") 0 0 / 180px 180px,
linear-gradient(rgba(var(--fitme-accent-rgb), .16), rgba(var(--fitme-accent-rgb), .16)); /* brand-colour frost tint */
background-blend-mode: overlay, normal;
}
.hero-text {
padding-top: 60px;
}
.hero-text h1 {
/* Fluid: replaces 4 step values (3.2rem @992-1199, 2.7rem @768-991,
2.1rem @<=767, 1.75rem @<=479) with one clamp anchored at 768px (2.7rem)
-> 1200px (3.8rem, the old desktop value), audit 4.5. */
font-size: clamp(1.75rem, calc(.7444rem + 4.0741vw), 3.8rem);
font-weight: 900;
color: #fff;
/* tight + soft shadow so the lettering separates from the frosted band */
text-shadow: 0 1px 2px rgba(0, 0, 0, .25);
line-height: 1.05;
letter-spacing: -.5px;
}
/* Subtitle (gym hero_subtitle): same h1 but a much smaller, tracked-out line
so the title leads and this reads as its strapline. */
.hero-text h1 span {
display: block;
margin-top: .55em;
font-size: .42em;
font-weight: 600;
line-height: 1.3;
letter-spacing: .12em;
color: var(--fitme-accent);
}
.hero-brand {
display: inline-block;
font-size: .95rem;
font-weight: 700;
letter-spacing: .35em;
text-transform: uppercase;
color: var(--fitme-accent);
margin-bottom: 1rem;
padding-left: .35em;
text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
.hero-text .site-btn {
margin-top: 2.5rem;
}
.hero-text .hero-tagline {
color: #fff;
font-size: 1.3rem;
font-weight: 500;
max-width: 600px;
margin: 1.25rem auto 0;
text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
.hero-cta-row {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
margin-top: 2.5rem;
}
.hero-cta-row .site-btn {
margin-top: 0;
}
.site-btn.sb-ghost {
background: transparent;
border: 2px solid #fff;
color: #fff;
padding: 14px 36px;
}
/* .sb-ghost hover: handled by the shared button hover above (dark face, white text, spinning edge) */
/* ── CSS performance: skip rendering off-screen sections ──────────────────── */
.trainers-section,
.service-section,
.schedule-section,
.workhours-section,
.map-section,
.classes-section {
content-visibility: auto;
contain-intrinsic-size: 500px;
}
/* ── Section backgrounds (alternating) ─────────────────────────────────────── */
.feature-section {
background: var(--fitme-white);
}
/* Team backdrop: the warm grey of the gym's block wall in the header photo
(sampled ≈ rgb(70,66,62)), a touch darker so white names still pop. On top,
very faint mortar joints in running bond (120×60 blocks, alternate rows
offset by half a block) plus a fine concrete grain, both as inline SVG
tiles, and a soft shade at the top and bottom edges. */
.trainers-section {
position: relative;
background-color: #403d3a;
background-image:
linear-gradient(180deg, rgba(0, 0, 0, .28) 0%, transparent 18%, transparent 82%, rgba(0, 0, 0, .28) 100%),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' 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 .07 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"),
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='120'%3E%3Cpath d='M0 1H240M0 61H240M1 0V60M121 0V60M61 60V120M181 60V120' fill='none' stroke='rgba(0,0,0,0.09)' stroke-width='1.5'/%3E%3Cpath d='M0 3.5H240M0 63.5H240' fill='none' stroke='rgba(255,255,255,0.022)' stroke-width='1'/%3E%3C/svg%3E");
background-size: 100% 100%, 200px 200px, 240px 120px;
}
.trainers-section:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, transparent, var(--fitme-accent), transparent);
opacity: .35;
}
.service-section {
background: var(--fitme-white);
}
.schedule-section {
background: var(--fitme-surface);
position: relative;
}
.schedule-section:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, transparent, var(--fitme-accent), transparent);
opacity: .35;
}
.contact-section {
background: var(--fitme-dark-2);
}
/* Horário de Funcionamento, nested inside Informações e contactos (not its
own section) — plain text lines, centered, matching the "less graphics"
direction the rest of that column took once the icons came out. */
/* One block per day, centred: the day on its own line, then one line per
opening period (Sábado: morning and afternoon). */
.wh-day + .wh-day { margin-top: 14px; }
.wh-text p {
margin: 0;
color: rgba(255, 255, 255, .7);
line-height: 1.6;
}
.wh-text strong {
display: block;
color: var(--fitme-accent);
font-weight: 700;
}
.wh-text .wh-closed {
color: rgba(255, 255, 255, .45);
}
.map-section {
background: var(--fitme-surface);
position: relative;
}
.map-section:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, transparent, var(--fitme-accent), transparent);
opacity: .35;
}
/* ── Center orphans in flex grids ──────────────────────────────────────────── */
.row.auto-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.row.auto-grid>[class*="col-"] {
flex: 0 0 auto;
}
.row.auto-grid>.col-6 {
width: calc(50% - .75rem);
}
@media (min-width: 768px) {
.row.auto-grid>.col-md-4 {
width: calc(33.333% - 1rem);
}
}
@media (min-width: 992px) {
.row.auto-grid>.col-lg-3 {
width: calc(25% - 1rem);
}
}
/* ── Feature / Offer section ───────────────────────────────────────────────── */
.feature-section {
padding: 100px 0 60px;
}
.icon-box-item {
text-align: center;
margin-bottom: 3rem;
}
.icon-box-item .ib-icon {
width: 72px;
height: 72px;
border-radius: var(--fitme-radius);
display: flex;
align-items: center;
justify-content: center;
background: var(--fitme-surface);
margin: 0 auto 1.5rem;
font-size: 2.5rem;
color: var(--fitme-accent);
transition: background-color var(--fitme-transition), transform var(--fitme-transition);
}
.icon-box-item .ib-icon img {
max-width: 44px;
max-height: 44px;
mix-blend-mode: multiply;
}
.icon-box-item h3,
.icon-box-item h4 {
margin-bottom: .75rem;
/* Fluid: replaces the .95rem @<=479px step with one clamp anchored at
479px (.95rem) -> 768px (1.15rem, the old desktop value), audit 4.5. */
font-size: clamp(.95rem, calc(.6185rem + 1.1073vw), 1.15rem);
}
.icon-box-item p {
font-size: .9rem;
color: var(--fitme-text-muted);
}
.icon-box-item:hover .ib-icon {
background: var(--fitme-accent);
transform: scale(1.06);
}
.icon-box-item {
transition: transform var(--fitme-transition);
}
.icon-box-item:hover {
transform: translateY(-3px);
}
.icon-box-item .ib-icon img {
transition: filter var(--fitme-transition);
}
.icon-box-item:hover .ib-icon img {
filter: brightness(0) invert(0);
/* darken icon on accent bg */
}
/* Icon boxes (Modalidades, offer): same hover as the buttons — dark face, white
icon, spinning brand-colour edge (a 2px ring cut out of ::after with a mask)
and a soft glow. The official YOURFIT PNGs keep their own colours on a white
face instead of being turned into silhouettes. */
.icon-box-item .ib-icon {
position: relative;
z-index: 0;
transition: background-color .4s ease, color .4s ease, transform .5s cubic-bezier(.22, .8, .3, 1), box-shadow .4s ease;
}
.icon-box-item .ib-icon::after {
content: '';
position: absolute;
inset: 0;
padding: 2px;
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;
}
.icon-box-item:hover .ib-icon,
.icon-box-item:focus-visible .ib-icon {
background: color-mix(in srgb, var(--fitme-accent) 10%, #000);
color: #fff;
transform: scale(1.06);
box-shadow: 0 0 16px 1px rgba(var(--fitme-accent-rgb), .4);
}
.icon-box-item:hover .ib-icon::after,
.icon-box-item:focus-visible .ib-icon::after { opacity: 1; animation: pc-spin 3.2s linear infinite; }
.icon-box-item:hover .ib-icon svg.mi,
.icon-box-item:focus-visible .ib-icon svg.mi { color: #fff; }
.icon-box-item:hover .ib-icon img,
.icon-box-item:focus-visible .ib-icon img { filter: brightness(0) invert(1); mix-blend-mode: normal; }
.icon-box-item:hover .ib-icon:has(img[src*="yourfit"]),
.icon-box-item:focus-visible .ib-icon:has(img[src*="yourfit"]) { background: #fff; }
.icon-box-item:hover .ib-icon img[src*="yourfit"],
.icon-box-item:focus-visible .ib-icon img[src*="yourfit"] { filter: none; }
@media (prefers-reduced-motion: reduce) {
.icon-box-item:hover .ib-icon::after { animation: none; }
}
/* ── Trainers / Team ───────────────────────────────────────────────────────── */
.trainers-section {
padding: 100px 0 60px;
}
/* Homepage: sit the team section right under the gallery (no big gap) */
#equipa.trainers-section {
padding-top: 48px;
}
.trainers-section>h2 {
margin-bottom: 3rem;
}
.trainer-item {
text-align: center;
padding: 0 5px;
margin-bottom: 2.5rem;
}
.trainer-item .trainer-pic {
width: 200px;
height: 200px;
border-radius: 0;
margin: 0 auto 1.5rem;
overflow: hidden;
position: relative;
border: 4px solid var(--fitme-accent);
box-shadow: var(--fitme-shadow-lg);
transform: rotate(-3deg);
/* Soft curve so the square straightens + lifts on hover (same as the buttons) */
transition: transform .5s cubic-bezier(.22, .8, .3, 1),
box-shadow .4s ease;
}
/* CSS overlay replaces the old small_overlay_white.svg — one less HTTP request */
.trainer-item .trainer-pic:after {
content: '';
position: absolute;
inset: 0;
border-radius: 0;
background: none; /* no gloss gradient over the member photos */
pointer-events: none;
z-index: 1;
}
.trainer-item .trainer-pic:hover {
transform: rotate(0deg) translateY(-8px) scale(1.05);
box-shadow: 0 18px 44px rgba(0, 0, 0, .22);
}
/* Alternate the tilt direction across the grid for a livelier team wall;
#powerRotation wraps the homepage team cards (the col-* siblings). */
#powerRotation>div:nth-child(even) .trainer-pic {
transform: rotate(3deg);
}
#powerRotation>div:nth-child(even) .trainer-pic:hover {
transform: rotate(0deg) translateY(-8px) scale(1.05);
}
/* 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
padding box, so only the border area shows the gradient. */
@media (hover: hover) {
.trainer-item .trainer-pic:hover,
#powerRotation>div:nth-child(even) .trainer-pic:hover {
border-color: transparent;
background:
linear-gradient(var(--fitme-dark), var(--fitme-dark)) padding-box,
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) border-box;
box-shadow: 0 0 18px 2px rgba(var(--fitme-accent-rgb), .4), var(--fitme-shadow-lg);
animation: pc-spin 3.2s linear infinite;
}
}
@media (prefers-reduced-motion: reduce) {
.trainer-item .trainer-pic:hover { animation: none; }
}
.trainer-item .trainer-pic img {
width: 100%;
height: 100%;
object-fit: cover;
position: relative;
z-index: 0;
background: var(--fitme-surface-2);
object-position: top;
}
/* Graceful fallback when image src is empty or 404 */
.trainer-item .trainer-pic img[src=""]:after,
.trainer-item .trainer-pic img:not([src]),
.trainer-item .trainer-pic img[src=""] {
/* Hide broken image icon — parent .trainer-pic already has :after overlay */
visibility: hidden;
}
.trainer-item h3,
.trainer-item h4 {
margin-bottom: .3rem;
}
.trainer-item>*:last-child {
font-size: .9rem;
color: var(--fitme-text-muted);
}
/* Team runs on the dark (Void Black) canvas: light text so names read and the
accent photo frames pop — the photos' own dark backgrounds now blend in. */
.trainers-section {
color: var(--fitme-ash);
}
.trainers-section .section-title h2,
.trainers-section .trainer-item h3,
.trainers-section .trainer-item h4,
.trainers-section .trainer-item>*:last-child {
color: #fff;
}
.trainers-section .section-subtitle {
color: var(--fitme-ash);
}
/* ── Classes / Modalidades ─────────────────────────────────────────────────── */
.service-section {
padding: 100px 0 60px;
}
.service-section>.container>.row:first-child {
margin-bottom: 2rem;
}
/* ── Schedule / Horário ────────────────────────────────────────────────────── */
.schedule_container {
margin-top: 2rem;
/* Scroll sideways rather than crush columns on narrow desktops/tablets. */
overflow-x: auto;
}
/* Time-aligned weekly grid: columns are days, rows are start times. Each cell is
placed by inline `grid-column` (day) + `grid-row` (time) from the PHP, so every
class lines up on the row of its start time across the whole week. */
.schedule_panel {
margin-top: 1rem;
display: grid;
grid-template-columns: repeat(var(--sched-days, 6), minmax(150px, 1fr));
/* Explicit rows (day header + Manhã/Tarde dividers + one per start time) so
the day stripes can span the whole grid with grid-row: 1 / -1. */
grid-template-rows: repeat(var(--sched-rows, 14), auto);
align-items: start; /* cells hug the top of their time row */
column-gap: 14px;
row-gap: 14px;
min-width: 760px; /* keep columns legible; the container scrolls if narrower */
}
/* Per-day vertical band, painted behind the cards (emitted first in the DOM) so
each weekday column reads as its own stripe. A faint wash of the brand accent
green; alternating columns get a deeper tint and the light column gaps act as
the separators between them. */
.schedule_stripe {
align-self: stretch; /* fill every row (panel sets align-items:start) */
grid-row: 1 / -1;
border-radius: 8px;
background: rgba(var(--fitme-accent-rgb), .06);
pointer-events: none;
}
.schedule_stripe.is-alt {
background: rgba(var(--fitme-accent-rgb), .13);
}
/* Manhã / Tarde divider spanning the whole week above each block of times. */
.schedule_section_label {
grid-column: 1 / -1;
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin: .35rem 0 .1rem;
text-align: center;
}
.schedule_section_label span {
font-weight: 800;
text-transform: uppercase;
letter-spacing: .18em;
font-size: .8rem;
color: var(--fitme-text-muted);
}
.schedule_section_label::before,
.schedule_section_label::after {
content: '';
flex: 1 1 0;
height: 2px;
border-radius: 2px;
background: rgba(var(--fitme-accent-rgb), .5);
}
/* Day header (grid row 1). Class cards carry their own time label, so the grid
needs no separate time gutter — rows align purely by placement. */
.schedule_dayhead {
display: flex;
justify-content: center;
align-items: flex-start;
margin-bottom: .25rem;
}
/* One (day, time) slot. Concurrent classes (same day + time, different rooms)
sit SIDE BY SIDE so the overlap reads at a glance; a lone class fills the
column. They share the column width equally and shrink to fit. */
.schedule_cell {
display: flex;
flex-direction: row;
align-items: stretch;
gap: 8px;
min-width: 0;
}
.schedule_cell > .schedule_box {
flex: 1 1 0;
min-width: 0; /* allow equal shrink instead of overflowing the column */
}
.rounded_frame {
background: var(--fitme-dark-3);
color: #fff;
border-radius: var(--fitme-radius);
height: 40px;
width: 140px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
font-weight: 700;
}
.rounded_frame_grey {
margin: auto;
text-align: center;
background: var(--fitme-surface-2);
border-radius: var(--fitme-radius);
height: 44px;
width: 210px;
display: flex;
align-items: center;
justify-content: center;
}
.rounded_frame_grey p {
margin: 0;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.rounded_frame_medium {
margin: auto;
text-align: center;
background: var(--fitme-dark-3);
border-radius: var(--fitme-radius);
height: 42px;
width: 250px;
display: flex;
align-items: center;
justify-content: center;
}
.schedule_frame {
min-width: 230px;
font-size: 1.1rem;
font-weight: 700;
color: #fff !important;
text-decoration: none;
}
.schedule_box {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
width: 100%;
padding: 8px 4px;
border-radius: var(--fitme-radius);
text-align: center;
transition: transform var(--fitme-transition), box-shadow var(--fitme-transition);
}
/* Reserve up to two lines for the class name so 1- and 2-line names produce the
same card height. */
.schedule_box a {
display: flex;
align-items: center;
justify-content: center;
min-height: 2.5em;
line-height: 1.15;
text-align: center;
}
.schedule_box a {
font-size: 11px;
color: #fff;
}
/* Fixed-height logo slot so every card's icon lines up regardless of the source
image's aspect ratio. */
.schedule_box img {
height: 30px;
width: auto;
max-width: 84%;
object-fit: contain;
margin-bottom: 4px;
mix-blend-mode: multiply;
filter: brightness(1.3) contrast(1.1);
}
.schedule_box>div:first-of-type {
/* Fluid: replaces the 14px @<=767px step with one clamp anchored at
375px (14px) -> 768px (16px, the old desktop value), audit 4.5. */
font-size: clamp(14px, calc(12.0916px + .5089vw), 16px);
color: #fff;
}
.schedule_box>div:last-of-type {
/* Fluid: replaces the 12px @<=767px step with one clamp anchored at
375px (12px) -> 768px (13px, the old desktop value), audit 4.5. */
font-size: clamp(12px, calc(11.0458px + .2545vw), 13px);
color: rgba(255, 255, 255, .85);
}
.schedule_box {
transition: transform .2s ease, box-shadow .2s ease, filter .2s ease;
}
.schedule_box:hover {
transform: scale(1.08);
z-index: 100;
box-shadow: 0 8px 32px rgba(0, 0, 0, .22);
filter: brightness(1.1);
}
.schedule_info {
/* Full-bleed footer band the full width of the card. The box is a centered
flex column, so the strip must align-self:stretch (otherwise it shrinks to
its text); negative margins then cancel the .schedule_box padding (8px
top/bottom, 4px sides) so it reaches the card edges. The time sits on its
own line with the classroom stacked beneath it — consistent at every card
width (no side-by-side / wrapping differences between wide and narrow). */
align-self: stretch;
width: auto;
margin: auto -4px -8px; /* margin-top:auto pins the strip to the card foot */
padding: 6px 8px;
background: rgba(0, 0, 0, .25);
border-radius: 0 0 var(--fitme-radius) var(--fitme-radius);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1px;
min-height: 2.6em; /* same strip height whether or not a room is set */
line-height: 1.25;
font-weight: 700; /* time — the primary line */
}
/* Classroom — the secondary line under the time. */
.schedule_info b {
font-weight: 500;
font-size: .88em;
opacity: .9;
}
/* Some classes have no room set (<b></b>); don't reserve a blank second line. */
.schedule_info b:empty {
display: none;
}
/* ── Contact section ───────────────────────────────────────────────────────── */
.contact-section {
padding: 100px 0 80px;
color: var(--fitme-ash);
position: relative;
overflow: hidden;
background-color: var(--fitme-dark-2);
}
/* Strong overlay to keep text readable over the background image */
.contact-section:before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background:
linear-gradient(180deg,
rgba(10, 10, 10, 0.88) 0%,
rgba(10, 10, 10, 0.78) 40%,
rgba(10, 10, 10, 0.82) 100%);
}
.contact-section .container {
z-index: 1;
position: relative;
}
.contact-section h1,
.contact-section h2,
.contact-section h3,
.contact-section h4,
.contact-section h5,
.contact-section h6 {
color: #fff;
}
.contact-title {
margin-bottom: 2.5rem;
}
/* The form heading is an h3 under the section's h2 — keep the h2 look. */
h3.contact-title {
font-size: 2.25rem;
}
.contact-info-warp {
margin-bottom: 1.4rem;
}
.contact-info-warp h3,
.contact-info-warp h4 {
color: var(--fitme-accent);
margin-bottom: .5rem;
font-size: 1rem;
}
.contact-info p {
color: rgba(255, 255, 255, .7);
line-height: 1.8;
margin: 0;
}
.contact-info-warp a {
color: rgba(255, 255, 255, .7);
}
.contact-info-warp a:hover {
color: var(--fitme-accent);
}
.contact-form input[type=text],
.contact-form input[type=email],
.contact-form textarea {
width: 100%;
padding: 14px 20px;
border: 1px solid rgba(255, 255, 255, .1);
background: rgba(255, 255, 255, .06);
color: #fff;
font-size: .95rem;
border-radius: var(--fitme-radius);
margin-bottom: 16px;
transition: border-color var(--fitme-transition), background var(--fitme-transition);
}
.contact-form input::placeholder,
.contact-form textarea::placeholder {
color: rgba(255, 255, 255, .35);
}
.contact-form input:focus,
.contact-form textarea:focus {
border-color: var(--fitme-accent);
background: rgba(255, 255, 255, .1);
}
.contact-form textarea {
resize: vertical;
min-height: 150px;
}
.contact-form .site-btn {
float: right;
}
/* The Nome/Telemóvel row sits in Bootstrap columns (12px gutter, BS5); cancel
that with negative margins so those inputs line up flush with the full-width
Razão and Mensagem fields below them. */
.contact-form .row {
margin-left: -0.75rem;
margin-right: -0.75rem;
}
@media (min-width: 992px) {
/* Natural column heights — the textarea is stretched by JS to meet the map's
bottom (see main.js), and the consent + submit button follow just below. */
#contactos > .container > .row { align-items: flex-start; }
}
/* ── Newsletter ────────────────────────────────────────────────────────────── */
.newsletter-section {
padding: 80px 0;
background-color: var(--fitme-dark-3); /* not shorthand → keeps .set-bg cover */
position: relative;
overflow: hidden;
}
.newsletter-section:before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background:
linear-gradient(180deg,
rgba(31, 31, 31, 0.92) 0%,
rgba(31, 31, 31, 0.85) 50%,
rgba(31, 31, 31, 0.92) 100%);
}
.newsletter-section .container {
z-index: 1;
position: relative;
}
.newsletter-section .section-title {
padding-top: .5rem;
}
.newsletter-form {
margin-left: -55px;
}
.newsletter-form input {
width: calc(100% - 210px);
height: 58px;
padding: 10px 28px;
float: left;
border: none;
border-radius: var(--fitme-radius) 0 0 var(--fitme-radius);
font-size: .95rem;
}
.newsletter-form .site-btn {
min-width: 180px;
border-radius: 0 var(--fitme-radius) var(--fitme-radius) 0;
height: 58px;
padding: 0 28px;
}
/* ── Map ───────────────────────────────────────────────────────────────────── */
.map {
position: relative;
height: 480px;
background: var(--fitme-surface-dark);
border-radius: var(--fitme-radius);
overflow: hidden;
}
/* Full-width map in Informações e contactos, below the info + form grid. */
.map-full {
margin-top: 2.5rem;
}
.map iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
}
/* ── Footer ────────────────────────────────────────────────────────────────── */
.footer-section {
padding: 60px 0 30px;
background-color: var(--fitme-dark); /* not shorthand → keeps .set-bg cover */
color: rgba(255, 255, 255, .6);
position: relative;
overflow: hidden;
}
.footer-section:before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
/* Same matte-metal texture as the reviews section, over the (now barely
visible) gym photo. */
background-image:
var(--metal-layers),
linear-gradient(180deg,
rgba(20, 21, 23, 0.96) 0%,
rgba(20, 21, 23, 0.92) 50%,
rgba(20, 21, 23, 0.96) 100%);
background-size: var(--metal-sizes), 100% 100%;
}
.footer-section .container {
z-index: 1;
position: relative;
}
.footer-widget {
margin-bottom: 2.5rem;
}
.footer-widget h4 {
color: #fff;
margin-bottom: 1.2rem;
font-size: 1rem;
}
.footer-widget .fw-info-box {
display: flex;
align-items: flex-start;
gap: .8rem;
margin-bottom: .75rem;
}
.footer-widget .fw-info-box .fas {
color: var(--fitme-accent);
font-size: 1.1rem;
margin-top: 3px;
}
.footer-widget .fw-info-box p {
color: rgba(255, 255, 255, .55);
line-height: 1.7;
margin: 0;
font-size: .88rem;
}
.footer-widget a {
color: rgba(255, 255, 255, .55);
}
.footer-widget a:hover {
color: var(--fitme-accent);
}
.footer-widget .social-links {
display: flex;
gap: .5rem;
}
.footer-widget .social-links a {
font-size: 1.4rem;
color: rgba(255, 255, 255, .45);
transition: color var(--fitme-transition), transform var(--fitme-transition);
}
.footer-widget .social-links a:hover {
color: var(--fitme-accent);
transform: translateY(-2px);
}
/* Slimmed, centred footer: social row, site menu, legal links. */
.footer-social {
display: flex;
justify-content: center;
gap: .9rem;
font-size: 1.6rem;
margin-bottom: 1.5rem;
}
.footer-social a {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 44px;
min-height: 44px;
color: rgba(255, 255, 255, .6);
transition: color var(--fitme-transition), transform var(--fitme-transition);
}
.footer-social a:hover {
color: var(--fitme-accent);
transform: translateY(-2px);
}
.footer-menu {
list-style: none;
text-align: center;
padding-top: 0;
margin: 0 0 1rem;
}
.footer-menu li {
display: inline-block;
}
.footer-menu li a {
color: rgba(255, 255, 255, .6);
font-size: .82rem;
font-weight: 700;
padding: 5px 10px;
margin: 0 .35rem;
transition: color var(--fitme-transition);
}
.footer-menu li a:hover {
color: var(--fitme-accent);
}
.footer-legal {
color: rgba(255, 255, 255, .5);
margin: .25rem 0;
}
.footer-legal a {
color: rgba(255, 255, 255, .7);
}
.footer-legal a:hover {
color: var(--fitme-accent);
}
/* Discreet backoffice link — faint until hovered. */
.footer-legal-sep {
color: rgba(255, 255, 255, .25);
margin: 0 .35rem;
}
.footer-admin-link {
opacity: .35;
transition: opacity .2s ease;
}
.footer-admin-link:hover {
opacity: 1;
}
/* ── Page-top header (CrossFit page) ───────────────────────────────────────── */
.page-top-section {
height: 340px;
text-align: center;
padding-top: 140px;
position: relative;
overflow: hidden;
background-color: var(--fitme-dark);
}
/* Depth gradient overlay */
.page-top-section:before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background:
linear-gradient(180deg,
rgba(0, 0, 0, 0.55) 0%,
rgba(0, 0, 0, 0.30) 50%,
rgba(0, 0, 0, 0.50) 100%);
}
.page-top-section .container {
z-index: 2;
position: relative;
}
.page-top-section h1 {
display: inline-block;
position: relative;
/* Fluid: replaces the 2.5rem @<=767px step with one clamp anchored at
375px (2.5rem) -> 768px (4rem, the old desktop value), audit 4.5. */
font-size: clamp(2.5rem, calc(1.0687rem + 6.1069vw), 4rem);
color: #fff;
padding-bottom: 16px;
text-shadow: 0 2px 30px rgba(0, 0, 0, .7);
}
.page-top-section h1:after {
position: absolute;
content: "";
width: 100%;
height: 5px;
bottom: 0;
left: 0;
background: var(--fitme-accent);
}
/* ── CrossFit video header ─────────────────────────────────────────────────── */
.video {
position: relative;
background: #000;
height: 75vh;
min-height: 20rem;
width: 100%;
overflow: hidden;
}
.video video {
position: absolute;
top: 50%;
left: 50%;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: 0;
transform: translate(-50%, -50%);
}
.video .container {
position: relative;
z-index: 2;
}
.video .overlay {
position: absolute;
inset: 0;
z-index: 1;
background:
linear-gradient(180deg,
rgba(0, 0, 0, 0.45) 0%,
rgba(0, 0, 0, 0.25) 35%,
rgba(0, 0, 0, 0.35) 65%,
rgba(0, 0, 0, 0.60) 100%);
}
@media (pointer: coarse) and (hover: none) {
.video {
background: url('../img/crossfit.jpg') #000 center/cover no-repeat;
}
.video video {
display: none;
}
}
/* ── Classes / CrossFit section ────────────────────────────────────────────── */
.classes-section {
padding: 80px 0;
/* background-color (not the `background` shorthand) so a .set-bg image keeps
the cover/no-repeat from .set-bg instead of tiling at natural size. */
background-color: var(--fitme-white);
}
.classes-section .section-title h2 span {
color: var(--fitme-accent);
}
/* Variant with a background image (e.g. the CrossFit "O que é o CrossFit?"
banner): dark gradient overlay for legible white text over the photo. */
.classes-section.has-bg {
position: relative;
background-color: var(--fitme-dark);
}
.classes-section.has-bg::before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background: linear-gradient(90deg, rgba(11,11,13,.82) 0%, rgba(11,11,13,.62) 55%, rgba(11,11,13,.40) 100%);
}
.classes-section.has-bg .container {
position: relative;
z-index: 1;
}
.classes-section.has-bg h2,
.classes-section.has-bg .classes-text p {
color: #fff;
text-shadow: 0 2px 12px rgba(0,0,0,.5);
}
.classes-text p {
color: var(--fitme-text-soft);
margin-bottom: 2.5rem;
}
/* ── Gallery (Splide overrides) ────────────────────────────────────────────── */
.splide__slide {
background-size: cover;
}
/* Brand the arrows + pagination (the sea-green theme ships them blue). Loaded
after the Splide theme CSS, so plain selectors win — no !important needed. */
.splide__arrow {
background: var(--fitme-accent);
opacity: 1;
width: 2.4em;
height: 2.4em;
border-radius: var(--fitme-radius);
transition: background var(--fitme-transition), transform var(--fitme-transition);
}
.splide__arrow svg,
.splide__arrow:hover svg,
.splide__arrow:focus svg {
fill: var(--fitme-dark);
width: 1.1em;
height: 1.1em;
}
.splide__arrow:hover {
background: var(--fitme-accent-dark);
}
.splide__arrow:disabled {
opacity: .35;
}
.splide__arrow--prev {
left: 1em;
}
.splide__arrow--next {
right: 1em;
}
.splide__pagination__page {
background: var(--fitme-ash);
opacity: .6;
}
.splide__pagination__page.is-active {
background: var(--fitme-accent);
opacity: 1;
transform: scale(1.3);
}
/* ── 404 / Error pages ─────────────────────────────────────────────────────── */
.page-top-section h1:after {
background: var(--fitme-accent);
}
/* ── Modal / Pop-up ────────────────────────────────────────────────────────── */
.modal-content {
border: none;
background: transparent !important;
}
/* ── Sticky mobile CTA bar ─────────────────────────────────────────────────── */
.mobile-cta-bar {
display: none;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 999;
background: rgba(10, 10, 10, 0.94);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
padding: 8px 12px;
gap: 10px;
border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.mobile-cta-bar .cta-btn {
flex: 1;
text-align: center;
padding: 12px 8px;
border-radius: var(--fitme-radius);
font-weight: 700;
font-size: .9rem;
text-decoration: none;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
transition: background var(--fitme-transition);
}
.mobile-cta-bar .cta-btn-call {
background: transparent;
color: #fff;
border: 1px solid rgba(255, 255, 255, 0.25);
}
.mobile-cta-bar .cta-btn-call:active {
background: rgba(255, 255, 255, 0.1);
}
.mobile-cta-bar .cta-btn-cta {
background: var(--fitme-accent);
color: var(--fitme-dark);
}
.mobile-cta-bar .cta-btn-cta:active {
background: var(--fitme-accent-dark);
}
/* ── Back to top button ────────────────────────────────────────────────────── */
.back-to-top {
position: fixed;
bottom: 80px;
right: 16px;
z-index: 998;
width: 44px;
height: 44px;
border-radius: 50%;
background: var(--fitme-accent);
color: var(--fitme-dark);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
font-weight: 700;
opacity: 0;
visibility: hidden;
transform: translateY(8px);
transition: opacity .25s, visibility .25s, transform .25s;
box-shadow: 0 2px 12px rgba(0, 0, 0, .25);
}
.back-to-top.visible {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.back-to-top:active {
transform: scale(0.95);
}
/* ── Consent checkbox (RGPD, contact + newsletter forms on dark sections) ──── */
.consent-check {
display: flex;
gap: 8px;
align-items: flex-start;
clear: both;
padding-top: 12px;
font-size: .8rem;
line-height: 1.5;
font-weight: 400;
color: rgba(255, 255, 255, .75);
cursor: pointer;
}
.consent-check input[type=checkbox] {
width: 16px;
height: 16px;
margin-top: 2px;
flex-shrink: 0;
accent-color: var(--fitme-accent);
cursor: pointer;
}
.consent-check a {
color: #fff;
text-decoration: none;
}
.consent-check a:hover {
color: var(--fitme-accent);
}
/* ── WhatsApp floating button ──────────────────────────────────────────────── */
.whatsapp-float {
position: fixed;
bottom: 20px;
right: 16px;
z-index: 998;
width: 48px;
height: 48px;
border-radius: 50%;
background: #25d366;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
box-shadow: 0 2px 12px rgba(0, 0, 0, .25);
}
.whatsapp-float:hover,
.whatsapp-float:focus {
background: #1ebe5d;
color: #fff;
text-decoration: none;
}
/* ── Mobile schedule: horizontal scroll ────────────────────────────────────── */
.schedule-scroll-hint {
display: none;
text-align: center;
font-size: .75rem;
color: var(--fitme-text-muted);
margin-top: .5rem;
}
/* ==========================================================================
RESPONSIVE
========================================================================== */
/* ── ≥ 1200px ──────────────────────────────────────────────────────────────── */
@media (min-width: 1200px) {
.container {
max-width: 1176px;
}
}
/* ── 992px–1199px ──────────────────────────────────────────────────────────── */
@media only screen and (min-width: 992px) and (max-width: 1199px) {
/* tighter link spacing so a long menu (3070) clears the logo and match head */
.header-section .navbar-nav { --bs-navbar-nav-link-padding-x: .35rem; }
.header-section .nav-link { margin: 0 .2rem !important; font-size: .8125rem; }
.header-right .hr-box {
display: none !important;
}
.newsletter-form {
margin-left: 0;
}
}
/* ── 768px–991px ───────────────────────────────────────────────────────────── */
@media only screen and (min-width: 768px) and (max-width: 991px) {
.header-right .hr-box {
display: none;
}
/* Schedule keeps the time-aligned grid here; .schedule_container scrolls it
sideways when six columns don't fit. */
.newsletter-section {
text-align: center;
}
.newsletter-form {
margin-top: 2rem;
margin-left: 0;
}
.newsletter-form input {
width: 100%;
margin-bottom: 1rem;
border-radius: var(--fitme-radius);
}
.newsletter-form .site-btn {
border-radius: var(--fitme-radius);
width: 100%;
}
.footer-menu {
text-align: center;
}
.footer-menu li a {
margin-left: .5rem;
}
.contact-form .site-btn {
float: none;
width: 100%;
}
.navbar-collapse {
background: #fff;
padding: 1rem;
}
.nav-link {
text-align: center;
}
.navbar-toggler {
margin-right: 1rem;
}
.trainer-item .trainer-pic {
width: 150px;
height: 150px;
}
.map {
height: 320px;
}
}
/* ── ≤ 767px ───────────────────────────────────────────────────────────────── */
@media only screen and (max-width: 767px) {
/* Hero */
.hero-section {
min-height: max(100svh, 500px);
min-height: max(100dvh, 500px);
}
.hero-text {
padding-top: 120px;
padding-bottom: 100px;
}
.hero-brand {
font-size: .8rem;
letter-spacing: .28em;
margin-bottom: .6rem;
}
.hero-text .site-btn {
min-width: 180px;
padding: 14px 28px;
font-size: .95rem;
}
/* General */
html {
scroll-padding-top: 60px;
}
/* Sticky mobile bar */
.mobile-cta-bar {
display: flex;
}
/* The dark footer clears the fixed CTA bar itself, so there's no blank strip
after it (the old body padding-bottom showed a white gap below the footer). */
.footer-section {
padding-top: 44px;
padding-bottom: 92px;
}
/* Glass bar on mobile too, just a touch more opaque for legibility. The open
dropdown stays solid (.navbar-collapse below) so menu text never competes
with the page content showing through the blur. */
.header-section {
background: rgba(247, 248, 250, 0.85);
}
.site-logo {
padding-left: 12px;
max-width: 130px;
}
.header-right {
display: none !important;
}
.navbar-collapse {
background: #fff;
padding: 1rem;
}
.navbar-toggler {
margin-right: .75rem;
}
/* The single-day layout + day picker now apply at every width (see the
"Schedule day filter" block); only small-screen card sizing lives here. */
.schedule:not(.schedule-export) .schedule_panel {
max-width: none; /* use the full phone width */
}
.schedule_box {
padding: 8px 6px;
gap: 3px;
}
.rounded_frame {
margin: 0 auto .75rem;
width: 130px;
height: 36px;
font-size: 1rem;
}
.schedule_box img {
height: 26px;
}
.schedule_box a {
font-size: 11px;
}
.schedule-scroll-hint {
display: block;
padding: 0 16px;
}
/* Work hours */
.rounded_frame_grey {
width: 160px;
}
.rounded_frame_medium {
width: 180px;
}
.schedule_frame {
min-width: auto;
font-size: .95rem;
}
/* Team grid */
.trainer-item .trainer-pic {
width: 140px;
height: 140px;
}
/* Gallery */
#primary-slider .splide__slide {
height: 280px !important;
}
/* Contact form */
.contact-form input[type=text],
.contact-form input[type=email],
.contact-form textarea {
font-size: 1rem;
padding: 14px 16px;
height: 50px;
}
.contact-form textarea {
height: 130px;
}
.contact-form .site-btn {
float: none;
width: 100%;
margin-top: .5rem;
}
.contact-form input:focus,
.contact-form textarea:focus {
box-shadow: 0 0 0 3px rgba(var(--fitme-accent-rgb), 0.35);
outline: none;
}
/* Map */
.map {
height: 220px;
}
.map-section {
padding-bottom: 0 !important;
}
/* Newsletter */
.newsletter-section {
text-align: center;
}
.newsletter-form {
margin-top: 2rem;
margin-left: 0;
}
.newsletter-form input {
width: 100%;
margin-bottom: .75rem;
border-radius: var(--fitme-radius);
height: 50px;
font-size: 1rem;
}
.newsletter-form .site-btn {
border-radius: var(--fitme-radius);
width: 100%;
height: 50px;
}
/* Footer */
.footer-menu {
text-align: center;
}
.footer-menu li a {
margin-left: .3rem;
font-size: .75rem;
padding: 8px 6px;
}
/* Floating buttons: stack above the sticky CTA bar */
.whatsapp-float {
bottom: 80px;
}
.back-to-top {
bottom: 140px;
}
}
/* ── ≤ 575px (xs) ──────────────────────────────────────────────────────────── */
@media only screen and (max-width: 575px) {
.hero-text {
padding-top: 100px;
padding-bottom: 80px;
}
.trainer-item .trainer-pic {
width: 120px;
height: 120px;
}
.site-btn {
min-width: 150px;
padding: 13px 22px;
font-size: .88rem;
}
/* Contact: stack name + phone */
.contact-form .col-md-6 {
width: 100%;
}
/* Offer + modalidades: compact icons */
.icon-box-item .ib-icon {
width: 56px;
height: 56px;
}
.icon-box-item .ib-icon img {
max-width: 34px;
max-height: 34px;
}
.rounded_frame {
width: 100px;
height: 30px;
font-size: .85rem;
}
}
/* ── Reduced motion ────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
.fade-in {
animation: none;
opacity: 1;
}
/* The team / modalidade detail cards are exempt: reduced-motion is on by
default over Remote Desktop and with Windows "animation effects" off, and
this nuke turned their grow-out-of-the-card move into a jarring pop. They
only move when the visitor asks (hover / tap) and settle in ~0.6s. */
*:not(.trainer-detail):not(.td-body):not(.mod-detail):not(.md-body),
*:before,
*:after {
animation-duration: .01ms !important;
transition-duration: .01ms !important;
}
}
/* ── Decorated section title (eyebrow + accent underline + subtitle) ────────── */
/* Reusable heading style — add `.deco` to a `.section-title` and optionally an
`.section-eyebrow` above the h2 and an `.section-subtitle` below it. */
.section-eyebrow {
display: inline-block;
font-size: .8rem;
font-weight: 700;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--fitme-accent);
margin-bottom: .5rem;
}
/* Short titles (e.g. "Modalidades") would otherwise sit on the eyebrow's line. */
.section-title.deco .section-eyebrow {
display: block;
}
/* Eyebrow on light sections: the neon accent is ~1.6:1 there (WCAG AA needs
4.5:1), so those use the ink green; dark sections keep the bright accent. */
.feature-section .section-eyebrow,
.gallery-section .section-eyebrow,
.service-section .section-eyebrow,
.schedule-section .section-eyebrow,
.workhours-section .section-eyebrow {
color: var(--fitme-accent-ink);
}
.section-title.deco h2 {
position: relative;
display: inline-block;
padding-bottom: .7rem;
}
.section-title.deco h2:after {
content: '';
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
width: 64px;
height: 4px;
background: var(--fitme-accent); /* slashed ends: "Brand slash" template */
}
.section-subtitle {
color: var(--fitme-text-muted);
margin-top: .9rem;
margin-bottom: 0;
font-size: 1rem;
}
/* ── Modalidades: scrollable strip + detail card ─────────────────────────────
.mod-scroll is a real horizontal scroller (touch, trackpad, wheel, mouse
drag, arrow buttons). main.js glides it on its own until someone interacts,
and loops it seamlessly over a cloned second set of cards. */
/* content-visibility:auto implies paint containment, which would clip the
detail card at the section edge and trap position:fixed on touch. */
#modalidades.service-section {
content-visibility: visible;
contain: none;
position: relative;
z-index: 2;
}
#modalidades.has-open-detail { z-index: 1100; }
.mod-strip {
position: relative;
}
/* Soft fades at both ends, under the arrow buttons. */
.mod-strip:before,
.mod-strip:after {
content: '';
position: absolute;
top: 0;
bottom: 0;
z-index: 2;
width: 90px;
pointer-events: none;
}
.mod-strip:before { left: 0; background: linear-gradient(90deg, var(--fitme-white), rgba(255, 255, 255, 0)); }
.mod-strip:after { right: 0; background: linear-gradient(270deg, var(--fitme-white), rgba(255, 255, 255, 0)); }
@media (max-width: 767px), (hover: none) {
.mod-strip:before, .mod-strip:after { width: 28px; }
}
.mod-scroll {
display: flex;
overflow-x: auto;
overflow-y: hidden;
padding: 10px 0 14px;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
overscroll-behavior-x: contain;
cursor: grab;
outline: none;
}
.mod-scroll::-webkit-scrollbar { display: none; }
.mod-scroll.is-dragging { cursor: grabbing; user-select: none; }
.mod-scroll.is-dragging .mod-card { pointer-events: none; }
/* Trailing margin (not flex gap) keeps both copies the same width, so the
loop jump from the clone back to the original is invisible. */
.mod-scroll .mod-card {
flex: 0 0 auto;
width: 180px;
min-height: 200px;
margin: 0 .5rem 0 0;
position: relative;
}
.mod-scroll .mod-card:first-child { margin-left: .5rem; }
.mod-card.has-info { cursor: pointer; outline: none; }
.mod-card.has-info:hover h3 { color: var(--fitme-accent-ink); }
.mod-card.has-info:focus-visible {
box-shadow: 0 0 0 3px rgba(var(--fitme-accent-rgb), .35);
border-radius: var(--fitme-radius);
}
/* The card whose detail is open is covered by the panel — hide it so the
panel reads as the card itself. */
.mod-card.is-source { visibility: hidden; }
/* Arrow buttons (desktop). Faded edges hint there is more to either side. */
.mod-nav {
position: absolute;
top: 50%;
z-index: 3;
width: 44px;
height: 44px;
margin-top: -30px;
border: 0;
border-radius: 50%;
background: var(--fitme-dark-2);
color: var(--fitme-accent);
box-shadow: var(--fitme-shadow-lg);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
opacity: .9;
transition: opacity var(--fitme-transition), transform var(--fitme-transition);
}
.mod-nav:hover { opacity: 1; transform: scale(1.06); }
.mod-nav-prev { left: 14px; }
.mod-nav-next { right: 14px; }
@media (max-width: 767px), (hover: none) {
.mod-nav { display: none; }
.mod-scroll { cursor: auto; }
}
/* ── Detail panel: grows out of the card ───────────────────────────────────
Same idea as the team card: main.js lays the panel so its left column
(.md-card, a replica of the card) sits exactly on the card, clipped to it;
opening unclips it sideways to reveal the description (.md-flip mirrors it
near the right edge). While open, the mouse drives a small 3D tilt. */
.mod-detail {
position: absolute;
z-index: 30;
left: var(--md-x, 0px);
top: var(--md-y, 0px);
width: var(--md-w, 540px);
min-height: var(--md-ch, 200px);
display: flex;
text-align: left;
background: #fff;
border-radius: 6px;
/* Discreet lift. Only visible because the open clip-path below reaches
40px past the card — a flush inset() would cut the shadow off. */
box-shadow: 0 12px 30px rgba(var(--fitme-dark-rgb), .16), 0 2px 6px rgba(var(--fitme-dark-rgb), .10);
overflow: hidden;
clip-path: inset(0px var(--md-cx, 360px) var(--md-cy, 0px) 0px round 2px);
transform-origin: calc(var(--md-cw, 180px) / 2) 50%;
transform: perspective(900px) rotateX(0deg) rotateY(0deg) translate(0px, 0px) scale(1);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition:
clip-path .38s cubic-bezier(.4, 0, .2, 1),
transform .38s cubic-bezier(.4, 0, .2, 1),
opacity .12s ease .26s,
visibility 0s linear .38s;
}
.mod-detail.md-flip {
flex-direction: row-reverse;
clip-path: inset(0px 0px var(--md-cy, 0px) var(--md-cx, 360px) round 2px);
transform-origin: calc(100% - var(--md-cw, 180px) / 2) 50%;
}
.mod-detail.is-open {
clip-path: inset(-40px -40px -40px -40px round 6px);
transform: perspective(900px) rotateX(var(--md-rx, 0deg)) rotateY(var(--md-ry, 0deg)) translate(var(--md-mx, 0px), var(--md-my, -6px)) scale(1.02);
opacity: 1;
visibility: visible;
pointer-events: auto;
transition:
clip-path .55s cubic-bezier(.2, .9, .25, 1),
transform .6s cubic-bezier(.34, 1.35, .64, 1),
opacity 0s,
visibility 0s;
}
.mod-detail.is-open.md-tracking {
transition:
clip-path .55s cubic-bezier(.2, .9, .25, 1),
transform .18s ease-out,
opacity 0s,
visibility 0s;
}
/* Left column: looks exactly like the card it came from. */
.md-card {
flex: 0 0 var(--md-cw, 180px);
min-height: var(--md-ch, 200px);
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding-top: var(--md-pad, 0px);
text-align: center;
background: #fff;
border-right: 4px solid var(--md-color, var(--fitme-accent));
}
.md-flip .md-card { border-right: 0; border-left: 4px solid var(--md-color, var(--fitme-accent)); }
.md-card .ib-icon {
width: 72px;
height: 72px;
border-radius: var(--fitme-radius);
display: flex;
align-items: center;
justify-content: center;
background: var(--fitme-accent);
margin: 0 auto 1.5rem;
}
.md-card .ib-icon img { max-width: 44px; max-height: 44px; }
.md-card h3 {
font-size: 1.15rem;
margin: 0 .5rem;
color: var(--fitme-accent-ink);
}
.md-body {
flex: 1 1 auto;
padding: 20px 24px 20px 22px;
max-height: 320px;
overflow-y: auto;
opacity: 0;
transform: translateX(-10px);
transition: opacity .12s ease, transform .12s ease;
}
.md-flip .md-body { transform: translateX(10px); }
.mod-detail.is-open .md-body {
opacity: 1;
transform: none;
transition: opacity .3s ease .18s, transform .35s ease .18s;
}
.md-name {
display: block;
font-size: 1.2rem;
font-weight: 900;
text-transform: uppercase;
color: var(--fitme-dark);
margin-bottom: .5rem;
padding-right: 18px;
}
.md-text {
font-size: .9rem;
line-height: 1.55;
color: var(--fitme-text-soft);
}
.md-text p:last-child { margin-bottom: 0; }
.md-close {
position: absolute;
top: 0;
right: 0;
z-index: 2;
width: 44px;
height: 44px;
display: none;
align-items: center;
justify-content: center;
background: transparent;
border: 0;
font-size: 1.6rem;
line-height: 1;
color: var(--fitme-text-muted);
cursor: pointer;
}
/* Touch / narrow: a centred fixed card over a dimmed page; main.js flies it
out of the card with a FLIP animation. */
@media (max-width: 767px), (hover: none) {
.mod-detail,
.mod-detail.md-flip {
position: fixed;
top: var(--md-top, 20vh);
left: 16px;
right: 16px;
width: auto;
max-width: 540px;
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;
}
.mod-detail.is-open {
clip-path: none;
transform: none;
transition: opacity 0s, visibility 0s;
}
.mod-detail-backdrop {
position: fixed;
inset: 0;
z-index: 29;
background: rgba(0, 0, 0, .55);
}
.md-close { display: flex; }
.md-card { flex-basis: 120px; min-height: 0; padding: 18px 6px; justify-content: center; }
.md-flip .md-card { border-left: 0; border-right: 4px solid var(--md-color, var(--fitme-accent)); }
.md-card .ib-icon { width: 60px; height: 60px; margin-bottom: .8rem; }
.md-card h3 { font-size: .95rem; }
.md-body,
.md-flip .md-body { max-height: calc(100dvh - 48px); padding: 16px 16px 16px 14px; transform: none; }
}
@media (max-width: 575px) {
.mod-detail, .mod-detail.md-flip { flex-direction: column; }
.md-card { flex-basis: auto; border-right: 0; border-bottom: 4px solid var(--md-color, var(--fitme-accent)); }
}
/* ── Horário "save as JPG" link + capture-clone export board ────────────────
A plain underlined link rather than a button — secondary action, shouldn't
compete with the day-filter bar right below it. */
.schedule-dl-btn {
display: inline-flex;
align-items: center;
gap: 6px;
border: none;
background: none;
cursor: pointer;
color: var(--fitme-accent-ink);
font-weight: 700;
font-size: .85rem;
letter-spacing: .3px;
/* Alvo de toque ≥44px sem engordar o visual: padding compensado por
margin negativa (o texto sublinhado fica do mesmo tamanho). */
padding: 12px 4px;
margin: -12px -4px;
min-height: 44px;
text-decoration: none;
transition: color var(--fitme-transition);
}
.schedule-dl-btn:hover {
color: var(--fitme-accent);
}
.schedule-dl-btn:disabled {
opacity: .6;
cursor: default;
}
/* Applied (via html2canvas onclone) to the schedule clone inside the capture
iframe — never visible on the live page. */
.schedule-export {
width: 1920px;
padding: 48px 40px 32px;
box-sizing: border-box;
background: var(--fitme-surface);
}
/* html2canvas snapshots the page inside a hidden iframe where the .fade-in /
.revealed entry animations restart from their opacity:0 keyframe — freeze
every node at its final visible state or the JPG exports blank white. */
.schedule-export,
.schedule-export * {
animation: none !important;
transition: none !important;
opacity: 1 !important;
}
.schedule-stamp {
text-align: center;
margin: 22px 0 0;
font-size: .9rem;
font-weight: 700;
letter-spacing: .3px;
color: var(--fitme-text-soft);
}
/* Force the full desktop time-grid inside the export board, independent of the
real viewport's media queries (otherwise a phone renders the clone with the
mobile single-column layout → a tall, mostly-empty image). */
.schedule-export .container {
max-width: none !important;
width: 100% !important;
}
.schedule-export .schedule-scroll-hint {
display: none !important;
}
.schedule-export .schedule_container {
overflow: visible !important;
}
.schedule-export .schedule_panel {
display: grid !important;
grid-template-columns: repeat(var(--sched-days, 6), minmax(0, 1fr)) !important;
align-items: start !important;
column-gap: 14px !important;
row-gap: 14px !important;
min-width: 0 !important;
margin: 0 !important;
padding: 0 !important;
-webkit-mask-image: none !important;
mask-image: none !important;
}
/* Cells keep their inline grid-row/grid-column placement: the capture iframe is
1920px wide so the ≤767px single-column override never applies, and inline
styles outrank these stylesheet rules anyway. */
.schedule-export .schedule_box {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
}
/* On-screen single-day layout — one centred column showing the chosen day's
classes in time order, keeping the Manhã / Tarde dividers as section breaks.
Scoped to :not(.schedule-export) so the capture clone keeps the full week. */
.schedule:not(.schedule-export) .schedule_container {
overflow-x: visible;
}
.schedule:not(.schedule-export) .schedule_panel {
grid-template-columns: minmax(0, 720px); /* single, comfortably wide column */
justify-content: center; /* …centred in the section */
column-gap: 0;
row-gap: 0;
min-width: 0;
margin: 1rem auto 0;
-webkit-mask-image: none;
mask-image: none;
}
/* Day stripes are a week-only device; drop them. Keep the Manhã/Tarde labels. */
.schedule:not(.schedule-export) .schedule_stripe {
display: none;
}
.schedule:not(.schedule-export) .schedule_section_label {
grid-column: 1;
margin: .9rem 0 1.1rem;
}
/* Pull the selected day's header + cells into the single column (override the
inline grid-column that otherwise places them under their weekday). */
.schedule:not(.schedule-export) .schedule_dayhead {
grid-column: 1 !important;
margin-bottom: 1.1rem;
}
.schedule:not(.schedule-export) .schedule_cell {
grid-column: 1 !important;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 1rem;
}
/* A lone class stays a tidy card instead of stretching the whole column. */
.schedule:not(.schedule-export) .schedule_cell > .schedule_box {
flex: 0 1 220px;
}
/* Hide every day but the selected one, plus any empty Manhã/Tarde divider
(JS toggles .sched-hide by data-day / by section). */
.schedule:not(.schedule-export) .schedule_cell.sched-hide,
.schedule:not(.schedule-export) .schedule_dayhead.sched-hide,
.schedule:not(.schedule-export) .schedule_section_label.sched-hide {
display: none !important;
}
/* Single-day mode: no day-filter bar any more (audit UX pass) — the header
itself is the only day switcher, so it always shows, with prev/next arrows
beside the day name. Kept plain (no arrows) for the 3-day desktop view
(.is-3day), where the side days are already directly clickable. */
.schedule:not(.schedule-export):not(.is-3day) .schedule_dayhead {
gap: 10px;
align-items: center;
}
/* Desktop 3-day view: arrows stay only beside the centred/focused day —
the side days are already directly clickable, arrows there would be noise. */
.schedule.is-3day .schedule_dayhead.sched-side .sched-nav,
.schedule-export .sched-nav {
display: none;
}
.sched-nav {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border: none;
border-radius: var(--fitme-radius);
background: var(--fitme-surface-2);
color: var(--fitme-text-soft);
font-size: 1rem;
cursor: pointer;
transition: background var(--fitme-transition), color var(--fitme-transition);
flex: 0 0 auto;
}
.sched-nav:hover {
background: var(--fitme-accent);
color: var(--fitme-dark);
}
.schedule-scroll-hint {
display: none !important;
}
/* ── Horário: compact cards (on screen, every width) ───────────────────────────
Smaller, narrower cards and type so a day reads at a glance and three days
fit side by side on desktop. The JPG export keeps its own sizing. */
.schedule:not(.schedule-export) .schedule_cell {
gap: 6px;
margin-bottom: .6rem;
}
.schedule:not(.schedule-export) .schedule_cell > .schedule_box {
flex: 0 1 112px;
padding: 6px 3px;
}
.schedule:not(.schedule-export) .schedule_box img {
height: 22px;
margin-bottom: 2px;
}
.schedule:not(.schedule-export) .schedule_box a {
font-size: 10px;
min-height: 2.3em;
}
.schedule:not(.schedule-export) .schedule_info {
margin: auto -3px -6px;
padding: 4px 6px;
font-size: 11.5px;
min-height: 2.4em;
}
.schedule:not(.schedule-export) .schedule_box:hover {
transform: scale(1.05);
}
.schedule:not(.schedule-export) .schedule_dayhead {
margin-bottom: .7rem;
}
.schedule:not(.schedule-export) .rounded_frame {
width: 104px;
height: 32px;
font-size: .95rem;
}
.schedule:not(.schedule-export) .schedule_section_label {
margin: .5rem 0 .8rem;
}
.schedule:not(.schedule-export) .schedule_section_label span {
font-size: .72rem;
}
/* ── Desktop: yesterday · today · tomorrow ─────────────────────────────────────
≥992px, main.js shows three days — the chosen one (today by default) centred
between its neighbours, wrapping round the week — and tags each visible
header/cell with .sched-pos-1/2/3 for its column. Rows stay time-aligned, so
classes at the same hour line up across the three days. The side days are
toned down so the centre one leads. */
@media (min-width: 992px) {
.schedule.is-3day:not(.schedule-export) .schedule_panel {
grid-template-columns: repeat(3, minmax(0, 420px));
column-gap: 28px;
}
.schedule.is-3day:not(.schedule-export) .schedule_section_label {
grid-column: 1 / -1;
}
.schedule.is-3day:not(.schedule-export) .sched-pos-1 { grid-column: 1 !important; }
.schedule.is-3day:not(.schedule-export) .sched-pos-2 { grid-column: 2 !important; }
.schedule.is-3day:not(.schedule-export) .sched-pos-3 { grid-column: 3 !important; }
.schedule.is-3day:not(.schedule-export) .schedule_cell.sched-side {
opacity: .5;
transition: opacity var(--fitme-transition);
}
.schedule.is-3day:not(.schedule-export) .schedule_cell.sched-side:hover {
opacity: 1;
}
.schedule.is-3day:not(.schedule-export) .schedule_dayhead.sched-side .rounded_frame {
background: var(--fitme-surface-2);
color: var(--fitme-text-muted);
}
.schedule.is-3day:not(.schedule-export) .schedule_dayhead.sched-pos-2 .rounded_frame {
background: var(--fitme-accent);
color: var(--fitme-dark);
}
.schedule.is-3day:not(.schedule-export) .schedule_dayhead.sched-side {
cursor: pointer;
}
.schedule.is-3day:not(.schedule-export) .schedule_dayhead.sched-pos-2 {
gap: 10px;
align-items: center;
}
}
/* ── Aula experimental modal ───────────────────────────────────────────────── */
.modal-content.trial-modal {
background: #fff !important;
border-radius: var(--fitme-radius);
overflow: hidden;
box-shadow: var(--fitme-shadow-lg);
}
.trial-modal-head {
position: relative;
background: var(--fitme-dark-2);
color: #fff;
padding: 1.75rem 1.75rem 1.5rem;
}
.trial-modal-head h3 {
margin: 0 0 .4rem;
font-weight: 900;
font-size: 1.5rem;
color: #fff; /* override the global dark h1–h6 colour (black-on-dark otherwise) */
}
.trial-modal-head p {
margin: 0;
color: var(--fitme-ash);
font-size: .92rem;
}
.trial-close {
position: absolute;
top: 12px;
right: 16px;
background: transparent;
border: none;
color: #fff;
font-size: 1.8rem;
line-height: 1;
cursor: pointer;
opacity: .8;
transition: opacity var(--fitme-transition);
}
.trial-close:hover {
opacity: 1;
}
.trial-form {
padding: 1.5rem 1.75rem 1.75rem;
}
.trial-form input,
.trial-form select,
.trial-form textarea {
width: 100%;
border: 1px solid var(--fitme-surface-2);
border-radius: var(--fitme-radius);
padding: 12px 14px;
font-size: .95rem;
color: var(--fitme-text);
background: #fff;
transition: box-shadow var(--fitme-transition), border-color var(--fitme-transition);
}
.trial-form input:focus,
.trial-form select:focus,
.trial-form textarea:focus {
border-color: var(--fitme-accent);
box-shadow: 0 0 0 3px rgba(var(--fitme-accent-rgb), .25);
}
.trial-form textarea {
resize: vertical;
}
.trial-form .consent-check {
margin-bottom: 1rem;
color: var(--fitme-text-soft);
}
.trial-form .consent-check a {
color: var(--fitme-text);
}
.trial-form .consent-check a:hover {
color: var(--fitme-accent-ink);
}
.trial-form .site-btn {
border: none;
}
/* ══════════════════════════════════════════════════════════════════════════
Events — homepage banner + landing page (/evento/<slug>)
══════════════════════════════════════════════════════════════════════════ */
/* ── Active events — featured inside the hero/header ───────────────────────── */
.event-live-dot {
width: 9px; height: 9px;
flex: 0 0 auto;
border-radius: 50%;
background: var(--fitme-accent);
box-shadow: 0 0 0 0 rgba(var(--fitme-accent-rgb), .7);
animation: event-pulse 1.8s infinite;
}
@keyframes event-pulse {
0% { box-shadow: 0 0 0 0 rgba(var(--fitme-accent-rgb), .7); }
70% { box-shadow: 0 0 0 10px rgba(var(--fitme-accent-rgb), 0); }
100% { box-shadow: 0 0 0 0 rgba(var(--fitme-accent-rgb), 0); }
}
.hero-events {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
margin-bottom: 1.75rem;
}
.hero-event {
--ev-accent: var(--fitme-accent);
position: relative;
overflow: hidden;
display: flex;
align-items: center;
gap: 16px;
width: min(640px, 92vw);
min-height: 88px;
padding: 18px 18px 18px 22px;
background: linear-gradient(90deg, rgba(11, 11, 13, .62), rgba(11, 11, 13, .42));
border: 1.5px solid var(--ev-accent); /* same colour as its button */
text-decoration: none;
text-align: left;
animation: hero-event-glow 2.8s ease-in-out infinite;
transition: transform var(--fitme-transition), box-shadow var(--fitme-transition), border-color var(--fitme-transition);
}
/* Defocus gradient: ::after blurs whatever is behind it (the event image in
::before, or the hero photo through the translucent bg), masked so the left is
sharp and the right most out of focus. .hero-event itself must not get
filter/backdrop-filter/opacity/mask, or it becomes the backdrop root and the
blur stops reaching the hero photo. */
.hero-event::after {
content: '';
position: absolute;
inset: 0;
z-index: 0;
pointer-events: none;
-webkit-backdrop-filter: blur(14px);
backdrop-filter: blur(14px);
-webkit-mask-image: linear-gradient(90deg, transparent 10%, #000 90%);
mask-image: linear-gradient(90deg, transparent 10%, #000 90%);
}
/* The event's own image as a darkened backdrop inside the card, only when
--ev-img is set; otherwise the translucent dark bg shows. */
.hero-event.has-img::before {
content: '';
position: absolute;
inset: 0;
z-index: 0;
background-image: var(--ev-img);
background-size: cover;
background-position: center;
filter: saturate(1.15) brightness(.5);
transform: scale(1.04);
transition: transform var(--fitme-transition);
}
.hero-event.has-img:hover::before { transform: scale(1.1); }
/* Keep the content above the image layer. */
.hero-event > * { position: relative; z-index: 1; }
@keyframes hero-event-glow {
0%, 100% { box-shadow: 0 10px 34px rgba(0,0,0,.45), 0 0 18px rgba(var(--fitme-accent-rgb), .14); }
50% { box-shadow: 0 10px 34px rgba(0,0,0,.45), 0 0 30px rgba(var(--fitme-accent-rgb), .32); }
}
.hero-event:hover {
transform: translateY(-2px);
border-color: var(--ev-accent);
box-shadow: 0 16px 44px rgba(0, 0, 0, .55), 0 0 34px rgba(var(--fitme-accent-rgb), .38);
}
.hero-event-badge {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
gap: 7px;
padding: 7px 13px;
font-size: .72rem;
font-weight: 800;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--fitme-accent);
background: rgba(var(--fitme-accent-rgb), .14);
}
.hero-event-text {
flex: 1 1 auto;
min-width: 0;
display: flex;
flex-direction: column;
line-height: 1.22;
}
.hero-event-title {
font-size: 1.12rem;
font-weight: 800;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hero-event-sub {
font-size: .9rem;
color: rgba(255, 255, 255, .72);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.hero-event-go {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 11px 20px;
font-size: .92rem;
font-weight: 700;
white-space: nowrap;
color: var(--ev-on, var(--fitme-on-accent)); /* set from the event colour (index.php) */
background: var(--ev-accent);
}
.hero-event-go i { transition: transform var(--fitme-transition); }
.hero-event:hover .hero-event-go i { transform: translateX(4px); }
@media (max-width: 575px) {
.hero-event {
flex-wrap: wrap;
justify-content: center;
text-align: center;
gap: 10px;
padding: 18px 14px;
}
.hero-event-text { flex-basis: 100%; align-items: center; }
.hero-event-title, .hero-event-sub { white-space: normal; }
.hero-event-go { flex-basis: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
.hero-event { animation: none; }
.event-live-dot { animation: none; }
}
/* ── Staff preview ribbon ──────────────────────────────────────────────────── */
.event-preview-bar {
position: sticky;
top: 0;
z-index: 1080;
padding: 8px 16px;
text-align: center;
font-size: .85rem;
font-weight: 600;
color: var(--fitme-text);
background: #ffd84d;
}
/* ── Landing hero ──────────────────────────────────────────────────────────── */
.event-hero {
position: relative;
display: flex;
align-items: center;
min-height: 70vh;
padding: 160px 0 90px;
background-size: cover;
background-position: center;
color: #fff;
}
.event-hero--plain {
background: linear-gradient(135deg, var(--fitme-dark) 0%, var(--fitme-dark-2) 100%);
}
.event-hero-overlay {
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(11,11,13,.35) 0%, rgba(11,11,13,.78) 100%);
}
.event-hero .container { position: relative; z-index: 2; }
.event-hero-inner { max-width: 760px; }
.event-hero-eyebrow {
display: inline-block;
font-size: .8rem;
font-weight: 700;
letter-spacing: 3px;
text-transform: uppercase;
margin-bottom: 14px;
}
.event-hero-inner h1 {
font-size: clamp(2.2rem, 5vw, 3.6rem);
line-height: 1.08;
margin: 0 0 14px;
color: #fff;
}
.event-hero-sub {
font-size: 1.2rem;
color: rgba(255,255,255,.85);
margin-bottom: 20px;
}
.event-hero-meta {
list-style: none;
padding: 0;
margin: 0 0 26px;
display: flex;
flex-wrap: wrap;
gap: 10px 26px;
}
.event-hero-meta li {
font-size: 1rem;
color: rgba(255,255,255,.9);
}
.event-hero-meta i { margin-right: 8px; opacity: .85; }
.event-hero-cta { border: none; color: var(--fitme-dark) !important; }
/* ── Landing body (admin HTML) ─────────────────────────────────────────────── */
.event-body { padding: 70px 0; background: var(--fitme-white); }
.event-body p { font-size: 1.05rem; line-height: 1.7; color: var(--fitme-text-soft); }
.event-body h2, .event-body h3, .event-body h4 { margin-top: 1.6rem; }
.event-body img { max-width: 100%; height: auto; border-radius: var(--fitme-radius); }
/* ── Lead form ─────────────────────────────────────────────────────────────── */
.event-leadform { padding: 70px 0; background: var(--fitme-surface); }
.event-form { margin-top: 26px; }
.event-form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.event-field--full { grid-column: 1 / -1; }
.event-field label {
display: block;
font-size: .85rem;
font-weight: 600;
margin-bottom: 6px;
color: var(--fitme-text-soft);
}
.event-field input,
.event-field textarea {
width: 100%;
padding: 12px 14px;
font-size: 1rem;
background: var(--fitme-white);
border: 1px solid var(--fitme-surface-dark);
border-radius: var(--fitme-radius);
color: var(--fitme-text);
}
.event-field input:focus,
.event-field textarea:focus {
outline: none;
border-color: var(--fitme-accent);
box-shadow: 0 0 0 3px rgba(var(--fitme-accent-rgb), .2);
}
/* honeypot — visually hidden, kept in the layout flow for bots */
.event-hp {
position: absolute !important;
left: -9999px;
width: 1px;
height: 1px;
opacity: 0;
}
.event-alert {
padding: 12px 16px;
margin-bottom: 16px;
border-radius: var(--fitme-radius);
font-size: .95rem;
}
.event-alert--ok { background: #e6f6ea; color: #1c6b34; border: 1px solid #9fdcb0; }
.event-alert--err { background: #fdecec; color: #a32424; border: 1px solid #f1b5b5; }
.event-consent {
display: flex;
align-items: flex-start;
gap: 9px;
margin-top: 16px;
font-size: .88rem;
color: var(--fitme-text-soft);
cursor: pointer;
}
.event-consent input { margin-top: 3px; flex: 0 0 auto; }
.event-consent a { color: var(--fitme-accent-ink); text-decoration: none; }
@media (max-width: 575px) {
.event-form-grid { grid-template-columns: 1fr; }
}
/* ══════════════════════════════════════════════════════════════════════════
Equipa — título + cartão de detalhe horizontal
Default card = photo + name + title. The detail card is laid OVER the grid
(absolute), so opening it never reflows the team wall. Desktop (fine pointer)
opens it on hover / keyboard focus; touch opens it on tap (.is-open, main.js),
where it becomes a centred fixed card with its own close button.
══════════════════════════════════════════════════════════════════════════ */
/* content-visibility:auto implies paint containment, which would clip the
overlay at the section edge and trap position:fixed inside the section. */
#equipa.trainers-section {
content-visibility: visible;
contain: none;
position: relative;
z-index: 3; /* hover card may overhang the next section */
}
/* While a card is open on touch, lift the whole section over the navbar and
the mobile CTA bar so the dimmed backdrop covers everything. */
#equipa.trainers-section.has-open-detail {
z-index: 1100;
}
/* The global scroll-reveal keeps transform:translateY(0) applied (fill
forwards), and any transform makes an element the containing block for
position:fixed descendants — which would pin the mobile detail card inside
its own tile. Reveal the team with opacity only. */
#equipa.revealed,
#equipa .trainer-item.revealed,
#modalidades.revealed {
animation-name: fitmeFadeOnly;
}
@keyframes fitmeFadeOnly {
from { opacity: 0; }
to { opacity: 1; }
}
.trainer-item {
position: relative;
}
/* The name used to be the tile's last child and got its size from the
`.trainer-item>*:last-child` rule; pin it so it stays the same whether or
not a title follows it. */
.trainers-section .trainer-item h3,
.trainers-section .trainer-item h4 {
font-size: .9rem;
}
/* …and keep that same rule (white, .9rem) off the detail card when it is the
last child. */
.trainers-section .trainer-item>.trainer-detail {
color: var(--fitme-text);
font-size: 1rem;
}
.trainers-section .trainer-item p.trainer-title {
margin: 0;
font-size: .85rem;
font-weight: 600;
letter-spacing: .04em;
color: var(--fitme-accent);
}
.trainer-item.has-detail {
cursor: pointer;
outline: none;
}
/* On tiles with a card, the card IS the hover effect: keep the photo in its
resting tilt (the card starts from exactly that pose) and hide it while the
card covers it, bringing it back only once the card has folded back in. */
#powerRotation>div:nth-child(odd) .trainer-item.has-detail .trainer-pic:hover { transform: rotate(-3deg); }
#powerRotation>div:nth-child(even) .trainer-item.has-detail .trainer-pic:hover { transform: rotate(3deg); }
.trainer-item.has-detail .trainer-pic {
transition: transform .4s cubic-bezier(.34, 1.56, .64, 1), box-shadow var(--fitme-transition), visibility 0s linear .38s;
}
.trainer-item.has-detail.is-open .trainer-pic {
visibility: hidden;
transition-delay: 0s;
}
@media (max-width: 767px), (hover: none) {
/* Touch: the card flies to the centre, so leave the tile photo in place. */
.trainer-item.has-detail.is-open .trainer-pic { visibility: visible; }
}
/* ── Detail card: grows out of the tile's own photo ─────────────────────────
main.js places the card so its photo column sits exactly on the tile photo
(--td-x/--td-y, size --td-pw/--td-ph) with the tile's tilt (--td-rot). Closed,
the clip-path shows only that photo square, so it reads as the tile itself;
opening straightens it and unclips it sideways — the card "stretches" out of
the photo and the text fades in behind the edge. .td-flip mirrors it for
right-hand tiles (photo on the right, card stretching left). While open, the
mouse position feeds a small 3D tilt + drift (--td-rx/--td-ry/--td-mx/--td-my).
Both transform lists have the same functions so they interpolate. */
.trainer-detail {
position: absolute;
z-index: 30;
left: var(--td-x, 0px);
top: var(--td-y, 0px);
width: var(--td-w, 560px);
min-height: var(--td-ph, 200px);
display: flex;
text-align: left;
background: #fff;
color: var(--fitme-text);
border-radius: 6px;
/* Discreet lift (a little deeper than the modalidades one: it sits on the
dark grey team backdrop). Visible only because the open clip-path reaches
40px past the card. */
box-shadow: 0 12px 30px rgba(0, 0, 0, .32), 0 2px 6px rgba(0, 0, 0, .18);
overflow: hidden;
/* px from main.js: Chrome won't interpolate inset() with calc(100% - …). */
clip-path: inset(0px var(--td-cx, 360px) var(--td-cy, 0px) 0px round 2px);
transform-origin: calc(var(--td-pw, 200px) / 2) calc(var(--td-ph, 200px) / 2);
transform: perspective(900px) rotateX(0deg) rotateY(0deg) translate(0px, 0px) rotate(var(--td-rot, 0deg));
opacity: 0;
visibility: hidden;
pointer-events: none;
transition:
clip-path .38s cubic-bezier(.4, 0, .2, 1),
transform .38s cubic-bezier(.4, 0, .2, 1),
opacity .12s ease .26s,
visibility 0s linear .38s;
}
.trainer-detail.td-flip {
flex-direction: row-reverse;
clip-path: inset(0px 0px var(--td-cy, 0px) var(--td-cx, 360px) round 2px);
transform-origin: calc(100% - var(--td-pw, 200px) / 2) calc(var(--td-ph, 200px) / 2);
}
.trainer-item.is-open .trainer-detail {
clip-path: inset(-40px -40px -40px -40px round 6px);
transform: perspective(900px) rotateX(var(--td-rx, 0deg)) rotateY(var(--td-ry, 0deg)) translate(var(--td-mx, 0px), var(--td-my, 0px)) rotate(0deg);
opacity: 1;
visibility: visible;
pointer-events: auto;
transition:
clip-path .55s cubic-bezier(.2, .9, .25, 1),
transform .6s cubic-bezier(.34, 1.35, .64, 1),
opacity 0s,
visibility 0s;
}
/* After the opening move, follow the mouse with a short, soft transition. */
.trainer-item.is-open .trainer-detail.td-tracking {
transition:
clip-path .55s cubic-bezier(.2, .9, .25, 1),
transform .18s ease-out,
opacity 0s,
visibility 0s;
}
.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);
position: relative;
isolation: isolate;
}
/* Slow brand-colour light drifting over the metal: three soft blobs in the
current gym's colour (and a paler tint of it) on a 200% layer whose position
eases back and forth. Sits above the section background, below the content. */
.pricing-section::before {
content: '';
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
background:
radial-gradient(38% 50% at 18% 28%, rgba(var(--fitme-accent-rgb), .4), transparent 70%),
radial-gradient(34% 46% at 82% 72%, color-mix(in srgb, color-mix(in srgb, var(--fitme-accent) 55%, #fff) 26%, transparent), transparent 70%),
radial-gradient(30% 42% at 55% 105%, rgba(var(--fitme-accent-rgb), .32), transparent 70%);
background-size: 200% 200%;
animation: pricing-drift 26s ease-in-out infinite alternate;
}
@keyframes pricing-drift {
0% { background-position: 0% 0%; }
50% { background-position: 100% 40%; }
100% { background-position: 30% 100%; }
}
@media (prefers-reduced-motion: reduce) {
.pricing-section::before { animation: none; }
}
.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 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-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-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;
height: var(--gal-h);
margin-right: var(--gal-gap);
}
.gal-unit--full { width: calc(var(--gal-h) * .82); }
.gal-unit--grid {
width: calc(var(--gal-h) * 1.05);
display: grid;
grid-template: 1fr 1fr / 1fr 1fr;
gap: var(--gal-gap);
}
.gal-tile { position: relative; margin: 0; min-width: 0; min-height: 0; height: 100%; }
@media (max-width: 991px) { .gal-wrap { --gal-h: 340px; } }
@media (max-width: 575px) { .gal-wrap { --gal-h: 260px; --gal-gap: 8px; margin-bottom: 48px; } }
.gal-link {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
border-radius: var(--fitme-radius); /* brand: square-ish corners */
position: relative;
background: var(--fitme-surface-2);
cursor: zoom-in;
}
/* .jxl images are <picture> (img_tag): let the <img> size against its parent as before. */
.gal-link picture, .navbar-brand picture, .gym-switch-btn picture { display: contents; }
.gal-link img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform .6s cubic-bezier(.2, .8, .2, 1), filter .4s ease;
}
/* Accent frame + slow zoom on hover / focus. */
.gal-link::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: inset 0 0 0 0 var(--fitme-accent);
transition: box-shadow .3s ease;
pointer-events: none;
}
.gal-link:hover img,
.gal-link:focus-visible img {
transform: scale(1.06);
filter: brightness(1.05);
}
/* Hover: the frame becomes the spinning brand-colour edge (same as buttons and
Mensalidades cards): ::after = 3px ring cut out with a mask, ::before = soft
inner glow. */
.gal-link::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: inset 0 0 22px 2px rgba(var(--fitme-accent-rgb), .5);
opacity: 0;
transition: opacity .45s ease;
pointer-events: none;
z-index: 1;
}
.gal-link::after {
z-index: 2;
padding: 3px;
box-shadow: none;
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;
}
.gal-link:hover::before,
.gal-link:focus-visible::before { opacity: 1; }
.gal-link:hover::after,
.gal-link:focus-visible::after { opacity: 1; animation: pc-spin 3.2s linear infinite; }
@media (prefers-reduced-motion: reduce) {
.gal-link:hover::after { animation: none; }
}
/* ── 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:hover img { filter: saturate(1); }
/* 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
out stretched and unreadable. Give their box a wide landscape shape and keep
the natural aspect ratio. */
.icon-box-item .ib-icon:has(img[src*="yourfit"]),
.md-card .ib-icon:has(img[src*="yourfit"]) {
width: 148px;
max-width: 100%;
}
.icon-box-item .ib-icon img[src*="yourfit"],
.md-card .ib-icon img[src*="yourfit"] {
width: 124px;
height: auto;
max-width: 100%;
max-height: none;
object-fit: contain;
}
/* At rest the YOURFIT lock-ups are black like every other icon; their own
(certified) colours come back on hover, on the white face. */
.icon-box-item .ib-icon img[src*="yourfit"],
.md-card .ib-icon img[src*="yourfit"] {
filter: brightness(0);
transition: filter .45s ease;
}
@media (max-width: 767px) {
.icon-box-item .ib-icon:has(img[src*="yourfit"]),
.md-card .ib-icon:has(img[src*="yourfit"]) { width: 128px; }
.icon-box-item .ib-icon img[src*="yourfit"],
.md-card .ib-icon img[src*="yourfit"] { width: 106px; }
}
/* Lightbox */
.gal-lightbox {
width: 100vw;
height: 100dvh;
max-width: none;
max-height: none;
margin: 0;
padding: 0;
border: 0;
background: transparent;
color: #fff;
}
.gal-lightbox[open] {
display: flex;
align-items: center;
justify-content: center;
}
.gal-lightbox::backdrop {
background: rgba(11, 11, 13, .92);
}
.gal-lb-figure {
margin: 0;
max-width: calc(100vw - 140px);
max-height: calc(100dvh - 80px);
display: flex;
flex-direction: column;
align-items: center;
}
.gal-lb-figure img {
max-width: 100%;
max-height: calc(100dvh - 110px);
object-fit: contain;
border-radius: var(--fitme-radius);
box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
animation: gal-in .35s ease;
}
@keyframes gal-in {
from { opacity: 0; transform: scale(.97); }
to { opacity: 1; transform: none; }
}
.gal-lb-count {
margin-top: 10px;
font-size: .85rem;
color: var(--fitme-ash);
letter-spacing: .08em;
}
.gal-lb-close,
.gal-lb-nav {
position: absolute;
border: 0;
background: rgba(255, 255, 255, .08);
color: #fff;
cursor: pointer;
transition: background var(--fitme-transition), color var(--fitme-transition);
}
.gal-lb-close:hover,
.gal-lb-nav:hover {
background: var(--fitme-accent);
color: var(--fitme-dark);
}
.gal-lb-close {
top: 16px;
right: 16px;
width: 44px;
height: 44px;
border-radius: 50%;
font-size: 1.8rem;
line-height: 1;
}
.gal-lb-nav {
top: 50%;
transform: translateY(-50%);
width: 48px;
height: 48px;
border-radius: 50%;
font-size: 1.1rem;
}
.gal-lb-prev { left: 20px; }
.gal-lb-next { right: 20px; }
@media (max-width: 575px) {
.gal-lb-figure { max-width: calc(100vw - 24px); }
.gal-lb-nav { top: auto; bottom: 18px; transform: none; }
.gal-lb-prev { left: calc(50% - 60px); }
.gal-lb-next { right: calc(50% - 60px); }
}
@media (prefers-reduced-motion: reduce) {
.gal-link img, .gal-lb-figure img { transition: none; animation: none; }
}
/* ── "In the middle of the screen" = hovered ─────────────────────────────────────
main.js adds .is-centered to the trainer photo / card / icon that sits on the vertical
middle of the viewport (and, inside the Modalidades strip, on the horizontal
middle too; the gallery photos only react to a real hover), so scrolling past shows the same state as a hover. These mirror
the :hover rules above. ─────────────────────────────────────────────────── */
.trainer-item .trainer-pic.is-centered,
#powerRotation>div:nth-child(even) .trainer-pic.is-centered {
transform: rotate(0deg) translateY(-8px) scale(1.05);
border-color: transparent;
background:
linear-gradient(var(--fitme-dark), var(--fitme-dark)) padding-box,
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) border-box;
box-shadow: 0 0 18px 2px rgba(var(--fitme-accent-rgb), .4), var(--fitme-shadow-lg);
animation: pc-spin 3.2s linear infinite;
}
.trainer-item .trainer-pic.is-centered img { filter: saturate(1); }
.trainer-item .trainer-pic.is-centered::before { opacity: 0; }
.icon-box-item.is-centered { transform: translateY(-3px); }
.icon-box-item.is-centered .ib-icon {
background: color-mix(in srgb, var(--fitme-accent) 10%, #000);
color: #fff;
transform: scale(1.06);
box-shadow: 0 0 16px 1px rgba(var(--fitme-accent-rgb), .4);
}
.icon-box-item.is-centered .ib-icon::after { opacity: 1; animation: pc-spin 3.2s linear infinite; }
.icon-box-item.is-centered .ib-icon svg.mi { color: #fff; }
.icon-box-item.is-centered .ib-icon img { filter: brightness(0) invert(1); mix-blend-mode: normal; }
.icon-box-item.is-centered .ib-icon:has(img[src*="yourfit"]) { background: #fff; }
.icon-box-item.is-centered .ib-icon img[src*="yourfit"] { filter: none; }
.price-card.is-centered { --pc-lift: -4px; --pc-bw: 2px; box-shadow: var(--fitme-shadow-lg); }
.price-card.is-centered::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.is-centered::after { opacity: .75; animation: pc-spin 3.2s linear infinite; }
@media (prefers-reduced-motion: reduce) {
.trainer-item .trainer-pic.is-centered,
.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; }
}
/* ── Noise texture ─────────────────────────────────────────────────────────────
Buttons: a tiled grey fractal-noise image laid over the face colour (!important
so the hover rules, which reset `background`, don't drop it; the hover face in
::before carries the same layer). Headings: the #pt-noise SVG filter (defined
in site/includes/include.php) multiplies grain into the lettering only. */
:root {
--noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='155' height='155'%3E%3Cfilter id='n' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.98' numOctaves='1' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.87' intercept='-0.435'/%3E%3CfeFuncG type='linear' slope='1.87' intercept='-0.435'/%3E%3CfeFuncB type='linear' slope='1.87' intercept='-0.435'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.160'/%3E%3C/svg%3E");
}
.site-btn,
.gym-switch-btn,
.crossfit-nav-link,
.hero-event-go,
.cta-btn,
.btn-primary {
background-image: var(--noise) !important;
background-size: 155px 155px !important;
background-blend-mode: overlay !important;
}
/* Logos get the same grain as the headings (the logo gym buttons add their
drop-shadow after it, see .gym-switch-btn--logo). */
h1, h2,
.navbar-brand img,
.gym-switch-logo { filter: url(#pt-noise); }