/*
 * La portada. Dueño: flujo F (ronda 2). Recompuesta en la ronda 4.
 *
 * ───────────────────────────────────────────────────────────────────────────
 * De dónde salen estas medidas
 *
 * De `motor/panel.html`, su vista pública. PLAN §6-bis decide que ésa es la
 * página, así que los números de aquí —los 44 px de hueco de la rejilla, los
 * 104 px que suben los paneles, los 86×6 de la raya naranja— **no se han
 * elegido otra vez**: están copiados, y los comentarios que explican por qué
 * son de allí. Cuando algo aquí parezca un número raro, lo es por un motivo
 * que ya estaba escrito, y arriba se dice cuál.
 *
 * Lo único que sí se ha reescrito es el ORDEN en que se declaran.
 *
 * ───────────────────────────────────────────────────────────────────────────
 * Móvil primero, y eso sí es distinto del panel
 *
 * El panel se dibujó en un monitor de 27 pulgadas y baja con `max-width`: lo
 * que hay sin `@media` es el escritorio, y las consultas «arreglan» lo demás.
 * Aquí va al revés: lo que no lleva consulta es el móvil —la caja primero,
 * los paneles debajo— y la rejilla de tres columnas se AÑADE a partir de
 * 1240 px, que es exactamente donde el panel decía que dejaba de caber.
 *
 * El resultado en pantalla es el mismo en las dos puntas. El motivo de darle
 * la vuelta es de dónde viene el tráfico: YouTube y TikTok. Escribir el
 * escritorio y parchear el móvil es como se acaba mandando a un teléfono el
 * CSS de un monitor más los remiendos.
 *
 * Las cuatro reglas que no se negocian, porque las cuatro se notan en la mano
 * y ninguna en un navegador estrecho:
 *
 *   · Los campos van a 16 px. Por debajo, iOS hace zoom al tocarlos y la
 *     página se queda descuadrada para el resto de la sesión.
 *   · Nada que se pueda tocar mide menos de 44 px de alto.
 *   · 16 px de aire a los lados, y `overflow-x` cortado.
 *   · `env(safe-area-inset-*)` en la cabecera y en el pie, que en un iPhone
 *     con muesca no es un detalle.
 *
 * ───────────────────────────────────────────────────────────────────────────
 * Los colores son los de la marca
 *
 * Los mismos del libro, las portadas y las miniaturas de los vídeos. Alguien
 * que llega desde un vídeo tiene que reconocer dónde ha caído antes de leer
 * nada. El verde a pantalla completa es parte de eso, no un tema oscuro.
 */

:root {
  --verde: #1b4332;        /* el fondo de la marca */
  --verde-claro: #245a41;  /* los círculos del fondo */
  --oro: #ffd166;
  --naranja: #ff8c42;
  --ink: #1b3a2c;
  --soft: #4f6b5c;
  --rule: #d9e8de;
  --tint: #eef6f0;
  --bg: #f7faf8;
  --mal: #b3261e;
  --display: 'Unbounded', 'Arial Black', 'Segoe UI', sans-serif;
  --sans: 'Hanken Grotesk', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --gutter: 16px;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /*
   * La cabecera es `sticky`, así que cualquier `scrollIntoView()` —el del
   * botón cuando ya hay resultados, y el del muro— deja el título justo
   * debajo de ella y tapado. Esto es la altura de la banda; no hay ningún
   * otro sitio desde el que se pueda saber.
   */
  scroll-padding-top: 64px;
}

body {
  margin: 0;
  font: 16px/1.55 var(--sans);
  color: #fff;
  background: var(--verde);
  overflow-x: hidden;
}

h1, h2, h3, h4 { font-family: var(--display); letter-spacing: -.02em; margin: 0; }

/* Mientras el diccionario no ha llegado, los huecos de texto están vacíos.
   Ocultarlos evita el parpadeo de ver la maqueta sin palabras; se quita en
   cuanto `pintarTextos()` ha pasado. Si algo fallara, un `setTimeout` de
   seguridad en app.js lo quita igual: más vale la maqueta desnuda que nada. */
.sin-textos [data-t] { visibility: hidden; }

/* Se oye, no se ve. La caja del panel no llevaba etiqueta y la composición
   manda, pero un campo sin nombre es un campo sin nombre. */
.oculto-visual {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/*
 * Los círculos del fondo, como en las portadas y las miniaturas. Decorativos
 * y por debajo de todo: en un móvil no pueden robar ni un píxel de la caja.
 * En pantallas estrechas se encogen — a 780 px de diámetro el de arriba se
 * come el titular entero.
 */
body::before, body::after {
  content: "";
  position: fixed;
  border-radius: 50%;
  background: var(--verde-claro);
  opacity: .45;
  pointer-events: none;
  z-index: 0;
}
body::before { width: 340px; height: 340px; top: -150px; right: -120px; }
body::after { width: 260px; height: 260px; bottom: -130px; left: -110px; }
main { position: relative; z-index: 1; }

/* ═════════════════════ CABECERA ═════════════════════
   Fija arriba: al bajar a leer las ofertas no se pierde la marca de vista. */

header {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: calc(12px + env(safe-area-inset-top)) var(--gutter) 11px;
  background: rgba(27, 67, 50, .82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: #fff;
}
header img { width: 30px; height: 30px; border-radius: 8px; display: block; }
@media (min-width: 560px) { header img { width: 34px; height: 34px; } }
header .marca {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -.01em;
}

main { max-width: 2080px; margin: 0 auto; padding: 0 var(--gutter) 10px; }

/* ═════════════════════ EL HERO ═════════════════════ */

/* 1180 y no 1040: en su pantalla la segunda línea del titular se partía en
   tres. El resto del hero no se ensancha, cada pieza lleva su medida. */
.hero {
  text-align: center;
  padding: 18px 0 14px;
  max-width: 1180px;
  margin: 0 auto;
}
.hero .kicker {
  font-size: 13px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--oro);
  font-weight: 700;
  margin: 0 0 11px;
}
/* Sin <em> en el titular a propósito: el oro se guarda para la cifra. Con el
   titular también en oro, las dos cosas competían y no ganaba ninguna. */
.hero h1 {
  font-family: var(--display);
  font-size: clamp(28px, 6.6vw, 68px);
  line-height: 1.06;
  margin: 0 0 13px;
  color: #fff;
  font-weight: 800;
  letter-spacing: -.02em;
  /* El panel partía el titular a mano, con un `<br>` en medio. Aquí la frase
     es una sola clave —partirla en dos deja media oración que traducir— así
     que el corte lo reparte el navegador. Sin esto, en 1440 px la última
     palabra se queda sola en su línea. */
  text-wrap: balance;
}
.regla {
  width: 72px; height: 5px;
  background: var(--naranja);
  border-radius: 3px;
  margin: 0 auto 24px;
}

/*
 * Una sola cifra manda, y es el argumento entero: hemos mirado estas contra
 * tu perfil. Al lado de otra igual de grande se leía como «sólo el 16 % es
 * para ti», que es el mismo dato contado al revés.
 */
.cifras { text-align: center; }
.protagonista .n {
  font-family: var(--display);
  font-size: clamp(46px, 13vw, 94px);
  font-weight: 800;
  line-height: 1;
  color: var(--oro);
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.protagonista .t { font-size: 16px; color: #fff; margin-top: 8px; font-weight: 600; }
.protagonista .t b { font-weight: 700; }

/* La fecha real, no «hoy»: «hoy» sólo es cierto hasta que deja de serlo, y
   quien lo mira no sabe cuándo fue ese hoy. */
.sello {
  display: inline-block;
  margin: 11px 0 0;
  padding: 7px 16px;
  border-radius: 22px;
  background: rgba(255, 209, 102, .14);
  border: 1px solid rgba(255, 209, 102, .3);
  color: var(--oro);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .02em;
}
/* Más de un día sin refrescar se marca, porque las ofertas caducan rápido. */
.sello.viejo { background: rgba(255, 140, 66, .16); border-color: rgba(255, 140, 66, .4); color: #ffb887; }
.sello:empty { display: none; }

.contexto {
  font-size: 15.5px;
  color: rgba(255, 255, 255, .62);
  margin: 12px auto 0;
  max-width: 600px;
  line-height: 1.55;
}
.contexto b { color: rgba(255, 255, 255, .88); font-weight: 700; }

/* ═════════════════════ LA ZONA ═════════════════════
   Los dos paneles del contraste y la caja. En el móvil se apilan y la caja va
   primera: es la que importa, y nada debe haber por encima que haya que
   saltarse para llegar a ella. */

.zona { display: grid; gap: 18px; max-width: 640px; margin: 0 auto; }
.buscador { order: -1; }

/* Al haber resultados los paneles desaparecen y la caja se recentra sola: a
   quien ya lo ha usado no hay que convencerlo de nada. */
body.con-resultados .c-lado { display: none; }

/*
 * La única consulta `max-width` del fichero, y va aquí por un motivo concreto.
 *
 * Mientras los paneles están APILADOS quedan entre el botón y el bloque de
 * espera: se pulsa Buscar y no se mueve nada de lo que se ve, que es
 * exactamente lo que hace que la gente vuelva a pulsar. Así que ahí se van al
 * empezar la búsqueda y no al terminarla. En ancho no aplica: el panel los
 * quita cuando llegan los resultados y esa pantalla no cambia.
 *
 * `min-width` no puede decir «sólo mientras estén apilados», que es la
 * condición de verdad. Escribirlo al revés sería esconder la razón.
 */
@media (max-width: 1239px) {
  body.buscando .c-lado { display: none; }
}

/* Izquierda = el camino largo, en naranja de aviso. Derecha = el bueno, en
   oro. El color dice cuál es cuál antes de que nadie lea una palabra. */
.c-lado {
  background: rgba(255, 140, 66, .11);
  border: 1px solid rgba(255, 140, 66, .3);
  border-radius: 16px;
  padding: 19px 22px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.c-lado.hecho { background: rgba(255, 209, 102, .1); border-color: rgba(255, 209, 102, .3); }

/* Centrado y con una regla corta debajo: es el mismo recurso que la barra
   naranja del titular, en pequeño, y es lo que hace que se lea como título de
   la columna y no como la primera línea de la lista. */
.c-tit {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 13px;
  padding-bottom: 10px;
  position: relative;
  text-align: center;
  color: #ffb887;
  letter-spacing: -.01em;
}
.c-tit::after {
  content: "";
  position: absolute;
  left: 50%; bottom: 0;
  transform: translateX(-50%);
  width: 36px; height: 3px;
  border-radius: 2px;
  background: var(--naranja);
}
.c-lado.hecho .c-tit { color: var(--oro); }
.c-lado.hecho .c-tit::after { background: var(--oro); }

.c-lado ul { margin: 0; padding: 0; list-style: none; }
/* Centrados y con la viñeta en línea, no colgando a la izquierda: alineados a
   la izquierda ninguno llenaba el ancho del panel y quedaba un pico de aire
   muerto a la derecha de cada punto. */
.c-lado li {
  font-size: 16.5px;
  line-height: 1.45;
  color: rgba(255, 255, 255, .8);
  margin-bottom: 11px;
  text-align: center;
}
/* El último punto no separa de nada: el aire hasta la raya lo pone .c-tiempo,
   y así ese hueco es un solo número en vez de la suma de dos. */
.c-lado li:last-child { margin-bottom: 0; }
.c-lado li::before { content: "\2022"; margin-right: 9px; color: var(--naranja); opacity: .85; }
.c-lado.hecho li::before { content: "\2713"; margin-right: 9px; color: var(--oro); opacity: 1; font-size: 14px; }
.c-lado li b { color: #ffd0b0; font-weight: 700; }
.c-lado.hecho li b { color: var(--oro); }

/* 15 px de aire por encima de la raya y 15 por debajo: el mismo hueco a los
   dos lados. Con `margin-top:auto` se iba al fondo de la caja y dejaba un
   agujero detrás del último punto. */
.c-tiempo {
  margin: 15px 0 0;
  padding-top: 15px;
  border-top: 1px solid rgba(255, 255, 255, .14);
  font-size: 15.5px;
  color: rgba(255, 255, 255, .84);
  line-height: 1.55;
  text-align: center;
}
.c-tiempo b {
  color: #ffb887;
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -.01em;
}
.c-lado.hecho .c-tiempo b { color: var(--oro); }

/* ═════════════════════ LA CAJA ═════════════════════ */

.buscador { max-width: 880px; width: 100%; margin: 0 auto; }

/* El micrófono va dentro de la caja, no al lado: es otra forma de rellenar
   ese mismo campo, no otra acción. */
.caja { position: relative; }

.caja textarea {
  width: 100%;
  border: 0;
  border-radius: 16px;
  /* 72 px de hueco a la derecha para el micrófono. */
  padding: 18px 72px 18px 18px;
  /* 17 px y no 19: en un móvil la caja mide media pantalla y con 19 caben
     cuatro palabras por línea. Nunca por debajo de 16, que es donde iOS
     empieza a hacer zoom al enfocar. */
  font: 17px/1.5 var(--sans);
  resize: none;
  min-height: 124px;
  background: #fff;
  color: var(--ink);
  /* Crece con el texto (ver `crecer()`). Con la barra visible aparecía un
     pico en la esquina redondeada; sólo reaparece pasado el tope. */
  overflow: hidden;
  box-shadow: 0 18px 44px rgba(0, 0, 0, .3);
}
.caja textarea.desbordada { overflow-y: auto; }
.caja textarea:focus { outline: 3px solid var(--oro); outline-offset: 2px; }
.caja textarea::placeholder { color: #93a79a; }

.mic {
  position: absolute;
  right: 11px; bottom: 11px;
  width: 46px; height: 46px;      /* por encima de los 44 del pulgar */
  border: 0;
  border-radius: 50%;
  background: var(--tint);
  color: var(--verde);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
}
.mic svg { width: 22px; height: 22px; fill: currentColor; display: block; }
.mic:hover { background: #dcebe1; }
.mic.grabando { background: #e5484d; color: #fff; animation: pulso 1.4s ease-in-out infinite; }
@keyframes pulso {
  0%, 100% { box-shadow: 0 0 0 0 rgba(229, 72, 77, .5); }
  60% { box-shadow: 0 0 0 11px rgba(229, 72, 77, 0); }
}

.micaviso {
  min-height: 19px;
  margin: 10px 0 0;
  font-size: 14px;
  color: rgba(255, 255, 255, .55);
  text-align: center;
}
.micaviso.mal { color: #ffb887; }

/* ── El botón ── */

.controles { display: flex; justify-content: center; gap: 13px; margin-top: 22px; flex-wrap: wrap; }

.accion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  background: var(--naranja);
  color: #fff;
  border: 0;
  border-radius: 12px;
  /* En móvil ocupa el ancho del campo: a 49 px de relleno lateral no cabe, y
     un CTA recortado es peor que uno ancho. */
  width: 100%;
  min-height: 56px;
  padding: 16px 24px;
  font: 700 19px var(--display);
  letter-spacing: -.01em;
  cursor: pointer;
  box-shadow: 0 12px 30px rgba(255, 140, 66, .35);
  transition: transform .12s ease, filter .12s ease;
}
.accion:hover:not(:disabled) { filter: brightness(1.07); transform: translateY(-1px); }
.accion:disabled { opacity: .45; cursor: default; box-shadow: none; transform: none; }

/*
 * Un botón que espera sigue siendo naranja y sigue latiendo: está trabajando,
 * no está deshabilitado. El `disabled` se queda por función —evita el doble
 * envío— pero no se le nota en el color. Un botón gris parece roto y la gente
 * vuelve a pulsar.
 */
.accion.esperando, .accion.esperando:disabled {
  opacity: 1;
  cursor: progress;
  box-shadow: 0 12px 30px rgba(255, 140, 66, .35);
  animation: respira 1.6s ease-in-out infinite;
}
@keyframes respira { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.13); } }

/* Con resultados en pantalla el botón cambia de trabajo: deja de buscar y
   pasa a llevarte a ellos. Se pone dorado para que se note que ha cambiado. */
.accion.listo {
  background: var(--oro);
  color: var(--verde);
  box-shadow: 0 12px 30px rgba(255, 209, 102, .34);
}
.accion.listo .fle { display: inline-block; margin-left: 7px; animation: baja 1.6s ease-in-out infinite; }
@keyframes baja { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(4px); } }

.girando {
  display: none;
  width: 15px; height: 15px;
  border: 2.5px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: girar .8s linear infinite;
}
.accion.esperando .girando { display: block; }
@keyframes girar { to { transform: rotate(360deg); } }

.error { margin: 10px 2px 0; font-size: 15px; color: #ffb887; font-weight: 600; text-align: center; }
.error:empty { display: none; }

/* ═════════════════════ LA ESPERA ═════════════════════
   En producción la búsqueda tarda unos 7 segundos contra el catálogo de
   verdad. En blanco se hacen larguísimos y la gente vuelve a pulsar. Tres
   avisos a la vez, porque cada uno se ve desde un sitio distinto de la
   pantalla: el botón late, la barra avanza, y una línea dice qué pasa. */

.buscando { max-width: 560px; margin: 34px auto; text-align: center; }
.buscando .bt { font-family: var(--display); font-size: 20px; font-weight: 700; color: #fff; letter-spacing: -.01em; }
.buscando .bb {
  height: 9px;
  margin: 18px 0 12px;
  border-radius: 5px;
  overflow: hidden;
  background: rgba(255, 255, 255, .12);
}
/* Hasta el 93 % y nunca al 100: la barra no sabe cuánto queda, y una barra
   que se planta en el tope es una barra que miente. */
.buscando .bb i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 5px;
  background: linear-gradient(90deg, var(--naranja), var(--oro));
  animation: llena 14s cubic-bezier(.12, .72, .24, 1) forwards;
}
@keyframes llena { 0% { width: 3%; } 100% { width: 93%; } }
.buscando .bp {
  font-size: 15.5px;
  color: rgba(255, 255, 255, .62);
  min-height: 22px;
  transition: opacity .25s ease;
}
.buscando .bp.fuera { opacity: 0; }

/* Los tres puntos que saltan, en los botones y en el bloque de búsqueda. */
.pts { display: inline-block; margin-left: 2px; letter-spacing: 2px; }
.pts i { display: inline-block; font-style: normal; animation: bota 1.25s ease-in-out infinite; }
.pts i:nth-child(2) { animation-delay: .16s; }
.pts i:nth-child(3) { animation-delay: .32s; }
@keyframes bota {
  0%, 70%, 100% { transform: translateY(0); opacity: .45; }
  35% { transform: translateY(-5px); opacity: 1; }
}

/* ═════════════════════ LOS RESULTADOS ═════════════════════ */

#resultados { max-width: 1140px; margin: 0 auto; padding-top: 8px; }
#resultados > h2 { font-size: 21px; font-weight: 800; color: #fff; margin-bottom: 12px; text-align: center; }

.resumen {
  max-width: 1140px;
  width: 100%;
  margin: 18px auto 20px;
  text-align: center;
  font-size: 15.5px;
  color: rgba(255, 255, 255, .8);
  line-height: 1.6;
}
.resumen b { color: var(--oro); font-family: var(--display); font-weight: 700; font-variant-numeric: tabular-nums; }
.resumen .nota { display: block; margin-top: 6px; font-size: 14px; color: rgba(255, 255, 255, .55); }

.perfil {
  background: rgba(255, 255, 255, .08);
  color: rgba(255, 255, 255, .85);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 15px;
  margin-bottom: 12px;
  text-align: center;
}

/*
 * El aviso de §6.5. No es un pie de página ni una nota al margen: cuando no
 * sabemos dónde vive alguien, esto es lo más importante de la pantalla, y va
 * antes de la primera oferta. Lo que NO hay aquí es una cifra de «te admiten»:
 * con `pais` nulo esa cuenta es el almacén entero, así que no se enseña
 * pequeña ni con asterisco — no se enseña.
 */
.sinpais {
  border: 1px solid rgba(255, 140, 66, .55);
  background: rgba(255, 140, 66, .13);
  border-radius: 16px;
  padding: 18px 20px;
  margin-bottom: 18px;
}
.sinpais h3 { font-size: 19px; font-weight: 700; color: #ffb887; margin-bottom: 8px; }
.sinpais p { margin: 0 0 14px; font-size: 15.5px; color: rgba(255, 255, 255, .82); line-height: 1.55; }
.sinpais label { display: block; font-weight: 700; font-size: 14px; margin-bottom: 7px; color: rgba(255, 255, 255, .9); }

/* Campo + botón: apilados en el móvil, en línea a partir de 560 px. */
.campos { display: grid; gap: 10px; }
.campos input {
  width: 100%;
  font: 17px var(--sans);
  padding: 15px 16px;
  border: 0;
  border-radius: 11px;
  min-height: 48px;
  background: #fff;
  color: var(--ink);
}
.campos input:focus { outline: 3px solid var(--oro); outline-offset: 2px; }
.campos .accion { min-height: 48px; padding: 13px 22px; font-size: 17px; box-shadow: none; }

/* ── Las tarjetas de oferta ── */

/*
 * `minmax(0, 1fr)` y no `1fr`.
 *
 * Una celda de rejilla no baja de su ancho mínimo de contenido, y aquí ese
 * mínimo lo marca una palabra que no se puede partir: el título de una oferta
 * en alemán, o los `████` que manda `enmascarar()` para las tapadas, que son
 * hasta 28 caracteres sin un solo sitio por donde cortar. Con `1fr` eso
 * ensanchaba la tarjeta a 445 px dentro de un móvil de 390 y la página entera
 * se iba de lado. Medido, no supuesto.
 */
.ofertas { display: grid; grid-template-columns: minmax(0, 1fr); gap: 13px; }

.oferta {
  min-width: 0;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .12);
  border-left: 5px solid var(--oro);
  border-radius: 0 14px 14px 0;
  padding: 17px 19px;
  /* Misma razón: lo que no cabe se parte, no desborda. */
  overflow-wrap: anywhere;
}
.oferta.alta { border-left-color: var(--naranja); background: rgba(255, 255, 255, .11); }
.ocab { display: flex; align-items: flex-start; gap: 10px; justify-content: space-between; }
/* Un hijo de flex tampoco baja de su mínimo de contenido si no se le dice. */
.ocab h3 { min-width: 0; }
.oferta h3 { font-family: var(--display); font-size: 18px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25; }
.oferta h3 a { color: #fff; text-decoration: none; }
.oferta h3 a:hover { color: var(--oro); }
.sc {
  flex: none;
  background: var(--oro);
  color: var(--verde);
  font-family: var(--display);
  font-weight: 800;
  font-size: 15px;
  padding: 4px 13px;
  border-radius: 22px;
  font-variant-numeric: tabular-nums;
}
.om { color: rgba(255, 255, 255, .62); font-size: 15px; margin: 7px 0 0; }
.badge { background: rgba(255, 255, 255, .16); color: #fff; border-radius: 6px; padding: 1px 7px; font-size: 13px; }
.mot { color: rgba(255, 255, 255, .8); font-size: 15px; margin: 9px 0 0; }
.avi { background: rgba(255, 140, 66, .17); color: #ffdcc4; font-size: 14.5px; border-radius: 8px; padding: 7px 10px; margin: 9px 0 0; }

/* Las tapadas llegan del servidor ya como siluetas: no hay título real que
   sacar con el inspector, que es justo el punto. El desenfoque es decoración
   encima de algo que ya no es nada. */
.oferta.oculta { filter: blur(6px); pointer-events: none; user-select: none; opacity: .75; }

.vacio { color: rgba(255, 255, 255, .6); font-size: 17px; text-align: center; padding: 26px 16px; }

/* ── El muro ── */

.muro {
  max-width: 1140px;
  margin: 6px 0 20px;
  padding: 24px 18px;
  text-align: center;
  background: rgba(255, 209, 102, .1);
  border: 1px solid rgba(255, 209, 102, .32);
  border-radius: 16px;
}
.muro h3 { font-size: 22px; font-weight: 700; color: #fff; margin-bottom: 9px; }
.muro p { margin: 0 0 18px; color: rgba(255, 255, 255, .78); font-size: 16px; line-height: 1.6; }
.muro .campos { max-width: 520px; margin: 0 auto; }
.muro .campos .accion { background: var(--oro); color: var(--verde); }
.muro .error { color: #ffb887; margin: 12px 0 0; }
.muro .espera { margin: 14px 0 0; font-size: 15px; color: rgba(255, 255, 255, .6); }
.muro .espera:empty { display: none; }

/* La casilla no es letra pequeña: es una oferta. Se lee como tal, con caja
   propia y contraste de texto normal, no de aviso legal. */
.consent {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  max-width: 620px;
  margin: 18px auto 0;
  text-align: left;
  font-size: 15px;
  line-height: 1.55;
  color: rgba(255, 255, 255, .9);
  cursor: pointer;
  padding: 14px 16px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 209, 102, .22);
  transition: background .15s ease, border-color .15s ease;
}
.consent:hover { background: rgba(255, 255, 255, .1); border-color: rgba(255, 209, 102, .45); }
.consent input { flex: none; width: 22px; height: 22px; margin: 2px 0 0; accent-color: var(--oro); }

/* La espera del informe son unos segundos más: la caja entera late. */
.muro.cargando { animation: latido 1.7s ease-in-out infinite; }
@keyframes latido {
  0%, 100% { border-color: rgba(255, 209, 102, .3); box-shadow: 0 0 0 0 rgba(255, 209, 102, 0); }
  50% { border-color: rgba(255, 209, 102, .75); box-shadow: 0 0 0 7px rgba(255, 209, 102, .07); }
}

/* ── El resultado del envío (§7) ── */

.muro.hecho { background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .2); }
.enlace { background: rgba(0, 0, 0, .25); border-radius: 12px; padding: 13px 14px; margin: 16px auto; max-width: 620px; text-align: left; }
.enlace .et { display: block; font-size: 13px; color: rgba(255, 255, 255, .6); margin-bottom: 6px; }
.enlace code { display: block; font-size: 13px; word-break: break-all; color: var(--oro); margin-bottom: 11px; }
.enlace .accion { background: transparent; color: #fff; border: 2px solid rgba(255, 255, 255, .34); box-shadow: none; min-height: 44px; font-size: 16px; }
.muro .accion { text-decoration: none; }
.porque { font-size: 13.5px; color: rgba(255, 255, 255, .6); margin: 12px 0 0; }

/* ═════════════════════ LA COMPOSICIÓN ═════════════════════
   Por qué «remoto» no significa «de cualquier parte», y cómo se calcula lo de
   cada uno. Va debajo de la acción: la caja manda, pero la explicación queda
   a mano para quien dude. Si `/api/estado` no trae la composición, esta
   sección se queda vacía y desaparece — no se inventa. */

.composicion:empty { display: none; }
.composicion {
  max-width: 1020px;
  margin: 30px auto 0;
  padding: 18px 18px 20px;
  background: rgba(0, 0, 0, .16);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 16px;
}
.composicion h2 { font-family: var(--display); font-size: 20px; font-weight: 700; margin: 0 0 8px; color: #fff; text-align: center; }
.composicion .pie { font-size: 15.5px; color: rgba(255, 255, 255, .58); margin: 0 auto 18px; text-align: center; max-width: 74ch; line-height: 1.55; }

.comp-fila { display: flex; align-items: baseline; gap: 12px; font-size: 15.5px; margin-bottom: 4px; }
.comp-fila .et { flex: 1; color: rgba(255, 255, 255, .88); }
.comp-fila .nu { font-family: var(--display); font-weight: 700; color: #fff; font-variant-numeric: tabular-nums; }
.comp-fila .pc { color: var(--oro); font-size: 14px; min-width: 58px; text-align: right; font-variant-numeric: tabular-nums; }
.comp-barra { height: 8px; background: rgba(255, 255, 255, .1); border-radius: 4px; overflow: hidden; margin-bottom: 9px; }
.comp-barra i { display: block; height: 100%; background: var(--oro); }
.comp-barra.gris i { background: rgba(255, 255, 255, .3); }

.regla-calculo {
  margin: 14px 0 0;
  padding: 12px 16px;
  background: rgba(255, 209, 102, .1);
  border-left: 4px solid var(--oro);
  border-radius: 0 9px 9px 0;
  font-size: 15.5px;
  color: rgba(255, 255, 255, .88);
  line-height: 1.6;
}
.regla-calculo b { color: var(--oro); font-variant-numeric: tabular-nums; }

/* ═════════════════════ PIE ═════════════════════ */

footer {
  max-width: 1020px;
  margin: 34px auto 0;
  padding: 22px 0 calc(26px + env(safe-area-inset-bottom));
  color: rgba(255, 255, 255, .5);
  font-size: 14px;
  border-top: 1px solid rgba(255, 255, 255, .12);
  text-align: center;
}
footer p { margin: 0 0 6px; }
footer a { color: var(--oro); }

/* ═════════════════════ PANTALLAS MÁS ANCHAS ═════════════════════
   A partir de aquí sólo se AÑADE. Nada de lo de arriba se deshace. */

@media (min-width: 560px) {
  :root { --gutter: 24px; }
  .campos { grid-template-columns: 1fr auto; }
  /* El botón deja de ocupar el ancho entero en cuanto cabe entero. */
  .controles .accion { width: auto; padding: 18px 40px; font-size: 20px; }
  .muro { padding: 30px 34px; }
}

@media (min-width: 900px) {
  .hero { padding: 26px 0 16px; }
  .regla { width: 86px; height: 6px; margin: 0 auto 28px; }
  .protagonista .t { font-size: 17.5px; }
  .caja textarea { padding: 22px 72px 22px 24px; font-size: 19px; }
  .mic { right: 13px; bottom: 13px; }
  .controles { margin-top: 32px; }
  .controles .accion { padding: 20px 49px; font-size: 21px; }
  .ofertas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .muro { grid-column: 1 / -1; }
  .composicion { padding: 16px 28px 22px; }
  .composicion h2 { font-size: 22.5px; }
  body::before { width: 780px; height: 780px; top: -310px; right: -240px; }
  body::after { width: 560px; height: 560px; bottom: -270px; left: -210px; }
}

/*
 * 1240 px: donde la rejilla de tres columnas cabe sin estrangular la caja.
 *
 * `align-items:start` más un margen negativo suben los paneles por encima de
 * la caja: se van en diagonal hacia arriba y hacia fuera, y la fila deja de
 * medir lo que miden ellos, así que el bloque de abajo sube con ellos.
 *
 * Los paneles se pegan a los bordes en vez de estirarse: el sitio que sobra
 * se va al hueco entre panel y caja, no a hacer líneas larguísimas.
 */
@media (min-width: 1240px) {
  main { padding-inline: 26px; }
  .zona {
    grid-template-columns: 1fr minmax(0, 700px) 1fr;
    gap: 44px;
    align-items: start;
    max-width: 2080px;
  }
  .zona .buscador { order: 0; align-self: start; }
  .zona > .c-lado { margin-top: -104px; max-width: 470px; width: 100%; align-self: stretch; }
  .zona > .c-lado:first-of-type { justify-self: start; }
  .zona > .c-lado:last-of-type { justify-self: end; }
  .c-lado li { font-size: 17px; }
  /* Sin los paneles la caja se recentra y la fila se estrecha con ella. */
  body.con-resultados .zona { grid-template-columns: 1fr; max-width: 880px; }
}

/*
 * Portátiles bajos: en 900 px de alto no hay margen que recortar que valga,
 * así que ahí el titular y la cifra bajan de tamaño. Es preferible a que la
 * caja de búsqueda quede por debajo del pliegue.
 */
@media (min-width: 900px) and (max-height: 900px) {
  .hero { padding: 14px 0 10px; }
  .hero .kicker { margin: 0 0 8px; }
  .hero h1 { font-size: clamp(28px, 3.2vw, 42px); margin: 0 0 9px; }
  .regla { margin: 0 auto 12px; height: 5px; }
  .protagonista .n { font-size: clamp(38px, 4vw, 54px); }
  .protagonista .t { font-size: 15px; margin-top: 6px; }
  .sello { margin: 8px 0 0; font-size: 13px; padding: 6px 15px; }
  .contexto { font-size: 14px; margin: 9px auto 0; }
  .controles { margin-top: 24px; }
  .composicion { margin: 24px auto 0; }
}

/* Quien pide que no se mueva nada, no ve nada moverse — pero se le avisa
   igual, quieto: un aviso que desaparece con la animación es un aviso que se
   pierde. El ejemplo que se teclea solo también se para: ver `tecleaEjemplos()`. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .muro.cargando { animation: none; border-color: var(--oro); }
  .girando { animation: none; border-top-color: rgba(255, 255, 255, .35); }
  .buscando .bb i { animation: none; width: 50%; }
  .pts i { animation: none; opacity: 1; }
}
