Files
Creeer-Web/docs/superpowers/specs/2026-07-21-creeer-landing-additions-design.md
T

10 KiB

creeer Landing — Additions: Header + Cómo empezar + Footer

Date: 2026-07-21 Branch: feat/header-comoempezar-footer Builds on: docs/superpowers/specs/2026-07-20-creeer-landing-design.md (original 7-section landing, already implemented).

Goal

Complete the page's structural chrome and its conversion on-ramp by adding three pieces to the existing one-page landing:

  1. A minimal sticky Header (wordmark + persistent CTA).
  2. A new "Cómo empezar" section (3 client-facing steps ending in a direct WhatsApp link).
  3. A slim Footer.

No new architecture: these reuse the existing primitives, tokens, motion pattern, and content-in-lib/content.ts convention. Still a statically-exported Next.js 14 site — no backend, no forms, contact via direct links only.

Global constraints (inherited — apply to every piece here)

  • Wordmark always lowercase creeer., rendered via the shared Wordmark primitive (never re-implemented, never uppercased).
  • Paleta (tokens): ink #0A1F44 · gold #B8901f (accents on LIGHT) · gold-bright #D4AF37 (accents on DARK) · base #FBFAF7 (light bg) · cream #F5EBD0 (text on dark) · muted/muted-dark.
  • Tipografía híbrida: Georgia italic = voz de marca (wordmark + citas + títulos de sección); Inter = body/UI.
  • Sin backend, sin formularios — contacto solo por enlaces directos (WhatsApp/mailto/LinkedIn).
  • Un único <h1> en toda la página — vive en el Hero. New pieces use <h2>/<h3> or no heading; Header/Footer carry no heading.
  • Todo el copy vive en lib/content.ts (nuevas claves comoEmpezar y footer).
  • Voz en segunda persona, sin jerga corporativa. Idioma español.
  • Todas las animaciones Framer Motion se desactivan con prefers-reduced-motion via usePrefersReducedMotion() + motionProps(reduced) (same pattern the 7 sections already use).
  • output: export — el build estático debe seguir produciendo out/.

File structure (additions)

components/
├── layout/
│   ├── Header.tsx            # NEW — sticky bar (server component, pure CSS sticky)
│   ├── Footer.tsx            # NEW — slim footer strip
│   └── __tests__/
│       ├── Header.test.tsx   # NEW
│       └── Footer.test.tsx   # NEW
└── sections/
    ├── ComoEmpezar.tsx       # NEW — section 07 (client component, motion pattern)
    └── __tests__/
        └── ComoEmpezar.test.tsx  # NEW
lib/content.ts                # ADD `comoEmpezar` and `footer` keys
app/page.tsx                  # compose Header + ComoEmpezar + Footer

Component 1 — Header (minimal sticky)

Interface: Header() at components/layout/Header.tsx. No props. Server component (no state, no JS — position: sticky is pure CSS).

Layout & style:

  • <header> with sticky top-0 z-50, light background (bg-base/80 or bg-pure/80) + backdrop-blur + a subtle bottom border (border-b border-ink/10). The light bar stays legible while scrolling over both light and dark sections.
  • A Container-width inner row, flex items-center justify-between, vertical padding ~py-3/py-4.
  • Left: <Wordmark size="base" /> wrapped in an <a href="#top"> (or the page top) — the wordmark ink color is the default (dark on the light bar).
  • Right: the CTA primitive, variant="light", with a short label from a new header.cta content key ("Hablemos", → appended by the primitive), href="#contacto". Rationale: the full-length "Define tu siguiente movimiento" would overflow next to the wordmark on ~375px screens; a compact nav CTA fits mobile and desktop, and the full CTA still appears in the Hero and Cierre. Layout is identical on mobile (no menu, no hamburger).
  • Semantic <header>; wrap the CTA link region in <nav aria-label="Principal">. No animation (nothing to gate on reduced motion).

A11y: the sticky header must not obscure anchor targets — ensure #contacto still scrolls into view (the closing section has ample padding; acceptable without extra scroll-margin, but scroll-mt on anchor targets may be added if visual testing shows clipping).

Component 2 — "Cómo empezar" section (07)

Interface: ComoEmpezar() at components/sections/ComoEmpezar.tsx. Client component using the established motion + usePrefersReducedMotion() + motionProps(reduced) + Container pattern (mirror Mecanismo.tsx/Disciplinas.tsx).

Placement: inserted between <Estratega /> (06) and <Cierre />. Cierre becomes section 08. This positions the on-ramp right before the contact close.

Purpose & differentiation: this is the client's on-ramp ("cómo empezar contigo"), distinct from Mecanismo which is her method ("cómo trabajo"). Framing is the engagement path that ends in the WhatsApp CTA.

Layout & style: light section (bg-base), py-24 md:py-32. Eyebrow + <h2> title (Georgia italic), then 3 numbered steps in a md:grid-cols-3 grid using the Mecanismo visual language (large Georgia-italic numbers 01/02/03 in gold, step name <h3>, short description in muted). A final CTA below the steps.

Steps (starting copy in content.ts, editable by the dueña):

  1. Escríbeme — cuéntame dónde está tu negocio hoy.
  2. Sesión de diagnóstico — una conversación para ubicar tu punto de inflexión.
  3. Estrategia ejecutable — sales con claridad y tu siguiente movimiento definido.

CTA (direct WhatsApp with prefilled message): an <a> (or the CTA primitive) whose href is the WhatsApp click-to-chat URL with a prefilled text, e.g. https://wa.me/<number>?text=Hola%2C%20quiero%20agendar%20una%20sesi%C3%B3n%20de%20diagn%C3%B3stico. The base number reuses cierre.contact.whatsapp (currently the 520000000000 placeholder — a TODO pending the dueña's real number). The full prefilled href and the un-encoded message live in content.ts under comoEmpezar so copy/number changes touch only content.

Light-section token discipline: accents in gold (never gold-bright), bg-base, text-ink/text-muted — matching the other light sections.

Interface: Footer() at components/layout/Footer.tsx. No props. Static (no motion).

Rationale: Cierre already renders the closing quote, primary CTA, and the three contact links. The footer therefore does not repeat the contact list — that would be redundant and produce a heavy "double dark block" right after the dark Cierre. Instead it is a thin closing strip.

Layout & style: <footer> with bg-dark, a subtle top divider (border-t border-cream/10), modest vertical padding (py-8/py-10), Container-width. Contents, centered or space-between:

  • <Wordmark size="base" onDark /> (small, gold-bright middle-e / period per the primitive).
  • A short tagline: "tu estratega de crecimiento" (text-muted-dark/cream, small).
  • Legal line: © 2026 creeer (year from a constant in content.ts, or computed — see decision below).

Decision — year: use a static © 2026 creeer string stored in content.ts footer.legal (static export → no need for a live new Date(); keeps the build deterministic and the copy in one place). The dueña/maintainer updates the year with the rest of the copy.

Out of scope: no privacy-policy page / aviso de privacidad, no social-icon set beyond what Cierre already links. These can be added later as their own change.

Content additions (lib/content.ts)

export const header = {
  cta: 'Hablemos',   // short nav CTA → #contacto (full CTA lives in Hero/Cierre)
};

export const comoEmpezar = {
  eyebrow: 'cómo empezar',
  title: 'Tu siguiente movimiento empieza con una conversación.',  // Georgia-italic h2
  steps: [
    { n: '01', name: 'Escríbeme', desc: 'cuéntame dónde está tu negocio hoy.' },
    { n: '02', name: 'Sesión de diagnóstico', desc: 'una conversación para ubicar tu punto de inflexión.' },
    { n: '03', name: 'Estrategia ejecutable', desc: 'sales con claridad y tu siguiente movimiento definido.' },
  ],
  cta: 'Agenda tu sesión de diagnóstico',
  // WhatsApp prefilled: base number reused from `cierre.contact.whatsapp`
  whatsappText: 'Hola, quiero agendar una sesión de diagnóstico',
};

export const footer = {
  tagline: 'tu estratega de crecimiento',
  legal: '© 2026 creeer',
};

The ComoEmpezar component builds the WhatsApp href from the cierre.contact.whatsapp number + encodeURIComponent(comoEmpezar.whatsappText) so number and message stay single-sourced. All copy above (title, steps, CTA, tagline) is a sensible default that the dueña can edit in content.ts.

Page composition (app/page.tsx)

<Header />
<main>
  <Hero variant="editorial" />
  <FraseAncla />
  <ParaQuien />
  <Mecanismo />
  <Disciplinas />
  <Estratega />
  <ComoEmpezar />   {/* NEW — 07 */}
  <Cierre />        {/* now 08 */}
</main>
<Footer />

The JSON-LD <script> already present in the page is preserved. Single-<h1> invariant holds (only Hero).

Testing (thin, matching the existing per-section pattern)

  • Header: renders the wordmark text and a CTA link with href="#contacto".
  • ComoEmpezar: renders the three step names and a WhatsApp link whose href starts with https://wa.me/ and includes the encoded prefilled text.
  • Footer: renders the wordmark and the legal/year line; does not introduce a second <h1>.

matchMedia is already stubbed in vitest.setup.ts, so ComoEmpezar's usePrefersReducedMotion() works in tests.

Constraints satisfied

  • No backend, no forms; contact via direct links (Header CTA → #contacto; ComoEmpezar → wa.me).
  • Existing palette/typography/tokens reused; light section uses gold, dark footer uses gold-bright/cream.
  • Single <h1> preserved (Hero only).
  • Reduced-motion honored uniformly (ComoEmpezar follows the motion pattern; Header/Footer are static).
  • Static export unaffected (all client interactivity is CSS/anchor links).

Out of scope (future changes, each its own branch)

  • Testimonials / social proof, results/case studies, FAQ.
  • Privacy-policy page, cookie/analytics integration.
  • Real OG image, branded favicon, real portrait photo, real contact details (dueña-pending).