feat: rediseño «El documento» en curso, contacto real y enlaces externos
Primitivas y contenido del rediseño (escala tipográfica, Revelar, MarcaSeccion, Seccion, Antetitulo, SimboloMarca, Resplandor, ClaridadHero, sección Proceso de ocho etapas, lib/content.ts reestructurado en seis secciones con alias para las viejas). Mecanismo y FormaTrabajar se retiran. Encima, lo de esta sesión: - recorrido: creeer vuelve a responder cada situación en vez de repetirla (el alias apuntaba respuesta a situacion); respuestas en plural. Créditos de las seis fotos de México. - contacto: WhatsApp, email (con mailto:) y LinkedIn reales; iconos de las redes en el cierre y el footer (IconoRed, trazos de Simple Icons, CC0). - enlaces: lo externo abre en otra pestaña con noopener y aviso para lectores de pantalla (lib/enlaces.ts); mailto y anclas se quedan. - Proceso: las ocho tarjetas no aparecían nunca en móvil (amount 0.3 sobre una lista de ~3000px); ahora cada una se revela sola. El ≡ de la 08 ya no tapa un entregable, título equilibrado, etiqueta a 12px, sin elevar al hover lo que no es clicable. - Disciplinas: la frase «No son la promesa — son los medios» gana peso y se agrupa con título e ilustración; sin cortes huérfanos en móvil. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3242a8bf71
commit
89e54a6e84
73 files changed
+5261
-592
No files matched your search
@@ -0,0 +1,101 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import * as content from '../content';
|
||||
import * as contenido from '../content';
|
||||
import {
|
||||
apertura, dondeEstas, queCambia, elTrabajo, paraQuienQuien, empezar,
|
||||
puntosInflexion, dolores, fraseAncla,
|
||||
} from '../content';
|
||||
|
||||
// The landing speaks in the first person plural (Erik's decision, 6/ago/2026,
|
||||
// recorded in docs/superpowers/specs/2026-08-06-proceso-ocho-etapas-design.md).
|
||||
// Before that it was singular, and the change touched copy in six different
|
||||
// objects — easy to reintroduce by accident when editing one of them.
|
||||
//
|
||||
// The reader stays "tú": that half is the dueña's locked decision and is not
|
||||
// what this file guards.
|
||||
|
||||
// Unambiguous first-person-singular markers: conjugated verbs and imperatives
|
||||
// with the enclitic "-me". Deliberately excludes anything that doubles as a
|
||||
// noun — "trabajo" is one ("el trabajo completo"), which is why the whole
|
||||
// word list is verbs and never bare stems.
|
||||
const SINGULAR = /\b(me sumerjo|sumerjo|cuestiono|separo|reviso|ubico|acompaño|escríbeme|cuéntame|conmigo)\b/i;
|
||||
|
||||
describe('voz de la marca en lib/content.ts', () => {
|
||||
it('speaks in the plural everywhere creeer is the one speaking', () => {
|
||||
// `dolores` is the one exception and it is not an oversight: those four
|
||||
// quotes are in the first person singular because the CLIENT is talking,
|
||||
// not creeer ("Trabajo más y gano casi lo mismo que hace dos años").
|
||||
// They are verbatim from slide 3 of the dueña's deck and must not move.
|
||||
const { dolores, ...resto } = content;
|
||||
|
||||
for (const [nombre, valor] of Object.entries(resto)) {
|
||||
expect(JSON.stringify(valor), `«${nombre}» quedó en singular`).not.toMatch(SINGULAR);
|
||||
}
|
||||
|
||||
// The eyebrow is where the old singular voice survived the plural
|
||||
// migration — locked now that the dueña confirmed it (19/ago/2026).
|
||||
expect(apertura.eyebrow).not.toMatch(/\btu estratega\b/i);
|
||||
|
||||
// Guard the guard: if the quotes are ever rewritten, this fails and forces
|
||||
// a decision instead of silently weakening the check above.
|
||||
expect(JSON.stringify(dolores)).toMatch(/Trabajo más y gano casi lo mismo/);
|
||||
});
|
||||
|
||||
it('keeps the reader in the second person', () => {
|
||||
expect(JSON.stringify(content.paraQuien)).toMatch(/\btienes\b/i);
|
||||
expect(JSON.stringify(content.proceso)).toMatch(/\btu\b/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe('la estructura de seis secciones', () => {
|
||||
it('numera el documento del 01 al 06 sin saltos', () => {
|
||||
expect(
|
||||
[apertura, dondeEstas, queCambia, elTrabajo, paraQuienQuien, empezar].map((s) => s.numero),
|
||||
).toEqual(['01', '02', '03', '04', '05', '06']);
|
||||
});
|
||||
|
||||
it('conserva verbatim las palabras de la dueña', () => {
|
||||
// Her doc is explicit: "they are already written in her voice — use them,
|
||||
// don't rewrite them." These tests fail if someone rewrites them.
|
||||
expect(dondeEstas.dolores).toContain('Trabajo más y gano casi lo mismo que hace dos años.');
|
||||
expect(dondeEstas.remate.accent).toBe('Se resuelve con una estrategia clara.');
|
||||
expect(queCambia.ancla.accent).toBe('dejan de crecer por falta de claridad.');
|
||||
expect(dondeEstas.puntos.map((p) => p.name)).toEqual([
|
||||
'Crecer', 'Consolidarse', 'Recuperar rentabilidad',
|
||||
'Simplificar', 'Expandirse', 'Replantear el portafolio',
|
||||
]);
|
||||
});
|
||||
|
||||
it('los alias viejos siguen leyendo de la misma fuente, no de una copia', () => {
|
||||
// While the two structures coexist, a silent divergence between them
|
||||
// would mean different copy on the same page.
|
||||
expect(puntosInflexion.items[0].situacion).toBe(dondeEstas.puntos[0].situacion);
|
||||
expect(dolores.quotes).toEqual(dondeEstas.dolores);
|
||||
expect(fraseAncla.quote).toBe(queCambia.ancla);
|
||||
});
|
||||
|
||||
it('mantiene en pie todo lo que las secciones viejas importan', () => {
|
||||
// The ten old sections stay mounted until Task 13, and a single missing
|
||||
// name here breaks the whole build. This is the real list of names the
|
||||
// code imports today from `@/lib/content`.
|
||||
const modulo = contenido as Record<string, unknown>;
|
||||
[
|
||||
'brandPillars', 'cierre', 'comoEmpezar', 'creditosFotos', 'disciplinas',
|
||||
'dolores', 'estratega', 'footer', 'fraseAncla', 'header', 'hero',
|
||||
'paraQuien', 'proceso', 'puntosInflexion',
|
||||
].forEach((nombre) => expect(modulo[nombre], nombre).toBeDefined());
|
||||
});
|
||||
|
||||
it('no promete escasez en la apertura', () => {
|
||||
expect(JSON.stringify(apertura)).not.toMatch(/cupos|cohorte|generación fundadora/i);
|
||||
});
|
||||
|
||||
it('arma los tres contactos como enlaces que abren algo', () => {
|
||||
// An email without `mailto:` is a relative URL: the browser navigates to
|
||||
// /nombre@dominio and lands on a 404 instead of opening the mail client.
|
||||
const { whatsapp, email, linkedin } = empezar.contacto;
|
||||
expect(whatsapp.href).toMatch(/^https:\/\/wa\.me\/\d{10,15}$/);
|
||||
expect(email.href).toMatch(/^mailto:[^\s@]+@[^\s@]+\.[^\s@]+$/);
|
||||
expect(linkedin.href).toMatch(/^https:\/\/(www\.)?linkedin\.com\/in\/[\w-]+\/?$/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
// Guardas de contraste, leídas del código fuente porque son una regla de
|
||||
// sistema, no el comportamiento de un componente suelto: lo que hay que impedir
|
||||
// es que el token vuelva a aparecer donde no se lee.
|
||||
//
|
||||
// `gris-medio` (#AAAAAA) da 7,2:1 sobre azul profundo — ahí es el token
|
||||
// correcto, y en Disciplinas y el footer se queda. Sobre blanco da 2,3:1 y
|
||||
// sobre gris-claro 2,1:1: en fondo claro es texto que no se lee.
|
||||
//
|
||||
// `dorado` (#C4942E) da 6,07:1 sobre azul profundo y 2,76:1 / 2,46:1 sobre los
|
||||
// dos fondos claros. Sigue siendo el color de rellenos, reglas, iconos y el ≡;
|
||||
// lo que no puede ser en claro es texto pequeño, y para eso está `dorado-texto`.
|
||||
|
||||
const SOBRE_CLARO = [
|
||||
'components/sections/Hero.tsx',
|
||||
'components/sections/Dolores.tsx',
|
||||
'components/sections/Proceso.tsx',
|
||||
'components/sections/ParaQuien.tsx',
|
||||
'components/sections/Estratega.tsx',
|
||||
'components/sections/ComoEmpezar.tsx',
|
||||
// La rama de movimiento reducido del recorrido va sobre gris-claro, y es
|
||||
// justo la que sirve a quien más necesita que el texto se lea.
|
||||
'components/primitives/ParDialogo.tsx',
|
||||
];
|
||||
|
||||
describe('tokens de texto sobre fondo claro', () => {
|
||||
it.each(SOBRE_CLARO)('%s no pinta texto en gris-medio', (archivo) => {
|
||||
expect(readFileSync(archivo, 'utf8')).not.toMatch(/text-gris-medio/);
|
||||
});
|
||||
|
||||
it('ParDialogo etiqueta al hablante en el dorado legible', () => {
|
||||
// La regla vertical sigue siendo `bg-dorado` — el dorado del manual como
|
||||
// relleno no tiene problema. Lo que no puede quedarse en #C4942E es la
|
||||
// etiqueta, que es texto de 12px sobre gris-claro.
|
||||
const fuente = readFileSync('components/primitives/ParDialogo.tsx', 'utf8');
|
||||
expect(fuente).toMatch(/text-dorado-texto/);
|
||||
expect(fuente).not.toMatch(/text-dorado(?!-)/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { esExterno, propsEnlace } from '../enlaces';
|
||||
|
||||
describe('propsEnlace', () => {
|
||||
it('opens outside links in a new tab without handing over window.opener', () => {
|
||||
expect(propsEnlace('https://wa.me/525558185802')).toEqual({ target: '_blank', rel: 'noopener noreferrer' });
|
||||
expect(propsEnlace('https://www.linkedin.com/in/x')).toEqual({ target: '_blank', rel: 'noopener noreferrer' });
|
||||
});
|
||||
|
||||
it('leaves in-page anchors and mailto: in the same tab', () => {
|
||||
expect(propsEnlace('#contacto')).toEqual({});
|
||||
expect(propsEnlace('mailto:hola@creeer.com')).toEqual({});
|
||||
expect(esExterno('mailto:hola@creeer.com')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import config from '../../tailwind.config';
|
||||
|
||||
// The scale is a contract, not a preference: the problem this redesign fixes is
|
||||
// that five elements were tied for largest on the page, and because of that,
|
||||
// none of them read as largest. Five roles: only one reaches above 4rem.
|
||||
const escala = () => (config.theme?.extend?.fontSize ?? {}) as Record<string, [string, object]>;
|
||||
|
||||
describe('escala tipográfica', () => {
|
||||
it('define los cinco roles del documento', () => {
|
||||
expect(Object.keys(escala())).toEqual(
|
||||
expect.arrayContaining(['display', 'titulo', 'sumario', 'cuerpo', 'rotulo']),
|
||||
);
|
||||
});
|
||||
|
||||
it('display es el único que llega a 7rem', () => {
|
||||
const conSieteRem = Object.entries(escala()).filter(([, v]) => v[0].includes('7rem'));
|
||||
expect(conSieteRem.map(([k]) => k)).toEqual(['display']);
|
||||
});
|
||||
|
||||
it('el cuerpo se compone holgado y el display apretado', () => {
|
||||
const lh = (rol: string) => (escala()[rol][1] as { lineHeight: string }).lineHeight;
|
||||
expect(Number(lh('display'))).toBeLessThan(1);
|
||||
expect(Number(lh('cuerpo'))).toBeGreaterThan(1.6);
|
||||
});
|
||||
|
||||
it('reserva una medida de 68 caracteres para el texto corrido', () => {
|
||||
const anchos = (config.theme?.extend?.maxWidth ?? {}) as Record<string, string>;
|
||||
expect(anchos.medida).toBe('68ch');
|
||||
});
|
||||
});
|
||||
+216
-154
@@ -11,160 +11,199 @@ export const brandPillars = {
|
||||
pillar3: "Crecimiento",
|
||||
};
|
||||
|
||||
export const hero = {
|
||||
eyebrow: '— tu estratega de crecimiento —',
|
||||
// Headline broken into segments for emphasis styling
|
||||
// ── 01 · Apertura ──────────────────────────────────────────────────────────
|
||||
export const apertura = {
|
||||
numero: '01',
|
||||
eyebrow: 'claridad estratégica para tu negocio',
|
||||
headline: {
|
||||
line1: 'Tu negocio no necesita',
|
||||
effort: 'más esfuerzo.', // gold (HV-1) or gold italic (V-a)
|
||||
acento: 'más esfuerzo.',
|
||||
line3: 'Necesita',
|
||||
clarity: 'más claridad.', // underlined gold
|
||||
cierre: 'más claridad.',
|
||||
},
|
||||
cta: 'Define tu siguiente movimiento',
|
||||
ctaSecundario: 'Ver cómo trabajo',
|
||||
quien: 'Claridad estratégica para empresarios con tracción que llegaron a su punto de inflexión.',
|
||||
// Hormozi: Dream Outcome — the hero names the problem; this line names the
|
||||
// result the reader walks away with. Concrete, time-bound, personal.
|
||||
dreamOutcome: 'Un plan a 12 meses para que tu negocio crezca sin depender de ti en cada decisión.',
|
||||
cta: 'Agenda una sesión de claridad — 30 min, sin costo',
|
||||
ctaSecundario: 'Ver cómo trabajamos',
|
||||
};
|
||||
|
||||
export const fraseAncla = {
|
||||
// Quote split into parts so the second clause can render in gold.
|
||||
quote: {
|
||||
before: 'Las empresas no dejan de crecer por falta de talento;',
|
||||
accent: 'dejan de crecer por falta de claridad.', // gold
|
||||
},
|
||||
};
|
||||
// ── 02 · Dónde estás ───────────────────────────────────────────────────────
|
||||
// Los seis puntos y los cuatro dolores son de las diapositivas 2 y 3 del deck
|
||||
// de la dueña. Verbatim. `respuesta` desaparece: existía para llenar seis
|
||||
// pantallas fijadas y el recorrido ya no existe.
|
||||
const PUNTOS = [
|
||||
{ name: 'Crecer', situacion: 'Ya demostraste que sabes crecer. El siguiente salto no tiene mapa.' },
|
||||
{ name: 'Consolidarse', situacion: 'Construiste rápido. Escalar así multiplicaría el desorden.' },
|
||||
{ name: 'Recuperar rentabilidad', situacion: 'Tu esfuerzo dejó de traducirse en resultado.' },
|
||||
{ name: 'Simplificar', situacion: 'Tu operación se volvió más compleja que tu negocio.' },
|
||||
{ name: 'Expandirse', situacion: 'Vas a mercados nuevos con el mismo mapa de decisión.' },
|
||||
{ name: 'Replantear el portafolio', situacion: 'Tienes varios frentes abiertos y ninguno con su lugar claro.' },
|
||||
];
|
||||
|
||||
// The six inflection points, from the dueña's deck "Rumbo Estratégico ·
|
||||
// Propuesta Socio" (slide 2). The deck states each one in the infinitive
|
||||
// ("Dar el siguiente salto sin saber por dónde"); here it is stated in the
|
||||
// second person, the way she reads them aloud herself — "estás atrapado en tu
|
||||
// compañía", "creciste muy rápido pero quieres expandirte" (call of 31/jul,
|
||||
// 6:01–7:15). `respuesta` is new copy and still needs her sign-off; 01 and 05
|
||||
// are the two exchanges she improvised on that call, written out.
|
||||
//
|
||||
// `situacion` describes the state of the business. It must not drift into how
|
||||
// the reader feels — that is `dolores`, one section down, in the client's own
|
||||
// first-person words, and the two would collapse into each other.
|
||||
export const puntosInflexion = {
|
||||
eyebrow: 'el contexto',
|
||||
title: 'Todos los negocios consolidados llegan a un punto de inflexión',
|
||||
lead: '¿Te reconoces?',
|
||||
items: [
|
||||
{
|
||||
name: 'Crecer',
|
||||
situacion: 'Ya demostraste que sabes crecer. El siguiente salto no tiene mapa.',
|
||||
respuesta: 'Me sumerjo hasta entender tu empresa desde dentro. Sales sabiendo por dónde, no intentándolo por todos lados a la vez.',
|
||||
},
|
||||
{
|
||||
name: 'Consolidarse',
|
||||
situacion: 'Construiste rápido. Escalar así multiplicaría el desorden.',
|
||||
respuesta: 'Ordenamos lo que ya existe antes de ponerle más peso encima. Escalas sobre algo que aguanta.',
|
||||
},
|
||||
{
|
||||
name: 'Recuperar rentabilidad',
|
||||
situacion: 'Tu esfuerzo dejó de traducirse en resultado.',
|
||||
respuesta: 'Cuestiono lo que todos dan por hecho en tu operación. El margen no siempre está en vender más.',
|
||||
},
|
||||
{
|
||||
name: 'Simplificar',
|
||||
situacion: 'Tu operación se volvió más compleja que tu negocio.',
|
||||
respuesta: 'Separo lo que solo tú puedes decidir de lo que la empresa debería resolver sin ti.',
|
||||
},
|
||||
{
|
||||
name: 'Expandirse',
|
||||
situacion: 'Vas a mercados nuevos con el mismo mapa de decisión.',
|
||||
respuesta: 'Reviso tu proceso y ubico la oportunidad real antes de mover una ficha. Expandirte deja de ser una apuesta.',
|
||||
},
|
||||
{
|
||||
name: 'Replantear el portafolio',
|
||||
situacion: 'Tienes varios frentes abiertos y ninguno con su lugar claro.',
|
||||
respuesta: 'Construimos, juntos, el criterio para decidir qué sigue y qué se deja ir. Por escrito, no en tu cabeza.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Slide 3 of the same deck. The four quotes are the client's own words —
|
||||
// keep them verbatim, in first person.
|
||||
export const dolores = {
|
||||
eyebrow: 'lo que realmente sientes',
|
||||
title: 'Los dolores detrás del punto de inflexión',
|
||||
quotes: [
|
||||
export const dondeEstas = {
|
||||
numero: '02',
|
||||
eyebrow: 'dónde estás',
|
||||
title: 'Tu negocio llegó a un punto de inflexión',
|
||||
sumario: 'Seis situaciones. Reconoce la tuya.',
|
||||
puntos: PUNTOS,
|
||||
etiquetaDolores: 'Y por dentro suena así',
|
||||
dolores: [
|
||||
'Trabajo más y gano casi lo mismo que hace dos años.',
|
||||
'Tengo varios proyectos y no sé en cuál enfocar mi tiempo y mi dinero.',
|
||||
'Mi empresa no puede crecer si yo no estoy en cada decisión.',
|
||||
'Lo que me trajo hasta aquí ya no me sirve para el siguiente nivel.',
|
||||
],
|
||||
// Split so the resolution renders in gold.
|
||||
remate: {
|
||||
before: 'Esto no se resuelve con más esfuerzo.',
|
||||
accent: 'Se resuelve con una estrategia clara.',
|
||||
},
|
||||
};
|
||||
|
||||
export const paraQuien = {
|
||||
// ── 03 · Qué cambia ────────────────────────────────────────────────────────
|
||||
export const queCambia = {
|
||||
numero: '03',
|
||||
eyebrow: 'qué cambia',
|
||||
ancla: {
|
||||
before: 'Las empresas no dejan de crecer por falta de talento;',
|
||||
accent: 'dejan de crecer por falta de claridad.',
|
||||
},
|
||||
// El "después": los dolores nombran el problema; esto pinta el resultado.
|
||||
// Paga directo el tercer dolor — "Mi empresa no puede crecer si yo no estoy
|
||||
// en cada decisión".
|
||||
despues: 'Sabes exactamente dónde invertir, tu equipo ejecuta sin que estés encima, y cada decisión tiene un plan detrás.',
|
||||
insight: 'No vendemos marketing. Vendemos claridad estratégica.',
|
||||
// Las tres disciplinas, degradadas de tres tarjetas con icono a una línea de
|
||||
// texto: el propio deck dice que son los medios, no la promesa.
|
||||
medios: 'Comunicación, digital y experiencias son las herramientas que usamos. No son lo que vendemos.',
|
||||
};
|
||||
|
||||
// ── 04 · El trabajo ────────────────────────────────────────────────────────
|
||||
export const elTrabajo = {
|
||||
numero: '04',
|
||||
eyebrow: 'el trabajo',
|
||||
// Hormozi: Name your mechanism. A named process is a system; an unnamed
|
||||
// process is a list. Systems sell. Lists don't.
|
||||
metodo: 'Ruta de Claridad',
|
||||
title: 'La Ruta de Claridad: de tu operación de hoy a tu plan a un año',
|
||||
sumario: 'Ocho etapas. Cada una deja algo por escrito.',
|
||||
fases: ['Inmersión', 'Desafiar supuestos', 'Estrategia ejecutable'],
|
||||
etiquetaEntregables: 'Entregables',
|
||||
etapas: [
|
||||
{ n: '01', name: 'Análisis de compañía y FODA', entregables: ['FODA', 'Diagnóstico ejecutivo', 'Prioridades', 'Quick wins'] },
|
||||
{ n: '02', name: 'Análisis interno', entregables: ['Mapa de capacidades', 'Restricciones del negocio', 'Oportunidades de crecimiento'] },
|
||||
{ n: '03', name: 'Conocimiento del consumidor', entregables: ['Segmentación', 'Buyer persona', 'Customer journey', 'Necesidades no cubiertas'] },
|
||||
{ n: '04', name: 'Estrategia de marca', entregables: ['Posicionamiento', 'Arquitectura de marcas', 'Manual estratégico'] },
|
||||
{ n: '05', name: 'Comunicación y branding', entregables: ['Plataforma de comunicación', 'Campaña anual', 'Estrategia de medios', 'Plan de contenido'] },
|
||||
{ n: '06', name: 'Marketing y ventas', entregables: ['Dashboard CEO', 'Dashboard comercial', 'Comité de crecimiento'] },
|
||||
{ n: '07', name: 'Innovación comercial', entregables: ['Roadmap de innovación', 'Go to market', 'Prioridades de innovación'] },
|
||||
{ n: '08', name: 'One Year Plan', entregables: ['Roadmap a 12 meses', 'Iniciativas prioritarias', 'Gobernanza del crecimiento'], remate: true },
|
||||
],
|
||||
};
|
||||
|
||||
// ── 05 · Para quién · Quién ────────────────────────────────────────────────
|
||||
export const paraQuienQuien = {
|
||||
numero: '05',
|
||||
eyebrow: 'para quién',
|
||||
title: '¿Llegaste a tu punto de inflexión?',
|
||||
lead: 'Esto es para ti si…',
|
||||
criteria: [
|
||||
'tienes tracción y ya demostraste que sabes crecer',
|
||||
'trabajar más ya no rinde como antes',
|
||||
'necesitas claridad para decidir el siguiente movimiento',
|
||||
'quieres profesionalizar sin perder tu esencia',
|
||||
],
|
||||
// Deck slide 9, "NO ES PARA". Kept impersonal on purpose: this disqualifies
|
||||
// a profile, it does not accuse the reader.
|
||||
leadNo: 'Esto no es para ti si…',
|
||||
criteriaNo: [
|
||||
'el negocio está en fase inicial o sin tracción',
|
||||
'buscas una solución rápida de venta',
|
||||
'buscas un curso, no una transformación',
|
||||
'la empresa está en crisis de supervivencia, no en transición',
|
||||
],
|
||||
si: {
|
||||
lead: 'Esto es para ti si…',
|
||||
criterios: [
|
||||
'tienes tracción y ya demostraste que sabes crecer',
|
||||
'trabajar más ya no rinde como antes',
|
||||
'necesitas claridad para decidir el siguiente movimiento',
|
||||
'quieres profesionalizar sin perder tu esencia',
|
||||
],
|
||||
},
|
||||
no: {
|
||||
lead: 'Esto no es para ti si…',
|
||||
criterios: [
|
||||
'el negocio está en fase inicial o sin tracción',
|
||||
'buscas una solución rápida, no un cambio de fondo',
|
||||
'buscas un curso, no una transformación',
|
||||
'la empresa está en crisis de supervivencia, no en transición',
|
||||
],
|
||||
},
|
||||
quien: {
|
||||
eyebrow: 'quiénes estamos detrás',
|
||||
title: 'Quiénes somos',
|
||||
cifra: '25+',
|
||||
cifraPie: 'años construyendo marcas',
|
||||
bio: '25 años de estrategia detrás de marcas que pasaron de locales a líderes de categoría. Hemos acompañado a más de 40 empresas en retail, servicios y manufactura a encontrar su siguiente movimiento.', // TODO dueña: confirmar cifra y lista de industrias
|
||||
quote: 'Tu negocio ya demostró que funciona. Ahora necesita un plan que lo lleve más lejos.',
|
||||
},
|
||||
};
|
||||
|
||||
export const mecanismo = {
|
||||
eyebrow: 'el mecanismo único',
|
||||
title: 'Cómo trabajo',
|
||||
steps: [
|
||||
{ n: '01', name: 'Inmersión', desc: 'Me sumerjo en tu empresa hasta comprenderla desde dentro.' },
|
||||
{ n: '02', name: 'Desafiar supuestos', desc: 'Cuestiono lo que todos dan por hecho y frenan el crecimiento.' },
|
||||
{ n: '03', name: 'Estrategia ejecutable', desc: 'Construimos, juntos, una estrategia que puedas ejecutar.' },
|
||||
// ── 06 · Empezar ───────────────────────────────────────────────────────────
|
||||
export const empezar = {
|
||||
numero: '06',
|
||||
eyebrow: 'empezar',
|
||||
title: 'Tu siguiente movimiento empieza con una conversación.',
|
||||
pasos: [
|
||||
{ n: '01', name: 'Escríbenos', desc: 'Cuéntanos dónde está tu negocio hoy.' },
|
||||
{ n: '02', name: 'Sesión de claridad', desc: 'Una conversación para ubicar tu punto de inflexión.' },
|
||||
{ n: '03', name: 'Plan en mano', desc: 'Sales con claridad y tu siguiente movimiento definido.' },
|
||||
],
|
||||
cta: 'Agenda tu sesión de claridad',
|
||||
whatsappText: 'Hola, quiero agendar una sesión de claridad',
|
||||
quote: 'Devuélvele claridad al rumbo de tu empresa.',
|
||||
contacto: {
|
||||
whatsapp: { label: 'WhatsApp', href: 'https://wa.me/525558185802' },
|
||||
email: { label: 'Email', href: 'mailto:jazmin.rodgon@gmail.com' },
|
||||
linkedin: { label: 'LinkedIn', href: 'https://www.linkedin.com/in/jazminrodriguez-jazinta' },
|
||||
},
|
||||
legal: '© 2026 creeer',
|
||||
};
|
||||
|
||||
// Practical details of the engagement — what the reader can expect when
|
||||
// working with creeer. Sits between Mecanismo (the high-level HOW) and
|
||||
// Disciplinas (the tools). All copy derived from approved sources:
|
||||
// mecanismo steps, puntosInflexion respuestas, comoEmpezar.
|
||||
// ⚠️ «Duración» left deliberately open — the dueña hasn't specified a
|
||||
// timeline. The card invites a conversation instead of committing a number.
|
||||
export const formaTrabajar = {
|
||||
eyebrow: 'qué esperar',
|
||||
title: 'Así es trabajar conmigo',
|
||||
items: [
|
||||
{
|
||||
name: 'Metodología',
|
||||
desc: 'Inmersión en tu empresa, desafío de lo que todos dan por hecho y construcción conjunta de tu estrategia.',
|
||||
},
|
||||
{
|
||||
name: 'Quién participa',
|
||||
desc: 'Tú y yo. Sin intermediarios. Trabajo directo con quien toma las decisiones.',
|
||||
},
|
||||
{
|
||||
name: 'De dónde partimos',
|
||||
desc: 'Tu operación real: números, procesos, equipo. Me sumerjo hasta comprenderla desde dentro.',
|
||||
},
|
||||
{
|
||||
name: 'Qué te llevas',
|
||||
desc: 'Un diagnóstico claro, tus prioridades ordenadas y una estrategia ejecutable. Por escrito, no en tu cabeza.',
|
||||
},
|
||||
{
|
||||
name: 'Duración',
|
||||
desc: 'Cada proceso tiene su ritmo. Lo definimos juntos en la sesión de diagnóstico.',
|
||||
},
|
||||
],
|
||||
// ── Alias de compatibilidad ────────────────────────────────────────────────
|
||||
// Los consumen las diez secciones viejas mientras conviven con las seis
|
||||
// nuevas. Derivan de los objetos de arriba, nunca duplican sus cadenas, y se
|
||||
// van enteros en la limpieza final. No añadir usos nuevos.
|
||||
|
||||
export const hero = {
|
||||
eyebrow: `— ${apertura.eyebrow} —`,
|
||||
headline: {
|
||||
line1: apertura.headline.line1,
|
||||
effort: apertura.headline.acento,
|
||||
line3: apertura.headline.line3,
|
||||
clarity: apertura.headline.cierre,
|
||||
},
|
||||
cta: apertura.cta,
|
||||
ctaSecundario: apertura.ctaSecundario,
|
||||
};
|
||||
|
||||
// La voz de creeer en el recorrido que sigue montado: cada situación del lector
|
||||
// recibe su respuesta. El rediseño las retira junto con el recorrido (ver
|
||||
// `dondeEstas`), pero mientras la sección vieja siga en la página, pregunta y
|
||||
// respuesta no pueden decir lo mismo. Son las del 31/jul pasadas al plural;
|
||||
// 01 y 05 las improvisó la dueña en esa llamada. Mismo orden que PUNTOS.
|
||||
const RESPUESTAS = [
|
||||
'Nos sumergimos hasta entender tu empresa desde dentro. Sales sabiendo por dónde, no intentándolo por todos lados a la vez.',
|
||||
'Ordenamos lo que ya existe antes de ponerle más peso encima. Escalas sobre algo que aguanta.',
|
||||
'Cuestionamos lo que todos dan por hecho en tu operación. El margen no siempre está en vender más.',
|
||||
'Separamos lo que solo tú puedes decidir de lo que la empresa debería resolver sin ti.',
|
||||
'Revisamos tu proceso y ubicamos la oportunidad real antes de mover una ficha. Expandirte deja de ser una apuesta.',
|
||||
'Construimos, juntos, el criterio para decidir qué sigue y qué se deja ir. Por escrito, no en tu cabeza.',
|
||||
];
|
||||
|
||||
export const puntosInflexion = {
|
||||
eyebrow: 'el contexto',
|
||||
title: dondeEstas.title,
|
||||
lead: '¿Te reconoces?',
|
||||
items: PUNTOS.map((p, i) => ({ ...p, respuesta: RESPUESTAS[i] })),
|
||||
};
|
||||
|
||||
export const dolores = {
|
||||
eyebrow: 'lo que realmente sientes',
|
||||
title: 'Los dolores detrás del punto de inflexión',
|
||||
quotes: dondeEstas.dolores,
|
||||
remate: dondeEstas.remate,
|
||||
};
|
||||
|
||||
export const disciplinas = {
|
||||
eyebrow: 'las herramientas',
|
||||
title: 'Las disciplinas que uso',
|
||||
title: 'Las disciplinas que usamos',
|
||||
lead: 'No son la promesa — son los medios.',
|
||||
items: [
|
||||
{ name: 'Comunicación', desc: 'Mensaje que alinea a tu equipo y a tu mercado.' },
|
||||
@@ -173,37 +212,48 @@ export const disciplinas = {
|
||||
],
|
||||
};
|
||||
|
||||
export const proceso = {
|
||||
eyebrow: 'el trabajo completo',
|
||||
title: elTrabajo.title,
|
||||
lead: elTrabajo.sumario,
|
||||
fases: elTrabajo.fases,
|
||||
etiquetaEntregables: elTrabajo.etiquetaEntregables,
|
||||
etapas: elTrabajo.etapas.map(({ n, name, entregables, remate }) =>
|
||||
remate ? { n, name, entregables, destacada: true } : { n, name, entregables },
|
||||
),
|
||||
};
|
||||
|
||||
export const paraQuien = {
|
||||
title: paraQuienQuien.title,
|
||||
lead: paraQuienQuien.si.lead,
|
||||
criteria: paraQuienQuien.si.criterios,
|
||||
leadNo: paraQuienQuien.no.lead,
|
||||
criteriaNo: paraQuienQuien.no.criterios,
|
||||
};
|
||||
|
||||
export const estratega = {
|
||||
// Split so the brand name keeps its lowercase inside an uppercase eyebrow —
|
||||
// CSS text-transform would otherwise render it as CREEER.
|
||||
eyebrow: { before: 'la mente detrás de', brand: 'creeer' },
|
||||
title: 'Sobre la estratega',
|
||||
bio: 'Más de 30 años construyendo marcas. Hoy acompaño a empresarios que ya lograron tracción y necesitan claridad para su siguiente movimiento.',
|
||||
quote: 'El tiempo no se compra, se invierte.',
|
||||
eyebrow: { before: 'quiénes estamos detrás de', brand: 'creeer' },
|
||||
title: paraQuienQuien.quien.title,
|
||||
bio: paraQuienQuien.quien.bio,
|
||||
quote: paraQuienQuien.quien.quote,
|
||||
};
|
||||
|
||||
export const comoEmpezar = {
|
||||
eyebrow: 'cómo empezar',
|
||||
title: 'Tu siguiente movimiento empieza con una conversación.',
|
||||
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: 'Plan en mano', desc: 'Sales con claridad y tu siguiente movimiento definido.' },
|
||||
],
|
||||
cta: 'Agenda tu sesión de diagnóstico',
|
||||
whatsappText: 'Hola, quiero agendar una sesión de diagnóstico',
|
||||
title: empezar.title,
|
||||
steps: empezar.pasos,
|
||||
cta: empezar.cta,
|
||||
whatsappText: empezar.whatsappText,
|
||||
};
|
||||
|
||||
export const cierre = {
|
||||
quote: 'Devuélvele claridad al rumbo de tu empresa.',
|
||||
cta: 'Define tu siguiente movimiento',
|
||||
contact: {
|
||||
whatsapp: { label: 'WhatsApp', href: 'https://wa.me/520000000000' }, // TODO dueña: real number
|
||||
email: { label: 'Email', href: 'mailto:hola@creeer.com' }, // TODO dueña: real email
|
||||
linkedin: { label: 'LinkedIn', href: 'https://linkedin.com/in/...' }, // TODO dueña: real URL
|
||||
},
|
||||
quote: empezar.quote,
|
||||
cta: apertura.cta,
|
||||
contact: empezar.contacto,
|
||||
};
|
||||
|
||||
export const fraseAncla = { quote: queCambia.ancla, despues: queCambia.despues };
|
||||
|
||||
export const header = {
|
||||
cta: 'Hablemos', // short nav CTA → #contacto (the full CTA lives in Hero/Cierre)
|
||||
};
|
||||
@@ -219,12 +269,24 @@ export const footer = {
|
||||
// image was modified — all of them get the navy/gold duotone treatment, and the
|
||||
// six in `recorrido` are additionally cropped and resized.
|
||||
export const creditosFotos = [
|
||||
{ desc: 'Foto: Golden Gate Bridge — Dietmar Rabich', href: 'https://commons.wikimedia.org/wiki/File:San_Francisco_(CA,_USA),_Golden_Gate_Bridge_--_2022_--_3023_(bw).jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: amanecer, Monte Nardi — Tony 1212', href: 'https://commons.wikimedia.org/wiki/File:Sunrise_over_the_summit_of_Mount_Nardi_from_the_south.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: distrito financiero de Riad — B.alotaby', href: 'https://commons.wikimedia.org/wiki/File:Riyadh_Skyline_showing_the_King_Abdullah_Financial_District_(KAFD)_and_the_famous_Kingdom_Tower_.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: sala de reuniones — Breather', href: 'https://commons.wikimedia.org/wiki/File:Minimalist_meeting_room_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ desc: 'Foto: cosechadora en el trigo — Michael Gäbler', href: 'https://commons.wikimedia.org/wiki/File:The_combine_Claas_Lexion_584_in_the_wheat_harvest.jpg', licencia: 'CC BY-SA 3.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/3.0/' },
|
||||
{ desc: 'Foto: pantalla de la Bolsa de Fráncfort — Ank Kumar', href: 'https://commons.wikimedia.org/wiki/File:Frankfurt_Stock_Exchange_(Ank_Kumar)_04.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: panel de salidas, aeropuerto de Ginebra — Tiia Monto', href: 'https://commons.wikimedia.org/wiki/File:Departure_board_at_Geneva_Airport.jpg', licencia: 'CC BY-SA 3.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/3.0/' },
|
||||
{ desc: 'Foto: distrito financiero de Boston — Ingfbruno', href: 'https://commons.wikimedia.org/wiki/File:USA-Financial_District.JPG', licencia: 'CC BY-SA 3.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/3.0/' },
|
||||
{ desc: 'Foto: Torre Mitikah en construcción, Ciudad de México — ProtoplasmaKid', href: 'https://commons.wikimedia.org/wiki/File:Torre_Mitikah_en_construcci%C3%B3n.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: oficina — Importaciones a México', href: 'https://commons.wikimedia.org/wiki/File:Importaciones_a_M%C3%A9xico_oficina.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: piñas de agave, Tequila, Jalisco — Gzzz', href: 'https://commons.wikimedia.org/wiki/File:Hearts_of_agave_plants_Tequila_Mexico.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: Distribuidor Vial San Antonio, Ciudad de México — ProtoplasmaKid', href: 'https://commons.wikimedia.org/wiki/File:Distribuidor_Vial_San_Antonio_2025_32.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: puertas de embarque, aeropuerto de Cancún — Vmzp85', href: 'https://commons.wikimedia.org/wiki/File:MMUN006.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
{ desc: 'Foto: skyline de Monterrey — Daniel Escobedo', href: 'https://commons.wikimedia.org/wiki/File:Skyline_de_Monterrey.jpg', licencia: 'CC BY-SA 4.0', licenciaHref: 'https://creativecommons.org/licenses/by-sa/4.0/' },
|
||||
|
||||
// Las ocho de `Proceso`, todas CC0 — ninguna obliga a atribuir, pero se
|
||||
// acreditan igual por coherencia con el resto de la lista. `archivo` ata cada
|
||||
// crédito a su imagen: hay un test en Proceso que falla si aparece una foto
|
||||
// en la sección sin entrada aquí.
|
||||
{ archivo: '/images/proceso/01.jpg', desc: 'Foto: sala de juntas — Benjamin Child', href: 'https://commons.wikimedia.org/wiki/File:Benjamin_Child_2015_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/02.jpg', desc: 'Foto: taller — Adi Goldstein', href: 'https://commons.wikimedia.org/wiki/File:The_Workshop_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/03.jpg', desc: 'Foto: escaleras concurridas — José Martín Ramírez C', href: 'https://commons.wikimedia.org/wiki/File:Busy_stairs_in_large_building_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/04.jpg', desc: 'Foto: tipografía sobre escritorio — rawpixel.com', href: 'https://commons.wikimedia.org/wiki/File:Typography,_coffee_and_roses_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/05.jpg', desc: 'Foto: estudio fotográfico — Alexander Dummer', href: 'https://commons.wikimedia.org/wiki/File:Photographic_studio_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/06.jpg', desc: 'Foto: tienda de discos — Samuel Dixon', href: 'https://commons.wikimedia.org/wiki/File:Vintage_record_store_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/07.jpg', desc: 'Foto: dispositivos sobre la mesa — Alejandro Escamilla', href: 'https://commons.wikimedia.org/wiki/File:Iphone,_macbook_and_smartphone_on_a_table_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
{ archivo: '/images/proceso/08.jpg', desc: 'Foto: planificador mensual — Eric Rothermel', href: 'https://commons.wikimedia.org/wiki/File:Monthly_schedule_(Unsplash).jpg', licencia: 'CC0', licenciaHref: 'https://creativecommons.org/publicdomain/zero/1.0/' },
|
||||
];
|
||||
@@ -0,0 +1,19 @@
|
||||
// Links that leave the site open in a new tab, so the reader never loses the
|
||||
// page: WhatsApp, LinkedIn, the photo credits. Everything else stays put —
|
||||
// in-page anchors (#contacto) obviously, and mailto: too, which hands off to
|
||||
// the mail client and would only leave an empty tab behind.
|
||||
//
|
||||
// `rel="noopener noreferrer"`: without noopener the opened page gets a handle
|
||||
// on this one through window.opener.
|
||||
|
||||
export function esExterno(href: string): boolean {
|
||||
return /^https?:\/\//i.test(href);
|
||||
}
|
||||
|
||||
export function propsEnlace(href: string) {
|
||||
return esExterno(href) ? ({ target: '_blank', rel: 'noopener noreferrer' } as const) : {};
|
||||
}
|
||||
|
||||
// Screen-reader users get told before the context switch happens (WCAG G201);
|
||||
// sighted readers see the new tab open.
|
||||
export const AVISO_PESTANA = 'se abre en otra pestaña';
|
||||
+1
-1
@@ -64,7 +64,7 @@ export const motionProps = (reduced: boolean) =>
|
||||
? { initial: 'visible' as const, animate: 'visible' as const, whileInView: undefined, viewport: undefined }
|
||||
: {};
|
||||
|
||||
// Cycles through `count` steps on its own (Mecanismo, ComoEmpezar): each
|
||||
// Cycles through `count` steps on its own (ComoEmpezar): each
|
||||
// manual change restarts the dwell timer, hovering pauses it, and it never
|
||||
// advances at all for reduced-motion users.
|
||||
export function useAutoStep(count: number, intervalMs = 3500) {
|
||||
|
||||
Reference in new issue
Block a user