/* ============================================================
   SMACHIL · experiencia.css
   Capa de experiencia visual sobre app.css
   ------------------------------------------------------------
   QUÉ ES ESTO
   Este archivo NO reemplaza a app.css. Se carga DESPUÉS y lo
   corrige por encima. app.css sigue siendo el esqueleto: acá
   sólo van las decisiones de dirección de arte que alinean la
   carta con el Brandbook Smachil v1.0.

   ORDEN OBLIGATORIO EN index.html:
     1. css/app.css        (esqueleto heredado)
     2. css/estados.css    (si existe; si no, este archivo cubre)
     3. css/experiencia.css  ← este

   REGLA DE ORO: proporción 70% negro · 25% amarillo · 5% blanco.
   El Smash Red #E63946 es SÓLO acento de alerta. Nunca un bloque.

   Autor: dirección de arte · sobre brandbook v1.0
   ============================================================ */


/* ============================================================
   01 · TOKENS OFICIALES DEL BRANDBOOK
   Copiados tal cual de 06-PLANTILLAS/tokens.css.
   Esta es la única fuente de verdad del color y la tipografía.
   ============================================================ */
:root {
  /* --- COLOR · primarios --- */
  --y:           #F5C518;           /* Smachil Yellow · protagonista */
  --y-deep:      #D4A800;           /* sombras del amarillo */
  --y-soft:      #FFE066;           /* highlights */
  --y-glow:      rgba(245,197,24,.18);
  --y-line:      rgba(245,197,24,.32);

  --bg:          #080808;           /* Deep Black · 70% del sistema */
  --ink:         #111111;           /* cards primarias */
  --char:        #1a1a1a;           /* cards secundarias */

  --white:       #FFFFFF;
  --off:         #B8B8B8;           /* texto secundario */
  --dim:         #6a6a6a;           /* SÓLO íconos, líneas, no-texto */

  --line:        rgba(255,255,255,.07);
  --line-2:      rgba(255,255,255,.12);

  --red:         #E63946;           /* Smash Red · SÓLO acento alerta */
  --whatsapp:    #25D366;

  /* --- TIPOGRAFÍA OFICIAL --- */
  --f-display:   'Anton', Impact, sans-serif;
  --f-cond:      'Barlow Condensed', sans-serif;
  --f-body:      'Barlow', sans-serif;

  /* --- RADIUS OFICIAL --- */
  --r-lg:        22px;
  --r-md:        14px;
  --r-sm:        8px;

  /* --- TRANSICIONES OFICIALES --- */
  --t:           .28s cubic-bezier(.4,0,.2,1);
  --t-slow:      .6s  cubic-bezier(.4,0,.2,1);


  /* ==========================================================
     ENMIENDA AL BRANDBOOK · accesibilidad
     --dim (#6a6a6a) sobre --bg da 3.70:1 de contraste.
     WCAG AA exige 4.5:1 para texto. Falla.
     Se crea --dim-txt (#8A8A8A → 5.79:1) exclusivamente para
     TEXTO. --dim se conserva para líneas e íconos, donde el
     mínimo es 3:1 y sí cumple.
     ========================================================== */
  --dim-txt:     #8A8A8A;


  /* ==========================================================
     CURVAS Y TIEMPOS DE INTERACCIÓN
     Asimétricas a propósito: lo que entra frena suave (se siente
     físico), lo que sale se va rápido (no hace esperar).
     ========================================================== */
  --ease-entra:  cubic-bezier(.16,1,.3,1);    /* desacelera fuerte */
  --ease-sale:   cubic-bezier(.3,0,.8,.15);   /* acelera y corta */
  --ease-std:    cubic-bezier(.4,0,.2,1);
  --ms-tap:      90ms;    /* el dedo baja */
  --ms-suelta:   260ms;   /* el dedo sube */
  --ms-sheet:    420ms;   /* la hoja modal sube */
  --ms-cierre:   280ms;   /* la hoja modal baja */


  /* ==========================================================
     EL PLATO DE LUZ
     Las fotos de producto son packshots sobre FONDO BLANCO.
     Puestas directo sobre negro dejan una lámina blanca gigante
     que rompe el 70/25/5. Solución: un foco de luz amarillo al
     que la foto se funde con multiply. El blanco desaparece y
     queda la hamburguesa flotando sobre luz cálida, que es
     exactamente la dirección de foto del brandbook.
     ========================================================== */
  --plato: radial-gradient(ellipse 78% 66% at 50% 44%,
             #F5C518 0%,
             #E9B713 42%,
             #9C7500 76%,
             #2A2000 100%);


  /* ==========================================================
     PUENTE · variables viejas de app.css → tokens oficiales
     app.css declara estas variables en su propio :root. Como
     experiencia.css se carga después y tiene la misma
     especificidad, estas ganan. Nada se rompe: todas las reglas
     de app.css siguen funcionando, sólo que ahora apuntan al
     brandbook.
     ========================================================== */
  --brand-yellow:      var(--y);
  --brand-yellow-dark: var(--y-deep);
  --brand-yellow-glow: var(--y-glow);
  --bg-deep:           var(--bg);
  --bg-card:           var(--ink);
  --bg-card2:          var(--char);
  --bg-modal:          #0E0E0E;
  --text-white:        var(--white);
  --text-off:          var(--off);
  --text-dim:          var(--dim-txt);   /* ← subido por contraste AA */
  --border:            var(--line);
  --border-yellow:     var(--y-line);
  --radius:            var(--r-lg);
  --radius-sm:         var(--r-sm);
  --transition:        var(--t);

  /* EL CAMBIO DE MARCA: Bebas Neue → Anton.
     app.css pedía 'Bebas Neue', que ni siquiera está cargada en
     index.html (el <link> trae Anton). Resultado real hoy: los
     titulares caen a sans-serif del sistema. Esta línea arregla
     la desviación y el bug al mismo tiempo. */
  --font-display:      var(--f-display);
  --font-body:         var(--f-body);
  --font-cond:         var(--f-cond);
}


/* ============================================================
   02 · TIPOGRAFÍA · recalibrado para Anton
   ------------------------------------------------------------
   Anton no es un reemplazo 1:1 de Bebas Neue:
     · pesa casi el doble de trazo
     · es ~15% más ancha por glifo
     · tiene la altura de mayúscula más alta
   Si se deja la misma escala, los titulares se desbordan en
   móvil y el amarillo se dispara sobre el 25%. Por eso cada
   tamaño baja ~12% y el letter-spacing pasa de +2px a 0.
   Regla del brandbook: Anton SIEMPRE en mayúsculas, con
   line-height entre 0.85 y 0.95.
   ============================================================ */
.hero-logo,
.section-title,
.card-name,
.fries-name,
.modal-name,
.cart-title,
.cta-title,
.footer-logo,
.drinks-price-big,
.total-amount,
.cart-total-amount {
  font-family: var(--f-display);
  font-weight: 400;                 /* Anton sólo tiene Regular */
  text-transform: uppercase;
  letter-spacing: 0;                /* Anton ya viene ajustada */
  font-synthesis: none;             /* nada de negritas falsas */
}

/* H1 Hero · escala oficial adaptada a una carta (no a un afiche) */
.hero-logo   { font-size: clamp(64px, 19vw, 118px); line-height: .86; }
/* H2 Section */
.section-title { font-size: clamp(36px, 10.5vw, 72px); line-height: .92; }
/* H3 y bajadas */
.modal-name  { font-size: clamp(34px, 9.5vw, 52px);  line-height: .9;  }
.cta-title   { font-size: clamp(32px, 9vw, 50px);    line-height: .92; }
.card-name   { font-size: clamp(21px, 5.6vw, 27px);  line-height: .95; }
.product-card:not(.featured) .card-name { font-size: clamp(19px, 5vw, 23px); }
.fries-name  { font-size: 20px; line-height: .95; }
.cart-title  { font-size: 28px; }
.footer-logo { font-size: 32px; }
.drinks-price-big { font-size: clamp(46px, 14vw, 72px); line-height: .9; }

/* Cifras: tabular para que el total no salte al cambiar de número.
   Es el detalle que separa una carta hecha de una improvisada. */
.total-amount,
.cart-total-amount,
.card-price,
.fries-price,
.modal-price-base,
.qty-display,
.cart-qty {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Etiquetas y UI compacta · Barlow Condensed en mayúsculas con
   tracking alto, tal como manda el brandbook. */
.brand-badge,
.hero-claim,
.section-sub,
.cta-label,
.tab,
.card-cta,
.extras-title,
.checkout-label,
.quantity-label,
.total-label,
.cart-total-label {
  font-family: var(--f-cond);
  text-transform: uppercase;
}

/* Cuerpo legible: el brandbook pide 16-17px con line-height 1.55.
   app.css tenía descripciones en 12px, que en un celular a la
   distancia normal de lectura es simplemente chico. */
.card-desc      { font-size: 13.5px; line-height: 1.5; color: var(--dim-txt); }
.fries-desc     { font-size: 13px;   line-height: 1.45; color: var(--dim-txt); }
.hero-tagline   { font-size: 15.5px; line-height: 1.55; color: var(--off); }
.modal-ingredients { font-size: 15px; line-height: 1.6; color: var(--off); }
.cta-sub        { font-size: 14.5px; line-height: 1.55; color: var(--dim-txt); }
.footer-info    { color: var(--dim-txt); }


/* ============================================================
   03 · BASE · selección, foco, tacto
   ============================================================ */
::selection { background: var(--y); color: #000; }

/* El resaltado azul de Android/iOS al tocar arruina cualquier
   diseño. Se apaga y se reemplaza por estados propios (bloque 11). */
a, button, .product-card, .fries-card, .drink-card, .tab {
  -webkit-tap-highlight-color: transparent;
}

/* app.css no tenía NINGÚN estado de foco. Quien navega con
   teclado o con switch no veía dónde estaba parado. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
[tabindex]:focus-visible,
.product-card:focus-visible,
.fries-card:focus-visible,
.drink-card:focus-visible {
  outline: 2px solid var(--y);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* Los emoji en la navegación son el delator número uno de una
   carta amateur. Shake Shack y Honest Burgers no ponen 🍔 en las
   pestañas. Una línea, fácil de revertir si Lukas los quiere. */
.tab-icon { display: none; }


/* ============================================================
   04 · EL PLATO DE LUZ · fotos de producto
   ------------------------------------------------------------
   Todas las fotos (chill-simple, pepon, kuyen, ruka, okla, smok,
   papas, bebidas) son 4:5 verticales sobre BLANCO PURO.
   `isolation:isolate` crea el contexto de mezcla para que
   multiply afecte sólo al plato y no al fondo de la página.
   ============================================================ */
.card-img-wrap,
.modal-img-wrap,
.fries-img-wrap,
.hero-img-wrap,
.drink-img-wrap {
  isolation: isolate;
  background: var(--plato);
}

.card-img,
.modal-img,
.fries-img,
.drink-img,
.hero-img {
  mix-blend-mode: multiply;
  background: transparent;
}

/* Escotilla de emergencia: si alguna foto futura NO viene sobre
   blanco (fondo gris, madera, plancha), se le pone esta clase en
   el <img> y queda plana sobre negro, sin mezcla. */
.foto-plana {
  mix-blend-mode: normal !important;
}
.foto-plana-wrap {
  background: linear-gradient(135deg, #1a1400, #080600) !important;
}

/* Las bebidas son latas con etiquetas de colores corporativos
   ajenos (Coca-Cola roja, Crush naranja). Multiply sobre amarillo
   las ensucia y además mete rojo al sistema. Van planas. */
.drink-img-wrap { background: #141414; border-radius: var(--r-sm); }
.drink-img      { mix-blend-mode: normal; }

/* Proporción de tarjeta unificada. Una grilla con dos relaciones
   de aspecto distintas se lee desordenada. Todo 4:3, salvo la
   destacada, que gana jerarquía por tamaño y no por recorte. */
.product-card:not(.featured) .card-img-wrap { aspect-ratio: 4/3; }
.product-card.featured .card-img-wrap       { aspect-ratio: 16/11; }

/* Sombra de contacto: la hamburguesa deja de flotar y se apoya.
   Se monta sobre .card-glow, el div que app.js ya pinta dentro de
   cada tarjeta, para no ocupar un pseudo-elemento que necesitan
   los estados de producto (bloque 08). */
.card-glow {
  height: 62%;
  background:
    radial-gradient(ellipse 58% 22% at 50% 88%, rgba(0,0,0,.5) 0%, transparent 72%),
    linear-gradient(0deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.18) 46%, transparent 100%);
  z-index: 1;
}

/* La misma sombra de apoyo en la foto grande del modal. */
.modal-img-wrap::before {
  content: '';
  position: absolute;
  left: 16%; right: 16%; bottom: 26%;
  height: 12%;
  background: radial-gradient(ellipse at center, rgba(0,0,0,.45) 0%, transparent 72%);
  filter: blur(7px);
  pointer-events: none;
  z-index: 1;
}


/* ============================================================
   05 · HERO · menos escalones antes del primer producto
   ------------------------------------------------------------
   Problema medido: en un teléfono de 667px de alto había que
   hacer dos scrolls completos para ver la primera hamburguesa.
   El hero cuesta dinero. Se comprime sin perder impacto.
   ============================================================ */
#hero {
  min-height: 86svh;
  padding: 44px 20px 28px;
  justify-content: flex-start;
  padding-top: max(44px, env(safe-area-inset-top));
}

.brand-badge   { margin-bottom: 14px; letter-spacing: 2px; }
.hero-claim    { margin-bottom: 18px; color: var(--off); letter-spacing: 2.5px; }
.hero-img-wrap { margin-bottom: 26px; border-radius: var(--r-lg); overflow: visible; }
.hero-tagline  { margin-bottom: 24px; }

/* La banda checker es la firma del letrero físico. En app.css
   estaba al 90% de opacidad y a todo el ancho: demasiado peso
   amarillo arriba. Se adelgaza y se degrada hacia los bordes,
   igual que el vinilo del local. */
.hero-checker-top,
.hero-checker-bottom {
  height: 12px;
  opacity: 1;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
}

/* El foto-plato del hero necesita su propio recorte redondeado
   porque el pudú se apoya en el borde (bloque 10). */
.hero-img {
  border-radius: var(--r-lg);
  aspect-ratio: 4/3;
}


/* ============================================================
   06 · TABS · barra pegajosa que se siente sólida
   ============================================================ */
.tabs-wrap {
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(8,8,8,.97) 76%, rgba(8,8,8,.55));
}

.tab {
  position: relative;
  min-height: 44px;              /* área táctil mínima real */
  padding: 0 20px;
  border-radius: 100px;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: 1.6px;
  background: transparent;
  border-color: var(--line-2);
  transition: color 220ms var(--ease-std),
              background-color 220ms var(--ease-std),
              border-color 220ms var(--ease-std);
}

/* El subrayado que crece desde el centro. No se puede deslizar
   la píldora sin JS, así que el movimiento se resuelve acá:
   una línea que se abre en 300ms al activarse. */
.tab::after {
  content: '';
  position: absolute;
  left: 20px; right: 20px; bottom: 6px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 300ms var(--ease-entra);
}
.tab.active::after { transform: scaleX(1); }
.tab.active { box-shadow: 0 4px 22px rgba(245,197,24,.28); }


/* ============================================================
   07 · TARJETAS · la unidad que más se mira
   ============================================================ */
.product-card,
.fries-card,
.drink-card {
  border-radius: var(--r-lg);
  border-color: var(--line);
  background: var(--ink);
  /* dos transiciones distintas: la de sombra puede ser lenta,
     la de transform tiene que ser inmediata al tacto */
  transition: transform var(--ms-suelta) var(--ease-entra),
              border-color 240ms var(--ease-std),
              box-shadow 320ms var(--ease-std),
              opacity 240ms var(--ease-std);
}

/* El precio es la segunda cosa que mira el cliente, después de
   la foto. Sube de tamaño y se le da aire. */
.card-price {
  font-family: var(--f-cond);
  font-weight: 900;
  font-size: clamp(20px, 5.4vw, 25px);
  letter-spacing: .3px;
}
.card-footer { padding-top: 12px; }
.card-body   { padding: 15px 15px 17px; gap: 7px; }

/* "Incluye papas" es un argumento de venta, no una nota al pie.
   Se convierte en una pastilla contenida. */
.includes-fries {
  align-self: flex-start;
  padding: 3px 9px;
  border-radius: 6px;
  background: rgba(245,197,24,.09);
  border: 1px solid rgba(245,197,24,.18);
  font-family: var(--f-cond);
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}

/* La ficha de papas gana una barra amarilla permanente y sutil
   a la izquierda: ancla la lectura en una lista horizontal. */
.fries-card::before { opacity: .35; width: 2px; }
.fries-card:hover::before { opacity: 1; }

/* Contextos de posicionamiento que app.css no declaró y que los
   estados (badges, tramas, filo rojo) necesitan para anclar. */
.fries-img-wrap,
.drink-img-wrap,
.drink-card,
.fries-card,
.product-card { position: relative; }


/* ============================================================
   08 · SISTEMA DE ESTADOS DE PRODUCTO
   ------------------------------------------------------------
   Contrato de clases que espera estados-ui.js:

     <article class="product-card producto--agotado" data-estado="agotado">
     <article class="product-card producto--pocas"   data-estado="pocas">
     <article class="product-card producto--nuevo">

   Y dentro de .card-img-wrap:
     <span class="badge-estado badge-estado--agotado">Se acabó hoy</span>
     <span class="badge-estado badge-estado--pocas">Últimas unidades</span>
     <span class="badge-estado badge-estado--nuevo">Nuevo</span>
     <span class="badge-estado badge-estado--favorita">Favorita</span>

   Las mismas clases sirven en .product-card, .fries-card y
   .drink-card.
   ============================================================ */

/* --- La etiqueta base ---------------------------------------
   Arriba a la IZQUIERDA, no a la derecha: en español se lee de
   izquierda a derecha y la esquina superior izquierda es lo
   primero que barre el ojo. Rectangular con esquina mínima:
   una píldora redonda sobre una foto redonda es ruido.
   backdrop-filter para que sobreviva sobre cualquier foto. */
.badge-estado {
  position: absolute;
  top: 10px; left: 10px;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px;
  border-radius: 5px;
  font-family: var(--f-cond);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  backdrop-filter: blur(10px) saturate(120%);
  -webkit-backdrop-filter: blur(10px) saturate(120%);
  border: 1px solid transparent;
}

/* FAVORITA · amarillo sólido. Es la única que grita, porque es
   la única que quiere vender. */
.badge-estado--favorita {
  background: var(--y);
  color: #000;
  box-shadow: 0 3px 14px rgba(245,197,24,.3);
}

/* NUEVO · Smash Red, pero como filo y letra, jamás como bloque.
   Pastilla negra + borde rojo 1.5px = el rojo ocupa unos pocos
   cientos de píxeles y el 5% del brandbook queda intacto.
   (app.css usaba #FF4444, que no es un color de la marca.) */
.badge-estado--nuevo {
  background: rgba(8,8,8,.72);
  border-color: var(--red);
  color: #FF6B76;                 /* el rojo puro sobre negro no llega a AA */
  box-shadow: 0 0 0 1px rgba(230,57,70,.18), 0 3px 14px rgba(230,57,70,.22);
}

/* ÚLTIMAS UNIDADES · urgencia sin alarma. No es una emergencia,
   es una oportunidad: por eso es amarillo, no rojo. */
.badge-estado--pocas {
  background: rgba(8,8,8,.72);
  border-color: var(--y-line);
  color: var(--y);
}
.badge-estado--pocas::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--y);
  animation: latidoPocas 2.4s var(--ease-std) infinite;
}
@keyframes latidoPocas {
  0%, 100% { opacity: 1;  box-shadow: 0 0 0 0 rgba(245,197,24,.55); }
  55%      { opacity: .5; box-shadow: 0 0 0 5px rgba(245,197,24,0); }
}

/* AGOTADO · gris carbón y letra apagada. Nada de rojo: quedarse
   sin stock no es un error del cliente, no hay que retarlo. */
.badge-estado--agotado {
  background: rgba(20,20,20,.86);
  border-color: var(--line-2);
  color: var(--off);
}


/* --- ESTADO: ÚLTIMAS UNIDADES -------------------------------
   El borde de la tarjeta respira. La tarjeta entera no se mueve:
   si todo late, nada destaca. */
.producto--pocas {
  border-color: var(--y-line);
  animation: bordePocas 2.4s var(--ease-std) infinite;
}
@keyframes bordePocas {
  0%, 100% { box-shadow: 0 0 0 0 rgba(245,197,24,0); }
  55%      { box-shadow: 0 0 0 3px rgba(245,197,24,.09); }
}


/* --- ESTADO: AGOTADO ----------------------------------------
   Criterio: NO se esconde el producto. Una carta que encoge se
   ve más pobre, y el cliente igual quiere saber qué existe para
   volver mañana. Lo que se hace es sacarle el apetito a la
   tarjeta: la foto pierde color, el precio pierde el amarillo
   (el amarillo significa "esto lo puedes pedir"), y encima se
   cruza una trama diagonal finísima, no un cartel pegado. */
.producto--agotado {
  opacity: .62;
  border-color: var(--line);
  cursor: default;
  filter: saturate(.25);
}
.producto--agotado:hover {
  transform: none;
  box-shadow: none;
  border-color: var(--line);
}

/* La trama diagonal: 1px cada 9px. Se ve como textura, no como
   tachón. Va sobre la foto, nunca sobre el texto: el nombre y el
   precio siguen perfectamente legibles. */
.producto--agotado .card-img-wrap::before,
.producto--agotado .fries-img-wrap::before,
.producto--agotado .drink-img-wrap::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    -45deg,
    rgba(255,255,255,.055) 0px, rgba(255,255,255,.055) 1px,
    transparent 1px, transparent 9px
  );
}

/* El precio deja de ser una invitación. */
.producto--agotado .card-price,
.producto--agotado .fries-price {
  color: var(--dim-txt);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(255,255,255,.22);
}

/* La llamada a la acción desaparece y no se puede tocar. */
.producto--agotado .card-cta,
.producto--agotado .add-direct-btn {
  opacity: 0;
  pointer-events: none;
}

/* La foto se apaga del todo. */
.producto--agotado .card-img,
.producto--agotado .fries-img,
.producto--agotado .drink-img {
  filter: grayscale(.85) brightness(.78);
}

/* El único rojo permitido en el estado agotado: un filo de 2px
   en el borde izquierdo de la tarjeta. Acento, no bloque. */
.producto--agotado::after {
  content: '';
  position: absolute;
  left: 0; top: 18%; bottom: 18%;
  width: 2px;
  border-radius: 0 2px 2px 0;
  background: var(--red);
  opacity: .75;
}


/* --- ESTADO: NUEVO ------------------------------------------
   Sin peso extra en la tarjeta. Sólo la etiqueta y un
   destello diagonal que cruza la foto una vez al entrar. */
.producto--nuevo .card-img-wrap::after {
  content: '';
  position: absolute;
  inset: -40% -10%;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 42%,
    rgba(255,255,255,.16) 50%,
    transparent 58%);
  transform: translateX(-120%);
  animation: destelloNuevo 2.6s var(--ease-std) .6s 2;
}
@keyframes destelloNuevo {
  0%   { transform: translateX(-120%); }
  38%  { transform: translateX(120%); }
  100% { transform: translateX(120%); }
}


/* --- Compatibilidad con los badges viejos de app.js ----------
   Mientras estados-ui.js no esté escrito, app.js sigue pintando
   .badge y .badge.new. Se les da el mismo lenguaje para que la
   carta no se vea mezclada en la transición. */
.badge {
  top: 10px; left: 10px; right: auto;
  border-radius: 5px;
  font-family: var(--f-cond);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 1.6px;
  padding: 5px 10px;
}
.badge.new,
.modal-badge.new-badge {
  background: rgba(8,8,8,.72);
  border: 1px solid var(--red);
  color: #FF6B76;
}

/* Los tres rojos piratas de app.css (#FF4444 ×2, #ff3b30) se
   unifican en el Smash Red oficial. */
.cart-badge        { background: var(--red); }
.removable-cb      { accent-color: var(--red); }
.cart-item-remove  { background: rgba(230,57,70,.10); border-color: rgba(230,57,70,.32); color: #FF6B76; }
.cart-item-remove:hover { background: rgba(230,57,70,.20); border-color: var(--red); }
/* El título "Quitar ingredientes" trae el color en atributo style
   dentro del HTML; sólo se puede corregir con !important. */
#removables-section .extras-title { color: #FF6B76 !important; }


/* ============================================================
   09 · LOCAL CERRADO · el momento de mayor rebote
   ------------------------------------------------------------
   El cliente llega con hambre y no puede pedir. Un rectangulo
   rojo que diga CERRADO lo manda a la competencia. Se resuelve
   con el pudu durmiendo y con el dato que de verdad importa:
   a que hora abrimos.

   El componente lo pinta estados-ui.js con la clase
   .smachil-cerrado. Todo su tratamiento visual vive en el
   bloque 15.3 de este archivo, para no duplicar reglas.
   Aca queda solo el ronquido, que ese bloque reutiliza.
   ============================================================ */
@keyframes ronquido {
  0%   { opacity: 0;  transform: translate(0,0)      scale(.6)  rotate(0deg); }
  28%  { opacity: .9; }
  100% { opacity: 0;  transform: translate(10px,-18px) scale(1.15) rotate(14deg); }
}


/* ============================================================
   10 · LA MASCOTA · siete apariciones, cero markup nuevo
   ------------------------------------------------------------
   Todas se resuelven con pseudo-elementos sobre clases que ya
   existen. Se usa smachil-isotipo.png y no smachil-mascota-flat.png
   porque el flat tiene ~15% de lienzo vacío abajo y a la derecha,
   y eso hace imposible calzarlo a un borde con precisión.
   Regla del brandbook respetada: proporción original intacta
   (siempre background-size: contain).
   ============================================================ */

/* --- 10.1 · El pudú se recuesta en el plato del hero ---------
   La pose del personaje es "recostado". Un personaje recostado
   necesita un borde donde apoyarse o queda flotando. El borde
   inferior del plato de luz es ese apoyo. Además: presenta la
   mascota en los primeros 800ms, junto al producto, sin robarle
   protagonismo. */
.hero-img-wrap::after {
  content: '';
  position: absolute;
  bottom: -16px;
  left: -10px;
  width: clamp(96px, 27vw, 132px);
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  filter: drop-shadow(0 10px 22px rgba(0,0,0,.7));
  z-index: 3;
  pointer-events: none;
  /* flota desfasado de la hamburguesa (5s en app.css) para que
     no se muevan en bloque, que es lo que delata una animación */
  animation: flotaPudu 6.4s ease-in-out infinite;
}
@keyframes flotaPudu {
  0%, 100% { transform: translateY(0)    rotate(0deg); }
  50%      { transform: translateY(-7px) rotate(-1.5deg); }
}

/* --- 10.2 · El pudú se echa sobre la banda checker -----------
   El divisor entre la carta y el cierre era una banda decorativa
   sin función. Convertido en respiro con firma: marca el final
   del menú y el comienzo del cierre de venta. */
.checker-divider {
  position: relative;
  height: 12px;
  margin: 46px 0 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 22%, #000 78%, transparent);
}
.checker-divider::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 84px;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center bottom/contain no-repeat;
  filter: drop-shadow(0 6px 14px rgba(0,0,0,.8));
}

/* --- 10.3 · El pudú gigante del cierre -----------------------
   Descartada la marca de agua a página completa (pelea con las
   fotos y dispara el amarillo sobre el 25%). Sobrevive acotada
   a un solo bloque: una silueta enorme sangrando por el borde
   derecho del recuadro final. Da peso al cierre sin sumar otra
   fotografía. */
.cta-box { position: relative; overflow: hidden; }
.cta-box::after {
  content: '';
  position: absolute;
  right: -14%;
  bottom: -18%;
  width: 62%;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  opacity: .07;
  pointer-events: none;
  transform: rotate(-6deg);
}
.cta-box > * { position: relative; z-index: 1; }

/* --- 10.4 · El pudú del carrito vacío ------------------------
   El carrito vacío es la única pantalla de la carta que no tiene
   nada que decir. Es donde la mascota más rinde: convierte un
   callejón sin salida en un chiste seco y en un empujón de
   vuelta a la carta. */
.cart-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 34px 20px 20px;
  font-family: var(--f-cond);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--dim-txt);
}
.cart-empty::before {
  content: '';
  width: 128px;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  opacity: .38;
  animation: esperaPudu 4.8s ease-in-out infinite;
}
@keyframes esperaPudu {
  0%, 88%, 100% { transform: rotate(0deg); }
  92%           { transform: rotate(-3deg); }
  96%           { transform: rotate(2deg); }
}

/* --- 10.5 · El pudú como cargador / foto caída ---------------
   .img-placeholder aparece cuando una foto no carga o va lenta.
   Hoy muestra un emoji 🍔. Un emoji del sistema en una carta
   premium es exactamente lo contrario de premium. */
.img-placeholder { background: var(--plato); position: relative; }
.img-placeholder span { display: none; }
.img-placeholder::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 46%;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  opacity: .34;
  animation: respiraPudu 1.6s ease-in-out infinite;
}
@keyframes respiraPudu {
  0%, 100% { opacity: .22; transform: scale(.97); }
  50%      { opacity: .46; transform: scale(1); }
}

/* --- 10.6 · El sello del pudú en la foto del modal -----------
   El brandbook manda la mascota al 8% en la esquina inferior
   derecha de cada pieza gráfica. El modal es la pieza más
   parecida a un post de Instagram que tiene la carta: se aplica
   literalmente la misma regla. Coherencia entre canales.
   Va colgado de .modal-body y no de .modal-img-wrap porque el
   degradado ::after de app.css lo taparía. */
.modal-body { position: relative; }
.modal-body::before {
  content: '';
  position: absolute;
  top: -46px;
  right: 16px;
  width: 58px;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  filter: drop-shadow(0 6px 16px rgba(0,0,0,.8));
  z-index: 3;
  pointer-events: none;
}

/* --- 10.7 · El pudú que firma el footer ----------------------
   Lo último que ve el cliente es la cara de la marca, igual que
   al salir del local se ve el letrero. */
footer { position: relative; padding-top: 96px; }
footer::before {
  content: '';
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  width: 118px;
  aspect-ratio: 1375/1246;
  background: url('../assets/brand/smachil-isotipo.png') center/contain no-repeat;
  opacity: .9;
}


/* ============================================================
   11 · MICRO-INTERACCIONES
   ------------------------------------------------------------
   Principio: lo que baja es rápido (90ms, el dedo ya llegó), lo
   que sube frena suave (260ms, la mano confía). Todo lo que
   pasa de 450ms se siente lento en un celular.
   ============================================================ */

/* --- Tocar una tarjeta --------------------------------------
   La tarjeta se hunde, NO se agranda la foto. El zoom de imagen
   al tocar en pantalla táctil se lee como un error de render;
   en desktop con mouse sí funciona y se conserva. */
.product-card:active,
.fries-card:active,
.drink-card:active {
  transform: scale(.975);
  transition-duration: var(--ms-tap);
  transition-timing-function: var(--ease-sale);
}
@media (hover: none) {
  .product-card:active .card-img { transform: none; }
}

/* Hover sólo donde hay mouse de verdad. app.css lo apagaba con
   un breakpoint de ancho, que falla en tablets y en celulares
   apaisados. */
@media (hover: hover) and (pointer: fine) {
  .product-card:hover { transform: translateY(-6px); }
  .product-card:hover .card-img { transform: scale(1.05); }
}
@media (hover: none) {
  .product-card:hover,
  .fries-card:hover,
  .drink-card:hover { transform: none; box-shadow: none; }
}

/* --- Botones: presión y rebote ------------------------------ */
.btn-primary, .btn-wapp, .btn-wapp-big,
.btn-order, .btn-checkout, .add-direct-btn, .order-type-btn {
  transition: transform var(--ms-suelta) var(--ease-entra),
              background-color 240ms var(--ease-std),
              border-color 240ms var(--ease-std),
              box-shadow 320ms var(--ease-std),
              color 240ms var(--ease-std);
}
.btn-primary:active, .btn-wapp:active, .btn-wapp-big:active,
.btn-order:active, .btn-checkout:active, .add-direct-btn:active {
  transform: scale(.965);
  transition-duration: var(--ms-tap);
  transition-timing-function: var(--ease-sale);
}

/* --- Agregar al pedido: el acuse de recibo ------------------
   El momento más importante de toda la carta. Si el cliente no
   ve que el producto entró, lo agrega dos veces o se va.
   JS debe añadir la clase .fab-cart--recibe al botón del
   carrito y quitarla a los 700ms. */
.fab-cart { position: fixed; }
.fab-cart::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--y);
  opacity: 0;
  pointer-events: none;
}
.fab-cart--recibe::after {
  animation: ondaRecibo 480ms var(--ease-entra) forwards;
}
@keyframes ondaRecibo {
  0%   { opacity: .95; transform: scale(1); }
  100% { opacity: 0;   transform: scale(1.75); }
}
.fab-cart--recibe { animation: saltoRecibo 420ms var(--ease-entra); }
@keyframes saltoRecibo {
  0%   { transform: scale(1); }
  38%  { transform: scale(1.14); }
  68%  { transform: scale(.96); }
  100% { transform: scale(1); }
}

/* El número del carrito hace "pop" al cambiar. */
.cart-badge.active { animation: popContador 260ms var(--ease-entra); }
@keyframes popContador {
  0%   { transform: scale(.4); opacity: 0; }
  60%  { transform: scale(1.22); opacity: 1; }
  100% { transform: scale(1); }
}

/* --- El modal: hoja que sube ------------------------------- */
.modal-overlay {
  transition: opacity var(--ms-cierre) var(--ease-sale);
}
.modal-overlay.open { transition-duration: 240ms; transition-timing-function: linear; }
.modal-sheet {
  transition: transform var(--ms-cierre) var(--ease-sale);
  overscroll-behavior: contain;   /* que el scroll no se contagie al body */
}
.modal-overlay.open .modal-sheet {
  transition: transform var(--ms-sheet) var(--ease-entra);
}

/* El contenido entra escalonado: nombre, precio, ingredientes.
   40ms de diferencia entre cada uno. Menos, no se percibe;
   más, se siente lento. */
.modal-overlay.open .modal-name        { animation: subeContenido 380ms var(--ease-entra)  40ms both; }
.modal-overlay.open .modal-price-base  { animation: subeContenido 380ms var(--ease-entra)  80ms both; }
.modal-overlay.open .modal-ingredients { animation: subeContenido 380ms var(--ease-entra) 120ms both; }
@keyframes subeContenido {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- El carrito: cajón que entra --------------------------- */
.cart-drawer { overscroll-behavior: contain; transition: transform var(--ms-cierre) var(--ease-sale); }
.cart-overlay.open .cart-drawer { transition: transform var(--ms-sheet) var(--ease-entra); }

/* --- Scroll: los títulos de sección suben al entrar ---------
   Con animation-timeline nativo donde existe (Chrome/Edge, que
   es el 80% del tráfico móvil en Chile). Donde no existe, no
   pasa nada: el título se ve normal. Cero JS, cero librería. */
@supports (animation-timeline: view()) {
  .section-header {
    animation: entraSeccion linear both;
    animation-timeline: view();
    animation-range: entry 8% cover 26%;
  }
  @keyframes entraSeccion {
    from { opacity: 0; transform: translateY(22px); }
    to   { opacity: 1; transform: translateY(0); }
  }
}

/* --- Los +/- de extras y carrito --------------------------- */
.qty-btn:active, .cart-qty-btn:active {
  transform: scale(.88);
  transition-duration: 80ms;
}
.qty-btn, .cart-qty-btn {
  transition: transform 220ms var(--ease-entra),
              background-color 200ms var(--ease-std),
              color 200ms var(--ease-std);
}


/* ============================================================
   12 · MODAL Y CARRITO · afinado visual
   ============================================================ */
.modal-sheet {
  border-radius: 26px 26px 0 0;
  border-top: 1px solid var(--line-2);
}
.modal-handle { width: 44px; height: 5px; background: rgba(255,255,255,.22); }

/* La barra de total: es el único bloque amarillo sólido grande
   de toda la carta y por eso funciona. Se le da altura y se
   equilibra el peso tipográfico. */
.total-bar {
  border-radius: var(--r-md);
  padding: 15px 20px;
  box-shadow: 0 8px 34px rgba(245,197,24,.22);
}
.total-label  { color: rgba(0,0,0,.62); letter-spacing: 2px; }
.total-amount { font-size: 34px; }

.extras-section { border-radius: var(--r-md); background: var(--char); }
.quantity-selector { border-radius: var(--r-md); background: var(--char); }
.checkout-panel { border-radius: var(--r-md); }
.cart-item { border-radius: var(--r-md); }
.cart-item-img { border-radius: var(--r-sm); background: var(--plato); }


/* ============================================================
   13 · MÓVIL PRIMERO · pulgar, tacto, contraste
   ------------------------------------------------------------
   Referencia: 44×44 CSS px es el mínimo de Apple HIG; 48dp el de
   Material. app.css tenía controles de 24, 26 y 34px.
   ============================================================ */

/* Todo lo que se toca, mínimo 44px. El tamaño visual puede ser
   menor: se agranda el área con un pseudo-elemento invisible. */
.qty-btn,
.modal-close,
.cart-close {
  min-width: 44px;
  min-height: 44px;
}
.cart-qty-btn {
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  position: relative;
}
.cart-qty-btn::before,
.cart-item-remove::before {
  content: '';
  position: absolute;
  inset: -7px;                    /* área táctil real de 44px+ */
}
.cart-item-remove { position: absolute; width: 30px; height: 30px; }

/* Los enlaces del pie también son objetivos táctiles. */
.footer-info a {
  display: inline-block;
  padding: 6px 2px;
  color: var(--off);
}

/* iOS hace zoom automático en cualquier input de menos de 16px.
   Ese zoom descoloca el carrito entero y el cliente se pierde. */
.checkout-input {
  font-size: 16px;
  border-radius: var(--r-md);
  min-height: 48px;
}
.order-type-btn { min-height: 48px; border-radius: var(--r-md); }

/* Zona del pulgar: los dos botones flotantes viven abajo a la
   derecha, que es donde llega el pulgar derecho sin mover la
   mano. Se respeta la barra de gestos de iPhone y se deja aire
   para que no tapen la última tarjeta. */
.fab-wapp,
.fab-cart {
  bottom: calc(20px + env(safe-area-inset-bottom));
  width: 56px;
  height: 56px;
}
footer { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }

@media (max-width: 768px) {
  /* Una columna, tarjetas grandes: en el celular la foto vende. */
  .product-grid { gap: 16px; }
  .fries-grid   { gap: 12px; }

  /* El botón del carrito por encima del de WhatsApp, no al lado:
     dos círculos en la misma línea se tocan por error. */
  .fab-cart { right: 20px; bottom: calc(86px + env(safe-area-inset-bottom)); }
  .fab-wapp { right: 20px; }

  /* El cajón del carrito no debe tapar toda la pantalla: dejar
     ver un borde de la carta detrás le dice al cliente que puede
     volver con un toque. */
  .cart-drawer { height: 88svh; border-radius: 26px 26px 0 0; }

  .badge-estado { font-size: 10.5px; height: 23px; }
  .modal-body::before { width: 50px; top: -40px; right: 14px; }
  .hero-img-wrap::after { left: -4px; bottom: -12px; }
}

@media (max-width: 380px) {
  /* Teléfonos chicos (iPhone SE y gama baja, frecuentes en
     Castro): el titular no puede empujar el layout. */
  .hero-logo { font-size: 58px; }
  .checker-divider::after { width: 66px; }
}


/* ============================================================
   15 · RECONCILIACIÓN CON estados.css / estados-ui.js
   ------------------------------------------------------------
   El contrato real que emite estados-ui.js es:

     .producto--agotado / .producto--pocas / .producto--oculto
     .badge-estado.es-agotado  ·  .badge-estado.es-pocas
     #smachil-cerrado.smachil-cerrado  (dentro de #menu)
     body.local-cerrado  ·  body.con-banner
     .smachil-banner  ·  .smachil-aviso

   Coincide casi entero con lo diseñado acá. Este bloque hace de
   traductor y afina lo que queda distinto. Como experiencia.css
   se carga DESPUÉS de estados.css, estas reglas ganan.
   ============================================================ */

/* --- 15.1 · Alias de las etiquetas ---------------------------
   estados-ui.js escribe `.es-agotado` / `.es-pocas`; este archivo
   diseñó `.badge-estado--agotado` / `--pocas`. Se igualan para que
   sirvan las dos nomenclaturas y nadie tenga que tocar el JS. */
.badge-estado.es-agotado,
.badge-estado--agotado {
  background: rgba(20,20,20,.86);
  border: 1px solid var(--line-2);
  color: var(--off);
}

/* --- 15.2 · "Últimas unidades" vuelve al amarillo -------------
   estados.css pinta este estado con Smash Red de fondo, borde,
   letra y punto pulsante. Sobre tres o cuatro tarjetas a la vez
   eso deja de ser un acento y se vuelve un tercer color
   permanente, que es justo lo que prohíbe el brandbook v1.0
   ("Smash Red solo como acento — nunca tercer color permanente").

   Criterio: quedar poco NO es una alerta, es una oportunidad.
   Va en amarillo. El rojo queda guardado para lo que sí falla. */
.badge-estado.es-pocas,
.badge-estado--pocas {
  background: rgba(8,8,8,.72);
  border: 1px solid var(--y-line);
  color: var(--y);
}
.badge-estado.es-pocas::before,
.badge-estado--pocas::before {
  background: var(--y);
  box-shadow: 0 0 0 0 rgba(245,197,24,.55);
  animation: latidoPocas 2.4s var(--ease-std) infinite;
}

/* Geometría común: rectangular con radio 5px, no píldora.
   Una píldora redonda sobre una foto redonda es ruido. */
.badge-estado {
  border-radius: 5px;
  padding: 0 10px;
  height: 24px;
  font-size: 11px;
  font-weight: 900;
  top: 10px;
  left: 10px;
}

/* --- 15.3 · El aviso de local cerrado ------------------------
   estados-ui.js lo inserta dentro de #menu como ficha, no como
   barra superior. Buena decisión: no tapa el hero. Acá se le
   sube el nivel sin cambiar una línea de su HTML. */
.smachil-cerrado {
  position: relative;
  border-radius: var(--r-lg);
  border-color: var(--y-line);
  background: linear-gradient(180deg, #171717 0%, #101010 100%);
  box-shadow: 0 18px 50px rgba(0,0,0,.5);
  overflow: hidden;
  animation: apareceCerrado 520ms var(--ease-entra) both;
}
@keyframes apareceCerrado {
  from { opacity: 0; transform: translateY(-14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* CORRECCIÓN DE ASSET: smachil-mascota-flat.png tiene ~33% de
   lienzo vacío abajo. Puesto a 62px, el pudú se ve chico y
   descolgado hacia arriba dentro de su propia caja. Se agranda y
   se recorta el vacío con márgenes negativos. */
.smachil-cerrado .cerrado-pudu {
  width: 86px;
  margin: -6px -10px -20px -4px;
  filter: grayscale(1) brightness(.66);   /* está durmiendo: apagado, como el local */
}

/* El ronquido. Con un solo asset no hay pose de dormir: se
   construye con la "Z" que sube cada 3.2s. Los lentes de sol ya
   hacen de ojos cerrados, el dibujo trabaja a favor. */
.smachil-cerrado::before {
  content: 'Z';
  position: absolute;
  left: 78px;
  top: 14px;
  font-family: var(--f-display);
  font-size: 16px;
  color: var(--y);
  opacity: 0;
  pointer-events: none;
  animation: ronquido 3.2s var(--ease-std) infinite;
}

/* La jerarquía correcta del aviso: el dato útil es LA HORA, no
   la palabra "cerrados", que el cliente ya dedujo solo. */
.smachil-cerrado strong { line-height: .95; }
.smachil-cerrado span   { color: var(--off); }

@media (max-width: 520px) {
  .smachil-cerrado::before { left: 50%; top: 10px; }
  .smachil-cerrado .cerrado-pudu { margin: -6px auto -20px; }
}

/* --- 15.4 · Producto oculto ---------------------------------- */
.producto--oculto { display: none !important; }

/* --- 15.5 · Banner de campaña y avisos flotantes -------------
   Sólo se les alinea la tipografía y el radio al sistema. */
.smachil-banner { font-family: var(--f-cond); letter-spacing: 1.2px; }
.smachil-aviso  { border-radius: var(--r-md); font-family: var(--f-cond); }

/* Con el local cerrado, los CTA de WhatsApp no se esconden (el
   cliente quiere escribir igual) pero bajan de intensidad para
   dejar de competir con la carta. */
body.local-cerrado .fab-wapp { animation: none; opacity: .78; }
body.local-cerrado .btn-order,
body.local-cerrado .btn-checkout { filter: saturate(.55); }


/* ============================================================
   14 · MOVIMIENTO REDUCIDO
   Quien lo pidió en su sistema operativo lo pidió en serio.
   La carta funciona igual: sólo deja de moverse.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .hero-img,
  .hero-img-wrap::after,
  .cart-empty::before,
  .img-placeholder::after,
  .smachil-cerrado::before { animation: none !important; }
}
