Files
Creeer-Web/components/sections/Dolores.tsx
T
erikghandClaude Opus 5.5 89e54a6e84 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>
2026-09-30 11:27:20 -06:00

74 lines
4.0 KiB
TypeScript

'use client';
import { motion } from 'framer-motion';
import { Container } from '@/components/primitives/Container';
import { Antetitulo } from '@/components/primitives/Antetitulo';
import { IlustracionNudo } from '@/components/primitives/IlustracionNudo';
import { TextoDesenfoque } from '@/components/primitives/TextoDesenfoque';
import { dolores } from '@/lib/content';
import { fadeInUp, viewportOnce, usePrefersReducedMotion, motionProps } from '@/lib/motion';
// The four quotes are the client's own words, from slide 3 of the dueña's deck.
//
// They were four tidy cards, which was the opposite of what they describe; then
// they were a marquee, which was worse — a loop belongs to a sale banner, and
// the brand's locked tone is "seguridad + cercanía", "simple, directo, limpio".
// It also sliced every sentence at both edges, so none was ever fully framed.
//
// Now they arrive one at a time as the reader comes down and they stay. What
// carries the weight is the pile, not the travel: each one lands further in or
// further out than the last, the way overheard sentences do, and by the fourth
// the reader is looking at everything at once. Then the resolution, flush left
// and gold, with nothing moving.
// Deliberately not a staircase. A regular indent reads as a list; an irregular
// one reads as four separate voices that happen to be in the same room.
const SANGRIAS = ['md:ml-0', 'md:ml-[14%]', 'md:ml-[5%]', 'md:ml-[21%]'];
export function Dolores() {
const reduced = usePrefersReducedMotion();
return (
<section className="bg-white bg-hondo-blanco relative overflow-hidden">
{/* Smaller and a touch stronger than it was: sprawling at 8% across the
whole title it read as a smudge over the headline rather than as a
knot. Stays centred. */}
<IlustracionNudo className="pointer-events-none select-none absolute top-0 left-1/2 -translate-x-1/2 w-56 md:w-80 text-azul-profundo/[0.11]" />
<Container className="relative py-16 md:py-24">
<Antetitulo as={motion.p} variants={fadeInUp} initial="hidden" whileInView="visible" viewport={viewportOnce} {...motionProps(reduced)}>
{dolores.eyebrow}
</Antetitulo>
<motion.h2 variants={fadeInUp} initial="hidden" whileInView="visible" viewport={viewportOnce} {...motionProps(reduced)}
className="mt-4 font-sans font-black text-seccion text-azul-profundo max-w-3xl">{dolores.title}</motion.h2>
{/* No stagger on the list. A container stagger fires all four the moment
the section is 30% on screen, and the section is 1.200px tall — the
reader would watch every sentence appear long before scrolling to
it, which is not what "se apilan al bajar" means. TextoDesenfoque
carries its own observer, so each quote waits for its own arrival
and then resolves out of blur, word by word: the pain coming into
focus. Same device as the hero and the anchor phrase. */}
<ul className="mt-14 flex flex-col gap-9 md:gap-12 list-none p-0">
{dolores.quotes.map((quote, i) => (
<li key={quote} className={`max-w-3xl ${SANGRIAS[i]}`}>
<blockquote className="font-sans italic font-bold leading-snug text-azul-profundo text-2xl md:text-4xl lg:text-[2.6rem]">
<span className="not-italic text-dorado">“</span>
<TextoDesenfoque segments={[{ text: quote }]} delayMs={38} />
<span className="not-italic text-dorado">”</span>
</blockquote>
</li>
))}
</ul>
{/* Flush left and still, against four sentences that are not. */}
<motion.p variants={fadeInUp} initial="hidden" whileInView="visible" viewport={viewportOnce} {...motionProps(reduced)}
className="mt-16 md:mt-20 font-sans font-black text-ancla text-azul-profundo max-w-4xl">
{dolores.remate.before}{' '}
<span className="text-dorado">{dolores.remate.accent}</span>
</motion.p>
</Container>
</section>
);
}