/* ═══════════════════════════════════════════════════════════════════════════
   WALMAR QUÍMICA — muestra del pedido
   Móvil primero: se llega escaneando un QR de papel, parado en el mostrador.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── TIPOGRAFÍAS (autoalojadas, sin CDN) ────────────────────────────────── */

/* Sólo el peso 800: la condensada se usa siempre en titular, y un peso que no
   se usa es peso que igual hay que subir al servidor. */
@font-face {
  font-family: 'Barlow Condensed';
  src: url('assets/fonts/barlowcondensed-800-latin.woff2') format('woff2');
  font-weight: 800; font-style: normal; font-display: swap;
}
/* IBM Plex Sans y no Inter: nació como tipografía técnica e industrial, que es
   el registro de una distribuidora química. Inter es la fuente por defecto de
   todo el software de los últimos años y no dice nada del rubro. Las dos tienen
   números tabulares, que es lo que la columna de precios necesita. */
@font-face {
  font-family: 'IBM Plex Sans';
  src: url('assets/fonts/ibmplexsans-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Sans';
  src: url('assets/fonts/ibmplexsans-600-latin.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'IBM Plex Sans';
  src: url('assets/fonts/ibmplexsans-700-latin.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}

/* ── TOKENS ─────────────────────────────────────────────────────────────── */

:root {
  /* Marca. Muestreados del logo, no inventados. */
  --tinta:       #021B3C;   /* la tinta oscura de las superficies CLARAS: precios, controles, texto fuerte sobre tarjeta */
  /* 🔄 Estos dos eran DERIVADOS del lienzo azul: subir un poco el azul para
     elevar una superficie, y bajarlo para separar. Con el lienzo en negro
     quedaron huérfanos y pasan a neutros.
     ⚠️ Y CAMBIAN DE NOMBRE, ⛔ no sólo de valor: un token llamado `--azul-*`
     con un gris adentro es cómo un sistema de diseño empieza a mentir. */
  --elevado:      #131218;   /* superficie apenas levantada del lienzo */
  --linea-oscura: #272430;   /* separadores SOBRE el lienzo */
  --amarillo:    #F0B006;
  --naranja:     #F16C19;   /* ⚠️ SÓLO detalles chicos. Nunca en bloque grande. */
  --blanco:      #FFFFFF;

  /* ── DOS FONDOS, y la diferencia importa ────────────────────────────────
     --lienzo → lo que hay ENTRE las tarjetas: es el azul de la marca, así que
                la página entera se lee como una sola pieza con el encabezado.
     --fondo  → superficie neutra clara para lo que va DENTRO de una tarjeta o
                del panel (chips, avisos, campos). ⛔ No confundirlos: usar
                --fondo en el lienzo devuelve la página casi blanca de antes.

     📌 La 001 decía "el azul es el marco, no el fondo" porque la lista era un
        talonario denso de 40 renglones y leer eso sobre azul cansa. Con la
        lista en tarjetas blancas ese motivo se cae: **no se lee sobre el azul,
        se lee sobre las tarjetas.** El azul quedó de lienzo. */
  /* 🔄 REBRAND 14-08-2026 — EL LIENZO PASÓ A NEGRO.
     Lo eligió MARCELO (su referencia es lettering de color sobre negro) y Luca
     lo ratificó dos veces con el argumento en contra sobre la mesa. ⛔ No se
     reabre. Ver specs/003-rebrand-walmar/research.md → R3.

     🔬 Muestreado de su arte, ⛔ no elegido a ojo: el fondo de la pieza da
     #040305. Acá va 3 puntos más arriba a propósito — negro absoluto con texto
     blanco produce HALACIÓN en pantallas OLED (el texto parece vibrar), y esta
     página se lee en un celular parado en un mostrador.

     ⚠️ EL AZUL NO SE FUE: cambió de rol. Ahora es el fondo del FOLLETO, que
     ⛔ no puede ir negro (negro pleno en papel se empasta, marca los dobleces
     y encarece). Es la versión imprimible del mismo oscuro. */
  --lienzo:      #08070B;
  --azul-papel:  #021B3C;

  /* 🔄 LOS CUATRO TOKENS DE SUPERFICIE SE DIERON VUELTA.
     Estaban bien usados —cada uno por su ROL: superficie, hueco, divisor,
     texto— así que ⛔ no hizo falta tocar las ~40 reglas que los consumen:
     cambia el VALOR y toda la página los sigue.
     🔑 Ésa es la prueba de que los roles estaban bien nombrados. Si en vez de
     `--superficie` se hubiera llamado `--blanco-tarjeta`, había que reescribir
     todo — el mismo error que tenían `--azul-claro` y `--azul-linea`. */
  --superficie:  #141319;   /* era #FFFFFF — la superficie de tarjetas y panel */
  --fondo:       #1B1A21;   /* era #F1F4F7 — huecos DENTRO de una superficie */
  --linea:       #2A2830;   /* era #DFE5EC — divisores */
  --texto:       #F4F2F6;   /* era #0E1B2A */
  --texto-suave: #B8B5BF;   /* era #5A6B7D */

  /* ── LOS 5 COLORES DE CATEGORÍA ──────────────────────────────────────────
     🔬 Muestreados del titular del arte de Marcelo, que lleva el degradado
     completo, ⛔ no inventados. Misma regla que los tokens de marca de arriba.

     🔑 Por qué existen: Marcelo pidió MÁS COLOR. Pero el color acá ⛔ no es
     adorno — cada rubro tiene el suyo, así que **también orienta**: el cliente
     sabe en qué sección está sin leer.

     ♿ Los cinco pasan AA como texto sobre el lienzo (medido: de 5,5:1 el más
     bajo a 13:1 el más alto). El más justo es el magenta. */
  --cat-quimica:  #F926A1;   /* Química a granel  — el rubro estrella, el color de la marca */
  --cat-bazar:    #00C0F8;   /* Bazar de limpieza — los trapos y cepillos celestes del balde */
  --cat-papeles:  #FFD22D;   /* Papeles           — cálido, como el papel */
  --cat-bolsas:   #AAE42C;   /* Bolsas            — el verde de las bolsas de residuo */
  --cat-envases:  #F98227;   /* Envases           — el naranja de los bidones */

  /* ── SUPERFICIES OSCURAS ────────────────────────────────────────────────
     🔴 EL CAMBIO QUE ORDENA TODO EL REDISEÑO. Antes las tarjetas eran BLANCAS
     y ocupaban ~70% de la pantalla, así que la página se leía como un panel
     administrativo con un tema oscuro encima: el color quedaba en los bordes y
     ⛔ ninguna cantidad de tokens nuevos iba a cambiar eso.
     ➡️ Ahora **el oscuro ocupa el 85-90% y el color vive en el 10-15%**, sólo
     donde hace un trabajo (orientar, marcar lo cargado, señalar el avance). */
  --carta:        #141319;   /* tarjeta de producto */
  --carta-activa: #191820;   /* tarjeta con producto cargado */
  --carta-borde:  #2A2830;   /* borde y divisores DENTRO de la tarjeta */
  --panel:        #111016;   /* la hoja del pedido: más honda que la tarjeta */
  --panel-borde:  #302D36;
  --control:      #1B1A21;   /* campos, selects y steppers */
  --control-borde:#34313C;
  --control-hover:#55505F;

  /* Texto sobre oscuro. ⚠️ Los secundarios llevan el tinte violáceo del lienzo,
     ⛔ no gris neutro: un gris puro sobre una superficie con temperatura se lee
     sucio. */
  --sobre-alto:   #F4F2F6;   /* nombres y texto principal */
  --sobre-medio:  #B8B5BF;   /* auxiliar */
  --sobre-bajo:   #8F8B97;   /* placeholder */
  --inactivo-bg:  #24222B;   /* botón deshabilitado */
  --inactivo-tx:  #A9A4B2;   /* ⚠️ más claro que el #77727E de la dirección: ese daba 3,4:1
                                y este texto es la INSTRUCCIÓN de qué falta hacer */

  /* ── EL AVISO NARANJA, SOBRE OSCURO ──────────────────────────────────────
     🔴 15-08 — ESTOS TRES VALORES ESTABAN ESCRITOS A MANO EN CUATRO LUGARES,
     y eran de la PALETA CLARA anterior: fondo `#FFF3EB`, texto `#A24608`,
     borde `#F5C7A6`. Sobre el lienzo negro se leían como recortes de otro
     sitio web — y aparecen justo cuando la página avisa que algo falta, o sea
     en el momento de más atención.
     ⚠️ Se encontró UNO mirando (el del selector de variante) y los otros TRES
     aparecieron barriendo la hoja: los campos de comercio y dirección, la nota
     de renglón y el aviso del pedido. **Donde hay un color suelto de una
     paleta muerta, casi nunca hay uno solo.**
     ♿ Medido: el texto sobre el fondo del aviso da 9,1:1. */
  --aviso-bg:     #2A1C10;
  --aviso-borde:  #5C3A18;
  --aviso-texto:  #F7B27A;

  /* ── EL RUBRO ACTIVO ─────────────────────────────────────────────────────
     `--rubro` es el color de la categoría que se está viendo. Lo resuelve el
     `data-cat` que `app.js` pone en el <body>, y de acá lo toman la línea de la
     tarjeta, el "+", el anillo, el foco y el botón de enviar.
     🔑 Como hay UNA categoría por vez, hay UN color por vez: es lo que impide
     que la pantalla se vuelva un arcoíris con cinco colores compitiendo. */
  --rubro: var(--cat-quimica);

  --display: 'Barlow Condensed', 'Arial Narrow', system-ui, sans-serif;
  --cuerpo:  'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --radio: 10px;
  --barra-alto: 68px;

  /* ── LAS SUPERFICIES FIJAS ───────────────────────────────────────────────
     🔴 ESTOS DOS NÚMEROS ESTABAN ESCRITOS A MANO EN TRES LUGARES QUE TIENEN
     QUE COINCIDIR, y nada los obligaba a hacerlo: el `top` de las categorías
     en la regla base decía 56, el de la regla de escritorio decía 70, y ahora
     se suma un tercero — el destino del botón del hero.
     ⚠️ Si el botón descuenta un número y las categorías usan otro, el primer
     producto aparece MEDIO TAPADO. Es un defecto que ⛔ no se ve leyendo el
     código: sólo aparece apretando el botón, o sea el que más chances tiene de
     llegar a producción. */
  --tope-alto: 56px;          /* el encabezado */
  --cats-alto: 48px;          /* la fila de categorías */
  --fijo-arriba: calc(var(--tope-alto) + var(--cats-alto));

  /* 1500 y no 1080: con la lista en grilla, el ancho de más se convierte en una
     columna más de productos en vez de en margen desperdiciado. Da 2 tarjetas
     por fila en un notebook y 3 en un monitor grande. */
  --ancho: 1500px;
}

/* ── BASE ───────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;

  /* 🔴 LAS DOS LÍNEAS QUE EVITAN QUE EL FOCO SE ESCONDA, y hacen falta porque
     esta página tiene DOS zonas ocupadas de forma permanente: arriba el
     encabezado + la fila de categorías, abajo la barra del pedido.
     ⚠️ Cuando algo recibe foco con Tab, el navegador lo scrollea "hasta que se
     vea" — y ⛔ no sabe nada de elementos fijos, así que lo deja justo en el
     borde, DEBAJO de la barra. Medido: los dos enlaces del pie quedaban tapados
     al enfocarlos, y con el teclado eso es un enlace que ⛔ no existe.
     ➡️ `scroll-padding` le dice al navegador cuánto NO puede usar. Una regla,
     y vale para el foco, para las anclas y para cualquier `scrollIntoView`. */
  scroll-padding-top: calc(var(--tope-alto) + var(--cats-alto) + 10px);
  scroll-padding-bottom: calc(var(--barra-alto) + 10px);
}

body {
  margin: 0;
  font-family: var(--cuerpo);
  font-size: 15px;
  line-height: 1.45;
  color: var(--texto);
  background: var(--lienzo);
  overflow-x: hidden;            /* red de seguridad: nunca scroll horizontal */
  -webkit-font-smoothing: antialiased;
}

button, input, select { font: inherit; color: inherit; }

/* iOS hace zoom al enfocar un campo de menos de 16px. Con esto no. */
input, select { font-size: 16px; }

:focus-visible {
  outline: 3px solid var(--amarillo);
  outline-offset: 2px;
  border-radius: 4px;
}
.sobre-oscuro :focus-visible { outline-color: var(--amarillo); }

/* ── SUPERFICIES DEL NAVEGADOR ──────────────────────────────────────────── */
/* Lo que uno NO dibuja también forma parte del diseño. Selección, cursor y
   barra de desplazamiento vienen con un gris que no pertenece a ninguna marca,
   y dejarlos así es la señal más barata de que una página fue ensamblada en vez
   de construida. */

/* 🔄 La selección era azul marino: sobre el lienzo negro casi ⛔ no se veía.
   Ahora es el magenta de la marca, que es el único color que aparece en las dos
   superficies (clara y oscura) sin cambiar de significado. */
::selection { background: var(--cat-quimica); color: var(--blanco); }
.sobre-oscuro ::selection { background: var(--cat-bazar); color: #08070B; }

input, textarea { caret-color: var(--cat-quimica); }

/* 🔄 El pulgar era azul (#2C5183) y quedaba huérfano sobre el negro. */
* { scrollbar-color: #3A3646 var(--lienzo); scrollbar-width: thin; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--lienzo); }
::-webkit-scrollbar-thumb {
  background: #3A3646;
  border-radius: 999px;
  border: 3px solid var(--lienzo);  /* el aire lo adelgaza sin achicar el blanco de agarre */
}
::-webkit-scrollbar-thumb:hover { background: #4C4759; }

/* La barra de la hoja del pedido vive DENTRO de una superficie blanca, así que
   ahí la barra vuelve a ser clara. */
.hoja-cuerpo { scrollbar-color: #3A3646 var(--panel); }
.hoja-cuerpo::-webkit-scrollbar-track { background: var(--panel); }
.hoja-cuerpo::-webkit-scrollbar-thumb { background: #3A3646; border-color: var(--panel); }

.limite { max-width: var(--ancho); margin: 0 auto; padding: 0 16px; }

.oculto-visual {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── ENCABEZADO ─────────────────────────────────────────────────────────── */

.tope {
  position: sticky; top: 0; z-index: 30;
  /* 🔄 Era el azul EXACTO del fondo cocido del PNG del logo. Con el logo en SVG
     transparente esa atadura desapareció y el encabezado puede seguir al
     lienzo, que es lo que hace que la página se lea como una sola pieza. */
  background: var(--lienzo);
  border-bottom: 1px solid var(--linea-oscura);
}
.tope .limite { display: flex; align-items: center; gap: 10px; height: var(--tope-alto); }

.tope img { height: 34px; width: auto; display: block; }

.tope-nombre {
  font-family: var(--display);
  font-weight: 800; font-size: 20px; letter-spacing: .01em;
  color: var(--blanco); text-transform: uppercase; line-height: 1;
}
/* La segunda palabra toma el cian de la marca — el mismo par de colores que el
   monograma: la W cálida y la M fría. */
.tope-nombre span { color: var(--cat-bazar); }

/* Hero: compacto a propósito. Esto no es una landing, es un talonario de
   pedidos — el que entra vino a pedir, no a leer. */
.hero {
  position: relative;
  background: var(--lienzo);
  overflow: hidden;
}
/* 🔄 15-08 — LA FOTO DE LOS ENVASES SE FUE Y ENTRARON LAS ONDAS.
   Lo pidió Luca con una referencia (`wavy-background`): trazos anchos y
   desenfocados con los colores del rubro, que es el mismo lenguaje del folleto.
   💰 Y de paso **la página adelgaza 106 kB**: `hero-web.jpg` era el archivo más
   pesado que se servía. El motor son ~3 kB de `ondas.js`.
   ⚠️ El JPG ⛔ NO se borró de `assets/`: el original sigue haciendo falta para
   las piezas impresas. Simplemente ya ⛔ no se sirve a la web. */
.hero-ondas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  /* El canvas se pinta a la mitad de resolución y el navegador lo estira: como
     todo lo de adentro está desenfocado, el estirado ⛔ no se nota. */
  opacity: .85;
}
/* 🔄 15-08 — EL VELO SE AFLOJÓ, porque ya ⛔ no está tapando lo mismo.
   Estaba calibrado para bajar una FOTO de envases, que traía detalle y bultos
   compitiendo con el titular. Las ondas ⛔ no tienen detalle: son manchas
   desenfocadas. Con los valores viejos (.94 arriba, .62 al medio) el efecto
   entero desaparecía y quedaba un resplandor gris.
   ⚠️ Pero ⛔ no se saca del todo, y ⛔ no es por gusto: el titular es blanco y el
   párrafo gris claro, y dos de los cinco colores —el amarillo y el verde— son
   CLAROS. Sin nada que los baje, el texto sobre esas dos ondas se cae de AA.
   ➡️ Los extremos siguen cerrados (arriba pega el encabezado, abajo la franja
   amarilla) y el centro se abre lo justo. */
.hero-velo {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(8,7,11,.86) 0%,
    rgba(8,7,11,.30) 50%,
    rgba(8,7,11,.92) 100%);
}
/* Centrado. ⚠️ Con `--ancho` en 1500 el bloque no puede quedar suelto a lo
   ancho: se le pone un tope propio para que el titular no se estire hasta el
   borde y el conjunto se lea como una pieza. */
/* 🔄 −20 % de alto (14-08). El hero ya era compacto, pero sigue siendo una BANDA
   DE PASO: el que llega escaneó un QR con el folleto en la mano, o sea que ya
   sabe qué es esto y a qué vino. Cada píxel que ocupa acá es un píxel que retrasa
   el primer precio. Lo que se recortó es AIRE —relleno, márgenes y el piso de
   alto—, ⛔ no el titular: ése es lo único que ata esta página al papel. */
/* 🔄 15-08 (tarde) — EL HERO VUELVE A RESPIRAR, y esto DESHACE a propósito el
   −15 % de la madrugada. ⚠️ ⛔ No es que aquello estuviera mal: el hero se había
   achicado porque **retrasaba el primer precio**, y era cierto.
   ➡️ Lo que cambió es que ahora hay un BOTÓN que baja al catálogo. El problema
   real ⛔ nunca fue el alto: era que para llegar a los productos había que
   descubrir el scroll. Con una puerta explícita, esconder la portada deja de
   ser necesario — y el alto se recupera en AIRE, ⛔ nunca achicando el titular,
   que es lo único que ata esta página al folleto impreso. */
.hero .limite {
  position: relative;
  padding-top: 40px; padding-bottom: 34px; min-height: 300px;
  display: flex; flex-direction: column; justify-content: center;
  text-align: center;
}

/* El botón se separa más de lo que se acerca: el aire de arriba lo despega del
   párrafo y lo deja leer como una acción, ⛔ no como el final del texto. */
.hero-cta { margin-top: 26px; align-self: center; }
.hero .limite > * { max-width: 46em; margin-left: auto; margin-right: auto; }

.hero h1 {
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  /* El techo baja de 58 a 52: sólo actúa de 580 px de ancho para arriba, así que
     ⛔ no le saca nada al celular —ahí manda el piso de 40— y en escritorio es
     donde el titular sobraba de tamaño para una banda de paso. */
  font-size: clamp(40px, 10vw, 52px);
  line-height: .9;
  letter-spacing: -.015em;
  text-transform: uppercase;
  color: var(--blanco);
  text-wrap: balance;
}
/* 🔴 SIN DEGRADADO SOBRE EL TEXTO, y coincidieron tres fuentes: el revisor de
   diseño, el piso de calidad y la dirección de arte. El motivo es el mismo:
   **texto con degradado es decorativo, ⛔ no significativo**, y es uno de los
   tells más reconocibles del diseño generado con IA — justo lo que este
   proyecto viene esquivando.
   💡 El degradado no se pierde: **vive en el logo**, que es donde la marca lo
   usa de verdad. Acá la jerarquía la hace el peso y el color plano. */
.hero h1 em {
  font-style: normal; display: block;
  color: var(--rubro);
}

.hero p {
  margin: 10px auto 0;
  max-width: 40em;
  /* 🔴 BLANCO, y ⛔ no el gris auxiliar de siempre. Medido: sobre la onda verde
     (`#AAE42C`, el más claro de los cinco) el gris `--sobre-medio` daba
     **3,27:1** y AA pide 4,5 — o sea que el fondo nuevo se había comido la
     legibilidad del único párrafo que explica qué es esto. En blanco da 6,3:1.
     ⚠️ La jerarquía ⛔ no se pierde: contra el titular sigue habiendo 52 px de
     condensada 800 en mayúsculas contra 16 px de regular. Acá el color ⛔ no era
     lo que separaba esos dos niveles. */
  color: var(--blanco);
  font-size: 16px;
  text-wrap: pretty;
}

/* ── MARQUESINA DE RUBROS ────────────────────────────────────────────────────
   🔑 LO QUE LA HACE VERSE CARA ⛔ NO ES QUE SE MUEVA: SON LOS BORDES QUE SE
   DESVANECEN. Con el mismo movimiento y los ítems cortándose contra el filo,
   la pieza se lee como un <marquee> de 1998. Si hay una sola cosa de acá que
   tiene que quedar bien hecha, es la máscara.

   ⚠️ Y va con `mask-image` y ⛔ NO con un degradado encima fingiendo el fondo:
   detrás hay un canvas de ondas que cambia de color todo el tiempo, así que
   cualquier degradado que imite el fondo se delata en cuanto pasa una onda.
   La máscara recorta de verdad y ⛔ no le importa qué hay atrás. */
.marquesina {
  position: relative;
  margin-top: 4px;
  /* Dos líneas, y ⛔ no son decorativas: cierran la marquesina COMO BANDA.
     · Arriba, la ámbar de siempre — la que ya separaba los rubros del hero.
     · Abajo (15-08, lo pidió Luca) la neutra del sistema: sin ella la
       marquesina y la fila de categorías se tocaban, y siendo las dos filas de
       mayúsculas espaciadas se leían como UN solo bloque de dos renglones.
     ⚠️ La de abajo va acá y ⛔ no como `border-top` de las categorías: esa fila
     es PEGAJOSA, así que al scrollear se pega debajo del encabezado —que ya
     tiene su propia línea— y quedarían dos rayas juntas. */
  border-top: 1px solid rgba(240,176,6,.35);
  border-bottom: 1px solid var(--linea-oscura);
  padding: 12px 0 14px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 10%, #000 90%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 10%, #000 90%, transparent 100%);
}

.marquesina-tira {
  list-style: none; margin: 0; padding: 0;
  display: flex; align-items: center;
  /* ⚠️ Sin esto la tira se topa al ancho del padre y las 24 piezas se apilan:
     ⛔ no habría nada que desplazar. */
  width: max-content;
  /* El desplazamiento lo maneja la API de animaciones desde `app.js`, ⛔ no una
     animación CSS — ver el comentario de `armarMarquesina()`. */
  will-change: transform;
}

.marquesina-tira li {
  flex: none;
  display: flex; align-items: center;
  font-size: 10.5px; font-weight: 700; letter-spacing: .13em;
  color: var(--blanco); text-transform: uppercase;
  white-space: nowrap;
}
/* El separador viaja CON cada rubro, así el bucle empalma sin un hueco raro
   entre la última pieza de una copia y la primera de la siguiente. */
.marquesina-tira li::after {
  content: '·';
  margin: 0 22px;
  color: var(--amarillo);
  opacity: .8;
}

/* ♿ MOVIMIENTO REDUCIDO: ⛔ no alcanza con frenarla.
   Una tira quieta mide más que la pantalla, así que se quedarían SEIS rubros
   afuera — y el requisito es que se lean los DOCE. Acá vuelve a ser lo que era:
   una lista que envuelve, centrada, sin máscara (⛔ nada que desvanecer) y sin
   la copia del bucle. */
@media (prefers-reduced-motion: reduce) {
  .marquesina {
    -webkit-mask-image: none;
            mask-image: none;
    padding-inline: 16px;
  }
  .marquesina-tira {
    width: auto;
    flex-wrap: wrap; justify-content: center;
    max-width: 40em; margin-inline: auto;
    transform: none !important;
  }
}

/* ── ÍCONOS ─────────────────────────────────────────────────────────────── */

/* Uno solo para todos, y lo que manda es el PESO DEL TRAZO, no el dibujo: a
   este tamaño dos íconos con grosores distintos se leen de familias distintas
   por bien dibujados que estén. Cuando la caja se achica, el trazo sube en la
   misma proporción para que el peso ÓPTICO no cambie. */
.icono {
  width: var(--ico, 20px); height: var(--ico, 20px); flex: none;
  fill: none; stroke: currentColor;
  stroke-width: var(--ico-trazo, 1.75);
  stroke-linecap: round; stroke-linejoin: round;
}

/* ── AVISO DE MUESTRA ───────────────────────────────────────────────────── */

/* 🔴 ESTA LÍNEA ARREGLA UN BUG QUE ESTUVO VIVO TODO EL PROYECTO SIN QUE SE VIERA.
   `display: flex` en la clase (0,1,0) le gana al `[hidden] { display: none }`
   que trae el navegador (0,0,1), así que poner el atributo `hidden` ⛔ NO
   ocultaba nada: `CONFIG.esMuestra = false` apagaba el aviso del mensaje de
   WhatsApp pero **la franja amarilla seguía en pantalla**. Nunca se notó porque
   la bandera estuvo en `true` desde el primer día.
   🔑 La regla general: **todo elemento que se oculte con `hidden` y tenga un
   `display` propio necesita su `[hidden]`.** En esta hoja los otros seis ya lo
   tenían — a éste se le había escapado. */
.aviso-muestra[hidden] { display: none; }
.aviso-muestra {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  margin: 0;
  background: var(--amarillo);
  color: #08070B;
  font-weight: 700; font-size: 12.5px;
  text-align: center;
  padding: 8px 16px;
  --ico: 17px; --ico-trazo: 2.06;   /* 1,75 × 20/17 → mismo peso a la vista */
}

/* ── CATEGORÍAS ─────────────────────────────────────────────────────────── */
/* Dos formas de la MISMA lista vertical: en celular sube desde abajo como una
   hoja (igual que el pedido, así se aprende una sola vez) y en pantalla ancha
   es una columna que siempre está. ⛔ Nunca una tira horizontal. */

/* El botón que dice qué se está viendo. Sólo celular. */
.selector { display: none; }   /* 🔄 abría la hoja de categorías: ya no hay hoja */
.selector-viejo {
  position: sticky; top: 54px; z-index: 20;
  background: var(--lienzo);
  border-bottom: 1px solid var(--linea-oscura);
}
.selector button {
  width: 100%;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px;
  border: 0; background: none; cursor: pointer; text-align: left;
}
.selector-rotulo {
  font-size: 10.5px; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: #9A9AA8;
}
.selector-nombre {
  flex: 1; min-width: 0;
  font-family: var(--display); font-weight: 800; font-size: 19px; line-height: 1.15;
  text-transform: uppercase; color: var(--blanco);
}
.selector .icono { color: #9A9AA8; }

/* 🔄 EN CELULAR ERA UNA HOJA QUE SE ABRÍA. Ahora es una BARRA HORIZONTAL fija
   debajo del encabezado, siempre visible.
   🔑 El motivo es de uso: cambiar de rubro era **tres toques** (abrir el menú,
   elegir, esperar que se cierre) y ahora es **uno**. En un mostrador, con el
   pedido a medio cargar, eso decide si el comercio recorre el catálogo o pide
   sólo lo que ya venía sabiendo.
   ⛔ El `.selector` que abría la hoja desaparece: ya no hay nada que abrir. */
.categorias[hidden] { display: none; }
.categorias {
  position: sticky; top: var(--tope-alto); z-index: 25;
  background: var(--lienzo);
  border-bottom: 1px solid var(--linea-oscura);
  /* ⚠️ `clip` y ⛔ NO `hidden`. Los dos cortan el desborde de la tira, pero
     `hidden` crea un contenedor de scroll y eso **rompe el `sticky`**: el
     elemento deja de pegarse y se va con la página. `clip` corta sin crear ese
     contenedor. Sin esto el documento medía 405 px en una pantalla de 390 y
     toda la página se movía de costado. */
  overflow-x: clip;
}
/* 🔄 RESTOS DE CUANDO ERA UNA HOJA QUE SE ABRÍA: el rótulo "CATEGORÍAS" con su
   ✕, y la caja con esquinas redondeadas que subía desde abajo.
   ⛔ Con la barra siempre visible ⛔ no tienen función: ese rótulo gastaba 56 px
   de alto para nombrar algo que ya se ve. Los nodos siguen en el HTML porque
   los usa el lector de pantalla; acá se ocultan a la vista. */
.categorias-cabeza { display: none; }
.categorias-caja {
  background: none; border-radius: 0; max-height: none;
  animation: none; padding-bottom: 0;
}

/* La tira: se desplaza a lo ancho cuando los cinco rubros no entran, sin barra
   a la vista. ⚠️ `scroll-snap` alinea el que se toca, así ⛔ no queda uno
   cortado al medio. */
.categorias-lista {
  list-style: none; margin: 0; padding: 0 16px;
  display: flex; align-items: stretch; gap: 22px;
  /* 🔄 15-08 — CENTRADA (lo pidió Luca). Ahora que el catálogo usa todo el
     ancho, la fila arrancando pegada a la izquierda quedaba descolgada del
     resto de la página, que está centrado.
     🔴 LAS DOS LÍNEAS SON A PROPÓSITO Y EL ORDEN IMPORTA. Esta tira SCROLLEA en
     horizontal cuando los rubros no entran, y en un contenedor con scroll un
     `center` común empuja el desborde hacia los DOS lados: el primer rubro
     queda cortado **y no hay forma de scrollear hasta él**, porque el scroll
     ⛔ no llega a valores negativos. Es una trampa clásica del centrado en flex
     y ⛔ no se ve en escritorio, sólo en el celular — justo donde se usa.
     ➡️ `safe center` centra SÓLO si entra, y si no entra vuelve solo al inicio.
     La primera línea es el respaldo para un navegador que no lo entienda: se
     queda en el comportamiento de antes, que es el seguro. */
  justify-content: flex-start;
  justify-content: safe center;
  height: var(--cats-alto);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  max-width: var(--ancho); margin-inline: auto;
}
.categorias-lista::-webkit-scrollbar { display: none; }
.categorias-lista > li { flex: none; display: flex; scroll-snap-align: start; }

.categoria {
  display: block; width: 100%; text-align: left;
  border: 0; background: none; padding: 0;
  font-family: var(--display); font-weight: 800;
  font-size: 15px; line-height: 1.15; letter-spacing: .005em;
  text-transform: uppercase;
  color: #9A96A1;
  display: flex; align-items: center; white-space: nowrap;
  cursor: pointer;
  transition: color .18s ease;
}
/* 🌈 CADA RUBRO CON SU COLOR.
   Marcelo pidió más color, y acá el color ⛔ no es adorno: **orienta**. El que
   está pidiendo sabe en qué sección está sin leer el rótulo.

   🔑 Va por atributo y ⛔ no por JS: el color es sistema visual, así que vive
   en la hoja de estilos. El botón ya trae `data-cat`, ⛔ no hizo falta tocar
   una línea de `app.js`.
   ⚠️ Si mañana entra una categoría nueva y ⛔ nadie le asigna color, hereda el
   blanco del respaldo de abajo: se ve sobria, ⛔ no rota. */
.categoria { --color-cat: var(--blanco); }
.categoria[data-cat="Química a granel"]  { --color-cat: var(--cat-quimica); }
.categoria[data-cat="Bazar de limpieza"] { --color-cat: var(--cat-bazar); }
.categoria[data-cat="Papeles"]           { --color-cat: var(--cat-papeles); }
.categoria[data-cat="Bolsas"]            { --color-cat: var(--cat-bolsas); }
.categoria[data-cat="Envases"]           { --color-cat: var(--cat-envases); }

/* El mismo mapa, pero para la PÁGINA: lo escribe `app.js` en el <body>. */
body[data-cat="Química a granel"]  { --rubro: var(--cat-quimica); }
body[data-cat="Bazar de limpieza"] { --rubro: var(--cat-bazar); }
body[data-cat="Papeles"]           { --rubro: var(--cat-papeles); }
body[data-cat="Bolsas"]            { --rubro: var(--cat-bolsas); }
body[data-cat="Envases"]           { --rubro: var(--cat-envases); }

.categoria[aria-current] { color: var(--blanco); }   /* la activa va BLANCA; el color lo pone la regla */
.categoria:hover { color: var(--color-cat); }

/* La marca de "estás acá": una regla amarilla DEBAJO DE LA PALABRA, que es el
   mismo recurso que la franja de rubros del hero. ⛔ No una barra al costado:
   eso es el andamio de siempre y además no dice nada del sistema de la página.
   🔑 Sirve sin color (está o no está) y sin cursor, que es lo que pide FR-005.
   ⚠️ Y el CUERPO no cambia entre activa e inactiva: con cinco ítems, agrandar
      la activa reacomodaría la lista entera en cada toque. */
.rodillo { display: inline-block; position: relative; }
.categoria[aria-current] .rodillo::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: -5px; height: 3px;
  background: var(--color-cat);   /* 🔄 era el amarillo fijo: ahora es el del rubro */
}

/* El rodillo de letras (NAV-1). Cada letra es una ventanita con la misma letra
   dos veces; al pasar el cursor el par sube y entra la de abajo. El retardo por
   letra es lo que hace que a mitad de camino se vean desfasadas.
   ⚠️ La ventana mide 1,15em y NO 1em: "QUÍMICA A GRANEL" lleva tilde en
      mayúscula, y a 1em el acento se corta. */
.palabra { display: inline-block; white-space: nowrap; }
.letra { display: inline-block; overflow: hidden; height: 1.15em; vertical-align: bottom; }
.letra .par {
  display: block;
  transition: transform .38s cubic-bezier(.22, 1, .36, 1);
  transition-delay: calc(var(--i) * 18ms);
}
.letra .par > span { display: block; height: 1.15em; line-height: 1.15; }
.categoria:hover .par,
.categoria:focus-visible .par { transform: translateY(-50%); }

/* ── LISTA DE PRODUCTOS ─────────────────────────────────────────────────── */

/* 🔑 GRILLA, ⛔ no una columna. Con una sola tarjeta por fila hay que scrollear
   mucho para ver un catálogo, y la referencia CARD-3 es justamente una grilla.
   `auto-fill` decide sola: 1 columna en el celular, 2 en un escritorio normal y
   3 en pantallas anchas — sin puntos de corte a mano.
   🔄 15-08 — ERA `align-items: start`, con la nota de que estirar las tarjetas
      al alto de la fila era "exactamente lo que la referencia advierte que NO hay
      que hacer". ⚠️ **Eso era una MALA LECTURA del reparo.** Lo que CARD-3 marca
      es la grilla de cajas con el mismo CONTENIDO GENÉRICO —ícono + título +
      texto, seis veces—; acá cada tarjeta lleva datos propios y distintos
      (precio, rinde, variante, envase), y eso ⛔ no cambia porque los bordes de
      abajo queden alineados.
   ➡️ Estiradas se gana algo que se usa: **todos los `+` de una fila caen a la
      misma altura**, así que la mano vuelve siempre al mismo lugar. Se paga con
      aire dentro de la tarjeta más corta, que sobre superficie oscura ⛔ casi no
      se ve. Verificado mirando las dos versiones, ⛔ no discutido en abstracto. */
.lista {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
  align-items: stretch;
  padding: 14px 16px calc(var(--barra-alto) + 28px);
  max-width: var(--ancho); margin: 0 auto;
}
.lista-vacia { grid-column: 1 / -1; }

/* La tarjeta. 🔑 Lo premium NO sale de agregarle efectos: sale de que use la
   tipografía que el resto de la página ya usa. Antes esto era IBM Plex 15,5 px
   sobre una caja blanca con borde gris — el aspecto por defecto de cualquier
   generador. Ahora el nombre y el precio hablan como el hero y el folleto.
   ⛔ Ninguna tarjeta lleva regla amarilla propia: el amarillo marca el ahorro y
      dónde estás parado, y puesto en las diez no significaría nada. */
/* La sombra es del AZUL de la marca, ⛔ no un gris neutro: una sombra gris sobre
   un fondo entonado se ve sucia. Y lleva desplazamiento + desenfoque suave —un
   halo sin desplazamiento es decoración, no profundidad. */
/* Columna flexible para que el bloque de controles pueda anclarse al pie (ver
   `.producto-controles`). ⚠️ Al pasar a flex, los hijos se estiran a lo ancho por
   defecto: los dos que miden lo que dice su texto —el chip del rinde y la nota
   del envase— llevan `align-self: flex-start` para no volverse barras. */
.producto {
  display: flex; flex-direction: column;
  position: relative;
  background: var(--carta);
  border: 1px solid var(--carta-borde);
  border-radius: 14px;
  padding: 19px 16px 16px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .28);
  transition: border-color .16s ease, background-color .16s ease,
              box-shadow .16s ease, transform .16s ease;
}
/* 🎨 EL ÚNICO COLOR DE LA TARJETA. Tres píxeles alcanzan para decir de qué rubro
   es sin que la tarjeta se vuelva de color: la diferencia entre acento y fondo.
   ⚠️ Va como PIEZA PROPIA y ⛔ no como `border-top`. Con borde, la línea sigue
   el radio de 14 px y se curva hacia abajo en las dos puntas: deja de leerse
   como una regla y pasa a leerse como un arco mal cerrado. Metida hacia adentro
   el ancho del radio, es una línea recta que ⛔ nunca toca las curvas. */
.producto::before {
  content: '';
  position: absolute; top: -1px; left: 14px; right: 14px; height: 3px;
  background: var(--rubro);
  border-radius: 0 0 2px 2px;
}
.producto:hover {
  border-color: var(--control-hover);
  box-shadow: 0 8px 26px rgba(0, 0, 0, .42);
  transform: translateY(-2px);
}

/* Un producto ya cargado se distingue SIN leer el número: el borde pasa a tinta
   plena y se le suma un aro del color de la marca, que es lo que lo hace saltar
   de la grilla sin cambiar de tamaño ni mover a los vecinos. */
/* 🔄 CARGADO, sin aro y sin resplandor. Antes era un aro amarillo de 3 px
   alrededor de toda la tarjeta: sobre superficie oscura eso es exactamente el
   glow que la dirección prohíbe, y con diez tarjetas cargadas la pantalla se
   llena de halos.
   ➡️ Ahora lo dice la SUPERFICIE: la tarjeta cargada se aclara un punto y su
   línea superior engorda. Se distingue de un vistazo, ⛔ no cambia de tamaño y
   ⛔ no mueve a las vecinas. */
.producto.en-pedido {
  background: var(--carta-activa);
  border-color: var(--control-hover);
}
/* Cargado: la línea se ensancha y se estira hasta las puntas. Se nota de un
   vistazo, ⛔ sin cambiar el tamaño de la tarjeta ni mover a las vecinas. */
.producto.en-pedido::before { height: 5px; left: 8px; right: 8px; }
.producto.en-pedido:hover {
  box-shadow: 0 8px 26px rgba(0, 0, 0, .48);
}

.producto-cabeza { display: flex; align-items: flex-start; gap: 12px; }

.producto-nombre {
  flex: 1; min-width: 0; margin: 0;
  font-family: var(--display); font-weight: 800;
  font-size: 21px; line-height: 1.05; letter-spacing: .005em;
  text-transform: uppercase;
  color: var(--sobre-alto);
  text-wrap: balance;
}
.producto-presentacion {
  display: block;
  margin-top: 5px;
  font-family: var(--cuerpo);
  font-weight: 700; font-size: 10.5px; letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--sobre-medio);
}

/* La píldora vive en la fila del precio. 🔴 En la del nombre NO puede ir: al
   aparecer le robaba ancho al título, el nombre pasaba a dos renglones y la
   tarjeta crecía de golpe — todo lo de abajo saltaba en cada `+`. */
.producto-fila-precio {
  position: relative;
  display: flex; align-items: baseline; gap: 12px;
}
.producto-estado[hidden] { display: none; }
/* 🔑 Absoluta a propósito: así NO aporta alto a la fila. En flujo, aparecer y
   desaparecer movía la fila 3 px y eso se siente como que la página tiembla. */
.producto-estado {
  position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  padding: 4px 9px; border-radius: 6px;
  background: var(--rubro); color: #08070B;
  font-family: var(--display); font-weight: 800;
  font-size: 12px; line-height: 1.2; letter-spacing: .04em;
  text-transform: uppercase; white-space: nowrap;
}

/* El dato dominante de la tarjeta. */
.producto-precio {
  flex: none;
  margin-top: 11px;
  font-family: var(--display); font-weight: 800;
  font-size: 34px; line-height: .95; letter-spacing: -.005em;
  font-variant-numeric: tabular-nums;
  color: var(--blanco);
  white-space: nowrap;
}
.producto-precio small {
  display: block; margin-top: 4px;
  font-family: var(--cuerpo);
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em;
  color: var(--sobre-medio); text-transform: uppercase;
}

/* El rinde es argumento de PLATA para un comercio, no una nota al pie: es lo
   que convierte un precio por litro en costo por uso. Por eso va en el amarillo
   de la marca, que en esta página significa "acá ganás". */
/* 🔄 Era una píldora CLARA (crema con borde arena) heredada de cuando la tarjeta
   era blanca. Sobre superficie oscura eso es un parche que grita más que el
   precio, y encima es el único elemento claro de toda la pantalla.
   ➡️ Ahora el amarillo va en el TEXTO y el fondo apenas se levanta. Sigue
   diciendo "acá ganás" y ⛔ ya no le compite al precio. */
.rinde {
  display: inline-block;
  align-self: flex-start;   /* mide lo que dice su texto, ⛔ no una barra */
  margin-top: 11px;
  padding: 5px 10px;
  background: rgba(240, 176, 6, .12);
  border: 1px solid rgba(240, 176, 6, .32);
  border-radius: 6px;
  font-size: 12.5px; font-weight: 700; color: var(--amarillo);
}

/* 🔄 Era `flex` con `wrap`, y entonces el envoltorio lo decidía el ancho que
   sobrara: en una tarjeta CON variante el selector se comía la primera línea y
   el contador caía SOLO al renglón de abajo, pegado a la derecha, dejando un
   hueco a su izquierda que se lee como un error de armado. Peor: como el wrap
   depende del ancho disponible, la MISMA tarjeta cambiaba de alto según si la
   grilla estaba en 2 o en 3 columnas.
   ➡️ Ahora la estructura es fija: el selector ocupa su propio renglón a lo
   ancho, y abajo van el envase y el contador, uno en cada punta.
   ⛔ Los altos NO se igualan a la fuerza —`align-items: start` en `.lista` sigue
      en pie y las tarjetas siguen midiendo lo que miden—: lo que se ataca acá es
      la CAUSA de que fueran tan distintas, ⛔ no el síntoma. */
.producto-controles {
  display: grid;
  /* Al pie de la tarjeta: con las alturas igualadas, esto alinea todos los "+"
     de una fila a la misma altura. Reemplaza al `margin-top: 13px` de antes. */
  margin-top: auto;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;

  padding-top: 13px;
  border-top: 1px solid var(--linea);
}

/* 📵 Debajo de 360 px la fila de abajo ya no entra: el contador mide 138 y la
   etiqueta necesita ~130, y en una tarjeta de 256 útiles eso parte "Traigo mi
   envase" en dos renglones. Ahí —y sólo ahí— el contador vuelve a bajar a su
   propio renglón, que es lo que el `flex-wrap` viejo hacía SIEMPRE.
   🔑 La regla no se elige a ojo: sale de sumar los dos anchos. */
@media (max-width: 359px) {
  .producto-controles { grid-template-columns: 1fr; }
}

/* ── SELECTOR DE VARIANTE ────────────────────────────────────────────────────
   🔄 15-08 — DEJÓ DE SER UN `<select>`. La lista que despliega un select LA
   DIBUJA EL SISTEMA OPERATIVO —blanca, con la fila azul de Windows— y ⛔ ninguna
   propiedad CSS la alcanza. Sobre una página negra eso es una ventana de otro
   programa abriéndose encima. */

.variante {
  grid-column: 1 / -1;      /* siempre un renglón propio, ⛔ nunca compartido */
  position: relative;
  min-width: 0;
}

.variante-boton {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  /* `--control` es el token de "campos, selects y steppers": el rol correcto. */
  border: 1px solid var(--control-borde); border-radius: 8px;
  background: var(--control); color: var(--texto);
  text-align: left; cursor: pointer;
  transition: border-color .16s ease, background-color .16s ease;
}
.variante-boton:hover { border-color: var(--control-hover); }
.variante-valor { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Sin elegir, el rótulo es una instrucción y ⛔ no un valor: va apagado, como
   cualquier texto de reposo de un campo. */
.variante.sin-elegir .variante-valor { color: var(--sobre-bajo); }
.variante-flecha { color: var(--sobre-bajo); --ico: 18px; transition: transform .18s ease; }
.variante[data-abierto="true"] .variante-flecha { transform: rotate(180deg); }

/* 🔴 EL AVISO DE "FALTA ELEGIR". Acá vivía el bug que vio Luca: era
   `background: #FFF3EB`, un crema del diseño CLARO anterior escrito a mano que
   nunca se migró. Sobre negro se leía como un recorte de otro sitio, y aparecía
   justo cuando la página avisa que falta algo. */
.variante.falta .variante-boton { border-color: var(--naranja); background: var(--aviso-bg); }

/* La lista. 🔑 Se levanta sobre las tarjetas vecinas: sin el apilado, en una
   grilla de cuatro columnas se desplegaría POR DEBAJO de la de al lado. */
.variante-lista {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  z-index: 30;
  list-style: none; margin: 0; padding: 5px;
  background: var(--elevado);
  border: 1px solid var(--control-borde); border-radius: 10px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, .55);
  /* 🔴 EL ALTO MÁXIMO ⛔ NO ES OPCIONAL: hay un producto con ~40 fragancias y sin
     tope la lista mide más que la pantalla. */
  max-height: 260px; overflow-y: auto;
  overscroll-behavior: contain;   /* llegar al final ⛔ no arrastra la página */
  scrollbar-width: thin; scrollbar-color: #3A3646 var(--elevado);
}
.variante-lista[hidden] { display: none; }

/* Hacia arriba cuando abajo no hay lugar: abajo del todo está la barra fija del
   pedido y la lista quedaría debajo de ella. */
.variante.hacia-arriba .variante-lista { top: auto; bottom: calc(100% + 6px); }

.variante-opcion {
  padding: 8px 10px; border-radius: 6px;
  color: var(--sobre-alto); cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 🔑 UNA sola marca de "acá estás", compartida por el mouse y por el teclado.
   Con dos estados distintos —hover y foco— la lista muestra dos resaltados a la
   vez y ⛔ no se sabe cuál se va a elegir al apretar Enter. */
.variante-opcion.activa { background: var(--control); }
/* La elegida se marca con el color del rubro, que es el mismo idioma que usa la
   categoría activa y la tarjeta cargada. */
.variante-opcion[aria-selected="true"] { color: var(--rubro); font-weight: 600; }
/* 🔴 EL TILDE VA DIBUJADO, ⛔ NO como carácter "✓".
   Es el MISMO trazo que la marca de verificación de los renglones del pedido:
   un glifo de texto tiene el peso que decida la tipografía y se lee de otra
   familia que el resto de los íconos — que es justo la señal de "hecho con un
   generador" que este proyecto vino a sacar (ya pasó con los emojis).
   🔑 Va como MÁSCARA y ⛔ no como imagen de fondo, para que tome
   `currentColor` y siga el color del rubro activo. */
.variante-opcion[aria-selected="true"]::after {
  content: ''; float: right;
  width: 16px; height: 16px; margin-left: 10px;
  background-color: currentColor;
  --tilde: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 10.5l3.5 3.5 7.5-8'/%3E%3C/svg%3E");
  -webkit-mask: var(--tilde) center / contain no-repeat;
          mask: var(--tilde) center / contain no-repeat;
}

/* La tarjeta con la lista abierta se levanta sobre sus vecinas de la grilla. */
.producto:has(.variante[data-abierto="true"]) { z-index: 20; }

.envase {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13.5px; font-weight: 600; color: var(--texto-suave);
  cursor: pointer;
}
.envase input { width: 17px; height: 17px; accent-color: var(--rubro); margin: 0; }

/* Misma familia que el rinde —información que se lee, no un control—, pero en
   gris: es una limitación, no un argumento de venta. */
.envase-incluido {
  display: inline-block;
  align-self: flex-start;   /* mide lo que dice su texto, ⛔ no una barra */
  margin: 11px 0 0;
  font-size: 12.5px; font-weight: 600; color: var(--texto-suave);
  background: var(--fondo); border: 1px solid var(--linea);
  border-radius: 6px; padding: 5px 10px;
}

/* Selector de cantidad: el corazón del talonario. Blancos de toque grandes.
   📱 44 × 44 y ⛔ no 40: es el único control que se toca DIEZ veces seguidas,
   parado detrás de un mostrador y muchas veces con una mano sola. 40 px es el
   piso de lo aceptable; 44 es el mínimo recomendado para el dedo, y acá se paga
   solo. En escritorio bajan a 40 (más abajo): con mouse el blanco de toque deja
   de ser el límite y 44 empieza a agrandar la tarjeta al pedo. */
.cantidad { margin-left: auto; display: flex; align-items: center; gap: 2px; }
.cantidad button {
  width: 44px; height: 44px;
  border: 1px solid var(--control-borde); background: var(--control);
  font-size: 20px; font-weight: 600; line-height: 1;
  color: var(--sobre-alto); cursor: pointer;
}
.cantidad button:first-child { border-radius: 8px 0 0 8px; }
.cantidad button:last-child  { border-radius: 0 8px 8px 0; background: var(--rubro); color: #08070B; border-color: var(--rubro); }
.cantidad button:disabled { opacity: .35; cursor: default; }
.cantidad output {
  min-width: 46px; height: 44px;
  display: grid; place-items: center;
  border-top: 1px solid var(--linea); border-bottom: 1px solid var(--linea);
  font-weight: 700; font-variant-numeric: tabular-nums;
}
.cantidad output.cargado {
  background: var(--control); color: var(--blanco);
  border-color: var(--rubro);
}

/* 🔴 El ícono va como SVG dibujado, ⛔ NUNCA como emoji. Era el último de los
   tres que marcaba T050: los otros dos (el aviso de muestra y el ✕ de cerrar)
   ya estaban pasados en `index.html`, y éste quedó vivo en producción. Un emoji
   lo dibuja el sistema operativo, así que sale distinto en cada teléfono y con
   otro peso de trazo que el resto de los íconos de la página — que es
   exactamente la señal de "hecho con un generador" que este rediseño vino a
   sacar. `align-items: start` para que el triángulo quede pegado al primer
   renglón cuando el texto ocupa dos o tres. */
.nota-renglon {
  margin-top: 9px;
  font-size: 12.5px; font-weight: 600;
  color: var(--aviso-texto);
  background: var(--aviso-bg); border: 1px solid var(--aviso-borde);
  padding: 6px 9px; border-radius: 6px;
  display: flex; align-items: start; gap: 6px;
}
.nota-renglon .icono { color: var(--naranja); margin-top: 1px; }
.nota-cargado {
  margin-top: 9px; font-size: 12.5px; color: var(--texto-suave);
}

/* ── BARRA DE PEDIDO (fija abajo en celular) ────────────────────────────── */

.barra {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  /* ⚠️ Un punto MÁS CLARO que el lienzo, ⛔ no igual: esta barra flota sobre el
     contenido y necesita despegarse. Sobre azul lo hacía el propio azul; sobre
     negro, si fuera del mismo color, el borde de 1 px sería lo único que la
     separa y en un celular con brillo bajo eso ⛔ no se ve. */
  background: var(--elevado);
  border-top: 1px solid var(--linea-oscura);
  padding-bottom: env(safe-area-inset-bottom);
}
.barra .limite {
  display: flex; align-items: center; gap: 12px;
  height: var(--barra-alto);
}
.barra-total { flex: 1; min-width: 0; color: var(--blanco); }
.barra-total b {
  display: block;
  font-size: 21px; font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.barra-total span { font-size: 12px; color: #9AA0AC; }   /* 🔄 era azulado */

.boton {
  flex: none;
  padding: 13px 20px;
  border: 0; border-radius: 8px;
  /* 🔄 Era amarillo sobre azul. Ahora el botón es el MAGENTA de la marca — el
     mismo del monograma y del balde.
     🔑 Es el ÚNICO botón sólido de color de la página, y eso es a propósito: en
     una pantalla con cinco colores, el que manda tiene que estar UNA sola vez.
     ⚠️ Texto en el negro del lienzo y ⛔ no blanco: sobre estos cinco colores
     saturados el negro da 8-13:1 y el blanco apenas 2-4:1. El instinto de poner
     blanco sobre color es justo el que rompe el contraste. */
  background: var(--rubro); color: #08070B;
  font-weight: 700; font-size: 15px;
  cursor: pointer;
}
/* ⚠️ El deshabilitado NO puede ser un gris apagado: este botón es el que dice
   QUÉ FALTA ("Cargá algo para poder enviar", "Completá comercio y dirección").
   WCAG exime a los controles inactivos, pero acá el texto es la instrucción, así
   que se mide igual. #C6C9D2 sobre #2E2B38 da 8,1:1. */
.boton:disabled { background: var(--inactivo-bg); color: var(--inactivo-tx); cursor: default; }
.boton-ancho { width: 100%; }

/* ── HOJA DEL PEDIDO ────────────────────────────────────────────────────── */

.hoja[hidden] { display: none; }
.hoja {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; justify-content: flex-end;
  background: rgba(2,27,60,.55);
}
.hoja-caja {
  background: var(--panel);
  border-radius: 16px 16px 0 0;
  max-height: 88vh;
  display: flex; flex-direction: column;
  animation: subir .22s ease-out;
}
@keyframes subir { from { transform: translateY(14px); opacity: .6; } to { transform: none; opacity: 1; } }

.hoja-cabeza {
  display: flex; align-items: center; gap: 12px;
  padding: 16px; border-bottom: 1px solid var(--linea);
}
/* ⚠️ BLANCO y ⛔ no del color del rubro. El color de rubro tiene una lista corta
   de lugares donde puede aparecer (línea de tarjeta, "+", anillo, foco, botón de
   enviar) y un título de panel ⛔ no está en ella: si el color se usa para todo,
   deja de señalar nada. */
.hoja-cabeza h2 {
  flex: 1; margin: 0;
  font-family: var(--display); font-weight: 800; font-size: 24px;
  text-transform: uppercase; letter-spacing: .01em;
  color: var(--sobre-alto);
}
.cerrar {
  width: 38px; height: 38px; border-radius: 8px;
  display: grid; place-items: center;
  border: 1px solid var(--linea); background: var(--superficie);
  color: var(--texto); cursor: pointer;
}

.hoja-cuerpo { overflow-y: auto; padding: 4px 16px 16px; }
.hoja-pie { border-top: 1px solid var(--panel-borde); padding: 14px 16px; background: var(--panel); }

.renglon {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 0; border-bottom: 1px solid var(--linea);
}
/* La marca de verificación: cada renglón dice "esto lo llevás". */
.renglon-tilde { color: var(--rubro); margin-top: 1px; --ico: 18px; --ico-trazo: 2.2; }
.renglon-texto { flex: 1; min-width: 0; }
.renglon-texto b { font-weight: 600; }
.renglon-detalle { display: block; font-size: 12.5px; color: var(--texto-suave); margin-top: 2px; }
.renglon-sub { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.quitar {
  border: 0; background: none; padding: 4px;
  color: var(--texto-suave); cursor: pointer; font-size: 13px;
  text-decoration: underline;
}

/* ── EL TOTAL Y EL ANILLO ───────────────────────────────────────────────── */
/* El total es el elemento de más peso de la hoja: es lo que el comercio vino a
   confirmar, y la desconfianza que este sistema vino a eliminar. */

.hoja-cifra {
  display: flex; align-items: center; gap: 16px;
  padding: 16px 0 12px;
}
.hoja-total { flex: 1; min-width: 0; }
.hoja-rotulo {
  display: block;
  font-size: 10.5px; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--texto-suave);
}
.hoja-total b {
  display: block; margin-top: 2px;
  font-family: var(--display); font-weight: 800;
  font-size: 44px; line-height: .95; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  color: var(--blanco);
}

.hoja-cuenta {
  flex: none;
  padding: 4px 9px; border-radius: 6px;
  background: var(--fondo); border: 1px solid var(--linea);
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--texto-suave);
  white-space: nowrap;
}
.hoja-cuenta[hidden] { display: none; }

/* El anillo: dos círculos y una propiedad. Sin librería y sin imagen. */
.anillo-caja[hidden] { display: none; }
.anillo-caja {
  position: relative; flex: none;
  width: 74px; height: 74px;
}
.anillo { width: 100%; height: 100%; display: block; }
.anillo circle {
  fill: none;
  stroke-width: 9;
  transform: rotate(-90deg);          /* arranca ARRIBA y barre en sentido horario */
  transform-origin: 50% 50%;
}
.anillo-pista { stroke: var(--control-borde); }
.anillo-arco {
  stroke: var(--rubro);
  stroke-linecap: round;
  /* El arco SE DIBUJA de cero a su valor. Salida suave, ~0,9 s. */
  transition: stroke-dashoffset .9s cubic-bezier(.22, 1, .36, 1), stroke .3s ease;
}
/* Al llegar al mínimo, el amarillo de la marca: en esta página significa
   "acá ganás", y es lo que hace que el logro se lea como logro. */
.anillo-caja.alcanzado .anillo-arco { stroke: var(--amarillo); }

.anillo-valor {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--display); font-weight: 800; font-size: 19px;
  color: var(--sobre-alto);
  font-variant-numeric: tabular-nums;
}

.hoja-minimo[hidden] { display: none; }
.hoja-minimo {
  margin: 0 0 4px;
  font-size: 13px; font-weight: 600; color: var(--texto-suave);
}
.hoja-minimo.logrado { color: #6B4E00; }

/* El chico, sobre azul: la pista y el arco se aclaran para leerse en el fondo. */
.anillo-caja-chica { width: 38px; height: 38px; }
.anillo-caja-chica .anillo-pista { stroke: var(--linea-oscura); }
.anillo-caja-chica .anillo-arco { stroke: #B9CBDE; }
.anillo-caja-chica.alcanzado .anillo-arco { stroke: var(--amarillo); }

.campo { margin-top: 12px; }
.campo label { display: block; font-size: 12.5px; font-weight: 600; color: var(--texto-suave); margin-bottom: 5px; }
.campo input {
  width: 100%; padding: 11px 12px;
  border: 1px solid var(--linea); border-radius: 8px; background: var(--control);
}
.campo input.falta { border-color: var(--naranja); background: var(--aviso-bg); }

.aviso {
  margin-top: 12px; padding: 10px 12px;
  border-radius: 8px; font-size: 13px; font-weight: 600;
  background: var(--aviso-bg); color: var(--aviso-texto); border: 1px solid var(--aviso-borde);
}
.aviso.info { background: var(--fondo); color: var(--texto-suave); border-color: var(--linea); }

.copiar-caja { margin-top: 12px; }
.copiar-caja textarea {
  width: 100%; min-height: 130px; padding: 10px;
  border: 1px solid var(--linea); border-radius: 8px;
  font-family: ui-monospace, monospace; font-size: 12.5px;
  resize: vertical;
}

.vacio { padding: 34px 8px; text-align: center; color: var(--texto-suave); }

/* Una categoría sin productos cargados. ⛔ Nunca la pantalla en blanco: es el
   estado normal mientras los precios de Marcelo van entrando por tandas. */
.lista-vacia {
  margin: 0; padding: 44px 12px; text-align: center;
  color: #9A9AA8; font-size: 14px;   /* vive sobre el lienzo oscuro */
}

/* ── PIE ────────────────────────────────────────────────────────────────── */

/* El pie ya no puede apoyarse en un cambio de fondo —es el mismo azul que el
   lienzo—, así que se separa con una línea. */
/* 🔄 15-08 — EL PIE, SEGUNDA FORMA.
   🔴 LA PRIMERA FUE UNA BANDA DE ONDAS QUE CRECÍA CON EL SCROLL, y se cayó.
   Estaba construida y andaba —los colores de la marca, el crecimiento medido,
   el contraste verificado—, pero Luca la miró y dijo *"sacalo al brillo ese del
   footer, no me gustó cómo quedó… o algo así que quede mejor"*. Y mirando su
   captura se entiende por qué: sobre la barra fija del pedido, la banda queda
   espachurrada en una franja delgada y se lee como una MANCHA, ⛔ no como luz.
   Un efecto que necesita altura ⛔ no puede vivir pegado a un elemento fijo que
   le come el piso.
   ➡️ Ahora el color lo pone una COSTURA de 2 px, y ⛔ no puede mancharse: no
   tiene alto que perder. ⛔ No reflotar la banda por iniciativa propia. */
.pie {
  position: relative;
  background: var(--lienzo); color: var(--sobre-medio);
  padding: 44px 16px calc(var(--barra-alto) + 30px);
  font-size: 12.5px; text-align: center;
}

/* 🎨 LA COSTURA. Los cinco colores de rubro en 2 px, desvaneciéndose hacia los
   dos costados.
   🔑 El desvanecido ⛔ no es decoración: es el MISMO recurso que usa la
   marquesina, así que la página cierra con el idioma con el que abrió. Y evita
   lo que haría ver esto barato — una raya de arcoíris cortada a ras contra los
   dos bordes, que es el degradado por defecto de cualquier generador.
   ⚠️ Reemplaza al `border-top` gris: dos líneas juntas serían una de más. */
.pie::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg,
    var(--cat-quimica), var(--cat-bazar), var(--cat-papeles),
    var(--cat-bolsas), var(--cat-envases));
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 18%, #000 82%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 18%, #000 82%, transparent 100%);
}

.pie-logo { height: 54px; width: auto; display: block; margin: 0 auto 14px; }

.pie-negocio {
  margin: 0;
  font-family: var(--display); font-weight: 800; font-size: 17px;
  letter-spacing: .02em; text-transform: uppercase;
  color: var(--blanco);
}

.pie-contacto {
  margin: 12px 0 0;
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center; gap: 8px 18px;
}
/* El separador aparece SÓLO si hay dos cosas que separar: con la zona de
   reparto vacía, un punto suelto colgando sería la señal de que falta un dato. */
.pie-zona[hidden] { display: none; }
.pie-zona::before { content: '·'; margin-right: 18px; opacity: .5; }

.pie-firma { margin: 22px 0 0; font-size: 12px; color: var(--sobre-bajo); }

.pie a { color: var(--amarillo); }
.pie-firma a { color: var(--sobre-medio); text-decoration-color: var(--amarillo); }

/* ── PANTALLA ANCHA ─────────────────────────────────────────────────────── */

@media (min-width: 860px) {
  body { font-size: 15.5px; }

  /* 🔴🔴 15-08 — SE FUERON LAS TRES COLUMNAS, Y ES EL CAMBIO MÁS GRANDE DE LA
     PÁGINA AUNQUE ACÁ SE VEA COMO UNA RESTA.

     Lo que había: `176px │ 1fr │ 320px` — menú a la izquierda, catálogo al
     medio, pedido a la derecha. **Medido: el catálogo se llevaba el 60 % del
     ancho** (868 de 1440) y el ojo hacía ping-pong entre las tres columnas.
     Luca lo dijo mirando la página: *"queda cargado del lado derecho y del
     izquierdo vacío"*.

     ➡️ Ahora es UNA sola columna de contenido con los dos controles
     persistentes en los BORDES de la pantalla: categorías arriba, catálogo al
     medio, pedido abajo.

     🔑 Y acá está lo que hace que esto sea barato: **esa jerarquía ya existía y
     estaba probada — es la del celular.** La fila horizontal de categorías y la
     barra fija del pedido están construidas desde el día uno. Lo único que
     había que hacer era **dejar de deshacerlas en escritorio**.
     Por eso este bloque BORRA reglas en vez de agregarlas. */

  /* ⚠️ `.contenido` ya no declara nada: vuelve a ser un bloque normal y cada
     hijo se arregla solo. La lista trae su propio tope de ancho y su centrado
     de la regla base.
     ✅ Y ⛔ NO revive el bug del margen automático: aquel rompía porque la lista
     era un ÍTEM DE GRILLA, donde `margin: 0 auto` anula el estirado. Sin grilla
     es un bloque con `max-width`, que es exactamente para lo que sirve. */

  .lista { padding-top: 18px; }

  .selector { display: none; }

  /* 🔄 Las categorías siguen siendo LA MISMA FILA HORIZONTAL del celular — antes
     acá se las volvía a apilar en columna. Sólo sube el cuerpo: con el ancho
     liberado hay lugar de sobra y a 15 px la fila se leía apretada. */
  .categoria { font-size: 17px; }

  /* 🔄 El pedido es la MISMA hoja que sube desde abajo, ⛔ no un panel al
     costado. Un modal centrado habría sido una TERCERA forma de ver el pedido
     en el mismo producto, y esta página se sostiene sobre una sola regla: se
     aprende una vez.
     🔑 Lo único que cambia en escritorio es el TOPE DE ANCHO. La hoja ocupa la
     ventana, pero los renglones son texto: a 1400 px un renglón como
     "3× Detergente concentrado · Verde" deja el precio a media pantalla del
     nombre y hay que barrer con la vista de punta a punta. */
  .hoja-caja {
    max-width: 720px; width: 100%;
    margin: 0 auto;
  }

  /* 🖱️ Con mouse el blanco de toque deja de ser el límite: el contador vuelve a
     40 px y la tarjeta recupera los 4 px de alto que el dedo necesitaba. */
  .cantidad button { width: 40px; height: 40px; }
  .cantidad output { min-width: 42px; height: 40px; }
}

/* ── MOVIMIENTO REDUCIDO ────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
