/* Vitrina de mamasoyartistx — SelenE.
 *
 * ## Por qué CSS propio y no un framework
 *
 * Un framework de utilidades obligaría a tener Node y un paso de compilación para cambiar un
 * color. La arquitectura lo prohíbe (ADR-0002): la app se despliega con `docker compose up`,
 * sin cadena de build de JS.
 *
 * ## La dirección de arte sale de la obra, no de un catálogo de tendencias
 *
 * SelenE pinta a mano sobre tela negra: guadalupes de línea fina, nopales, llamas, payasos,
 * gatos-monstruo. Flash de tatuaje y gráfica chicana. Los colores no son suaves —rosa
 * mexicano, turquesa, naranja fuego— y viven **encima del negro**.
 *
 * De ahí las cuatro decisiones:
 *
 * 1. **Dos soportes, no un tema y su negativo.** La obra vive en dos lugares reales: el papel
 *    donde se dibuja y la tela donde se pinta. El tema claro es el papel y el oscuro es la
 *    tela, y por eso cada uno se sostiene solo en vez de parecer el otro apagado. Detalle
 *    abajo, en la sección de temas.
 * 2. **La interfaz no compite: aporta el rosa y se calla.** Un solo acento saturado, y solo
 *    en lo accionable. Todo el resto del color lo ponen las fotos.
 * 3. **Titulares de cartel.** Negras condensadas en mayúscula con tracking apretado: es la
 *    tipografía del volante de banda, que es exactamente el mundo de donde viene esta obra.
 *    Texto en sans del sistema, que se lee. Cero fuentes web: cero solicitudes, cero
 *    parpadeo, cero terceros.
 * 4. **Cada pieza es única y el diseño lo dice.** No es una talla de un stock: es *esta*.
 *    Por eso «pieza única» va en la tarjeta y «vendida» es definitivo, no un «vuelve pronto».
 */

/* ## Los dos temas no son uno el negativo del otro
 *
 * Cada uno es un soporte real de esta obra, y por eso los dos se sostienen solos:
 *
 * - **Claro es el papel**: el dibujo nace en tinta negra sobre crema. Es el tema por
 *   defecto, el que ve quien llega por primera vez.
 * - **Oscuro es la tela**: la prenda pintada, que es como la obra termina.
 *
 * El acento **cambia de tono entre temas y no es un capricho**: el rosa #ff2d78 sobre crema
 * queda en 3.1:1, por debajo del mínimo AA para texto. En claro baja a #c2185b (5.2:1) y en
 * oscuro se usa #ff2d78 (5.5:1 sobre #0c0b0a). El mismo rosa en los dos habría dejado los
 * enlaces ilegibles justo en el tema por defecto.
 *
 * Los ratios están medidos, no estimados: se calcularon con la fórmula de luminancia
 * relativa de WCAG 2.1 antes de fijar los valores.
 */

:root {
  color-scheme: light;

  /* Papel cálido, no blanco puro: es el color del bloc donde se dibuja, y baja el brillo del
     fondo sin tocar el contraste del texto. */
  --tinta: #16130f;
  --tinta-media: #55504a;
  --tinta-tenue: #7c766e;
  --papel: #f5f0e6;
  --superficie: #fffdf8;
  --linea: #e0d9cc;
  --linea-fuerte: #cdc4b4;

  --acento: #c2185b;
  --acento-vivo: #9c144a;
  --acento-tenue: #fdeaf1;
  --contraste-acento: #fffdf8;

  --turquesa: #0e7c8a;
  --fuego: #d1400d;

  --error: #a3341f;
  --error-tenue: #fdf1ee;
  --exito: #0e7c8a;
  --exito-tenue: #e6f4f6;

  /* Tipografía: ambas familias vienen del sistema. */
  --fuente-titulo: "Archivo Black", "Arial Black", "Helvetica Neue", Impact, system-ui, sans-serif;
  --fuente-texto: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  --radio: 2px;
  --radio-grande: 4px;
  --ancho: 78rem;
  --sombra: 0 1px 2px rgba(22, 19, 15, 0.05), 0 12px 32px -14px rgba(22, 19, 15, 0.18);
  --transicion: 180ms cubic-bezier(0.2, 0, 0.2, 1);
}

/* El negro es cálido —#0c0b0a, no #000— porque el negro puro sobre pantalla OLED corta el
   borde de las fotos y la prenda parece recortada con tijera. */
:root[data-tema="oscuro"] {
  color-scheme: dark;

  --tinta: #f7f2e8;
  --tinta-media: #a8a099;
  --tinta-tenue: #726b64;
  --papel: #0c0b0a;
  --superficie: #161412;
  --linea: #2a2622;
  --linea-fuerte: #3f3a35;

  --acento: #ff2d78;
  --acento-vivo: #ff6ba1;
  --acento-tenue: #2a0f1c;
  --contraste-acento: #0c0b0a;

  --turquesa: #35c9d6;
  --fuego: #ff5a1f;

  --error: #ff7a5c;
  --error-tenue: #2a1310;
  --exito: #35c9d6;
  --exito-tenue: #0d2427;

  --sombra: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 32px -14px rgba(0, 0, 0, 0.8);
}

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

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

body {
  margin: 0;
  font-family: var(--fuente-texto);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--tinta);
  background: var(--papel);
  /* Mejora la forma de las letras en pantallas de baja densidad. */
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; }

h1, h2 {
  font-family: var(--fuente-titulo);
  font-weight: 900;
  /* Mayúscula y tracking negativo: el titular se comporta como un bloque gráfico, que es
     como funciona la letra en un volante. Con interlineado de párrafo se vería despegado. */
  text-transform: uppercase;
  line-height: 0.92;
  letter-spacing: -0.02em;
  margin: 0 0 0.5em;
}

/* Los titulares grandes pisan el borde óptico del contenedor si no se compensa la caja de
   la mayúscula: sin esto, un H1 en negra parece indentado respecto del texto de abajo. */
h1 { font-size: clamp(2.4rem, 1.2rem + 5vw, 5rem); margin-left: -0.04em; }
h2 { font-size: clamp(1.6rem, 1.1rem + 1.8vw, 2.4rem); margin-left: -0.03em; }

/* El nombre de la pieza no va en negra: compite con el titular y, sobre todo, con la foto.
   Sans, peso medio, y que la obra hable. */
h3 {
  font-family: var(--fuente-texto);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  margin: 0 0 0.25rem;
}

p { margin: 0 0 1rem; }

a { color: var(--acento); }

/* Nunca se elimina el foco visible: es la única pista de ubicación de quien navega con
   teclado. Se refuerza con un halo para que también se vea sobre fondos oscuros. */
:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
  border-radius: 2px;
}

/* El enlace de salto solo aparece al enfocarlo. */
.salto-contenido {
  position: absolute;
  left: -9999px;
}
.salto-contenido:focus {
  left: 1rem;
  top: 1rem;
  z-index: 20;
  padding: 0.6rem 1rem;
  background: var(--tinta);
  color: var(--papel);
  border-radius: var(--radio);
  text-decoration: none;
}

/* ─────────────────────────────────────────────────────── cabecera y pie */

/* Se queda arriba al desplazar y se translucida sobre el contenido: en un catálogo largo,
   volver a la navegación no debería costar un scroll hasta el principio. */
.cabecera {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: baseline;
  gap: 2rem;
  padding: 1.1rem clamp(1rem, 4vw, 2.5rem);
  border-bottom: 1px solid var(--linea);
  background: color-mix(in srgb, var(--papel) 88%, transparent);
  backdrop-filter: blur(10px);
}

/* Sin `backdrop-filter` la barra quedaría semitransparente y el texto de abajo se leería
   a través. Se vuelve opaca. */
@supports not (backdrop-filter: blur(1px)) {
  .cabecera { background: var(--papel); }
}

.marca {
  font-family: var(--fuente-titulo);
  font-size: 1.15rem;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--tinta);
  margin-right: auto;
}
/* El rosa entra solo en la mitad del nombre. Un logotipo entero en acento satura la barra y
   deja al resto de la interfaz sin dónde crecer; partido, la marca tiene gesto y el acento
   sigue disponible para lo accionable. */
.marca b { color: var(--acento); font-weight: inherit; }

.cabecera nav {
  display: flex;
  gap: 1.5rem;
  font-size: 0.9375rem;
}
.cabecera nav a {
  color: var(--tinta-media);
  text-decoration: none;
  padding-bottom: 2px;
  /* Subrayado que crece desde la izquierda: se dibuja con background, así no desplaza nada
     al aparecer —un `border-bottom` condicional sí lo haría—. */
  background-image: linear-gradient(var(--acento), var(--acento));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size var(--transicion), color var(--transicion);
}
.cabecera nav a:hover,
.cabecera nav a[aria-current] {
  color: var(--tinta);
  background-size: 100% 1px;
}

/* Interruptor de tema. Es un `button` de verdad y no un checkbox disfrazado: se enfoca con
   teclado, se anuncia como botón y `aria-pressed` dice en qué estado está. */
.tema {
  display: grid;
  place-items: center;
  /* La cabecera alinea por línea base para que marca y navegación se sienten sobre el mismo
     riel. Un botón cuadrado en esa alineación cuelga; se centra respecto de la barra. */
  align-self: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: transparent;
  color: var(--tinta-media);
  cursor: pointer;
  transition: color var(--transicion), border-color var(--transicion);
}
.tema:hover { color: var(--tinta); border-color: var(--tinta-tenue); }
.tema svg { width: 1.05rem; height: 1.05rem; display: block; }

/* Se muestra el icono del tema al que se va a cambiar, no el actual: el botón anuncia su
   efecto. Mostrar el estado presente obliga a deducir qué hace al tocarlo. */
.tema .a-oscuro { display: block; }
.tema .a-claro { display: none; }
:root[data-tema="oscuro"] .tema .a-oscuro { display: none; }
:root[data-tema="oscuro"] .tema .a-claro { display: block; }

/* Sin JS el botón no puede hacer nada, así que no se muestra: un control muerto es peor que
   ausente. `no-js` lo pone el propio script al arrancar, quitándolo. */
:root.sin-js .tema { display: none; }

main {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(2rem, 5vw, 4rem) clamp(1rem, 4vw, 2.5rem) 5rem;
}

.pie {
  border-top: 1px solid var(--linea);
  padding: 2.5rem clamp(1rem, 4vw, 2.5rem);
  color: var(--tinta-tenue);
  font-size: 0.875rem;
}
.pie p { margin: 0; }
.pie a { color: var(--tinta-media); }
.pie-nota { margin-top: 0.35rem !important; color: var(--tinta-tenue); }

/* ─────────────────────────────────────────────────────── portada */

.portada {
  /* Ancho de lectura, no de pantalla: una línea de 120 caracteres es incómoda de leer. */
  max-width: 34ch;
  margin-bottom: clamp(3rem, 8vw, 5rem);
}
.portada h1 { margin-bottom: 0.75rem; }
.portada p {
  font-size: 1.125rem;
  color: var(--tinta-media);
  max-width: 46ch;
}

/* Etiqueta pequeña sobre un titular: ubica la sección sin gastar una línea de titular. */
.antetitulo {
  display: block;
  font-family: var(--fuente-texto);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
  margin-bottom: 0.35rem;
}

.seccion { margin-bottom: clamp(3rem, 7vw, 4.5rem); }
.seccion:last-child { margin-bottom: 0; }

.encabezado-pagina { margin-bottom: 2rem; }
.encabezado-pagina h1 { margin-bottom: 0.35rem; }
.entrada { color: var(--tinta-media); max-width: 52ch; }

/* Fichas de categoría: pastillas con borde, sin relleno de color. Un fondo saturado por
   categoría convertiría la fila en un semáforo y competiría con las fotos. */
.fichas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  list-style: none;
  padding: 0;
  margin: 0;
}
.ficha {
  display: inline-block;
  padding: 0.45rem 1rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: 999px;
  font-size: 0.875rem;
  text-decoration: none;
  color: var(--tinta-media);
  transition: border-color var(--transicion), color var(--transicion), background var(--transicion);
}
.ficha:hover, .ficha[aria-current] {
  color: var(--acento);
  border-color: var(--acento);
  background: var(--acento-tenue);
}

.conteo {
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
  margin-bottom: 1rem;
}

.encabezado-seccion {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.75rem;
}
.encabezado-seccion h2 { margin: 0; }
.enlace-mas {
  font-size: 0.9375rem;
  color: var(--tinta-media);
  text-decoration: none;
  border-bottom: 1px solid var(--linea-fuerte);
}
.enlace-mas:hover { color: var(--acento); border-color: var(--acento); }

/* ─────────────────────────────────────────────────────── grilla y tarjetas */

.grilla {
  display: grid;
  /* `auto-fill` con un mínimo: la grilla decide cuántas columnas caben sin media queries,
     y `min(100%, …)` evita que en un móvil angosto se desborde. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15.5rem), 1fr));
  gap: clamp(1rem, 2.5vw, 2rem) clamp(0.75rem, 2vw, 1.5rem);
  list-style: none;
  padding: 0;
  margin: 0;
}

.tarjeta { position: relative; }

.tarjeta a {
  display: block;
  text-decoration: none;
  color: inherit;
}

.marco {
  position: relative;
  overflow: hidden;
  border-radius: var(--radio-grande);
  background: var(--acento-tenue);
  /* Retrato 4:5, no cuadrado: es la proporción con la que se fotografía ropa y objetos, y
     deja ver la pieza entera sin recortarla. */
  aspect-ratio: 4 / 5;
  margin-bottom: 0.85rem;
}
.marco img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 400ms cubic-bezier(0.2, 0, 0.2, 1);
}
.tarjeta a:hover .marco img { transform: scale(1.04); }

.sin-imagen {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  color: var(--tinta-tenue);
  font-family: var(--fuente-titulo);
  font-size: 1.75rem;
}

/* Sello «vendida» sobre la foto. Tinta sólida y no un color de estado: es un hecho del
   producto, no una alarma. Y acá «vendida» es definitivo —la pieza era una—, así que no
   se atenúa ni se acompaña de un «vuelve pronto» que sería mentira. */
.sello {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  padding: 0.25rem 0.65rem;
  border-radius: var(--radio);
  background: var(--tinta);
  color: var(--papel);
  font-family: var(--fuente-titulo);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Marca de pieza única. Es la información que reordena la compra: no se elige talla de un
   stock, se elige *esta*. Va sobre la foto y en el borde opuesto al sello, para que cuando
   una pieza esté vendida los dos datos se lean juntos sin pisarse. */
.unica {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  padding: 0.25rem 0.65rem;
  border-radius: var(--radio);
  /* Fondo sólido y no translúcido: encima de una foto pintada a mano, un chip con
     transparencia se vuelve ilegible justo en las piezas más cargadas de color. */
  background: var(--acento);
  /* El texto del chip NO es blanco fijo. Blanco sobre el rosa del tema oscuro da 3.6:1, por
     debajo de AA para un texto de 11px; con `--papel` sube a 5.5:1. En el tema claro, donde
     el acento es más profundo, `--superficie` da 5.9:1. Un `#fff` en ambos habría dejado
     ilegible justo el sello que más se repite en la página. */
  color: var(--contraste-acento);
  font-family: var(--fuente-titulo);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
/* Vendida y única a la vez: la que manda es «vendida», así que la otra se apaga. */
.tarjeta:has(.sello) .unica { background: var(--linea-fuerte); color: var(--tinta-media); }

.aviso-vendida {
  display: inline-block;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: var(--superficie);
  color: var(--tinta-media);
  font-size: 0.875rem;
}

.tarjeta h2,
.tarjeta h3 {
  font-family: var(--fuente-texto);
  font-size: 0.9375rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.4;
  margin: 0 0 0.2rem;
}
.tarjeta .categoria {
  display: block;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
  margin-bottom: 0.4rem;
}
.precio {
  margin: 0;
  font-size: 0.9375rem;
  color: var(--tinta-media);
  /* Cifras de ancho fijo: en una grilla, los precios quedan alineados entre tarjetas. */
  font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────────────────────────────── filtros */

.filtros {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  align-items: end;
  padding: 1rem 1.25rem;
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio-grande);
  margin-bottom: 2rem;
}
.campo { display: grid; gap: 0.3rem; }
/* La búsqueda se queda con el espacio sobrante; el select solo pide lo que necesita. */
.campo-crece { flex: 1 1 14rem; }
.campo > label,
.filtros label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
}

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

input[type="text"], input[type="search"], input[type="email"], input[type="tel"],
input[type="date"], input[type="number"], input[type="password"], select, textarea {
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: var(--superficie);
  color: var(--tinta);
  min-width: 0;
  transition: border-color var(--transicion), box-shadow var(--transicion);
}
input:hover, select:hover, textarea:hover { border-color: var(--tinta-tenue); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--acento);
  box-shadow: 0 0 0 3px var(--acento-tenue);
}
textarea { min-height: 7rem; resize: vertical; }

/* El indicador de carga solo se ve mientras htmx tiene una petición en vuelo. */
.indicador { display: none; color: var(--tinta-tenue); font-size: 0.875rem; }
.htmx-request .indicador, .htmx-request.indicador { display: inline; }

/* ─────────────────────────────────────────────────────── botones */

.boton, button[type="submit"] {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 1.15rem;
  border: 1px solid var(--tinta);
  border-radius: var(--radio);
  background: var(--tinta);
  color: var(--papel);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: opacity var(--transicion), transform var(--transicion);
}
.boton:hover, button[type="submit"]:hover { opacity: 0.85; }
.boton:active, button[type="submit"]:active { transform: translateY(1px); }

.boton-fantasma {
  background: transparent;
  color: var(--tinta);
  border-color: var(--linea-fuerte);
}
.boton-fantasma:hover { border-color: var(--tinta); opacity: 1; }

.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.7rem 1.4rem;
  background: var(--tinta);
  color: var(--papel);
  border-radius: var(--radio);
  text-decoration: none;
  font-size: 0.9375rem;
  transition: opacity var(--transicion);
}
.cta:hover { opacity: 0.85; }
/* La flecha se mueve, no el botón: menos ruido visual que un desplazamiento completo. */
.cta::after { content: "→"; transition: transform var(--transicion); }
.cta:hover::after { transform: translateX(3px); }

.paginacion {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: center;
  margin-top: 3rem;
  font-size: 0.9375rem;
  color: var(--tinta-media);
}
.paginacion button {
  padding: 0.5rem 1rem;
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--radio);
  background: var(--superficie);
  cursor: pointer;
}
.paginacion button:hover { border-color: var(--tinta); }

/* ─────────────────────────────────────────────────────── ficha de producto */

.producto {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
}
/* Dos columnas solo cuando hay ancho para que la galería respire. */
@media (min-width: 56rem) {
  .producto { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); align-items: start; }
  .producto .columna-datos { position: sticky; top: 6rem; }
}

.migas {
  font-size: 0.8125rem;
  color: var(--tinta-tenue);
  margin-bottom: 1rem;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.migas a { color: var(--tinta-media); text-decoration: none; }
.migas a:hover { color: var(--acento); }

/* Galería con desplazamiento por «imanes»: cada foto se detiene encajada, sin quedar a
   medio camino. Es lo que hace que un carrusel sin JavaScript se sienta terminado. */
.galeria {
  display: grid;
  gap: 0.75rem;
}
@media (max-width: 55.99rem) {
  .galeria {
    grid-auto-flow: column;
    grid-auto-columns: 82%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
    padding-bottom: 0.5rem;
  }
  .galeria > * { scroll-snap-align: start; }
}
.galeria img,
.galeria .sin-imagen {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radio-grande);
  background: var(--acento-tenue);
}

.codigo {
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
}
.descripcion { color: var(--tinta-media); }

/* Las tablas anchas se desplazan dentro de su contenedor: el cuerpo de la página nunca se
   desplaza en horizontal. */
.precios { margin-top: 2rem; }
.precios .envoltorio-tabla { overflow-x: auto; }
.precios table {
  border-collapse: collapse;
  min-width: 100%;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}
.precios caption {
  text-align: left;
  color: var(--tinta-tenue);
  font-size: 0.8125rem;
  padding-bottom: 0.6rem;
}
.precios th, .precios td {
  padding: 0.6rem 0.9rem;
  text-align: left;
  /* Solo líneas horizontales: la retícula completa agrega 30 líneas que no aportan a leer
     un número. */
  border-bottom: 1px solid var(--linea);
}
.precios thead th {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
  font-weight: 600;
}
.precios tbody th { font-weight: 500; }
.lista-precios { list-style: none; padding: 0; margin: 0; font-variant-numeric: tabular-nums; }
.lista-precios li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--linea);
}

/* ─────────────────────────────────────────────────────── avisos y formularios */

.aviso, .error-bloque, .exito {
  padding: 0.9rem 1.1rem;
  border-radius: var(--radio-grande);
  border: 1px solid;
  margin-bottom: 1.25rem;
  font-size: 0.9375rem;
}
.aviso, .error-bloque {
  background: var(--error-tenue);
  border-color: color-mix(in srgb, var(--error) 30%, transparent);
  color: var(--error);
}
.exito {
  background: var(--exito-tenue);
  border-color: color-mix(in srgb, var(--exito) 30%, transparent);
  color: var(--exito);
}
.exito h2 { margin-top: 0; color: var(--tinta); }

.formulario {
  display: grid;
  gap: 1.1rem;
  max-width: 34rem;
  padding: clamp(1.25rem, 3vw, 2rem);
  background: var(--superficie);
  border: 1px solid var(--linea);
  border-radius: var(--radio-grande);
  box-shadow: var(--sombra);
}
.formulario input, .formulario select, .formulario textarea { width: 100%; }
.error {
  display: block;
  color: var(--error);
  font-size: 0.875rem;
  margin-top: 0.25rem;
}
.acciones { display: flex; align-items: center; gap: 0.85rem; }
.sobre-producto {
  margin: 0;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--linea);
  color: var(--tinta-media);
  font-size: 0.9375rem;
}
.campo small { color: var(--tinta-tenue); font-size: 0.8125rem; }

.vacio {
  padding: 3.5rem 1rem;
  text-align: center;
  color: var(--tinta-tenue);
  border: 1px dashed var(--linea-fuerte);
  border-radius: var(--radio-grande);
}
.vacio p { margin-bottom: 1.25rem; }

/* Quien pidió menos movimiento en su sistema operativo lo pidió en serio: las animaciones
   pueden provocar mareo y malestar real, no son solo una preferencia estética. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
