/* ==========================================================================
   Vidriera pública
   --------------------------------------------------------------------------
   Papel, tinta y una línea. Nada más.

   Portado del boceto de paginaDescartable/. Lo que el boceto no tenía —
   checkout, OTP, relacionados, overlays de pago — está al final del archivo,
   resuelto con el mismo vocabulario: sin cajas, una línea por debajo y
   mayúsculas chicas para las etiquetas.
   ========================================================================== */

:root {
  --paper: #f4f3f0;
  --paper-deep: #eceae5;
  --ink: #171614;
  --ink-soft: #605e58;
  --ink-faint: #a6a29a;
  --line: #d5d2ca;

  --glass: rgba(244, 243, 240, 0.72);
  --glass-blur: saturate(1.25) blur(16px);

  /* Acentos de las etiquetas de la grilla: celeste para la oferta, rojo apagado
     para el stock que se termina. */
  --flag-oferta-bg: #9fcbe8;
  --flag-oferta-ink: #10303f;
  --flag-ultimas-bg: #d99483;
  --flag-ultimas-ink: #3d1a12;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  --pad: clamp(18px, 3.2vw, 52px);
  --header-h: 58px;
  /* Lo que el encabezado ocupa de verdad en pantalla: su alto más la barra de
     estado del teléfono, que con viewport-fit=cover queda por debajo. Todo lo
     que se pega abajo del encabezado tiene que usar esta y no --header-h, o en
     iPhone se mete detrás. En pantallas sin muesca las dos valen lo mismo. */
  --header-total: calc(var(--header-h) + env(safe-area-inset-top, 0px));

  --ease: cubic-bezier(0.16, 0.84, 0.24, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* La página es una columna: el alto sobrante lo toma la portada, así el pie
   nunca empuja el contenido fuera de la ventana.
   Va con la clase puesta porque tokens.css y base.css, que se cargan antes,
   pintan el tema oscuro del panel sobre el mismo selector. */
body.vidriera {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  /* Transparente a propósito: el color lo pinta <html> para que la ilustración
     del fondo (body::before, más abajo) no quede tapada. */
  background: transparent;
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* Grano de papel */
body.vidriera::after {
  content: "";
  position: fixed;
  inset: 0;
  /* base.css usa este mismo pseudo-elemento como manchón de color: un círculo
     de 62vw. Sin resetear la caja, el grano queda recortado en círculo y se ve
     un arco enorme cruzando la página. */
  width: auto;
  height: auto;
  border-radius: 0;
  z-index: 100;
  pointer-events: none;
  opacity: 0.03;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

main {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

[hidden] { display: none !important; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* Una sola familia de etiquetas chicas para toda la página */
.half-index,
.half-label,
.half-brands,
.card-brand,
.sheet-brand,
.sizes-head,
.site-footer,
.filter,
.ph-text {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   Encabezado
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 30;
  /* Con viewport-fit=cover la página llega hasta el borde del teléfono, así que
     el encabezado se agranda por debajo de la barra de estado en vez de quedar
     tapado por ella. En pantallas sin muesca el env() vale 0 y no cambia nada. */
  height: var(--header-total);
  padding-top: env(safe-area-inset-top, 0px);
  display: flex;
  align-items: center;
  gap: 40px;
  padding-left: var(--pad);
  padding-right: var(--pad);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  /* Capa propia: en iOS el desenfoque de un elemento pegajoso se repinta con un
     cuadro de retraso mientras se scrollea, y se ve la franja parpadeando. */
  transform: translateZ(0);
}

/* Forro que sube por detrás del encabezado. En iPhone, cuando la barra de la
   URL se contrae o el scroll rebota contra el tope, arriba del encabezado
   asoma una franja de contenido sin desenfocar; esto la tapa con el mismo
   vidrio. En el tope de la página queda fuera de la ventana, invisible. */
.site-header::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 140px;
  pointer-events: none;
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}

@supports not (backdrop-filter: blur(1px)) {
  .site-header,
  .site-header::before { background: var(--paper); }
}

.brand {
  margin-right: auto;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
}

.header-nav {
  display: flex;
  gap: 26px;
}

.nav-link,
.bag-btn {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  font-size: 13px;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  transition: color 0.25s ease;
}

.nav-link {
  position: relative;
  padding-bottom: 2px;
}

/* Subrayado que crece desde la izquierda, pegado al texto y no a la caja de click */
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 10px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.nav-link:hover,
.bag-btn:hover,
.nav-link.is-active { color: var(--ink); }

.nav-link:hover::after,
.nav-link.is-active::after { transform: scaleX(1); }

.bag-btn {
  gap: 6px;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   Portada 50 / 50
   -------------------------------------------------------------------------- */

.split {
  flex: 1 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 420px;
}

.half {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--pad);
  overflow: hidden;
}

/* Toda la mitad entra a la categoría (ver portada.js), así que toda la mitad
   tiene que parecer clickeable. */
.half:not(.is-empty) { cursor: pointer; }

.half + .half::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
}

/* Cuerpo centrado de cada mitad. Va por encima de la cortina. */
.half-body {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: min(100%, 460px);
}

.half-title {
  margin: 0;
  font-size: clamp(34px, 4.6vw, 68px);
  font-weight: 500;
  line-height: 0.94;
  letter-spacing: -0.035em;
}

.half-text {
  margin: 18px 0 0;
  max-width: 30ch;
  color: var(--ink-soft);
}

.half-data {
  display: flex;
  justify-content: center;
  gap: clamp(32px, 4vw, 56px);
  margin: 26px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  width: min(100%, 340px);
}

.half-data dt {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.half-data dd {
  margin: 4px 0 0;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
}

.half-brands {
  margin: 14px 0 0;
  max-width: 44ch;
  line-height: 1.9;
  color: var(--ink-faint);
}

/* Botones de acción: una barra de ancho fijo con la línea abajo.
   Mismas dimensiones en la portada y en la ficha. */
.half-cta,
.add-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  width: min(100%, 260px);
  min-height: 44px;
  padding: 0 0 2px;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.half-cta { margin-top: 30px; }

.half-cta::before,
.half-cta::after,
.add-btn::before,
.add-btn::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 1px;
  width: 100%;
}

.half-cta::before,
.add-btn::before { background: var(--line); }

.half-cta::after,
.add-btn::after {
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}

.half-cta:hover::after,
.add-btn:hover::after { transform: scaleX(1); }

/* La flecha se corre unos píxeles al pasar */
.btn-arrow {
  font-size: 14px;
  letter-spacing: 0;
  color: var(--ink-soft);
  transition: transform 0.4s var(--ease), color 0.3s ease;
}

.half-cta:hover .btn-arrow,
.add-btn:hover .btn-arrow {
  transform: translateX(4px);
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   Catálogo
   -------------------------------------------------------------------------- */

.catalog { padding-bottom: clamp(64px, 12vh, 140px); }

.catalog-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(28px, 5vh, 56px) var(--pad) 20px;
}

.catalog-title {
  margin: 0;
  font-size: clamp(28px, 3.4vw, 48px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.035em;
}

.catalog-count {
  margin: 0 0 8px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.back-link {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  color: var(--ink-soft);
  font-size: 13px;
  letter-spacing: 0.06em;
  transition: color 0.25s ease;
}

.back-link:hover { color: var(--ink); }

.catalog-bar {
  position: sticky;
  top: var(--header-total);
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 32px;
  padding: 14px var(--pad);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(26px, 4vh, 44px);
}

@supports not (backdrop-filter: blur(1px)) {
  .catalog-bar { background: var(--paper); }
}

/* Filtros: texto, sin cajas */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
}

.filter {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding-bottom: 1px;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.filter::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 7px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.filter:hover { color: var(--ink-soft); }

.filter.is-active { color: var(--ink); }

.filter:hover::after,
.filter.is-active::after { transform: scaleX(1); }

.tools {
  display: flex;
  align-items: center;
  gap: 28px;
}

.search input {
  width: 200px;
  padding: 9px 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  transition: border-color 0.3s ease;
}

.search input::placeholder { color: var(--ink-faint); }

.search input:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

.grid-toggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.grid-toggle:hover { color: var(--ink); }

/* --------------------------------------------------------------------------
   Grilla
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(34px, 4.5vh, 56px) var(--pad);
  padding: 0 var(--pad);
}

.grid.is-wide { grid-template-columns: repeat(3, 1fr); }

.card {
  display: block;
  width: 100%;
  text-align: left;
  /* Perspectiva más corta que la del boceto: con la misma inclinación, cuanto
     más cerca está el punto de fuga más se nota el volumen. */
  perspective: 800px;

  /* Las escribe el JS con la posición del puntero */
  --rx: 0deg;
  --ry: 0deg;
}

/* Vidriera de sólo exhibición: la tarjeta se sigue viendo (y se sigue
   inclinando con el puntero) pero no se ofrece como algo en lo que entrar. */
.card.is-solo-vista { cursor: default; }

.card-photo {
  position: relative;
  aspect-ratio: 3 / 4;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper-deep);
  transform-style: preserve-3d;
  transform: rotateX(var(--rx)) rotateY(var(--ry));
  transition: transform 0.7s var(--ease), background-color 0.5s ease;
}

.card.is-tilting .card-photo { transition: background-color 0.5s ease; }

.card:hover .card-photo { background: #e5e2dc; }

/* Marco interior: el único indicio de que la tarjeta es un plano en el espacio */
.card-photo::before {
  content: "";
  position: absolute;
  inset: 18px;
  z-index: 1;
  border: 1px solid rgba(23, 22, 20, 0.13);
  transform: translateZ(34px);
  transition: inset 0.7s var(--ease), border-color 0.5s ease;
}

.card:hover .card-photo::before {
  inset: 12px;
  border-color: rgba(23, 22, 20, 0.22);
}

.ph-text {
  color: var(--ink-faint);
  transform: translateZ(48px);
}

.card-brand {
  margin: 20px 0 0;
  color: var(--ink-faint);
}

.card-name {
  margin: 7px 0 0;
  font-size: 16px;
  font-weight: 400;
}

.card-price {
  margin: 5px 0 0;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.card-price s {
  margin-left: 10px;
  color: var(--ink-faint);
}

.empty {
  padding: 0 var(--pad);
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   Ficha: repite el 50 / 50 de la portada
   -------------------------------------------------------------------------- */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: stretch;
  background: rgba(23, 22, 20, 0.18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  animation: fade 0.3s ease both;
  /* El gesto de scroll muere acá: no se lo pasa al catálogo de atrás cuando la
     ficha llega a su tope. */
  overscroll-behavior: contain;
}

.sheet {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 100%;
  max-width: 1400px;
  margin: auto;
  max-height: 100svh;
  overflow: auto;
  background: var(--paper);
  animation: sheet-in 0.55s var(--ease) both;
}

@keyframes fade {
  from { opacity: 0; }
}

@keyframes sheet-in {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
}

.sheet-close {
  position: absolute;
  top: 14px;
  right: var(--pad);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.sheet-close:hover { color: var(--ink); }

.sheet-photo {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 54svh;
  overflow: hidden;
  background: var(--paper-deep);
  perspective: 1200px;

  --mx: 50%;
  --my: 50%;
  --tx: 0px;
  --ty: 0px;
}

/* Luz suave que sigue al puntero: es el único brillo de la página */
.sheet-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    460px circle at var(--mx) var(--my),
    rgba(255, 255, 255, 0.4),
    rgba(255, 255, 255, 0) 68%
  );
}

.sheet-photo .ph-text {
  position: relative;
  z-index: 1;
  transform: translate3d(var(--tx), var(--ty), 30px);
  transition: transform 0.6s var(--ease);
}

.sheet-photo.is-tracking .ph-text { transition: none; }

.sheet-info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: clamp(40px, 6vh, 76px) var(--pad);
}

.sheet-brand {
  margin: 0;
  color: var(--ink-faint);
}

.sheet-title {
  margin: 14px 0 0;
  font-size: clamp(24px, 2.4vw, 36px);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.sheet-price {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin: 16px 0 0;
  font-size: 18px;
  font-variant-numeric: tabular-nums;
}

.sheet-price s,
.sale-tag {
  font-size: 13px;
  color: var(--ink-faint);
}

.sheet-text {
  margin: 22px 0 0;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  max-width: 46ch;
  color: var(--ink-soft);
}

.sheet-code {
  margin: 14px 0 0;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.sizes {
  width: min(100%, 560px);
  margin-top: 30px;
}

.sizes-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 14px;
  color: var(--ink-faint);
}

.sizes-note { letter-spacing: 0.1em; }

/* Talles: números en una fila, sin cajas */
.sizes-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 18px;
}

.size {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  min-height: 36px;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  transition: color 0.25s ease;
}

.size::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 7px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform 0.3s var(--ease);
}

.size:hover,
.size.is-active { color: var(--ink); }

.size:hover::after,
.size.is-active::after { transform: scaleX(1); }

.size:disabled {
  color: var(--ink-faint);
  cursor: default;
  text-decoration: line-through;
}

.size:disabled::after { display: none; }

.add-btn { margin-top: 34px; }

/* --------------------------------------------------------------------------
   Pie y aviso
   -------------------------------------------------------------------------- */

.site-footer {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 32px;
  padding: 22px var(--pad);
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
}

.site-footer p { margin: 0; }

.toast {
  position: fixed;
  left: var(--pad);
  bottom: 26px;
  z-index: 60;
  padding: 13px 0;
  border-top: 1px solid var(--ink);
  min-width: 260px;
  background: var(--paper);
  font-size: 13px;
  animation: toast-in 0.4s var(--ease) both;
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

/* --------------------------------------------------------------------------
   Movimiento: un solo gesto, la persiana
   -------------------------------------------------------------------------- */

.reveal {
  clip-path: inset(0 0 102% 0);
  transform: translateY(14px);
}

.reveal.is-in {
  clip-path: inset(0 0 -20% 0);
  transform: none;
  transition: clip-path 0.9s var(--ease) var(--reveal-delay, 0s),
              transform 0.9s var(--ease) var(--reveal-delay, 0s);
}

/* --------------------------------------------------------------------------
   Pantallas chicas
   -------------------------------------------------------------------------- */

@media (max-width: 1200px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
  .grid.is-wide { grid-template-columns: repeat(2, 1fr); }
}


@media (max-width: 820px) {
  :root { --header-h: 56px; }

  /* En el teléfono la ilustración entra recortada por los lados y las tarjetas
     le tapan casi todo el hueco: sube para que al menos se lea como textura. */
  body.vidriera:not(.en-portada) { --bg-ilustracion: 0.14; }

  .site-header { gap: 10px; }

  /* En 390px entran cuatro cosas en el encabezado (marca, dos categorías y
     Staff): hay que apretar tipografía y tracking o "Staff" queda cortado
     contra el borde. */
  .brand {
    font-size: 10px;
    letter-spacing: 0.08em;
    white-space: nowrap;
  }

  .header-nav { gap: 12px; }

  .nav-link { font-size: 11px; }

  .staff-link { font-size: 9px; }

  .split { grid-template-columns: 1fr; }

  /* Apiladas y a mitad de pantalla cada una: la portada sigue entrando entera
     sin scroll, que es su razón de ser. */
  .vidriera.en-portada .split { grid-template-rows: 1fr 1fr; }

  .half { min-height: 0; }

  .half-title { font-size: clamp(30px, 9vw, 46px); }

  .half + .half::before {
    left: var(--pad);
    right: var(--pad);
    top: 0;
    bottom: auto;
    width: auto;
    height: 1px;
  }

  .catalog-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .catalog-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
  }

  .tools { justify-content: space-between; }

  .search { flex: 1; }

  .search input { width: 100%; }

  /* En una columna la ficha mide más que la pantalla (foto + talles + el
     formulario de envío). El que scrollea es el overlay, no la ficha: así el
     alto de la ficha es libre y no hay nada que quede fuera de alcance.
     Antes la ficha crecía dentro de un overlay fijo de 100svh sin scroll y
     todo lo que pasaba del primer pantallazo era inaccesible. */
  .overlay {
    align-items: flex-start;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Sin el desenfoque: la ficha tapa la pantalla entera, así que no se ve, y
       mientras esté puesto el navegador toma al overlay como marco de
       referencia de los hijos fijos y el botón de cerrar se va con el scroll. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .sheet {
    grid-template-columns: 1fr;
    max-height: none;
    min-height: 100%;
    margin: 0;
    overflow: visible;
    /* Sólo el fundido, sin el desplazamiento de entrada: al terminar, una
       animación con transform deja el elemento con una matriz identidad puesta,
       y eso alcanza para que el navegador lo tome como marco de referencia del
       botón de cerrar, que entonces scrollea con la ficha en vez de quedarse
       fijo. El desplazamiento de 18px no se extraña en un teléfono. */
    animation: fade 0.35s ease both;
  }

  /* Queda flotando sobre la foto: al scrollear la ficha, la salida sigue ahí.
     Funciona porque ni el overlay ni la ficha tienen ya filtro ni transform
     puestos: cualquiera de los dos lo volvería el marco de referencia del
     botón y entonces se iría con el contenido en vez de quedarse fijo. */
  .sheet-close {
    position: fixed;
    top: 10px;
    right: var(--pad);
    z-index: 5;
    min-height: 44px;
    padding: 0 14px;
    background: var(--paper);
    border: 1px solid var(--line);
    color: var(--ink);
  }

  .grid,
  .grid.is-wide { grid-template-columns: repeat(2, 1fr); }

  /* Proporción de foto en vez de un alto arbitrario: con min-height la caja
     quedaba casi cuadrada y una foto vertical dejaba dos franjas de papel a los
     costados. Con 4/5 la foto llena el ancho de la pantalla. */
  .sheet-photo {
    min-height: 0;
    aspect-ratio: 4 / 5;
  }

  .toast {
    left: var(--pad);
    right: var(--pad);
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .reveal {
    clip-path: none;
    transform: none;
  }

  .overlay,
  .sheet,
  .toast { animation: none; }

  * { transition-duration: 0.01ms !important; }
}

/* ==========================================================================
   Puente con el sistema real
   --------------------------------------------------------------------------
   El boceto era una maqueta suelta. Acá se le enchufan los nombres de clase
   que ya usan los módulos de vidriera/ y las piezas que la maqueta no tenía.
   ========================================================================== */

/* base.css pinta dos manchones de color fijos con body::before/::after para el
   panel oscuro. Acá no van: el ::before se reusa para la ilustración del local
   y el ::after para el grano. */
body.vidriera::before { content: none; }

/* --------------------------------------------------------------------------
   Fondo: la ilustración del local
   --------------------------------------------------------------------------
   El dibujo a tinta de la vidriera, en negativo y muy bajo, detrás del
   catálogo y del acceso staff. En la portada NO va: ahí las dos mitades son
   todo el diseño y cualquier cosa por detrás las ensucia.

   Va en un pseudo-elemento fijo y no en background-attachment: fixed, que en
   iOS se mueve a los saltos. Para que el z-index negativo no lo deje detrás
   del fondo de la página, el color base lo pinta <html> y no <body>.
   -------------------------------------------------------------------------- */

html { background: var(--paper); }

body.vidriera:not(.en-portada)::before {
  content: "";
  position: fixed;
  inset: 0;
  /* base.css usa este mismo pseudo-elemento como manchón de color: un círculo
     de 62vw anclado arriba a la izquierda. Sin resetear la caja, inset: 0 no
     alcanza —width y height siguen mandando— y el dibujo queda encerrado en un
     cuadrado en un rincón. Es el mismo reset que hace el grano del ::after. */
  width: auto;
  height: auto;
  border-radius: 0;
  background-color: transparent;
  z-index: -1;
  pointer-events: none;
  background: url("/background-tienda.jpg?v=20260803") center / cover no-repeat;
  /* El dibujo es tinta negra sobre papel claro: invertido queda trazo claro
     sobre el fondo oscuro, que es el mismo dibujo leído al revés. */
  filter: invert(1) grayscale(1);
  /* El encuadre es el mismo en todas las pantallas: el dibujo entero, centrado.
     Lo que cambia es cuánto se ve — en el catálogo va más bajo que en el acceso
     porque compite con el título de la categoría y con las tarjetas. */
  opacity: var(--bg-ilustracion, 0.09);
}

/* El contenido cuelga de #login-screen, así que es él —y no <body>— quien tiene
   que estirarse: si no, el pie queda flotando a media pantalla. */
.vidriera #login-screen {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}

/* Los módulos ocultan cosas con .hidden, no con el atributo [hidden]. */
.vidriera .hidden { display: none !important; }

/* Con la ficha abierta el catálogo de atrás no se mueve. El overflow tiene que
   ir también en <html>: el elemento que scrollea la página es él, así que
   ponerlo sólo en <body> dejaba el fondo corriéndose por debajo de la ficha
   mientras la ficha misma no se movía (se veía en el celular sobre todo). */
html:has(> body.body-no-scroll),
body.body-no-scroll {
  overflow: hidden;
  overscroll-behavior: none;
}

/* --------------------------------------------------------------- Arranque */

.vidriera .loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: var(--paper);
  color: var(--ink-faint);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.vidriera .loader,
.vidriera .spinner-loader {
  width: 26px;
  height: 26px;
  border: 1px solid var(--line);
  border-top-color: var(--ink);
  border-radius: 50%;
  animation: vidriera-spin 0.9s linear infinite;
}

@keyframes vidriera-spin {
  to { transform: rotate(360deg); }
}

/* ------------------------------------------------------- Encabezado y pie */

.staff-link {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.staff-link:hover { color: var(--ink); }

.site-footer {
  display: block;
  padding-bottom: 26px;
}

.footer-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px 32px;
}

.footer-title {
  color: var(--ink);
  margin-bottom: 8px !important;
}

.site-footer a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s ease, color 0.25s ease;
}

.site-footer a:hover {
  color: var(--ink);
  border-bottom-color: var(--line);
}

.footer-bottom {
  margin-top: 24px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------- Portada */

/* Una categoría sin nada cargado no se puede abrir. */
.half.is-empty { opacity: 0.55; }

.half.is-empty .half-cta { cursor: default; }
.half.is-empty .half-cta::after { display: none; }

/* ---------------------------------------------------------------- Filtros */

.filter-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  flex: 1;
}

.filter-row {
  display: flex;
  align-items: baseline;
  gap: 18px;
  min-width: 0;
}

.filter-label {
  flex: none;
  width: 74px;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Los chips que dibuja filtros.js toman el aspecto de .filter del boceto. */
.store-talle-filter-btn,
.store-filter-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding-bottom: 1px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color 0.25s ease;
}

.store-talle-filter-btn { font-variant-numeric: tabular-nums; }

.store-talle-filter-btn::after,
.store-filter-chip::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 5px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.store-talle-filter-btn:hover,
.store-filter-chip:hover { color: var(--ink-soft); }

.store-talle-filter-btn.active,
.store-filter-chip.active { color: var(--ink); }

.store-talle-filter-btn:hover::after,
.store-filter-chip:hover::after,
.store-talle-filter-btn.active::after,
.store-filter-chip.active::after { transform: scaleX(1); }

.tools { flex: none; }

/* ----------------------------------------------------------------- Grilla */

.card-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s ease;
}

.card-img.loaded { opacity: 1; }

.card-sizes {
  margin: 6px 0 0;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
}

.card-flags {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  /* Levantadas en el eje Z para que floten junto con el marco cuando la
     tarjeta se inclina, en vez de quedar pegadas al fondo. */
  transform: translateZ(40px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 10px;
}

/* Las dos únicas manchas de color de toda la vidriera: son las que tienen que
   frenar el ojo mientras se recorre la grilla, y por eso se salen del papel y
   la tinta. */
.card-flag {
  padding: 3px 8px;
  background: var(--flag-ultimas-bg);
  color: var(--flag-ultimas-ink);
  font-size: 9px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.card-flag-offer {
  background: var(--flag-oferta-bg);
  color: var(--flag-oferta-ink);
}

.card-price.is-offer s {
  margin: 0 8px 0 0;
  color: var(--ink-faint);
}

.load-more {
  padding: clamp(30px, 5vh, 52px) var(--pad) 0;
  text-align: center;
}

/* ------------------------------------------------------------------ Ficha */

/* El formulario de compra es largo: la ficha se lee de arriba hacia abajo y
   no centrada como en el boceto, que sólo tenía cuatro renglones. */
.sheet-info { justify-content: flex-start; }

.sheet-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transform: translate3d(var(--tx), var(--ty), 0);
  transition: opacity 0.6s ease, transform 0.6s var(--ease);
}

.sheet-photo img.loaded { opacity: 1; }

/* Con foto cargada sobra el cartel de "Sin foto". */
.sheet-photo img.loaded ~ .ph-text { display: none; }

@media (min-width: 821px) {
  /* La foto acompaña el scroll del formulario en vez de irse para arriba. */
  .sheet-photo {
    position: sticky;
    top: 0;
    align-self: start;
    height: 100svh;
  }
}

.sheet-countdown {
  margin-top: 10px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Talles de la ficha: mismo trazo que .size del boceto. */
.store-lightbox-talle-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 30px;
  min-height: 36px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  transition: color 0.25s ease;
}

/* El subrayado cuelga del talle y no del botón entero: con el aviso de "quedan
   pocas" al lado, una línea a todo el ancho se leía como si fuera parte del
   aviso. */
.store-lightbox-talle-btn > span:first-child {
  position: relative;
  padding-bottom: 2px;
}

.store-lightbox-talle-btn > span:first-child::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transition: transform 0.3s var(--ease);
}

.store-lightbox-talle-btn:hover,
.store-lightbox-talle-btn.active { color: var(--ink); }

.store-lightbox-talle-btn:hover > span:first-child::after,
.store-lightbox-talle-btn.active > span:first-child::after { transform: scaleX(1); }

.talle-low-stock-badge {
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.add-btn.disabled,
.add-btn:disabled {
  color: var(--ink-faint);
  cursor: default;
}

.add-btn.disabled::after,
.add-btn:disabled::after { display: none; }

/* ------------------------------------------------- Formulario de compra */

.sheet-form,
.sheet-otp {
  width: min(100%, 560px);
  margin-top: 30px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}

.form-group { margin-bottom: 16px; }

.sheet-form label,
.sheet-otp label {
  display: block;
  margin-bottom: 6px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.sheet-form input,
.sheet-otp input[type="text"],
.sheet-otp input[type="tel"] {
  width: 100%;
  padding: 9px 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
  transition: border-color 0.3s ease;
}

.sheet-form input::placeholder { color: var(--ink-faint); }

.sheet-form input:focus,
.sheet-otp input:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

.delivery-options {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
}

.delivery-options.is-stacked {
  flex-direction: column;
  gap: 10px;
}

/* Las opciones de radio también son <label>, así que necesitan ganarle a la
   regla de arriba: si no, salen en mayúsculas y con el punto encima del texto. */
.sheet-form .delivery-option,
.sheet-otp .delivery-option {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-size: 13px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  cursor: pointer;
}

.delivery-option input {
  width: auto;
  accent-color: var(--ink);
}

.sheet-form .delivery-option:hover { color: var(--ink); }

.form-hint {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--ink-soft);
}

.shipping-address-container {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

/* ---------------------------------------------------------------- OTP */

.otp-title {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
}

.otp-text {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--ink-soft);
}

.otp-warn { color: var(--ink); }

.otp-timer {
  margin-bottom: 18px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}

.otp-timer strong {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.otp-input {
  font-size: 22px !important;
  letter-spacing: 0.4em;
  font-variant-numeric: tabular-nums;
}

.otp-actions {
  display: flex;
  align-items: center;
  gap: 26px;
}

.otp-actions .add-btn { margin-top: 0; }

.btn-store-resend {
  flex: none;
  min-height: 44px;
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.btn-store-resend:hover { color: var(--ink); }

.add-btn.is-wa {
  text-decoration: none;
  color: inherit;
}

.otp-waiting {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  font-size: 12px;
  color: var(--ink-faint);
}

.otp-waiting .spinner-loader {
  width: 15px;
  height: 15px;
}

/* -------------------------------------------------------- Relacionados */

.sheet-related {
  width: min(100%, 560px);
  margin-top: 34px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

.related-title {
  margin: 0 0 16px;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.related-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}

.related-card {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.related-card-photo {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  background: var(--paper-deep);
  overflow: hidden;
}

.related-card-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.related-card-name {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--ink);
}

.related-card-price {
  margin: 3px 0 0;
  font-size: 12px;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------- Avisos, pago y diálogos */

/* Los avisos van al margen izquierdo, no centrados como en el panel. Hay que
   deshacer el centrado entero de components/dialogs.css: dejando puesto su
   translateX(-50%) el aviso se iba media pantalla para afuera y se leía
   cortado ("...tu Nombre"), tanto en el celular como en la computadora. */
.vidriera .toast-host {
  position: fixed;
  left: var(--pad);
  bottom: 26px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  width: min(480px, calc(100vw - var(--pad) * 2));
  transform: none;
}

/* El aviso se dibuja como el resto de la vidriera: papel, una línea arriba y
   nada más. Hay que apagar a mano la caja que trae components/dialogs.css
   (esquinas redondeadas, borde de color y sombra), que es del panel oscuro y
   acá quedaba como un cartel pegado encima del papel. */
.vidriera .toast-host .toast,
.vidriera .toast-host > div {
  min-width: 260px;
  padding: 13px 0;
  border: 0;
  border-top: 1px solid var(--ink);
  border-radius: 0;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--paper);
  color: var(--ink);
  font-size: 13px;
  animation: toast-in 0.4s var(--ease) both;
}

.vidriera .payment-status-modal,
.vidriera .store-payment-overlay,
.vidriera .app-dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--pad);
  background: rgba(23, 22, 20, 0.18);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.vidriera .payment-status-card,
.vidriera .store-payment-overlay-card,
.vidriera .app-dialog {
  width: min(100%, 420px);
  padding: clamp(28px, 4vh, 44px);
  background: var(--paper);
  border: 1px solid var(--line);
  color: var(--ink);
  text-align: left;
}

.vidriera .store-payment-overlay-card { text-align: center; }

.vidriera .payment-status-card h3,
.vidriera .store-payment-overlay-card h3,
.vidriera .app-dialog h3 {
  margin: 18px 0 10px;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.02em;
}

.vidriera .payment-status-card p,
.vidriera .store-payment-overlay-card p,
.vidriera .app-dialog p {
  margin: 0;
  color: var(--ink-soft);
}

.vidriera .store-payment-overlay-card .spinner-loader {
  width: 30px;
  height: 30px;
  margin: 0 auto;
}

.vidriera .app-dialog-accent { display: none; }

.vidriera .app-dialog-input {
  width: 100%;
  margin-top: 16px;
  padding: 9px 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
}

.vidriera .app-dialog-actions,
.vidriera .payment-status-card .btn-payment-status-close {
  margin-top: 26px;
}

.vidriera .app-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 26px;
}

.vidriera .btn-payment-status-close,
.vidriera .app-dialog-actions button {
  min-height: 40px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.vidriera .btn-payment-status-close:hover,
.vidriera .app-dialog-actions button:hover { color: var(--ink); }

.vidriera .app-dialog-actions .btn-primary { color: var(--ink); }

/* ------------------------------------------------------ Pantallas chicas */

@media (max-width: 820px) {
  .filter-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }

  .filter-label { width: auto; }

  .form-row { grid-template-columns: 1fr; gap: 0; }

  .footer-cols { grid-template-columns: 1fr; }

  .related-grid { grid-template-columns: repeat(2, 1fr); }

  .otp-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .vidriera .toast-host {
    left: var(--pad);
    right: var(--pad);
    width: auto;
  }
}

/* Precio de la ficha: lo escribe fichaPrecio.js con sus propias clases. */
.lightbox-price {
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.lightbox-price .price-old {
  margin-right: 10px;
  font-size: 13px;
  color: var(--ink-faint);
}

/* ==========================================================================
   Portada a pantalla completa
   --------------------------------------------------------------------------
   En la portada no se ve nada más que las dos mitades: ni encabezado ni pie.
   Al entrar a un catálogo vuelven los dos.
   ========================================================================== */

.vidriera.en-portada .site-header,
.vidriera.en-portada .site-footer { display: none; }

.vidriera.en-portada .split {
  min-height: 100svh;
  height: 100svh;
}

.vidriera.en-portada #login-screen { min-height: 100svh; }

/* Sin encabezado ni pie no hay nada que scrollear: la portada es una pantalla
   fija y el rebote vertical sólo distrae. */
.vidriera.en-portada { overflow: hidden; }

/* Salvo que no entre. Apiladas, las dos mitades tienen que compartir el alto de
   un teléfono, y en los más bajos el botón de entrar al catálogo quedaba
   recortado por el overflow de la mitad, sin manera de llegar a él porque la
   página tampoco scrolleaba. Con alto mínimo en vez de fijo, cuando entra se ve
   igual que antes y cuando no entra, se puede scrollear. */
@media (max-width: 820px) {
  .vidriera.en-portada { overflow: auto; }

  .vidriera.en-portada .split {
    height: auto;
    grid-template-rows: auto auto;
  }

  .vidriera.en-portada .half { min-height: 50svh; }
}

/* --------------------------------------------------------------- La cortina */

/* Se despliega de abajo hacia arriba al posar el mouse y tiñe la mitad entera.
   Es el mismo gesto de persiana que usan las apariciones al scrollear, y por
   eso comparte la curva de aceleración. */
.half-curtain {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.62s var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .half:not(.is-empty):hover .half-curtain { transform: scaleY(1); }

  /* Con la cortina abajo se invierte el papel: tinta de fondo, papel encima. */
  .half:not(.is-empty):hover .half-title,
  .half:not(.is-empty):hover .half-data dd,
  .half:not(.is-empty):hover .half-cta { color: var(--paper); }

  .half:not(.is-empty):hover .half-text { color: rgba(244, 243, 240, 0.78); }

  .half:not(.is-empty):hover .half-data dt,
  .half:not(.is-empty):hover .half-brands,
  .half:not(.is-empty):hover .btn-arrow { color: rgba(244, 243, 240, 0.55); }

  .half:not(.is-empty):hover .half-data { border-top-color: rgba(244, 243, 240, 0.22); }

  .half:not(.is-empty):hover .half-cta::before { background: rgba(244, 243, 240, 0.3); }
  .half:not(.is-empty):hover .half-cta::after { background: var(--paper); }

  .half:not(.is-empty):hover .half-cta .btn-arrow { color: var(--paper); }
}

/* El texto acompaña a la cortina, con un pelo de retraso para que se lea el
   barrido y no un cambio de color seco. */
.half-title,
.half-text,
.half-brands,
.half-cta,
.half-data,
.half-data dt,
.half-data dd,
.btn-arrow {
  transition: color 0.45s var(--ease) 0.08s, border-color 0.45s var(--ease) 0.08s;
}

/* La línea divisoria queda por encima de las cortinas. */
.half + .half::before { z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .half-curtain { transition: none; }
}

/* ==========================================================================
   Cajón de filtros
   --------------------------------------------------------------------------
   Reemplaza la barra de tres renglones que empujaba la grilla hacia abajo y,
   al ser translúcida y pegajosa, dejaba ver las tarjetas por debajo al
   scrollear. Ahora cerrado es un solo renglón opaco, y el panel se despliega
   por encima de la grilla al acercar el mouse.
   ========================================================================== */

.catalog-bar {
  position: sticky;
  /* Justo debajo del encabezado, que también es pegajoso: con top: 0 los dos
     compiten por el mismo lugar y el cajón desaparece detrás. */
  top: var(--header-total);
  z-index: 25;
  display: block;
  padding: 0;
  /* Opaco a propósito: el panel se superpone a la grilla y tiene que taparla. */
  background: var(--paper);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(26px, 4vh, 44px);
}

.dock-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 11px var(--pad);
}

.dock-trigger {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  min-height: 34px;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.dock-trigger-label {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
}

.dock-summary {
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  transition: color 0.25s ease;
}

.dock-trigger:hover .dock-summary,
.is-open .dock-summary { color: var(--ink-soft); }

/* Un triangulito que gira: el único indicio de que el renglón se abre. */
.dock-caret {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 4px solid var(--ink-faint);
  transition: transform 0.45s var(--ease);
}

.catalog-bar.is-open .dock-caret { transform: rotate(180deg); }

/* El panel se revela como una persiana vertical y encima se superpone a la
   grilla, en vez de empujarla: la posición de las tarjetas no se mueve. */
.dock-panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 1;
  padding: 0 var(--pad);
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  clip-path: inset(0 0 100% 0);
  opacity: 0;
  pointer-events: none;
  /* Cerrado se esconde de verdad: recortado con clip-path los chips seguían
     siendo tabulables con el teclado, aunque no se vieran. La visibilidad
     cambia recién al terminar el cierre para no cortar la persiana. */
  visibility: hidden;
  transition: clip-path 0.5s var(--ease), opacity 0.3s ease, padding 0.5s var(--ease),
    visibility 0s linear 0.5s;
}

.catalog-bar.is-open .dock-panel {
  padding: 20px var(--pad) 24px;
  clip-path: inset(0 0 0 0);
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: clip-path 0.5s var(--ease), opacity 0.3s ease, padding 0.5s var(--ease),
    visibility 0s linear 0s;
}

/* Las filas entran escalonadas detrás de la persiana. */
.dock-panel .filter-row {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}

.catalog-bar.is-open .dock-panel .filter-row {
  opacity: 1;
  transform: none;
}

.catalog-bar.is-open .dock-panel .filter-row:nth-child(1) { transition-delay: 0.08s; }
.catalog-bar.is-open .dock-panel .filter-row:nth-child(2) { transition-delay: 0.14s; }
.catalog-bar.is-open .dock-panel .filter-row:nth-child(3) { transition-delay: 0.2s; }

.dock-clear { margin-top: 16px; }

@media (prefers-reduced-motion: reduce) {
  .dock-panel,
  .dock-panel .filter-row { transition: none; }
}

@media (max-width: 820px) {
  .dock-row {
    flex-wrap: wrap;
    gap: 12px;
  }

  .dock-row .tools {
    width: 100%;
    justify-content: space-between;
    gap: 16px;
  }

  .dock-row .search { flex: 1; }
}

/* ==========================================================================
   Tema oscuro  — TEMPORAL
   --------------------------------------------------------------------------
   Sólo invierte la paleta: papel y tinta cambian de lugar y el resto de la
   hoja sigue funcionando sin tocar nada, porque todo el diseño se apoya en
   estas seis variables. Se borra entero cuando se elija una de las dos
   versiones (ver js/views/vidriera/tema.js).
   ========================================================================== */

:root[data-tema="oscuro"] {
  --paper: #131211;
  --paper-deep: #1c1a18;
  --ink: #f2f0ec;
  --ink-soft: #a29d95;
  --ink-faint: #6b665e;
  --line: #302d29;

  --glass: rgba(19, 18, 17, 0.72);

  --flag-oferta-bg: #7db4d6;
  --flag-oferta-ink: #07202c;
  --flag-ultimas-bg: #c8806e;
  --flag-ultimas-ink: #2c110b;
}

/* El grano es una textura negra: sobre fondo oscuro hay que invertirla para
   que se siga notando. */
:root[data-tema="oscuro"] body.vidriera::after {
  filter: invert(1);
  opacity: 0.04;
}

/* Con la paleta dada vuelta la cortina entra clara sobre fondo oscuro, que es
   el mismo contraste al revés. El destello de la ficha sí hay que bajarlo: en
   oscuro un blanco al 40% quema. */
:root[data-tema="oscuro"] .sheet-photo::after {
  background: radial-gradient(
    460px circle at var(--mx) var(--my),
    rgba(255, 255, 255, 0.07),
    rgba(255, 255, 255, 0) 68%
  );
}

:root[data-tema="oscuro"] .card:hover .card-photo { background: #24211e; }

:root[data-tema="oscuro"] .card-photo::before { border-color: rgba(242, 240, 236, 0.14); }

:root[data-tema="oscuro"] .card:hover .card-photo::before { border-color: rgba(242, 240, 236, 0.24); }

/* El texto invertido de la cortina: en oscuro la cortina es clara, así que lo
   de encima tiene que volver a ser tinta oscura. */
@media (hover: hover) and (pointer: fine) {
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-title,
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-data dd,
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-cta { color: #131211; }

  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-text { color: rgba(19, 18, 17, 0.78); }

  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-data dt,
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-brands,
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .btn-arrow,
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-cta .btn-arrow { color: rgba(19, 18, 17, 0.55); }

  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-data { border-top-color: rgba(19, 18, 17, 0.22); }

  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-cta::before { background: rgba(19, 18, 17, 0.3); }
  :root[data-tema="oscuro"] .half:not(.is-empty):hover .half-cta::after { background: #131211; }
}

/* --------------------------------------------------------------------------
   Cajón de filtros: contención del alto
   --------------------------------------------------------------------------
   Con muchas marcas o modelos el panel llegaba a ocupar dos tercios de la
   pantalla y no quedaba dónde mover el mouse para que se cerrara. Ahora tiene
   techo y, si aun así sobra, scrollea por dentro.
   -------------------------------------------------------------------------- */

.catalog-bar.is-open .dock-panel {
  max-height: 55svh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* "+30 más" / "Ver menos": misma familia que las etiquetas, pero subrayado fijo
   para que se lea como acción y no como un valor más de la lista. */
.chip-mas {
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding: 0 0 1px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  transition: color 0.25s ease, border-color 0.25s ease;
}

.chip-mas:hover {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* Aviso de la fila que todavía no se puede usar (modelo sin marca elegida). */
.filter-hint {
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

.filter-row.is-locked .filter-label { opacity: 0.55; }

/* ==========================================================================
   Barras de desplazamiento
   --------------------------------------------------------------------------
   base.css las pinta con el naranja y el azul del panel. Acá van en tinta
   sobre papel, y siguen al tema porque salen de las mismas variables. Los
   selectores van sin prefijo a propósito: esta hoja sólo se carga en la
   vidriera, así que no puede alcanzar al panel de admin.
   ========================================================================== */

:root {
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}

::-webkit-scrollbar-track { background: transparent; }

::-webkit-scrollbar-thumb {
  background: var(--line);
  border: 2px solid var(--paper);
  border-radius: 0;
}

::-webkit-scrollbar-thumb:hover { background: var(--ink-faint); }

::-webkit-scrollbar-corner { background: transparent; }

:root[data-tema="oscuro"] .card-photo::before { border-color: rgba(242, 240, 236, 0.16); }

:root[data-tema="oscuro"] .card:hover .card-photo::before { border-color: rgba(242, 240, 236, 0.3); }

/* ==========================================================================
   Renglones parejos y objetivos de toque
   --------------------------------------------------------------------------
   Dos arreglos de uso, no de estilo.
   ========================================================================== */

/* Los nombres de uno y de dos renglones desalineaban los talles y el precio de
   las tarjetas vecinas, y entre fila y fila quedaban huecos de distinto tamaño.
   Reservar los dos renglones siempre los deja a la misma altura. No se recorta
   nada: un nombre de tres renglones sigue entrando entero. */
.card-name,
.related-card-name {
  line-height: 1.3;
  min-height: 2.6em;
}

/* --------------------------------------------------------------------------
   Touch: nada por debajo de 44px
   --------------------------------------------------------------------------
   Los talles del cajón de filtros medían 16 x 30 px reales: con el dedo se le
   erraba casi siempre. El área de toque crece; el tamaño de letra y el
   subrayado quedan igual, así que el diseño no cambia.
   -------------------------------------------------------------------------- */

@media (max-width: 820px) {
  .store-talle-filter-btn,
  .store-filter-chip,
  .chip-mas,
  .filter {
    min-height: 44px;
  }

  .store-talle-filter-btn {
    justify-content: center;
    min-width: 44px;
  }

  /* El subrayado se dibuja desde abajo de la caja; con la caja más alta hay que
     recolocarlo bajo el texto, que ahora va centrado. */
  .store-talle-filter-btn::after,
  .store-filter-chip::after {
    bottom: auto;
    top: calc(50% + 0.72em);
  }

  .filters { gap: 10px 20px; }

  .size,
  .store-lightbox-talle-btn {
    min-height: 48px;
    min-width: 48px;
  }

  .brand,
  .grid-toggle,
  .dock-trigger,
  .staff-link,
  .nav-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .nav-link::after { bottom: 12px; }

  /* El redondel del radio mide 13px: lo que se toca es el renglón entero. */
  .sheet-form .delivery-option,
  .sheet-otp .delivery-option { min-height: 44px; }

  .search input,
  .sheet-form input,
  .sheet-otp input[type="text"],
  .sheet-otp input[type="tel"] { min-height: 44px; }

  /* Direccion, telefono e Instagram del pie tambien se tocan. */
  .footer-col a {
    display: inline-flex;
    align-items: center;
    min-height: 36px;
  }
}
