Files
InsanityLab-web/.superpowers/sdd/review-2fdd1b9..45e5214.diff
Adriano b913a2bf90 registri dei piani in git (AI-OS#309)
Refs gitea:Adriano/AI-OS#310

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 10:36:26 +02:00

481 lines
23 KiB
Diff
Raw Permalink 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.
# Review package: 2fdd1b9..HEAD
## Commits
45e5214 feat: homepage completa da design Figma
## Files changed
src/components/Agenda.astro | 54 +++++++++++++++++++++++++++++++++
src/components/home/FeatureBlocks.astro | 35 +++++++++++++++++++++
src/components/home/HeroSlider.astro | 54 +++++++++++++++++++++++++++++++++
src/components/home/InfoColumns.astro | 26 ++++++++++++++++
src/components/home/MethodSteps.astro | 39 ++++++++++++++++++++++++
src/components/home/PartnersStrip.astro | 18 +++++++++++
src/components/home/ProgramsGrid.astro | 38 +++++++++++++++++++++++
src/components/home/QuoteBanner.astro | 22 ++++++++++++++
src/components/home/TeamSection.astro | 34 +++++++++++++++++++++
src/components/home/TrainingCards.astro | 42 +++++++++++++++++++++++++
src/pages/index.astro | 27 ++++++++++++++++-
11 files changed, 388 insertions(+), 1 deletion(-)
## Diff
diff --git a/src/components/Agenda.astro b/src/components/Agenda.astro
new file mode 100644
index 0000000..116b0c0
--- /dev/null
+++ b/src/components/Agenda.astro
@@ -0,0 +1,54 @@
+---
+import { agenda, disciplines, days, slots } from '../data/agenda';
+---
+<section class="section section--dark agenda">
+ <div class="container">
+ <div class="section-heading"><h2>Agenda</h2></div>
+ <div class="agenda__tabs" role="tablist">
+ {disciplines.map((d, i) => (
+ <button class:list={['agenda__tab', { 'is-active': i === 0 }]} data-filter={d} role="tab" aria-selected={i === 0 ? 'true' : 'false'}>{d}</button>
+ ))}
+ </div>
+ <div class="agenda__grid">
+ <div class="agenda__corner"></div>
+ {days.map((d) => <div class="agenda__day">{d}</div>)}
+ {slots.map((slot) => (
+ <>
+ <div class="agenda__slot">{slot}</div>
+ {days.map((_, dayIdx) => {
+ const entry = agenda.find((e) => e.day === dayIdx && e.slot === slot);
+ return entry
+ ? <div class="agenda__cell" data-discipline={entry.discipline}><strong>{entry.discipline}</strong><span>{entry.time}</span><em>{entry.trainer}</em></div>
+ : <div class="agenda__cell agenda__cell--empty"></div>;
+ })}
+ </>
+ ))}
+ </div>
+ </div>
+</section>
+
+<style>
+ .agenda__tabs { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin-bottom: 40px; }
+ .agenda__tab { background: transparent; color: #b9aea4; border: 0; cursor: pointer; font-family: var(--font-heading); font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; padding: 10px 18px; }
+ .agenda__tab.is-active { background: var(--c-accent); color: #fff; }
+ .agenda__grid { display: grid; grid-template-columns: 70px repeat(7, 1fr); gap: 2px; }
+ .agenda__day, .agenda__slot { font-family: var(--font-heading); font-size: .66rem; letter-spacing: .14em; text-transform: uppercase; color: #b9aea4; display: flex; align-items: center; justify-content: center; padding: 10px 4px; }
+ .agenda__cell { background: var(--c-accent); color: #fff; padding: 14px 8px; text-align: center; font-size: .72rem; display: flex; flex-direction: column; gap: 2px; }
+ .agenda__cell strong { font-family: var(--font-heading); font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; }
+ .agenda__cell em { font-style: normal; opacity: .85; }
+ .agenda__cell--empty { background: transparent; }
+ .agenda__cell.is-dim { opacity: .15; }
+ @media (max-width: 991px) { .agenda__grid { grid-template-columns: 60px repeat(7, minmax(90px, 1fr)); overflow-x: auto; } }
+</style>
+
+<script>
+ document.querySelectorAll<HTMLElement>('.agenda').forEach((root) => {
+ const tabs = root.querySelectorAll<HTMLButtonElement>('.agenda__tab');
+ const cells = root.querySelectorAll<HTMLElement>('.agenda__cell[data-discipline]');
+ tabs.forEach((tab) => tab.addEventListener('click', () => {
+ tabs.forEach((t) => { t.classList.toggle('is-active', t === tab); t.setAttribute('aria-selected', String(t === tab)); });
+ const f = tab.dataset.filter!;
+ cells.forEach((c) => c.classList.toggle('is-dim', f !== 'Events' && c.dataset.discipline !== f));
+ }));
+ });
+</script>
diff --git a/src/components/home/FeatureBlocks.astro b/src/components/home/FeatureBlocks.astro
new file mode 100644
index 0000000..914f7fd
--- /dev/null
+++ b/src/components/home/FeatureBlocks.astro
@@ -0,0 +1,35 @@
+---
+import { Image } from 'astro:assets';
+import featPerformance from '../../assets/img/feature-performance.jpg';
+import featBalance from '../../assets/img/feature-balance.jpg';
+import featLongevity from '../../assets/img/feature-longevity.jpg';
+const blocks = [
+ { title: 'PERFORMANCE', image: featPerformance, reverse: false,
+ text: 'Allenamenti progettati su misura per adattarsi ai tuoi obiettivi e al tuo livello. Programmi mirati che sviluppano forza, resistenza e funzionalità in modo equilibrato. Un metodo efficace per migliorare le performance e ottenere risultati concreti e duraturi.' },
+ { title: 'BALANCE', image: featBalance, reverse: true,
+ text: 'L’equilibrio tra corpo e mente è la base di ogni performance duratura. Attraverso movimento, recupero e gestione dello stress, costruiamo stabilità e controllo. Un approccio integrato che sostiene benessere, energia e continuità nel tempo.' },
+ { title: 'LONGEVITY', image: featLongevity, reverse: false,
+ text: 'Benessere completo tra movimento, nutrizione e stile di vita. Un percorso personalizzato che unisce prevenzione, recupero ed equilibrio. Investi nella tua salute e qualità della vita nel tempo.' },
+];
+---
+<section class="section">
+ <div class="container">
+ {blocks.map((b) => (
+ <div class:list={['feat', { 'feat--reverse': b.reverse }]}>
+ <Image src={b.image} alt={b.title} class="feat__img" widths={[500, 900]} sizes="(max-width: 767px) 100vw, 45vw" />
+ <div class="feat__text">
+ <h2>{b.title}</h2>
+ <p>{b.text}</p>
+ <a class="btn" href="/programs">Scopri</a>
+ </div>
+ </div>
+ ))}
+ </div>
+</section>
+
+<style>
+ .feat { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; padding-block: 40px; }
+ .feat--reverse .feat__img { order: 2; }
+ .feat__text h2 { text-transform: uppercase; letter-spacing: .1em; }
+ @media (max-width: 767px) { .feat { grid-template-columns: 1fr; gap: 24px; } .feat--reverse .feat__img { order: 0; } }
+</style>
diff --git a/src/components/home/HeroSlider.astro b/src/components/home/HeroSlider.astro
new file mode 100644
index 0000000..75f3e9d
--- /dev/null
+++ b/src/components/home/HeroSlider.astro
@@ -0,0 +1,54 @@
+---
+import { Image } from 'astro:assets';
+import hero1 from '../../assets/img/hero-1.jpg';
+const slides = [
+ { title: ['PERFORMANCE.', 'BALANCE.', 'LONGEVITY.'], image: hero1, alt: 'Atleti InsanityLab' },
+];
+---
+<section class="hero" aria-label="presentazione">
+ {slides.map((s, i) => (
+ <div class:list={['hero__slide', { 'is-active': i === 0 }]}>
+ <div class="container hero__in">
+ <div class="hero__text">
+ <h1>{s.title.map((line) => <span class="hero__line">{line}</span>)}</h1>
+ <a class="btn" href="/programs">Scopri</a>
+ </div>
+ <Image src={s.image} alt={s.alt} class="hero__img" widths={[600, 1000, 1400]} sizes="(max-width: 991px) 100vw, 60vw" loading="eager" />
+ </div>
+ </div>
+ ))}
+ {slides.length > 1 && (
+ <>
+ <button class="hero__arrow hero__arrow--prev" aria-label="precedente">‹</button>
+ <button class="hero__arrow hero__arrow--next" aria-label="successiva">›</button>
+ </>
+ )}
+</section>
+
+<style>
+ .hero { position: relative; background:
+ repeating-linear-gradient(to bottom, transparent 0 10px, rgba(0,0,0,.05) 10px 11px) left top / 40% 60% no-repeat, #fff; }
+ .hero__slide { display: none; }
+ .hero__slide.is-active { display: block; }
+ .hero__in { display: grid; grid-template-columns: 1fr 1.2fr; align-items: center; min-height: calc(100vh - var(--header-h)); gap: 30px; }
+ .hero__line { display: block; }
+ .hero__text h1 { font-weight: 500; }
+ .hero__img { object-fit: cover; height: 100%; max-height: calc(100vh - var(--header-h)); width: 100%; }
+ .hero__arrow { position: absolute; top: 50%; transform: translateY(-50%); background: none; border: 0; font-size: 3rem; color: var(--c-heading); cursor: pointer; }
+ .hero__arrow--prev { left: 12px; } .hero__arrow--next { right: 12px; }
+ @media (max-width: 991px) { .hero__in { grid-template-columns: 1fr; padding-block: 40px; min-height: 0; } }
+</style>
+
+<script>
+ const slides = document.querySelectorAll('.hero__slide');
+ if (slides.length > 1) {
+ let cur = 0;
+ const show = (i: number) => {
+ slides[cur].classList.remove('is-active');
+ cur = (i + slides.length) % slides.length;
+ slides[cur].classList.add('is-active');
+ };
+ document.querySelector('.hero__arrow--prev')?.addEventListener('click', () => show(cur - 1));
+ document.querySelector('.hero__arrow--next')?.addEventListener('click', () => show(cur + 1));
+ }
+</script>
diff --git a/src/components/home/InfoColumns.astro b/src/components/home/InfoColumns.astro
new file mode 100644
index 0000000..763bc2b
--- /dev/null
+++ b/src/components/home/InfoColumns.astro
@@ -0,0 +1,26 @@
+---
+import infoPerformance from '../../assets/img/info-performance.jpg';
+import infoBalance from '../../assets/img/info-balance.jpg';
+import infoLongevity from '../../assets/img/info-longevity.jpg';
+const cols = [
+ { title: 'PERFORMANCE.', image: infoPerformance },
+ { title: 'BALANCE.', image: infoBalance },
+ { title: 'LONGEVITY.', image: infoLongevity },
+];
+---
+<section class="info" aria-label="pilastri">
+ {cols.map((c) => (
+ <a class="info__col" href="/programs" style={`background-image:url(${c.image.src})`}>
+ <span class="info__title">{c.title}</span>
+ </a>
+ ))}
+</section>
+
+<style>
+ .info { display: grid; grid-template-columns: repeat(3, 1fr); }
+ .info__col { position: relative; min-height: 320px; background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; text-decoration: none; }
+ .info__col::before { content: ''; position: absolute; inset: 0; background: rgba(30,24,20,.35); transition: background .2s; }
+ .info__col:hover::before { background: rgba(30,24,20,.15); }
+ .info__title { position: relative; color: #fff; font-family: var(--font-heading); font-weight: 600; letter-spacing: .1em; font-size: 1.1rem; }
+ @media (max-width: 767px) { .info { grid-template-columns: 1fr; } }
+</style>
diff --git a/src/components/home/MethodSteps.astro b/src/components/home/MethodSteps.astro
new file mode 100644
index 0000000..dfbbd1a
--- /dev/null
+++ b/src/components/home/MethodSteps.astro
@@ -0,0 +1,39 @@
+---
+import { Image } from 'astro:assets';
+import type { ImageMetadata } from 'astro';
+import { methodIntro, methodExtraNote, methodSteps } from '../../data/method';
+const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/method-*.{jpg,png}', { eager: true });
+const imgOf = (name: string) => Object.entries(images).find(([p]) => p.includes(name))?.[1].default;
+---
+<section class="section section--alt">
+ <div class="container">
+ <div class="section-heading">
+ <h2>Il metodo<br />InsanityLab</h2>
+ <p set:html={methodIntro.replace('Metodo Insanitylab', '<strong>Metodo Insanitylab</strong>')} />
+ </div>
+ <p class="method__note">{methodExtraNote}</p>
+ <div class="method__row">
+ {methodSteps.map((s) => (
+ <div class:list={['method__step', { 'method__step--extra': s.extra }]}>
+ <div class="method__circle">
+ {imgOf(s.image) && <Image src={imgOf(s.image)!} alt="" widths={[220]} sizes="220px" />}
+ <span>{s.n}</span>
+ </div>
+ <h3>{s.title}</h3>
+ <p>{s.text}</p>
+ </div>
+ ))}
+ </div>
+ </div>
+</section>
+
+<style>
+ .method__note { text-align: right; font-size: .8rem; color: var(--c-text-light); max-width: 260px; margin-left: auto; }
+ .method__row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 30px; text-align: center; position: relative; }
+ .method__circle { position: relative; width: 150px; height: 150px; margin: 0 auto 20px; border: 1px dashed var(--c-accent-dark); border-radius: 50%; padding: 8px; }
+ .method__circle img { border-radius: 50%; width: 100%; height: 100%; object-fit: cover; }
+ .method__circle span { position: absolute; top: -6px; left: -6px; font-family: var(--font-heading); font-size: 2.4rem; color: var(--c-heading); background: var(--c-bg-alt); padding: 0 8px; }
+ .method__step h3 { font-size: .85rem; text-transform: uppercase; letter-spacing: .14em; }
+ .method__step p { font-size: .85rem; color: var(--c-text-light); }
+ @media (max-width: 767px) { .method__row { grid-template-columns: 1fr 1fr; } }
+</style>
diff --git a/src/components/home/PartnersStrip.astro b/src/components/home/PartnersStrip.astro
new file mode 100644
index 0000000..f5e8bf6
--- /dev/null
+++ b/src/components/home/PartnersStrip.astro
@@ -0,0 +1,18 @@
+---
+import { Image } from 'astro:assets';
+import type { ImageMetadata } from 'astro';
+import { partners } from '../../data/partners';
+const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/partner-*.{jpg,png}', { eager: true });
+const imgOf = (name: string) => Object.entries(images).find(([p]) => p.includes(name))?.[1].default;
+---
+<section class="pstrip" aria-label="partner">
+ <div class="container pstrip__in">
+ {partners.map((p) => imgOf(p.image) && <Image src={imgOf(p.image)!} alt={p.name} height={44} />)}
+ </div>
+</section>
+
+<style>
+ .pstrip { background: var(--c-accent); padding-block: 40px; }
+ .pstrip__in { display: flex; align-items: center; justify-content: space-around; gap: 30px; flex-wrap: wrap; }
+ .pstrip img { height: 44px; width: auto; opacity: .9; }
+</style>
diff --git a/src/components/home/ProgramsGrid.astro b/src/components/home/ProgramsGrid.astro
new file mode 100644
index 0000000..d4c1c98
--- /dev/null
+++ b/src/components/home/ProgramsGrid.astro
@@ -0,0 +1,38 @@
+---
+import { programs } from '../../data/programs';
+const icons: Record<string, string> = {
+ 'personal-training': 'M4 12h3m10 0h3M9 8v8m6-8v8M7 10v4m10-4v4',
+ 'performance-class': 'M13 3l-2 7h4l-6 11 2-8H7l4-10z',
+ 'coaching': 'M12 3a4 4 0 110 8 4 4 0 010-8zm-7 18a7 7 0 0114 0',
+ 'pilates-flow': 'M12 4a2 2 0 110 4 2 2 0 010-4zM6 20c2-6 10-6 12 0M12 8v6',
+ 'rehab': 'M12 21C7 17 3 13 3 9a5 5 0 019-3 5 5 0 019 3c0 4-4 8-9 12z',
+ 'nutrition': 'M12 3c4 0 7 3 7 8s-3 10-7 10-7-5-7-10 3-8 7-8zm0-1v4',
+};
+---
+<section class="section">
+ <div class="container">
+ <div class="section-heading">
+ <h2>Programmi</h2>
+ <p>Questi sono i programmi delle classi di Insanity Lab selezionati per voi. Abbiamo scelto i migliori percorsi per offrirvi un’esperienza di allenamento completa e mirata.</p>
+ </div>
+ <div class="pgrid">
+ {programs.map((p) => (
+ <a class="pgrid__item" href={`/programs/${p.slug}`}>
+ <svg viewBox="0 0 24 24" fill="none" stroke="var(--c-accent-dark)" stroke-width="1.4" width="52" height="52" aria-hidden="true"><path d={icons[p.slug]} /></svg>
+ <h3>{p.title}</h3>
+ <p>{p.subtitle}</p>
+ </a>
+ ))}
+ </div>
+ </div>
+</section>
+
+<style>
+ .pgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 50px 40px; text-align: center; }
+ .pgrid__item { text-decoration: none; }
+ .pgrid__item svg { margin-inline: auto; }
+ .pgrid__item h3 { text-transform: uppercase; letter-spacing: .12em; font-size: .95rem; margin: 18px 0 6px; }
+ .pgrid__item p { font-size: .85rem; color: var(--c-text-light); margin: 0; }
+ @media (max-width: 767px) { .pgrid { grid-template-columns: 1fr 1fr; } }
+ @media (max-width: 480px) { .pgrid { grid-template-columns: 1fr; } }
+</style>
diff --git a/src/components/home/QuoteBanner.astro b/src/components/home/QuoteBanner.astro
new file mode 100644
index 0000000..09a6e06
--- /dev/null
+++ b/src/components/home/QuoteBanner.astro
@@ -0,0 +1,22 @@
+---
+import quoteBg from '../../assets/img/quote-bg.jpg';
+---
+<section class="quote" style={`background-image:url(${quoteBg.src})`}>
+ <div class="container quote__in">
+ <p class="quote__mark">“</p>
+ <blockquote>
+ <p><strong>PERFORMANCE</strong> È SPINGERE OLTRE I PROPRI LIMITI, <strong>BALANCE</strong> È SAPERLI ASCOLTARE, <strong>LONGEVITY</strong> È COSTRUIRE NEL TEMPO CIÒ CHE DAVVERO CONTA.</p>
+ <cite>Insanitylab</cite>
+ </blockquote>
+ </div>
+</section>
+
+<style>
+ .quote { position: relative; background-size: cover; background-position: center; text-align: center; }
+ .quote::before { content: ''; position: absolute; inset: 0; background: rgba(46,32,24,.82); }
+ .quote__in { position: relative; padding-block: 110px; max-width: 820px; }
+ .quote__mark { color: #fff; font-size: 4rem; font-family: var(--font-heading); margin: 0; line-height: 1; }
+ .quote blockquote { margin: 0; }
+ .quote blockquote p { color: #fff; font-family: var(--font-heading); font-size: clamp(1.1rem, 2.4vw, 1.6rem); letter-spacing: .06em; line-height: 1.6; }
+ .quote cite { display: block; margin-top: 24px; color: var(--c-accent); font-style: normal; font-family: var(--font-heading); font-size: .75rem; letter-spacing: .3em; text-transform: uppercase; }
+</style>
diff --git a/src/components/home/TeamSection.astro b/src/components/home/TeamSection.astro
new file mode 100644
index 0000000..65cb0b7
--- /dev/null
+++ b/src/components/home/TeamSection.astro
@@ -0,0 +1,34 @@
+---
+import { Image } from 'astro:assets';
+import type { ImageMetadata } from 'astro';
+import { team, homeTeam } from '../../data/team';
+const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/team-*.{jpg,png}', { eager: true });
+const members = homeTeam.map((short) => team.find((m) => m.shortName === short)!).filter((m) => m.image);
+const imgOf = (name: string) => Object.entries(images).find(([p]) => p.includes(name))?.[1].default;
+---
+<section class="section">
+ <div class="container">
+ <div class="tteam__head">
+ <h2>Team<br />Trainer</h2>
+ <a class="btn" href="/about">Scopri team</a>
+ </div>
+ <div class="tteam__grid">
+ {members.map((m) => (
+ <figure class="tteam__card">
+ <Image src={imgOf(m.image!)!} alt={m.name} widths={[300, 500]} sizes="(max-width: 767px) 50vw, 25vw" />
+ <figcaption>{m.shortName}</figcaption>
+ </figure>
+ ))}
+ </div>
+ </div>
+</section>
+
+<style>
+ .tteam__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px; }
+ .tteam__head h2 { text-transform: uppercase; letter-spacing: .1em; margin: 0; }
+ .tteam__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
+ .tteam__card { position: relative; margin: 0; }
+ .tteam__card img { aspect-ratio: 3/4; object-fit: cover; width: 100%; }
+ .tteam__card figcaption { position: absolute; right: 10px; bottom: 14px; background: #fff; padding: 10px 6px; writing-mode: vertical-rl; font-family: var(--font-heading); font-size: .62rem; letter-spacing: .3em; text-transform: uppercase; color: var(--c-accent-dark); }
+ @media (max-width: 767px) { .tteam__grid { grid-template-columns: 1fr 1fr; } }
+</style>
diff --git a/src/components/home/TrainingCards.astro b/src/components/home/TrainingCards.astro
new file mode 100644
index 0000000..93b2fbe
--- /dev/null
+++ b/src/components/home/TrainingCards.astro
@@ -0,0 +1,42 @@
+---
+import { Image } from 'astro:assets';
+import type { ImageMetadata } from 'astro';
+import { trainings } from '../../data/trainings';
+const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/training-*.{jpg,png}', { eager: true });
+const imgOf = (name: string) => Object.entries(images).find(([p]) => p.includes(name))?.[1].default;
+const tones = ['taupe', 'tan', 'dark', 'charcoal'];
+// riga 1 (training 0-1): card, foto | riga 2 (training 2-3): foto, card
+const isSwapRow = (i: number) => Math.floor(i / 2) % 2 === 1;
+---
+<section class="tcards">
+ {trainings.map((t, i) => {
+ const img = imgOf(t.image);
+ const card = (
+ <div class:list={['tcards__cell', `tcards__cell--${tones[i]}`]}>
+ <h3>{t.title}</h3>
+ <p>{t.caption}</p>
+ <a class="tcards__link" href={t.cta.href}>Scopri →</a>
+ </div>
+ );
+ const photo = img ? <Image src={img} alt={t.title} class="tcards__img" widths={[400, 700]} sizes="(max-width: 767px) 50vw, 25vw" /> : null;
+ return isSwapRow(i) ? <>{photo}{card}</> : <>{card}{photo}</>;
+ })}
+</section>
+
+<style>
+ .tcards { display: grid; grid-template-columns: repeat(4, 1fr); }
+ .tcards__cell { padding: 48px 36px; display: flex; flex-direction: column; justify-content: center; aspect-ratio: 1; }
+ .tcards__cell--taupe { background: #6b5d5b; }
+ .tcards__cell--dark { background: var(--c-dark); }
+ .tcards__cell--charcoal { background: #27252a; }
+ .tcards__cell--taupe h3, .tcards__cell--taupe p,
+ .tcards__cell--dark h3, .tcards__cell--dark p,
+ .tcards__cell--charcoal h3, .tcards__cell--charcoal p { color: #efe9e3; }
+ .tcards__cell--tan { background: var(--c-accent); }
+ .tcards__cell--tan h3, .tcards__cell--tan p { color: #fff; }
+ .tcards__cell h3 { text-transform: uppercase; letter-spacing: .12em; }
+ .tcards__cell p { font-size: .88rem; }
+ .tcards__link { color: #fff; font-family: var(--font-heading); font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; text-decoration: none; margin-top: 18px; }
+ .tcards__img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 1; }
+ @media (max-width: 767px) { .tcards { grid-template-columns: repeat(2, 1fr); } }
+</style>
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 86dcea2..665a928 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,7 +1,32 @@
---
import Base from '../layouts/Base.astro';
+import HeroSlider from '../components/home/HeroSlider.astro';
+import InfoColumns from '../components/home/InfoColumns.astro';
+import FeatureBlocks from '../components/home/FeatureBlocks.astro';
+import QuoteBanner from '../components/home/QuoteBanner.astro';
+import TrainingCards from '../components/home/TrainingCards.astro';
+import ProgramsGrid from '../components/home/ProgramsGrid.astro';
+import Agenda from '../components/Agenda.astro';
+import TeamSection from '../components/home/TeamSection.astro';
+import MethodSteps from '../components/home/MethodSteps.astro';
+import PartnersStrip from '../components/home/PartnersStrip.astro';
export const prerender = true;
---
<Base title="Performance. Balance. Longevity.">
- <section class="section"><div class="container"><h1>Homepage in costruzione</h1></div></section>
+ <HeroSlider />
+ <InfoColumns />
+ <FeatureBlocks />
+ <QuoteBanner />
+ <section class="section" style="padding-bottom:0">
+ <div class="section-heading">
+ <h2>Training</h2>
+ <p>Porta i tuoi allenamenti al livello successivo: trova il percorso più adatto alle tue esigenze.</p>
+ </div>
+ </section>
+ <TrainingCards />
+ <ProgramsGrid />
+ <Agenda />
+ <TeamSection />
+ <MethodSteps />
+ <PartnersStrip />
</Base>