Commit Graph
100 Commits
Author SHA1 Message Date
andre 22edadf0d7 chore: stop tracking assistant notes 2026-10-26 16:55:12 +00:00
andre 2279970768 feat(footer): add Powered by andmore.pt credit 2026-10-26 16:52:20 +00:00
andre e804c52b4e feat(site): Comunidade section with Instagram posts the gym was tagged in
Per-gym Graph API /tags fetch with file cache and local thumbnails, section after the gallery, navbar link and admin page (Gestão > Site).
2026-10-26 14:19:43 +00:00
andre 6ac5213624 feat(galerias): upload several images at once, clear errors and JPEG XL placeholders 2026-10-26 13:48:02 +00:00
andre 6abc486630 feat(site): YourFit brand glyphs as modalidade icons, light plate for the other-gym logo button 2026-10-26 12:55:36 +00:00
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
andre 785d1f6ceb style(hero): event card border in its button colour, no glow on hero text, lighter subtitle 2026-10-26 12:06:15 +00:00
andre 0bc14f5f72 style(navbar): match head slash in the colour of the gym it links to 2026-10-26 12:03:30 +00:00
andre e7ab661f4c feat(navbar): match head shows the other gym's brand, centred logo on CrossFit, mobile band
The match head is painted in the other gym's colours with a strip in this site's accent; below 992px it is a slashed band at the bottom of the open menu (menu height from the real header height). The CrossFit page gets the centred logo crossfade, the hero logo has a fixed 52px height, and the hero h1 shadow is softer with the frosted blur at .8.
2026-10-26 12:00:56 +00:00
andre 4b54a777b7 style(navbar): logo crossfade, match-head end, full-screen mobile menu, brand slash template 2026-10-26 11:53:44 +00:00
andre 2e8b6d20f6 style(navbar): smaller centred logo, hero clears the bar, liquid-glass backdrop 2026-10-26 11:34:11 +00:00
andre c2b1f98e96 docs: libjxl-tools in the production Dockerfile, pending rebuild 2026-10-26 11:30:35 +00:00
andre 04df7f8997 style(site): truly centred navbar, smoother logo docking, grain on logos and buttons, slashed title underlines 2026-10-26 11:27:28 +00:00
andre f72292fc02 docs: centred home logo, nav underline and hero event card 2026-10-26 11:24:15 +00:00
andre bfbd04a2d3 feat(site): centred home logo that docks on scroll, slashed nav underline, square defocused hero event 2026-10-26 11:23:28 +00:00
andre 4f44bc1609 feat(images): JPEG XL optimizer with webp/jpg fallback and <picture> serving
img_optimize() decodes .jxl with djxl or Imagick, resizes with GD, re-encodes
with cjxl and writes foto.jxl.webp beside it; skips cleanly without a decoder.
Gallery, hero, navbar logos and JSON-LD serve the JXL with the fallback, and
trash/removal move the fallback with its .jxl.
2026-10-26 11:18:13 +00:00
andre 8fe73eb5d6 style(navbar): dark outline instead of white halo on gym logo buttons 2026-10-26 10:15:22 +00:00
andre 49adbd0ae1 feat(site): navbar links only sections with content, Galeria link, brand-tinted gallery background 2026-10-26 10:14:04 +00:00
andre 1eb2a61031 fix(admin): empty DataTables listings no longer error; their message becomes emptyTable
docs: JPEG XL optimizer plan and image-input rule
2026-10-26 10:13:29 +00:00
andre cc677af92d style(contactos): opening hours stacked by day, one line per period, centred 2026-10-26 10:01:57 +00:00
andre 7fa2da73dc feat(galerias): accept JPEG XL photos and list every uploaded format 2026-10-26 10:00:18 +00:00
andre 14dbabcad5 style(site): logo gym buttons without face or glow, gallery off scroll hover, Mensalidades brand glow 2026-10-26 09:59:51 +00:00
andre bab6eb87bf feat(site): slow brand-colour sweep along the bottom of the navbar 2026-10-26 09:54:32 +00:00
andre 3ffcf0fe38 fix(gyms): migration adding gyms.logo where the edited brand-colour migration had already run 2026-10-26 09:48:53 +00:00
andre 9c28be314b feat(gyms): current logo thumbnail next to the upload input; updated help text 2026-10-26 09:46:13 +00:00
andre d445ba64b9 feat(gyms): show gym logos in navbar buttons and brand; accept JPEG XL uploads 2026-10-26 09:35:46 +00:00
andreandClaude Sonnet 5.5 a85bec6851 fix(gyms): saving no longer fails before the brand-colour migration; upload header image and logo instead of typing paths
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:12:25 +01:00
andreandClaude Sonnet 5.5 965a123834 style(site): softer, denser h1 shadow (more blur and opacity)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:07:55 +01:00
andreandClaude Sonnet 5.5 68ac78097a style(site): finer grain on the hero frost
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:07:21 +01:00
andreandClaude Sonnet 5.5 3d30f09bb3 style(site): green frost tint on the hero band, discreet text shadow on the h1
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:07:01 +01:00
andreandClaude Sonnet 5.5 938347779c style(site): hero blur as a horizontal frosted band (blur 100->0 outward, grain veil)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:06:17 +01:00
andreandClaude Sonnet 5.5 b2b736734e style(site): gradient blur behind the hero text, fading outward
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:05:02 +01:00
andreandClaude Sonnet 5.5 a2219ebd63 style(site): apply tuned grain from the lab (freq 1.98, 1 octave, overlay on buttons, 155px tile)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:01:18 +01:00
andreandClaude Sonnet 5.5 9e3eee227b chore(dev): lab - label the grain sliders as opacity
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:59:49 +01:00
andreandClaude Sonnet 5.5 72cf3dad98 feat(dev): lab - full grain controls (type, frequency, octaves, seed, contrast, softness, tile, blend, mono) + generated CSS
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:57:21 +01:00
andreandClaude Sonnet 5.5 e5f4fd8fc9 feat(dev): style lab page with sliders for the visual effects (dev only)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:55:26 +01:00
andre 18676ad6d0 feat(icons): load Bootstrap Icons and Font Awesome from the shared platform-tools packs
Register the icons packs in platform_connect, add fit_icon_assets() with local
fallback, and add a sysadmin 'Pacotes de icones' link to platform?tool=icons.
2026-10-13 18:55:12 +01:00
andreandClaude Sonnet 5.5 781a3a324e style(site): subtler noise (buttons slightly, headings 50%)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:52:15 +01:00
andreandClaude Sonnet 5.5 18556ca8b9 style(site): noise texture on buttons and h1/h2 lettering
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:51:17 +01:00
andreandClaude Sonnet 5.5 3d2a696162 fix(site): restore CSS lost in 6c14e64; gallery click-and-drag; no link underline + colour/glow hover; brand-colour CrossFit pill; lighter trial link; no gloss on team photos
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:49:53 +01:00
andreandClaude Sonnet 5.5 6c14e644b1 feat(site): auto-scrolling gallery strip (full-height + 2x2), centre-of-screen hover state, trial link as text under the hero button
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:44:31 +01:00
andreandClaude Sonnet 5.5 99c28f04b4 style(site): gallery tint is a brand gradient fading to transparent
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:41:03 +01:00
andreandClaude Sonnet 5.5 4b6329f529 style(site): YOURFIT icons keep their aspect ratio (wide box), black until hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:40:27 +01:00
andreandClaude Sonnet 5.5 356554db42 style(site): spinning brand edge + glow on open detail cards (team, Modalidades)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:39:24 +01:00
andreandClaude Sonnet 5.5 b884749a4e style(site): photos 10% desaturated with a discreet brand tint until hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:38:47 +01:00
andreandClaude Sonnet 5.5 f9ec3644c8 style(site): spinning-edge hover on Modalidades icon boxes and gallery tiles
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:37:59 +01:00
andreandClaude Sonnet 5.5 da90c5c681 style(site): square team photo frames (no border radius)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:35:43 +01:00
andreandClaude Sonnet 5.5 9017c849f6 style(site): team photo frames use the spinning-edge hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:35:16 +01:00
andreandClaude Sonnet 5.5 83398eb7f5 style(site): slower button lift transition
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:34:21 +01:00
andreandClaude Sonnet 5.5 9588f902c6 style(site): button hover like the Mensalidades cards (spinning brand edge, dark face, white text)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:33:27 +01:00
andreandClaude Sonnet 5.5 8e889adeb9 revert(site): drop the 3D neon button/photo-frame hover effect
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:31:34 +01:00
andreandClaude Sonnet 5.5 f28b2b8482 style(site): lighting model for the 3D neon buttons (AO, graded walls, bloom, shaded face)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:29:34 +01:00
andreandClaude Sonnet 5.5 4b99991c11 style(site): neon extrusion on the team photo frames
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:26:43 +01:00
andreandClaude Sonnet 5.5 db28427c1e style(site): single neon blink after a moment of hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:24:57 +01:00
andreandClaude Sonnet 5.5 d40f6d8b2d style(site): neon flicker on button hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:24:22 +01:00
andreandClaude Sonnet 5.5 348e7d6848 style(site): flatter wall gradient, softer box-shadow glow on buttons
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:24:01 +01:00
andreandClaude Sonnet 5.5 e52709b926 style(site): stronger neon on button hover (inner glow, halo, neon lettering)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:21:44 +01:00
andreandClaude Sonnet 5.5 7bf2a8542e style(site): angled 3D button (bottom + right walls), slower colour fade on hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:20:01 +01:00
andreandClaude Sonnet 5.5 acac3a191a style(site): pushable 3D neon buttons (lifting face + ::before wall, spring curves)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:18:17 +01:00
andreandClaude Sonnet 5.5 251644c393 style(site): button hover wall 4px with graded sides and lit bevel
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:13:20 +01:00
andreandClaude Sonnet 5.5 2a4596e7e3 style(site): neon lives in the extruded sides, plain face (no double outline)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:12:35 +01:00
andreandClaude Sonnet 5.5 9a42c91471 style(site): button hover as one continuous extruded wall, no ghost copy
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:11:47 +01:00
andreandClaude Sonnet 5.5 2a66f74275 style(site): neon outline on button hover face
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:11:06 +01:00
andreandClaude Sonnet 5.5 a94287e3d6 style(site): near-black button hover keeping 10% brand colour; no underline on buttons
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:10:09 +01:00
andreandClaude Sonnet 5.5 b103aeae58 style(site): white text on a deeper brand colour on button hover
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:06:43 +01:00
andreandClaude Sonnet 5.5 8ede31ce3a style(site): subtler 3D neon button hover (3px depth)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:06:18 +01:00
andreandClaude Sonnet 5.5 58d5199883 feat(gyms): gym logo field; other-gym navbar button uses that gym's brand colour and logo
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:45:17 +01:00
andreandClaude Sonnet 5.5 32f8d7a613 feat(branding): re-theme Bootstrap to the brand colour; 3D neon button hover; hide Mensalidades link without plans
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:16:50 +01:00
andreandClaude Sonnet 5.5 4b2823d1e5 feat(gyms): per-gym brand colour; CrossFit pill follows it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:08:30 +01:00
andreandClaude Sonnet 5.5 716eec9f6d feat(site): root opens the main gym; other gyms as navbar buttons
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:06:59 +01:00
andreandClaude Sonnet 5.5 aa55d44406 feat(sidebar): fleet sidebar standard (header row, user in sidebar, collapsible groups, mini mode, no-flash transitions)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 16:56:46 +01:00
andreandClaude Sonnet 5.5 b73c23bf55 feat(dev): environment ribbon and one-click dev login on the public site and auth pages
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 16:56:40 +01:00
andreandClaude Sonnet 5.5 5f64ae57db feat(dev): adopt shared platform-tools dev toolbar and one-click dev login
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 22:10:58 +01:00
andreandClaude Sonnet 5.5 8edc37e43a chore(dev): dev_accounts script (fail-closed, dev only)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 21:58:06 +01:00
andreandClaude Sonnet 5.5 63adaf19ce chore: bump shared/platform-tools to 1c51c84 (brand feed)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 21:08:59 +01:00
andreandClaude Sonnet 5.5 4446224c19 feat(settings): save uploaded logos to uploads/public/logo
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 19:41:01 +01:00
andreandClaude Sonnet 5.5 79a0047f29 feat(brand): adopt platform-tools Brand feed; logo path convention in emails
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 15:37:31 +01:00
andreandClaude Sonnet 5.5 f2a9c5181b feat: mapa carrega logo no site; sysadmin edita utilizadores (incl. promover a admin)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 12:39:36 +01:00
andreandClaude Sonnet 5 4bf177289a feat(site): horário — esconde botão ao abrir, setas no desktop, swipe no telemóvel
- "Ver Horário das aulas" desaparece assim que o acordeão abre (clique no
  próprio botão ou o link "Horário" da navbar a abrir por JS) — deixa de
  ficar um botão grande por cima da grelha já visível.
- Setas ‹ › junto ao dia em foco também no desktop (vista de 3 dias): só o
  dia central as mostra, os laterais continuam sem elas (já são clicáveis
  diretamente).
- Deslizar no telemóvel/tablet muda de dia, com o mesmo efeito das setas —
  só reage a arrastos maioritariamente horizontais, para não roubar o
  scroll vertical da página.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 11:18:51 +01:00
andreandClaude Sonnet 5 b1e88781b8 feat(backoffice): DataTables cliente-only nas 11 listagens com CSV
Fecha o item 6.9 da auditoria (sem server-side/AJAX — todas as tabelas
estão bem abaixo de 60 linhas): ordenação, pesquisa, paginação, pt-PT
e Responsive (colapso em ecrãs estreitos), reaproveitando o botão
"Exportar CSV" já existente.

DataTables 2.3.4 + Responsive 3.0.6 vendorizados em
assets/vendor/datatables-2.3.4/ (mesma versão/decisão do hub.andmore.pt),
nunca de CDN. Tradução pt-PT oficial inline em assets/js/datatables-init.js,
que expõe initDataTable(selector, opts) — cada página dá um id estável à
tabela e marca a coluna de Ações como orderable:false/searchable:false.
Os vendor scripts só carregam nas 10 páginas que os usam (injeção dinâmica
depois do DOMContentLoaded, como o loader do Summernote), não no
header/footer partilhado.

views/admin/trials/index.php ficou de fora de propósito: cada linha tem
um <select> de estado e um <textarea> de notas editados in-line antes de
"Guardar" — um redraw da DataTable a meio dessa edição (ordenar, paginar)
arrisca perder ou baralhar o que ainda não foi submetido.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:34:09 +01:00
andreandClaude Sonnet 5 4222b8f2e0 feat(backoffice,site): Sistema consistente com a frota; horário como acordeão
- Sidebar do backoffice: Backups/Auditoria/IP bans/Geo/Origem das visitas/
  Atualizações deixam de ser um link cada (enumerados à mão) e passam a um
  só link "Sistema" para o índice partilhado do platform-tools
  (platform.php?tool=index), como a fotografia/design/dance já fazem — uma
  ferramenta nova no platform-tools passa a aparecer sozinha, sem link novo
  a escrever aqui. Definições, Mensagens e Comunicações continuam com link
  próprio (são páginas do fitme, não do router).
- Horário de Aulas (home e CrossFit, mesmo componente partilhado): a grelha
  fica fechada por omissão atrás de um botão "Ver Horário das aulas"
  (Bootstrap collapse); clicar em "Horário" na navbar (ou abrir a página já
  com #horario no URL) abre-a de imediato em vez de só rolar até uma secção
  fechada.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:14:46 +01:00
andreandClaude Sonnet 5 b5bbbd3b5f feat(site): mapa dos contactos a toda a largura
O mapa deixa de ser um cartão comprimido dentro da coluna de Informações
(220px) e passa a ocupar a largura toda numa linha própria, por baixo da
grelha Informações + Formulário (480px, mesma altura do .map de outras
páginas). A coluna de Informações fica só com o texto (Localização,
Telefone, E-mail, Horário de Funcionamento).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 09:04:53 +01:00
andreandClaude Sonnet 5 7e2798d0b7 feat(site): informações e contactos sem ícones, horário em texto; entra na frota
- Informações e contactos: os ícones fas ao lado do texto saem (desalinhavam
  em layout centrado — fa-envelope é mais largo que os outros e o texto ficava
  a começar em posições diferentes). Horário de Funcionamento deixa de ser
  cartões (dt/dd com barra escura) e passa a texto simples centrado, uma
  linha por dia, a condizer com o resto da coluna.
- Textarea "Mensagem" deixa de esticar até à base do mapa (chegava a 763px
  de altura, vazio) — volta ao min-height:150px + resize:vertical do CSS.
- CrossFit: removida a secção "A nossa Localização" duplicada, agora que a
  página tem a sua própria secção de Contactos com mapa incluído.
- Reviews: "Ver todas no Google" passa a link de texto simples (sublinhado);
  "Deixa a tua review" mantém-se o botão em destaque.
- api/health.php, api/hub_ops.php, api/hub_pair.php: stubs de uma linha para
  o platform-tools (mesmo padrão da fotografia/design/dance) — preparam a
  entrada do fitme3070 na Frota do hub.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 08:46:49 +01:00
andreandClaude Sonnet 5 65182eecd6 feat(site): horário sem barra de dias em cima, CrossFit ganha contactos
- Horário de aulas (home e CrossFit, mesmo componente partilhado): removida
  a barra de botões Seg/Ter/Qua/Qui/Sex/Sab acima da grelha — o próprio
  cabeçalho do dia (já existente) passa a ser sempre visível (antes só em
  desktop, 3 dias) e ganha setas ‹ › ao lado do nome do dia para mudar de
  dia em ecrãs de telemóvel/tablet. No desktop (3 dias lado a lado) as
  setas ficam escondidas — clicar no dia lateral já muda o dia em foco.
  CSS/JS morto do botão-filtro removido.
- Informações e contactos extraído para site/includes/contactos.php,
  partilhado pela home e pelo CrossFit — a página CrossFit ganha a mesma
  secção de contactos (localização, telefone, e-mail, horário de
  funcionamento, mapa, formulário) em vez de só linkar de volta à home.
  Hero e restantes secções do CrossFit não foram tocados.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 08:19:12 +01:00
andreandClaude Sonnet 5 5478952171 feat(site): secção Reviews em branco, horário de funcionamento nos contactos
- .reviews-section deixa de repetir o fundo metálico escuro da secção de
  mensalidades logo a seguir — passa a branca, restaurando a alternância de
  fundos ao longo da página. Textos e o botão "Ver todas no Google"
  recuperam as cores por omissão (escuras sobre branco); os cartões de
  review mantêm o próprio fundo escuro.
- Horário de Funcionamento deixa de ser secção própria e passa a viver
  dentro de "Informações" (Contactos), como mais um bloco de info, antes do
  mapa.
- Ícones de Localização/Telefone/E-mail alinhados: fa-envelope é mais largo
  que fa-map-marker-alt/fa-phone-volume, o que desalinhava o texto ao lado
  (4.8px de deslocamento, medido no browser); os ícones ganham uma largura
  fixa comum.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 02:39:21 +01:00
andreandClaude Fable 5 3f2c505c17 feat(rgpd): pedido de acesso/apagamento de dados + processo escrito (item 9.5)
- migration_20260925_rgpd_requests.sql: tabela rgpd_requests (email, tipo,
  estado, consentimento).
- config/functions_rgpd.php: rgpd_find() (acesso, art.º 15) e rgpd_erase()
  (apagamento por anonimização, art.º 17) sobre membership_leads/trial_leads/
  event_leads, + CRUD dos pedidos.
- Política de Privacidade: formulário público (POST + CSRF + anti-spam) para
  pedir acesso ou apagamento, e o processo escrito (resposta em 30 dias).
- Backoffice: página "Pedidos RGPD" (nav + index) para exportar os dados de um
  email (CSV, audit) ou anonimizá-los (POST + CSRF, audit).

O email está desligado, por isso os pedidos ficam guardados (como as leads),
não dependem de SMTP. Texto legal com placeholders — rever com jurista antes
do go-live (como já constava na Política).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:48:18 +01:00
andreandClaude Fable 5 116817e2de feat(backoffice): exportação CSV nas listagens, com audit
Novo helper csv_export() (config/functions.php): CSV Excel-friendly (BOM UTF-8
+ ';') e cada exportação fica no audit_log (RGPD: exportar dados pessoais tem
de ser rastreável). Botão "Exportar CSV" em todas as listagens do backoffice:
equipa, eventos, galerias, ginásios, horário, mensalidades, modalidades,
horário de funcionamento e lixeira (pedidos de inscrição e aulas experimentais
já tinham). Fecha a metade "exportação com permissões e audit" do item 6.9
(a única parte que o relatório considera ganho real à escala atual).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:43:41 +01:00
andreandClaude Fable 5 33158381bb chore(fonts): FontAwesome de 18 MB para 264 KB (remover build/source)
O diretório vendorizado incluía ficheiros de build/fonte que nunca são
carregados em runtime: js/, less/, scss/, metadata/, sprites/, svgs/, os
formatos de fonte não-woff2 (eot/svg/ttf/woff) e 13 folhas CSS redundantes.
Ficam só o que o site carrega de facto: css/all.css + 3 webfonts woff2
(solid/brands/regular). Sem alterar a fonte em si — nenhum ícone muda.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:29:53 +01:00
andreandClaude Fable 5 6d7b6456a9 fix(responsivo): elimina overflow horizontal de 3px em mobile
As regras `.container>.row` e `.contact-form .row` usavam margem negativa de
-15px (herança do Bootstrap 4), mas o container do Bootstrap 5 tem padding de
12px — sobrava 3px de overflow horizontal a 375px (scrollWidth 378 vs 375).
Passaram a -0.75rem (o gutter real do BS5), anulando exatamente o padding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:25:23 +01:00
andreandClaude Fable 5 c5c4a818f2 fix(contraste+fontes): verde de texto legível em fundo claro e Roboto auto-hospedado
Contraste (auditoria 4.8, WCAG AA):
- Novo token --fitme-accent-ink #667000 (≈5.1:1 sobre #F7F8FA), aplicado aos 7
  usos de texto que estavam em --fitme-accent-dark (#A6B600 ≈2.1:1 em fundo claro).
  O --fitme-accent-dark mantém-se para fundos de botões em hover/active (onde tem
  texto escuro por cima — escurecê-lo quebraria esses estados).
- .section-eyebrow passa a usar o ink green nas secções claras (oferta, galeria,
  modalidades, horário, workhours); as secções escuras mantêm o verde vivo.

Fontes (CSS "Google Fonts ainda carregado do CDN"):
- Roboto (variável, latin, 43 KB woff2) em site/assets/fonts/roboto/.
- @font-face 100-900 em style.css; removidos os <link> para fonts.googleapis.com
  em include.php e gym_chooser.php. Ficam apenas os pedidos à API do Places
  (legítimos, server-side).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:22:06 +01:00
andreandClaude Fable 5 8a0c2272a4 chore(frontend): remove Bootstrap 4 morto e alinha breakpoints à grelha
- assets/vendor/bootstrap/ (cópia BS 4.3.1) já sem referências desde a
  migração para 5.3.3 (auditoria 5.1); removida do repositório.
- style.css: cabeçalho corrigido (Bootstrap 4.3.1 → 5.3.3).
- Breakpoints inventados alinhados à grelha (auditoria 4.1): 479px e os dois
  339px passaram a max-width: 575px (o tier xs do Bootstrap). Os cartões de
  detalhe (modalidade/equipa) passam a coluna em todos os telefones ≤575px.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 22:47:25 +01:00
andreandClaude Sonnet 5 231b8eb699 feat(security): CSP ganha script-src (auditoria: CSP ainda sem script-src)
'self' 'unsafe-inline' https://cdn.jsdelivr.net — levantamento antes
de mexer: só um host externo carrega <script> a sério (jsdelivr, o
html2canvas de views/admin/horario/instagram.php e o bootstrap-icons
da página de erro); tudo o resto (Bootstrap, jQuery, Summernote) já é
vendorizado desde a migração de 25/09. 'unsafe-inline' fica por sítio
ter vários <script> inline (tema claro/escuro, GA-like snippets) que
não valia a pena reescrever para nonce/hash nesta passagem — mas isto
já bloqueia o caso que mais importa: um <script src="outro-domínio">
injetado por uma falha de XSS deixa de carregar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 22:10:26 +01:00
andreandClaude Sonnet 5 7482dc98f2 docs: atualiza CLAUDE.md e ASSETS.md pós-migração Bootstrap/Composer
Ficaram desatualizados depois da sessão de fixes: CLAUDE.md ainda
dizia "Bootstrap 4+5 em simultâneo" (já não, ver 1e2068b) e listava
"sem srcset"/"sem create/edit unificado" sem as razões reais por trás
de cada um continuar em aberto. ASSETS.md ainda tinha a tabela de
antes da migração (duas versões de Bootstrap, jQuery duplicado,
"sem Composer") — reescrito para o estado real: Bootstrap 5.3.3
único, jQuery uma cópia, Composer ligado (composer.json/lock),
PHPMailer hand-vendored por decisão documentada (não por falta de
tentar).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 22:01:29 +01:00
andreandClaude Sonnet 5 4ddefa6dae fix(navbar): logo esticava a barra (altura 252px) — height:auto em falta
O logo tem style="width: 150px" sem height desde sempre; a auditoria
4.7 acrescentou width="756" height="252" (lidos do viewBox do SVG)
sem adicionar height:auto ao inline style. Sem height:auto, o browser
não escala a altura proporcionalmente ao width CSS — ficou fixa nos
252px do atributo, esticando a barra toda. Confirmado ao vivo:
getComputedStyle(img).height passou de "252px" para o valor
proporcional depois desta correção.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 22:00:45 +01:00
andreandClaude Sonnet 5 30e85b2438 fix(css): tipografia fluida com clamp() no site público (auditoria 4.5)
6 seletores tinham font-size a fazer step-function em vez de escalar:
.hero-text h1 (4 breakpoints), .section-title h2 (3), .page-top-section
h1, .icon-box-item h3/h4 e os dois .schedule_box>div (2 cada). Cada par/
trio de valores por media query passa a um único clamp() na regra base,
com a interpolação (vw) calculada para bater certo com o valor antigo
nas larguras 375/768/1400px+ testadas.

Ficam por mexer (não são apenas escala de tipo): .rounded_frame,
.hero-text .site-btn, .site-btn @479px e .schedule_frame (o font-size
muda junto com padding/width/min-width, é redimensionamento de layout,
não só tipografia); .footer-menu li a (idem, padding muda junto — alvos
de toque da auditoria 4.4); .contact-form/.newsletter-form input (o
valor sobe para 1rem no mobile, não desce — evita o zoom automático do
iOS ao focar); .md-card h3 (faz parte da troca de layout do cartão para
modal fixo, não é só escala); .schedule_box a (o valor de mobile já era
igual ao base, 11px, não havia degrau nenhum).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:51:13 +01:00
andreandClaude Sonnet 5 1e2068bea2 feat(css): site público passa de Bootstrap 4.3.1 (EOL) para 5.3.3
Auditoria: "Site público em Bootstrap 4.3.1 (EOL); backoffice em
5.3.3" — o backoffice já usa a 5.3.3 vendorizada (assets/vendor/bootstrap5/),
o site público passa a usar a mesma cópia em vez da 4.3.1.

Levantamento antes de mexer: a folha de estilo própria (style.css)
quase não usa classes utilitárias cruas do Bootstrap (grep confirma
zero ml-/mr-/pl-/pr-/float-left/float-right/custom-select/
custom-control/badge-/sr-only/font-weight-/text-left/text-right —
tudo classes próprias como .site-btn). O que precisava de mudar:

- CSS/JS: assets/vendor/bootstrap/ -> assets/vendor/bootstrap5/
  (bundle, inclui Popper).
- Os 7 atributos data-toggle/data-target/data-dismiss (BS4) ->
  data-bs-toggle/data-bs-target/data-bs-dismiss (BS5): toggle da nav
  mobile, os dois modais (aula experimental, inscrição), o botão de
  fechar do alerta. O seletor em main.js que lê data-target também
  mudou para não parar de encontrar os botões.
- .close -> .btn-close (BS5 renomeou o componente; markup sem o
  &times; interno, que o BS5 desenha via CSS).
- .form-row -> .row (BS4 tinha form-row com gutters menores; BS5 não
  tem, style.css não tinha overrides para form-row, confirmado).
- O apanhado maior: dois <script> inline chamavam
  jQuery('#trialModal').modal('show') ao estilo de plugin jQuery do
  BS4 (para reabrir o modal depois de um erro de submissão) — o BS5
  não regista plugins jQuery nenhuns, isto ficava morto em silêncio.
  Trocado por new bootstrap.Modal(...).show(), a API JS nativa do
  BS5. grep confirma zero outras chamadas .modal()/.collapse()/etc.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:47:15 +01:00
andreandClaude Sonnet 5 b837def5a0 refactor(horas): partilhar _form.php entre create e edit (audit 6.8)
Mesmo padrão de horario/: extrai dia/abertura/fecho para _form.php.
create.php formatava open/close sem substr() enquanto edit.php cortava
para "HH:MM" com substr(..., 0, 5) por vir de uma coluna TIME da BD;
unificado na versão de edit.php (sem efeito em create.php).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:45:14 +01:00
andreandClaude Sonnet 5 33b7f19d15 refactor(horario): partilhar _form.php entre create e edit (audit 6.8)
Extrai os campos comuns (modalidade, dia, início, fim, sala) para
_form.php. create.php formatava hora_inicio/hora_fim sem substr()
enquanto edit.php aplicava substr(..., 0, 5) para cortar os segundos
que vêm da coluna TIME da BD — unificado na versão de edit.php (mais
defensiva; sem efeito em create.php, cujos valores já vêm em "HH:MM").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:45:14 +01:00
andreandClaude Sonnet 5 b8c0422318 refactor(modalidades): partilhar _form.php entre create e edit (audit 6.8)
Extrai os campos comuns (nome, cor, ícone/upload, ordem, descrição, e a
biblioteca de ícones disponíveis) para _form.php, seguindo o padrão de
events/ e memberships/. A diferença genuína entre criar e editar — o
bloco de ícone mostra pré-visualização e checkbox "remover imagem
atual" só quando já existe um registo — fica como um if ($item ===
null) explícito dentro do parcial, tal como o hero_image em events/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:45:14 +01:00
andreandClaude Sonnet 5 22dc14c8c8 refactor(equipa): partilhar _form.php entre create e edit (audit 6.8)
create.php e edit.php tinham os mesmos campos de formulário duplicados
lado a lado. Extrai o markup comum (nome, nascimento, área, estado,
foto, título, aptidões, formações, descrição) para _form.php, seguindo
o padrão já usado em events/ e memberships/. Cada view fica só com a
lógica que lhe é própria (criar vs. carregar registo existente,
upload/validação de foto, título da página, redirect).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:45:14 +01:00