/* ---------- Carrito fijo a la derecha ----------
   Mismo patrón que .pos-cart en el punto de venta: columna sticky en escritorio para
   que el resumen se vaya reflejando sin perder de vista el catálogo aunque haya muchos
   productos; en móvil se vuelve barra inferior colapsada (solo el total) con un botón
   para desplegar el detalle + el formulario, en vez de tapar la pantalla completa. */
.tienda-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: var(--space-5);
  align-items: start;
}
.tienda-col { min-width: 0; }

/* Escritorio: el carrito NUNCA es más alto que la pantalla. La lista y el formulario
   scrollean por dentro (el botón de pago se queda pegado abajo) y el formulario queda
   contraído tras el botón "Checkout" hasta que se pide — así, por muchos productos que
   se agreguen, el total y el pago siempre están a la vista. */
.tienda-cart {
  --sitio-header-h: 72px;
  position: sticky;
  top: calc(var(--sitio-header-h) + var(--space-4));
  margin-bottom: 0;
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - var(--sitio-header-h) - var(--space-4) * 2);
}
.tienda-cart .eyebrow { margin-bottom: var(--space-1); }
.tienda-cart h2 { margin-bottom: var(--space-3); }

#tienda-carrito-lista {
  min-height: 0;
  max-height: 30vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Si la lista no cabe, la última fila se desvanece en vez de cortarse por la mitad.
   La clase la pone renderCarrito() solo cuando de verdad hay desborde. */
#tienda-carrito-lista.recortada {
  mask-image: linear-gradient(to bottom, #000 calc(100% - 20px), transparent);
}
/* Con el checkout abierto los productos se esconden DEL TODO: antes la lista se
   comprimía a 16vh y quedaba una fila cortada a media altura. En su lugar va una
   línea con cuántas piezas van, y el espacio es para los datos de entrega. */
.tienda-cart.resumen-abierto #tienda-carrito-lista { display: none; }
.tienda-carrito-total { flex: 0 0 auto; }

.tienda-carrito-resumen {
  display: none;
  margin: 0 0 var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.tienda-cart.resumen-abierto .tienda-carrito-resumen { display: block; }

.tienda-checkout-form { display: none; }
.tienda-cart.resumen-abierto .tienda-checkout-form { display: flex; }

.tienda-resumen-toggle {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  margin-top: var(--space-3);
  height: var(--control-h);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--color-gold-bright);
  background: var(--tint-gold-2);
  border: 1px solid var(--color-gold);
}
.tienda-resumen-toggle .tt-flecha { transition: transform var(--duration-fast) var(--ease-out); }
.tienda-resumen-toggle[aria-expanded="true"] .tt-flecha { transform: rotate(180deg); }

@media (max-width: 1024px) {
  .tienda-layout { grid-template-columns: 1fr; }

  .tienda-cart {
    position: sticky;
    bottom: 0;
    top: auto;
    margin: var(--space-5) calc(var(--space-5) * -1) calc(var(--space-5) * -1);
    padding: var(--space-4) var(--space-5) calc(var(--space-4) + env(safe-area-inset-bottom));
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    border-top: 1px solid var(--color-border-strong);
    background: rgba(12, 12, 12, .94);
    backdrop-filter: blur(14px);
    box-shadow: 0 -14px 40px rgba(0, 0, 0, .7), var(--edge-top);
    z-index: 10;
    max-height: 82vh;
  }

  /* La lista de productos se ve SIEMPRE (antes se escondía hasta abrir el checkout,
     que es lo que hacía que el botón dijera "View cart & checkout"). Lo que se esconde
     al abrir es el formulario... o al revés: al abrir el checkout se esconden los
     productos y aparece el formulario. */
  #tienda-carrito-lista { display: block; }
  .tienda-resumen-colapsable { display: none; }
  .tienda-cart.resumen-abierto form.tienda-resumen-colapsable { display: flex; }

  .tienda-resumen-toggle {
    height: auto;
    margin: var(--space-1) 0 var(--space-2);
    padding: var(--space-1) 0;
    font-size: var(--text-2xs);
    color: var(--color-text-muted);
    background: transparent;
    border: 0;
    box-shadow: none;
    cursor: pointer;
  }
  .tienda-resumen-toggle:hover { color: var(--color-gold); background: transparent; box-shadow: none; transform: none; }
}

.tienda-toolbar {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.tienda-toolbar button.activo {
  border-color: var(--color-gold);
  background: var(--tint-gold-2);
  color: var(--color-gold-bright);
}

.producto-card-agotado {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: rgba(5, 5, 5, .85);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  border-radius: var(--radius-sm);
}

.tienda-cantidad {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.tienda-cantidad input {
  /* flex: 0 0 56px, no width: 56px — como ítem de flex el input se encoge por default,
     y en una tarjeta angosta desaparecía dejando solo los botones − y +. */
  flex: 0 0 56px;
  width: 56px;
  text-align: center;
  padding: 0;
}
.tienda-cantidad button {
  width: var(--control-h);
  height: var(--control-h);
  padding: 0;
  flex: 0 0 auto;
}

/* Rejilla de 4 columnas: nombre (elástico), cantidad, precio y quitar.
   El precio no se parte nunca y el nombre se recorta con puntos suspensivos, así
   ninguna fila se desordena por un nombre largo. */
.tienda-carrito-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border-soft);
}
.tienda-carrito-item:last-child { border-bottom: none; }

.tci-nombre {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tci-cant {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tci-precio {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 520px) {
  .tienda-carrito-item { grid-template-columns: minmax(0, 1fr) auto auto; }
  .tienda-carrito-item .quitar { grid-column: 3; }
  .tci-cant { display: none; }
}
.tienda-carrito-total {
  display: flex;
  justify-content: space-between;
  font-weight: 600;
  padding-top: var(--space-3);
  margin-top: var(--space-2);
  border-top: 1px solid var(--color-border-soft);
}

/* El formulario de contacto/pago vive DENTRO de la misma tarjeta que el carrito
   (antes eran dos .card separadas, casi sin aire entre "revisa tu total" y
   "ahora tus datos" — se sentía como si el layout se hubiera roto). */
.tienda-checkout-form {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border-soft);
  /* Scrollea por dentro si no cabe; el margen negativo/relleno evita que el borde del
     scroll recorte el anillo de foco de los campos. */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-inline: -4px;
  padding-inline: 4px;
}
/* El botón de pago se queda pegado abajo del carrito mientras se scrollean los campos. */
.tienda-checkout-form .actions {
  position: sticky;
  bottom: 0;
  padding-top: var(--space-3);
  background: var(--color-surface);
}
.tienda-checkout-form .actions button { width: 100%; }

.tienda-resultado {
  text-align: center;
  max-width: 480px;
  margin-inline: auto;
}
.tienda-resultado .sitio-icono { width: 40px; height: 40px; color: var(--color-gold); margin-bottom: var(--space-3); }
.tienda-resultado .actions,
.tienda-resultado a { justify-content: center; }

/* ---------- Variantes: los estilos del selector viven en components.css (lo comparten
   la tienda, la reserva y el POS) ---------- */

/* ---------- Tarjetas de la tienda ---------- */
/* El contenedor exterior lleva [data-reveal] (su transform es de la animación de entrada);
   la elevación al pasar el cursor va en el <article class="pc"> hijo para no pisarse. */
/* La tarjeta ocupa todo el alto de su celda: así todas las de una fila terminan
   a la misma altura aunque a una le quepa una línea más de texto. */
.producto-card--tienda {
  display: flex;
  height: 100%;
  cursor: default;
  overflow: visible;
  border: 0;
  border-radius: var(--radius-lg);
  background: none;
}
/* Ancho propio: sin esto la tarjeta se encoge al contenido y un producto SIN foto
   quedaba como un cuadrito de 157px en medio de la rejilla (la foto era lo único
   que le daba ancho). El botón se estira porque la regla global de botones fija
   align-self: flex-start. */
.producto-card--tienda .pc { flex: 1 1 auto; width: 100%; }
.pc {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--color-border-soft);
  border-radius: var(--radius-lg);
  background: var(--color-surface-raised);
  transition:
    transform var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out);
}
.producto-card--tienda .pc-abrir {
  display: block;
  align-self: stretch;
  width: 100%;
  min-height: 0;
  height: auto;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: inherit;
  font: inherit;
  letter-spacing: normal;
  text-align: left;
  text-transform: none;
  transform: none;
}
button.pc-abrir { cursor: pointer; }
button.pc-abrir:focus-visible { outline: 2px solid var(--color-gold); outline-offset: -2px; }
.pc-foto {
  position: relative;
  display: block;
  overflow: hidden;
  /* Marco cuadrado, igual para todas las tarjetas. */
  aspect-ratio: 1;
  background: var(--color-surface-sunken);
}
.producto-card--tienda .pc-foto img,
.producto-card--tienda .pc-foto .producto-card-sin-foto {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
  transition: transform 700ms var(--ease-out);
}
/* Productos sin foto cargada: en vez del recuadro vacío con "No photo", el icono
   del set propio sobre un degradado tenue. Se ve intencional, no roto. */
.pc-sin-foto {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    radial-gradient(120% 90% at 50% 0%, var(--tint-gold-1), transparent 72%),
    var(--color-surface-sunken);
}
.pc-sin-foto .sitio-icono { width: 38px; height: 38px; color: var(--color-gold); opacity: .5; }
.pc-foto::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 45%;
  background: linear-gradient(to top, rgba(12, 12, 12, .85), transparent);
  pointer-events: none;
}
.pc-etiqueta {
  position: absolute;
  z-index: 2;
  top: var(--space-3);
  left: var(--space-3);
  padding: 3px var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: rgba(5, 5, 5, .7);
  backdrop-filter: blur(6px);
  color: var(--color-gold-bright);
  font-size: var(--text-2xs);
  letter-spacing: .1em;
  text-transform: uppercase;
}
/* La pastilla de agotado va DEBAJO de la de categoría, no al otro extremo: en
   tarjetas angostas las dos no caben en el mismo renglón y se encimaban
   (se leía "STUD SOLD OUT"). Apiladas funcionan a cualquier ancho. */
.pc-foto .producto-card-agotado {
  z-index: 2;
  top: calc(var(--space-3) + 26px);
  left: var(--space-3);
  right: auto;
}
/* Agotado: se apaga la foto y el texto baja de intensidad, así se entiende antes
   de leer la pastilla. La tarjeta sigue abriendo el modal para ver el detalle. */
.pc--agotado .pc-foto img { filter: grayscale(.7) brightness(.62); }
.pc--agotado .pc-nombre,
.pc--agotado .pc-precio { color: var(--color-text-muted); }
.pc-vista {
  position: absolute;
  z-index: 2;
  left: 50%;
  bottom: var(--space-3);
  padding: 6px var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  backdrop-filter: blur(6px);
  color: var(--color-gold);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, 10px);
  transition: opacity var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out);
}
/* Cuerpo de la tarjeta: nombre, precio y la línea de contexto. */
.pc-cuerpo {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  padding: var(--space-4);
}
/* El nombre reserva sus dos renglones aunque ocupe uno: así el precio queda a la
   misma altura en toda la fila y la rejilla se ve como retícula, no como escalera. */
.pc-nombre {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(2 * 1.3em);
  color: var(--color-text);
  font-size: var(--text-base);
  font-weight: 600;
  line-height: 1.3;
}
/* La clase nace en pos.css, que la tienda no carga: se define aquí también.
   (En la tienda ya no se usa — el precio público es solo en dólares — pero el modal
   y las pantallas que sí la comparten necesitan la definición.) */
.moneda-usd {
  display: block;
  font-size: var(--text-2xs);
  font-weight: 400;
  color: var(--color-text-faint);
  white-space: nowrap;
}

/* Una sola línea: el precio de la web va en dólares y no lleva segunda moneda.
   (Era flex en columna para apilar pesos + dólares; con el "From" delante, ese flex
   partía la línea en dos y unas tarjetas quedaban 24px más altas que el resto.) */
.pc-precio {
  display: block;
  color: var(--color-gold-bright);
  font-weight: 600;
  white-space: nowrap;
}
/* Siempre presente, aunque vaya vacía: reserva su renglón para que el alto de la
   tarjeta no dependa de si el producto tiene opciones o no. */
.pc-opciones {
  margin-top: auto;
  /* 1.5em clavado: una línea vacía mide lo mismo que una con texto (medido: 12px vs
     17px con min-height: 1.1em), así el alto no depende del contenido. */
  min-height: 1.5em;
  line-height: 1.5;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--color-text-muted);
  font-size: var(--text-2xs);
  letter-spacing: .04em;
}

/* La columna del catálogo es más angosta que una pantalla completa (el carrito vive
   al lado), así que la rejilla admite tarjetas más chicas: con el mínimo de 240px
   solo cabían dos columnas y sobraba ancho. */
.tienda-col .productos-grid {
  grid-template-columns: repeat(auto-fill, minmax(212px, 1fr));
}

/* Solo donde hay cursor: la elevación, el brillo dorado, el zoom de la foto y "Quick view".
   En pantallas táctiles no hay hover, así que "Quick view" queda siempre visible. */
@media (hover: hover) {
  .pc:hover,
  .pc:focus-within {
    transform: translateY(-6px);
    border-color: var(--color-gold);
    box-shadow: var(--shadow-md), var(--glow-gold-md);
  }
  .pc:hover .pc-foto img,
  .pc:focus-within .pc-foto img { transform: scale(1.07); }
  .pc:hover .pc-vista,
  .pc:focus-within .pc-vista { opacity: 1; transform: translate(-50%, 0); }
}
@media (hover: none) {
  .pc-vista { opacity: 1; transform: translate(-50%, 0); }
}

/* ---------- Modal de producto (quick view) ---------- */
body.vp-abierto { overflow: hidden; }
.vp {
  width: min(920px, calc(100vw - 2rem));
  max-height: min(86vh, 660px);
  max-height: min(86dvh, 660px);
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  background: #0c0c0c;
  color: var(--color-text);
  box-shadow: 0 30px 90px rgba(0, 0, 0, .8), var(--edge-top);
}
.vp::backdrop { background: rgba(0, 0, 0, .72); backdrop-filter: blur(6px); }
.vp-panel {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  max-height: min(86vh, 660px);
  max-height: min(86dvh, 660px);
}
.vp-cerrar {
  position: absolute;
  z-index: 3;
  top: var(--space-3);
  right: var(--space-3);
  width: 40px;
  height: 40px;
  min-height: 0;
  padding: 0;
  border-radius: 50%;
  font-size: var(--text-xl);
  line-height: 1;
}
.vp-galeria { position: relative; display: flex; flex-direction: column; min-width: 0; overflow-y: auto; background: var(--color-surface-sunken); }
.vp-tira {
  display: flex;
  aspect-ratio: 1;
  max-height: min(62vh, 560px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* Suavidad declarada aquí y no en cada scrollTo({behavior:'smooth'}): si el
     navegador no la soporta, degrada a salto instantáneo igual se mueve. Con la
     opción en JS, un navegador que no la anima dejaba el scroll en 0. */
  scroll-behavior: smooth;
}
.vp-tira::-webkit-scrollbar { display: none; }
/* El slide se estira al alto de la tira; si no, la foto queda más chica que el
   marco y aparece una franja negra debajo (height:100% no resuelve contra un
   contenedor sin alto propio). */
.vp-slide { flex: 0 0 100%; scroll-snap-align: center; display: flex; }
.vp-slide img { display: block; width: 100%; height: 100%; aspect-ratio: auto; object-fit: cover; }
/* Sin foto: el icono del set propio centrado en el marco, igual que en la tarjeta. */
.vp-slide .producto-card-sin-foto {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  height: 100%;
}

/* Flechas para pasar de foto, solo cuando hay más de una. */
.vp-flecha {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  padding: 0;
  transform: translateY(-50%);
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-bg) 82%, transparent);
  backdrop-filter: blur(6px);
  color: var(--color-gold);
  cursor: pointer;
  transition: background var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast);
}
.vp-flecha[hidden] { display: none; }
.vp-flecha svg { width: 20px; height: 20px; }
.vp-flecha--prev { left: var(--space-3); }
.vp-flecha--next { right: var(--space-3); }
.vp-flecha:hover,
.vp-flecha:focus-visible,
.vp-flecha:active {
  background: var(--color-gold);
  border-color: var(--color-gold);
  color: var(--color-bg);
  /* La regla global de `button:hover` mete `transform: translateY(-2px)` y la de
     `:active` otro tanto. Como `button:hover` (0,1,1) gana a `.vp-flecha` (0,1,0), la
     flecha perdía el centrado y daba un brinco al pasar el cursor: hay que volver a
     fijar el translateY(-50%) en los tres estados. */
  transform: translateY(-50%);
}
/* Marco de la foto: contiene la tira y ancla las flechas y el contador a la IMAGEN
   (no a la columna, que en escritorio puede ser más alta que la foto). */
.vp-marco { position: relative; }
/* Cuántas fotos hay y en cuál vas. Sustituye a la tira de miniaturas, que dejaba una
   franja fea debajo de la foto: ahora la navegación son las flechas (y el deslizar). */
.vp-contador {
  position: absolute;
  z-index: 2;
  right: var(--space-3);
  bottom: var(--space-3);
  padding: 3px var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  backdrop-filter: blur(6px);
  color: var(--color-gold);
  font-size: var(--text-2xs);
  font-weight: 600;
  letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.vp-contador[hidden] { display: none; }
.vp-info {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-6) var(--space-6) 0;
  overflow-y: auto;
}
/* Sin esto los bloques con scroll propio (las opciones) se encogen en vez de dejar que la
   información haga scroll. */
.vp-info > * { flex-shrink: 0; }
.vp-titulo { margin: 0; font-size: var(--text-2xl); }
.vp-precio { margin: 0; color: var(--color-gold-bright); font-size: var(--text-xl); font-weight: 700; }
/* Con muchas variantes los botones se acomodan en filas y esta zona hace scroll: el modal
   nunca crece más que la pantalla. */
.vp-opciones { max-height: 34vh; overflow-y: auto; padding-right: var(--space-1); }
.vp-pista { margin: 0; }
/* Texto libre que escribe el negocio: pre-line respeta sus saltos de línea. */
.vp-descripcion { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); white-space: pre-line; }
.vp-agotado { margin: 0; color: var(--color-text-muted); letter-spacing: .1em; text-transform: uppercase; }
/* La barra de compra se queda fija abajo mientras la información hace scroll por detrás. */
.vp-comprar {
  position: sticky;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: auto;
  padding: var(--space-3) 0 var(--space-6);
  background: #0c0c0c;
  /* Sombra hacia arriba: la barra queda pegada al fondo mientras las opciones pasan
     por debajo, y sin esto parecía el final del contenido. */
  box-shadow: 0 -16px 20px -14px rgba(0, 0, 0, .95);
}
.vp-cantidad { margin-top: 0; }
.vp-agregar { flex: 1 1 10rem; min-height: var(--control-h-lg); }

@media (prefers-reduced-motion: no-preference) {
  .vp[open] { animation: vp-entra var(--duration-slow) var(--ease-out); }
  .vp[open]::backdrop { animation: vp-fondo var(--duration-base) ease-out; }
}
@keyframes vp-entra { from { opacity: 0; transform: translateY(24px) scale(.97); } }
@keyframes vp-fondo { from { opacity: 0; } }

/* Celular: tarjeta FLOTANTE, no pantalla completa. Se deja aire alrededor para que la
 * página siga viéndose detrás: se siente parte del sitio y no una pantalla aparte.
 * Dentro, todo el contenido se desplaza junto (foto, opciones y descripción) con la
 * botonera de compra pegada abajo. */
@media (max-width: 720px) {
  .vp {
    /* Ancho automático + tope: así el margen automático la centra de verdad. Con
       `width: 100vw` el aire salía desigual (el vw incluye la barra de scroll y el
       margen se calcula sobre el ancho útil). */
    width: auto;
    max-width: min(460px, calc(100% - var(--space-5) * 2));
    max-height: 82vh;
    max-height: 82dvh;
    /* Centrada: el `dialog` ya trae `inset: 0`, así que el margen automático la centra
       en las dos direcciones. Nada de animación de "sube desde abajo": ya no es una
       hoja pegada al borde, entra como en escritorio. */
    margin: auto;
  }
  /* El panel es el que scrollea (nada de posición estática aquí: el `dialog` se centra
     con el `position: fixed` que le pone el navegador, y tocarlo lo saca de la capa
     modal). La X se queda pegada arriba con sticky y el margen negativo la saca del
     flujo, para que la foto arranque arriba y la X flote encima. */
  .vp-panel {
    display: flex;
    flex-direction: column;
    max-height: 82vh;
    max-height: 82dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .vp-cerrar {
    position: sticky;
    top: var(--space-3);
    align-self: flex-end;
    margin: 0 var(--space-3) -40px 0;
  }
  .vp-galeria { flex: 0 0 auto; overflow: visible; }
  /* Marco CUADRADO, igual que la tarjeta del catálogo. Estaba en 4/3 con tope de 34vh:
     en un teléfono vertical eso da una franja apaisada de ~390×287 y las fotos del
     estudio son verticales (1778×2371) — `cover` recortaba una tira del centro. */
  .vp-tira { aspect-ratio: 1; max-height: none; }
  .vp-info { flex: 0 0 auto; min-height: 0; overflow: visible; padding: var(--space-4) var(--space-4) 0; }
  .vp-comprar { padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom)); }
  .vp-titulo { font-size: var(--text-xl); }
  .vp-opciones { max-height: none; overflow: visible; }
}
/* Celular acostado o pantalla muy baja: la foto se limita y se muestra completa
   (contain) en vez de recortarse a una franja. */
@media (max-width: 720px) and (max-height: 620px) {
  .vp-tira { max-height: 44vh; max-height: 44dvh; }
  .vp-slide img { object-fit: contain; }
}
/* Acostado y ancho (un teléfono en horizontal mide ~844×390 y ya no entra en el
   layout de celular): el modal se queda en dos columnas, pero la foto necesita más
   alto del que da el tope de escritorio y mostrarse completa, no recortada. */
@media (orientation: landscape) and (max-height: 620px) {
  .vp,
  .vp-panel { max-height: 92vh; max-height: 92dvh; }
  .vp-tira { max-height: 72vh; max-height: 72dvh; }
  .vp-slide img { object-fit: contain; }
}