/* ===========================================================================
   corder.pro — el cotizador por pasos
   ===========================================================================

   Hoja propia, cargada por las DOS páginas que lo usan: la portada, donde el
   cotizador ES el contenido principal, y /cotizar/, que es el mismo formulario
   con más aire y sin el resto de la portada alrededor.

   Vivía dentro de home.css, y mientras sólo existía en "/" tenía sentido. Al
   pasar /cotizar/ a usar el mismo componente había tres salidas y dos eran
   malas: duplicar el CSS en las dos hojas (dos copias que divergen con el
   primer arreglo), o subirlo entero a site.css (las veinte páginas del sitio
   pagando unos 15 KB de un formulario que sólo aparece en dos). Un archivo
   aparte no tiene ninguno de los dos defectos.

   Se carga DESPUÉS de site.css y ANTES de home.css, desde el slot `head` de
   cada vista. Hereda todos los tokens de site.css: aquí no se define un color.
   CUATRO PASOS, y los tres primeros se contestan con un dedo:

     1. Qué necesitas construir   seis placas con pictograma
     2. Para cuándo lo necesitas  cuatro pastillas
     3. Por dónde te contestamos  WhatsApp o correo, dos placas grandes
     4. Tus datos                 UN campo obligatorio, más el texto opcional

   El paso 3 existe para que el 4 sea corto. Antes el último paso pedía nombre,
   teléfono, correo y un mensaje obligatorio de quince caracteres: cuatro
   campos de teclado seguidos, que en un teléfono es donde se cae la mitad de
   los formularios. Preguntando primero POR DÓNDE quiere que le contesten, el
   paso final enseña sólo el campo que corresponde y el otro ni aparece.

   El presupuesto se quitó entero. Era el segundo paso y preguntaba con cuánto
   se puede empezar; es la pregunta que más incomoda a quien todavía no sabe lo
   que cuesta, y llegaba antes de haber demostrado nada.

   Sin JavaScript la placa no se muestra: en su lugar sale un enlace al
   cotizador completo, que es una página real y funciona sin nada. Un
   formulario por pasos degradado a medias es peor que un enlace honesto.
   =========================================================================== */

/* EL CONMUTADOR MIRA data-on, NO LA CLASE js. Y sólo en la portada.
   ===========================================================================

   Aquí había `.js .quoter { display: block }`, y eso creaba un callejón sin
   salida silencioso en la conversión principal del sitio.

   `js` la pone site.js, que dice "este navegador ejecuta JavaScript". Pero lo
   que el cotizador de la portada necesita no es eso: necesita que haya corrido
   SU script, quoter.js, que es quien pide el token CSRF, pliega los pasos y
   engancha el avance. Con `js` puesta y quoter.js ausente —un despliegue sin
   ese archivo, un 404, un bloqueador— la placa se mostraba igualmente y
   quedaba así:

     · la opción SÍ se marcaba al hacer clic (el radio es nativo),
     · pero no avanzaba de paso,
     · y "Siguiente" se quedaba apagado para siempre, porque quien lo enciende
       es quoter.js.

   O sea: un formulario que parece funcionar, acepta el clic y no lleva a
   ningún lado. Lo natural es volver a hacer clic, y de ahí el "hay que dar
   doble clic" que se reportó. Reproducido quitando el <script> del HTML.

   `data-on="true"` lo escribe quoter.js en cuanto termina de montarse, así que
   ahora la placa aparece si y sólo si va a funcionar. Si no, sale el enlace a
   /cotizar/, que es una página real. Era lo que el comentario de arriba ya
   prometía; ahora es verdad.

   SE ACOTA A .opening__form, que es el contenedor de la portada. En /cotizar/
   el mismo formulario DEBE verse sin JavaScript: esa ruta no se cachea, su
   token viene impreso y el formulario se envía de una vez. Gatearlo allá por
   data-on rompería justo el camino sin JavaScript que esa página existe para
   cubrir.

   POR QUÉ NO SE GATEA DIRECTAMENTE CON data-on: quoter.js va diferido, así que
   el atributo llega después del primer pintado. Gatear con él dejaría ver el
   enlace de respaldo un instante en CADA carga, que es el parpadeo que la
   clase `js` vino a evitar en su momento.

   Así que se conserva el camino rápido —`js` enseña la placa antes de
   pintar— y site.js pone `data-quoter-roto` si al terminar de cargar el
   documento el formulario sigue sin `data-on`. El intercambio a respaldo sólo
   ocurre cuando algo está roto de verdad, que debería ser nunca. */
.quoter { display: none; }
.js .quoter { display: block; }

.quoter-fallback { display: grid; }
.js .quoter-fallback { display: none; }

/* La red de seguridad: quoter.js no llegó. Se esconde la placa muerta y vuelve
   el enlace a /cotizar/, que sí funciona. */
.opening__form[data-quoter-roto="true"] .quoter { display: none; }
.opening__form[data-quoter-roto="true"] .quoter-fallback { display: grid; }

.quoter {
  position: relative;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--edge), var(--shadow-lg);
  overflow: hidden;

  /* UN SOLO relleno lateral para toda la placa.

     Antes cada bloque traía el suyo a mano (1.1 rem la cabecera, 1.15 los
     pasos, 1.15 la navegación, 1.15 el reaseguro) y ya estaban desincronizados
     entre sí: la cabecera iba medio píxel adentro del resto, que es de esas
     cosas que no se ven señaladas pero hacen que una tarjeta se sienta mal
     armada.

     Y sobre todo eran POCOS. 18 px de aire en una placa de 500 px dejan el
     texto pegado al contorno: el ojo lee el borde y la primera letra como si
     fueran la misma línea, y la tarjeta se siente apretada por más que el
     resto esté bien resuelto. En escritorio sube a ~30 px, que es donde el
     texto empieza a respirar; en un teléfono se queda en 18, que ahí sí es lo
     correcto, porque el ancho útil es lo que escasea. */
  --quoter-pad: clamp(1.15rem, 3.2vw, 1.85rem);
}

/* Cada paso es un <fieldset> porque un grupo de radios necesita su <legend>
   para que un lector de pantalla lea la pregunta junto a cada opción.

   min-width: 0 no es cosmético: el fieldset trae un ancho mínimo intrínseco
   heredado de los tiempos de las tablas, y dentro de un grid o un flex ese
   ancho gana sobre el contenedor. Es la causa clásica del scroll horizontal en
   un teléfono, y no se ve hasta que se prueba en uno. */
/* OJO CON LA ESPECIFICIDAD: este selector es `.quoter fieldset`, o sea (0,1,1),
   y le gana a `.quoter__step`, que es (0,1,0).

   Aquí había un `padding: 0` y por eso el relleno declarado en .quoter__step no
   se aplicaba NUNCA: el texto de cada paso salía pegado al contorno de la
   placa, con cero píxeles de aire. Se veía como un defecto de espaciado y era
   en realidad una regla ganando una batalla de especificidad que nadie había
   mirado.

   El reset se queda sólo con lo que de verdad tiene que resetear del fieldset
   —el borde y el margen del navegador, más el min-width intrínseco que hereda
   de los tiempos de las tablas y que provoca scroll horizontal dentro de un
   grid— y el relleno lo decide .quoter__step, que es a quien le toca. */
.quoter fieldset {
  border: 0;
  margin: 0;
  min-width: 0;
}

/* EL AIRE DE ARRIBA LO PONE EL PROPIO legend, no el fieldset.

   El <legend> IGNORA el padding-top de su <fieldset>: no es un bug del CSS,
   está en la especificación —se coloca sobre el borde superior, fuera del flujo
   normal— y por eso `display: block` no lo normaliza. Su `margin-top` tampoco
   surte efecto: computa, pero no desplaza (medido, offsetTop se quedaba en 0).

   Se veía así: `.quoter__step` declaraba 22.4 px de relleno superior y la
   pregunta salía a CERO de la cabecera de progreso, pegada al filo, mientras
   los rellenos lateral e inferior sí se aplicaban. La placa se veía torcida sin
   que se entendiera por qué.

   Se probaron las tres salidas conocidas antes de elegir ésta:

     display:grid/flex en el fieldset   no mueve el legend (medido: sigue en 0)
     float:left + width:100%            funciona, pero el bloque siguiente se
                                        monta 21 px encima —un flotante
                                        desplaza líneas, no cajas— y al
                                        arreglarlo con `clear` la clearance se
                                        come el margen superior del siguiente
     padding en el propio legend        funciona y no rompe nada

   Por dentro el legend SÍ es una caja normal, así que su relleno cuenta para su
   altura y el contenido que va después fluye debajo con sus propios márgenes
   intactos. Cero flotantes, cero clearance, cero hacks.

   Resultado medido en los cuatro pasos: 30 px arriba, 30 abajo. */
.quoter legend {
  display: block;
  width: 100%;
  padding: var(--quoter-pad) 0 0;
}

/* --- Cabecera: progreso ---------------------------------------------------
   Cuatro segmentos, no una barra continua con porcentaje. Un porcentaje invita
   a calcular cuánto falta; cuatro marcas dicen "son cuatro" de un vistazo, y
   el cuarto ya se ve desde el primero. */

.quoter__top {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.9rem var(--quoter-pad);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.quoter__bars {
  display: flex;
  gap: 0.3rem;
  flex: 1;
  min-width: 0;
}

.quoter__bar {
  flex: 1;
  height: 4px;
  border-radius: 999px;
  background: var(--border-strong);
  opacity: 0.45;
  transform-origin: left center;
  transition: background-color 0.22s var(--out), opacity 0.22s var(--out);
}

.quoter__bar[data-done="true"] {
  background: var(--accent-ink);
  opacity: 1;
}

/* --text-mute y no --text-faint: en mayúsculas y a 0.72rem esto es texto
   pequeño, y el tono apagado se queda por debajo del mínimo legible sobre la
   placa. El apagado sirve para adorno, no para el único indicador de en qué
   paso vas. */
.quoter__count {
  flex: none;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mute);
}

/* --- Cuerpo ---------------------------------------------------------------
   El alto lo anima JavaScript midiendo el paso que entra. Es la única
   propiedad de layout que se anima en toda la página, y se hace una vez por
   paso, no por cuadro: sin esto la placa da un salto seco cada vez que cambia
   el número de opciones, y ese salto es lo que hace sentir barato un
   formulario por pasos. */

/* LA RETÍCULA DEL FONDO.

   Líneas, no luz. El contrato de marca prohíbe el resplandor radial de fondo,
   así que la profundidad se construye con una malla de 1 px al 60 % de opacidad
   sobre el borde ya existente, no con un degradado que brille.

   Dos degradados repetidos y nada más: ni imagen, ni SVG, ni un pseudoelemento
   con filtro. Cuesta cero peticiones y se recalcula solo al cambiar de tema,
   porque el color sale de --border.

   Se desvanece hacia abajo con una máscara: arriba, detrás de la pregunta,
   ancla la placa; abajo, detrás de las opciones, competiría con los bordes de
   las propias placas y ensuciaría la lectura. */
.quoter__body::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right,  color-mix(in srgb, var(--border) 60%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--border) 60%, transparent) 1px, transparent 1px);
  background-size: 2.25rem 2.25rem;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, transparent 62%);
  mask-image: linear-gradient(to bottom, #000 0, transparent 62%);
}

/* El contenido va por encima de la retícula. Sin esto, los pasos —que no
   tienen fondo propio— quedarían debajo y la malla les cruzaría el texto. */
.quoter__step { position: relative; z-index: 1; }

.quoter__body {
  position: relative;

  /* La cámara compartida de los pasos. Va AQUÍ y no en cada paso: puesta en el
     elemento que gira, cada uno tendría su propio punto de fuga y los dos
     lados del cruce se verían inconsistentes. Ver los @keyframes de abajo. */
  perspective: 900px;
  perspective-origin: 50% 45%;
  /* Excepción deliberada y acotada: es la única propiedad de layout animada
     del sitio, corre una vez por paso y no por cuadro, y `contain: layout`
     (abajo) impide que el recálculo salga de este bloque. Las alternativas
     están evaluadas en el comentario de arriba. */
  /* impeccable-disable-next-line layout-transition: alto del paso, acotado con contain */
  transition: height 0.26s var(--in-out);

  /* contain acota el recálculo de layout a este bloque: el navegador sabe que
     lo de dentro no puede afectar a lo de fuera y no vuelve a medir el resto
     de la página en cada cuadro de la animación de alto.

     Las alternativas se probaron y son peores: un alto fijo obliga a dejar la
     placa tan alta como el paso más largo y deja un hueco muerto en los tres
     primeros, y grid-template-rows sirve para desplegar y plegar un mismo
     contenido, no para pasar del alto de un paso al del siguiente. */
  contain: layout;
}

/* Sin relleno superior: ése lo pone el propio <legend> (ver el porqué largo
   arriba, en `.quoter legend`). Los otros tres lados valen --quoter-pad, así
   que la placa queda simétrica. Antes eran 22.4 arriba, 29.6 a los lados y 24
   abajo: tres cifras distintas sin ninguna razón. */
.quoter__step { padding: 0 var(--quoter-pad) var(--quoter-pad); }

/* El paso que sale no empuja al que entra: se superponen durante el cruce. */
.quoter__step[data-leaving="true"] {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.quoter__step[hidden] { display: none; }

/* Entrada y salida asimétricas y direccionales. Avanzar entra desde la
   derecha, retroceder desde la izquierda: el gesto coincide con el sentido del
   avance, y sin eso "Atrás" se siente igual que "Siguiente".

   La salida es más corta que la entrada. Lo que el usuario espera es el paso
   nuevo; el viejo sólo tiene que quitarse de en medio.

   240 ms de entrada y 160 de salida, los dos por debajo del techo de 250 ms.
   Si se cambian aquí, hay que cambiar CROSS en quoter.js: el paso que sale se
   oculta cuando termina la entrada, no antes. */
.quoter__step[data-state="in"]  { animation: quoter-in  0.24s var(--out) both; }
.quoter__step[data-state="out"] { animation: quoter-out 0.16s var(--out) both; }

.quoter__body[data-dir="back"] .quoter__step[data-state="in"]  { animation-name: quoter-in-back; }
.quoter__body[data-dir="back"] .quoter__step[data-state="out"] { animation-name: quoter-out-back; }

/* El paso gira desde el borde por el que entra. Sobre el centro barrería hacia
   los dos lados a la vez y el gesto perdería dirección — "Atrás" se sentiría
   igual que "Siguiente", que es justo lo que la animación direccional viene a
   evitar. */
.quoter__step[data-state="in"]  { transform-origin: right center; }
.quoter__step[data-state="out"] { transform-origin: left center; }

.quoter__body[data-dir="back"] .quoter__step[data-state="in"]  { transform-origin: left center; }
.quoter__body[data-dir="back"] .quoter__step[data-state="out"] { transform-origin: right center; }

/* LOS PASOS GIRAN SOBRE SU EJE, no se deslizan de lado.

   Antes entraban con un `translate3d` de 12 px: correcto, discreto y sin
   ninguna personalidad. Ahora el paso que entra viene girado sobre el eje
   vertical y se endereza, como una tarjeta que rota hacia el lector.

   Las tres piezas que lo hacen leerse como profundidad y no como un
   estiramiento raro:

     · `perspective` en el CUERPO, no en el paso. Puesta en el elemento que
       gira, cada paso tendría su propio punto de fuga y los dos lados del
       cruce se verían inconsistentes. En el contenedor, los dos comparten
       cámara.
     · El giro va acompañado de un desplazamiento en Z. Sin él la tarjeta rota
       en su sitio y parece una puerta; alejándose un poco, parece que viene
       desde atrás.
     · `transform-origin` al borde por el que entra: girando sobre el centro,
       el paso barre hacia los dos lados a la vez y el gesto pierde dirección.

   El ángulo es CHICO a propósito —14°—. Por encima de unos 20° la tipografía
   se deforma lo suficiente como para que el texto se lea borroso a media
   transición, y eso en un formulario se nota como un defecto, no como un
   efecto. */
@keyframes quoter-in {
  from {
    opacity: 0;
    transform: perspective(900px) translate3d(28px, 0, -70px) rotateY(14deg);
  }
  to {
    opacity: 1;
    transform: perspective(900px) translate3d(0, 0, 0) rotateY(0deg);
  }
}

@keyframes quoter-out {
  from {
    opacity: 1;
    transform: perspective(900px) translate3d(0, 0, 0) rotateY(0deg);
  }
  to {
    opacity: 0;
    transform: perspective(900px) translate3d(-22px, 0, -55px) rotateY(-11deg);
  }
}

@keyframes quoter-in-back {
  from {
    opacity: 0;
    transform: perspective(900px) translate3d(-28px, 0, -70px) rotateY(-14deg);
  }
  to {
    opacity: 1;
    transform: perspective(900px) translate3d(0, 0, 0) rotateY(0deg);
  }
}

@keyframes quoter-out-back {
  from {
    opacity: 1;
    transform: perspective(900px) translate3d(0, 0, 0) rotateY(0deg);
  }
  to {
    opacity: 0;
    transform: perspective(900px) translate3d(22px, 0, -55px) rotateY(11deg);
  }
}

.quoter__q {
  font-size: clamp(1.15rem, 1.02rem + 0.55vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.028em;
  line-height: 1.15;
  text-wrap: balance;
}

/* El foco se lleva al enunciado en cada cambio de paso para que un lector de
   pantalla lea la pregunta nueva. Marcarlo con contorno sería confuso: el
   usuario no lo enfocó, se lo movimos nosotros. */
.quoter__q:focus { outline: none; }

.quoter__hint {
  margin-top: 0.4rem;
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--text-mute);
}

/* --- Opciones -------------------------------------------------------------
   El radio real sigue existiendo y se queda encima de su etiqueta, invisible:
   así el clic, el foco por teclado y el lector de pantalla siguen viendo un
   grupo de radios normal, que es lo que es. */

.opts-grid {
  display: grid;
  gap: 0.5rem;
  margin-top: 1.05rem;
}

/* Dos columnas ya a 360 px para el paso de servicios: seis opciones en una
   sola columna empujan el resto del formulario fuera de la pantalla y obligan
   a desplazarse antes de haber contestado nada. */
.opts-grid--tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.pick {
  position: relative;
  display: flex;
}

.pick input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.pick label {
  flex: 1;
  /* min-width: 0 permite que el texto se rompa dentro de la celda. Sin esto un
     hijo de flex se niega a bajar de su ancho mínimo de contenido, y como la
     placa recorta lo que se sale, una palabra larga se cortaría a la mitad. */
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* 3.25rem = 52 px. Por debajo de 48 el pulgar falla y el usuario culpa al
     sitio, no a su dedo. */
  min-height: 3.25rem;
  padding: 0.75rem 0.95rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  font-size: 0.94rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.012em;
  /* "Automatización" no cabe de una pieza en media pantalla de 360 px. Con
     guionado parte como una palabra bien partida; overflow-wrap queda como red
     por si el navegador no trae diccionario de español. El <html> declara
     lang="es-MX", que es lo que activa el guionado. */
  hyphens: auto;
  overflow-wrap: break-word;
  cursor: pointer;
  /* Nunca `transition: all`: enumerar las propiedades es lo que impide que
     mañana entre a la lista algo que dispara layout sin que nadie lo note. */
  transition: border-color 0.15s var(--out),
              background-color 0.15s var(--out),
              color 0.15s var(--out),
              box-shadow 0.18s var(--out),
              transform 0.14s var(--out);
}

/* --- Las placas del primer paso ------------------------------------------
   El símbolo va encima de la etiqueta y no a su lado: al lado se comía el
   ancho útil de una celda de media pantalla y obligaba a partir
   "Automatización". Encima, cada opción se vuelve una placa que se reconoce
   por su dibujo antes de leerla, y el objetivo táctil pasa de una franja de
   52 px a un bloque de más de 100.

   Es además lo que saca al primer paso de parecer un formulario: seis
   rectángulos con texto son un formulario, seis placas con su símbolo son una
   elección. */
.pick--tile label {
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  min-height: 6.4rem;
  padding: 0.9rem 0.9rem 0.85rem;
  background: var(--surface);
  box-shadow: var(--edge), var(--shadow-sm);
}

/* El bisel interior — el doble borde anidado.

   El símbolo ya no flota suelto sobre la placa: vive en su propia placa, con
   su borde, su radio chico y su filo de luz. Son dos superficies anidadas, y
   ese anidamiento es lo que hace que la opción se lea como un objeto físico y
   no como un rectángulo con un dibujo encima.

   Se apoya en el suelo (--bg) y no en la superficie: dentro de una placa
   blanca, la pieza que se hunde es la que se ve más oscura. En oscuro la
   relación se invierte sola porque los tokens ya la invierten, y por eso no
   hay ni una regla aquí que consulte el tema. */
.pick__badge {
  display: grid;
  place-items: center;
  width: 2.3rem;
  height: 2.3rem;
  flex: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  box-shadow: var(--edge);
  transition: border-color 0.15s var(--out),
              background-color 0.15s var(--out),
              box-shadow 0.18s var(--out),
              transform 0.16s var(--out);
}

.pick__glyph {
  width: 1.3rem;
  height: 1.3rem;
  flex: none;
  color: var(--accent-ink);
  transition: color 0.15s var(--out), transform 0.2s var(--out);
}

.pick__name {
  font-size: 0.92rem;
  line-height: 1.2;
}

/* Elegida, la placa se invierte entera y el bisel interior se vuelve del color
   del papel con el símbolo en tinta de acento: la misma lógica del rótulo
   encendido que usa el CTA, aplicada a los dos niveles a la vez.

   Y SE LEVANTA. Dos píxeles de subida con la sombra creciendo a la vez: la
   opción elegida deja de estar al mismo nivel que las demás, que es lo que
   convierte "está marcada" en "está encima". Es `translateY`, no `top` ni
   `margin`: se resuelve en el compositor y no vuelve a medir la rejilla. */
.pick--tile input:checked + label {
  box-shadow: var(--shadow-md);
  transform: translate3d(0, -2px, 0);
}

/* Al presionar gana la escala de retroalimentación, que ya está declarada más
   abajo para todas las placas. Sin esta línea, el `transform` de arriba le
   ganaría por orden y la opción ya elegida dejaría de responder al tacto. */
.pick--tile input:checked:active + label { transform: scale(0.97); }

.pick--tile input:checked + label .pick__badge {
  border-color: transparent;
  background: var(--on-accent);
  box-shadow: none;
}

.pick--tile input:checked + label .pick__glyph { color: var(--accent); }

/* --- Placa de canal: WhatsApp o correo --------------------------------------
   ===========================================================================

   El paso 3, y la pieza que permite que el 4 sea corto.

   Es una placa de pictograma como la de servicios, pero más alta y a dos
   columnas fijas: son dos opciones y sólo dos, así que la rejilla no se adapta
   a nada — se declara. Cada una lleva su marca real dibujada (ver el porqué del
   SVG en línea en el marcado) y una línea de apoyo debajo del nombre, que es lo
   que contesta la pregunta de verdad: no "cuál prefiero" sino "cuál es más
   rápido".

   El símbolo va más grande que en las placas de servicio (1.75 rem contra 1.3):
   aquí el pictograma ES la opción, se reconoce antes que la palabra, y a tamaño
   de viñeta la de WhatsApp se vuelve una mancha verde sin forma.

   VERDE SÓLO EN LA DE WHATSAPP Y SÓLO EN EL SÍMBOLO. Es una de las tres
   excepciones de marca a "un solo azul" (DESIGN.md), y se gasta aquí porque el
   verde ES el reconocimiento: una placa de WhatsApp en azul se lee como un
   botón genérico. La placa elegida, en cambio, se invierte al acento azul como
   todas las demás — el verde identifica el canal, el azul sigue significando
   "esto es lo que elegiste".
   --------------------------------------------------------------------------- */

.opts-grid--channel { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.pick--channel label {
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 0.7rem;
  min-height: 7.5rem;
  padding: 1rem 0.95rem;
  background: var(--surface);
  box-shadow: var(--edge), var(--shadow-sm);
}

.pick--channel .pick__badge {
  width: 2.9rem;
  height: 2.9rem;
}

.pick--channel .pick__glyph {
  width: 1.75rem;
  height: 1.75rem;
}

/* La marca de WhatsApp en su verde, y sólo el símbolo. */
.pick--channel[data-canal="whatsapp"] .pick__glyph { color: var(--whatsapp); }

.pick__hint {
  margin-top: 0.1rem;
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: 0;
  color: var(--text-mute);
}

.pick--channel input:checked + label { box-shadow: var(--shadow-md); }

.pick--channel input:checked + label .pick__badge {
  border-color: transparent;
  background: var(--on-accent);
  box-shadow: none;
}

/* Elegida, la placa se invierte y el símbolo pasa al acento: incluida la de
   WhatsApp, que suelta su verde. Dentro de la placa encendida el verde sobre
   azul no se lee, y a esas alturas el canal ya está decidido: lo que el color
   tiene que comunicar es "ésta es la que elegiste". */
.pick--channel input:checked + label .pick__glyph { color: var(--accent); }
.pick--channel input:checked + label .pick__hint {
  color: color-mix(in srgb, var(--on-accent) 82%, transparent);
}

/* --- El texto libre, plegado ------------------------------------------------
   ===========================================================================

   El mensaje pasó de obligatorio a opcional, y eso obliga a tratarlo distinto:
   un textarea abierto con su etiqueta encima SIGUE pidiendo que escribas
   aunque el asterisco ya no esté. Plegado, el paso final se ve como un campo y
   un botón.

   Es un <details> nativo y no un acordeón escrito a mano: se abre sin
   JavaScript, el teclado ya lo maneja y el lector de pantalla ya anuncia su
   estado. Un acordeón propio sería más código para llegar a lo mismo peor.

   El triángulo por defecto del navegador se retira y se dibuja uno propio, con
   el mismo trazo que el resto de los iconos. `list-style: none` es lo que lo
   quita en Firefox y Chrome; `::-webkit-details-marker`, en Safari.
   --------------------------------------------------------------------------- */

.fld-extra > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: fit-content;
  padding: 0.35rem 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--accent-ink);
  cursor: pointer;
  list-style: none;
  transition: color 0.15s var(--ease);
}

.fld-extra > summary::-webkit-details-marker { display: none; }

.fld-extra > summary::before {
  content: "";
  width: 0.7rem;
  height: 0.7rem;
  flex: none;
  /* Un "+" dibujado con dos degradados, sin SVG ni fuente de iconos: son dos
     barras de 2 px cruzadas en el centro. Al abrirse, la vertical se apaga y
     queda el "−". */
  background:
    linear-gradient(currentColor, currentColor) center / 100% 2px no-repeat,
    linear-gradient(currentColor, currentColor) center / 2px 100% no-repeat;
  transition: transform 0.2s var(--out);
}

.fld-extra[open] > summary::before {
  background: linear-gradient(currentColor, currentColor) center / 100% 2px no-repeat;
  transform: rotate(180deg);
}

.fld-extra[open] > summary { margin-bottom: 0.5rem; }

@media (hover: hover) and (pointer: fine) {
  .fld-extra > summary:hover { color: var(--accent); }
}

.fld-extra > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* El hover sólo donde existe de verdad. En táctil se dispara al tocar y deja
   la opción anterior pintada como si siguiera activa. */
@media (hover: hover) and (pointer: fine) {
  .pick input:hover + label {
    border-color: var(--border-strong);
    background: var(--surface-2);
  }

  .pick--tile input:hover + label .pick__badge {
    transform: translateY(-2px);
    border-color: var(--border-strong);
  }

  /* La placa destacada no cambia de borde al pasar el cursor: el suyo es el
     degradado, y pintarlo encima apagaría justo lo que la distingue. */
  .pick--star input:hover + label { border-color: transparent; }
}

@media (max-width: 359px) {
  .pick--tile label { min-height: 5.8rem; padding-inline: 0.7rem; }
  .pick__badge { width: 2rem; height: 2rem; }
  .pick__glyph { width: 1.15rem; height: 1.15rem; }
  .pick__name { font-size: 0.86rem; }
}

/* --- La opción destacada --------------------------------------------------

   Un filo degradado que da la vuelta despacio alrededor de una sola placa. La
   tienda en línea es la puerta de entrada más pedida y necesita romper la
   rejilla para que se vea antes que las otras cinco.

   No es un resplandor difuso ni un backdrop-filter: los dos están prohibidos
   por marca. Es el mismo degradado de --primary a --spark que ya usa el
   subrayado del titular, del grosor de un píxel, girando.

   Cómo funciona: el contenedor lleva un píxel de relleno y el degradado como
   fondo. La etiqueta, opaca, tapa todo menos ese píxel, así que lo único que
   se ve del degradado es el marco. Ningún pseudo-elemento con z-index
   negativo, ningún overflow que recorte el anillo de foco. */
@property --halo {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.pick--star {
  padding: 1px;
  border-radius: calc(var(--radius) + 1px);
  background: conic-gradient(from var(--halo),
              transparent 0deg 186deg,
              var(--spark) 268deg,
              var(--primary) 322deg,
              transparent 360deg);
  animation: star-halo 6s linear infinite;
}

/* El borde propio de la etiqueta sobra: el marco ya lo pone el degradado, y
   dejar los dos deja una línea doble de dos píxeles que se ve como un error de
   maquetación. */
.pick--star label { border-color: transparent; }

@keyframes star-halo {
  to { --halo: 360deg; }
}

/* Hundir la placa al presionar. Es el acuse de recibo más barato que existe y
   sin él la interfaz parece que no escuchó. El bisel interior se hunde un poco
   más que la placa, que es como se comporta una pieza montada sobre otra. */
.pick input:active + label { transform: scale(0.97); }
.pick--tile input:active + label .pick__badge { transform: scale(0.94); }

.pick input:focus-visible + label {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}

.pick input:checked + label {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-accent);
}

/* La paloma se dibuja con clip-path en vez de aparecer de golpe: se traza de
   izquierda a derecha, que es como se hace una marca a mano. */
.pick__tick {
  flex: none;
  width: 1.05rem;
  height: 1.05rem;
  margin-left: auto;
  clip-path: inset(0 100% 0 0);
  transition: clip-path 0.22s var(--out) 0.03s;
}

.pick input:checked + label .pick__tick { clip-path: inset(0 0 0 0); }

/* En las placas del primer paso la marca de selección la da el relleno de
   acento y el bisel invertido, que se ven de sobra. Una paloma encima
   sobraría y quitaría ancho a la etiqueta. */
.pick--tile .pick__tick { display: none; }

/* --- Campos del último paso ---------------------------------------------- */

.quoter__fields {
  display: grid;
  gap: 0.75rem;
  margin-top: 1.05rem;
}

.fld { display: grid; gap: 0.3rem; }

/* SIN ESTA LÍNEA, `hidden` NO ESCONDE NADA AQUÍ.

   El navegador trae `[hidden] { display: none }` en su hoja de usuario-agente,
   pero cualquier `display` declarado por la hoja del sitio le gana: las hojas
   de autor mandan sobre las del navegador. `.fld` declara `display: grid`, así
   que un `.fld[hidden]` se seguía viendo.

   Se detectó en el paso 4 del cotizador: quoter.js ponía `hidden` y
   `disabled` en el campo del canal no elegido —y lo hacía bien, medido en el
   DOM— pero el campo seguía pintado en pantalla. El formulario mostraba
   WhatsApp Y correo a la vez, que es exactamente lo que el paso del canal
   viene a evitar. El `disabled` sí funcionaba, así que el campo de más ni
   siquiera se enviaba: no se veía como un fallo, se veía como un formulario
   que pide de más.

   Especificidad 0,2,0 contra los 0,1,0 de `.fld`, así que gana sin !important. */
.fld[hidden] { display: none; }

.fld label {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text-mute);
}

.fld input,
.fld textarea {
  width: 100%;
  min-height: 3.1rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  /* Nunca por debajo de 16 px: Safari en iOS hace zoom al enfocar un campo más
     chico y deja la página descuadrada, con el formulario a medio salir. */
  font-size: 1rem;
  line-height: 1.45;
  color: var(--text);
  transition: border-color 0.15s var(--out), box-shadow 0.15s var(--out);
}

.fld textarea {
  min-height: 5.5rem;
  resize: vertical;
}

.fld input::placeholder,
.fld textarea::placeholder { color: var(--text-faint); }

.fld input:focus,
.fld textarea:focus {
  outline: none;
  border-color: var(--accent-ink);
  box-shadow: 0 0 0 3px rgb(37 99 235 / 0.16);
}

/* El error usa --danger sólo en el borde y en el mensaje escrito debajo, que
   es lo que de verdad comunica el fallo a quien no distingue colores. */
.fld[data-bad="true"] input,
.fld[data-bad="true"] textarea {
  border-color: var(--danger);
  box-shadow: 0 0 0 1px var(--danger);
}

/* La tinta, no el color de estado: --danger sirve para el filo de 1 px del
   campo, pero a 0.8rem sobre el suelo claro se queda en 3.76:1. Ver
   --danger-ink en site.css. */
.fld__err {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--danger-ink);
}

/* El mensaje de error NO se oculta con display:none cuando está vacío.
   Es una región aria-live: varios lectores de pantalla no anuncian el texto
   que aparece dentro de un elemento que acaba de pasar de display:none a
   visible, porque para ellos el elemento nace en ese momento. Vacío no ocupa
   alto de todos modos. */

/* Correo y teléfono comparten renglón en cuanto hay ancho. Con uno de los dos
   basta para contestar, así que ponerlos uno debajo del otro haría el paso más
   largo de lo que realmente es. */
.fld-pair {
  display: grid;
  gap: 0.75rem;
}

@media (min-width: 440px) {
  .fld-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Pie del cotizador --------------------------------------------------- */

.quoter__foot {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.15rem;
}

/* Fila de navegación: "Atrás" a la izquierda, "Siguiente" a la derecha.

   "Siguiente" existe aunque los tres primeros pasos avancen solos al tocar una
   opción, y no es redundante:

     · Al volver atrás, la opción ya está marcada. Volver a tocarla no dispara
       ningún cambio, así que sin este botón el usuario se quedaba encerrado en
       el paso a menos que eligiera una respuesta distinta a la suya.
     · Con teclado, las flechas recorren el grupo de radios. Avanzar solo ahí
       saltaría de paso con una respuesta que la persona sólo estaba mirando.

   Así el avance automático se queda para el dedo, que es como entra el 90 % de
   la gente, sin encerrar a nadie más. */
.quoter__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0 var(--quoter-pad) var(--quoter-pad);
}

.quoter__nav[hidden] { display: none; }

.quoter__back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 3rem;
  padding: 0 0.6rem;
  margin-left: -0.6rem;
  border-radius: 999px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--text-mute);
  transition: color 0.15s var(--out),
              background-color 0.15s var(--out),
              transform 0.14s var(--out);
}

/* Es el único control DENTRO del formulario que todavía tenía hover sin
   proteger, y ahí es donde más caro sale: en iOS, un elemento cuyo aspecto
   cambia al pasar el cursor se lleva el primer toque para "pasar el cursor" y
   sólo activa al segundo. En un botón del cotizador eso se vive como que hay
   que tocar dos veces para que responda. */
@media (hover: hover) and (pointer: fine) {
  .quoter__back:hover { color: var(--text); background: var(--surface-2); }
}

/* Todo lo que se presiona lleva escala de retroalimentación, no sólo los
   botones con relleno. */
.quoter__back:active { transform: scale(0.97); }

.quoter__back svg { width: 15px; height: 15px; }

/* El atributo hidden lo apaga `display: none` de la hoja del navegador, que
   pierde contra cualquier selector de clase. Sin estas dos reglas, "Atrás"
   seguía viéndose en el primer paso y "Siguiente" en el último, aunque el
   JavaScript los marcara como ocultos. */
.quoter__back[hidden],
.quoter__next[hidden] { display: none; }

/* Arranca a la derecha aunque "Atrás" esté oculto en el primer paso. */
.quoter__next { margin-left: auto; }

/* APAGADO CON COLORES PROPIOS, NO CON `opacity`.

   Llevaba `opacity: 0.45`, y eso no es un ajuste flojo sino un planteamiento
   que no puede funcionar: la opacidad apaga el relleno y la tinta en la MISMA
   proporción, así que el contraste entre los dos siempre tiende a 1 según baja.
   Medido sobre el vidrio, la palabra "Siguiente" apagada daba 1.42:1 en claro y
   1.24:1 en oscuro —invisible—, y recorriendo la opacidad de 0.45 a 1 el texto
   sólo cruzaba el 4.5 justo en 1, donde ya no parece apagado. No hay valor
   bueno; hay que cambiar de herramienta.

   Se toleraba mientras el botón era un atajo opcional. Desde que se quitó el
   avance automático es el ÚNICO camino al paso siguiente, y es lo primero que
   alguien mira al llegar: un control ilegible ahí no dice "todavía no", dice
   "roto".

   Apagado no significa invisible: significa que se lee lo que hace y se ve que
   aún no toca. */
.quoter__next[disabled] {
  border-color: var(--border);
  background: var(--surface-2);
  color: var(--text-mute);
  box-shadow: none;
  pointer-events: none;
}

/* Sobre el vidrio los tokens del sistema no sirven —son del tema de la página,
   no de la placa azul— así que la variante declara su propios valores.

   LOS TRES ESTÁN MEDIDOS, y el reparto entre ellos también. Con el relleno al
   0.16 y la tinta al 0.92 el texto se quedaba en 3.99 sobre el tema claro, que
   es el difícil de los dos. Recorriendo las combinaciones, el relleno es lo que
   empuja el fondo hacia el blanco y le come el contraste a la tinta: cuanto más
   macizo, menos se lee lo que dice. 0.14 con tinta plena es el punto donde
   todavía queda cuerpo de botón y el texto cruza —4.63 en claro, de sobra en
   oscuro—.

   Y la FORMA la lleva el filo, no el relleno: a 0.14 el fondo apenas se separa
   de la placa (1.35), así que el borde sube a 0.55, que es el primer valor que
   cruza el 3:1 exigido al contorno de un control. Es el mismo 0.55 que ya usan
   las opciones y los campos de esta variante, medido en su día por lo mismo. */
.quoter--glass .quoter__next[disabled] {
  border-color: rgb(255 255 255 / 0.55);
  background: rgb(255 255 255 / 0.14);
  color: #fff;
}

/* Aviso de fallo de red al pedir el token. Se queda dentro de la placa para
   que el visitante NO pierda lo que ya escribió: mandarlo a otra página con el
   formulario a medias era tirar cuatro respuestas y sus datos de contacto. */
.quoter__alert {
  margin: 0 var(--quoter-pad) var(--quoter-pad);
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--accent-ink);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text);
}

.quoter__alert[hidden] { display: none; }

/* Aparece a media sesión, cuando el envío ya falló, así que entra en vez de
   materializarse: sin esto un bloque de texto se planta bajo el pulgar sin
   nada que explique de dónde salió, y lo primero que se piensa es que se tocó
   algo por error.

   Es animación y no transición porque de display: none no se transiciona. Sólo
   corre al aparecer: no hay salida que animar, el aviso se va cuando el
   siguiente intento funciona y para entonces ya se está mirando otra cosa. */
.quoter__alert:not([hidden]) { animation: alert-in 0.2s var(--out) both; }

@keyframes alert-in {
  from { opacity: 0; transform: translate3d(0, -4px, 0); }
  to   { opacity: 1; transform: none; }
}

.quoter__send {
  flex: 1;
  min-height: 3.35rem;
  font-size: 1rem;
}

/* El estado de envío (.btn[data-busy], .spin y su @keyframes) vive en site.css:
   lo usan este formulario y el de /cotizar/, y tenerlo dos veces era garantizar
   que un día el spinner girara a distinta velocidad en cada página. */

/* --- Reaseguro ------------------------------------------------------------
   Dentro de la placa, no suelto en el hero. Es la objeción que aparece con el
   dedo ya encima de la primera opción ("¿esto me compromete a algo?"), así que
   se contesta ahí. */

.quoter__sure {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.1rem;
  padding: 0.85rem var(--quoter-pad);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 0.8rem;
  color: var(--text-mute);
}

.quoter__sure li {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.quoter__sure svg {
  width: 13px;
  height: 13px;
  flex: none;
  color: var(--accent-ink);
}

.quoter-fallback {
  gap: 0.85rem;
  justify-items: start;
  padding: clamp(1.35rem, 4vw, 2rem);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--edge), var(--shadow-lg);
}

.quoter-fallback h2 {
  font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem);
  letter-spacing: -0.03em;
}

.quoter-fallback p {
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--text-mute);
}

/* ===========================================================================
   VARIANTE DE VIDRIO ESMERILADO  ·  .quoter--glass
   ===========================================================================

   Sólo la usa la portada. En /cotizar/ el cotizador se queda como está, sobre
   el suelo normal de la página: allá no hay campo de color detrás y un vidrio
   sobre blanco es un recuadro gris.

   El campo que se desenfoca lo pone `.opening__form::before` en home.css; ver
   allí por qué está acotado al cotizador y por qué no usa cian.

   POR QUÉ ESTO NO ES SÓLO "backdrop-filter"

   Un `backdrop-filter: blur()` a secas se ve como una mancha translúcida. Lo
   que hace que se lea como vidrio son tres capas que van juntas:

     1. El desenfoque CON saturación. Sin `saturate()` el color de detrás se
        apaga al difuminarse y el vidrio se ve sucio, no transparente.
     2. Un filo de luz de 1 px arriba, por dentro (`inset 0 1px 0`). Es el
        canto del cristal cogiendo la luz, y es lo que le da espesor.
     3. Un borde claro de 1 px. Sin él la placa no termina en ningún sitio.

   EL TEXTO SE INVIERTE A BLANCO porque el fondo efectivo pasa a ser azul
   medio. Todos los tonos de aquí abajo se midieron contra ese fondo compuesto,
   no contra el token de superficie, que aquí ya no aplica.

   LA OPCIÓN ELEGIDA ES BLANCA SÓLIDA, no más vidrio. Dos niveles de
   translucidez uno encima de otro no se distinguen, y "cuál elegí" es la única
   pregunta que esta pantalla tiene que contestar sin ambigüedad.
   =========================================================================== */

.quoter--glass {
  /* EL PAPEL Y SU TINTA VAN JUNTOS Y LOS DOS SON FIJOS.

     La opción elegida se pintaba con `background: #fff` (fijo) y
     `color: var(--text)` (token que cambia con el tema). En oscuro --text es
     #f1f5f9, casi blanco: el nombre de la opción quedaba a 1.1:1 sobre el papel
     blanco, o sea invisible. Es justo lo que DESIGN.md prohíbe —una regla que
     mezcla un valor fijo con uno que consulta el tema— y por eso el fallo sólo
     aparecía en un tema.

     Se declaran aquí los tres tonos del papel para que el par no se pueda
     volver a romper por separado: si algún día el papel deja de ser blanco, su
     tinta se cambia en la misma línea. */
  --vidrio-papel: #fff;
  --vidrio-tinta: #0f172a;
  --vidrio-tinta-apoyo: #475569;

  border-color: rgb(255 255 255 / 0.3);
  background: rgb(255 255 255 / 0.13);
  backdrop-filter: blur(22px) saturate(165%);
  -webkit-backdrop-filter: blur(22px) saturate(165%);

  /* EL VIDRIO CUAJA, NO SE DESVANECE.

     La placa entraba con la animación `enter` de su contenedor: opacidad y 14
     px de desplazamiento. Eso sirve para un bloque de texto, pero para una
     superficie de vidrio es mentira — un material no aparece transparentándose,
     se forma. Se anima el desenfoque desde 0 junto a una escala mínima, así que
     durante los 620 ms el fondo pasa de nítido a esmerilado: se ve CUAJAR.

     Mismo retraso y misma duración que la animación del contenedor, a
     propósito: las dos tienen que llegar en el mismo cuadro o se leen como dos
     cosas distintas ocurriendo seguidas.

     La opacidad y el desplazamiento los sigue poniendo el contenedor. Aquí sólo
     el desenfoque y la escala, para no desvanecer dos veces. */
  animation: vidrio-cuaja 0.62s var(--out) 0.21s both;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.45),
    0 24px 70px rgb(2 6 23 / 0.3);
  color: #fff;
}

@keyframes vidrio-cuaja {
  from {
    -webkit-backdrop-filter: blur(0) saturate(100%);
    backdrop-filter: blur(0) saturate(100%);
    transform: scale(0.985);
  }
  to {
    -webkit-backdrop-filter: blur(22px) saturate(165%);
    backdrop-filter: blur(22px) saturate(165%);
    transform: none;
  }
}

.quoter--glass .quoter__top {
  background: rgb(255 255 255 / 0.08);
  border-bottom-color: rgb(255 255 255 / 0.18);
}

.quoter--glass .quoter__count { color: rgb(255 255 255 / 0.93); }
.quoter--glass .quoter__q     { color: #fff; }
.quoter--glass .quoter__hint  { color: rgb(255 255 255 / 0.93); }

.quoter--glass .quoter__bar { background: rgb(255 255 255 / 0.28); opacity: 1; }
.quoter--glass .quoter__bar[data-done="true"] { background: #fff; }

/* La retícula sobraría: el campo de detrás ya da profundidad, y una malla
   encima del desenfoque se ve como suciedad en el cristal. */
.quoter--glass .quoter__body::before { display: none; }

/* --- Las opciones sobre vidrio ---

   EL FILO AL 0.55 ES EL MÍNIMO MEDIDO, NO UN GUSTO. Iba al 0.26 y sobre la
   placa clara daba 1.76:1; el relleno de blanco al 10 % aporta 1.25:1, así que
   entre los dos no llegaban al 3:1 que pide el borde visible de un control.
   Sobre un vidrio azul, una casilla que sólo se distingue por un velo tenue
   desaparece para quien no separa bien el azul: no se ve DÓNDE se toca. El
   0.55 es el primer paso que cruza el umbral en claro (3.08:1), que es el tema
   difícil de los dos —en oscuro el mismo valor da 5.05:1—. */

.quoter--glass .pick label {
  border-color: rgb(255 255 255 / 0.55);
  background: rgb(255 255 255 / 0.1);
  color: #fff;
}

/* Sin marcar el filo iba al 0.26 y sobre el vidrio claro se quedaba en 1.62:
   no llegaba a desaparecer como el de la opción elegida, pero tampoco se veía.
   0.40 lo sube a 2.08 en claro y 2.98 en oscuro, y se queda deliberadamente por
   DEBAJO del 0.55 que lleva el borde de la casilla: el pictograma es un detalle
   dentro de la opción, no otro control, y si los dos filos pesan igual la
   casilla deja de leerse como una sola pieza. */
.quoter--glass .pick__badge {
  border-color: rgb(255 255 255 / 0.4);
  background: rgb(255 255 255 / 0.14);
  box-shadow: none;
}

.quoter--glass .pick__glyph { color: #fff; }

/* 0.96 y no el 0.86 que llevaba: medido sobre la placa de opción —que ya lleva
   su propio 10 % de blanco encima del vidrio— el apagado daba 4.17:1, por
   debajo del 4.5 de un texto de 12 px. Es el único tono de la variante que no
   pasaba. A 0.96 sigue leyéndose como texto de apoyo, un punto por debajo del
   nombre, sin caer del mínimo. */
.quoter--glass .pick__hint { color: rgb(255 255 255 / 0.96); }

/* Elegida: papel sólido y tinta oscura. Ver el porqué arriba.

   Las reglas de dentro NO se escriben por modificador (--tile, --channel). Así
   estaban y por eso se colaba el fallo: cada vez que nace un tipo de opción
   nuevo hay que acordarse de repetir aquí sus tres líneas, y el paso del plazo
   —un `.pick` pelado, sin modificador— nunca las tuvo. Al colgarlas del estado
   marcado, cualquier opción futura queda cubierta sin tocar nada. */
.quoter--glass .pick input:checked + label {
  border-color: var(--vidrio-papel);
  background: var(--vidrio-papel);
  color: var(--vidrio-tinta);
}

/* .pick__name no declara color propio y heredaría bien, pero .pick__hint sí
   —lleva el blanco al 96 % de la variante— y sobre el papel desaparecía. Se
   fijan los dos: el que hereda no pierde nada y el que no, se arregla. */
.quoter--glass .pick input:checked + label .pick__name { color: var(--vidrio-tinta); }
.quoter--glass .pick input:checked + label .pick__hint { color: var(--vidrio-tinta-apoyo); }

/* EL BORDE DEL PICTOGRAMA SE VOLVÍA INVISIBLE AL ELEGIR, y no por un tono
   flojo: era `transparent` literal, medido en 1.00 de contraste.

   Venía de la regla base `.pick--tile input:checked + label .pick__badge`, que
   lo quita a propósito —y bien— para el diseño SIN vidrio: allí la placa
   elegida se rellena de acento y el pictograma se invierte a papel macizo, así
   que la forma la carga el propio relleno y un borde encima sobraría.

   Sobre el vidrio no se cumple ninguna de esas dos cosas. La placa elegida es
   papel blanco y el pictograma queda como un lavado oscuro al 7 %, o sea que
   sin borde no queda nada: el icono se disuelve en el papel. Hereda la regla
   sin heredar el motivo, que es como se cuelan estos fallos.

   0.45 da 2.96 contra el papel y 2.57 contra su propio relleno: se ve el
   contorno sin que el pictograma se convierta en una caja negra que compita
   con el nombre de la opción, que es lo que de verdad hay que leer. */
.quoter--glass .pick input:checked + label .pick__badge {
  border-color: rgb(15 23 42 / 0.45);
  background: rgb(15 23 42 / 0.07);
}

.quoter--glass .pick input:checked + label .pick__glyph { color: var(--accent); }

.quoter--glass .pick__tick { color: var(--accent); }

/* El filo giratorio de la opción destacada se retira: sobre el campo de color
   el degradado azul-cian pierde todo contraste y queda como un halo sucio. */
.quoter--glass .pick--star { background: none; animation: none; padding: 0; }
.quoter--glass .pick--star label { border-color: rgb(255 255 255 / 0.5); }

@media (hover: hover) and (pointer: fine) {
  .quoter--glass .pick input:hover + label {
    border-color: rgb(255 255 255 / 0.5);
    background: rgb(255 255 255 / 0.18);
  }
}

.quoter--glass .pick input:focus-visible + label {
  outline-color: #fff;
}

/* --- Campos, texto plegado y pie --- */

.quoter--glass .fld label { color: rgb(255 255 255 / 0.9); }

/* Mismo 0.55 medido que en las opciones, y por el mismo motivo: al 0.3 el
   borde daba 1.92:1 y la caja de escribir no se distinguía del vidrio. Un
   campo de texto que no se ve es un campo que no se rellena. */
.quoter--glass .fld input,
.quoter--glass .fld textarea {
  border-color: rgb(255 255 255 / 0.55);
  background: rgb(255 255 255 / 0.12);
  color: #fff;
}

.quoter--glass .fld input::placeholder,
.quoter--glass .fld textarea::placeholder { color: rgb(255 255 255 / 0.72); }

.quoter--glass .fld input:focus,
.quoter--glass .fld textarea:focus {
  border-color: #fff;
  box-shadow: 0 0 0 3px rgb(255 255 255 / 0.28);
}

/* El rojo de estado se hunde contra el azul. El error se marca con el blanco
   del borde y el mensaje escrito, que es lo que de verdad lo comunica a quien
   no distingue colores. */
.quoter--glass .fld[data-bad="true"] input,
.quoter--glass .fld[data-bad="true"] textarea {
  border-color: #fff;
  box-shadow: 0 0 0 2px rgb(255 255 255 / 0.72);
}

.quoter--glass .fld__err { color: #fff; }

.quoter--glass .fld-extra > summary { color: rgb(255 255 255 / 0.93); }
.quoter--glass .quoter__back { color: rgb(255 255 255 / 0.92); }

/* EL PIE TENÍA FONDO PROPIO Y SE QUEDABA BLANCO.

   `.quoter__sure` no hereda el fondo de la placa: declara el suyo,
   `var(--surface-2)`, que en tema claro es casi blanco. Al invertir el texto a
   blanco para el vidrio, la franja quedó blanco sobre blanco — las dos líneas
   de reaseguro, que son las que dicen "respuesta en 24 horas" y "sin costo",
   desaparecieron por completo.

   Se vio en la primera captura y no en la medición: mi comprobación de
   contraste componía cada elemento contra la placa, no contra su propio fondo,
   así que el pie salía correcto en los números y en blanco en la pantalla. La
   foto lo cazó antes que la aritmética.

   Ahora la franja también es vidrio, un punto más opaca que la placa para que
   se siga leyendo como un pie y no como parte del cuerpo. */
.quoter--glass .quoter__sure {
  border-top-color: rgb(255 255 255 / 0.18);
  background: rgb(255 255 255 / 0.08);
  color: rgb(255 255 255 / 0.9);
}

.quoter--glass .quoter__sure svg { color: #fff; }

/* El botón principal invierte a papel, igual que dentro del rótulo encendido:
   sobre un fondo saturado, repetir el acento no destaca nada. */
.quoter--glass .quoter__send,
.quoter--glass .btn--primary {
  background: var(--on-accent);
  color: var(--accent);
  box-shadow: none;
}

/* El fantasma llevaba el borde al 45 % y sobre el vidrio se leía como un botón
   deshabilitado —el contraste del texto pasaba, pero la forma no se veía—. Con
   el filo al 72 % y un velo de blanco detrás recupera cuerpo de botón sin
   competir con el principal, que sigue siendo el único relleno macizo. */
.quoter--glass .btn--ghost {
  color: #fff;
  border-color: rgb(255 255 255 / 0.72);
  background: rgb(255 255 255 / 0.1);
}

@media (hover: hover) {
  .quoter--glass .btn--ghost:hover {
    border-color: #fff;
    background: rgb(255 255 255 / 0.18);
  }
}

/* --- Tema oscuro ---
   El campo de detrás es el mismo azul, pero la página ya es oscura: un vidrio
   claro encima se vería como una mancha luminosa flotando. Se invierte a
   cristal ahumado y el texto se queda blanco, que sobre él sigue leyéndose. */
:root[data-theme="dark"] .quoter--glass {
  border-color: rgb(255 255 255 / 0.16);
  background: rgb(2 6 23 / 0.42);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.18),
    0 24px 70px rgb(0 0 0 / 0.5);
}

:root[data-theme="dark"] .quoter--glass .quoter__top {
  background: rgb(2 6 23 / 0.3);
}

/* --- Sin transparencia ---
   Quien pide menos transparencia en el sistema recibe una placa sólida. No es
   un caso raro: es una opción de accesibilidad de iOS y de Windows, y con el
   vidrio activo este formulario sería ilegible para esa persona. */
@media (prefers-reduced-transparency: reduce) {
  .quoter--glass {
    /* El mismo tono que el vidrio deja pasar, no el azul puro: medido, el texto
       blanco de 12 px sobre --primary sin oscurecer da 4.14:1 y el nombre de la
       opción 4.36:1, los dos por debajo del 4.5 exigido. Con la mezcla que ya
       usa el campo de color de la portada, esta variante mide igual que la de
       vidrio y nadie recibe una versión peor por pedir menos transparencia. */
    background: color-mix(in srgb, var(--primary) 52%, #0f172a);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-color: rgb(255 255 255 / 0.35);

    /* La animación de entrada TERMINA en blur(22px), y una animación le gana a
       una declaración normal: sin apagarla, el vidrio volvería a aparecer justo
       en el modo que existe para quitarlo. Dura 620 ms y luego se queda puesto,
       así que el fallo sería permanente, no un parpadeo. */
    animation: none;
  }

  /* El bloque de tema oscuro gana por especificidad (`:root[data-theme]` contra
     una clase suelta) y volvía a dejar la placa translúcida justo dentro del
     respaldo que existe para quitarla: medido, el texto caía a 2.44:1. Se
     repite aquí el mismo selector para que la placa quede opaca en los dos
     temas. El azul profundo se lee como tarjeta en oscuro igual que en claro,
     así que no hacen falta dos tonos. */
  :root[data-theme="dark"] .quoter--glass {
    background: color-mix(in srgb, var(--primary) 52%, #0f172a);
  }

  :root[data-theme="dark"] .quoter--glass .quoter__top {
    background: rgb(2 6 23 / 0.22);
  }

  .opening__form::before { display: none; }
}

