:root {
  color-scheme: light;
}

body {
  font-family: Inter, system-ui, sans-serif;
  background: var(--color-bg);
  color: var(--color-text);
  margin: 0;
  min-height: 100vh;
  /* 100dvh despues de 100vh (no en vez de): en Safari/iPhone 100vh usa el
     viewport mas grande posible (como si la barra de direcciones y el
     teclado estuvieran ocultos), asi que al aparecer el teclado puede
     quedar espacio de sobra reservado que no es visible de verdad. 100dvh
     se ajusta al viewport REAL visible en cada momento. Navegadores sin
     soporte simplemente ignoran esta linea (valor invalido) y se quedan
     con el 100vh de arriba -- ninguna deteccion de JS necesaria. */
  min-height: 100dvh;
  cursor: default;
  /* Prevent accidental global horizontal scroll while we keep layout responsive */
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }

button, .hero__tab, .top-bar__link, .button { cursor: pointer; }
input, select, textarea { cursor: text; }

/* Sistema visual movil general: margen lateral base de 16px (layout.css
   define 1.5rem/24px para todos los anchos) -- en movil se reduce a 16px,
   consistente con el resto de los espacios de este archivo (8/12/16/24/32).
   safe-area-inset-top con max(): si el sitio alguna vez se sirve con
   viewport-fit=cover (hoy no es el caso, el meta viewport actual no lo
   activa, asi que env() vale 0 y esto no cambia nada todavia), el
   contenido superior no quedara debajo del notch/isla dinamica. */
@media (max-width: 767px) {
  .page-wrapper { padding-inline: 16px; padding-top: max(1rem, env(safe-area-inset-top)); }
}

/* Top bar */
.top-bar { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-sm); font-size: 0.875rem; color: var(--color-text-muted); padding: calc(var(--space-sm) / 2) 0; }
.top-bar__group { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }
.top-bar__link { color: var(--color-text-muted); text-decoration: none; font-weight: 600; }
.top-bar__pill { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.35rem 0.75rem; border-radius: var(--radius-lg); background: var(--color-surface-alt); border: 1px solid var(--color-border); }

/* Envíos/Garantía/Soporte: must always read as one line. flex-wrap:nowrap
   keeps the three items together; if they still don't fit on an extremely
   narrow screen, this row (not the page body) scrolls horizontally. */
.top-bar__group--shipping {
  flex-wrap: nowrap;
  gap: 0.6rem;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.top-bar__group--shipping::-webkit-scrollbar { display: none; }
.top-bar__group--shipping span { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 479px) { .top-bar__group--shipping { font-size: 0.8rem; } }

/* Movil: la barra superior se reduce a una sola linea compacta -- "Envíos
   México" a la izquierda y "MXN" a la derecha. "Garantía"/"Soporte experto"
   (2º y 3er <span> del primer grupo) y los enlaces WhatsApp/Ayuda/Rastrear
   pedido (todos <a class="top-bar__link">) se ocultan solo en movil -- nunca
   se quitan del HTML ni del escritorio/tablet. */
@media (max-width: 767px) {
  .top-bar__group--shipping > span:not(:first-child) { display: none; }
  .top-bar__group:not(.top-bar__group--shipping) .top-bar__link { display: none; }
}

/* Header: real KLIC brand blue, so buttons sitting on it need light (white)
   treatment for contrast — scoped to .site-header only, since .button--ghost
   is reused on the white footer. */
.site-header { display: grid; gap: var(--space-md); background: var(--color-primary); border-radius: var(--radius-lg); }
/* 3ra columna en "auto": el bloque Cuenta/Carrito/WhatsApp nunca debe
   encogerse por debajo de su contenido. Con un ancho fijo (minmax(160,260))
   mas angosto que el contenido real, el navegador dejaba que ese contenido
   desbordara hacia la izquierda (justify-content:end + overflow visible),
   invadiendo visualmente la columna de busqueda -- por eso "Buscar" y
   "Cuenta" se veian empalmados. Con "auto" la columna crece a lo que el
   contenido necesita y el gap explicito del grid (--space-lg) separa ambos
   bloques de verdad. La columna de busqueda usa minmax(0,1fr) para poder
   encogerse de forma segura y ceder ese espacio. */
.header-grid { display: grid; grid-template-columns: minmax(120px, 220px) minmax(0, 1fr) auto; gap: var(--space-lg); align-items: center; }
.brand-logo { display: inline-flex; align-items: center; }
.brand-logo__image { display: block; width: 130px; height: auto; max-width: 100%; }
@media (max-width: 767px) { .brand-logo__image { width: 110px; } }

.search-panel { background: #ffffff; border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: calc(var(--space-sm) / 2); box-shadow: var(--shadow-sm); display:flex; gap:0.5rem; align-items:center; min-width: 0; }
.search-panel .form-group { flex:1; margin:0; min-width: 0; }
.search-panel .input-text { width:100%; min-width: 0; }

/* Autocomplete del buscador (src/scripts/klic-autocomplete.js) -- inyectado
   por JS envolviendo el <input> existente, nunca reemplazándolo (progressive
   enhancement real: si el JS no corre, el <input> se ve/funciona exactamente
   igual dentro de .search-panel). */
.klic-autocomplete { position: relative; flex: 1; min-width: 0; }
.klic-autocomplete__lista {
	position: absolute;
	top: calc(100% + 6px);
	left: 0;
	right: 0;
	z-index: 40;
	margin: 0;
	padding: 0.4rem;
	list-style: none;
	background: #ffffff;
	border: 1px solid var(--color-border);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-md, 0 10px 28px rgba(19,41,75,0.12));
	max-height: min(70vh, 420px);
	overflow-y: auto;
}
.klic-autocomplete__item + .klic-autocomplete__item { margin-top: 0.25rem; }
.klic-autocomplete__link {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.5rem;
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: inherit;
}
.klic-autocomplete__item.is-active .klic-autocomplete__link,
.klic-autocomplete__link:hover,
.klic-autocomplete__link:focus {
	background: var(--color-surface, #f7f9fc);
}
.klic-autocomplete__img { width: 44px; height: 44px; object-fit: contain; border-radius: var(--radius-sm); background: #f7f9fc; flex-shrink: 0; }
.klic-autocomplete__info { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.klic-autocomplete__nombre { font-weight: 600; font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.klic-autocomplete__meta { font-size: 0.8rem; color: var(--color-text-muted, #5f718f); }
.klic-autocomplete__precio { font-size: 0.85rem; font-weight: 700; color: var(--color-primary); }
.klic-autocomplete__vacio,
.klic-autocomplete__error { padding: 0.75rem 0.5rem; }
.klic-autocomplete__vacio p { margin: 0 0 0.2rem; }
.klic-autocomplete__vacio-hint { color: var(--color-text-muted, #5f718f); font-size: 0.85rem; }
.klic-autocomplete__ver-todos { border-top: 1px solid var(--color-border); margin-top: 0.4rem; padding-top: 0.4rem; }
.klic-autocomplete__ver-todos a { display: block; padding: 0.4rem 0.5rem; font-size: 0.85rem; font-weight: 700; color: var(--color-primary); text-decoration: none; }
.klic-autocomplete__ver-todos a:hover { text-decoration: underline; }
/* Estados EXACT_MATCH/RELATED_ONLY (modelo de relevancia, ver
   inc/klic-search-service.php) -- el encabezado de "relacionados" nunca se
   confunde visualmente con un resultado exacto: fondo distinto, sin ser un
   <a>/opción seleccionable. */
.klic-autocomplete__seccion-titulo {
	padding: 0.5rem 0.5rem 0.2rem;
	margin-top: 0.3rem;
	border-top: 1px solid var(--color-border);
	font-size: 0.78rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: var(--color-text-muted, #5f718f);
}
.klic-autocomplete__acciones { display: flex; flex-wrap: wrap; gap: 0.5rem; padding: 0.5rem; }
.klic-autocomplete__accion {
	display: inline-flex;
	align-items: center;
	padding: 0.4rem 0.7rem;
	border-radius: 999px;
	border: 1px solid var(--color-border);
	font-size: 0.82rem;
	font-weight: 700;
	color: var(--color-primary);
	text-decoration: none;
}
.klic-autocomplete__accion:hover { background: var(--color-surface, #f7f9fc); }
@media (max-width: 480px) {
	.klic-autocomplete__lista { position: fixed; left: 0.5rem; right: 0.5rem; top: auto; }
}
.search-actions { display: flex; gap: 0.5rem; justify-content: flex-end; flex-shrink: 0; }
.search-actions .button { min-width: 56px; flex-shrink: 0; }
.account-links { display: flex; gap: var(--space-sm); justify-content: end; align-items:center; flex-shrink: 0; }
.account-links a { flex-shrink: 0; }
.site-header .account-links .button--ghost { color: #ffffff; border-color: rgba(255,255,255,0.45); }
.site-header .account-links .button--ghost:hover { background: rgba(255,255,255,0.14); }

/* Reduce vertical height of header */
.site-header { padding: calc(var(--space-sm) / 2) var(--space-md); }

/* Shared wrapper for every horizontally-scrolling row (nav pills, benefits,
   products, categories). No overlay of any kind: the chevrons are plain flex
   items that RESERVE their own space beside the track, so the track shrinks
   to fit around them instead of them floating on top of the first/last card.
   No gradients/fades — those visually "ate" the edge cards. */
/* Centered as a block within the page (margin-inline:auto), not by
   justify-content:center on the scrolling content inside — centering
   overflowing flex content that way can make its own start unreachable. */
.carousel { display: flex; align-items: center; gap: 0.35rem; width: 100%; max-width: 100%; margin-inline: auto; }
.carousel > *:not(.carousel-chevron) { flex: 1 1 0%; min-width: 0; }
.carousel-chevron {
  flex: 0 0 auto;
  width: 18px;
  background: none;
  border: none;
  padding: 0;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color 160ms ease;
}
.carousel-chevron:hover { color: var(--color-primary); }
.carousel-chevron[hidden] { display: none; }
/* Chevrons are a desktop/tablet affordance only — mobile uses touch/swipe
   plus (for Productos/Categorías) the "Desliza para ver más" text hint. */
@media (max-width: 639px) { .carousel-chevron { display: none; } }

/* "Desliza para ver más" — mobile-only text hint next to a section heading,
   shown only when that carousel actually overflows (toggled in home.js). */
.section-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
.carousel-hint { font-size: 0.8rem; color: var(--color-text-muted); opacity: 0.85; white-space: nowrap; }
@media (min-width: 640px) { .carousel-hint { display: none; } }

/* Nav: fila de pills de categorias.
   .main-nav es el contenedor de scroll (overflow-x) con padding horizontal
   explicito para que el ultimo chip ("Novedades") nunca quede pegado ni
   cortado por el borde. .main-nav__track es la fila flex real.
   flex-wrap NUNCA se activa, a ningun ancho -- una ronda anterior permitia
   wrap a una segunda linea en escritorio (>=1024px) "si de verdad no
   cabian", pero en produccion SI ocurria (comprobado con capturas reales):
   a 1200px el contenido necesitaba ~1166px contra ~1128px disponibles, asi
   que "Novedades" saltaba a una segunda fila. La regla que ganaba la
   cascada era exactamente esa: ".main-nav__track { flex-wrap: wrap; }"
   dentro de "@media (min-width: 1024px)". Ahora, en vez de permitir una
   segunda linea, se resuelve por espacio: <1200px sigue siendo una sola
   fila con scroll horizontal contenido dentro de .main-nav; >=1200px es
   una sola fila SIN scroll, con gap/padding reducidos lo suficiente para
   que las 10 categorias quepan siempre (verificado con
   getBoundingClientRect a 1200px, el caso mas ajustado). */
.main-nav { overflow-x: auto; -webkit-overflow-scrolling: touch; scroll-behavior: smooth; padding: 0.4rem var(--space-sm); }
.main-nav__track { display: flex; flex-wrap: nowrap; gap: 0.45rem; align-items: center; width: max-content; margin-inline: auto; }
.main-nav a { flex: 0 0 auto; height: 38px; display: inline-flex; align-items: center; padding: 0 0.7rem; border-radius: var(--radius-md); background: var(--color-surface); border: 1px solid var(--color-border); color: var(--color-text); white-space: nowrap; font-size: 0.85rem; transition: background-color 160ms ease, transform 120ms ease; }
.main-nav a:hover, .main-nav a:focus-visible { background: rgba(27,63,160,0.06); transform: translateY(-1px); }
/* <1200px: pista visual real de que la barra se puede desplazar -- una
   barra de scroll delgada en vez de ocultarla sin otro indicador. */
@media (max-width: 1199px) {
  .main-nav { scrollbar-width: thin; }
  .main-nav::-webkit-scrollbar { height: 6px; display: block; }
  .main-nav::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 999px; }
  .main-nav::-webkit-scrollbar-track { background: transparent; }
}
/* >=640px: un poco mas compacto para que quepan mas pills antes de que
   haga falta desplazarse -- el tamaño de letra nunca se toca, solo el
   espaciado, asi ningun nombre se recorta. */
@media (min-width: 640px) {
  .main-nav__track { gap: 0.3rem; }
  .main-nav a { padding: 0 0.5rem; }
}
/* Escritorio >=1200px: SIEMPRE una sola fila, sin scroll y sin wrap.
   Gap y padding horizontal se reducen moderadamente (el tamaño de letra no
   se toca -- con estos valores ya sobra margen incluso en el caso mas
   ajustado, 1200px) para que las 10 categorias quepan siempre, con la
   misma altura de fila que en cualquier otro ancho. */
@media (min-width: 1200px) {
  .main-nav { overflow-x: visible; }
  .main-nav__track { flex-wrap: nowrap; width: auto; margin-inline: 0; justify-content: center; gap: 0.2rem; }
  .main-nav a { padding: 0 0.4rem; }
}

/* Hero: no min-height anywhere in this block (audited) — height is content-
   driven. The old bloat came from the decorative image having no height cap
   at all, not from any fixed-height rule. */
.hero { display: grid; grid-template-columns: 1fr; gap: var(--space-sm); align-items: center; padding: 1rem; background: linear-gradient(135deg,#081a38 0%,#0f2a5f 45%,#112f6d 100%); color: var(--color-text-dark); border-radius: var(--radius-lg); overflow: hidden; }
@media (min-width: 900px) { .hero { grid-template-columns: 1.05fr 0.95fr; padding: 1.5rem; } }
.hero__content { display: grid; gap: 0.75rem; }
.hero__title { margin: 0; font-size: clamp(1.5rem, 4vw, 2.2rem); line-height: 1.15; font-weight: 800; }
.hero__title strong { color: var(--color-secondary); }
.no-break { white-space: nowrap; }
.hero__subtitle { margin: 0; color: rgba(255,255,255,0.9); line-height: 1.5; }
.hero__media { display: flex; justify-content: center; align-items: center; padding-inline: 1rem; }
/* Sized by width — 98% of the right column's own (padded) content box,
   which lands at ~92% of the column overall (~514px at the current 1200px
   container cap) — a straight percentage rather than the previous
   clamp(460px,...) so it scales cleanly with the column at every width
   instead of hitting a fixed px floor that stopped tracking the column at
   all. max-width:530px is just an absolute ceiling in case the column ever
   grows past today's container cap; the percentage alone already keeps it
   inside .hero__media's own padding at any width, so it never touches the
   hero's edges or the form column. height:auto + object-fit:contain keep
   the original proportion (no distortion/crop). At ~514px wide the image
   is ~343px tall, still comfortably under the form column's own height, so
   the hero's overall height doesn't grow. */
.hero__image { width: 98%; max-width: 530px; height: auto; border-radius: var(--radius-lg); object-fit: contain; box-shadow: var(--shadow-lg); }
/* Mobile: drop the decorative image entirely (not just visually hide it)
   so the hero ends right after the form, with no leftover blue space. */
@media (max-width: 899px) { .hero__media { display: none; } }

/* Tabs */
.hero__search { background: rgba(255,255,255,0.06); border-radius: var(--radius-lg); padding: var(--space-md); display: grid; gap: var(--space-sm); border: 1px solid rgba(255,255,255,0.08); }
.hero__tabs { display: flex; gap: 0.5rem; }
.hero__tab { border-radius: 999px; padding: 0.6rem 0.9rem; min-height: 44px; border: 1px solid transparent; background: var(--color-primary-strong); color: #ffffff; white-space: nowrap; transition: background-color 160ms ease, transform 120ms ease; }
.hero__tab[aria-selected="true"] { background: #fff; color: var(--color-primary); box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.hero__tab:focus { outline: 3px solid rgba(255,255,255,0.14); }
.hero__tab-panel { display: none; gap: var(--space-sm); }
.hero__tab-panel.active { display: grid; }
/* .hero__search's grid gap already gives 12px before .hero__info; +4px here
   reaches the requested 16px between the active panel and the text below.
   El <p> interior nunca tenia margin:0 -- el margen por defecto del
   navegador (~1em arriba y abajo) sumaba ~32px de alto no intencional,
   parte real de por que el hero se sentia mas alto de lo necesario. */
.hero__info { margin-top: 4px; }
.hero__info p { margin: 0; }
.hero__search-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--space-sm); }
.hero__search-grid .form-group { margin: 0; }
.hero__search-grid select, .hero__search-grid input { background: #fff; }

/* Mobile: the three tabs still must fit on one line without wrapping or
   clipping — smaller font/padding/gap only, same tabs, same behavior. Panel
   padding/gaps are trimmed too (wrapper spacing only — form-control padding
   in forms.css is untouched, so every input/select stays ≥44px tall). */
@media (max-width: 639px) {
  .hero__tabs { gap: 0.4rem; }
  .hero__tab { padding: 0.5rem 0.55rem; font-size: 0.85rem; }
  .hero__search { padding: 0.75rem; gap: 0.625rem; }
  .hero__tab-panel { gap: 0.625rem; }
  .hero__search-grid { gap: 0.5rem; }
}

/* Movil (<768px): padding exterior del hero en 24px horizontal / 16px
   vertical (una ronda de pulido posterior compacta el vertical un poco mas,
   el horizontal se conserva), titulo reducido de forma controlada (conserva
   jerarquia -- sigue siendo el texto mas grande de la pagina, y "KLIC" sigue
   en naranja via .hero__title strong, sin tocar). Los tabs llevan un scroll
   horizontal contenido como red de seguridad -- hoy caben en una sola linea
   a estos anchos, pero si algun dia no cupieran, nunca se recorta el texto.
   El resto de los gaps internos (contenido/buscador/tabs/formulario) se
   reducen tambien un paso en la escala 8/12/16/24/32 -- ninguna se toca por
   debajo de eso, y ningun control baja de 44px de alto. En conjunto esto
   recorta la altura total del hero en movil ~10-15% frente a la version
   anterior (601px -> ~520px medido a 390px de ancho). */
@media (max-width: 767px) {
  .hero { padding: 16px 24px; }
  .hero__title { font-size: clamp(1.35rem, 6vw, 1.8rem); }
  .hero__tabs { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin; padding-bottom: 2px; }
  .hero__content { gap: 0.5rem; }
  .hero__info { margin-top: 0; }
  .hero__search { padding: 0.5rem; gap: 0.5rem; }
  .hero__tab-panel { gap: 0.5rem; }
  .hero__search-submit { gap: 0.5rem; }
}
/* Safety net only — well below the 360/400/430px widths this round targets,
   where two columns already fit; kept here strictly for anything narrower
   that genuinely can't. */
@media (max-width: 359px) {
  .hero__search-grid { grid-template-columns: 1fr; }
}

/* Search submit + clear actions */
.hero__search-submit { display: flex; gap: var(--space-sm); }
.hero__search-submit .button--secondary { flex: 2 1 0; }
.hero__search-submit .button--outline { flex: 1 1 0; }
@media (max-width: 599px) { .hero__search-submit { flex-direction: column; } .hero__search-submit .button { width: 100%; flex: none; } }

/* Resultados de "Por vehículo" (conexión real a klic-core GET /compatibilidad).
   Mismos tokens/paleta que .hero__search ya usa (fondo translúcido blanco
   sobre el panel azul oscuro), no un patrón visual nuevo. */
.hero__search-results[hidden] { display: none; }
.hero__search-results__message { margin: 0; color: rgba(255,255,255,0.9); }
.hero__search-results__message a { color: #ffffff; text-decoration: underline; }
.hero__search-results__list { display: grid; gap: var(--space-sm); margin: 0; padding: 0; list-style: none; }
.hero__search-results__item { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08); border-radius: var(--radius-md); padding: 0; display: grid; gap: 0.25rem; }
.hero__search-results__item-link { display: flex; align-items: center; gap: 0.6rem; padding: var(--space-sm); text-decoration: none; color: inherit; border-radius: inherit; }
.hero__search-results__item-link:hover, .hero__search-results__item-link:focus { background: rgba(255,255,255,0.08); }
.hero__search-results__item-img { width: 48px; height: 48px; object-fit: contain; border-radius: var(--radius-sm); background: rgba(255,255,255,0.9); flex-shrink: 0; }
.hero__search-results__item-info { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; flex: 1 1 auto; }
.hero__search-results__item-name { margin: 0; color: #ffffff; font-weight: 600; }
.hero__search-results__item-meta { margin: 0.15rem 0 0; color: rgba(255,255,255,0.75); font-size: 0.9rem; }
.hero__search-results__item-price { margin: 0.15rem 0 0; color: #ffffff; font-weight: 700; }
.hero__search-results__title { margin: 0 0 var(--space-sm); color: #ffffff; font-weight: 700; }
.hero__search-results__aviso { margin: var(--space-sm) 0 0; color: rgba(255,255,255,0.7); font-size: 0.8rem; }

/* "No encuentro mi vehículo" (§8-12, ronda nocturna v8): acción discreta
   (texto subrayado, no un botón compacto) debajo de .hero__info, con un
   panel colapsable que reutiliza los mismos tokens que .hero__search-results
   (fondo translúcido blanco sobre el panel azul oscuro) para que se sienta
   parte del mismo hero, no un formulario ajeno. */
.vehicle-request { margin-top: var(--space-sm); }
/* QA producción (post-V8.2.1): era un link de texto subrayado (opacity baja,
   sin fondo/borde) -- se perdía visualmente debajo del finder. Ahora un CTA
   secundario evidente (pill con borde), pero deliberadamente más liviano que
   el botón primario "Buscar" de arriba -- nunca un banner ni un segundo hero. */
.vehicle-request__toggle {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 0.5rem 1rem;
	background: rgba(255,255,255,0.06);
	border: 1px solid rgba(255,255,255,0.4);
	border-radius: var(--radius-md);
	color: #ffffff;
	font-weight: 600;
	font-size: 0.9rem;
	text-decoration: none;
	cursor: pointer;
}
.vehicle-request__toggle:hover { background: rgba(255,255,255,0.14); border-color: rgba(255,255,255,0.6); }
.vehicle-request__toggle:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.vehicle-request__panel[hidden] { display: none; }
.vehicle-request__panel { margin-top: var(--space-sm); padding: var(--space-sm); background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08); border-radius: var(--radius-md); display: grid; gap: var(--space-sm); }
.vehicle-request__intro { margin: 0; color: rgba(255,255,255,0.85); font-size: 0.9rem; }
.vehicle-request__result[hidden] { display: none; }
.vehicle-request__result { display: grid; gap: var(--space-sm); }
.vehicle-request__mensaje { margin: 0; color: rgba(255,255,255,0.9); }
.vehicle-request__mensaje--ok { color: #ffffff; font-weight: 600; }
.vehicle-request__mensaje--error { color: #ffd7d7; }

/* Upload dropzone: solid brand-blue fill (not a translucent wash) so it
   reads clearly against the dark hero panel, with white text throughout.
   Spacing below is explicit (not the panel's shared grid gap) to match the
   12 / 10-12 / 8 / 12px rhythm requested between box, buttons, formats text
   and the Analizar button. */
.hero__upload-box { border: 2px dashed rgba(255,255,255,0.4); border-radius: var(--radius-lg); padding: var(--space-md); margin-bottom: 0.75rem; text-align: center; background: var(--color-primary); }
.hero__upload-box p { margin:0 0 0.5rem; color: #ffffff; }
.hero__upload-actions { display: flex; gap: 0.625rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.hero__upload-actions .button { min-height:44px; }
.hero__upload-actions[hidden] { display: none; }
.hero__upload-panel > p { margin: 0 0 0.75rem; }
/* Texto secundario ("Formatos: ... Tamaño máximo: 5 MB"): mas pequeño que el
   cuerpo normal y con mejor interlineado, para que se lea como nota al pie,
   no como texto de igual jerarquia que los botones. */
.hero__upload-hint { margin: 0; color: rgba(255,255,255,0.9); font-size: 0.82rem; line-height: 1.55; }
@media (max-width: 480px) { .hero__upload-actions .button { width: 100%; } }

/* Movil: area de subir foto mas compacta -- menos padding/margenes
   verticales entre caja, botones y el texto de formatos, sin tocar la
   altura tactil de 44px de los botones. */
@media (max-width: 767px) {
  .hero__upload-box { padding: 12px; margin-bottom: 12px; }
  .hero__upload-actions { gap: 0.5rem; margin-bottom: 0.4rem; }
}

.hero__upload-preview { display: grid; gap: 0.75rem; align-items: center; grid-template-columns: 120px 1fr; text-align: left; }
.hero__upload-preview img { width: 120px; height: 120px; object-fit: contain; border-radius: 8px; background: #fff; }
.hero__upload-preview-info { display: grid; gap: 0.35rem; }
.hero__upload-preview-name { display: block; color: #ffffff; }
.hero__upload-preview-size { display: block; color: rgba(255,255,255,0.8); font-size: 0.9rem; }
.hero__upload-preview-actions { display: flex; flex-wrap: wrap; gap: 0.625rem; margin-top: 0.25rem; }
.hero__upload-preview-actions .button { min-height: 44px; }
@media (max-width: 480px) {
  .hero__upload-preview { grid-template-columns: 1fr; }
  .hero__upload-preview img { width: 100%; height: auto; max-height: 200px; }
  .hero__upload-preview-actions .button { width: 100%; }
}

/* Webcam capture modal. padding-bottom con env(safe-area-inset-bottom):
   el modal cubre todo el viewport (position:fixed; inset:0) y sus botones
   de accion viven al fondo del panel -- en iPhone la franja de gestos de
   Safari puede quedar encima de esos botones si no se respeta el area
   segura. El fallback (var(--space-md)) es el mismo padding que ya tenia
   para navegadores sin soporte de env(). */
.webcam-modal { position: fixed; inset: 0; background: rgba(7,20,42,0.72); display: grid; place-items: center; z-index: 1000; padding: var(--space-md); padding-bottom: max(var(--space-md), env(safe-area-inset-bottom)); }
.webcam-modal__panel { background: #fff; border-radius: var(--radius-lg); padding: var(--space-md); display: grid; gap: var(--space-sm); max-width: 480px; width: 100%; box-shadow: var(--shadow-lg); }
.webcam-modal__video { width: 100%; max-height: 360px; border-radius: var(--radius-md); background: #000; object-fit: cover; }
.webcam-modal__actions { display: flex; gap: var(--space-sm); justify-content: flex-end; flex-wrap: wrap; }
@media (max-width: 480px) { .webcam-modal__actions { flex-direction: column; } .webcam-modal__actions .button { width: 100%; } }
/* "Cambiar cámara": oculta por defecto -- JS la muestra solo cuando de
   verdad hay más de una cámara disponible (enumerateDevices tras el
   permiso). El icono es un SVG inline (sin depender de una libreria de
   iconos que el proyecto no tiene) + texto, nunca solo el icono. */
.webcam-modal__switch { display: none; align-items: center; gap: 0.4rem; }
.webcam-modal__switch.is-visible { display: inline-flex; }
.webcam-modal__switch svg { width: 18px; height: 18px; flex: 0 0 18px; }
.webcam-modal__status { margin: 0; font-size: 0.85rem; color: var(--color-text-muted); text-align: center; }

/* ============================================================
   Chat KLIC IA — sistema de burbujas compartido entre la pestaña
   "KLIC IA" del hero y el bloque "Pregúntale a KLIC IA". Mismas
   clases en los dos lugares a propósito, para no duplicar CSS ni
   JS -- ver crearChatKlicIA() en home.js.
   ============================================================ */
.klic-chat__row { display: flex; gap: 0.5rem; align-items: flex-end; margin-bottom: 0.65rem; }
.klic-chat__row:last-child { margin-bottom: 0; }
.klic-chat__row--user { flex-direction: row-reverse; }

/* Avatar de KLIC IA: .klic-chat__avatar es un circulo contenedor de 28x28
   (reducido de 32x32 -- una ronda de pulido posterior lo hace un poco mas
   discreto, mejora la composicion junto a burbujas mas compactas);
   .klic-chat__avatar-img es la imagen oficial (la "K" de la marca) dentro,
   con object-fit:contain para no deformarla. Si la imagen falla (404, ruta
   rota), el onerror en JS/HTML la quita del DOM y agrega la clase
   --fallback, que dibuja la misma "K" con CSS puro (::after) -- nunca debe
   verse el icono de imagen rota del navegador. */
.klic-chat__avatar { width: 28px; height: 28px; border-radius: 50%; flex: 0 0 28px; display: flex; align-items: center; justify-content: center; overflow: hidden; background: #ffffff; border: 1px solid rgba(11, 43, 92, 0.12); }
.klic-chat__avatar-img { width: 100%; height: 100%; object-fit: contain; display: block; padding: 3px; box-sizing: border-box; }
.klic-chat__avatar--fallback { background: var(--color-primary); border-color: transparent; }
.klic-chat__avatar--fallback::after { content: "K"; color: #ffffff; font-weight: 800; font-size: 13px; line-height: 1; font-family: inherit; }

.klic-chat__col { display: flex; flex-direction: column; max-width: 78%; min-width: 0; }
.klic-chat__row--user .klic-chat__col { align-items: flex-end; }
.klic-chat__row--ai .klic-chat__col { align-items: flex-start; }

.klic-chat__bubble { border-radius: var(--radius-md); padding: 0.55rem 0.85rem; }
.klic-chat__bubble--ai { background: var(--color-surface); color: var(--color-text); border: 1px solid var(--color-border); box-shadow: var(--shadow-sm); border-bottom-left-radius: 4px; }
.klic-chat__bubble--user { background: var(--color-primary); color: #ffffff; border: 1px solid rgba(255,255,255,0.18); border-bottom-right-radius: 4px; }
.klic-chat__text { margin: 0; font-size: 0.92rem; line-height: 1.45; overflow-wrap: break-word; word-break: break-word; white-space: pre-wrap; }

/* La hora queda pegada a su burbuja (sin separarse del mensaje) -- reducida
   ligeramente junto con el avatar. */
.klic-chat__time { font-size: 0.68rem; color: var(--color-text-muted); margin-top: 0.15rem; padding-inline: 0.25rem; }
/* En el hero (fondo oscuro) la hora de --color-text-muted no tiene
   contraste suficiente -- el propio contenedor .hero__chat-bubbles ya
   define un color de texto claro por defecto que .klic-chat__time hereda
   si no se sobreescribe aqui explicitamente por especificidad de :root. */
.hero__chat-bubbles .klic-chat__time { color: rgba(255,255,255,0.65); }

.klic-chat__whatsapp-btn { display: inline-flex; margin-top: 0.6rem; min-height: 36px; height: 36px; padding: 0.4rem 0.9rem; font-size: 0.85rem; }

/* Movil: avatar + burbuja + hora un poco mas compactos (menos espacio
   vertical entre filas y menos padding dentro de la burbuja), para que el
   chat se sienta ajustado al telefono en vez de un bloque de escritorio
   encogido. */
@media (max-width: 767px) {
  .klic-chat__row { gap: 0.4rem; margin-bottom: 0.5rem; }
  .klic-chat__bubble { padding: 0.5rem 0.7rem; }
}

/* Contenedor del bloque inferior "Pregúntale a KLIC IA" (fondo claro). */
.ia-block__chat-window { display: flex; flex-direction: column; }

/* Contenedor de la pestaña del hero (fondo oscuro) -- antes no tenia
   ningun estilo propio, los mensajes salian como texto corrido sin
   límite de alto ni scroll. */
.hero__chat-bubbles {
  display: flex;
  flex-direction: column;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: var(--radius-lg);
  padding: var(--space-sm);
  /* 280px, igual que .ia-block__chat-window: con 260px, conversaciones
     cortas (1-2 turnos) a veces no dejaban suficiente margen de scroll
     para ocultar del todo el saludo inicial sin sacrificar la burbuja mas
     reciente -- medido: hacia falta 116px de recorrido y solo habia 111px
     disponibles, un margen de apenas ~5px. 20px extra de alto le da
     margen real a ese caso comun sin crecer demasiado. */
  max-height: 280px;
  overflow-y: auto;
}

/* Button hierarchy on dark/blue surfaces (hero search panel, upload dropzone,
   its preview actions): .button--secondary is already brand-orange from
   buttons.css and needs no override anywhere. .button--outline/.button--ghost
   only need this ONE shared "transparent, light border, white text" rule
   instead of one override per container.
   QA producción (post-V8.2.1) -- causa raíz real del CTA de WhatsApp
   "deshabilitado": .vehicle-request__result nunca estaba en esta lista, así
   que el <a class="button button--outline"> del folio heredaba el
   .button--outline de buttons.css (color/border #13294b, pensado para fondo
   claro) sobre el mismo degradado azul oscuro del hero -- texto y borde casi
   invisibles (no un bug de JS: el enlace siempre tuvo href válido y nunca
   estuvo disabled/aria-disabled). Agregar el selector aquí es la corrección
   completa, sin tocar la lógica de klic-vehicle-request.js. */
.hero__search-submit .button--outline,
.hero__upload-actions .button--outline,
.hero__upload-preview-actions .button--outline,
.hero__upload-preview-actions .button--ghost,
.vehicle-request__result .button--outline {
  background: transparent;
  color: #ffffff;
  border-color: rgba(255,255,255,0.5);
}
.hero__search-submit .button--outline:hover,
.hero__upload-actions .button--outline:hover,
.hero__upload-preview-actions .button--outline:hover,
.hero__upload-preview-actions .button--ghost:hover,
.vehicle-request__result .button--outline:hover {
  background: rgba(255,255,255,0.12);
}

/* Benefits: no min-height anywhere here (audited). Two real causes of the
   excess height, neither of them a height rule:
   1) .benefit-card__title/__text had NO CSS at all, so the <h3>/<p> used the
      browser's default margins (~1em each side), stacking on top of the
      card's own deliberate gap.
   2) .benefits-grid never set align-items, so it defaulted to `stretch` —
      every card in a row was forced to match the tallest one (e.g. "Garantía
      de compatibilidad" wrapping to 2 lines), leaving visible empty space
      inside the shorter cards' own borders even though align-content:start
      already packs their own text at the top. align-items:start below lets
      each card size to its own content instead. */
.benefits-grid { display: grid; align-items: start; gap: 0.625rem; grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width:900px){ .benefits-grid { grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--space-sm); } }
.benefit-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.8rem; display: grid; gap: 0.3rem; align-content: start; }
.benefit-card__title { margin: 0; }
.benefit-card__text { margin: 0; }
@media (min-width: 900px) { .benefit-card { padding: 0.7rem 0.9rem; } }

/* ≤639px: the 2×2 grid still cost two full rows of vertical scroll — a
   single scroll-snapped row of the same four cards costs one. */
@media (max-width: 639px) {
  /* No habia ninguna pista de que el carrusel se puede desplazar en este
     bloque (a diferencia de Productos/Categorias, que ya la tenian) --
     mismo patron ya establecido (.carousel-hint), visible solo en movil. */
  .benefits-hint { display: block; margin-bottom: 0.5rem; }
  .benefits-grid {
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    gap: 0.625rem;
    /* Margen inicial/final real -- antes la primera y ultima tarjeta
       quedaban exactamente pegadas al borde del carrusel. */
    padding: 0 0.25rem 0.5rem;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .benefits-grid::-webkit-scrollbar { display: none; }
  /* Fixed height:118px previously clipped the title+description pair on the
     longer benefits (text rendered past the card's border). min-height only,
     no height/max-height/overflow, so the card always grows to fit both
     lines fully. Width is a % of the viewport (matches the products/
     categories carousels) so exactly one card + a sliver of the next shows,
     and the first card is fully visible at scrollLeft 0. */
  .benefit-card { flex: 0 0 82%; min-height: 100px; padding: 0.65rem 0.75rem; gap: 0.3rem; scroll-snap-align: start; }
}

/* Categories: 8 cards, ONE flat horizontally-scrolling, scroll-snapped
   carousel — same flat flex + per-card scroll-snap-align pattern
   .products-grid already uses. No page/group wrapper divs, no
   display:contents, no nested flex/grid. At exactly 5-cards-visible
   (desktop, see the 1024px card-width formula below), 5 × card + 4 × gap
   fills the track's own width exactly, so scrollWidth − clientWidth
   (the right arrow's target, set in home.js) works out to exactly
   3 × (card + gap) — 8 total − 5 visible = 3 cards of travel, landing on
   cards 4-8. No artificial width/margin/padding/transform on
   .categories-preview (a plain flex row).
   No min-height (audited/removed, including the stale 160px duplicate that
   lived in cards.css and would otherwise have re-surfaced once this one was
   gone). align-items was never set here either, so the row defaulted to
   `stretch`: every .category-card was force-stretched to match the tallest
   one in the row. "Herramientas de programación" has by far the longest
   title (wraps to several lines), so it was naturally the tallest card, and
   the others got stretched to match it — the same bug/fix pattern as
   .benefits-grid needing align-items:start two rounds ago. flex-start below
   lets each card size to its own content instead. */
.categories-preview {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  gap: 0.625rem;
  margin: 0;
  padding: 0 0 0.5rem;
  -ms-overflow-style: none;
  scrollbar-width: none;
  cursor: grab;
}
.categories-preview::-webkit-scrollbar { display: none; }
/* The scrollbar is hidden for a cleaner look; the discrete .carousel-chevron
   pair (desktop/tablet) plus home.js's click-and-drag scrolling (mouse) and
   native touch/trackpad scrolling cover the affordance that hiding it removes.
   This class only flips the cursor while dragging. */
.categories-preview.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.category-card { display: grid; gap: 0.5rem; align-items: start; text-align: center; padding: 0.7rem; border-radius: var(--radius-md); background: var(--color-surface); border: 1px solid var(--color-border); min-height: 0; flex: 0 0 46%; scroll-snap-align: start; transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease; }
@media (min-width: 768px) { .category-card { flex: 0 0 31%; } }
/* Exactly the requested formula: each card is 1/5 of the track width minus
   its share of the 4 gaps between 5 visible cards — 5 × card + 4 × gap =
   100%, so 5 full cards fit with zero left over, no partial 6th peeking in. */
@media (min-width: 1024px) { .category-card { flex: 0 0 calc((100% - 4 * 0.625rem) / 5); } }
/* Container: fixed, uniform 130px canvas, flex-centered, 12px padding on
   every side, clips nothing the image itself doesn't already fit inside
   (object-fit:contain below guarantees the image never exceeds this box). */
.category-card__icon { display: flex; align-items: center; justify-content: center; width: 100%; height: 130px; padding: 0.75rem; background: var(--color-surface-alt); border-radius: 1rem; overflow: hidden; }
/* The real <img> gets the sizing/fit properties directly (not just its
   container): full width/height of the padded canvas, contain (never
   cover — never crops or upscales past the canvas), centered. */
.category-card__icon img { display: block; width: 100%; height: 100%; max-width: 100%; max-height: 100%; object-fit: contain; object-position: center; }
.category-card__title { margin: 0; font-weight:700; }
.category-card:focus, .category-card:hover { box-shadow: var(--shadow-sm); transform: translateY(-3px); border-color: rgba(27, 63, 160, 0.16); }

/* Chat/message input rows shared by the hero KLIC IA tab and the standalone
   "Pregúntale a KLIC IA" section: gap (not a margin or <br>) between the text
   field and the Enviar button. */
.hero__chat-footer,
.ia-block__chat-footer {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}
.hero__chat-footer .form-group,
.ia-block__chat-footer .form-group {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
}
/* Movil: el campo ya crece con flex:1 (arriba), pero el boton "Enviar"
   seguia con el padding horizontal normal de .button (1rem/16px cada
   lado) -- se reduce moderadamente aqui para dejarle mas ancho relativo
   al campo de texto, que es lo que el usuario realmente necesita ver. */
@media (max-width: 767px) {
  .hero__chat-footer .button,
  .ia-block__chat-footer .button {
    padding-inline: 0.75rem;
    flex-shrink: 0;
  }
}

/* IA block */
.ia-block { display: grid; gap: var(--space-sm); grid-template-columns: 1fr; padding: var(--space-md); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); }
.ia-block__info { order: 1; display: grid; gap: 0.4rem; align-content: center; }
.ia-block__info h2 { margin: 0; font-size: 1.25rem; line-height: 1.2; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.ia-block__info p { margin: 0; color: var(--color-text-muted); }
.badge { display: inline-flex; align-items: center; padding: 0.2rem 0.6rem; border-radius: 999px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.badge--soon { background: #fff3dd; color: #92600a; border: 1px solid var(--color-warning); }
.pro-account-block { display: grid; gap: 0.6rem; padding: var(--space-md); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); text-align: center; justify-items: center; }
.pro-account-block h2 { margin: 0; }
.pro-account-block p { margin: 0; color: var(--color-text-muted); max-width: 46ch; }
.pro-account-block__actions { display: flex; gap: 0.6rem; flex-wrap: wrap; justify-content: center; }
/* Estados sin acción (solicitud en revisión / precio ya activo) -- mismo
   lugar que el botón, pero sin parecer clicable cuando no hay nada que
   hacer todavía. */
.pro-account-block__estado { display: inline-flex; align-items: center; padding: 0.6rem 1.2rem; border-radius: var(--radius-md); background: var(--color-surface-alt); border: 1px solid var(--color-border); font-weight: 700; color: var(--color-text-muted); }
.pro-account-block__estado--activo { background: rgba(31, 157, 85, 0.1); border-color: var(--color-success, #1f9d55); color: var(--color-success, #1f9d55); }
.ia-block__robot { order: 2; display: flex; align-items: center; justify-content: center; }
.ia-block__chat { order: 3; display: grid; gap: 0.5rem; align-content: center; }
.ia-block__robot img { width:100%; max-width:140px; object-fit:contain; }
.ia-block__chat-window { background: var(--color-bg); border-radius: var(--radius-md); padding: var(--space-sm); max-height: 280px; overflow-y: auto; }
/* .ia-suggestions-wrap is the actual grid/flex-placed item (order/grid-area/
   grid-column all live here); .ia-suggestions is just the scrollable row
   inside it, so the "Desliza para ver opciones" hint can sit above the row
   without being swept into its horizontal scroll. */
.ia-suggestions-wrap { order: 4; display: grid; gap: 0.3rem; min-width: 0; }
.ia-suggestions { display:flex; gap:0.5rem; flex-wrap:wrap; }
.suggestion-btn { background: var(--color-surface-alt); border-radius: 999px; padding:0.45rem 0.75rem; border:1px solid var(--color-border); font-size: 0.85rem; }

/* True mobile only — desktop (≥900px) and tablet (640-899px) keep their
   current structure untouched. Same four existing elements, just placed by
   name instead of source order: row 1 is info+robot side by side, row 2 is
   the full-width chat, row 3 is the full-width suggestions row. Every row is
   auto-sized (no 1fr) so nothing stretches to fill empty space. */
@media (max-width: 639px) {
  .ia-block {
    grid-template-columns: 1fr 72px;
    grid-template-rows: auto auto auto;
    grid-template-areas:
      "info robot"
      "chat chat"
      "sugg sugg";
    padding: 0.875rem;
    gap: 0.625rem;
  }
  .ia-block__info { grid-area: info; order: initial; }
  /* Robot reducido y alineado arriba (no centrado verticalmente contra el
     titulo) -- apoyo visual discreto en vez de competir con titulo y
     descripcion por atencion. */
  .ia-block__robot { grid-area: robot; order: initial; align-items: flex-start; padding-top: 0.15rem; }
  .ia-block__chat { grid-area: chat; order: initial; }
  .ia-suggestions-wrap { grid-area: sugg; order: initial; }
  /* Margen inicial/final real dentro de la fila desplazable -- antes el
     primer y ultimo chip quedaban pegados al borde del bloque. */
  .ia-suggestions { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; padding: 0 0.25rem 2px; -ms-overflow-style: none; scrollbar-width: none; }
  .ia-block__robot img { max-width: 72px; }
  .ia-suggestions::-webkit-scrollbar { display: none; }
  .suggestion-btn { flex: 0 0 auto; white-space: nowrap; }
}

@media (min-width: 640px) and (max-width: 899px) {
  .ia-block { grid-template-columns: 160px 1fr; align-items: center; }
  .ia-block__info { order: initial; grid-column: 2; grid-row: 1; }
  .ia-block__robot { order: initial; grid-column: 1; grid-row: 1 / span 2; }
  .ia-block__chat { order: initial; grid-column: 2; grid-row: 2; }
  .ia-suggestions-wrap { order: initial; grid-column: 1 / -1; }
}

@media (min-width: 900px) {
  /* No min-height here on purpose — the old min-height:360px stretched rows
     1/2 to fill it, so .ia-block__info and .ia-suggestions each centered
     inside an oversized row and ended up far apart. align-self end/start
     below pins them to the shared row boundary with just a 12px gap. */
  .ia-block { grid-template-columns: 200px minmax(300px,1fr) minmax(360px,1fr); column-gap: var(--space-lg); row-gap: var(--space-sm); align-content: center; justify-content: center; padding: var(--space-lg); }
  .ia-block__robot { grid-column: 1; grid-row: 1 / span 2; }
  .ia-block__info { grid-column: 2; grid-row: 1; align-self: end; }
  .ia-suggestions-wrap { grid-column: 2; grid-row: 2; align-self: start; }
  .ia-block__chat { grid-column: 3; grid-row: 1 / span 2; align-self: center; }
  .ia-block__robot img { max-width: 200px; }
}

/* Banner: no min-height, fixed height or justify-content:space-between
   anywhere here (audited). The remaining vertical bulk was the default
   browser margin on the unstyled <h2> title plus a redundant inline margin
   on the subtitle — both zeroed below so the container's own gap is the
   only source of spacing. */
.banner-offers { display:grid; grid-template-columns:1fr; gap:0.6rem; padding:0.85rem; border-radius:var(--radius-lg); background:linear-gradient(135deg,#081a38,#112f6d); color:var(--color-text-dark); }
.banner-offers > div { display:grid; gap:0.6rem; align-content:start; }
.banner-offers__title { margin:0; }
@media(min-width:900px){ .banner-offers { grid-template-columns:1fr 1fr; align-items:center; padding:1.5rem; } }
/* Mobile/tablet (<900px): capped at 90% of the available width (not 100%)
   so it never touches the section's edges, centered via margin-inline:auto. */
.banner-offers__image { width:90%; max-height:130px; object-fit:contain; border-radius:var(--radius-lg); margin-inline:auto; display:block; }
/* Desktop: the banner's own height is set by this image (the text column
   next to it is much shorter than any width/height this image can reach),
   so any width increase forces the banner taller by the same proportion —
   there's no slack to absorb it. Raised the ceiling from 420×280 to
   462×308 (+10% each, ratio-preserved) as the minimum bump needed to make
   the image visibly bigger without growing the banner by more than that
   same ~10% (328px → ~356px). width/max-width match height/max-height
   exactly (both at the image's 3:2 ratio) so the box itself equals the
   content — no pillarboxing — centered via margin-inline:auto. */
@media(min-width:900px){ .banner-offers__image { width:100%; max-width:462px; height:auto; max-height:308px; margin-inline:auto; display:block; } }

/* Products: one horizontally-scrolling, scroll-snapped row at every
   breakpoint (no JS, no multi-row grid) — 6 cards never cost more than a
   single row of vertical scroll. No min-height (audited/removed below);
   .product-card__image now has an explicit height instead of aspect-ratio
   so it hits the requested px target regardless of the card's own width. */
.products-grid {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  gap: 0.625rem;
  padding-bottom: 0.5rem;
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.products-grid::-webkit-scrollbar { display: none; }

.product-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 0.8rem;
  flex: 0 0 82%;
  scroll-snap-align: start;
}
@media (min-width: 768px) { .product-card { flex: 0 0 46%; } }
/* calc() accounts for the row's own 10px gap so exactly 4 full cards fit
   with no sliver of a 5th — "cuatro tarjetas completas" before scrolling. */
@media (min-width: 1200px) { .product-card { flex: 0 0 calc(25% - 7.5px); } }
/* Movil: ya median ~326px de ancho a 430px de viewport (dentro del rango
   320-340px pedido, sin cambios ahi) -- se compacta el padding interno, la
   separacion vertical entre bloques y la imagen un poco mas baja, sin
   perder nombre/precio/botones ni bajar del area tactil de 44px. */
@media (max-width: 767px) {
  .product-card { padding: 0.65rem; gap: 0.4rem; }
}

.product-card__image {
  width: 100%;
  height: 150px;
  object-fit: contain;
  background: var(--color-surface-alt);
  border-radius: 8px;
}
@media (min-width: 768px) { .product-card__image { height: 160px; } }
@media (max-width: 767px) { .product-card__image { height: 128px; } }

/* Info area stretches to push price/actions to the bottom */
.product-card__info {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1 1 auto;
}

/* Title: clamp to maximum 2 lines. min-height reserva el espacio de 2
   líneas siempre (aunque el nombre real quepa en 1) -- así el precio y los
   botones caen en la misma altura en todas las tarjetas de una fila, sin
   truncar ni acortar ningún nombre técnico (el clamp de arriba ya evita
   que crezca más de 2 líneas; esto solo evita que colapse a menos). */
.product-card__title {
  margin: 0;
  font-size: 1rem;
  line-height: 1.2;
  min-height: 2.4em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.product-card__meta-row { display: flex; gap: 0.5rem; color: var(--color-text-muted); font-size: 0.9rem; }

/* Price and action row: keep actions at bottom */
.product-card__price { font-weight: 700; }
.product-card__info > div:last-child { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: auto; }

/* Buttons: row on desktop/tablet, stacked on small screens */
@media (max-width: 767px) {
  .product-card__info > div:last-child { flex-direction: column; }
}
@media (min-width: 768px) {
  .product-card__info > div:last-child { flex-direction: row; align-items: center; }
}

/* Footer: the old grid had no responsive override at all, so its
   minmax(220px,…)/minmax(140px,…) columns had a combined ~640px floor that
   overflowed any viewport narrower than that (Contacto/Políticas pushed off
   screen). minmax(0,1fr) below removes that hard floor on small screens. */
/* padding-bottom con env(safe-area-inset-bottom): en iPhone la franja de
   gestos de Safari puede quedar encima del ultimo contenido del footer.
   max() con el padding normal como piso -- en navegadores sin notch env()
   vale 0 y no cambia nada (desktop/tablet quedan identicos). */
.footer { padding: var(--space-lg) 0; padding-bottom: max(var(--space-lg), env(safe-area-inset-bottom)); border-top: 1px solid var(--color-border); color: var(--color-text-muted); }
@media (min-width: 900px) { .footer { padding: var(--space-2xl) 0; padding-bottom: max(var(--space-2xl), env(safe-area-inset-bottom)); } }
.footer-grid { display:grid; gap:var(--space-md); grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width: 900px) { .footer-grid { grid-template-columns: minmax(220px,1fr) repeat(3, minmax(140px,1fr)); gap:var(--space-lg); } }
.footer__list { list-style:none; padding:0; margin:0; display:grid; gap:0.65rem; }
/* Políticas sin página real todavía (auditoría P1 22/08/2026) -- texto +
   badge "Próximamente" en vez de un href="#" que no lleva a ningún lado. */
.footer__list-soon { display:inline-flex; align-items:center; gap:0.5rem; flex-wrap:wrap; }

/* Bottom bar: copyright left, social links right — was two bare <span>s with
   no layout rule at all, so they rendered as one run-on inline sentence. */
.footer__bottom { display: flex; justify-content: space-between; align-items: center; gap: var(--space-sm); margin-top: var(--space-lg); font-size: 0.875rem; }
.footer__social a { color: inherit; text-decoration: none; }
.footer__social a:hover, .footer__social a:focus-visible { text-decoration: underline; }
/* Escritorio/tablet: identico a como se veia antes -- texto plano en linea
   ("Redes sociales: Facebook · Instagram · TikTok · WhatsApp"). .footer__social-row
   es un span mas alrededor de los 4 enlaces (necesario para el layout de
   fila en movil, ver mas abajo) pero queda display:inline aqui, asi que no
   afecta el flujo de texto. El separador " · " y los ":" del titulo se
   generan con ::after en vez de vivir como texto literal en el HTML, para
   poder reestructurar el marcado (icono + texto accesible) sin cambiar el
   resultado visual en escritorio. */
.footer__social-row { display: inline; }
.footer__social-label::after { content: ": "; }
.footer__social-link:not(:last-child)::after { content: " · "; }
/* Tamaño del icono SIEMPRE fijo, sin condicionarlo a que el media query de
   "mostrar en movil" (mas abajo) coincida -- asi nunca depende de eso para
   no heredar un tamaño gigante por defecto. Selector de una sola clase,
   pero con reglas explicitas de ancho/alto/max-ancho/max-alto que ganan
   sin ambiguedad sobre el "svg{max-width:100%}" generico de reset.css
   (2 declaraciones directas siempre superan una regla de tipo). En
   escritorio el icono esta oculto (display:none, ver abajo) asi que estas
   medidas no afectan nada ahi -- solo importan cuando display pasa a flex
   en movil. */
.footer__social-icon {
  display: none;
  width: 22px;
  height: 22px;
  max-width: 22px;
  max-height: 22px;
  flex: 0 0 22px;
}

/* Movil (<768px): reorganizacion completa, no solo una cuadricula de
   escritorio comprimida.
   1) Marca a todo el ancho, alineada a la izquierda.
   2) Enlaces | Politicas en 2 columnas iguales (misma tipografia/altura).
   3) Contacto a todo el ancho debajo -- telefono y correo con
      white-space:nowrap SOLO en el <a> (nunca en el texto alrededor) para
      que nunca se partan a la mitad, sin impedir que la linea completa
      envuelva si hace falta.
   4) Cierre: derechos y redes sociales centrados, con wrap natural entre
      nombres de redes (nunca dentro de un nombre).
   Titulos ~18px, enlaces/texto ~15-16px -- nunca los tamaños de escritorio. */
@media (max-width: 767px) {
  /* Padding exterior y gaps recortados un paso mas en la escala
     8/12/16/24/32 (antes 24/24/16). Nota honesta: los botones-icono de
     redes sociales (mas abajo) necesitan 44px de alto por area tactil
     minima -- mas altos que la linea de texto plano que reemplazan (~19px)
     -- asi que ese bloque especifico no puede reducirse mas sin romper esa
     regla; el resto del footer si se compacta lo maximo posible sin bajar
     los tamaños de fuente minimos (titulos ~18px, texto ~15px) pedidos. */
  .footer { padding: 12px 0; }
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "brand brand"
      "links policies"
      "contact contact";
    row-gap: 12px;
    column-gap: 16px;
  }
  /* El <p> de la descripcion nunca tenia margin:0 -- igual que el bug de
   .hero__info p, el margen por defecto del navegador (~1em arriba y abajo)
   sumaba espacio no intencional. El logo tambien se reduce un poco aqui
   (independiente del logo del header, que usa la misma clase pero no
   necesita compartir tamaño). */
.footer__brand { grid-area: brand; text-align: left; }
.footer__brand p { margin: 0.5rem 0 0; }
.footer__brand .brand-logo__image { width: 92px; }
  .footer__col--links { grid-area: links; }
  .footer__col--policies { grid-area: policies; }
  .footer__col--contact { grid-area: contact; }
  .footer-grid h3 { margin: 0 0 0.35rem; font-size: 1.1rem; line-height: 1.2; }
  .footer__list { gap: 0.4rem; font-size: 0.95rem; line-height: 1.25; }
  .footer__col--contact .footer__list a[href^="tel:"],
  .footer__col--contact .footer__list a[href^="mailto:"] {
    white-space: nowrap;
  }

  .footer__bottom { flex-direction: column; align-items: center; text-align: center; gap: 0.4rem; margin-top: 12px; }

  /* Redes sociales en movil: titulo "Redes sociales" compacto y centrado
     arriba, fila unica horizontal de botones-icono discretos debajo. El
     nombre de cada red (.footer__social-text) usa .sr-only (definida en
     utilities.css) en vez de display:none -- sigue en el arbol de
     accesibilidad como refuerzo del aria-label del enlace, en vez de
     desaparecer del todo. flex-direction/flex-wrap quedan explicitos
     (no solo confiando en el valor por defecto) para que la fila nunca
     pueda convertirse en columna por error. */
  .footer__social {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
  .footer__social-label {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--color-text);
  }
  .footer__social-label::after { content: none; }
  /* El nombre de cada red queda visualmente oculto pero SIGUE en el arbol
     de accesibilidad (mismo patron que .sr-only de utilities.css, aplicado
     solo aqui -- nunca como clase estatica en el HTML, que lo ocultaria
     tambien en escritorio) -- refuerzo del aria-label del enlace, no
     display:none. */
  .footer__social-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
  }
  .footer__social-link::after { content: none; }
  .footer__social-row {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    gap: 10px;
  }
  .footer__social-link {
    display: inline-flex;
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
  }
  .footer__social-link:hover,
  .footer__social-link:focus-visible {
    color: var(--color-primary);
    border-color: var(--color-primary);
    text-decoration: none;
  }
  /* El tamaño (22x22, max-width/max-height, flex-basis) ya quedo fijo de
     forma incondicional mas arriba -- aqui solo se togglea la visibilidad. */
  .footer__social-icon { display: flex; }
  /* Solo permitir wrap en una pantalla excepcionalmente angosta (menos de
     lo que cualquier telefono real mide hoy) -- nunca columna. */
  @media (max-width: 320px) {
    .footer__social-row { flex-wrap: wrap; row-gap: 8px; }
  }
}

/* Accessibility */
:focus { outline: none; }
:focus-visible { outline: 3px solid rgba(0,123,255,0.18); border-radius:4px; }

/* Small screens tweaks */
/* Header movil: antes se apilaba en una sola columna (logo, luego acciones,
   luego buscador), lo que dejaba el logo aislado en su propia fila -- exacto
   el problema reportado ("el logo queda aislado"). Ahora es un rediseño real
   de 2 filas: fila 1 = logo (izquierda) + acciones (derecha) compartiendo
   una misma fila via grid-template-areas; fila 2 = buscador a todo el ancho.
   row-gap de 8px / column-gap de 12px, padding de 12px -- una ronda de
   pulido posterior lo compacto un poco mas frente a los 16px/12px
   iniciales, siempre dentro de la escala 8/12/16/24/32 -- nada de
   position:absolute. */
@media (max-width: 767px) {
  .site-header { padding: 12px; }
  .header-grid {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "logo actions"
      "search search";
    row-gap: 8px;
    column-gap: 12px;
  }
  .brand-logo { grid-area: logo; }
  .account-links { grid-area: actions; order: initial; }
  .search-panel { grid-area: search; order: initial; width: 100%; }

  /* Cuenta/Carrito/WhatsApp equilibrados a lo ancho, con icono + etiqueta
     corta (Cuenta/Carrito) -- en vez de quedar cargados a la derecha. Los
     3 con la misma area tactil minima de 44px. */
  .account-links { justify-content: space-between; gap: 0.5rem; }
  /* .account-links a (no solo la clase) para igualar la especificidad de la
     regla de escritorio ".account-links a { flex-shrink:0 }" (linea ~67) y
     ganar por orden de aparicion -- si no, ese flex-shrink:0 mas especifico
     bloqueaba el reparto equilibrado de ancho aqui. */
  .account-links a { flex: 1 1 0; flex-shrink: 1; justify-content: center; gap: 0.35rem; padding: 0.5rem 0.4rem; min-height: 44px; font-size: 0.85rem; white-space: nowrap; }
  .account-links__icon { display: inline-block; }

  /* El input ya trae su propio borde (regla global de forms.css); dentro
     del panel blanco del buscador eso se veia como un borde doble. El
     panel ya aporta el limite visual, asi que el campo no necesita el
     suyo aqui. */
  .search-panel .input-text { border-color: transparent; }
}

/* .account-links__icon solo se muestra en movil (arriba) -- en escritorio/
   tablet el boton sigue siendo solo texto, sin cambios visuales ahi. */
.account-links__icon { display: none; width: 18px; height: 18px; flex: 0 0 18px; }
