/* ==========================================================================
   MAMASITA MEDALLO · Componentes de interfaz
   Compartidos por el sitio público, el panel de meseros y el de administración.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Campo de partículas: círculos con degradado que flotan detrás del contenido.
   El <canvas> lo pinta particles.js; estos blobs CSS son el respaldo estático
   (y lo que se ve con prefers-reduced-motion o si falla el script).
   -------------------------------------------------------------------------- */

.particles {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* multiply en claro mantiene los pasteles limpios; screen en oscuro
     hace que los círculos aporten luz en vez de ensuciar el fondo */
  /* Igual que las manchas: sin mezcla. El campo es position:fixed y con
     `multiply` parpadeaba al hacer scroll. Los círculos son pastel sobre
     papel, así que normal y multiply dan lo mismo a la vista. */
}

.particles__canvas { width: 100%; height: 100%; }

.particles__fallback {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(38vmax 38vmax at 12% 8%,  var(--rosa-300), transparent 62%),
    radial-gradient(30vmax 30vmax at 88% 14%, var(--rojo-soft), transparent 64%),
    radial-gradient(34vmax 34vmax at 74% 82%, var(--rosa-200), transparent 66%),
    radial-gradient(26vmax 26vmax at 20% 88%, var(--rojo), transparent 68%);
  opacity: 0.5;
  filter: blur(6px);
}

/* Todo el contenido vive por encima del campo de partículas */
.layer { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   Trama de puntos · manchas Ben-Day que sangran por el borde del papel
   --------------------------------------------------------------------------
   No es una textura de fondo ni una franja que cruce la pantalla: es tinta
   que se escapa por el borde de la hoja. Tres reglas la definen:

   1. SILUETA IRREGULAR. La máscara de cada mancha es la unión de tres
      elipses de distinto tamaño y centro. Al sumarse dan un contorno con
      lóbulos —una mancha, no un círculo— y ni un solo canto recto dentro de
      la composición. Lo único que la recorta es el borde físico de la
      página, que es justamente donde una revista sangra.

   2. EL DEGRADADO SE HACE CON EL TAMAÑO DEL PUNTO, NO CON LA OPACIDAD.
      Esto es lo que separa una trama de imprenta de una mancha borrosa. En
      cuatricromía un rojo no se aclaraba bajando tinta: la tinta era siempre
      la misma y lo que cambiaba era el diámetro del punto sobre una retícula
      fija. Si en vez de eso se baja la opacidad, cada punto queda medio
      transparente y el conjunto se lee como un desenfoque sucio.

      Por eso cada calibre tiene su MESETA: dentro de su tramo la máscara
      está al 100% y el punto se ve entero y nítido; fuera, desaparece rápido
      y toma el relevo el calibre siguiente, más chico.

          ●●●●●  ● ● ●  · · ·
          meseta meseta meseta     -> y se acaba
          gruesa  media   fina

   3. RETÍCULA FINA Y DENSA. Cada calibre son DOS capas desfasadas media
      celda (--dot-half), lo que convierte la cuadrícula en el enrejado
      diagonal de una trama real en vez de una cuadrícula de lunares. La
      celda es de 9px: a tamaños mayores los puntos dejan de leerse como
      trama y se ven como círculos sueltos.
   -------------------------------------------------------------------------- */

.dot-bloom {
  position: absolute;
  z-index: 0;
  pointer-events: none;
  /* SIN mix-blend-mode a propósito.
     Con `multiply` las manchas desaparecían al hacer scroll: hay elementos
     position:fixed en la página (el campo de partículas, la nav, la burbuja
     de WhatsApp) y eso hace que el navegador promueva capas de composición
     durante el scroll; ahí el grupo de mezcla se parte y el elemento deja de
     pintarse. Y no perdíamos nada: multiplicar el rojo del logo sobre el
     papel da (232,64,58) contra (232,65,60) en normal —diferencia de 0, 1 y
     2 por canal, invisible—. El único caso que sí necesitaba mezcla era el
     pie, y ahí el color va precalculado (ver --on-dark). */

  /* capa fina: la cola del degradado, la que llega más lejos */
  background-image:
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-fine)) 16%, transparent 21%),
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-fine)) 16%, transparent 21%);
  background-size: var(--dot-grid) var(--dot-grid);
  background-position: 0 0, var(--dot-half) var(--dot-half);

  -webkit-mask-image:
    radial-gradient(66% 60% at 0% 0%,   transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(34% 36% at 46% 24%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(26% 40% at 16% 56%, #000 0%, #000 52%, transparent 100%);
  mask-image:
    radial-gradient(66% 60% at 0% 0%,   transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(34% 36% at 46% 24%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(26% 40% at 16% 56%, #000 0%, #000 52%, transparent 100%);
}

.dot-bloom::before,
.dot-bloom::after {
  content: '';
  position: absolute;
  inset: 0;
  background-size: var(--dot-grid) var(--dot-grid);
  background-position: 0 0, var(--dot-half) var(--dot-half);
}

/* capa media: el tramo central, punto de diámetro intermedio */
.dot-bloom::before {
  background-image:
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-medium)) 22%, transparent 27%),
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-medium)) 22%, transparent 27%);
  -webkit-mask-image:
    radial-gradient(66% 60% at 0% 0%, transparent 22%, #000 28%, #000 50%, transparent 56%);
  mask-image:
    radial-gradient(66% 60% at 0% 0%, transparent 22%, #000 28%, #000 50%, transparent 56%);
}

/* capa gruesa: el núcleo, donde los puntos casi se tocan */
.dot-bloom::after {
  background-image:
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-coarse)) 29%, transparent 34%),
    radial-gradient(circle, rgba(var(--dot-rgb), var(--dot-a-coarse)) 29%, transparent 34%);
  -webkit-mask-image:
    radial-gradient(66% 60% at 0% 0%, #000 0%, #000 22%, transparent 28%);
  mask-image:
    radial-gradient(66% 60% at 0% 0%, #000 0%, #000 22%, transparent 28%);
}

/* --------------------------------------------------------------------------
   Variante de costado: el núcleo entra por el lateral, no por un vértice
   --------------------------------------------------------------------------
   En la de esquina el núcleo está en el vértice y solo hay página hacia
   dentro. En esta el núcleo está a media altura del borde, así que la mancha
   tiene que abrirse en curva hacia arriba Y hacia abajo.

   OJO con los radios: la máscara se dibuja en coordenadas de la caja, y lo
   que cae fuera de la caja no se pinta. Si una elipse todavía lleva tinta al
   llegar al borde, el borde la GUILLOTINA en recto. Por eso las tres caben
   enteras a lo alto (ninguna pasa de 0% ni de 100%); lo único que sale de la
   caja es hacia el costado, que ahí sí es el borde del papel.
   -------------------------------------------------------------------------- */

.dot-bloom--edge {
  -webkit-mask-image:
    radial-gradient(48% 46% at 0% 50%,  transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(28% 21% at 38% 27%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(26% 19% at 32% 74%, #000 0%, #000 52%, transparent 100%);
  mask-image:
    radial-gradient(48% 46% at 0% 50%,  transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(28% 21% at 38% 27%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(26% 19% at 32% 74%, #000 0%, #000 52%, transparent 100%);
}

.dot-bloom--edge::before {
  -webkit-mask-image:
    radial-gradient(48% 46% at 0% 50%, transparent 22%, #000 28%, #000 50%, transparent 56%);
  mask-image:
    radial-gradient(48% 46% at 0% 50%, transparent 22%, #000 28%, #000 50%, transparent 56%);
}

.dot-bloom--edge::after {
  -webkit-mask-image:
    radial-gradient(48% 46% at 0% 50%, #000 0%, #000 22%, transparent 28%);
  mask-image:
    radial-gradient(48% 46% at 0% 50%, #000 0%, #000 22%, transparent 28%);
}

/* --------------------------------------------------------------------------
   Siluetas · tres manchas distintas, no una sola espejada
   --------------------------------------------------------------------------
   Con una única silueta las nueve manchas se leen como la misma pieza pegada
   nueve veces, y como todas anclan el núcleo al borde, siempre carga el mismo
   costado. Hay tres:

     A (por defecto)  núcleo a media altura del borde, masa repartida
     B  (--forma-b)   núcleo alto en el borde, masa cayendo hacia abajo
     C  (--libre)     núcleo DENTRO de la caja: no toca ningún borde, así que
                      puede ir en mitad de la página y se apaga por los cuatro
                      lados sin que nada la recorte

   Regla que las tres respetan: ninguna elipse sobresale de la caja a lo alto.
   Lo que cae fuera no se pinta, y si una elipse llega al borde con tinta, el
   borde la guillotina en recto. A lo ancho sí sobresalen A y B, pero por el
   costado, que ahí es el filo del papel.
   -------------------------------------------------------------------------- */

/* ---- B: núcleo alto, cola hacia abajo --------------------------------- */

.dot-bloom--forma-b {
  -webkit-mask-image:
    radial-gradient(44% 38% at 0% 40%,  transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(30% 24% at 34% 58%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(22% 15% at 20% 80%, #000 0%, #000 52%, transparent 100%);
  mask-image:
    radial-gradient(44% 38% at 0% 40%,  transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(30% 24% at 34% 58%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(22% 15% at 20% 80%, #000 0%, #000 52%, transparent 100%);
}

.dot-bloom--forma-b::before {
  -webkit-mask-image: radial-gradient(44% 38% at 0% 40%, transparent 22%, #000 28%, #000 50%, transparent 56%);
  mask-image: radial-gradient(44% 38% at 0% 40%, transparent 22%, #000 28%, #000 50%, transparent 56%);
}

.dot-bloom--forma-b::after {
  -webkit-mask-image: radial-gradient(44% 38% at 0% 40%, #000 0%, #000 22%, transparent 28%);
  mask-image: radial-gradient(44% 38% at 0% 40%, #000 0%, #000 22%, transparent 28%);
}

/* ---- C: suelta, sin tocar ningún borde -------------------------------- */

.dot-bloom--libre {
  -webkit-mask-image:
    radial-gradient(32% 28% at 40% 50%, transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(24% 18% at 66% 34%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(20% 22% at 22% 68%, #000 0%, #000 52%, transparent 100%);
  mask-image:
    radial-gradient(32% 28% at 40% 50%, transparent 50%, #000 56%, #000 84%, transparent 100%),
    radial-gradient(24% 18% at 66% 34%, #000 0%, #000 52%, transparent 100%),
    radial-gradient(20% 22% at 22% 68%, #000 0%, #000 52%, transparent 100%);
}

.dot-bloom--libre::before {
  -webkit-mask-image: radial-gradient(32% 28% at 40% 50%, transparent 22%, #000 28%, #000 50%, transparent 56%);
  mask-image: radial-gradient(32% 28% at 40% 50%, transparent 22%, #000 28%, #000 50%, transparent 56%);
}

.dot-bloom--libre::after {
  -webkit-mask-image: radial-gradient(32% 28% at 40% 50%, #000 0%, #000 22%, transparent 28%);
  mask-image: radial-gradient(32% 28% at 40% 50%, #000 0%, #000 22%, transparent 28%);
}

/* --------------------------------------------------------------------------
   Orientación, calibre, intensidad
   --------------------------------------------------------------------------
   La retícula de puntos es simétrica, así que para llevar el núcleo a otro
   vértice basta espejar la caja: no hace falta reescribir las elipses y las
   cuatro manchas quedan garantizadamente iguales.
   -------------------------------------------------------------------------- */

.dot-bloom--tr { transform: scaleX(-1); }   /* núcleo arriba a la derecha */
.dot-bloom--bl { transform: scaleY(-1); }   /* abajo a la izquierda       */
.dot-bloom--br { transform: scale(-1); }    /* abajo a la derecha         */

.dot-bloom--fine   { --dot-grid: 8px;  --dot-half: 4px; }
.dot-bloom--coarse { --dot-grid: 15px; --dot-half: 7.5px; }

/* Versión suave: la que va donde pasa texto corrido por encima.
   El techo no es estético, es aritmético: un punto puede recibir hasta DOS
   pasadas de tinta (la cola de una elipse sobre el tramo medio de otra), así
   que 0.36 da 0.59 efectivo. Ese es el techo medido: a 0.38 el rótulo de una
   sede cae a 4.49:1 y se queda a una centésima de no pasar AA. Más tinta que
   esto exige texto casi negro (0.88 de tinta), que se come la jerarquía. */
/* Donde pasa texto corrido por encima la tinta tiene techo por contraste
   (0.36; ver arriba). Si además el punto es chico, el conjunto se lee como
   bruma roja y no como trama. Así que acá el punto va GRANDE: misma tinta,
   misma cobertura —depende del radio relativo, no del tamaño de celda— pero
   el punto se distingue. */
.dot-bloom--soft {
  --dot-a-coarse: 0.36;
  --dot-a-medium: 0.36;
  --dot-a-fine:   0.36;
  --dot-grid: 16px;
  --dot-half: 8px;
}

/* Sobre una superficie oscura, tinta roja normal da negro sobre negro. En vez
   de mezclar con `screen` —que traía el mismo bug de scroll— va el resultado
   YA CALCULADO: screen(coral, #17110F) = rgb(255,121,108). Exacto, porque el
   fondo del pie es un color plano conocido. */
.dot-bloom--on-dark {
  --dot-rgb: 255, 121, 108;
}

/* --------------------------------------------------------------------------
   Sangrado de la página
   --------------------------------------------------------------------------
   Contenedor de las manchas de nivel documento. No recorta: las manchas ya
   traen su propia caída y lo único que las corta es el borde de la hoja, que
   es el efecto buscado.
   -------------------------------------------------------------------------- */

.page-bloom {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Botones
   -------------------------------------------------------------------------- */

.btn {
  --btn-bg: var(--tinta);
  --btn-fg: var(--paper);
  --btn-bd: var(--tinta);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 44px;                    /* objetivo táctil cómodo en móvil */
  padding: var(--sp-2) var(--sp-5);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 180ms var(--ease), background-color 180ms var(--ease),
              color 180ms var(--ease), border-color 180ms var(--ease), opacity 180ms var(--ease);
}

.btn:hover:not(:disabled) { transform: translateY(-2px); }
.btn:active:not(:disabled) { transform: translateY(0) scale(0.985); }
.btn:disabled { opacity: 0.42; cursor: not-allowed; }

.btn--red   { --btn-bg: var(--rojo-btn-bg); --btn-bd: var(--rojo-btn-bg); --btn-fg: var(--rojo-btn-fg); }
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--tinta); --btn-bd: var(--linea); }
.btn--ghost:hover:not(:disabled) { --btn-bd: var(--tinta); }
.btn--pink  { --btn-bg: var(--rosa-200); --btn-bd: var(--rosa-300); --btn-fg: var(--tinta); }
.btn--paper { --btn-bg: var(--surface); --btn-bd: var(--surface); --btn-fg: var(--tinta); }
.btn--sm    { min-height: 36px; padding: var(--sp-1) var(--sp-3); font-size: var(--fs-xs); }
.btn--lg    { min-height: 54px; padding: var(--sp-3) var(--sp-6); font-size: var(--fs-base); }
.btn--block { width: 100%; }
.btn--icon  { padding: 0; width: 44px; min-height: 44px; border-radius: var(--radius-pill); }
.btn--icon.btn--sm { width: 34px; min-height: 34px; }

/* --------------------------------------------------------------------------
   Chips / etiquetas
   -------------------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 5px var(--sp-3);
  border: 1px solid var(--linea);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tinta-70);
  white-space: nowrap;
  transition: background-color 160ms var(--ease), color 160ms var(--ease),
              border-color 160ms var(--ease);
}

.chip[aria-pressed='true'],
.chip.is-active {
  background: var(--tinta);
  border-color: var(--tinta);
  color: var(--paper);
}

.chip--red   { background: var(--rojo-btn-bg); border-color: var(--rojo-btn-bg); color: var(--rojo-btn-fg); }
.chip--pink  { background: var(--rosa-100); border-color: var(--rosa-200); color: var(--rojo-ink); }
.chip--ok    { background: rgba(47, 143, 91, 0.12); border-color: rgba(47, 143, 91, 0.3); color: var(--ok); }
.chip--warn  { background: rgba(201, 138, 18, 0.12); border-color: rgba(201, 138, 18, 0.3); color: var(--warn); }

/* --------------------------------------------------------------------------
   Formularios
   -------------------------------------------------------------------------- */

.field { display: grid; gap: var(--sp-1); }

.field__label {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tinta-55);
}

.input,
.select,
.textarea {
  width: 100%;
  min-height: 46px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--field-bg);
  border: 1px solid var(--linea);
  border-radius: var(--radius);
  font-size: var(--fs-base);
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}

.textarea { min-height: 88px; resize: vertical; line-height: 1.5; }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--rojo);
  box-shadow: 0 0 0 3px rgba(232, 65, 60, 0.14);
}

.input::placeholder,
.textarea::placeholder { color: var(--tinta-40); }

.select {
  appearance: none;
  padding-right: var(--sp-6);
  /* la flecha se dibuja con currentColor para que siga al tema */
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-size: 6px 6px, 6px 6px;
  background-position: right calc(var(--sp-3) + 6px) center, right var(--sp-3) center;
  background-repeat: no-repeat;
}

.field__hint { font-size: var(--fs-xs); color: var(--tinta-55); }
.field__error { font-size: var(--fs-xs); color: var(--rojo-ink); font-weight: 600; }

/* --------------------------------------------------------------------------
   Tarjeta de producto
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--linea-fina);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 220ms var(--ease), transform 220ms var(--ease),
              box-shadow 220ms var(--ease);
}

.card:hover { border-color: var(--linea); transform: translateY(-3px); box-shadow: var(--shadow-soft); }

.card__media {
  position: relative;
  display: block;
  width: 100%;
  /* puede ser un <button>: hay que anular el relleno y el borde del navegador */
  padding: 0;
  border: 0;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--rosa-100);
}

.card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease), filter 600ms var(--ease);
}

.card:hover .card__media img { transform: scale(1.045); }

.card__badges {
  position: absolute;
  inset: auto auto var(--sp-2) var(--sp-2);
  display: flex;
  gap: var(--sp-1);
  flex-wrap: wrap;
}

.card__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-3);
  flex: 1;
}

.card__title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  line-height: 1.16;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  text-wrap: balance;
}

.card__desc {
  font-size: var(--fs-sm);
  color: var(--tinta-70);
  line-height: 1.56;
  /* recorte a 3 líneas, uniforme en toda la grilla */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  line-clamp: 3;
  overflow: hidden;
}

.card__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: var(--sp-2);
  border-top: 1px solid var(--linea-fina);
}

.card__price {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  color: var(--rojo-text);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* En tarjetas angostas el botón se queda con el icono y suelta la palabra */
.btn__label { display: inline; }

@media (max-width: 519px) {
  .card__foot .btn { padding-inline: var(--sp-2); }
  .card__foot .btn__label { display: none; }
}

/* Ficha en modo lista (licores, vinos, cervezas: sin fotografía) */
.listing {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--linea);
}

.listing__row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--linea-fina);
}

.listing__name {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.listing__desc {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  color: var(--tinta-55);
  margin-top: calc(var(--sp-1) * -1);
}

.listing__price {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--rojo-text);
  white-space: nowrap;
}

.listing__actions { grid-column: 1 / -1; display: flex; gap: var(--sp-2); }

/* Subtítulo de sección dentro de una categoría (DE MAÍZ, PICADAS, …) */
.subhead {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-5) 0 var(--sp-1);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--rojo-text);
}

.subhead::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--linea-rosa);
}

/* --------------------------------------------------------------------------
   Grillas
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
}

/* La misma composición, solo cambia el número de columnas.
   Dos columnas ya desde 400px: en el teléfono la carta se escanea igual de
   rápido que en escritorio, que es justo lo que buscamos. */
@media (min-width: 380px)  { .grid { --cols: 2; } }
@media (min-width: 860px)  { .grid { --cols: 3; } }
@media (min-width: 1240px) { .grid { --cols: 4; } }

.grid--2 { --cols: 1; }
@media (min-width: 720px) { .grid--2 { --cols: 2; } }

.grid--wide { --cols: 1; }
@media (min-width: 560px)  { .grid--wide { --cols: 2; } }
@media (min-width: 1000px) { .grid--wide { --cols: 3; } }

/* --------------------------------------------------------------------------
   Modal / hoja inferior
   -------------------------------------------------------------------------- */

.sheet {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: end center;
  padding: 0;
  background: var(--scrim);
  backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms var(--ease), visibility 260ms var(--ease);
}

.sheet[aria-hidden='false'] { opacity: 1; visibility: visible; }

.sheet__panel {
  width: 100%;
  max-width: 720px;
  max-height: min(88svh, 900px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--linea);
  border-bottom: 0;
  border-radius: 18px 18px 0 0;
  transform: translateY(14px);
  transition: transform 300ms var(--ease);
  overflow: hidden;
}

.sheet[aria-hidden='false'] .sheet__panel { transform: none; }

@media (min-width: 720px) {
  .sheet { place-items: center; padding: var(--sp-4); }
  .sheet__panel { border-bottom: 1px solid var(--linea); border-radius: var(--radius-md); }
}

.sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--linea-fina);
}

.sheet__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  text-transform: uppercase;
  line-height: 1;
}

.sheet__body { padding: var(--sp-4); overflow-y: auto; overscroll-behavior: contain; }
.sheet__foot {
  padding: var(--sp-4);
  border-top: 1px solid var(--linea-fina);
  display: flex;
  gap: var(--sp-2);
  /* respeta la barra inferior del navegador móvil */
  padding-bottom: max(var(--sp-4), env(safe-area-inset-bottom));
}

/* --------------------------------------------------------------------------
   Avisos flotantes
   -------------------------------------------------------------------------- */

.toasts {
  position: fixed;
  z-index: 300;
  left: 50%;
  bottom: calc(var(--sp-5) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  display: grid;
  gap: var(--sp-2);
  width: min(100% - 2 * var(--gutter), 420px);
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--bar-bg);
  color: var(--bar-fg);
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  box-shadow: var(--shadow-pop);
  animation: toast-in 280ms var(--ease);
  pointer-events: auto;
}

.toast--ok    { background: var(--ok); }
.toast--error { background: var(--rojo-ink); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(12px) scale(0.97); }
}

/* --------------------------------------------------------------------------
   Tablas de datos (paneles)
   -------------------------------------------------------------------------- */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  min-width: 520px;
}

.table th,
.table td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  border-bottom: 1px solid var(--linea-fina);
  white-space: nowrap;
}

.table th {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tinta-55);
  border-bottom-color: var(--linea);
}

.table td.num,
.table th.num { text-align: right; font-variant-numeric: tabular-nums; }

.table tbody tr:hover { background: var(--paper-pink); }

/* --------------------------------------------------------------------------
   Estados
   -------------------------------------------------------------------------- */

.empty {
  display: grid;
  gap: var(--sp-2);
  place-items: center;
  text-align: center;
  padding: var(--sp-7) var(--sp-4);
  color: var(--tinta-55);
  border: 1px dashed var(--linea);
  border-radius: var(--radius-md);
}

.spinner {
  width: 18px; height: 18px;
  border: 2px solid var(--rosa-200);
  border-top-color: var(--rojo);
  border-radius: 50%;
  animation: spin 720ms linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.skeleton {
  background: linear-gradient(90deg, var(--rosa-100) 25%, var(--paper-pink) 37%, var(--rosa-100) 63%);
  background-size: 400% 100%;
  animation: shimmer 1400ms ease-in-out infinite;
  border-radius: var(--radius);
}

@keyframes shimmer { to { background-position: -135% 0; } }

/* --------------------------------------------------------------------------
   Aparición al hacer scroll
   -------------------------------------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
}

.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   Vista giratoria de un plato
   --------------------------------------------------------------------------
   No es 3D de verdad: es una vuelta fotografiada repartida en cuadros dentro
   de una sola imagen, y arrastrar cambia de cuadro. Ver assets/js/plato3d.js.
   -------------------------------------------------------------------------- */

.product-media { margin-bottom: var(--sp-4); }

.plato3d { position: relative; }

.plato3d__lienzo {
  width: 100%;
  aspect-ratio: 1;
  border-radius: var(--radius);
  background-repeat: no-repeat;
  /* mientras carga el sprite se ve el póster, que llena el cuadro */
  background-size: cover;
  background-position: center;
  cursor: grab;
  /* sin esto, arrastrar en el móvil hace scroll de la página en vez de girar */
  touch-action: none;
  user-select: none;
}

/* cuando el sprite ya está puesto manda su propio background-size (N00%) */
.plato3d[data-listo] .plato3d__lienzo { background-size: auto; }

.plato3d[data-girando] .plato3d__lienzo { cursor: grabbing; }

.plato3d__lienzo:focus-visible { outline: 2px solid var(--rojo); outline-offset: 3px; }

.plato3d__pista {
  position: absolute;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  margin: 0;
  padding: 5px 12px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  border: 1px solid var(--linea-rosa);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tinta-55);
  pointer-events: none;
  transition: opacity 200ms var(--ease);
}

/* la pista sobra en cuanto el dedo ya está encima */
.plato3d[data-girando] .plato3d__pista { opacity: 0; }

/* Y no debe prometer nada antes de que el sprite esté cargado: hasta entonces
   esto es una foto fija, y un cartel que dice «arrastrá» sobre algo que no se
   mueve es peor que no poner cartel. */
.plato3d:not([data-listo]) .plato3d__pista { opacity: 0; }

/* si el sprite no cargó, esto sigue siendo una foto: nada de "arrastrá" */
.plato3d[data-error] .plato3d__pista { display: none; }
.plato3d[data-error] .plato3d__lienzo { cursor: default; }
