/* ============================================================================
   Azulejo — sistema visual de Farmacia Márquez
   ============================================================================
   🔴 Los colores NO se eligen a ojo. `node ops/comprobar-css.js` calcula el
      contraste de cada pareja con la fórmula de WCAG y falla por debajo del
      mínimo. Si se cambia uno, hay que pasar ese script — porque el cliente
      medio de una farmacia de barrio tiene setenta años y mira el móvil en la
      calle, y porque el RD 193/2023 art. 14 obliga a nivel AA a las webs
      privadas de bienes y servicios, sin exención por tamaño, el 1-ene-2029.

   LA IDEA. El azulejo sevillano es loza blanca vidriada con un rótulo encima,
   azul y blanco, cogida con junta. Aquí eso no se imita con texturas: la
   página es CAL y el contenido es PLIEGO blanco apoyado encima. El blanco deja
   de ser el vacío y vuelve a ser un material — que es justo lo que hace falta
   cuando los packshots del proveedor son blancos y hoy se funden con el fondo.

   TRES COSAS QUE NO SE HACEN, Y POR QUÉ:
   · NO hay tipografía web. Medido: la web pesa 17-22 kB en el cable y bloquea
     6,2 (ops/pesar.js). Una variable de dos ejes en woff2 son 40-90 kB: entre
     dos y cuatro veces la página entera. Y lo único que era requisito de
     verdad —las cifras tabulares para que los precios no bailen— ya lo da la
     pila del sistema. El registro de rótulo se consigue con peso, caja alta y
     prosa espaciada. Si algún día se quiere, se presupuesta contra pesar.js.
   · NO hay modo oscuro. Los packshots son blancos y deslumbran sobre negro.
   · NO hay animación de entrada, ni sombras que floten, ni urgencia. El
     art. 3.4 del RD 870/2013 prohíbe incentivos con medicamentos, y la
     cerámica no flota: solo se animan color, borde y sombra, 120 ms.
   ========================================================================= */

:root {
  /* --- los ocho nombres que audita ops/comprobar-css.js. No se renombran. -- */
  --fondo: #ffffff;          /* EL PLIEGO: tarjeta, ficha, diálogo, packshot   */
  --texto: #0c1a14;          /* tinta · 17,90:1 sobre pliego · 16,29 sobre cal */
  --gris: #4f5f59;           /* secundario · 7,04:1 sobre pliego               */
  --verde: #0f6b4f;          /* verde botica · 6,49:1                          */
  --verde-claro: #d7e8df;    /* verde cal                                      */
  --rojo: #a3231c;           /* 7,46:1                                         */
  --borde: #d5ded8;          /* 🔴 DECORATIVO. 1,38:1. Nunca en un control.     */
  --borde-campo: #6e827a;    /* 4,09:1 — el de los CONTROLES                   */

  /* --- el resto del sistema --------------------------------------------- */
  --papel: #f2f5f2;                /* cal: el suelo de body, cabecera y pie   */
  --verde-hondo: #0a4633;          /* :hover y :active del botón principal    */
  --azul: #1b4b73;                 /* azul de Triana                          */
  --azul-hondo: #12324d;           /* barra de identidad del panel            */
  --azul-cal: #e3eaf1;             /* fondo del bloque oficial                */
  --azul-tenue: #a9c0d4;           /* texto secundario SOBRE --azul-hondo     */
  --rojo-hondo: #7f1b16;           /* :hover del botón de rechazar            */
  --rojo-cal: #f7e4e2;
  --ambar: #7a4a00;                /* el tercer temple: «lo revisa alguien»   */
  --ambar-banda: #a9660a;
  --ambar-cal: #f6e9d4;
  --wa: #25d366;                   /* verde de Meta. Fijo, no es nuestro.     */

  /* 🔴 Inerte con COLOR, no con `opacity`. Un botón a opacity .5 da 2,28:1 y
     además el valor no se puede medir con un script: el comprobador ve el
     color declarado, no el compuesto. Aquí el deshabilitado tiene contraste
     real y se audita como cualquier otro par. */
  --inerte: #e1e7e4;
  --inerte-texto: #45524d;         /* 6,29:1 sobre --inerte                   */
  --inerte-borde: #a9b6b0;

  /* El foco. Azul de Triana: es lo que mete el azulejo dentro de la tienda y
     no solo en el bloque oficial. 9,13:1 sobre pliego, 8,31 sobre cal. */
  --foco: #1b4b73;
  --aro: 2px;

  /* Formas. Cerámica: canto vivo, radio corto. */
  --radio: 3px;
  --radio-min: 2px;
  --linea: 1px;
  --regla: 2px;                    /* la regla que cierra un rótulo           */
  --banda: 3px;                    /* la banda de estado a la izquierda       */

  /* Espacio. TODO en rem: el cliente de setenta años sube el tamaño de letra
     del navegador, y un objetivo táctil congelado en px rompe WCAG 1.4.4.
     El módulo grande es la junta del azulejo, 2,125rem = 34px por defecto. */
  --e1: .25rem;  --e2: .5rem;   --e3: .75rem;  --e4: 1.0625rem;
  --e5: 1.5rem;  --e6: 2.125rem; --e7: 3.1875rem; --e8: 4.25rem;
  --junta: 2.125rem;
  --toque: 2.75rem;                /* 2.5.8 pide 24px; 44 es lo cómodo        */

  --ancho: 1100px;
  --ancho-doc: 46rem;
  --medida: 68ch;                  /* ninguna prosa más ancha que esto        */
  --rapido: 120ms;
}

* { box-sizing: border-box; }

/* 🔴 Sin esto, el atributo `hidden` NO oculta nada en cuanto el elemento tiene
   una clase que fija `display`. Y aquí las tiene: `.campo`, `.consent`,
   `.ia-panel` y `.prod` son todas flex o grid, así que `el.hidden = true`
   —que es como se ocultan cosas en todo el JavaScript de esta web— no hacía
   absolutamente nada sobre ellas. Consecuencias reales que hubo: los campos
   de dirección seguían a la vista al elegir «recoger en la farmacia», y el
   consentimiento de renuncia al desistimiento salía en TODOS los carritos.
   El `!important` es correcto: `hidden` es una decisión del documento y tiene
   que ganar a cualquier clase de presentación. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--papel);
  color: var(--texto);
  font: 1rem/1.6 system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* Las cifras del sistema son proporcionales por defecto y los precios bailan
     en columna. Esto no cuesta un solo byte de descarga. */
  font-variant-numeric: lining-nums;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--verde); text-underline-offset: .18em; }
a:hover { color: var(--verde-hondo); }

/* --- EL FOCO ---------------------------------------------------------------
   🔴 Antes había UNA sola regla :focus-visible en toda la web (las tarjetas de
      categoría). Todo lo demás dependía del recuadro del navegador, que sobre
      estos colores casi no se ve. Es el criterio 2.4.7, nivel AA.

      El `outline-offset` no es estético: un aro verde sobre un botón verde da
      1,00:1 —invisible—. Con separación, el aro se apoya en la PÁGINA, no en
      el botón, y ahí el azul da 9,13:1 sobre pliego y 8,31 sobre cal. Por eso
      el offset es obligatorio y por eso el aro es azul y no verde. */
:focus-visible {
  outline: var(--aro) solid var(--foco);
  outline-offset: var(--aro);
}
/* Sobre fondos oscuros el aro azul desaparece: allí se cambia el token, no la
   regla. */
.barra-panel, .ia-yo { --foco: #ffffff; }

/* El foco al <h1> tras buscar es para lectores de pantalla; el recuadro ahí no
   aporta nada y despista. Es la ÚNICA excepción legítima de toda la hoja. */
h1[tabindex="-1"]:focus, h1[tabindex="-1"]:focus-visible { outline: none; }

/* --- rótulos ---------------------------------------------------------------
   La voz de azulejo se hace con caja alta, peso y prosa espaciada, no con una
   tipografía descargada. */
h1, h2, h3 { text-wrap: balance; line-height: 1.2; }
h1 { font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2rem); margin: 0 0 var(--e3); letter-spacing: -.01em; }
h2 { font-size: 1.375rem; margin: var(--e6) 0 var(--e3); }
h3 { font-size: 1.0625rem; margin: 0 0 var(--e2); }
p { margin: 0 0 var(--e3); max-width: var(--medida); }

/* La regla de cartucho: cierra el rótulo de sección y corre hasta el final.
   Es el gesto del bote de botica, y cuesta dos declaraciones. */
.regla { border-bottom: var(--regla) solid var(--texto); padding-bottom: var(--e2); }

.rotulo {
  font-size: .75rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .14em; color: var(--gris);
}

/* --- cabecera -------------------------------------------------------------- */
header {
  background: var(--papel);
  border-bottom: var(--linea) solid var(--borde);
  position: sticky; top: 0; z-index: 10;
}
/* La cornisa: una junta de verde a sangre arriba del todo. Es lo único
   decorativo de la cabecera y es lo que la identifica de un vistazo. */
header::before { content: ""; display: block; height: 4px; background: var(--verde); }

.barra {
  max-width: var(--ancho); margin: 0 auto; padding: var(--e3) var(--e4);
  display: flex; gap: var(--e4); align-items: center; flex-wrap: wrap;
}
.logo {
  display: inline-flex; align-items: center; gap: var(--e2);
  font-weight: 700; font-size: 1.1rem; color: var(--texto); text-decoration: none;
  letter-spacing: -.01em;
}
.logo img { width: 1.75rem; height: 1.75rem; display: block; }
.logo b { font-weight: 700; }
.logo i {
  font-style: normal; font-size: .6875rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: var(--gris); display: block; margin-top: -.1em;
}

/* 🔴 El `flex:1` va en el FORMULARIO, no en el input. Al envolver el input en
   un <form>, el hijo flex de `.barra` pasa a ser el form; si el `flex:1` se
   quedara en el input y el form no lo tuviera, el `min-width` empujaría y la
   cabecera se descolocaría EN TODAS LAS PÁGINAS a la vez, fichas incluidas.
   Por lo mismo `min-width: 0`: sin él, un hijo flex no baja de su tamaño
   natural y se desborda en móvil en vez de encogerse. */
.buscador-form { flex: 1 1 12rem; display: flex; gap: var(--e1); min-width: 0; }
.buscador {
  flex: 1; min-width: 0; min-height: var(--toque); padding: var(--e2) var(--e3); font-size: 1rem;
  background: var(--fondo); color: var(--texto);
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
}
.buscador::placeholder { color: var(--gris); opacity: 1; }
.buscador-ir {
  min-height: var(--toque); padding: var(--e2) var(--e3); border: 0; border-radius: var(--radio);
  background: var(--verde); color: #fff; font-size: .95rem; cursor: pointer;
}
.nav-cat {
  text-decoration: none; font-size: .95rem; white-space: nowrap; color: var(--texto);
  /* 2.5.8: 24px de alto mínimo. Con .95rem y lh 1.6 son 24,3 px justos, así
     que se le da holgura en vez de dejarlo en el filo. */
  display: inline-flex; align-items: center; min-height: 1.75rem;
}
.nav-cat:hover { color: var(--verde); }

.buscador-grande { display: flex; gap: var(--e2); max-width: 36rem; margin: var(--e4) 0 var(--e6); }
.buscador-grande .buscador { font-size: 1.05rem; padding: var(--e3); }

@media (max-width: 560px) {
  /* enterkeyhint="search" ya pone la tecla «buscar» en el teclado del móvil,
     así que el botón es redundante y ahí el sitio hace falta. */
  .buscador-ir { display: none; }
  .buscador-grande .buscador-ir { display: block; }
}

.icono-carrito {
  position: relative; text-decoration: none; color: var(--texto);
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--toque); min-height: var(--toque); font-size: 1.3rem;
}
.icono-carrito span {
  position: absolute; top: .25rem; right: .1rem;
  background: var(--verde); color: #fff; border-radius: 999px;
  font-size: .7rem; padding: .05rem .3rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* --- el pliego ------------------------------------------------------------
   Lo que lleva contenido se apoya en la cal. Un canto de 1 px y nada más: sin
   sombra, porque la cerámica no flota. */
main { max-width: var(--ancho); margin: 0 auto; padding: var(--e6) var(--e4) var(--e8); }
.pliego {
  background: var(--fondo); border: var(--linea) solid var(--borde);
  border-radius: var(--radio); padding: var(--e5);
}

.aviso {
  background: var(--verde-claro); border-left: var(--banda) solid var(--verde);
  padding: var(--e3) var(--e4); border-radius: 0 var(--radio) var(--radio) 0;
  margin-bottom: var(--e5);
}
.aviso p:last-child { margin-bottom: 0; }
.aviso.rojo { background: var(--rojo-cal); border-left-color: var(--rojo); }
.aviso.ambar { background: var(--ambar-cal); border-left-color: var(--ambar-banda); }

/* --- controles ------------------------------------------------------------- */
button, .boton {
  font: inherit; font-weight: 600; cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--toque); padding: var(--e2) var(--e4);
  border: var(--linea) solid var(--verde); border-radius: var(--radio);
  background: var(--verde); color: #fff;
  transition: background-color var(--rapido), border-color var(--rapido), color var(--rapido);
}
button:hover, .boton:hover { background: var(--verde-hondo); border-color: var(--verde-hondo); color: #fff; }
/* 🔴 El deshabilitado NO usa opacity: ver el comentario de --inerte. */
button:disabled, button:disabled:hover {
  background: var(--inerte); border-color: var(--inerte-borde);
  color: var(--inerte-texto); cursor: not-allowed;
}
.boton-secundario {
  background: var(--fondo); color: var(--verde); border-color: var(--borde-campo);
}
.boton-secundario:hover { background: var(--verde-claro); color: var(--verde-hondo); border-color: var(--verde); }
.boton-grande { font-size: 1.05rem; padding: var(--e3) var(--e6); }

/* --- rejilla de productos --------------------------------------------------
   La tarjeta conserva su canto. Se probó quitarlo y separar solo con la junta,
   y la separación medía 1,10:1: a ese contraste no hay junta, hay un campo
   continuo. Una separación que no se puede medir no es una separación. */
.rejilla { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.prod {
  background: var(--fondo); border: var(--linea) solid var(--borde);
  border-radius: var(--radio); padding: var(--e3);
  display: flex; flex-direction: column; gap: var(--e1);
  transition: border-color var(--rapido);
}
.prod:hover { border-color: var(--borde-campo); }
/* 🔴 La tarjeta lleva la imagen y los textos DENTRO de un <a> para que se
   pueda llegar a la ficha. Al meter ese <a>, los hijos flex de `.prod` pasaron
   a ser uno solo, y dentro del enlace los <span> volvieron a ser en línea:
   nombre, laboratorio y precio salían pegados en un párrafo. Con nombres
   reales de 70 caracteres la rejilla era ilegible. */
.prod > a { display: flex; flex-direction: column; gap: var(--e1); height: 100%;
            text-decoration: none; color: inherit; }
.prod img {
  width: 100%; aspect-ratio: 1; object-fit: contain;
  background: var(--fondo); border: var(--linea) solid var(--borde);
  border-radius: var(--radio-min); margin-bottom: var(--e1);
}
.prod .nom { font-weight: 600; font-size: .95rem; line-height: 1.35; }
.prod > a:hover .nom { text-decoration: underline; }
.prod .lab {
  color: var(--gris); font-size: .6875rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .08em;
}
/* El precio se apoya en una regla fina: es el gesto de la etiqueta de botica y
   además alinea todas las tarjetas de la fila a la misma altura. */
.prod .pvp {
  font-size: 1.25rem; font-weight: 700; margin-top: auto;
  padding-top: var(--e2); border-top: var(--linea) solid var(--borde);
  font-variant-numeric: tabular-nums lining-nums;
}
.etq {
  font-size: .6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  padding: .15rem var(--e1); border-radius: var(--radio-min); align-self: flex-start;
}
/* Ámbar: el tercer temple. Significa «esto lo mira un farmacéutico», y es la
   única señal cálida del sistema. Sustituye al #8a5200 sobre #fff3e0. */
.etq-med { background: var(--ambar-cal); color: var(--ambar); }
.agotado { color: var(--rojo); font-size: .85rem; font-weight: 600; }

/* --- carrito --------------------------------------------------------------- */
.linea {
  display: grid; grid-template-columns: 60px 1fr auto auto; gap: var(--e3);
  align-items: center; padding: var(--e3) 0; border-bottom: var(--linea) solid var(--borde);
}
.linea img {
  width: 60px; height: 60px; object-fit: contain; background: var(--fondo);
  border: var(--linea) solid var(--borde); border-radius: var(--radio-min);
}
.linea input[type=number] {
  width: 4.5rem; min-height: var(--toque); padding: var(--e1) var(--e2); font: inherit;
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
  font-variant-numeric: tabular-nums;
}
.quitar {
  background: none; border: 0; color: var(--gris); font-size: .85rem;
  text-decoration: underline; min-height: var(--toque); padding: 0 var(--e2);
}
.quitar:hover { background: none; color: var(--rojo); }
.totales { margin-top: var(--e5); margin-left: auto; max-width: 22rem;
           font-variant-numeric: tabular-nums lining-nums; }
.totales div { display: flex; justify-content: space-between; gap: var(--e4); padding: var(--e1) 0; }
.totales .total {
  font-size: 1.25rem; font-weight: 700; border-top: var(--regla) solid var(--texto);
  margin-top: var(--e2); padding-top: var(--e2);
}

/* --- formularios ----------------------------------------------------------- */
.campos { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.campo { display: flex; flex-direction: column; gap: var(--e1); }
.campo label { font-size: .85rem; font-weight: 600; }
.campo input, .campo textarea, .campo select {
  min-height: var(--toque); padding: var(--e2) var(--e3); font: inherit;
  background: var(--fondo); color: var(--texto);
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
}
.campo textarea { min-height: 5rem; }
.campo input:hover, .campo textarea:hover, .campo select:hover { border-color: var(--texto); }
.campo.ancho { grid-column: 1 / -1; }
.consent { display: flex; gap: var(--e2); align-items: flex-start; margin: var(--e3) 0; font-size: .9rem; }
.consent input { margin-top: .3rem; flex-shrink: 0; width: 1.15rem; height: 1.15rem; accent-color: var(--verde); }

.aviso-flotante {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: var(--e5);
  background: var(--rojo); color: #fff; padding: var(--e3) var(--e5);
  border-radius: var(--radio); z-index: 100; max-width: 90vw;
  box-shadow: 0 1px 0 rgba(12,26,20,.06), 0 10px 24px -14px rgba(12,26,20,.5);
}
.aviso-flotante.ok { background: var(--verde); }

/* 🔴 Texto OSCURO sobre el verde de WhatsApp, NUNCA blanco. Blanco sobre
   #25d366 da 1,98:1 — menos de la mitad del mínimo. En oscuro da 9,02:1.
   La regla estaba escrita aquí y aun así `.ia-cta-wa` la incumplía cien
   líneas más abajo, porque el comprobador solo miraba `.wa`. Ahora las dos
   salen del mismo token y las dos se comprueban. */
.wa, .ia-cta-wa { background: var(--wa); border-color: var(--wa); color: var(--texto); }
.wa:hover, .ia-cta-wa:hover { background: #1fb457; border-color: #1fb457; color: var(--texto); }
.wa {
  position: fixed; right: var(--e4); bottom: var(--e4); z-index: 90;
  padding: var(--e3) var(--e5); border-radius: 999px; text-decoration: none; font-weight: 700;
  display: inline-flex; align-items: center; min-height: var(--toque);
  box-shadow: 0 1px 0 rgba(12,26,20,.06), 0 10px 24px -14px rgba(12,26,20,.55);
}

/* --- pie ------------------------------------------------------------------- */
footer { border-top: var(--linea) solid var(--borde); background: var(--papel); margin-top: var(--e8); }
.pie { max-width: var(--ancho); margin: 0 auto; padding: var(--e6) var(--e4); font-size: .85rem; color: var(--gris); }
.pie h3 { color: var(--texto); font-size: .75rem; text-transform: uppercase; letter-spacing: .12em; margin: 0 0 var(--e2); }
.pie a { color: var(--texto); }
.pie-cols { display: grid; gap: var(--e5); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
/* El distintivo declara 90×52 en el HTML. Forzar solo la altura lo estiraba:
   se fija el ancho y la altura se calcula sola. */
.distintivo img { width: 90px; height: auto; display: block; }
.pie-legal { margin-top: var(--e5); padding-top: var(--e4); border-top: var(--linea) solid var(--borde); }
.pie-legal a, .pie-legal span a {
  margin-right: var(--e4); display: inline-flex; align-items: center;
  min-height: var(--toque); /* 2.5.8: no basta el espaciado, se le da altura */
}

@media (max-width: 560px) {
  .linea { grid-template-columns: 50px 1fr; grid-template-areas: "img nom" "img ctl"; }
  .totales { max-width: none; }
  main { padding: var(--e5) var(--e4) var(--e7); }
}

/* --- consentimiento de cookies ---------------------------------------------
   Aceptar y rechazar tienen el MISMO tamaño, peso y jerarquía a propósito: la
   guía de la AEPD exige que rechazar sea tan fácil como aceptar, y un
   «rechazar» en gris pequeño al lado de un «aceptar» verde grande es
   precisamente lo que se sanciona. */
.ck-banner {
  position: fixed; left: var(--e4); right: var(--e4); bottom: var(--e4); z-index: 200;
  max-width: var(--ancho-doc); margin: 0 auto; background: var(--fondo);
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
  box-shadow: 0 24px 48px -24px rgba(12,26,20,.45);
  padding: var(--e4) var(--e5); display: flex; gap: var(--e5); align-items: center; flex-wrap: wrap;
}
.ck-txt { flex: 1; min-width: 15rem; }
.ck-txt p { margin: var(--e1) 0 0; font-size: .88rem; color: var(--gris); }
.ck-btns { display: flex; gap: var(--e2); flex-wrap: wrap; }
.ck-btns button { font-size: .9rem; }
.ck-si, .ck-no { background: var(--verde); color: #fff; }   /* misma prominencia */
.ck-cfg { background: var(--fondo); color: var(--texto); border-color: var(--borde-campo); }
.ck-cfg:hover { background: var(--papel); color: var(--texto); border-color: var(--texto); }

.ck-dlg {
  border: var(--linea) solid var(--borde); border-radius: var(--radio); padding: var(--e5);
  max-width: 34rem; width: 92vw; box-shadow: 0 24px 48px -24px rgba(12,26,20,.45);
}
.ck-dlg::backdrop { background: rgba(12,26,20,.5); }
.ck-srv { border-top: var(--linea) solid var(--borde); padding: var(--e3) 0; }
.ck-srv label { display: flex; gap: var(--e2); align-items: center; min-height: var(--toque); }
.ck-srv p { margin: var(--e1) 0; font-size: .85rem; color: var(--gris); }
.ck-srv table { width: 100%; border-collapse: collapse; font-size: .8rem; }
.ck-srv th, .ck-srv td { text-align: left; padding: var(--e1); border-bottom: var(--linea) solid var(--borde); }

@media (max-width: 560px) {
  .ck-banner { flex-direction: column; align-items: stretch; }
  .ck-btns button { flex: 1; }
}

/* --- portada ---------------------------------------------------------------
   El único sitio del sitio donde asoma la trama de la junta: una rejilla de
   34 px sobre el verde cal, apenas perceptible, que es lo que hace que el
   bloque se lea como una pieza de cerámica y no como un banner. */
.portada {
  background:
    repeating-linear-gradient(0deg,  rgba(12,26,20,.05) 0 1px, transparent 1px var(--junta)),
    repeating-linear-gradient(90deg, rgba(12,26,20,.05) 0 1px, transparent 1px var(--junta)),
    var(--verde-claro);
  border: var(--linea) solid var(--borde);
  border-radius: var(--radio); padding: var(--e7) var(--e5); margin-bottom: var(--e7);
}
.portada h1 { margin: 0 0 var(--e3); font-size: clamp(1.75rem, 1.2rem + 2.4vw, 2.5rem); }
.portada p { max-width: var(--medida); margin: var(--e2) 0; }
.portada-datos { font-size: .92rem; color: var(--texto); line-height: 1.9; }
.valores { display: grid; gap: var(--e5); grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); margin-top: var(--e7); }
.valores h3 { font-size: .75rem; text-transform: uppercase; letter-spacing: .12em; margin: 0 0 var(--e2);
              color: var(--texto); padding-bottom: var(--e1); border-bottom: var(--regla) solid var(--verde); }
.valores p { margin: 0; font-size: .9rem; color: var(--gris); }

/* --- asistente -------------------------------------------------------------
   El lanzador va APILADO sobre el de WhatsApp, no en su sitio: el botón verde
   de WhatsApp lleva al farmacéutico de carne y hueso y no puede perder
   protagonismo frente a una máquina. */
.ia-lanzador {
  position: fixed; right: var(--e4); bottom: 5rem; z-index: 90;
  background: var(--fondo); color: var(--verde); border: var(--linea) solid var(--borde-campo);
  border-radius: 999px; padding: var(--e2) var(--e4); font-weight: 600;
  box-shadow: 0 1px 0 rgba(12,26,20,.06), 0 10px 24px -14px rgba(12,26,20,.4);
}
.ia-lanzador:hover { background: var(--verde-claro); color: var(--verde-hondo); border-color: var(--verde); }

.ia-panel {
  position: fixed; right: var(--e4); bottom: var(--e4); z-index: 95;
  width: min(24rem, calc(100vw - 2rem)); height: min(34rem, calc(100vh - 2rem));
  display: flex; flex-direction: column; background: var(--fondo);
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio); overflow: hidden;
  box-shadow: 0 24px 48px -24px rgba(12,26,20,.45);
}
.ia-cab { display: flex; gap: var(--e2); align-items: flex-start; padding: var(--e3) var(--e4);
          border-bottom: var(--linea) solid var(--borde); background: var(--verde-claro); }
.ia-cab > div { flex: 1; }
/* El gris sobre verde cal se queda en 4,10:1 y no llega al 4,5. Aquí el aviso
   legal del asistente va en tinta: es texto que hay que leer, no un adorno. */
.ia-aviso { display: block; font-size: .72rem; color: var(--texto); line-height: 1.35; margin-top: .15rem; }
.ia-cerrar { background: none; border: 0; color: var(--texto); font-size: 1rem;
             min-width: var(--toque); min-height: var(--toque); }
.ia-cerrar:hover { background: var(--fondo); color: var(--rojo); }

.ia-lista { flex: 1; overflow-y: auto; padding: var(--e3); display: flex; flex-direction: column; gap: var(--e3); }
.ia-msg { padding: var(--e2) var(--e3); border-radius: var(--radio); max-width: 88%;
          font-size: .92rem; line-height: 1.5; overflow-wrap: anywhere; }
.ia-bot { background: var(--papel); border: var(--linea) solid var(--borde); align-self: flex-start; }
.ia-yo  { background: var(--verde); color: #fff; align-self: flex-end; }

.ia-form { display: flex; gap: var(--e1); padding: var(--e2); border-top: var(--linea) solid var(--borde); }
.ia-form input {
  flex: 1; min-width: 0; min-height: var(--toque); padding: var(--e2) var(--e3); font: inherit;
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
}
.ia-oculto { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* Derivación al farmacéutico: el botón va DENTRO de la respuesta. Decir
   «pregunta por WhatsApp» y dejar el enlace en otra esquina no es derivar. */
.ia-ctas { display: flex; flex-wrap: wrap; gap: var(--e1); margin-top: var(--e2); }
.ia-cta {
  font-size: .82rem; font-weight: 600; text-decoration: none; padding: var(--e1) var(--e3);
  border-radius: 999px; border: var(--linea) solid var(--borde-campo);
  color: var(--verde); background: var(--fondo);
  display: inline-flex; align-items: center; min-height: 2rem;
}
.ia-cta:hover { background: var(--verde-claro); color: var(--verde-hondo); border-color: var(--verde); }

.ia-fichas { display: flex; flex-direction: column; gap: var(--e1); margin-top: var(--e2); }
.ia-ficha {
  display: grid; grid-template-columns: 1fr auto; gap: .1rem var(--e2);
  padding: var(--e2) var(--e3); border: var(--linea) solid var(--borde);
  border-radius: var(--radio); background: var(--fondo);
  text-decoration: none; color: var(--texto); font-size: .82rem;
}
.ia-ficha:hover { border-color: var(--verde); }
.ia-ficha-nom { font-weight: 600; }
.ia-ficha-pvp { font-weight: 700; color: var(--verde); font-variant-numeric: tabular-nums; }
.ia-ficha-stock { grid-column: 1 / -1; color: var(--gris); font-size: .75rem; }

/* 🔴 «Está escribiendo» tenía tres puntos grises a opacity .25: 1,40:1, es
   decir, invisible, y sin ningún texto detrás. Ahora el punto en reposo ya
   tiene contraste propio y la animación solo lo refuerza. */
.ia-puntos i {
  display: inline-block; width: .4rem; height: .4rem; margin-right: .18rem;
  border-radius: 50%; background: var(--gris); animation: ia-late 1.2s infinite;
}
.ia-puntos i:nth-child(2) { animation-delay: .2s; }
.ia-puntos i:nth-child(3) { animation-delay: .4s; }
@keyframes ia-late { 0%,60%,100% { transform: none; } 30% { transform: translateY(-.2rem); } }
@media (prefers-reduced-motion: reduce) { .ia-puntos i { animation: none; } }

@media (max-width: 560px) {
  /* En móvil el panel ocupa la pantalla: un chat de 24rem dentro de 360px de
     ancho no se puede usar. */
  .ia-panel { right: 0; bottom: 0; width: 100vw; height: 100dvh; border-radius: 0; border: 0; }
}

/* --- ficha de producto (la monta el servidor) ------------------------------ */
.ficha-producto { display: grid; gap: var(--e6); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 46rem) { .ficha-producto { grid-template-columns: minmax(0, 22rem) 1fr; gap: var(--e7); } }

/* El packshot es blanco: sobre la cal, el pliego blanco lo enmarca y el
   producto deja de fundirse con la página. Esta es la razón práctica de haber
   invertido el fondo, no una preferencia estética. */
.ficha-img img, .sin-img {
  width: 100%; aspect-ratio: 1; background: var(--fondo);
  border: var(--linea) solid var(--borde); border-radius: var(--radio);
}
.ficha-img img { height: auto; object-fit: contain; }
.sin-img { display: grid; place-items: center; border-style: dashed; color: var(--gris); font-size: .85rem; }

.ficha-datos h1 { font-size: clamp(1.4rem, 3.5vw, 2rem); margin: 0 0 var(--e1); }
.ficha-datos .lab {
  color: var(--gris); margin: 0 0 var(--e4); font-size: .75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
}
.pvp-grande {
  font-size: clamp(1.75rem, 1.35rem + 1.8vw, 2.25rem); font-weight: 700; margin: 0 0 var(--e1);
  font-variant-numeric: tabular-nums lining-nums;
}
.pvp-grande .iva { font-size: .82rem; font-weight: 400; color: var(--gris); }
.hay-stock { color: var(--verde); font-weight: 600; margin: 0 0 var(--e5); }
.ficha-datos .agotado { margin: 0 0 var(--e5); }

.descripcion { margin-top: var(--e6); }
.descripcion h2, .oficial h2 {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .12em; margin: 0 0 var(--e3);
  padding-bottom: var(--e1); border-bottom: var(--regla) solid var(--texto);
}
.descripcion p { margin: 0; }

.datos-tecnicos { display: grid; grid-template-columns: auto 1fr; gap: var(--e1) var(--e4);
                  margin: var(--e6) 0 0; font-size: .88rem; }
.datos-tecnicos dt { color: var(--gris); }
.datos-tecnicos dd { margin: 0; font-variant-numeric: tabular-nums; }

/* 🔴 La información oficial de la AEMPS va visualmente separada a propósito:
   no es nuestra, y el cliente tiene que ver de un vistazo que la fuente es
   otra. Por eso va en AZUL —el color institucional del sistema— y con banda,
   no solo con un fondo claro: un relleno a 1,10:1 no separa nada. */
.oficial {
  margin-top: var(--e6); padding: var(--e4); background: var(--azul-cal);
  border-left: var(--banda) solid var(--azul); border-radius: 0 var(--radio) var(--radio) 0;
  font-size: .88rem;
}
.oficial h2 { border-bottom-color: var(--azul); color: var(--azul); }
.oficial p { margin: 0 0 var(--e2); }
.oficial p:last-child { margin-bottom: 0; }
.oficial a { color: var(--azul); }

/* --- índice de categorías --------------------------------------------------- */
.rejilla-cats { display: grid; gap: var(--e3); grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }
.tarjeta-cat {
  display: flex; flex-direction: column; gap: var(--e1); padding: var(--e4);
  border: var(--linea) solid var(--borde); border-radius: var(--radio);
  text-decoration: none; color: inherit; background: var(--fondo);
  transition: border-color var(--rapido), background-color var(--rapido);
}
.tarjeta-cat:hover { border-color: var(--verde); background: var(--verde-claro); }

/* Paginación. Enlaces de verdad, no un «cargar más» que solo va con
   JavaScript: los buscadores no pulsan botones y quien tiene mala conexión,
   tampoco. Los objetivos van a --toque de alto: el criterio 2.5.8 pide 24 px y
   eso es el mínimo, no el objetivo. */
.paginacion { display: flex; flex-wrap: wrap; gap: var(--e1); align-items: center; margin: var(--e6) 0 0; }
.paginacion a, .pag-actual {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--toque); height: var(--toque); padding: 0 var(--e3);
  border: var(--linea) solid var(--borde-campo); border-radius: var(--radio);
  text-decoration: none; font-variant-numeric: tabular-nums;
}
.paginacion a:hover { background: var(--verde-claro); border-color: var(--verde); }
.pag-actual { background: var(--verde); border-color: var(--verde); color: #fff; font-weight: 700; }
.pag-hueco { padding: 0 var(--e1); color: var(--gris); }

/* El índice de categorías en árbol: las hijas colgando de su padre. */
.arbol-cats { display: grid; gap: var(--e4); grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.rama-cat {
  background: var(--fondo); border: var(--linea) solid var(--borde);
  border-radius: var(--radio); padding: var(--e4);
}
.rama-cat > a { font-weight: 700; text-decoration: none; font-size: 1.02rem; }
.rama-cat .cat-n { display: block; color: var(--gris); font-size: .8rem; margin-top: .1rem; }
.rama-cat ul { list-style: none; margin: var(--e3) 0 0; padding: 0; display: grid; gap: var(--e1); }
.rama-cat li a { text-decoration: none; font-size: .92rem;
                 display: inline-flex; align-items: center; min-height: 1.75rem; }
.cat-nombre { font-weight: 600; }
.cat-n { font-size: .82rem; color: var(--gris); font-variant-numeric: tabular-nums; }

/* --- modo de alto contraste del sistema ------------------------------------
   Windows en «contraste alto» descarta nuestros colores y usa los suyos. Los
   bordes que dibujamos con `background` desaparecen; con `border` sobreviven.
   Esto no lo prueba ningún script: se declara y ya. */
@media (forced-colors: active) {
  button, .boton, .prod, .tarjeta-cat, .rama-cat, .ia-ficha { border: 1px solid; }
  :focus-visible { outline-color: Highlight; }
}

/* 🔴 Un enlace que ocupa su propio párrafo NO es un «enlace en línea»: la
   excepción del criterio 2.5.8 no le aplica y tiene que llegar a 24 px de
   alto. Medido en la portada: «Ver todo por categorías» daba 185×21. */
.mas { margin-top: var(--e5); }
.enlace-suelto {
  display: inline-flex; align-items: center; min-height: var(--toque);
  font-weight: 600;
}
