// KineSuite landing — section components. // Imports nothing — relies on globals: LANDING_COPY, LANDING_SCALES, // LANDING_CAT_LABEL, LandingMark, LandingBrandIcon, LandingWordmark, LandingPhone, // LandingCatalogScreen. // ───────────────────────────────────────────────────────────── // Eyebrow — small mono label that introduces each section // ───────────────────────────────────────────────────────────── function Eyebrow({ children, color }) { return (
{children}
); } // ───────────────────────────────────────────────────────────── // Store badges — official Apple / Google marketing assets (local) // ───────────────────────────────────────────────────────────── const STORE_BADGES = { apple: { src: 'assets/badges/app-store-badge.svg', label: { es: 'Consíguelo en el App Store', en: 'Download on the App Store' }, }, google: { en: { src: 'assets/badges/google-play-badge.png', label: 'Get it on Google Play', }, es: { src: 'assets/badges/google-play-badge-es.png', label: 'Disponible en Google Play', }, }, }; function storeBadgeMeta(kind, lang) { const locale = lang === 'es' ? 'es' : 'en'; if (kind === 'apple') { const b = STORE_BADGES.apple; return { src: b.src, label: b.label[locale] }; } return STORE_BADGES.google[locale]; } function StoreBadge({ kind, lang, comingSoon, soonLabel }) { const badge = storeBadgeMeta(kind, lang); const ariaLabel = comingSoon ? `${soonLabel} — ${badge.label}` : badge.label; const className = `badge-store badge-store--${kind}${comingSoon ? ' badge-store--soon' : ''}`; const img = ; if (comingSoon) { return ( {img} ); } return ( {img} ); } function StoreBadges({ lang, t, comingSoon = true, onDark = false }) { const soonLabel = t?.storeComingSoon ?? (lang === 'es' ? 'Próximamente en App Store y Google Play' : 'Coming soon on App Store and Google Play'); return (
{comingSoon && (

{soonLabel}

)}
); } // ───────────────────────────────────────────────────────────── // Nav // ───────────────────────────────────────────────────────────── function LandingNav({ t, lang, setLang, theme, setTheme }) { const compareLabel = lang === 'es' ? 'Comparativa' : 'Comparison'; return (
{t.navScales} {t.navHow} {lang === 'es' ? 'Comparativa' : 'Comparison'} {t.navClinics} {t.navFaq}
{t.navDownload}
); } // ───────────────────────────────────────────────────────────── // Hero — three variants // ───────────────────────────────────────────────────────────── function HeroSplit({ t, lang, animated }) { return (
{t.heroEyebrow}

{t.heroTitleA}
{t.heroTitleB}

{t.heroSub}

{t.heroCtaPrimary} → {t.heroCtaSecondary}
); } function HeroCentered({ t, lang, animated }) { return (
{t.heroEyebrow}

{t.heroTitleA}{' '} {t.heroTitleB}

{t.heroSub}

); } function HeroEditorial({ t, lang, animated }) { return (
{t.heroEyebrow}

{t.heroTitleA}
{t.heroTitleB}

{t.heroSub}

); } function HeroSection({ variant, t, lang, animated }) { if (variant === 'centered') return ; if (variant === 'editorial') return ; return ; } // ───────────────────────────────────────────────────────────── // Marquee strip // ───────────────────────────────────────────────────────────── function StripSection({ t }) { const items = [ t.stripScales, t.stripDoi, t.stripOffline, t.stripFree, t.stripPro, t.stripI18n, ]; // Duplicate items so the loop is seamless const doubled = [...items, ...items]; return (
{doubled.map((it, i) => ( {it} ))}
); } // ───────────────────────────────────────────────────────────── // Catalog grid // ───────────────────────────────────────────────────────────── function CatalogSection({ t, lang }) { return ( ); } function CatalogCard({ scale, t, lang }) { const catVar = `var(--cat-${scale.cat})`; const name = lang === 'es' ? scale.name_es : scale.name_en; const tags = lang === 'es' ? scale.tags_es : scale.tags_en; const cat = LANDING_CAT_LABEL[scale.cat][lang]; return (
{cat}
{scale.timed && ( {t.catalogTimed} )} {scale.isNew && ( {t.catalogNew} )}

{name}

{scale.items} {t.catalogItemsLabel}
{tags.map((tg, i) => ( {tg} ))}
); } // ───────────────────────────────────────────────────────────── // How it works // ───────────────────────────────────────────────────────────── function HowSection({ t }) { const steps = [ { num: '01', title: t.howStep1Title, desc: t.howStep1Desc }, { num: '02', title: t.howStep2Title, desc: t.howStep2Desc }, { num: '03', title: t.howStep3Title, desc: t.howStep3Desc }, ]; return (
{t.howEyebrow}

{t.howTitle}

{steps.map((s, i) => (
{s.num}

{s.title}

{s.desc}

))}
); } // ───────────────────────────────────────────────────────────── // Clinical categories // ───────────────────────────────────────────────────────────── function CategoryIcon({ catKey }) { const common = { width: 26, height: 26, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.75, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true, }; switch (catKey) { case 'neuro': return ( ); case 'geriatrics': return ( ); case 'msk': return ( ); case 'cardio': return ( ); case 'pain': return ( ); case 'rehab': return ( ); case 'pediatrics': return ( ); case 'sports_medicine': return ( ); case 'rheumatology': return ( ); case 'general': return ( ); default: return ( ); } } function CategoryCard({ cat, lang, compact }) { const label = LANDING_CAT_LABEL[cat.key][lang]; const className = compact ? 'cat-card cat-card--compact' : 'cat-card'; return (
{label}

{cat.title}

{cat.desc}

{cat.items.map((it) => ( {it} ))}
); } function CategoriesSection({ t, lang }) { const catsFeatured = [ { key: 'neuro', color: 'var(--cat-neuro)', title: t.catNeuroTitle, desc: t.catNeuroDesc, items: t.catNeuroList }, { key: 'geriatrics', color: 'var(--cat-geriatrics)', title: t.catGeriatricsTitle, desc: t.catGeriatricsDesc, items: t.catGeriatricsList }, { key: 'msk', color: 'var(--cat-msk)', title: t.catMskTitle, desc: t.catMskDesc, items: t.catMskList }, { key: 'cardio', color: 'var(--cat-cardio)', title: t.catCardioTitle, desc: t.catCardioDesc, items: t.catCardioList }, { key: 'pain', color: 'var(--cat-pain)', title: t.catPainTitle, desc: t.catPainDesc, items: t.catPainList }, { key: 'rehab', color: 'var(--cat-rehab)', title: t.catRehabTitle, desc: t.catRehabDesc, items: t.catRehabList }, ]; const catsMore = [ { key: 'pediatrics', color: 'var(--cat-pediatrics)', title: t.catPediatricsTitle, desc: t.catPediatricsDesc, items: t.catPediatricsList }, { key: 'sports_medicine', color: 'var(--cat-sports_medicine)', title: t.catSportsTitle, desc: t.catSportsDesc, items: t.catSportsList }, { key: 'rheumatology', color: 'var(--cat-rheumatology)', title: t.catRheumTitle, desc: t.catRheumDesc, items: t.catRheumList }, { key: 'general', color: 'var(--cat-general)', title: t.catGeneralTitle, desc: t.catGeneralDesc, items: t.catGeneralList }, ]; return (
{t.catsEyebrow}

{t.catsTitle}

{t.catsSub}

{catsFeatured.map((c) => ( ))}

{t.catsMoreTitle}

{catsMore.map((c) => ( ))}
); } // ───────────────────────────────────────────────────────────── // PDF section — copy + mocked PDF page // ───────────────────────────────────────────────────────────── function PdfMockSheet({ lang }) { // A simplified PDF report mockup, matches the spirit of pdf-reports.jsx. const isEs = lang === 'es'; return (
{/* Header */}
KineSuite
{isEs ? 'Reporte de evaluación · v1.0' : 'Assessment report · v1.0'}
{isEs ? 'Lic. Camila Reyes' : 'Lic. Camila Reyes'}
{isEs ? 'Matrícula 28.451 · Kinesióloga' : 'License 28.451 · Kinesiologist'}
{isEs ? 'Centro de Rehabilitación CRS' : 'CRS Rehabilitation Center'}
{/* Patient block */}
{isEs ? 'Paciente' : 'Patient'}
P. Morales · 72 a
{isEs ? 'Ficha 4729 · ACV isquémico (3 sem.)' : 'File 4729 · Ischemic stroke (3 wk)'}
{isEs ? 'Evaluación' : 'Assessment'}
{isEs ? 'Escala de Berg' : 'Berg Balance Scale'}
14 ítems · 12 abr 2026 · 11:23
{/* Score */}
{isEs ? 'Bandera clínica' : 'Clinical flag'}
{isEs ? 'Precaución · riesgo moderado' : 'Caution · moderate risk'}
34/56
{isEs ? 'puntaje total' : 'total score'}
{/* Items list */}
{isEs ? 'Ítems · resumen' : 'Items · summary'}
{[ { n: 1, l: isEs ? 'Sentado a de pie' : 'Sitting to standing', v: 3 }, { n: 2, l: isEs ? 'De pie sin apoyo' : 'Standing unsupported', v: 4 }, { n: 3, l: isEs ? 'Sentado sin apoyo' : 'Sitting unsupported', v: 4 }, { n: 4, l: isEs ? 'De pie a sentado' : 'Standing to sitting', v: 3 }, { n: 5, l: isEs ? 'Transferencias' : 'Transfers', v: 2 }, ].map((row) => (
{String(row.n).padStart(2,'0')} {row.l} {row.v}/4
))}
{isEs ? '+ 9 ítems más · ver detalle abajo' : '+ 9 more items · see detail below'}
{/* Footer */}
DOI: 10.1093/ptj/72.6.420 KineSuite v0.1 · 17/05/2026 · pág. 1 / 2
); } function PdfSection({ t, lang }) { return (
{t.pdfEyebrow}

{t.pdfTitle}

{t.pdfSub}

    {t.pdfFeatures.map((f, i) => (
  • {String(i + 1).padStart(2, '0')}
    {f.t}
    {f.d}
  • ))}
); } // ───────────────────────────────────────────────────────────── // Privacy section // ───────────────────────────────────────────────────────────── function PrivacySection({ t }) { return (
{t.privEyebrow}

{t.privTitle}

{t.privSub}

{t.privPoints.map((p, i) => (
·{String(i + 1).padStart(2,'0')}
{p.t}

{p.d}

))}
); } // ───────────────────────────────────────────────────────────── // Team // ───────────────────────────────────────────────────────────── function TeamSection({ t }) { return (
{t.teamEyebrow}

{t.teamTitle}

{t.teamSub}

{t.teamRoles.map((r, i) => (
{r.name.split(' ').slice(-2).map(w => w[0]).join('').slice(0,2)}
{r.name}
{r.role}
{r.meta}
))}
{t.teamPartnersTitle}
{t.teamPartners.map((p, i) => (
{p}
))}
); } // ───────────────────────────────────────────────────────────── // FAQ // ───────────────────────────────────────────────────────────── function FaqSection({ t }) { return (
{t.faqEyebrow}

{t.faqTitle}

{t.faqItems.map((it, i) => (
{it.q}

{it.a}

))} {t.pricingLocalizedNote && (

{t.pricingLocalizedNote}

)}
); } // ───────────────────────────────────────────────────────────── // Final CTA + Footer // ───────────────────────────────────────────────────────────── function FinalCtaSection({ t, lang }) { return (
{t.finalEyebrow}

{t.finalTitle}

{t.finalSub}

); } function FooterSection({ t, lang, setLang }) { const legalHrefs = lang === 'es' ? ['legal/terminos.html', 'legal/privacidad.html'] : ['legal/terms.html', 'legal/privacy.html']; const productHrefs = lang === 'es' ? ['#catalogo', '#how', 'legal/privacidad.html', '#changelog'] : ['#catalogo', '#how', 'legal/privacy.html', '#changelog']; const companyHrefs = ['#equipo', '#', '#', `mailto:${t.footerContact}`]; return ( ); } Object.assign(window, { Eyebrow, StoreBadges, StoreBadge, LandingNav, HeroSection, StripSection, CatalogSection, HowSection, CategoriesSection, PdfSection, PrivacySection, TeamSection, FaqSection, FinalCtaSection, FooterSection, });