# Landing Sr. Pan — Contexto, avances y pendientes

Documento de referencia para continuidad del desarrollo de la landing pública de **Sr. Pan** (panadería gourmet).  
**Última actualización: 1 julio 2026.**

---

## Resumen ejecutivo

Landing de conversión orientada a pedidos por **WhatsApp**, integrada en el proyecto **panaderia** (CodeIgniter 4). La ruta raíz `/` sirve la landing; el POS/admin sigue en `/entrar`, `/inicio`, etc.

La landing incluye una **bolsa de pan** client-side: el usuario arma su pedido en el catálogo, elige sucursal y lo envía por WhatsApp. Sin pagos ni registro.

| Campo | Valor |
|---|---|
| **Marca** | Sr. Pan — Panadería gourmet |
| **Branch activa** | `feat/landing-srpan` |
| **Ruta** | `GET /` → `Home::landing` |
| **Vista** | `app/Views/landing.php` |
| **Estilos** | `public/assets/css/srpan-landing.css` |
| **JS** | `srpan-landing.js` (nav) + `srpan-cart.js` (bolsa + catálogo) |
| **Controlador** | `app/Controllers/Home.php` |

---

## Stack técnico

- **Backend:** CodeIgniter 4 (PHP 8.1+)
- **Datos dinámicos:** `ArticleService::getArticles(true)` — catálogo completo activo (`paused = 0`)
- **Bolsa:** 100 % client-side — `localStorage` + mensaje WhatsApp formateado
- **Fuentes (Google Fonts):** DM Sans (body), Fraunces (headlines), JetBrains Mono (labels)
- **Iconos:** Remix Icon (`remixicon.css` — subset completo, optimizable)
- **Sin frameworks JS** en la landing (vanilla JS)

### Optimizaciones de rendimiento aplicadas

- Eliminados `core.css` y `theme-default.css` del vendor (~920 KB)
- Fuentes reducidas a pesos esenciales
- `preload` de imagen hero
- En móvil: sin `backdrop-filter` en barra de bolsa, sin `filter` en foto hero
- `loading="lazy"` en imágenes del catálogo
- `width`/`height` en imágenes de producto del catálogo

### CSS/JS del vendor NO cargados en landing

```
/assets/vendor/css/core.css          ← removido
/assets/vendor/css/theme-default.css ← removido
```

---

## Archivos del feature

| Archivo | Rol |
|---|---|
| `app/Config/Routes.php` | `$routes->get('/', 'Home::landing')` |
| `app/Controllers/Home.php` | Catálogo completo, JSON embebido, mapa de imágenes por nombre |
| `app/Views/landing.php` | HTML, drawer de bolsa, sticky bar, OG, Schema.org |
| `public/assets/css/srpan-landing.css` | Estilos completos + bolsa + catálogo colapsable |
| `public/assets/js/srpan-landing.js` | Menú hamburguesa |
| `public/assets/js/srpan-cart.js` | Bolsa, filtro categorías, «mostrar más», WhatsApp checkout |
| `public/assets/img/srpan/logo.png` | Logo |
| `public/assets/img/srpan/products/*.png` | Fotos de producto |

---

## Bolsa de pan (carrito WhatsApp)

### Flujo de usuario

1. Explorar catálogo → **Agregar** piezas (stepper `− / +`)
2. Abrir **Tu bolsa** (nav o barra sticky inferior)
3. Elegir sucursal: **Huixtla** o **Tapachula** (obligatorio)
4. Pulsar **Enviar pedido por WhatsApp**

### Arquitectura

```
Home::landing → ArticleService → catalogJson (PHP)
                                      ↓
                              #srpan-catalog (JSON en HTML)
                                      ↓
                              srpan-cart.js
                              ├── localStorage (srpan_bag_v1)
                              ├── render cards / drawer / sticky bar
                              └── buildWhatsAppUrl() → api.whatsapp.com
```

### Estado en localStorage

Clave: `srpan_bag_v1`

```json
{
  "items": {
    "12": { "id": 12, "name": "Bigotes almendra", "price": 45, "qty": 2 }
  },
  "location": "Huixtla"
}
```

### Mensaje WhatsApp generado

```
Hola Sr. Pan, quiero hacer un pedido:

• Bigotes almendra x2 — $90.00
• Panque café x1 — $65.00

Total estimado: $155.00
Recoger en: Huixtla

(Confirmen disponibilidad, por favor)
```

- Teléfono: `5212281159021`
- Límite URL: ~1800 chars; si excede, trunca lista y añade «...y X productos más»

### Componentes UI

| Elemento | ID / clase | Descripción |
|---|---|---|
| Botón nav | `#srpan-nav-bag-btn` | Abre drawer; badge con contador |
| Barra sticky | `#srpan-bag-bar` | Visible cuando `totalQty > 0` |
| Drawer | `#srpan-bag-drawer` | Panel lateral (desktop) / sheet (móvil) |
| Estado vacío | `#srpan-bag-empty` | Mensaje cuando no hay piezas |
| Lista | `#srpan-bag-items` | Líneas con stepper y subtotal |
| Checkout | `#srpan-bag-checkout` | Activo solo con piezas + sucursal |

### Decisiones explícitas

- **Sin** `POST /sale` — la bolsa no registra ventas en el POS
- **Sin** pagos online ni registro de usuarios
- **Sin** campo de notas (pendiente si el cliente lo pide)
- Precios en bolsa son **referencia**; disclaimer en drawer y catálogo

---

## Catálogo

### Comportamiento actual

- Muestra **todo el catálogo activo** de la BD (no solo 6 destacados)
- **9 productos visibles** por defecto; el resto oculto
- Botón **«Mostrar X productos más»** expande el grid completo
- Al filtrar por categoría: muestra los primeros 9 de esa categoría; el contador del botón se recalcula
- Filtro en chips del hero (scroll a `#catalogo`) y en `featured-rail` del catálogo

### Imágenes de producto

Mapeo por **nombre** en `Home::resolveProductImage()` (no por índice ni ID de artículo).

| Keyword en nombre | Archivo |
|---|---|
| panque + café/cafe | `panque_cafe.png` |
| bigote | `bigotes_almendra.png` |
| cartera | `carteras_cajeta_philadelphia.png` |
| brownie | `brownies_chocolate.png` |
| tartina | `tartinas.png` |
| marmoleado | `panque_marmoleado.png` |
| nata / coco | `panque_nata_coco.png` |
| (sin match) | Placeholder con inicial del nombre |

Ruta: `public/assets/img/srpan/products/`  
Fuente alternativa del cliente: `~/Desktop/inspiration/images/`

> **No convertir a WebP** hasta que el catálogo fotográfico esté estable.

---

## Estructura de secciones (orden)

1. **Hero full-bleed** — foto, headline, trust bar, CTA «Arma tu bolsa», métricas
2. **Categorías** — chips filtrables (top 4 + «Todas»)
3. **Por qué Sr. Pan** — `#esencia`
4. **Catálogo** — `#catalogo` — catálogo completo, 9 visibles + «mostrar más»
5. **Galería** — 4 piezas con copy
6. **Cómo pedir** — 3 pasos (bolsa → WhatsApp → disfrutar)
7. **Social proof** — `#ubicaciones`
8. **FAQ** — incluye «¿Puedo armar mi pedido en la página?»
9. **CTA final** — `#contacto` → «Armar mi bolsa»
10. **Footer** — links + crédito sistematlan

---

## Copy clave (estado actual)

**Hero headline:**  
`Donde cada pieza se antoja al instante.`

**Hero sub:**  
`Para tu mesa, tu oficina o ese regalo que no puede fallar. Un mensaje y listo.`

**CTAs principales:**
- Nav: `Tu bolsa` (abre drawer)
- Hero: `Arma tu bolsa` (scroll a catálogo)
- Cierre: `Armar mi bolsa`

**Framework:** StoryBrand — antojo → Sr. Pan guía → bolsa → WhatsApp → disfrute.

---

## Variables PHP en la vista

```php
$catalogArticles   // todos los artículos activos
$catalogJson       // { whatsappPhone, locations, articles[] } para JS
$productImages     // mapa article.id => ruta PNG o null
$categorySummary   // top 4 categorías con conteo (chips hero)
$categoryFilters   // todas las categorías con conteo (filtro catálogo)
$heroBackground    // imagen full-bleed
$galleryImages     // 4 imágenes galería
$articleCount      // total piezas
$categoryCount     // total categorías
$startingPrice     // precio mínimo o null
$locationLabel     // 'Huixtla y Tapachula, Chiapas'
$locations         // [{ city, state, mapsUrl }, ...]
$instagramHandle   // '@sr.pan_mx'
$instagramUrl
```

---

## Contacto y canales

| Canal | Valor |
|---|---|
| **WhatsApp** | `https://api.whatsapp.com/send?phone=5212281159021` |
| **Instagram** | [@sr.pan_mx](https://www.instagram.com/sr.pan_mx/) |
| **Área interna** | `/entrar` (login POS — no enlazado en nav público) |

---

## Ubicaciones (2 sucursales)

| Ciudad | Google Maps |
|---|---|
| **Huixtla, Chiapas** | https://maps.app.goo.gl/CDxgUsomwrCSYRWM6 |
| **Tapachula, Chiapas** | https://maps.app.goo.gl/MTufhojMjWhbqy898 |

> Direcciones físicas (calle/número) **pendientes**.

---

## Avances completados

### Landing base (jun 2026)
- [x] Hero full-bleed, copy StoryBrand, tipografía Fraunces + DM Sans
- [x] Ubicaciones Huixtla y Tapachula con Maps
- [x] Navbar hamburguesa ≤991px
- [x] Auditoría móvil (trust bar, métricas, overflow)
- [x] Social proof, FAQ, galería, footer

### Bolsa de pan (jul 2026)
- [x] Catálogo completo desde BD
- [x] Agregar / stepper en cada product card
- [x] Drawer «Tu bolsa» con lista y subtotal estimado
- [x] Selección obligatoria de sucursal (Huixtla / Tapachula)
- [x] Checkout por WhatsApp con mensaje formateado
- [x] Persistencia en `localStorage` (`srpan_bag_v1`)
- [x] Barra sticky inferior con contador (móvil + desktop)
- [x] Botón «Tu bolsa» en nav con badge
- [x] Filtro por categoría (chips + featured rail)
- [x] Open Graph + Twitter Card
- [x] Schema.org `Bakery` con 2 sucursales (JSON-LD)
- [x] Mapa de imágenes por nombre de producto
- [x] Placeholder elegante (inicial) para productos sin foto

### UX catálogo (jul 2026)
- [x] Mostrar 9 productos por defecto
- [x] Botón «Mostrar X productos más» (compatible con filtro de categoría)

### Bugs corregidos
- [x] Drawer mostraba «Tu bolsa está vacía» con productos en bolsa — `display: grid` en `.srpan-bag-empty` anulaba `[hidden]`; fix con `[hidden] { display: none !important }`

---

## Pendientes por implementar

### Alta — conversión y contenido

- [ ] **Campo de notas en checkout** — fecha/hora deseada, entrega, comentarios (usuario lo pospuso para probar primero)
- [ ] **Direcciones físicas** — calle/número en footer y FAQ (cuando el cliente las proporcione)
- [ ] **Horarios de atención** — en FAQ o sección ubicaciones
- [ ] **Testimonios reales** — 2–3 quotes de clientes/Instagram

### Media — rendimiento y SEO

- [ ] **Subset Remix Icon** — solo iconos usados (~12)
- [ ] **Critical CSS inline** — above-the-fold del hero
- [ ] **Self-host fonts** — eliminar request a Google Fonts
- [ ] **Analytics** — eventos `add_to_bag`, `open_bag`, `whatsapp_checkout` (GA4 / Meta Pixel)

### Media — catálogo e imágenes

- [ ] **Imágenes por `article.id`** — columna o tabla en BD en lugar de match por nombre
- [ ] **WebP/AVIF** — cuando el catálogo fotográfico esté cerrado
- [ ] **Re-colapsar catálogo** al cambiar categoría (opcional; hoy permanece expandido tras «mostrar más»)

### Baja — pulido y deploy

- [ ] Animaciones scroll suaves (con `prefers-reduced-motion`)
- [ ] Variante headline A/B: *«Pan gourmet que se come con los ojos primero»*
- [ ] Mapa embebido (Google Maps iframe) en `#ubicaciones`
- [ ] Revisar flujo `/entrar` para visitantes de la landing
- [ ] Deploy producción + dominio final
- [ ] Merge `feat/landing-srpan` → `main`

---

## Posibles actualizaciones futuras

| Área | Idea |
|---|---|
| **Hero** | Rotar foto de fondo por temporada o promoción |
| **PWA** | Solo si se justifica instalación móvil |
| **i18n** | No planeado — copy 100 % español |
| **CMS** | Editar copy desde admin en lugar de PHP |
| **Inventario en tiempo real** | Mostrar «agotado» según stock POS (requiere API) |

---

## Decisiones de diseño (no revertir sin consultar)

1. **Velocidad > decoración** en móvil — sin efectos pesados
2. **WhatsApp como canal principal** — no formulario de contacto
3. **Fotos reales** — placeholder solo cuando no hay imagen mapeada
4. **Dos sucursales siempre visibles** — Huixtla y Tapachula por igual
5. **Nav público** sin link a «Entrar» — separar landing de POS
6. **Bolsa sin backend** — pedido = mensaje WhatsApp, no venta en POS
7. **9 productos iniciales** — reducir scroll; expandir bajo demanda

---

## Breakpoints CSS

| Breakpoint | Comportamiento |
|---|---|
| `>991px` | Nav horizontal (pill), drawer lateral derecho |
| `≤991px` | Menú hamburguesa, grids a 1–2 columnas |
| `≤767px` | Drawer como bottom sheet; barra bolsa sin backdrop-filter |
| `≤479px` | Product grid a 1 columna |
| `≤359px` | Categorías y featured rail a 1 columna |

---

## Preview en Cloudflare Pages

| Campo | Valor |
|---|---|
| **Proyecto** | `srpan-landing-preview` |
| **URL rama actual** | https://feat-landing-srpan.srpan-landing-preview.pages.dev |
| **Config** | `wrangler.toml` |

La preview es un **snapshot estático** (HTML renderizado + `public/`). El catálogo queda congelado al momento del build; bolsa, WhatsApp, Maps e Instagram funcionan en cliente.

```bash
# 1. Build (requiere app local en https://panaderia.test/)
./scripts/build-cloudflare-preview.sh

# 2. Deploy con wrangler
wrangler pages deploy dist \
  --project-name=srpan-landing-preview \
  --branch=feat/landing-srpan \
  --commit-dirty=true
```

---

## Comandos útiles

```bash
# Landing local
# http://panaderia.test/

# Archivos principales del feature
git diff main...feat/landing-srpan -- \
  app/Views/landing.php \
  app/Controllers/Home.php \
  public/assets/css/srpan-landing.css \
  public/assets/js/srpan-landing.js \
  public/assets/js/srpan-cart.js
```

---

## Notas para el próximo agente / sesión

1. **Leer este archivo** antes de tocar la landing.
2. La bolsa vive en `srpan-cart.js`; el menú en `srpan-landing.js` — no mezclar responsabilidades.
3. Cualquier elemento con `[hidden]` necesita `display: none !important` si tiene `display: grid/flex` en su clase.
4. Probar siempre: bolsa vacía / con items, recarga (localStorage), filtro + «mostrar más», checkout WhatsApp con sucursal.
5. Probar en **≤375px** (iPhone) y **≤991px** (menú hamburguesa).
6. Imágenes del cliente en `~/Desktop/inspiration/images/` → sincronizar a `public/assets/img/srpan/products/`.
7. No reintroducir `core.css` en la landing sin necesidad real.

---

## Historial de sesiones

| Fecha | Trabajo realizado |
|---|---|
| Jun 2026 | Landing base: hero, copy, ubicaciones, nav móvil, galería, FAQ |
| 1 jul 2026 | Bolsa de pan WhatsApp: catálogo completo, drawer, sticky, filtro categorías, OG, Schema.org |
| 1 jul 2026 | Fix drawer «vacío» con productos (CSS `[hidden]`) |
| 1 jul 2026 | UX catálogo: 9 productos default + «mostrar más» |

---

*Documento vivo del feature `feat/landing-srpan` — Sr. Pan / sistematlan.*