/* Tienda online — rediseño 2026-08-06 aplicando la guia de diseño del proyecto.
   Estilo premium: mucho aire, foto de producto como protagonista, jerarquia por tamaño y
   espacio (no por color), y el celeste de marca presente de verdad.

   ── La decision de color, que no es obvia ──────────────────────────────────────────────
   El dueño pidio "mas celeste y mas brillante". Un celeste brillante NO puede usarse como
   texto chico sobre blanco: #00a8e8 da 2.7:1 y #0093c4 da 3.5:1, los dos por debajo del
   minimo de 4.5:1. Pero ESE MISMO celeste como RELLENO con texto oscuro encima da 9:1.
   Por eso el celeste vivo va en superficies (franja, badges, bloques) y el azul profundo
   queda solo para texto y links. Resultado: mas presencia de marca, no menos, y accesible. */

:root {
  --ink: #0b1220;
  --ink-soft: #58626f;
  --line: #e4e8ee;
  --bg: #ffffff;
  --bg-soft: #f5f7fa;

  /* Celeste vivo — SOLO como relleno, siempre con --ink encima (9.1:1). */
  --brand: #35c3f0;
  --brand-deep: #0b6ea8;   /* texto y links sobre blanco (5.5:1) */
  --brand-wash: #eaf8fe;   /* fondos suaves de marca */
  --ok: #0f7a58;

  --radius: 16px;
  --radius-sm: 10px;
  --shadow: 0 1px 2px rgba(11, 18, 32, .04), 0 10px 30px rgba(11, 18, 32, .07);
  --max: 1240px;

  /* Escala de apilado explicita: evita la guerra de z-index cuando crecen las pantallas. */
  --z-media: 1;
  --z-badge: 2;
  /* Por debajo de --z-header a proposito: el menu mobile (.nav.is-open) cuelga del header y
     tiene que taparlo, no al reves, cuando se abre sobre una pantalla chica. */
  --z-fab: 15;
  --z-header: 20;
  --z-dropdown: 25;
  /* El popover de "agregar rapido" (quick-add) es position:fixed sobre TODA la pagina —
     tiene que ganarle hasta al header fijo. */
  --z-quickadd: 30;

  /* Ritmo de espaciado en multiplos de 4, como manda la guia. */
  --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-12: 48px; --sp-16: 64px;
}

* { box-sizing: border-box; }

/* Ninguna pagina de la tienda debe poder correrse para el costado. Se usa clip y no hidden
   porque hidden convierte al body en contenedor de scroll y rompe el sticky de la barra. */
html, body { overflow-x: clip; max-width: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

a:focus-visible, button:focus-visible, select:focus-visible, input:focus-visible {
  outline: 3px solid var(--brand-deep);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ── Barra superior ─────────────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: var(--z-header);
  background: rgba(255, 255, 255, .94);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar-inner {
  max-width: var(--max); margin: 0 auto; padding: var(--sp-3) var(--sp-4);
  display: flex; align-items: center; gap: var(--sp-6);
}

/* El ancho lo manda el ALTO: se fija la altura y el ancho sale solo del logo, asi no se
   deforma nunca. width:auto es imprescindible porque el <img> lleva los atributos width/height
   reales (estan para que el navegador reserve el lugar y la barra no pegue un salto al cargar). */
.brand { display: flex; align-items: center; flex: 0 0 auto; }
.brand img { height: 64px; width: auto; }
.brand-name { font-size: 21px; font-weight: 800; letter-spacing: .14em; }
.brand-sub { font-size: 9.5px; font-weight: 700; letter-spacing: .34em; color: var(--brand-deep); margin-top: 4px; }

.nav { display: flex; gap: var(--sp-4); flex: 1 1 auto; flex-wrap: wrap; }
.nav a {
  font-size: 14px; font-weight: 600; color: var(--ink-soft);
  padding: 6px 0; border-bottom: 2.5px solid transparent; white-space: nowrap;
}
.nav a:hover, .nav a.is-active { color: var(--ink); border-bottom-color: var(--brand); }

/* "Mas" (Sucursales/Taller) — mismo patron que .account-dropdown, panel flotante que no le saca
   ancho a las categorias reales (2026-08-14, pedido de ahorrar espacio en el header). */
.nav-more { position: relative; }
.nav-more-trigger {
  display: inline-flex; align-items: center; gap: 4px;
  background: none; border: 0; cursor: pointer; font: inherit;
  font-size: 14px; font-weight: 600; color: var(--ink-soft);
  padding: 6px 0; border-bottom: 2.5px solid transparent;
}
.nav-more-trigger:hover, .nav-more-trigger[aria-expanded="true"] { color: var(--ink); border-bottom-color: var(--brand); }
.nav-more-dropdown {
  position: absolute; top: calc(100% + var(--sp-2)); left: 0; z-index: var(--z-dropdown);
  min-width: 160px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--sp-2);
  transform-origin: top left; transform: scale(.96); opacity: 0; pointer-events: none;
  transition: transform .16s ease-out, opacity .16s ease-out;
}
.nav-more-dropdown.is-open { transform: scale(1); opacity: 1; pointer-events: auto; }
.nav-more-dropdown a {
  display: block; padding: 10px var(--sp-3); border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 600; color: var(--ink); white-space: nowrap;
}
.nav-more-dropdown a:hover { background: var(--bg-soft); }

/* min-width:0 es imprescindible: sin el, un hijo flex NUNCA se achica por debajo de su
   contenido, y el buscador de 210px estiraba la barra mas alla de la pantalla. Eso hacia
   que TODA la pagina se pudiera correr para el costado (reportado 2026-08-06). */
.topbar-actions { display: flex; align-items: center; gap: var(--sp-2); flex: 1 1 auto; min-width: 0; justify-content: flex-end; }
/* El buscador es hermano de .topbar-actions, no hijo (ver el comentario en index.html). En
   escritorio el order lo deja donde estuvo siempre: nav (1) · buscador (2) · iconos (3). El brand
   no lleva order porque el default (0) ya lo pone primero. */
.search { order: 2; }
.topbar-actions { order: 3; }

/* Buscador FIJO, siempre visible, sin toggle ni animacion (2026-08-14). Hubo dos vueltas
   intentando un buscador colapsable (lupita que se abre al tocar) que terminaron dando problemas
   de posicionamiento reales — pedido explicito del dueño: mejor algo simple y estable que un
   ahorro de espacio que sigue saliendo mal. Ver Title Case + "Mas" en el nav (mismo dia) como la
   forma real de ganar espacio en la barra, en vez de esconder el buscador. */
.search {
  /* 260px, no 220px (pedido del dueño 2026-08-14): con 220 el placeholder "Buscar bicis,
     accesorios..." se cortaba a mitad de "accesorios". */
  display: flex; align-items: center; min-width: 0; flex: 0 1 260px;
  background: var(--bg-soft); border-radius: 999px; padding: 0 4px 0 var(--sp-4);
}
.search input { border: 0; background: none; padding: 11px 0; width: 100%; min-width: 0; font-size: 15px; color: inherit; outline: none; }
.search button { border: 0; background: none; color: var(--ink-soft); cursor: pointer; padding: var(--sp-2); display: grid; place-items: center; flex: 0 0 auto; }
.search button:hover { color: var(--brand-deep); }
.icon-btn {
  display: inline-grid; place-items: center; min-width: 44px; min-height: 44px;
  border: 0; background: none; cursor: pointer; color: var(--ink); padding: var(--sp-2); border-radius: 999px;
}
.icon-btn:hover { background: var(--bg-soft); }
#menuToggle { display: none; }
/* Bug real 2026-08-13: [hidden] del navegador y esta clase tienen la MISMA especificidad
   (0,1,0) — como .icon-btn esta en la hoja de estilos del autor, le gana al [hidden] nativo del
   navegador aunque el atributo este puesto, y el elemento se veia igual aunque estuviera
   "oculto" (paso con accountButton al arrancar, y hubiera pasado con searchToggle al abrirse el
   buscador). El selector de atributo suma especificidad (0,2,0) y lo saca de dudas. */
.icon-btn[hidden] { display: none; }

/* ── Cuenta (staff) ──────────────────────────────────────────────────────────
   Ojo: esto NO es una cuenta de cliente — todavia no existe (la tienda no tiene carrito ni
   checkout — ver TODO al principio de tienda.js). El icono de cuenta esta SIEMPRE visible: sin
   sesion abre el modal de login/registro (mas abajo), con sesion se convierte en un dropdown con
   los datos/pedidos del cliente, y si la sesion resulta ser de staff (Enzo/Facu/Pao/Pablo, ver
   storeCustomerAuthRoutes.js), suma "Ingresar al panel" — un link, nunca una sesion admin
   regalada desde aca. */
.account-menu { position: relative; }
/* Solo icono, sin la etiqueta de texto al lado (2026-08-14) — .account-trigger hereda el tamaño
   cuadrado normal de .icon-btn sin overrides, mismo criterio que el carrito y la lupita. */
.cart-link { position: relative; }
.cart-badge {
  position: absolute; top: 2px; right: 2px;
  min-width: 16px; height: 16px; padding: 0 3px; border-radius: 999px;
  background: var(--ink); color: #fff; font-size: 10px; font-weight: 800;
  display: grid; place-items: center; line-height: 1;
}
/* Mismo bug real de [hidden] vs display custom (ver .icon-btn mas arriba) — sin esto el badge
   mostraba "0" siempre en vez de ocultarse con el carrito vacio, encontrado al revisar el mismo
   patron en toda la hoja 2026-08-14. */
.cart-badge[hidden] { display: none; }
.account-dropdown {
  position: absolute; top: calc(100% + var(--sp-2)); right: 0; z-index: var(--z-dropdown);
  min-width: 200px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--sp-2);
  transform-origin: top right;
  transform: scale(.96); opacity: 0; pointer-events: none;
  transition: transform .16s ease-out, opacity .16s ease-out;
}
.account-dropdown.is-open { transform: scale(1); opacity: 1; pointer-events: auto; }
.account-dropdown-header { padding: var(--sp-2) var(--sp-3) var(--sp-3); border-bottom: 1px solid var(--line); margin-bottom: var(--sp-2); }
.account-dropdown-header strong { display: block; font-size: 14px; }
.account-dropdown-header small { color: var(--ink-soft); font-size: 12px; }
.account-dropdown-item {
  display: flex; align-items: center; width: 100%; min-height: 44px; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); border: 0; background: none;
  font: inherit; font-size: 14px; font-weight: 600; color: var(--ink); text-align: left; cursor: pointer;
}
.account-dropdown-item:hover { background: var(--bg-soft); }
/* Mismo bug real de [hidden] vs display custom (ver .icon-btn mas arriba) — sin esto "Ingresar al
   panel" se veia SIEMPRE en el dropdown, incluso para un cliente comun sin sesion de staff, que
   es exactamente el link que tiene que quedar oculto para ellos. Encontrado al revisar el mismo
   patron en toda la hoja 2026-08-14. */
.account-dropdown-item[hidden] { display: none; }
.account-dropdown-divider { height: 1px; background: var(--line); margin: var(--sp-2) 0; }
.account-dropdown-item.is-destructive { color: #b3261e; }

/* ── Modal de cuenta: Iniciar sesión / Crear cuenta ─────────────────────────── */
.auth-modal-backdrop {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(11, 18, 32, .55);
  display: grid; place-items: center; padding: var(--sp-4);
}
.auth-modal-backdrop[hidden] { display: none; }
.auth-modal {
  position: relative; width: 100%; max-width: 420px; max-height: 90vh; overflow-y: auto;
  background: var(--bg); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: var(--sp-8) var(--sp-6) var(--sp-6);
}
.auth-modal-close {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 36px; height: 36px; border-radius: 999px; border: 0; background: var(--bg-soft);
  color: var(--ink-soft); cursor: pointer; display: grid; place-items: center;
}
.auth-modal-close:hover { background: var(--line); color: var(--ink); }
/* margin-top: la X de cerrar (auth-modal-close) es absoluta, top:12px + 36px de alto = ocupa
   hasta los 48px del modal — sin este margen las pestañas arrancaban a los 32px (el padding-top
   del modal) y la X les quedaba encima. Reportado por el dueño 2026-08-14. */
.auth-tabs { display: flex; gap: var(--sp-2); margin-top: var(--sp-6); margin-bottom: var(--sp-4); }
.auth-tab {
  flex: 1 1 0; padding: 10px; border-radius: var(--radius-sm); border: 1.5px solid var(--line);
  background: none; font-weight: 700; font-size: 13.5px; color: var(--ink-soft); cursor: pointer;
}
.auth-tab.is-active { border-color: var(--ink); color: var(--ink); background: var(--bg-soft); }
.auth-modal-title { font-size: 22px; margin: 0 0 var(--sp-2); }
.auth-modal-status {
  min-height: 18px; font-size: 13px; font-weight: 600; color: #b3261e; margin: 0 0 var(--sp-3);
}
.auth-modal-status.is-ok { color: var(--ok); }
.auth-form[hidden] { display: none; }
.auth-form { display: flex; flex-direction: column; gap: var(--sp-3); }
.auth-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
/* min-width:0 en los dos niveles: un <input> dentro de un grid de 2 columnas (.auth-field-row) no
   se achica por debajo de su ancho minimo intrinseco si no se lo decis explicitamente — mismo
   bug ya documentado en este archivo para .topbar-actions, con otra causa (ahi era flex, aca
   grid), mismo arreglo. Sin esto aparecia una barra de scroll horizontal en el modal. */
.auth-field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; font-weight: 700; color: var(--ink-soft); min-width: 0; }
.auth-field input, .auth-field select, .auth-field textarea {
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); padding: 12px var(--sp-3);
  font-size: 15px; color: var(--ink); font-family: inherit; background: var(--bg);
  width: 100%; min-width: 0;
}
.auth-field textarea { resize: vertical; min-height: 90px; }
.auth-field input:focus-visible, .auth-field textarea:focus-visible { border-color: var(--brand-deep); outline: none; }
/* Honeypot anti-bot (formulario de arrepentimiento, /tienda/contacto) — fuera de pantalla pero
   presente en el DOM y fuera del tab order, mismo recurso que el turnero público (book.css). */
.hp-field { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.auth-field input[readonly] { background: var(--bg-soft); color: var(--ink-soft); cursor: default; }
/* DNI/CUIT de facturación (2026-08-19, referencia Tiendanube): tilde verde que confirma formato
   válido mientras se escribe — ver wireDniCuitInput() en tienda.js, que prende/apaga la clase
   is-valid en cada tecla sin volver a pintar() todo el formulario. */
.input-check-wrap { position: relative; }
.input-check-wrap input { padding-right: 42px; }
.input-check-icon {
  position: absolute; top: 50%; right: 12px; transform: translateY(-50%);
  width: 20px; height: 20px; fill: none; stroke: var(--ok); stroke-width: 2.5;
  stroke-linecap: round; stroke-linejoin: round; opacity: 0; transition: opacity .12s ease;
}
.input-check-icon.is-valid { opacity: 1; }
.auth-submit { width: 100%; margin-top: var(--sp-2); }
/* Link chico y discreto, no compite en peso visual con el botón de "Ingresar" — mismo criterio de
   jerarquía que un link de "olvidé mi contraseña" en cualquier login real. */
.auth-forgot-link {
  background: none; border: none; padding: 0; margin-top: -6px; align-self: flex-end;
  font-size: 12.5px; font-weight: 700; color: var(--ink-soft); cursor: pointer; text-decoration: underline;
}
.auth-forgot-link:hover { color: var(--ink); }
#authForgotBack { align-self: center; margin-top: 0; }
/* Honeypot: oculto visualmente sin display:none (algunos bots lo detectan y saltean el campo si
   ven eso) — se saca de pantalla con posicion en vez de esconderlo del DOM. */
.auth-honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

@media (max-width: 480px) {
  .auth-field-row { grid-template-columns: 1fr; }
}

/* Términos y Condiciones / Política de Privacidad (2026-08-20) — pagina de puro texto, sin
   ambicion visual: lo que importa es que se lea comodo, no que sea "linda". */
.legal-page h1 { font-size: 26px; margin-bottom: var(--sp-2); }
.legal-page h2 { font-size: 17px; margin: var(--sp-6) 0 var(--sp-2); }
.legal-page p { color: var(--ink-soft); line-height: 1.6; margin: 0; }
.legal-page a { color: var(--brand-deep); text-decoration: underline; }

/* ── Toast (agregar al carrito, errores de stock, etc.) ─────────────────────── */
/* El techo de ancho es min(420px, ...) y no solo el 100vw-margen de antes (2026-08-21): con el
   viewport entero disponible, un nombre largo del catalogo se desplegaba en una pildora enorme de
   varios renglones que tapaba media pantalla del celular. Con 420px el texto corta antes y el
   cartel se mantiene del tamaño de un aviso. El radio deja de ser 999px por el mismo motivo: en
   dos renglones, un radio mayor a la mitad del alto deforma los costados en dos panzas — 18px se
   ve igual de redondeado en un renglon y sigue prolijo si se va a dos. */
.store-toast {
  position: fixed; left: 50%; bottom: var(--sp-6); z-index: 200;
  transform: translate(-50%, 16px); opacity: 0; pointer-events: none;
  background: var(--ink); color: #fff; font-size: 14px; font-weight: 700;
  padding: 12px var(--sp-5); border-radius: 18px; box-shadow: var(--shadow);
  /* width:max-content NO es redundante con el max-width. Un position:fixed se dimensiona
     "shrink-to-fit" contra el espacio que le queda desde su borde de anclaje: con left:50%, ese
     espacio es la MITAD de la pantalla (195px en un celular de 390), asi que el texto se partia en
     cuatro renglones mucho antes de acercarse al techo de 420px. Con max-content el ancho lo pide
     el texto —una sola linea si entra— y recien ahi el max-width lo recorta. */
  width: max-content;
  max-width: min(420px, calc(100vw - var(--sp-8))); text-align: center;
  line-height: 1.35;
  transition: transform .2s ease-out, opacity .2s ease-out;
}
.store-toast.is-visible { transform: translate(-50%, 0); opacity: 1; }
.store-toast.is-error { background: #b3261e; }

/* ── Franja de beneficios — el celeste de marca a pleno ─────────────────────── */
/* Desfile continuo. Se mueve el carril con transform y no con posiciones: transform lo resuelve
   la placa de video y no obliga al navegador a recalcular la pagina en cada cuadro, asi que no
   pesa aunque este animando todo el tiempo.
   El contenido esta repetido 4 VECES en el HTML (ver el comentario largo en index.html) — con
   solo 2 copias, en un monitor ancho una sola copia (~1280px) es mas angosta que el viewport y en
   cierto punto del recorrido se ve la linea casi vacia antes de reiniciar (bug real reportado por
   Enzo 2026-08-20, se notaba como un salto/gif). El recorrido es exactamente -25% (el ancho de
   UNA copia sobre un carril de 4): cuando la primera copia termina de salir por la izquierda, la
   segunda ya esta exactamente donde arrancaba la primera y el salto es invisible — misma logica
   que antes con -50%/2 copias, solo que con margen de sobra para pantallas anchas. */
.benefits {
  background: var(--brand);
  color: var(--ink);
  overflow: hidden;
  padding: 11px 0;
  position: relative;
}
.benefits-track {
  display: flex; width: max-content;
  animation: desfileCuarto 38s linear infinite;
}
/* Se frena al pasar el mouse: si algo te intereso, podes leerlo tranquilo. */
.benefits:hover .benefits-track { animation-play-state: paused; }

.benefits-run {
  display: flex; align-items: center; flex: 0 0 auto;
  gap: var(--sp-12); padding-right: var(--sp-12);
}
.benefits-run span {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 13px; font-weight: 700; letter-spacing: .01em; white-space: nowrap;
}
.benefits-run svg { flex: 0 0 auto; opacity: .85; }

/* Degradados en los bordes: el texto aparece y desaparece en lugar de cortarse de golpe. */
.benefits::before, .benefits::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 42px; z-index: 2; pointer-events: none;
}
.benefits::before { left: 0; background: linear-gradient(90deg, var(--brand), rgba(53,195,240,0)); }
.benefits::after { right: 0; background: linear-gradient(270deg, var(--brand), rgba(53,195,240,0)); }

@keyframes desfile {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

/* Version para un carril de 4 copias (.benefits-track) — se mueve 1/4 del carril total, que es
   exactamente el ancho de UNA copia. Las reseñas siguen usando "desfile" (2 copias, -50%) porque
   ahi cada tarjeta ya es bien ancha (320px x 8 = de sobra para cubrir cualquier pantalla real). */
@keyframes desfileCuarto {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-25%, 0, 0); }
}

/* Sin movimiento para quien lo pidio en su sistema: queda quieta y centrada, con una sola copia. */
@media (prefers-reduced-motion: reduce) {
  .benefits-track { animation: none; width: 100%; justify-content: center; }
  .benefits-run { flex-wrap: wrap; justify-content: center; gap: var(--sp-3) var(--sp-8); padding-right: 0; }
  .benefits-run[aria-hidden="true"] { display: none; }
  .benefits::before, .benefits::after { display: none; }
}

/* ── Layout ─────────────────────────────────────────────────────────────────── */
.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--sp-4); }
.section { margin: var(--sp-16) auto; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-6); }
.section-head h2 {
  font-size: 28px; margin: 0; letter-spacing: -.025em; position: relative; padding-left: 14px;
}
/* Barrita de marca al costado del titulo: presencia de color sin ensuciar el texto. */
.section-head h2::before {
  content: ''; position: absolute; left: 0; top: .15em; bottom: .15em;
  width: 5px; border-radius: 3px; background: var(--brand);
}
.section-head a { font-size: 14.5px; font-weight: 700; color: var(--brand-deep); white-space: nowrap; }

/* ── Hero: carrusel ────────────────────────────────────────────────────────────
   Claro, como el resto del sitio. Lo que lo hace premium no es el color de fondo sino los
   detalles: tipografia grande y bien apretada, una reticula apenas visible, un halo de
   marca difuso detras del producto y movimiento corto y bien curvado. El producto se apoya
   sobre un gris muy leve (no blanco puro) para que la foto —que viene con fondo blanco—
   quede separada del fondo en vez de fundirse. */
.hero { max-width: var(--max); margin: var(--sp-6) auto 0; padding: 0 var(--sp-4); }
.hero-inner {
  position: relative; border-radius: 26px; overflow: hidden;
  background: #fbfcfe;
  border: 1px solid var(--line);
  height: 520px;
  isolation: isolate;
  /* Tarjeta partida a la mitad (2026-08-28, pedido de Enzo): productos a la izquierda, taller a
     la derecha — dos carruseles independientes, ver heroCarouselHtml/initHeroCarousel. */
  display: grid; grid-template-columns: 1fr 1fr;
}
/* Halo de marca difuso detras del producto: da profundidad sin ensuciar. */
.hero-inner::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(56% 68% at 76% 48%, rgba(53,195,240,.26) 0%, rgba(53,195,240,0) 64%),
    radial-gradient(46% 60% at 8% 6%, rgba(53,195,240,.10) 0%, rgba(53,195,240,0) 72%);
}
/* Reticula apenas visible: el detalle que hace que se lea "producto" y no "plantilla". Cubre TODA
   la tarjeta (no solo el lado de productos) — el lado del taller la necesita tanto o mas, es su
   unica textura de fondo al no tener foto. */
.hero-inner::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background-image:
    linear-gradient(rgba(11,18,32,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(11,18,32,.045) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(78% 78% at 50% 50%, #000 25%, transparent 100%);
}

/* Cada mitad es su propio contexto de posicionamiento Y un flex column: contenido arriba (crece
   para llenar el lugar disponible), controles abajo pegados a ese contenido — sin numeros magicos
   de padding esperando que "algo" los llene (bug real reportado: hueco enorme entre el boton y
   las flechas). */
.hero-panel { position: relative; z-index: 1; overflow: hidden; display: flex; flex-direction: column; padding: var(--sp-6) var(--sp-6) var(--sp-5); }
.hero-panel-taller { border-left: 1px solid var(--line); }

/* ── Mitad de productos ───────────────────────────────────────────────────── */
/* flex-basis:0 (no "auto"), mismo motivo que .hero-media mas abajo: sus hijos son
   position:absolute (los .hero-slide van uno arriba del otro para el crossfade), asi que su
   tamaño de contenido "natural" no es confiable como base — tiene que salir SOLO de la
   distribucion flex. Bug real visto en vivo: sin esto, en el lado del taller (sin foto que le de
   una altura grande al hermano de al lado) esta caja colapsaba y el icono/texto se superponia
   con el badge de arriba. */
.hero-slides { position: relative; flex: 1 1 0; min-height: 0; }
.hero-slide {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  opacity: 0; visibility: hidden;
  transition: opacity .55s ease-out, visibility .55s;
}
.hero-slide.is-active { opacity: 1; visibility: visible; }

/* Alto FIJO a proposito, no flex:1 (2026-08-28, tercera vuelta sobre esto mismo dia): con flex:1
   el alto de esta caja es un VALOR CALCULADO por la distribucion flex, no uno escrito a mano — y
   "max-height:100%" en la foto de adentro no resuelve de fiar contra un alto asi (limitacion real
   de como los navegadores resuelven porcentajes de alto contra un padre flex, confirmado en vivo
   con la foto real de un producto: la mostraba recortada, no achicada). Con un numero fijo la foto
   de adentro SI puede confiar en su max-height, y nunca se recorta. Mas chica que "tan grande como
   entre" pero confiable siempre, en cualquier producto — se prefiere eso a que ande bien con unas
   fotos y mal con otras. */
/* Alto subido de 190 a 235 (2026-08-28, pedido de Enzo: "la imagen que se vea mas grande") — el
   texto de al lado se achico a proposito (ver .hero-copy mas abajo) para hacerle lugar sin tocar
   el alto total de la tarjeta (.hero-inner sigue en 520px). */
.hero-media { height: 235px; flex: 0 0 auto; overflow: hidden; text-align: center; padding-bottom: var(--sp-3); }
/* max-height en PIXELES LITERALES (221px = 235 de la caja menos el padding-bottom de arriba), no
   en porcentaje — tercer intento el mismo dia: ni con flex-basis:0 ni con un alto fijo en el
   padre el "max-height:100%" resolvia bien contra el contenedor (probado en vivo con una foto
   real, se veia recortada las dos veces). Un numero en px no necesita resolver nada contra nadie,
   no hay ambiguedad posible. margin:0 auto centra horizontalmente sin display:grid (se saco por
   las dudas de que el grid tuviera algo que ver). */
.hero-media img {
  display: inline-block; max-width: 100%; max-height: 221px; width: auto; height: auto;
  filter: drop-shadow(0 18px 30px rgba(11,18,32,.16));
}
.hero-slide.is-active .hero-media img { animation: heroFloat .6s cubic-bezier(.22,.8,.28,1) both; }

.hero-copy { flex: 0 0 auto; color: var(--ink); }
/* Todo el bloque de texto se achico un escalon (2026-08-28, pedido de Enzo: "disminuir la letra
   y el boton para que la imagen se vea mas grande") — la foto de arriba subio de 190 a 235px de
   alto y esta es la mitad que le hizo lugar. */
.hero-copy .eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .16em;
  background: var(--brand-wash); color: var(--brand-deep);
  border: 1px solid rgba(53,195,240,.45);
  padding: 5px 10px; border-radius: 999px;
}
/* max-height + overflow:hidden (no -webkit-line-clamp): reportado en vivo, el titulo
   desaparecia por completo en vez de acortarse a 2 renglones — mismo texto confirmado presente
   en el DOM, era un problema de render de esa combinacion especifica. Este clamp es menos
   prolijo (corta seco, sin "...") pero nunca hace desaparecer el texto entero. */
.hero-copy h1 {
  font-size: clamp(15px, 1.3vw, 18px); line-height: 1.2;
  margin: var(--sp-2) 0 var(--sp-2); letter-spacing: -.03em; font-weight: 800;
  max-height: 2.4em; overflow: hidden;
}
.hero-price { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-3); flex-wrap: wrap; }
.hero-price .now { font-size: 17px; font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.hero-price .was { font-size: 12px; color: var(--ink-soft); text-decoration: line-through; }
.hero-price .off {
  font-size: 10px; font-weight: 800; background: var(--brand); color: var(--ink);
  align-self: center; padding: 3px 8px; border-radius: 999px;
}
/* Boton mas chico que el .btn de base (que es compartido por todo el sitio, no se toca) — solo
   en esta mitad de la tarjeta, para que le gane espacio a la foto. */
.hero-cta .btn { width: 100%; padding: 11px 20px; font-size: 13.5px; }
.btn.on-dark { background: var(--ink); color: #fff; }
.btn.on-dark:hover { background: #1b2331; }
.btn.ghost-dark { background: #fff; color: var(--ink); border: 1.5px solid var(--line); }
.btn.ghost-dark:hover { border-color: var(--ink); background: var(--bg-soft); color: var(--ink); }

.hero-slide.is-active .hero-copy > * { animation: heroRise .5s cubic-bezier(.22,.8,.28,1) both; }
.hero-slide.is-active .hero-copy > *:nth-child(1) { animation-delay: .04s; }
.hero-slide.is-active .hero-copy > *:nth-child(2) { animation-delay: .09s; }
.hero-slide.is-active .hero-copy > *:nth-child(3) { animation-delay: .14s; }
.hero-slide.is-active .hero-copy > *:nth-child(4) { animation-delay: .19s; }

@keyframes heroFloat { from { opacity: 0; transform: translate3d(0, 10px, 0) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes heroFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes heroRise { from { opacity: 0; transform: translate3d(0, 12px, 0); } to { opacity: 1; transform: none; } }

/* Fila de controles: SIEMPRE pegada abajo del contenido (flex:0, normal flow), nunca flotando a
   una distancia fija del piso de la tarjeta. */
.hero-panel-footer { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); margin-top: var(--sp-4); }
.hero-dots { display: flex; gap: 8px; }
.hero-dot {
  width: 26px; height: 4px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  background: rgba(11,18,32,.16); transition: background .2s, width .25s;
}
.hero-dot.is-active { background: var(--brand); width: 38px; }
.hero-arrows { display: flex; gap: var(--sp-2); flex: 0 0 auto; }
.hero-arrow {
  width: 38px; height: 38px; border-radius: 50%; cursor: pointer;
  background: #fff; border: 1px solid var(--line);
  color: var(--ink); display: grid; place-items: center; transition: background .18s, border-color .18s;
}
.hero-arrow:hover { background: var(--brand-wash); border-color: var(--brand); }

/* ── Mitad del taller ─────────────────────────────────────────────────────── */
/* Segunda vuelta de diseño (mismo dia, feedback real: "tan vacio, tan feo, para eso una fija").
   Tres cosas lo llenan sin necesitar una foto real: un icono grande de fondo (marca de agua,
   apenas visible), un icono propio en circulo por cada punto (mismo peso visual que la foto del
   otro lado), y controles en la MISMA fila que el CTA en vez de apilados con aire de mas. */
.hero-panel-taller { background: linear-gradient(165deg, rgba(53,195,240,.10), rgba(53,195,240,.02) 60%); }
/* Bug real encontrado en vivo (midiendo con getBoundingClientRect): con la misma especificidad
   que ".hero-panel-taller > *" de abajo, esa regla ganaba por orden de aparicion y le pisaba el
   position:absolute a esta marca de agua — pasaba a ser un item de flex mas, de 220px, empujando
   TODO el resto del panel para abajo (eyebrow, icono, texto y controles quedaban superpuestos
   entre si en vez de apilados). Selector mas especifico para que esto nunca dependa del orden. */
.hero-panel-taller .taller-watermark {
  position: absolute; z-index: 0; right: -34px; bottom: -34px;
  width: 220px; height: 220px; color: var(--brand-deep); opacity: .07;
  pointer-events: none;
}
.hero-panel-taller > * { position: relative; z-index: 1; }
.hero-panel-taller .eyebrow {
  display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto;
  font-size: 10.5px; font-weight: 800; letter-spacing: .16em;
  background: #fff; color: var(--brand-deep);
  border: 1px solid rgba(53,195,240,.45);
  padding: 6px 12px; border-radius: 999px; margin: 0 0 var(--sp-3); align-self: flex-start;
}
.hero-slide.hero-slide-taller {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 0; visibility: hidden;
  transition: opacity .55s ease-out, visibility .55s;
}
/* Especificidad a proposito mas alta que .hero-slide.is-active (0-2-0) — sin el
   .hero-slide.hero-slide-taller.* completo, la regla generica del carrusel de productos le gana
   por orden de aparicion y la mitad del taller nunca se ve. */
.hero-slide.hero-slide-taller.is-active { opacity: 1; visibility: visible; }
.taller-icon {
  width: 52px; height: 52px; border-radius: 16px; flex: 0 0 auto;
  background: var(--ink); color: #fff;
  display: grid; place-items: center; margin-bottom: var(--sp-4);
}
.hero-slide.hero-slide-taller h2 {
  font-size: clamp(21px, 1.9vw, 27px); line-height: 1.14; letter-spacing: -.03em; font-weight: 800;
  margin: 0 0 var(--sp-2); color: var(--ink);
}
.hero-slide.hero-slide-taller.is-active .taller-icon,
.hero-slide.hero-slide-taller.is-active h2,
.hero-slide.hero-slide-taller.is-active p { animation: heroRise .5s cubic-bezier(.22,.8,.28,1) both; }
.hero-slide.hero-slide-taller.is-active h2 { animation-delay: .05s; }
.hero-slide.hero-slide-taller.is-active p { animation-delay: .1s; }
.hero-slide.hero-slide-taller p { color: var(--ink-soft); font-size: 14.5px; line-height: 1.5; margin: 0; max-width: 30ch; }
.hero-panel-taller .hero-panel-footer .btn { width: auto; flex: 0 0 auto; padding: 12px 22px; }
/* Con las flechas sumadas (2026-08-28) la fila pasa de 2 a 3 elementos — en mobile angosto
   (tarjeta apilada a ancho de telefono) ya no entran los tres en una linea y el boton quedaba
   cortado a la mitad. wrap sin punto de quiebre fijo: solo baja de linea cuando de verdad no
   entra, a cualquier ancho, en vez de adivinar un numero de pixeles. */
.hero-panel-taller .hero-panel-footer { flex-wrap: wrap; row-gap: var(--sp-3); }

/* Mitad de productos: la misma composicion "foto arriba, texto abajo" a CUALQUIER ancho — la
   tarjeta partida ya deja cada mitad angosta de por si, no hace falta una version aparte para
   mobile (ver @media mas abajo, que ahora solo apila las dos mitades una sobre la otra). */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ink); color: #fff;
  padding: 14px 28px; border-radius: 999px;
  font-weight: 700; font-size: 15px; border: 0; cursor: pointer;
  transition: transform .15s ease-out, background .15s;
}
/* El fondo oscuro solo para los botones que YA son oscuros. Antes .btn:hover se lo aplicaba
   tambien a los blancos (.ghost, .ghost-dark) y quedaba texto oscuro sobre fondo oscuro. */
.btn:hover { transform: translateY(-1px); }
.btn:not(.ghost):not(.ghost-dark):hover { background: #1b2331; }
.btn:active { transform: translateY(0); }
.btn.ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--line); }
.btn.ghost:hover { border-color: var(--ink); background: transparent; }

/* ── Grilla de productos ────────────────────────────────────────────────────── */
.grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
  column-gap: var(--sp-6); row-gap: 0;
}
/* La separacion entre filas de tarjetas la da la ultima pieza, porque row-gap tiene que quedar
   en cero para no inflar el interior de cada tarjeta. */
.grid .card .price-transfer { margin-bottom: var(--sp-10, 40px); }

/* Las tarjetas de una misma fila COMPARTEN sus filas internas (subgrid). Sin esto cada tarjeta
   se mide sola: un nombre de producto de 4 renglones empuja hacia abajo el precio, las cuotas y
   el precio de transferencia SOLO en esa tarjeta, y la fila queda escalonada — se ve desprolijo
   incluso sin buscarlo.
   Requiere que la tarjeta emita SIEMPRE las mismas 6 piezas (ver cardHtml en tienda.js): con
   cantidades distintas de hijos no habria filas que compartir. */
.card {
  display: grid;
  grid-row: span 6;
  grid-template-rows: subgrid;
  align-content: start;
}

/* Respaldo para navegadores viejos sin subgrid: al menos el titulo mide siempre lo mismo, que
   es de donde salia casi todo el desfasaje. */
@supports not (grid-template-rows: subgrid) {
  .card { grid-row: auto; grid-template-rows: auto auto auto auto auto auto; }
  .card-title {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
}
.card-media {
  position: relative; background: var(--bg-soft); border-radius: var(--radius);
  aspect-ratio: 1 / 1; overflow: hidden; margin-bottom: 10px;
  border: 1px solid transparent; transition: border-color .18s, box-shadow .18s;
}
.card:hover .card-media { border-color: var(--brand); box-shadow: var(--shadow); }
.card-media img {
  width: 100%; height: 100%; object-fit: contain; padding: var(--sp-3);
  position: relative; z-index: var(--z-media);
  transition: transform .28s ease-out;
}
.card:hover .card-media img { transform: scale(1.05); }

/* El z-index NO es decorativo: el `transform` de la foto crea un contexto de apilado propio
   y sin esto la foto se dibuja ENCIMA del cartel, haciendo desaparecer el "20% OFF" justo
   al pasar el mouse (bug real reportado por el dueño 2026-08-06). */
.tag {
  position: absolute; top: var(--sp-3); left: var(--sp-3); z-index: var(--z-badge);
  background: var(--brand); color: var(--ink);
  font-size: 11.5px; font-weight: 800; letter-spacing: .03em;
  padding: 5px 10px; border-radius: 999px;
}
.tag.out { background: var(--ink); color: #fff; }
/* Carril de los carteles de arriba (2026-08-21). Antes cada uno era un position:absolute suelto:
   el de transferencia anclado a la izquierda y el de envío gratis a la derecha, los dos al mismo
   `top`. Con la tarjeta angosta —celular, grilla de 2 columnas— se superponían SIEMPRE ("22% tra"
   tapado por "Envío gratis", reportado por Enzo con captura). Un solo carril flex de borde a borde
   lo resuelve a cualquier ancho, sin números mágicos: entran los dos en un renglón si hay lugar y
   si no, el segundo baja al de abajo. pointer-events:none para que el carril (que ahora cubre todo
   el ancho de la foto) no se coma el click sobre la tarjeta. */
.card-tags {
  position: absolute; top: var(--sp-3); left: var(--sp-3); right: var(--sp-3);
  z-index: var(--z-badge);
  display: flex; flex-wrap: wrap; gap: 6px;
  justify-content: space-between; align-items: flex-start;
  pointer-events: none;
}
/* Adentro del carril mandan flex y el gap, no las coordenadas. */
.card-tags .tag { position: static; }
/* Mas discreto a propósito (fondo blanco, no celeste): es informativo, no una oferta como el
   resto de los tags — no tiene que gritar igual. */
.tag.ship-free { background: var(--bg); color: var(--ink); border: 1px solid var(--line); font-weight: 700; }

/* Agregar rápido (2026-08-20, pedido de Enzo) — flotante sobre la esquina de la foto. Oculto por
   default en desktop y aparece con el hover de la tarjeta (mismo gesto que ya revela el zoom de
   la foto); en táctil no hay hover, así que ahí queda siempre visible — sin eso no habría forma
   de encontrarlo con el dedo. */
.card-quick-add {
  position: absolute; right: var(--sp-3); bottom: var(--sp-3); z-index: var(--z-badge);
  width: 34px; height: 34px; border-radius: 50%; border: none;
  background: var(--ink); color: #fff; display: grid; place-items: center; cursor: pointer;
  box-shadow: 0 4px 10px rgba(11,18,32,.22);
  opacity: 0; transform: scale(.85);
  transition: opacity .15s ease-out, transform .15s ease-out, background .15s;
}
.card:hover .card-quick-add, .card:focus-within .card-quick-add { opacity: 1; transform: scale(1); }
.card-quick-add:hover { background: var(--brand-deep); }
@media (hover: none) { .card-quick-add { opacity: 1; transform: none; } }

/* Popover de talle/color al agregar rápido — position:fixed y anclado por JS (posicionarQuickAdd-
   Popover en tienda.js): .card-media tiene overflow:hidden y .riel tiene su propio scroll, un
   position:absolute adentro de cualquiera de los dos quedaria recortado o invisible. */
.quick-add-pop {
  position: fixed; z-index: var(--z-quickadd);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--sp-3);
}
.quick-add-loading { margin: 0; padding: var(--sp-2) 0; font-size: 13px; color: var(--ink-soft); text-align: center; }
.quick-add-close {
  position: absolute; top: 2px; right: 6px; width: 26px; height: 26px;
  border: none; background: none; font-size: 20px; line-height: 1; color: var(--ink-soft); cursor: pointer;
}
.quick-add-group { margin: 0 22px var(--sp-2) 0; }
.quick-add-group:first-child { margin-top: 2px; }
.quick-add-group-label { font-size: 11.5px; font-weight: 800; color: var(--ink-soft); letter-spacing: .03em; text-transform: uppercase; margin: 0 0 6px; }
.quick-add-values { display: flex; flex-wrap: wrap; gap: 6px; }
.quick-add-variant-btn {
  padding: 4px 11px; border-radius: 999px; border: 1.5px solid var(--line);
  background: var(--bg); font-size: 12.5px; font-weight: 600; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.quick-add-variant-btn.is-selected { border-color: var(--brand); background: var(--brand-wash); }
.quick-add-variant-btn:disabled { opacity: .35; cursor: not-allowed; text-decoration: line-through; }
.quick-add-confirm { width: 100%; margin-top: 4px; }

.card-brand { font-size: 11px; font-weight: 800; letter-spacing: .12em; color: var(--ink-soft); text-transform: uppercase; margin: 0; }
.card-title {
  font-size: 15px; font-weight: 600; line-height: 1.35; margin: 4px 0 0;
  /* Dos renglones fijos. El nombre completo esta en la ficha del producto; aca lo unico que
     lograba un titulo de cuatro renglones era estirar TODAS las tarjetas de la fila, porque
     comparten alto. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.price-list { font-size: 13px; color: var(--ink-soft); text-decoration: line-through; }
/* El precio grande es el de lista (lo que paga la mayoria, con tarjeta). El de transferencia
   va debajo en celeste: sigue siendo un argumento de venta fuerte, pero ya no se confunde
   con "el precio" ni contradice lo que muestra Tiendanube para el mismo producto. */
.price-transfer { font-size: 13px; font-weight: 800; color: var(--brand-deep); margin: 4px 0 0; }
/* Vacias no ocupan: si ningun producto de la fila tiene marca, cuotas o transferencia, esa fila
   del subgrid queda en cero y no deja un hueco fantasma. */
.card-brand:empty, .price-inst:empty, .price-transfer:empty { margin: 0; }
.price-transfer span { font-weight: 600; color: var(--ink-soft); }
.price-transfer-box {
  margin-top: var(--sp-4); padding: var(--sp-3) var(--sp-4);
  background: var(--brand-wash); border: 1px solid rgba(53,195,240,.45);
  border-radius: 12px; font-size: 14.5px; color: var(--ink);
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
}
.price-transfer-box strong { font-size: 22px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.price-transfer-box span {
  margin-left: auto; background: var(--brand); color: var(--ink);
  font-size: 12px; font-weight: 800; padding: 4px 10px; border-radius: 999px; white-space: nowrap;
}
.price-main { font-size: 20px; font-weight: 800; letter-spacing: -.025em; font-variant-numeric: tabular-nums; margin: 10px 0 0; }
.price-note { font-size: 12.5px; color: var(--ok); font-weight: 700; margin-top: 3px; }
.price-inst { font-size: 12.5px; color: var(--ink-soft); margin: 3px 0 0; }

/* Oferta real del producto (price.onSale) — distinta del descuento por transferencia, que sigue
   con su propio bloque azul (.price-transfer-box) mas abajo. .price-was queda inline (<s> en la
   tarjeta) o en bloque (<p> en la ficha) segun donde se use, mismo criterio de una sola clase que
   se adapta al tag que la usa. */
.price-was { font-size: 13px; color: var(--ink-soft); font-weight: 600; text-decoration: line-through; }
.detail .price-was { font-size: 16px; margin: 10px 0 0; }
.price-sale-badge {
  font-size: 11px; font-weight: 800; background: #b3261e; color: #fff;
  padding: 2px 8px; border-radius: 999px; vertical-align: middle; white-space: nowrap;
}

/* ── Sucursales ───────────────────────────────────────────────────────────────
   Una tarjeta grande por sucursal, con el mapa ocupando la mitad. Alternan de lado para que
   la pagina tenga ritmo y no se lea como una planilla. El mapa NO es decoracion: es lo que
   la persona vino a buscar, asi que pesa lo mismo que el texto. */
.sucursales-head { max-width: 640px; margin-bottom: var(--sp-12); }
.sucursales-head h1 {
  font-size: clamp(28px, 3.4vw, 44px); line-height: 1.06; letter-spacing: -.035em;
  margin: 0 0 var(--sp-3);
}
.sucursales-head p { font-size: 17px; line-height: 1.6; color: var(--ink-soft); margin: 0; }

.sucursales { display: grid; gap: var(--sp-8); }

.sucursal {
  display: grid; grid-template-columns: 1fr 1.1fr;
  background: #fff; border: 1px solid var(--line); border-radius: 22px;
  overflow: hidden;
  transition: border-color .22s, box-shadow .22s;
}
.sucursal:hover { border-color: rgba(53,195,240,.5); box-shadow: var(--shadow); }
/* La segunda invierte el orden: el mapa queda del lado de adentro en las dos. */
.sucursal.is-invertida .sucursal-info { order: 2; }
.sucursal.is-invertida .sucursal-mapa { order: 1; }

.sucursal-info { padding: var(--sp-12); display: grid; align-content: start; gap: var(--sp-3); }
.sucursal-info .eyebrow {
  justify-self: start;
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 800; letter-spacing: .17em;
  background: var(--brand-wash); color: var(--brand-deep);
  border: 1px solid rgba(53,195,240,.45);
  padding: 6px 13px; border-radius: 999px; margin: 0;
}
.sucursal-info h2 { font-size: 34px; letter-spacing: -.035em; margin: var(--sp-2) 0 0; }
/* Reseñas de Google por sucursal (2026-08-25) — un link si hay ficha real, texto simple si no.
   :any-link cubre las dos etiquetas (<a> o <p>) sin duplicar la regla. */
.sucursal-resenas {
  display: flex; align-items: center; gap: 6px; margin: var(--sp-2) 0 0;
  font-size: 14.5px; color: var(--ink-soft);
}
a.sucursal-resenas:hover { color: var(--brand-deep); }
.sucursal-resenas strong { color: var(--ink); font-weight: 800; }
.sucursal-dir { font-size: 16px; color: var(--ink-soft); margin: 0; }

.sucursal-datos { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: grid; gap: var(--sp-4); }
.sucursal-datos li { display: grid; gap: 3px; padding-left: var(--sp-4); border-left: 3px solid var(--brand); }
.sucursal-datos strong { font-size: 11.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-soft); }
.sucursal-datos span { font-size: 15px; }

.sucursal-chip {
  justify-self: start; margin: var(--sp-4) 0 0;
  background: var(--brand); color: var(--ink);
  font-size: 12.5px; font-weight: 800;
  padding: 7px 14px; border-radius: 999px;
}

.sucursal-acciones { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-6); }

.sucursal-mapa { position: relative; min-height: 380px; background: var(--bg-soft); }
.sucursal-mapa iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  /* SIN filtros de color: un filter sobre un iframe lo obliga a recomponerse en otra capa y el
     mapa se ve levemente pixelado. Se habia puesto para atemperar el blanco de OpenStreetMap. */
}

/* Claro y no oscuro, igual que la franja del taller del inicio: dos bloques oscuros grandes
   en la misma pagina pesaban demasiado. Y con fondo claro el boton vuelve a ser un .btn comun,
   asi que se va de raiz el hover ilegible que tenia cuando era celeste sobre oscuro. */
.sucursales-cierre {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-8);
  margin-top: var(--sp-12); padding: var(--sp-12);
  background: var(--brand-wash); border: 1px solid rgba(53,195,240,.4); border-radius: 22px;
}
.sucursales-cierre h2 { font-size: 26px; letter-spacing: -.03em; margin: 0 0 var(--sp-2); }
.sucursales-cierre p { color: var(--ink-soft); margin: 0; max-width: 52ch; line-height: 1.6; }
.sucursales-cierre .btn { flex: 0 0 auto; }

@media (max-width: 980px) {
  /* Objetivo concreto: que la ficha ENTERA de una sucursal entre en una pantalla de celular,
     sin tener que scrollear para ver los botones. Por eso el mapa es mas bajo, el aire es
     menor y los dos botones van uno al lado del otro en vez de apilados. */
  .sucursal { grid-template-columns: 1fr; }
  /* En una columna el mapa va SIEMPRE arriba, sin importar la alternancia de escritorio:
     es la referencia visual que ubica la sucursal antes de leer nada. */
  .sucursal-info, .sucursal.is-invertida .sucursal-info {
    order: 2; padding: var(--sp-5) var(--sp-5) var(--sp-6); gap: var(--sp-2);
  }
  .sucursal-mapa, .sucursal.is-invertida .sucursal-mapa { order: 1; min-height: 190px; }
  .sucursal-info .eyebrow { font-size: 10px; padding: 5px 11px; }
  .sucursal-info h2 { font-size: 24px; margin-top: 4px; }
  .sucursal-dir { font-size: 14.5px; line-height: 1.45; }
  .sucursal-datos { gap: var(--sp-3); margin-top: var(--sp-3); }
  .sucursal-datos strong { font-size: 10.5px; }
  .sucursal-datos span { font-size: 14px; }
  .sucursal-chip { margin-top: var(--sp-3); font-size: 12px; padding: 6px 12px; }
  .sucursal-acciones { margin-top: var(--sp-4); gap: var(--sp-2); flex-wrap: nowrap; }
  /* flex:1 con min-width:0 reparte el ancho en dos: sin el min-width, el boton de WhatsApp no
     se dejaria achicar por debajo de su texto y se irian de la pantalla. */
  .sucursal-acciones .btn {
    flex: 1 1 0; min-width: 0; width: auto;
    padding: 12px 10px; font-size: 13.5px; white-space: nowrap;
  }
  .sucursales-cierre { flex-direction: column; align-items: flex-start; padding: var(--sp-8) var(--sp-6); }
  .sucursales-cierre .btn { width: 100%; }
}

/* ── Categorias ─────────────────────────────────────────────────────────────── */
/* ── Riel de productos ────────────────────────────────────────────────────────
   Una sola fila que se desliza en horizontal, en lugar de dos lineas de grilla.
   El ancho de columna esta pensado para que se vea un PEDAZO de la tarjeta siguiente
   (23% x 4 = 92%): ese recorte es lo que le avisa al visitante que hay mas para el costado.
   Un carrusel que corta justo en el borde parece terminar ahi y la flecha no se toca.
   El scroll es nativo: se arrastra con el dedo en celular y con la rueda en escritorio.
   Las flechas son un atajo, no el unico camino. */
.riel-wrap { position: relative; }
.riel {
  display: grid; grid-auto-flow: column;
  /* Tarjetas ENTERAS: 4 en escritorio, 2 en pantalla chica. Ver un producto cortado al
     costado molesta mas de lo que ayuda, asi que el aviso de que hay mas son las flechas,
     que por eso quedan visibles tambien en tactil. */
  grid-auto-columns: calc((100% - 3 * var(--sp-6)) / 4);
  column-gap: var(--sp-6); row-gap: 0; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* overflow-x: auto obliga al eje vertical a recortar tambien (regla de CSS: si un eje deja
     de ser visible, el otro tampoco puede serlo). La tarjeta se levanta 4px al pasar el mouse
     y su borde celeste quedaba cortado arriba. El relleno le da lugar adentro del contenedor
     y el margen negativo lo compensa, asi la fila sigue alineada con el titulo. */
  padding: 10px 12px var(--sp-4);
  margin: -10px -12px 0;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.riel::-webkit-scrollbar { display: none; }
.riel > .card { scroll-snap-align: start; }

/* Carrusel de Instagram (2026-08-18, pedido del dueño en la reunión con el jefe) — reusa el
   mismo .riel-wrap/.riel de los productos (flechas, drag, snap), solo cambia la tarjeta: acá es
   una foto/video cuadrado que linkea al posteo real, sin precio ni nombre. */
.riel > .ig-card { scroll-snap-align: start; }
.ig-card {
  display: block; position: relative; border-radius: var(--radius); overflow: hidden;
  aspect-ratio: 1 / 1; background: var(--bg-soft);
}
.ig-card img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.ig-card:hover img { transform: scale(1.06); }
.ig-card .ig-play {
  position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,0) 55%, rgba(0,0,0,.35) 100%);
}
.ig-play svg { width: 34px; height: 34px; filter: drop-shadow(0 2px 6px rgba(0,0,0,.4)); }

/* Reseñas de Google (2026-08-20, pedido del dueño: sección de testimonios "prolija y premium" en
   el inicio). Sin fecha relativa a propósito ("hace 3 meses" envejece mal) — el sello de Google
   alcanza para que se pueda verificar sin mostrar un dato que se desactualiza solo.

   Desfile automatico continuo (feedback de Enzo viendolo en dev: el riel manual de antes quedaba
   "pegado a la izquierda"): mismo patron ya probado de .benefits-track de arriba, contenido
   DUPLICADO en el HTML (ver resenasHtml en tienda.js) y recorrido de exactamente -50%. */
.resenas-band {
  background: linear-gradient(180deg, #fff 0%, var(--brand-wash) 25%, var(--brand-wash) 60%, #fff 100%);
  padding: var(--sp-16) 0;
}
.resenas-band .section-head { margin-bottom: var(--sp-6); }
/* Promedio agregado real (2026-08-25) — mismo lugar que ocuparía un link "ver todo" en otras
   secciones (.section-head ya es flex + space-between), así no hace falta una regla de layout
   nueva. font-variant-numeric por el "4,9" y el conteo, aunque acá no cambian en vivo — mismo
   criterio del resto del sitio para cualquier dígito. */
.resenas-agregado {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: 15px; color: var(--ink-soft); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.resenas-agregado strong { color: var(--ink); font-size: 17px; }

.resenas-marquee { overflow: hidden; position: relative; }
.resenas-track { display: flex; width: max-content; animation: desfile 70s linear infinite; }
.resenas-band:hover .resenas-track { animation-play-state: paused; }
.resenas-run { display: flex; align-items: stretch; flex: 0 0 auto; gap: var(--sp-6); padding: 4px var(--sp-6) var(--sp-4) 0; }
.resenas-run > .resena-card { flex: 0 0 320px; width: 320px; }

/* Degradados en los bordes, mismo recurso que .benefits::before/after — acá el color de base es
   var(--brand-wash) (el tono que domina donde cae la fila) en vez de var(--brand). */
.resenas-marquee::before, .resenas-marquee::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 64px; z-index: 2; pointer-events: none;
}
.resenas-marquee::before { left: 0; background: linear-gradient(90deg, var(--brand-wash), rgba(234,248,254,0)); }
.resenas-marquee::after { right: 0; background: linear-gradient(270deg, var(--brand-wash), rgba(234,248,254,0)); }

@media (prefers-reduced-motion: reduce) {
  .resenas-track { animation: none; }
  .resenas-marquee { overflow-x: auto; }
  .resenas-run[aria-hidden="true"] { display: none; }
}

@media (max-width: 720px) {
  .resenas-run > .resena-card { flex-basis: 260px; width: 260px; }
  .resenas-marquee::before, .resenas-marquee::after { width: 28px; }
}

.resena-card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: var(--sp-3); height: 100%;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-5); box-shadow: var(--shadow);
  transition: transform .2s cubic-bezier(.22,.8,.28,1), box-shadow .2s ease, border-color .2s ease;
}
/* Mismo criterio que .card:hover (levantada de 4px) — consistencia con el resto del sitio. */
.resena-card:hover {
  transform: translateY(-4px);
  border-color: var(--brand);
  box-shadow: 0 4px 8px rgba(11,18,32,.06), 0 20px 40px rgba(11,18,32,.12);
}
.resena-comillas {
  position: absolute; top: -4px; right: 16px; z-index: 0; pointer-events: none; user-select: none;
  font-family: Georgia, 'Times New Roman', serif; font-size: 64px; line-height: 1; font-weight: 700;
  color: var(--brand-wash);
}
.resena-cabecera { display: flex; align-items: center; gap: 10px; }
.resena-avatar {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 14px;
}
.resena-cabecera-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.resena-nombre { font-size: 14px; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.resena-estrellas { display: flex; gap: 2px; }
.resena-texto {
  font-size: 14.5px; line-height: 1.5; color: var(--ink); flex: 1; margin: 0; position: relative;
  /* Recorta prolijo en vez de estirar la tarjeta al tamaño de la reseña más larga del grupo. */
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.resena-fuente { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--ink-soft); margin-top: auto; }
.resena-fuente svg { flex-shrink: 0; }

.riel-arrow {
  position: absolute; top: 38%; z-index: 3;
  width: 42px; height: 42px; border-radius: 50%;
  background: #fff; border: 1px solid var(--line); color: var(--ink);
  display: grid; place-items: center; cursor: pointer;
  box-shadow: 0 6px 18px rgba(11,18,32,.13);
  transition: opacity .2s, border-color .2s, transform .2s;
}
.riel-arrow:hover { border-color: var(--brand); transform: scale(1.06); }
.riel-arrow.prev { left: calc(var(--sp-6) * -1); }
.riel-arrow.next { right: calc(var(--sp-6) * -1); }
/* Desactivada y no escondida: si desaparece, el bloque salta y se pierde la referencia. */
.riel-arrow:disabled { opacity: 0; pointer-events: none; }

/* En tactil se arrastra con el dedo, pero las flechas se dejan igual: sin ellas y sin
   producto asomando no queda ninguna pista de que la fila sigue. */
@media (hover: none) { .riel-arrow { width: 36px; height: 36px; } }
@media (max-width: 1100px) {
  .riel-arrow.prev { left: 2px; }
  .riel-arrow.next { right: 2px; }
}
@media (max-width: 980px) { .riel { grid-auto-columns: calc((100% - var(--sp-4)) / 2); column-gap: var(--sp-4); } }
@media (max-width: 720px) {
  /* Las flechas se centran sobre la FOTO y no sobre el alto total del riel: con el 38% de
     escritorio caian sobre el nombre de la marca y lo tapaban. La foto es cuadrada y ocupa la
     mitad del ancho, asi que su centro esta a ~22vw del techo del riel. */
  .riel-arrow { top: calc(22vw + 12px); }

  .riel {
    grid-auto-columns: calc((100% - var(--sp-3)) / 2);
    column-gap: var(--sp-3);
    /* Sin relleno lateral: con el, la caja visible quedaba 24px mas ancha que la usada para
       calcular las columnas y asomaba el borde de una tercera tarjeta. En tactil no hay hover
       que proteger, asi que el relleno solo hacia daño. */
    padding-left: 0; padding-right: 0;
    margin-left: 0; margin-right: 0;
  }
}

/* ── Baldosas de rubro ───────────────────────────────────────────────────────
   Cortan la seguidilla de filas de producto. Tipograficas y no con foto: no hay fotos
   propias de rubro y una imagen de producto estirada de fondo se nota. */
.baldosas { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
.baldosa {
  position: relative; display: flex; flex-direction: column; gap: 6px;
  min-height: 168px; padding: var(--sp-6) var(--sp-6) var(--sp-8);
  border-radius: 18px; background: var(--ink); color: #fff;
  justify-content: flex-end; overflow: hidden;
  transition: transform .2s ease-out;
}
.baldosa::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(70% 90% at 88% 8%, rgba(53,195,240,.42) 0%, rgba(53,195,240,0) 62%);
}
.baldosa > * { position: relative; }
.baldosa:hover { transform: translateY(-3px); }
.baldosa-titulo { font-size: 22px; font-weight: 800; letter-spacing: -.025em; }
.baldosa-bajada { font-size: 14px; color: rgba(255,255,255,.72); }
.baldosa-flecha { position: absolute; top: var(--sp-6); right: var(--sp-6); opacity: .85; }
/* La del taller va en celeste con texto oscuro: el celeste de marca no tiene contraste
   suficiente como color de texto, si como fondo. */
.baldosa.is-brand { background: var(--brand); color: var(--ink); }
.baldosa.is-brand::before { background: radial-gradient(70% 90% at 88% 8%, rgba(255,255,255,.5) 0%, rgba(255,255,255,0) 62%); }
.baldosa.is-brand .baldosa-bajada { color: rgba(11,18,32,.7); }

/* ── Franja del taller ───────────────────────────────────────────────────────
   Es lo que nos diferencia de cualquier tienda de bicis online, asi que tiene lugar
   propio en el inicio en vez de quedar escondido en el pie. */
.taller {
  display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--sp-8);
  align-items: center; padding: var(--sp-12);
  background: var(--brand-wash); border: 1px solid rgba(53,195,240,.4); border-radius: 22px;
}
.taller-copy h2 { font-size: 28px; margin: 0 0 var(--sp-3); letter-spacing: -.03em; }
.taller-copy p { color: var(--ink-soft); font-size: 15.5px; line-height: 1.6; margin: 0 0 var(--sp-6); max-width: 46ch; }
.taller-puntos { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.taller-puntos li { display: grid; gap: 2px; padding-left: var(--sp-4); border-left: 3px solid var(--brand); }
.taller-puntos strong { font-size: 15px; }
.taller-puntos span { font-size: 13.5px; color: var(--ink-soft); }

@media (max-width: 980px) {
  .baldosas { grid-template-columns: 1fr; }
  .baldosa { min-height: 132px; }
  .taller { grid-template-columns: 1fr; padding: var(--sp-8) var(--sp-6); gap: var(--sp-6); }
  .taller-copy h2 { font-size: 23px; }
  .taller-copy .btn { width: 100%; }
}

/* ── Categorias ───────────────────────────────────────────────────────────────
   Antes eran seis cajas grises con un nombre adentro: correcto pero muerto. Ahora cada una
   lleva una foto real de un producto del rubro (la elige el servidor) sobre un halo de marca,
   y la flecha se desplaza al pasar el mouse. La foto es lo que le da vida — es informacion,
   no decoracion: de un vistazo se entiende que hay en cada rubro. */
.cats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
.cat {
  position: relative; display: flex; align-items: center; gap: var(--sp-4);
  background: var(--bg-soft); border-radius: 16px; padding: var(--sp-4) var(--sp-5);
  border: 1.5px solid transparent; overflow: hidden;
  transition: border-color .18s, transform .18s, background .18s, box-shadow .18s;
}
.cat::before {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(60% 100% at 8% 50%, rgba(53,195,240,.18) 0%, rgba(53,195,240,0) 70%);
  opacity: 0; transition: opacity .22s;
}
.cat > * { position: relative; }
.cat:hover {
  border-color: var(--brand); background: #fff;
  transform: translateY(-3px); box-shadow: 0 12px 28px rgba(11,18,32,.10);
}
.cat:hover::before { opacity: 1; }

.cat-foto {
  flex: 0 0 auto; width: 62px; height: 62px; border-radius: 12px;
  background: #fff; border: 1px solid var(--line);
  display: grid; place-items: center; overflow: hidden;
}
.cat-foto img {
  width: 100%; height: 100%; object-fit: contain; padding: 6px;
  transition: transform .25s cubic-bezier(.22,.8,.28,1);
}
.cat:hover .cat-foto img { transform: scale(1.08); }

.cat-texto { display: grid; gap: 2px; min-width: 0; }
.cat-texto strong { font-size: 15px; letter-spacing: -.01em; }
.cat-texto span { font-size: 12.5px; color: var(--ink-soft); }

.cat-flecha {
  margin-left: auto; flex: 0 0 auto; color: var(--ink-soft);
  display: grid; place-items: center;
  transition: transform .22s, color .22s;
}
.cat:hover .cat-flecha { color: var(--brand-deep); transform: translateX(4px); }

/* ── Listado ────────────────────────────────────────────────────────────────── */
.listing { display: grid; grid-template-columns: 232px 1fr; gap: var(--sp-12); align-items: start; }
/* Bug real reportado 2026-08-28: con las subcategorias (LUCES, Rodado 29, etc.) la lista de
   filtros quedo mas alta que antes, y en pantallas de menos de 1080px de alto el sticky la
   empujaba fuera de la vista sin forma de scrollearla aparte — habia que scrollear la pagina
   ENTERA hasta el pie para ver las ultimas opciones. max-height + overflow-y le da su propio
   scroll interno cuando no entra completa, sin tocar el resto del layout. */
.filters {
  position: sticky; top: 96px; display: grid; gap: var(--sp-6);
  max-height: calc(100vh - 116px); overflow-y: auto; padding-right: 4px; padding-bottom: var(--sp-4);
  scrollbar-width: thin;
}
.filter-group h3 { font-size: 11.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-soft); margin: 0 0 var(--sp-3); }
.filter-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.filter-group a { font-size: 14.5px; color: var(--ink-soft); }
.filter-group a:hover { color: var(--brand-deep); }
.filter-group a.is-active { color: var(--ink); font-weight: 700; }

/* Chips de categoria: SOLO en mobile. Reemplazan la lista larga de filtros para que los
   productos se vean sin tener que scrollear media pantalla (pedido del dueño). */
.chips { display: none; }

.listing-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-6); flex-wrap: wrap; }
.listing-head h1 { font-size: 28px; margin: 0; letter-spacing: -.025em; }
.listing-head .count { font-size: 14px; color: var(--ink-soft); margin: 4px 0 0; }
select {
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); padding: 10px 13px;
  font-size: 15px; font-family: inherit; color: inherit; background: #fff; cursor: pointer;
}
select:hover { border-color: var(--ink); }

/* ── Ficha ──────────────────────────────────────────────────────────────────── */
.detail { display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--sp-12); align-items: start; }
.gallery-main { background: var(--bg-soft); border-radius: 20px; aspect-ratio: 1 / 1; overflow: hidden; }
.gallery-main img { width: 100%; height: 100%; object-fit: contain; padding: var(--sp-6); }
.gallery-main video { width: 100%; height: 100%; object-fit: contain; background: #000; }
.thumbs { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); flex-wrap: wrap; }
.thumb {
  width: 70px; height: 70px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg-soft); border: 2.5px solid transparent; cursor: pointer; padding: 0;
  position: relative;
}
.thumb.is-active { border-color: var(--brand); }
.thumb img, .thumb video { width: 100%; height: 100%; object-fit: contain; padding: 6px; }
/* Video en la galeria de producto (2026-08-18): sin generador de miniaturas (no hay ffmpeg en el
   proyecto), preload="metadata" ya alcanza para que el navegador muestre el primer frame solo. */
.thumb-play {
  position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none;
  background: rgba(0, 0, 0, .18);
}
.thumb-play svg { width: 20px; height: 20px; filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .5)); }

.detail h1 { font-size: 32px; line-height: 1.18; margin: var(--sp-2) 0 var(--sp-4); letter-spacing: -.03em; }
.detail .price-main { font-size: 36px; }
.detail-buy { display: flex; gap: var(--sp-3); margin: var(--sp-6) 0; flex-wrap: wrap; }
.detail-shipping { display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 700; color: var(--ink-soft); margin: 0 0 var(--sp-6); }
.detail-shipping svg { flex-shrink: 0; color: var(--ok); }
.stock-line { font-size: 14.5px; font-weight: 700; }
.stock-line.ok { color: var(--ok); }
.stock-line.out { color: var(--ink-soft); }
/* Selector de talle/color de la ficha (pedido del dueño 2026-08-11). */
.variant-group { margin: var(--sp-5) 0; }
.variant-group-label { font-size: 13px; font-weight: 700; color: var(--ink); margin: 0 0 var(--sp-2); }
.variant-group-label .variant-value-selected { font-weight: 400; color: var(--ink-soft); }
.variant-options { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.variant-btn {
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); padding: 9px 16px;
  font-size: 14px; font-family: inherit; background: #fff; color: var(--ink); cursor: pointer;
}
.variant-btn:hover:not(:disabled) { border-color: var(--ink); }
.variant-btn.is-selected { border-color: var(--brand); background: var(--brand-wash); color: var(--brand-deep); font-weight: 700; }
/* Combinacion sin stock: se ve, no se puede elegir — no desaparece del todo (pedido del dueño). */
.variant-btn:disabled {
  color: var(--ink-soft); border-color: var(--line); background: var(--bg-soft);
  cursor: not-allowed; text-decoration: line-through; opacity: .65;
}
.variant-hint { font-size: 13.5px; color: var(--ink-soft); margin: var(--sp-2) 0 0; }
/* .btn:disabled cubre los <button> (los del selector no llegan a ser <a>); .is-disabled cubre
   el <a> de "Comprar por WhatsApp", que no acepta el atributo disabled nativo de HTML. */
.btn:disabled, .btn.is-disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
.btn:disabled:hover, .btn.is-disabled:hover { transform: none; }

.detail-desc { margin-top: var(--sp-8); padding-top: var(--sp-6); border-top: 1px solid var(--line); }
.detail-desc h3 { font-size: 15px; margin: 0 0 var(--sp-3); }
.detail-desc p { color: var(--ink-soft); font-size: 15px; line-height: 1.7; white-space: pre-line; margin: 0; }
.detail-desc > * + * { margin-top: var(--sp-4); }
.crumbs { font-size: 13px; color: var(--ink-soft); margin-bottom: var(--sp-2); }
.crumbs a:hover { color: var(--brand-deep); }

/* ── Estados ────────────────────────────────────────────────────────────────── */
.empty { text-align: center; padding: var(--sp-16) var(--sp-4); color: var(--ink-soft); }
.skeleton { background: var(--bg-soft); border-radius: var(--radius); animation: pulse 1.3s ease-in-out infinite; }
.skeleton.card-media { aspect-ratio: 1/1; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .55; } }

/* Boton flotante de WhatsApp (pedido del dueño 2026-08-11): visible en cualquier pagina de la
   tienda, no solo en la ficha de producto. Vive fuera de #view en index.html — es parte del
   shell estatico, no algo que arme cada render. */
.whatsapp-fab {
  position: fixed; right: var(--sp-5); bottom: calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-fab);
  width: 58px; height: 58px; border-radius: 50%;
  background: #25d366; color: #fff; display: grid; place-items: center;
  box-shadow: 0 6px 20px rgba(11, 18, 32, .28);
  transition: transform .15s ease, box-shadow .15s ease;
}
.whatsapp-fab:hover { transform: scale(1.07); box-shadow: 0 10px 26px rgba(11, 18, 32, .34); }
@media (max-width: 640px) {
  .whatsapp-fab {
    right: var(--sp-4); bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
    width: 52px; height: 52px;
  }
  /* El toast se sube por ENCIMA del boton flotante (2026-08-21). En celular ocupa casi todo el
     ancho, asi que a la altura de siempre le pasaba justo por atras al circulo de WhatsApp. La
     cuenta sale de la regla de arriba: 52px de alto + su separacion del borde + 12px de aire. */
  .store-toast { bottom: calc(var(--sp-4) + 52px + 12px + env(safe-area-inset-bottom, 0px)); }
}

/* ── Pie ────────────────────────────────────────────────────────────────────── */
.footer { background: var(--bg-soft); margin-top: var(--sp-16); padding: var(--sp-12) var(--sp-4); border-top: 3px solid var(--brand); }
.footer-inner { max-width: var(--max); margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--sp-8); font-size: 14.5px; color: var(--ink-soft); }
.footer-brand { font-weight: 800; letter-spacing: .12em; color: var(--ink); margin: 0 0 var(--sp-2); }
.footer-title { font-weight: 700; color: var(--ink); margin: 0 0 var(--sp-2); }
.footer p { margin: 0 0 6px; }
.footer-social { display: flex; gap: var(--sp-3); margin-top: var(--sp-3); }
.footer-social a { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 10px; background: #fff; border: 1px solid var(--line); color: var(--ink); }
.footer-social a:hover { border-color: var(--brand); color: var(--brand-deep); }
.footer-list { list-style: none; margin: 0; padding: 0; }
.footer-list li { margin-bottom: 6px; }
/* Barra legal: en Argentina el boton de arrepentimiento y el enlace a Defensa del Consumidor
   son obligatorios para vender online, y Tiendanube ya los tiene. */
.footer-legal {
  max-width: var(--max); margin: var(--sp-8) auto 0; padding-top: var(--sp-6);
  border-top: 1px solid var(--line); font-size: 13px; color: var(--ink-soft);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-5);
}
.footer-legal a { color: var(--brand-deep); font-weight: 600; }
.footer-legal .sep { color: var(--ink-soft); opacity: .5; }
/* El sello fiscal se va al extremo para que no compita con los enlaces legales. */
.footer-fiscal { margin-left: auto; display: inline-flex; }
.footer-fiscal img { height: 54px; width: auto; display: block; }
.footer a:hover { color: var(--brand-deep); }

/* ── Responsive ─────────────────────────────────────────────────────────────── */
/* Respeta a quien pidio menos animacion en el sistema. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .card:hover .card-media img { transform: none; }
  .btn:hover { transform: none; }
  .whatsapp-fab:hover { transform: none; }
}

/* ── Movimiento de entrada ────────────────────────────────────────────────────
   Regla de la guia: pocas animaciones, cortas, solo transform/opacity, y con escalonado
   de 30-50ms entre items. Nada decorativo: la entrada escalonada guia el ojo por la
   grilla en el orden en que se lee. */
.reveal { opacity: 0; transform: translate3d(0, 18px, 0); }
.reveal.is-in { opacity: 1; transform: none; transition: opacity .5s ease-out, transform .5s cubic-bezier(.22,.8,.28,1); }

.grid.is-in .card { animation: cardIn .45s cubic-bezier(.22,.8,.28,1) both; }
.grid.is-in .card:nth-child(1) { animation-delay: .00s; }
.grid.is-in .card:nth-child(2) { animation-delay: .04s; }
.grid.is-in .card:nth-child(3) { animation-delay: .08s; }
.grid.is-in .card:nth-child(4) { animation-delay: .12s; }
.grid.is-in .card:nth-child(5) { animation-delay: .16s; }
.grid.is-in .card:nth-child(6) { animation-delay: .20s; }
.grid.is-in .card:nth-child(7) { animation-delay: .24s; }
.grid.is-in .card:nth-child(8) { animation-delay: .28s; }
@keyframes cardIn { from { opacity: 0; transform: translate3d(0, 14px, 0); } to { opacity: 1; transform: none; } }

/* Levantada sutil de la tarjeta: da sensacion de material sin mover el layout. */
.card { transition: transform .2s cubic-bezier(.22,.8,.28,1); }
.card:hover { transform: translateY(-4px); }

@media (max-width: 980px) {
  /* Tarjeta partida (2026-08-28): en mobile las dos mitades no entran lado a lado, apiladas una
     debajo de la otra. El layout interno de cada mitad (foto flex arriba, texto abajo, controles
     pegados al contenido) es el MISMO que en escritorio — la tarjeta partida ya deja cada mitad
     angosta de por si, no hace falta una composicion aparte para mobile, solo apilarlas. */
  .hero-inner { height: auto; grid-template-columns: 1fr; }
  .hero-panel-productos { height: 500px; }
  /* 300 -> 330: la fila de controles puede pasar a dos lineas aca (dots+flechas / boton, ver
     .hero-panel-taller .hero-panel-footer mas arriba) y necesita el lugar de sobra. */
  .hero-panel-taller { border-left: none; border-top: 1px solid var(--line); height: 330px; }
  .hero-cta .btn.ghost-dark { display: none; }

  /* La franja de beneficios se iba a dos lineas y quedaba cortada: en mobile pasa a una
     sola linea que se desliza. */
  .benefits {
    justify-content: center; flex-wrap: wrap;
    gap: 6px var(--sp-3); font-size: 11.5px; line-height: 1.5;
  }
  .benefits::-webkit-scrollbar { display: none; }
  .benefits span { white-space: nowrap; }

  .detail { grid-template-columns: 1fr; gap: var(--sp-8); }

  /* Los filtros de escritorio se ocultan y entran los chips: asi los productos quedan
     arriba y no hay que scrollear la lista entera de categorias. */
  .listing { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
  .filters { display: none; }
  .chips {
    display: flex; gap: var(--sp-2); overflow-x: auto; min-width: 0; padding-bottom: var(--sp-2);
    margin-bottom: var(--sp-4); scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .chips::-webkit-scrollbar { display: none; }
  .chip {
    flex: 0 0 auto; padding: 10px 16px; border-radius: 999px;
    background: var(--bg-soft); border: 1.5px solid transparent;
    font-size: 14px; font-weight: 600; color: var(--ink-soft); white-space: nowrap;
    min-height: 44px; display: inline-flex; align-items: center;
  }
  .chip.is-active { background: var(--brand); border-color: var(--brand); color: var(--ink); font-weight: 700; }
}

/* Bug real reportado 2026-08-13: con 7 items de nav + logo + lupita + cuenta, a un ancho de
   ventana "laptop sin maximizar" (aprox 900-1023px) el nav ya no entraba en una sola linea y
   se partia en dos ("Taller" quedaba solo, colgado) — quedaba roto, no es un wrap prolijo.
   El colapso a hamburguesa se sube de 720px a 1024px: mejor perder el nav horizontal un poco
   antes que dejarlo partirse a la mitad. Las reglas de tipografia/grillas mas abajo (720px) no
   se tocan — esas si son ajustes genuinamente de celular chico, no del ancho del nav. */
@media (max-width: 1024px) {
  .nav { display: none; }
  .nav.is-open {
    display: flex; position: absolute; top: 100%; left: 0; right: 0;
    background: #fff; border-bottom: 1px solid var(--line);
    flex-direction: column; gap: 0; padding: var(--sp-2) var(--sp-4) var(--sp-4);
    max-height: 70vh; overflow-y: auto;
  }
  .nav.is-open a { min-height: 48px; display: flex; align-items: center; border-bottom: 1px solid var(--line); }
  /* En el menu mobile ya es vertical, de a un item por renglon — no hace falta "ahorrar espacio"
     ahi, así que "Mas" se muestra siempre abierto como dos links normales (el trigger se oculta).
     El inert lo saca solo el JS de renderNav via matchMedia, viendo este mismo breakpoint. */
  .nav-more-trigger { display: none; }
  .nav-more-dropdown {
    position: static; opacity: 1; pointer-events: auto; transform: none;
    box-shadow: none; border: 0; border-radius: 0; padding: 0; min-width: 0;
  }
  .nav-more-dropdown a {
    padding: 0; min-height: 48px; display: flex; align-items: center;
    border-bottom: 1px solid var(--line); border-radius: 0;
  }
  /* #menuToggle, no .icon-btn: el hamburguesa es el UNICO icon-btn que sigue oculto en escritorio
     (ver regla base) — los demas (buscador, cuenta) ya son visibles siempre. Un selector de ID le
     gana en especificidad al `#menuToggle { display:none }` de la regla base sin depender del
     orden de aparicion en el archivo. */
  #menuToggle { display: grid; min-width: 44px; min-height: 44px; }
}

@media (max-width: 720px) {
  /* 16px es el minimo real: por debajo, iOS hace zoom solo al enfocar y descoloca la pagina. */
  .search input { font-size: 16px; width: 100%; min-width: 0; }
  /* Buscador en su PROPIO renglon, de borde a borde (2026-08-21). Toda la historia de abajo fue
     un intento de repartir UN solo renglon entre logo, buscador e iconos — y el reparto siempre
     terminaba mal porque en 390px no hay ancho para los tres:
       1) flex:1 1 auto sin techo dejaba que el buscador creciera de mas y empujaba carrito/cuenta/
          menu fuera del area visible (el overflow-x:clip del body los tapaba, sin barra de scroll
          que delatara el desborde).
       2) max-width:calc(100% - 156px) no alcanzo: el % de un item flex se resuelve contra
          .topbar-actions, que era OTRO flex:1 1 auto — numero equivocado.
       3) max-width:calc(100vw - 190px) tampoco: ese presupuesto restaba los iconos y se olvidaba
          del LOGO (~123px), que vive en el mismo topbar-inner.
       4) flex-basis:0 (el arreglo que quedo hasta hoy) reparte BIEN, pero el reparto correcto de
          390px eran ~67px de buscador: una cajita con "Bu" adentro y nada mas (captura de Enzo,
          2026-08-21). Correcto por dentro, inservible por fuera.
     La salida no era repartir mejor sino dejar de repartir: el buscador baja a un renglon propio
     (order lo manda al final + flex-basis:100% fuerza el salto) y se queda con los 358px enteros.
     Logo e iconos se quedan solos arriba, con lugar de sobra. Es lo que hace Mercado Libre —la
     referencia visual pedida para la tienda— en su header de celular. */
  .topbar-inner { gap: var(--sp-3); flex-wrap: wrap; row-gap: var(--sp-3); }
  .search { order: 4; flex: 1 0 100%; }
  .search button { min-width: 44px; min-height: 44px; }
  .brand img { height: 50px; }

  /* .resenas-agregado (badge de "4,9 · 709 opiniones", 2026-08-25) apretaba el título a 4
     renglones angostos y el badge se cortaba afuera del viewport — .section-head es
     space-between sin wrap, pensado para un link corto tipo "Ver todo", no para un texto largo
     al lado. Apilado en vertical en vez de lado a lado: título con el ancho completo, badge
     debajo con su propio renglón (confirmado con captura real a 390px, no a ojo). */
  .resenas-band .section-head { flex-direction: column; align-items: flex-start; gap: var(--sp-2); }
  .resenas-agregado { white-space: normal; font-size: 14px; }

  .benefits { font-size: 12px; padding: 10px var(--sp-4); }
  .section { margin: var(--sp-12) auto; }
  .section-head h2, .listing-head h1, .detail h1 { font-size: 23px; }

  /* minmax(0, 1fr) y no 1fr: 1fr no permite que la columna baje del ancho de su palabra
     mas larga, y en pantallas de 320px eso desbordaba la pagina. */
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-3); }
  .card-title { font-size: 13.5px; }
  /* Siempre en dos renglones: entraba en uno o en dos segun el largo del importe y las dos
     tarjetas de la fila quedaban con distinta forma. */
  /* Cuotas y transferencia SIEMPRE en dos renglones: segun el largo del importe entraban en
     uno o en dos, y dos tarjetas de la misma fila quedaban con distinta forma. */
  .price-inst span, .price-transfer span { display: block; }
  .price-main { font-size: 17px; }
  .detail .price-main { font-size: 30px; }

  .btn { min-height: 48px; padding: 14px 24px; }
  .detail-buy { flex-direction: column; align-items: stretch; }
  .detail-buy .btn { width: 100%; }
  .thumb { width: 58px; height: 58px; }

  /* UNA sola columna: con dos, "SERVICE & REPARACION" no entra de ninguna manera y el nombre
     terminaba partido al medio. */
  .cats { grid-template-columns: 1fr; }
  /* La columna de navegacion del pie repite lo que ya esta en el menu de arriba y en el bloque
     de categorias. Apilada en celular solo alarga un pie que ya es largo. */
  .footer-nav { display: none; }
  /* Apilados en una columna, los separadores quedan colgando al final de cada linea. */
  .footer-legal { flex-direction: column; align-items: flex-start; gap: var(--sp-3); }
  .footer-legal .sep { display: none; }
  .footer-fiscal { margin: var(--sp-2) 0 0; }
}

/* Sin movimiento para quien lo pidio en su sistema: se ve todo, sin animar nada. */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .grid.is-in .card,
  .hero-slide.is-active .hero-media img,
  .hero-slide.is-active .hero-copy > * { animation: none; }
  .card:hover,
  .resena-card:hover { transform: none; }
}

/* ── Reflector que sigue al cursor ─────────────────────────────────────────────
   El recurso de Vercel: una luz difusa que acompaña al mouse. Se dibuja en una capa
   propia con `mix-blend-mode` para que ilumine el fondo sin lavar el texto ni la foto.
   Las coordenadas llegan por variables CSS que actualiza el JS, asi el navegador solo
   repinta esta capa y no recalcula el layout. */
.spotlight {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity .35s ease-out;
  background: radial-gradient(
    260px circle at var(--mx, 50%) var(--my, 50%),
    rgba(53, 195, 240, .32) 0%,
    rgba(53, 195, 240, .10) 45%,
    transparent 70%
  );
}
.hero-inner:hover .spotlight { opacity: 1; }

/* Borde que se enciende del lado por donde pasa el mouse. */
.hero-inner { transition: border-color .3s; }
.hero-inner:hover { border-color: rgba(53, 195, 240, .55); }

/* Brillo que barre el boton principal al pasar por encima. */
.btn.on-dark { position: relative; overflow: hidden; }
.btn.on-dark::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 45%;
  left: -60%; transform: skewX(-20deg);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.28), transparent);
}
.btn.on-dark:hover::after { animation: sweep .65s ease-out; }
@keyframes sweep { to { left: 130%; } }

/* Las tarjetas tambien reciben un halo suave del lado del cursor. */
.card-media { --mx: 50%; --my: 50%; }
.card-media::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity .3s ease-out;
  background: radial-gradient(180px circle at var(--mx) var(--my), rgba(53,195,240,.18), transparent 65%);
}
.card:hover .card-media::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .spotlight, .card-media::after { display: none; }
  .btn.on-dark:hover::after { animation: none; }
}

/* En tactil no hay cursor: no tiene sentido pagar el costo de estos efectos. */
@media (hover: none) {
  .spotlight, .card-media::after { display: none; }
}

/* "Ultimas 2": urgencia honesta, sale del stock real del catalogo. Va abajo a la izquierda
   para no pelearse con el cartel de descuento, que va arriba. */
.tag.last {
  top: auto; bottom: var(--sp-3); left: var(--sp-3);
  background: var(--ink); color: #fff;
}

/* ── Carrito / Checkout / Cuenta (2026-08-13) ───────────────────────────────── */
.cart-layout, .checkout-layout, .account-layout {
  display: grid; grid-template-columns: 1fr 320px; gap: var(--sp-8); align-items: start;
}
@media (max-width: 860px) {
  .cart-layout, .checkout-layout, .account-layout { grid-template-columns: 1fr; }
}

.cart-items { display: flex; flex-direction: column; gap: var(--sp-4); }
/* Selección parcial + miniatura por linea (2026-08-14, referencia Mercado Libre). Las dos
   columnas nuevas (checkbox y foto) van al principio, con ancho fijo. */
.cart-selectall {
  display: flex; align-items: center; gap: var(--sp-2); font-weight: 700; font-size: 14.5px;
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm); cursor: pointer;
}
.cart-line-media {
  width: 56px; height: 56px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg-soft); display: grid; place-items: center; flex-shrink: 0;
}
.cart-line-media img { width: 100%; height: 100%; object-fit: contain; }
/* Foto y nombre linkean a la ficha del producto (2026-08-14). Son DOS <a> separados pero tienen
   que comportarse como una sola cosa clickeable: parandose en la foto se resalta tambien el
   texto, y al reves. Eso se logra con :has() sobre la linea; sin esto el cliente pasaba el mouse
   por la foto y nada le indicaba que tambien era un link (reporte del dueño). Sin subrayado:
   ensucia la linea y el cambio de color ya alcanza como señal. */
.cart-line-name { font-size: 14.5px; font-weight: 700; color: var(--ink); text-decoration: none; }
.cart-line-name:hover,
.cart-line:has(a.cart-line-media:hover) .cart-line-name { color: var(--brand-deep); }
a.cart-line-media:hover,
.cart-line:has(.cart-line-name:hover) a.cart-line-media { outline: 2px solid var(--brand); outline-offset: 2px; }
.cart-line {
  display: grid; grid-template-columns: auto auto 1fr auto auto auto; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.cart-line.is-unavailable { opacity: .55; }
.cart-line-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cart-line-info strong { font-size: 14.5px; }
.cart-line-info small { color: var(--ink-soft); font-size: 12.5px; }
.cart-line-warning { color: #b3261e !important; font-weight: 700; }
.cart-line-qty {
  display: flex; align-items: center; gap: var(--sp-2);
  background: var(--bg-soft); border-radius: 999px; padding: 4px;
}
.cart-qty-btn {
  width: 30px; height: 30px; border-radius: 50%; border: 0; background: #fff; cursor: pointer;
  font-size: 16px; font-weight: 700; color: var(--ink); box-shadow: 0 1px 2px rgba(11,18,32,.08);
}
.cart-line-qty span { min-width: 20px; text-align: center; font-weight: 700; }
/* El precio de lista tachado (si hay oferta) va arriba del que se cobra, en su propio renglon. */
.cart-line-total { font-weight: 800; white-space: nowrap; text-align: right; }
.cart-line-total .price-was { display: block; font-weight: 600; }
.cart-line-remove {
  width: 36px; height: 36px; border-radius: 50%; border: 0; background: none; cursor: pointer;
  color: var(--ink-soft); display: grid; place-items: center;
}
.cart-line-remove:hover { background: var(--bg-soft); color: #b3261e; }
@media (max-width: 560px) {
  .cart-line {
    grid-template-columns: auto auto 1fr auto;
    grid-template-areas: "check media info remove" "qty qty total total";
  }
  .cart-line-check { grid-area: check; }
  .cart-line-media { grid-area: media; }
  .cart-line-info { grid-area: info; }
  .cart-line-remove { grid-area: remove; }
  .cart-line-qty { grid-area: qty; }
  .cart-line-total { grid-area: total; text-align: right; }
}

/* Resumen de compra: cupon + descuento (2026-08-14, referencia Mercado Libre). */
.cart-summary-title { font-size: 16px; margin: 0 0 var(--sp-2); }
.cart-coupon { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
.cart-coupon input {
  flex: 1 1 0; min-width: 0; border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  padding: 9px var(--sp-3); font: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
}
.cart-coupon-msg { font-size: 12.5px; margin: 4px 0 0; min-height: 16px; }
.cart-coupon-msg.is-ok { color: var(--ok); font-weight: 700; }
.cart-coupon-msg.is-error { color: #b3261e; font-weight: 700; }
.cart-discount-row { color: var(--ok); font-weight: 700; }
.cart-discount-row[hidden] { display: none; }

.cart-summary {
  position: sticky; top: calc(var(--sp-16) + 8px);
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.cart-summary-row { display: flex; justify-content: space-between; gap: var(--sp-3); font-size: 14px; color: var(--ink-soft); }
/* CVU/Alias con boton de copiar (2026-08-28) — el valor no se corta ni empuja el boton afuera en
   mobile: min-width:0 en el contenedor + el texto puede romper si un CVU de 22 numeros no entra. */
.cart-summary-row-copy > span:last-child { min-width: 0; }
.copy-value { display: flex; align-items: center; gap: 8px; font-weight: 700; color: var(--ink); }
.copy-value > span:first-child { overflow-wrap: anywhere; text-align: right; }
.copy-btn {
  flex: 0 0 auto; display: grid; place-items: center; width: 26px; height: 26px;
  border: 1.5px solid var(--line); border-radius: 6px; background: var(--bg);
  color: var(--ink-soft); cursor: pointer; transition: border-color .15s, color .15s, background .15s;
}
.copy-btn:hover { border-color: var(--brand-deep); color: var(--brand-deep); }
.copy-btn.is-copied { border-color: var(--ok); color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }
.cart-summary-total { padding-top: var(--sp-3); margin-top: var(--sp-2); border-top: 1px solid var(--line); font-size: 16px; color: var(--ink); }
.cart-checkout-btn { text-align: center; margin-top: var(--sp-2); }

.checkout-form { display: flex; flex-direction: column; gap: var(--sp-6); }
/* Mismo bug real ya documentado arriba para .icon-btn (2026-08-13): [hidden] del navegador y esta
   clase empatan en especificidad (0,1,0), asi que .checkout-form ganaba y el formulario de agregar
   domicilio quedaba SIEMPRE visible aunque tuviera el atributo hidden puesto — reportado por el
   dueño 2026-08-14, "el boton de agregar domicilio no tiene sentido si abajo esta todo". No era
   el boton: era este mismo bug de siempre, en un lugar nuevo. */
.checkout-form[hidden] { display: none; }
.checkout-block { display: flex; flex-direction: column; gap: var(--sp-3); }
.checkout-block h2, .account-layout h2 { font-size: 17px; margin: 0; }
/* Sub-título dentro de un mismo checkout-block (2026-08-19: "Persona que pagará el pedido", el
   sub-formulario que aparece al destildar "mis datos son los mismos" en Facturación) — un
   escalón mas chico que el h2 del bloque, no es una sección nueva. */
.checkout-block-subtitle { font-size: 14.5px; font-weight: 700; color: var(--ink); margin: 0; }
.checkout-hint { font-size: 13px; color: var(--ink-soft); margin: 0; }
.checkout-radio { display: flex; align-items: center; gap: var(--sp-2); font-weight: 600; font-size: 14.5px; cursor: pointer; }
.link-btn { background: none; border: 0; color: var(--brand-deep); font-weight: 700; font-size: inherit; cursor: pointer; padding: 0; }
.checkout-submit { margin-top: var(--sp-2); }

/* ── Checkout en 2 pasos (2026-08-14, referencia Mercado Libre) ───────────────────────────── */
.checkout-pasos {
  display: flex; gap: var(--sp-6); list-style: none; padding: 0;
  margin: 0 0 var(--sp-5); font-size: 14px; font-weight: 700; color: var(--ink-soft);
}
.checkout-pasos li { display: flex; align-items: center; gap: var(--sp-2); }
.checkout-pasos span {
  width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--bg-soft); color: var(--ink-soft); font-size: 12.5px;
}
.checkout-pasos .is-actual { color: var(--ink); }
.checkout-pasos .is-actual span { background: var(--ink); color: #fff; }
.checkout-pasos .is-hecho span { background: var(--ok); color: #fff; }

/* Dos botones grandes en vez de radios chiquitos: la forma de entrega es la decision principal
   de esta pantalla y merece el peso visual. */
.entrega-opciones { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.entrega-opcion, .direccion-opcion {
  display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  border: 1.5px solid var(--line); border-radius: var(--radius-sm); padding: var(--sp-3) var(--sp-4);
  background: var(--bg); font: inherit; color: var(--ink);
}
.entrega-opcion strong, .direccion-opcion strong { font-size: 14.5px; }
.entrega-opcion small, .direccion-opcion small { font-size: 12.5px; color: var(--ink-soft); }
.entrega-opcion.is-selected, .direccion-opcion.is-selected {
  border-color: var(--brand-deep); box-shadow: inset 0 0 0 1px var(--brand-deep);
}
.entrega-opcion.is-selected small { color: var(--ok); font-weight: 700; }
.entrega-opcion:hover, .direccion-opcion:hover { border-color: var(--ink-soft); }

.direccion-elegir, .retiro-opciones { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
/* Formulario de domicilio nuevo dentro del checkout: los mismos campos separados que "Mis
   domicilios" (2026-08-14). Antes era una sola linea de texto libre, imposible de validar. */
.checkout-direccion-form { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-4); }

/* Tarjeta de "lo que ya elegiste" (direccion o sucursal) con su link para cambiarlo. */
.checkout-elegido {
  display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-3);
  border: 1.5px solid var(--brand-deep); border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-4); margin-top: var(--sp-3);
}
.checkout-elegido strong { display: block; font-size: 14.5px; }
.checkout-elegido small { display: block; font-size: 12.5px; color: var(--ink-soft); margin-top: 2px; }
.checkout-horario { margin-top: var(--sp-3); }
.checkout-gratis { color: var(--ok); font-weight: 700; }

.medios-pago { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); font-size: 14px; color: var(--ink-soft); }
.medios-pago li { margin-bottom: 4px; }

/* Resumen con miniatura por producto (antes era solo una linea de texto). */
.checkout-resumen-item {
  display: grid; grid-template-columns: 44px 1fr auto; gap: var(--sp-3); align-items: center;
  padding-bottom: var(--sp-3); margin-bottom: var(--sp-3); border-bottom: 1px solid var(--line);
}
.checkout-resumen-media {
  width: 44px; height: 44px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--bg-soft); display: grid; place-items: center;
}
.checkout-resumen-media img { width: 100%; height: 100%; object-fit: contain; }
.checkout-resumen-info { display: flex; flex-direction: column; min-width: 0; font-size: 13.5px; }
.checkout-resumen-info small { color: var(--ink-soft); font-size: 12px; }
.checkout-resumen-precio { font-weight: 700; font-size: 13.5px; white-space: nowrap; }

@media (max-width: 560px) {
  .entrega-opciones { grid-template-columns: 1fr; }
}

.checkout-confirm { max-width: 480px; margin: 0 auto; text-align: center; }
.checkout-confirm h1 { font-size: 26px; }
.checkout-confirm.is-ok h1 { color: var(--ok); }
.checkout-confirm.is-error h1 { color: #b3261e; }
.checkout-confirm-number { color: var(--ink-soft); font-weight: 700; margin-bottom: var(--sp-5); }
.checkout-confirm .cart-summary { margin: var(--sp-5) 0; text-align: left; position: static; }
.checkout-confirm .btn { margin-top: var(--sp-2); width: 100%; }
/* Mensaje tras apretar "Ya transferí" (2026-08-28) — mismo verde que .checkout-confirm.is-ok h1,
   para que se sienta como un paso cumplido, no como un texto mas. */
.checkout-confirm-ok { color: var(--ok); font-weight: 700; font-size: 15px; margin: 0 0 var(--sp-2); }

.pedido-card { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: var(--sp-4); margin-bottom: var(--sp-3); }
.pedido-card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--sp-2); }
.pedido-status {
  font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  padding: 4px 10px; border-radius: 999px; background: var(--bg-soft); color: var(--ink-soft);
}
.pedido-status-approved { background: color-mix(in srgb, var(--ok) 16%, white); color: var(--ok); }
.pedido-status-rejected, .pedido-status-cancelled { background: #fbe9e7; color: #b3261e; }
.pedido-card-total { font-weight: 800; margin: var(--sp-2) 0 0; }

/* Domicilios guardados (pedido del dueño 2026-08-14, referencia: Mercado Libre) — tarjeta
   compacta con menu de "..." en vez de un formulario repetido en cada una. */
.direccion-card {
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: var(--sp-4);
  margin-bottom: var(--sp-3);
}
.direccion-card-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-3); }
.direccion-card-info strong { font-size: 14.5px; }
.direccion-card-info p { margin: 2px 0 0; }
/* Pedido del dueño 2026-08-14 (misma tarde): "por las dudas quitemos el tipo de domicilio" — se
   saco el tag Residencial/Laboral del formulario y la tarjeta, queda solo el de predeterminada. */
.direccion-tag-default { font-size: 12px; color: var(--ok); font-weight: 700; }

.direccion-menu { position: relative; flex-shrink: 0; }
.direccion-menu-btn {
  width: 32px; height: 32px; border-radius: 50%; border: 0; background: none; cursor: pointer;
  color: var(--ink-soft); display: grid; place-items: center;
}
.direccion-menu-btn:hover { background: var(--bg-soft); }
.direccion-menu-dropdown {
  display: none; position: absolute; top: calc(100% + 4px); right: 0; z-index: 5; min-width: 190px;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--sp-2); flex-direction: column; gap: 2px;
}
.direccion-menu.is-open .direccion-menu-dropdown { display: flex; }
.direccion-menu-dropdown button {
  border: 0; background: none; text-align: left; padding: 10px var(--sp-2); border-radius: var(--radius-sm);
  font: inherit; font-size: 14px; font-weight: 600; color: var(--ink); cursor: pointer;
}
.direccion-menu-dropdown button:hover { background: var(--bg-soft); }
.direccion-menu-dropdown button.is-destructive { color: #b3261e; }

/* Barra sutil para agregar, no un boton negro gigante (pedido del dueño 2026-08-14, referencia
   Mercado Libre: el CTA de agregar es liviano, la jerarquia visual la tienen las direcciones
   guardadas, no el boton de agregar una nueva). */
.direccion-add-bar {
  width: 100%; border: 0; border-radius: var(--radius-sm); padding: 14px; margin-top: var(--sp-2);
  background: var(--bg-soft); color: var(--brand-deep); font: inherit; font-size: 14.5px;
  font-weight: 700; cursor: pointer; text-align: center;
}
.direccion-add-bar:hover { background: var(--line); }

/* Paso separado de "nuevo/editar domicilio" (pedido del dueño 2026-08-14, calcado a Mercado
   Libre): la vista completa pasa a ser el formulario, con "Volver" arriba. */
.direccion-volver {
  display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 700;
  color: var(--brand-deep); margin-bottom: var(--sp-3);
}
.direccion-form-section { max-width: 560px; }

/* Selector de provincia "buscable" (pedido del dueño 2026-08-14, referencia Mercado Libre: el
   <select> nativo con 24 opciones se veía feo). Panel propio en vez del <select> del navegador. */
.combo { position: relative; }
.combo-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  width: 100%; border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  padding: 12px var(--sp-3); font: inherit; font-size: 15px; color: var(--ink);
  background: var(--bg); cursor: pointer; text-align: left;
}
.combo-trigger:hover { border-color: var(--ink-soft); }
.combo-trigger svg { flex-shrink: 0; color: var(--ink-soft); transition: transform .15s ease; }
.combo.is-open .combo-trigger svg { transform: rotate(180deg); }

.combo-panel {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 10;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--sp-2); flex-direction: column; gap: var(--sp-2);
}
/* Clase, no [hidden] — mismo criterio que .direccion-menu-dropdown, evita de raiz la trampa de
   especificidad [hidden] vs display propio que ya paso varias veces en este archivo. */
.combo.is-open .combo-panel { display: flex; }

.combo-search-wrap {
  display: flex; align-items: center; gap: var(--sp-2); padding: 8px var(--sp-3);
  background: var(--bg-soft); border-radius: var(--radius-sm); color: var(--ink-soft); flex-shrink: 0;
}
.combo-search { border: 0; background: none; outline: none; width: 100%; font: inherit; font-size: 14px; color: var(--ink); }

.combo-options { display: flex; flex-direction: column; max-height: 220px; overflow-y: auto; }
.combo-option {
  border: 0; background: none; text-align: left; padding: 10px var(--sp-3); border-radius: var(--radius-sm);
  font: inherit; font-size: 14px; color: var(--ink); cursor: pointer;
}
.combo-option:hover { background: var(--bg-soft); }
.combo-option[hidden] { display: none; }
.combo-empty { font-size: 13px; color: var(--ink-soft); padding: var(--sp-2) var(--sp-3); margin: 0; }
.combo-empty[hidden] { display: none; }
