# Maqueta visual de la tienda — para aprobación del cliente

Última actualización: 2026-08-13 v5 (descripciones enriquecidas integradas desde maino_pocketbase.zip)

## Qué es

`maqueta-bicicletas-maino.html` — un solo archivo autocontenido (424 KB, sin build, sin
dependencias salvo la fuente de Google) que muestra cómo queda la tienda después de la migración.
**Es maqueta**: no hay carrito real, ni backend, ni persistencia, ni llamadas a API.

## Fuentes

Estaban en `C:\Users\pc\Downloads\maino-maqueta-src\`.

| Archivo | Qué es |
|---|---|
| `plantilla.html` | Estructura + todo el CSS. Tokens en `:root`. Marcadores `/*__DATOS__*/` y `/*__JS__*/` |
| `app.js` | Vistas y router. JS plano, sin framework |
| `catalogo.json` | Copia de `datos/catalogo_compacto.json` |
| `descripciones.json` | Descripciones por handle (HTML sanitizado) extraídas del bundle de la migración |
| `extraer_descripciones.py` | Regenera `descripciones.json` desde `catalog_enriquecido.json` |
| `build.py` | `python build.py` → regenera el HTML. Mezcla catálogo + descripciones. Excluye `alertas_compra` (voz interna) |
| `LEEME.md` | Guía completa |
| `maqueta-bicicletas-maino.html` | Salida compilada. **No editar a mano** |

> **Comprobado el 2026-09-03: ni `maino-maqueta-src\` ni `maino_pocketbase.zip` están ya en el PC.**
> Hay que recuperarlos de los adjuntos del chat de la migración.

## Dónde vive cada parte del enriquecimiento

1. **Specs canónicas** → `datos/catalogo_compacto.json` (671 entradas) — tabla «Especificaciones» de la ficha.
2. **Alertas (578)** → en el compacto y en el zip, pero **en voz interna** de enriquecimiento
   («verificar la unidad antes de publicar», «si el cliente busca…»). Excluidas de la maqueta pública.
   Pendiente: separarlas en alertas_comprador/notas_internas y redactar las primeras en voz de tienda.
3. **Descripciones** → `catalog_enriquecido.json` del zip (169/169 con HTML: H2 diferenciador + párrafos;
   los no enriquecidos traen el copy original). Integradas a la maqueta en v5 vía `extraer_descripciones.py`,
   que corta las secciones internas y sanitiza el HTML a tags de texto sin atributos.

## Vistas

`#/` home · `#/c/<slug>` listado · `#/p/<handle>` ficha · `#/carro` · `#/checkout`.

## Estructura de la ficha (v5)

Galería sticky (contador «i / N») + columna derecha: marca/título/código, chips de datos clave,
caja de compra (precio, cuotas, stock, cantidad, CTAs, pagos). Debajo a ancho completo: panel
«Descripción» (HTML enriquecido; cae al excerpt si falta; los enriquecidos llevan el sello
«redactada contra documentación del fabricante») → panel «Especificaciones técnicas» → relacionados.
Barra de compra fija en móvil (≤640 px).

`p.desc` se inyecta como HTML a propósito (sanitizado en el extractor, no en runtime).
«Ficha verificada» sale de `p.enriquecido`. Relevancia de listados: nº de specs + fotos.

## Decisiones de diseño que conviene conservar

- **Tokens CSS** con los nombres del proyecto real — `:root` va tal cual a tokens.css.
- **Solo se muestra lo que existe**: sin specs no hay tabla, sin desc/excerpt no hay panel,
  sin foto placeholder con la marca.
- Filtros con facetas y conteos reales. Fotos `object-fit: contain`, caja 1:1.
- Home: destacados una pieza por categoría y marca, en múltiplo de 4.

## Verificación hecha (2026-08-13, v5)

Playwright 1440 y 390 px: home, listado, carro, checkout + 3 fichas: **0 errores JS, 0 desbordes**.
El sandbox no alcanza el CDN de Shopify — se verifica con placeholder.

## Deuda conocida al pasar a React

1. Router real + redirects 301 desde handles de Shopify (186 filas).
2. Carro en zustand + total server-side en `pb_hooks`.
3. Imágenes a thumbs de PocketBase con `srcset`.
4. Separar y redactar alertas al comprador; reactivar el bloque «Antes de comprar».
5. Sanitizado de descripciones: en producción usar DOMPurify o equivalente server-side.
6. Buscador decorativo. 7. Roles/`alt` de accesibilidad. 8. Títulos duplicados en el dato.
