Fase 3 — completa (Bloques A-H)

Composition

Componentes de composición: construyen páginas combinando primitivos de /design-system/primitives. Ninguno reestila desde cero algo que ya existe como primitivo.

Nota sobre responsive: este entorno no tiene herramienta de captura/browser automation. Cada sección incluye qué comprobar a 360/768/1024/1440px — verifícalo redimensionando la ventana real, los componentes son Tailwind responsive genuino (no hay una simulación de viewport dentro de la página).

4.3Container

max-width de página (1280px) con padding lateral responsive: 16px móvil → 24px tablet → 32px desktop.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px el padding lateral debe ser 16px; a partir de 768px, 24px; a partir de 1024px, 32px; a partir de 1280px el contenido deja de crecer y solo respira más el fondo alrededor.

Con fondo para ver los límites

max-w-container (1280px), con el padding lateral del breakpoint actual
<Container>
  <p>Contenido con el max-width y el padding del sistema.</p>
</Container>

// Elemento semántico distinto (por defecto es <div>):
<Container as="main">…</Container>

4.5Section / SectionHeader

Patrón repetible de sección mayor de página: <section> con padding vertical del sistema envolviendo un Container, más una cabecera opcional (eyebrow + h2 + subtítulo).

Comprobar en 360 / 768 / 1024 / 1440px: el padding vertical pasa de 64px (py-16) a 96px (py-24) en md (768px). El SectionHeader centrado debe mantenerse legible y no estirarse más allá de max-w-2xl incluso en 1440px.

Alineado a la izquierda (por defecto)

Nuestros servicios

Profesionales verificados para tu vivienda

Fontaneros, electricistas, pintores y cerrajeros de confianza en toda la Costa Blanca.

Centrado (align="center")

Confianza

Lo que dicen nuestros clientes

Karl, Alicante — 'Encontré un fontanero en menos de una hora.'

<Section>
  <SectionHeader
    eyebrow="Nuestros servicios"
    title="Profesionales verificados para tu vivienda"
    subtitle="Fontaneros, electricistas, pintores y cerrajeros de confianza."
  />
  {/* contenido de la sección */}
</Section>

4.4Grid system

El markdown es explícito: 'grid de Tailwind directa, sin wrapper propio' (§4.4). No existe un componente Grid — se documenta aquí el uso recomendado, no se implementa nada nuevo.

Ejemplo de uso recomendado (no es un componente)

Fontanería
Electricidad
Pintura
Cerrajería
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
  {services.map((s) => <FeatureCard key={s.id} {...s} />)}
</div>

3.1Card

Variantes: imagen top, imagen left (colapsa a top en móvil), sin imagen (con icono), con acciones al pie. El título es el link principal vía el patrón stretched-link cuando se pasa href.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px, la variante imagen-left debe colapsar a imagen arriba/texto abajo (grid-cols-1); a partir de md (768px) pasa a 160px + resto en fila. El footer con dos botones debe caber sin envolver texto en 360px.

Imagen top, con href (stretched link) y footer

Fontanero reparando una tubería

Fontanería en Alicante

Reparación de averías, grifería y calentadores. Respuesta en menos de 24h.

Verificado

Imagen left (colapsa a top en móvil)

Electricista revisando un cuadro eléctrico

Electricidad en Málaga

Instalaciones y averías eléctricas.

Disponible hoy

Sin imagen, con icono

¿Necesitas un cerrajero urgente?

Servicio de apertura y cambio de bombín disponible 24h en toda la provincia.

<Card
  image={{ src: '/fontanero.jpg', alt: 'Fontanero reparando una tubería' }}
  title="Fontanería en Alicante"
  href="/fontaneros/alicante"
  description="Reparación de averías, grifería y calentadores."
  meta={<Badge variant="primary">Verificado</Badge>}
  footer={<Button size="sm">Pedir presupuesto</Button>}
/>

3.2Feature card

Icono + título + descripción corta, con CTA opcional. Variantes bordered/filled/plain. Compone el primitivo Link para el CTA.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px el grid de 4 debe pasar a 2 columnas (grid-cols-2); a partir de md, 4 columnas. Los títulos no deben desbordar ni forzar scroll horizontal.

Grid de 4 (bordered)

Fontanería

Averías, grifería, calentadores y fugas.

Ver más

Electricidad

Instalaciones, cuadros eléctricos y averías.

Ver más

Pintura

Interiores, exteriores y reformas ligeras.

Ver más

Cerrajería

Aperturas, cambios de bombín y urgencias 24h.

Ver más

Variantes filled / plain

Filled

Fondo sunken, sin borde.

Plain

Sin fondo ni borde — para grids densos donde el propio grid ya estructura.

Sin icono (bloque de texto destacado, sin icono ni número asociado)

Cómo seleccionamos a los profesionales

Cada profesional se da de alta como autónomo o empresa verificable, con seguimiento tras el primer servicio prestado.

Conoce cómo trabajamos
<FeatureCard
  icon={<Wrench size={24} />}
  title="Fontanería"
  description="Averías, grifería, calentadores y fugas."
  ctaLabel="Ver más"
  ctaHref="/fontaneros"
/>

3.4Texto con imagen embebida

Para páginas informativas y de blog. Imagen a izquierda/derecha (float en desktop), ancha centrada (rompe el max-w-prose), o ancho completo. Siempre dentro de max-w-prose para la lectura continua.

Comprobar en 360 / 768 / 1024 / 1440px: por debajo de md, el float se desactiva y la imagen pasa a ancho completo antes del texto (nunca solapada); a partir de md, el texto debe fluir alrededor de la imagen flotante sin huecos raros.

inline-left

Pintor trabajando en una fachada
Nuestros pintores usan siempre materiales certificados.

Elegir un pintor de confianza en una zona que no conoces bien puede ser complicado, especialmente si el idioma es una barrera. En MyCasa Spain verificamos la identidad y las referencias de cada profesional antes de ponerlo en contacto contigo.

Todos los presupuestos son gratuitos y sin compromiso, y puedes comparar varias opciones antes de decidir. El pago siempre se gestiona directamente con el profesional, nunca a través de la plataforma.

wide-centered

Vivienda reformada en la Costa Blanca
Reforma completa en Jávea, 2025.

La imagen rompe el ancho de lectura del texto — pensada para fotografías destacadas dentro de un artículo largo.

<TextWithImage
  image={{ src: '/pintor.jpg', alt: 'Pintor trabajando en una fachada', caption: '…' }}
  position="inline-left"
>
  <p>Elegir un pintor de confianza…</p>
</TextWithImage>

3.5Sección alternada

Imagen y texto alternando lado en desktop (flex-row / flex-row-reverse). En móvil siempre imagen arriba, texto abajo — nunca invertido, por previsibilidad de lectura.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px ambos bloques deben apilarse siempre en el mismo orden (imagen, luego texto), incluso en el segundo item; a partir de md, el segundo item debe invertir el lado (imagen a la derecha).

Dos pasos, lado alternado en desktop

Persona rellenando un formulario en el móvil

1. Cuéntanos qué necesitas

Describe el problema y tu ubicación en menos de 2 minutos, sin registro.

Empezar ahora
Profesional llamando por teléfono

2. Te contactamos en 24h

Un profesional verificado se pone en contacto contigo con un presupuesto.

<AlternatingSection
  items={[
    { image: { src: '/paso1.jpg', alt: '…' }, title: '1. Cuéntanos qué necesitas', description: '…', ctaLabel: 'Empezar ahora', ctaHref: '/presupuesto' },
    { image: { src: '/paso2.jpg', alt: '…' }, title: '2. Te contactamos en 24h', description: '…' },
  ]}
/>

3.10Testimonial

Card con avatar (fallback de iniciales), rating opcional y cita — preparada para schema.org/Review vía microdata. Variante grid y variante carrusel (sin autoplay, con scroll-snap y controles).

Comprobar en 360 / 768 / 1024 / 1440px: el grid de 3 debe pasar a 1 columna a 360px; el carrusel debe mostrar ~1 card visible a 360px y ~2.5 a 1024px, con scroll-snap suave y los botones prev/next deshabilitados en los extremos.

Grid

Encontré un fontanero en menos de una hora y hablaba inglés perfectamente. La avería de la cisterna quedó resuelta el mismo día, sin sorpresas en el precio.

Buen servicio de electricidad, puntuales y el presupuesto se respetó al céntimo.

Como recién llegada a España, no confiaba en encontrar a alguien de fiar para pintar la casa. MyCasa Spain me puso en contacto con un profesional verificado, con reseñas reales y un trato exquisito. Repetiré sin duda para la próxima reforma.

Carrusel (arrastra o usa los controles)

Encontré un fontanero en menos de una hora y hablaba inglés perfectamente. La avería de la cisterna quedó resuelta el mismo día, sin sorpresas en el precio.

Buen servicio de electricidad, puntuales y el presupuesto se respetó al céntimo.

Como recién llegada a España, no confiaba en encontrar a alguien de fiar para pintar la casa. MyCasa Spain me puso en contacto con un profesional verificado, con reseñas reales y un trato exquisito. Repetiré sin duda para la próxima reforma.

<TestimonialGrid items={testimonials} />
<TestimonialCarousel items={testimonials} />

3.11Rating de estrellas

role="img" con aria-label numérico — nunca solo visual. Usa warning-500 (decisión explícita del usuario para esta fase; el markdown pedía un token rating-500 dedicado que no existe todavía en foundations).

Valores

<StarRating value={4.5} />

3.18Trust bar

Tira horizontal de señales de confianza con datos propios verificables — nunca sellos genéricos sin certificación real detrás.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px debe verse en grid de 2×2; a partir de md, en una sola fila de 4. Los números grandes no deben partirse a mitad de palabra.

Ejemplo

350+

Profesionales verificados

12.000

Servicios realizados

8 años

En la Costa Blanca

100%

Con seguro de responsabilidad civil

<TrustBar
  items={[
    { value: '350+', label: 'Profesionales verificados' },
    { value: '12.000', label: 'Servicios realizados' },
  ]}
/>

3.13Pagination

Numerado con elipsis en desktop; colapsa a 'Anterior / Página N de M / Siguiente' en móvil.

Comprobar en 360 / 768 / 1024 / 1440px: por debajo de sm debe verse solo el formato colapsado de texto; a partir de sm, los botones numerados con touch target de 48px.

Página actual: 3 de 12

<Pagination currentPage={page} totalPages={12} onPageChange={setPage} />

3.14Tabs

role=tablist con roving tabindex: solo el tab activo es tabbable, las flechas (←→ Home End) mueven el foco y seleccionan a la vez.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px, si los tabs no caben deben scrollear horizontalmente (overflow-x-auto) sin romper el layout de la página.

Prueba con flechas del teclado tras enfocar un tab

Desde 45€ la visita, presupuesto cerrado antes de empezar.

<Tabs items={[
  { id: 'precio', label: 'Precio', content: <p>…</p> },
  { id: 'cobertura', label: 'Zona de cobertura', content: <p>…</p> },
]} />

3.15Accordion

aria-expanded/aria-controls, animación con grid-template-rows (no max-height en px). Varios items pueden estar abiertos a la vez.

Ejemplo

<Accordion items={[
  { id: 'a1', title: '¿Cómo se verifica a los profesionales?', content: '…' },
]} />

3.16FAQ block

Composición sobre Accordion. HTML preparado para schema.org/FAQPage: contenedor FAQPage, cada pregunta en itemType=Question con un <h3 itemProp='name'> dentro del button, respuesta en itemType=Answer.

Ejemplo

Preguntas frecuentes

Todo lo que necesitas saber antes de pedir un presupuesto.

<FAQBlock
  title="Preguntas frecuentes"
  items={[{ question: '¿En qué idiomas…?', answer: '…' }]}
/>

3.21Drawer / off-canvas

Desliza desde la derecha, w-[85vw] max-w-sm. Mismo focus trap y Esc que Modal. Caso de uso típico: menú móvil.

Abrir

<Drawer open={open} onClose={() => setOpen(false)} label="Menú">
  <nav>…</nav>
</Drawer>

3.22Toast / notification

API imperativa vía ToastProvider + useToast(). role=status (info/success/warning) o role=alert (danger). Solo danger no hace auto-dismiss.

Dispara un toast

const { showToast } = useToast();
showToast('success', 'Presupuesto enviado correctamente.');

3.23Alert / Callout inline

Dentro del flujo de contenido (a diferencia de Toast, que es flotante). border-l-4 + fondo -50 del semántico correspondiente.

Variantes

Los precios son orientativos y varían según la visita.

Solicitud enviada

Te contactaremos en menos de 24h laborables.
<Alert variant="success" title="Solicitud enviada">
  Te contactaremos en menos de 24h laborables.
</Alert>

3.8Formulario de contacto/presupuesto

Patrón de referencia para todos los formularios del sitio. Validación en onBlur, resumen de errores con anclas cuando hay ≥3, y estado de éxito que sustituye el formulario completo. Ningún texto hardcodeado — todo llega vía el prop texts.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px todos los campos deben apilarse a ancho completo y el botón de envío debe ser w-full; a partir de sm el botón vuelve a su ancho de contenido.

Envía el formulario vacío para ver el resumen de errores; luego rellénalo para ver el éxito

Pide tu presupuesto gratis

Te contactamos en menos de 24h laborables.

Te llamaremos solo si hace falta confirmar el servicio.

<ContactForm
  texts={contactFormTexts}
  serviceOptions={[{ value: 'fontaneria', label: 'Fontanería' }, …]}
  onSubmit={async (values) => api.sendLead(values)}
/>

3.9Formulario de búsqueda hero

Servicio + ubicación + botón de búsqueda, en una sola barra en desktop y apilado en móvil. Ver nota en el componente sobre por qué mantiene las labels visibles.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px los 3 elementos deben apilarse a ancho completo; a partir de md pasan a una fila con el botón alineado al fondo de los campos (self-end), no a su centro vertical.

Ejemplo

<HeroSearchForm
  texts={heroSearchTexts}
  serviceOptions={services}
  locationOptions={locations}
  onSubmit={({ service, location }) => router.push(`/${service}/${location}`)}
/>

3.17CTA banner

Sección de llamada a la acción entre bloques de contenido. Variante solid (fondo primary-700, CTA inverso) y soft (fondo sunken, CTA accent normal). El CTA no usa el primitivo Button — ver nota en el componente.

Solid

¿Necesitas un profesional de confianza hoy mismo?

Pide presupuesto gratis y te contactamos en menos de 24h.

Soft

¿Eres profesional del hogar?

Únete a nuestra red verificada en la Costa Blanca.

Con acción secundaria (p.ej. WhatsApp + Llamar)

¿Necesitas un profesional hoy mismo?

Escríbenos por WhatsApp o llama directamente.

<CTABanner
  title="¿Necesitas un profesional de confianza hoy mismo?"
  description="Pide presupuesto gratis y te contactamos en menos de 24h."
  ctaLabel="Pedir presupuesto"
  ctaHref="/presupuesto"
/>

// Con acción secundaria:
<CTABanner
  title="…" ctaLabel="WhatsApp" ctaHref="https://wa.me/…" ctaExternal
  secondaryCtaLabel="Llamar · +34 600 000 000" secondaryCtaHref="tel:+34600000000"
/>

3.19Newsletter signup

Card compacta con email + botón en fila (desktop) o apilado (móvil). Texto legal siempre visible bajo el botón, nunca oculto en tooltip.

Ejemplo

Consejos de mantenimiento del hogar, una vez al mes

Puedes darte de baja cuando quieras. Consulta nuestra política de privacidad.

<NewsletterSignup texts={newsletterTexts} onSubmit={(email) => api.subscribe(email)} />

3.3Hero

HeroImage (imagen dominante, páginas de servicio/ubicación, con variante textOverlay opcional) y HeroHome (formulario adyacente, homepage — compone HeroSearchForm del Bloque D).

Comprobar en 360 / 768 / 1024 / 1440px: HeroImage: a 360px aspect-[16/9], a partir de md aspect-[21/9]. HeroHome: a 360px todo apilado (imagen, luego formulario en el flujo); a partir de md, dos columnas con el formulario flotando superpuesto al borde inferior de la imagen (-bottom-12) sin tapar el centro de la foto.

HeroImage — bloques separados (por defecto)

Fontanero reparando una tubería en una vivienda

Fontaneros en Alicante

Fontaneros de confianza en Alicante

Profesionales verificados, presupuesto gratis y respuesta en menos de 24h.

Pedir presupuesto

HeroImage — textOverlay (uso homepage)

Electricista revisando una instalación

MyCasa Spain

Profesionales de confianza para tu vivienda

Buscar un profesional

HeroHome — formulario adyacente

MyCasa Spain

Encuentra un profesional de confianza cerca de ti

Fontaneros, electricistas, pintores y cerrajeros verificados en toda la Costa Blanca.

350+ profesionales verificados

4,8/5 valoración media

Profesional del hogar sonriendo frente a una vivienda

HeroHome — sin foto (fallback a una columna centrada; usado en la Home real mientras no hay asset de fotografía)

MyCasa Spain

Encuentra un profesional de confianza cerca de ti

Fontaneros, electricistas, pintores y cerrajeros verificados en toda la Costa Blanca.

350+ profesionales verificados

<HeroImage
  title="Fontaneros de confianza en Alicante"
  image={{ src: '/fontanero.jpg', alt: '…' }}
  ctaLabel="Pedir presupuesto"
  ctaHref="/presupuesto"
/>

// Sin foto (fallback a una columna centrada) + ubicación como Select en vez de Combobox:
<HeroHome title="…" searchForm={{ …, locationMode: 'select' }} />

3.6Grid de servicios

SectionHeader + grid de FeatureCard, escalable de 4 a N. Con initialVisible + showMoreLabel, colapsa el resto tras un botón 'ver más' en vez de crecer indefinidamente.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px, grid-cols-2; a partir de md, grid-cols-4. Con 7 servicios y initialVisible=4, deben verse solo 4 + el botón 'ver más' hasta hacer click.

7 servicios, colapsado a 4

Nuestros servicios

Todo lo que tu vivienda necesita

Profesionales verificados para cualquier tipo de mantenimiento del hogar.

Fontanería

Averías, grifería, calentadores y fugas.

Electricidad

Instalaciones, cuadros eléctricos y averías.

Pintura

Interiores, exteriores y reformas ligeras.

Cerrajería

Aperturas, cambios de bombín y urgencias 24h.

<ServicesGrid
  title="Todo lo que tu vivienda necesita"
  services={services}
  initialVisible={4}
  showMoreLabel="Ver todos los servicios"
/>

3.7Grid de ubicaciones

Jerárquico en 2 niveles (provincia → municipios destacados), compacto, sin mapa obligatorio. Reusa el primitivo Link.

Comprobar en 360 / 768 / 1024 / 1440px: a 360px, columns-2; a partir de md, columns-3. Los nombres de municipio no deben partirse a mitad de palabra entre columnas (break-inside-avoid en cada li).

<LocationsGrid
  provinces={[
    { name: 'Alicante', municipalities: [{ name: 'Benidorm', href: '/fontaneros/benidorm' }, …], viewAll: { href: '…', label: 'Ver todas' } },
  ]}
/>

3.24Mapa de provincias

Complementa el grid de ubicaciones (§3.7), nunca lo sustituye. Server Component: SVG inlineado en build, coloreado por Tailwind, hover/enlaces sin JS de cliente.

Comprobar en 360 / 768 / 1024 / 1440px: w-full con aspect-ratio propio del SVG (569×392) — se reduce de forma fluida, no tiene breakpoint propio.

Con 4 provincias activas

<ProvinceMap
  title="Provincias donde operamos"
  provinces={[{ id: 1, name: 'Alicante', href: '/fontaneros/alicante' }, …]}
/>

5.1Article card

Compone Card (Bloque B) + Badge — usa el nuevo prop imageOverlay de Card (añadido en este bloque) para la etiqueta de categoría superpuesta.

Grid de 3

Fontanero revisando una tubería
Fontanería

Cómo elegir un fontanero de confianza en la Costa Blanca

Laura Gómez 4 min de lectura

Cuadro eléctrico abierto
Electricidad

5 señales de que necesitas revisar tu instalación eléctrica

Marc Ibáñez 3 min de lectura

Piscina en una vivienda con jardín
Jardinería

Mantenimiento de piscina antes del verano: guía completa

Laura Gómez 6 min de lectura

<ArticleCard
  title="Cómo elegir un fontanero de confianza en la Costa Blanca"
  href="/blog/como-elegir-fontanero"
  image={{ src: '/blog/fontanero.jpg', alt: '…' }}
  category="Fontanería"
  author="Laura Gómez"
  publishedAtISO="2026-02-10"
  publishedAtLabel="10 feb 2026"
  readingTimeLabel="4 min de lectura"
/>

5.2Article header

Tag + h1 (font-serif, solo aquí) + meta con Avatar + imagen destacada. El Breadcrumb ya no vive aquí — las páginas lo colocan al final del contenido, justo encima del footer. Preparado para schema.org/Article vía itemProp — sin itemScope propio: lo pone la plantilla de página que envuelve header + body juntos (ver nota en el componente).

Comprobar en 360 / 768 / 1024 / 1440px: a 360px la imagen destacada debe mantener aspect-[16/9] a ancho completo; el h1 (font-serif) no debe desbordar ni partir palabras largas alemanas.

Cabecera completa

Fontanería

Cómo elegir un fontanero de confianza en la Costa Blanca

4 min de lectura

Fontanero reparando una tubería
Foto: archivo MyCasa Spain
<div itemScope itemType="https://schema.org/Article">
  <ArticleHeader category="Fontanería" title="…" authorName="Laura Gómez" image={{ src: '…', alt: '…' }} … />
  <ArticleBody>…</ArticleBody>
</div>

5.3Article body + Table of contents

ArticleBody usa @tailwindcss/typography (instalado en este bloque) con los tokens del sistema. TableOfContents con scroll-spy real vía IntersectionObserver — haz scroll dentro de la caja para ver el item activo cambiar.

Comprobar en 360 / 768 / 1024 / 1440px: por debajo de lg, el TOC debe ser un <details> colapsable (nunca desaparece); a partir de lg, sticky lateral junto al texto.

Ejemplo con scroll propio (420px de alto)

Introducción

Elegir un fontanero de confianza en una zona que no conoces bien puede ser complicado, especialmente si el idioma es una barrera.

Señales de alarma

Desconfía de presupuestos verbales sin desglose, de quien no puede acreditar un seguro de responsabilidad civil, y de tarifas muy por debajo de la media de la zona.

Un profesional serio siempre te dará un presupuesto por escrito antes de empezar.

Cómo verificamos a los profesionales

Comprobamos identidad, seguro y referencias antes de dar de alta a cualquier profesional en la plataforma.

Conclusión

Con estas pautas, encontrar un fontanero de confianza en la Costa Blanca no tiene por qué ser complicado.

<div className="lg:grid lg:grid-cols-[1fr_200px] lg:gap-8">
  <ArticleBody>
    <h2 id="toc-intro">Introducción</h2>
    <p>…</p>
  </ArticleBody>
  <TableOfContents items={tocItems} mobileLabel="Índice del artículo" />
</div>

5.5Author bio box

Avatar grande + nombre + rol + bio corta + links sociales opcionales.

Ejemplo

Laura Gómez

Redactora especializada en mantenimiento del hogar

Lleva 6 años escribiendo sobre reformas y mantenimiento en la Costa Blanca, y colabora habitualmente con profesionales verificados de la red.

<AuthorBio name="Laura Gómez" role="Redactora…" bio="…" avatarSrc="/authors/laura.jpg" />

5.7Share buttons

WhatsApp, email y copiar enlace — discretos, sin colores de marca. El botón de copiar da feedback accesible (cambia el aria-label y el icono, no solo el color).

Prueba a copiar el enlace

<ShareButtons
  url={articleUrl}
  title={articleTitle}
  whatsappLabel="Compartir por WhatsApp"
  emailLabel="Compartir por email"
  copyLabel="Copiar enlace"
  copiedLabel="Enlace copiado"
/>

6.1Empty state

Icono en círculo neutro + título + descripción + CTA. Comparte base con Error state y Zero results (StateMessage) — mismo criterio que Badge/Tag/Pill.

Ejemplo

Aún no tienes solicitudes

Cuando pidas un presupuesto, aparecerá aquí para que hagas seguimiento.

<EmptyState
  title="Aún no tienes solicitudes"
  description="Cuando pidas un presupuesto, aparecerá aquí."
  primaryAction={{ label: 'Pedir tu primer presupuesto', href: '/presupuesto' }}
/>

6.2Loading state

Skeleton compuesto, preferido sobre spinner para contenido de duración predecible (§6.2). role=status anuncia 'Cargando' una sola vez para todo el bloque, no por cada rectángulo.

variant=cards

Cargando contenido…

variant=list

Cargando contenido…

variant=text

Cargando contenido…
<LoadingState variant="cards" count={4} />

6.3Error state

Círculo danger-50/danger-600, título sin jerga técnica, 'Reintentar' (acción) + link a inicio (navegación) — combina las dos formas de acción que soporta StateMessage.

Ejemplo

No hemos podido cargar esta página

Puede que sea un problema temporal de conexión.

Ir a inicio
<ErrorState
  title="No hemos podido cargar esta página"
  primaryAction={{ label: 'Reintentar', onClick: refetch }}
  secondaryAction={{ label: 'Ir a inicio', href: '/' }}
/>

6.4Zero results

Mismo patrón visual que Empty state (§6.4) — mensaje específico de búsqueda sin resultados, nunca un callejón sin salida: siempre una alternativa clara.

Ejemplo

No encontramos fontaneros en Requena todavía

Déjanos tu contacto y te avisamos en cuanto tengamos cobertura en tu zona.

<ZeroResultsState
  title="No encontramos fontaneros en Requena todavía"
  primaryAction={{ label: 'Avísame', href: '/contacto' }}
  secondaryAction={{ label: 'Ver servicios cercanos', href: '/fontaneros' }}
/>