/* ==========================================================================
   Cocina · webapp — hoja de estilos única.
   Sin fuentes de terceros, sin CDN, sin compilación: esto es lo que se sirve.
   Tema oscuro por defecto; con prefers-color-scheme: light se invierten los
   tokens (mismos nombres) y ningún componente necesita saberlo.
   ========================================================================== */

:root {
  /* Superficies: gris muy oscuro, nunca negro puro. La elevación se hace ACLARANDO el fondo.
     Decisión del 2026-10-14 (razonada en docs/webapp-diseno.md §7): se adopta el modelo de UNA SOLA
     SUPERFICIE SIN BORDES, medido en la app de Revolut, porque es una OBSERVACIÓN de algo en
     producción y gana a la opinión de un artículo de tendencias. El escalón entre fondo y
     superficie tiene que VERSE sin ayuda de una línea: si hace falta dibujar un borde para saber
     dónde empieza una tarjeta, el problema es el escalón, no la falta de borde. */
  /* ESCALONES MEDIDOS, no elegidos a ojo. El usuario dijo «veo todo apagado» y la causa NO era que
     faltaran bordes: era que faltaba ESCALÓN. Medido: los nuestros separaban 1,122:1 y 1,135:1, y los
     de Revolut 1,207:1. Un 7 % menos y sin bordes que taparan la diferencia se lee como una masa
     oscura uniforme. Ahora los tres separan ≥1,20:1. Lo vigila un criterio estático (C28), para que
     no se vuelva a aplanar sin que nadie lo vea. */
  --fondo: #101115;          /* Y=0.00565 */
  --sup-1: #23252e;          /* Y=0.01877  →  1.236:1 sobre el fondo */
  --sup-2: #333642;          /* Y=0.03738  →  1.271:1 sobre la superficie */
  --borde: rgba(255, 255, 255, .09);
  --borde-fuerte: rgba(255, 255, 255, .16);
  /* Relleno de la barra de fondo de cada alimento de Despensa: solo un poco más claro que la
     tarjeta, para que la cantidad se lea sin convertir la fila en otro bloque. */
  --despensa-relleno: rgba(255, 255, 255, .085);
  /* Velo de la cabecera y de la barra inferior. Es un rgba EXPLÍCITO y no un
     `color-mix()` a propósito: el verificador tiene que poder leer este color y
     componerlo, y un color-mix se serializa en un formato que se puede
     malinterpretar como números 0-255 y dar un contraste falso. */
  --velo: rgba(23, 24, 27, .92);

  /* Texto */
  --texto: #f1f2f4;          /* blanco roto, no #fff */
  --texto-2: #a6abb4;
  --texto-3: #8b919a;        /* aclarado a propósito: con #7b8189 se quedaba en 4,1:1 sobre --sup-1 y no llegaba al 4,5:1 de texto normal */
  /* REGLA DEL TERCIARIO (2026-10-14, medida): --texto-3 da 5,94:1 sobre --fondo y 4,81:1 sobre --sup-1, pero
     3,79:1 sobre --sup-2 (#333642). Sobre la superficie MÁS CLARA el terciario NO se usa: ahí el texto sube a
     --texto-2 (5,21:1). NO se arregla aclarando --texto-3, porque para llegar a 4,5:1 sobre --sup-2 tendría que
     valer ~#a9aeb8, que ya es --texto-2: se perdería un nivel de jerarquía para tapar un error de USO. */

  /* UN solo acento. */
  --acento: #d9a15e;
  --acento-suave: rgba(217, 161, 94, .14);
  /* Rojo de error: definido en los DOS temas. Antes solo existía el fallback #ff8a7a, que en claro daba
     2,29:1 sobre blanco. En oscuro este rojo da 6,67:1; en claro se usa un rojo más oscuro. */
  --peligro: #ff8a7a;
  /* Ámbar de aviso (2026-10-30): la conservación de la despensa UNA VEZ ABIERTO sale del texto de la
     etiqueta, no de una fecha de caducidad, así que no puede llevar el rojo de error. Se dice «se pasó»,
     no «está malo». */
  --aviso: #e0b062;
  /* SEXTA TANDA (punto 2, corregido por el usuario) · EL MISMO COLOR PARA LAS DOS BARRAS. «en lugar de negro
     con que fuera del mismo color que el fondo de la barra superior valdría para que no haya diferencia entre
     la barra de navegación de android y dicho elemento». Es UNA variable: si cambia una, cambia la otra. */
  --barra: var(--fondo);

  --radio-s: 8px;
  --radio: 12px;
  --radio-g: 16px;
  --ancho: 960px;
  --nav-alto: 72px;
}

@media (prefers-color-scheme: light) {
  :root {
    --fondo: #f7f7f5;
    --sup-1: #ffffff;
    --sup-2: #efefec;
    --borde: rgba(0, 0, 0, .10);
    --borde-fuerte: rgba(0, 0, 0, .18);
    --despensa-relleno: rgba(0, 0, 0, .085);
    --velo: rgba(247, 247, 245, .92);
    --texto: #1b1c1f;
    --texto-2: #5c6068;
    /* Oscurecido a propósito: con #6b7078 daba 4,33:1 sobre --sup-2 (#efefec), por
       debajo del 4,5:1. El fondo más exigente NO es el blanco de las tarjetas sino
       el gris de los recuadros internos (.dato), y ahí es donde fallaba. */
    --texto-3: #646970;
    /* Oscurecido por el mismo motivo: el acento sobre su propio tinte
       (--acento-suave) se quedaba en 4,33:1 en la pestaña activa. */
    --acento: #855719;
    --acento-suave: rgba(133, 87, 25, .12);
    --peligro: #b3261e;
    /* Ámbar de aviso en claro: oscurecido para pasar 4,5:1 sobre --sup-1. */
    --aviso: #7a5410;
    --barra: var(--fondo);
  }
}

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

/* EL ATRIBUTO `hidden` MANDA, SIEMPRE. Y no lo hacía: la regla del navegador para `[hidden]` es
   `display: none`, pero CUALQUIER regla nuestra de clase la gana (`.pie { display: flex }`), así que un
   elemento «oculto» seguía pintándose —con su borde de 1 px incluido—. Se descubrió en el ciclo 2 de las
   capturas del 2026-10-15: el pie de la app seguía dibujando la línea gris del punto 1 aunque su
   atributo `hidden` estuviera puesto, y el criterio C42 lo daba por bueno porque leía el atributo en vez
   de mirar lo que se pinta. Con `!important` esto no puede volver a pasar en ningún elemento. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--fondo);
  color: var(--texto);
  /* Tipografía del sistema: cero peticiones de red. */
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  /* Todas las cifras alineadas: se leen de un vistazo. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  -webkit-font-smoothing: antialiased;
}

:focus-visible {
  outline: 2px solid var(--acento);
  outline-offset: 2px;
  border-radius: var(--radio-s);
}

/* ------------------------------------------------------------------ enlaces */

a { color: var(--acento); text-decoration: none; }
/* EL SUBRAYADO DEL RATÓN, SOLO DONDE HAY RATÓN (quinta tanda, punto 13). En una pantalla táctil el `:hover`
   se queda pegado después de tocar, así que el usuario veía el texto de la pestaña subrayado «como si fuera
   un enlace» y no se iba hasta tocar otra cosa. Con `@media (hover: hover)` el subrayado no existe en el
   móvil; en el PC sigue igual. Lo mide el criterio en los dos temas: `text-decoration: none` en la etiqueta
   de la pestaña activa y de la pulsada. */
@media (hover: hover) {
  a:hover { text-decoration: underline; text-underline-offset: 2px; }
}

code, pre, .mono { font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace; }

.saltar {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--sup-2); color: var(--texto);
  padding: 12px 16px; border-radius: 0 0 var(--radio) 0;
}
.saltar:focus { left: 0; }

/* ------------------------------------------------------------------ cabecera */

.cabecera {
  position: sticky; top: 0; z-index: 20;
  flex: none;
  background: var(--velo);
  backdrop-filter: blur(8px);
  /* SEXTA TANDA (punto 3) · FUERA LA LÍNEA GRIS DE ARRIBA. El usuario mandó captura: «en la parte superior de
     todas las pestañas también tenemos una pequeña línea gris claro que sobra». Era este `border-bottom` de
     1 px, que se quedaba pegado al borde de arriba al hacer scroll. Se quita en las tres pestañas (medido:
     0 px de borde/línea en la parte superior). */
  border-bottom: 0;
}

.cabecera-fila {
  max-width: var(--ancho); margin: 0 auto;
  padding: 14px 16px 10px;
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
}

.marca {
  margin: 0; font-size: 20px; font-weight: 650; letter-spacing: -.01em;
  display: flex; align-items: center; gap: 9px;
}
.marca-punto {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--acento); flex: none;
}
.cabecera-nota {
  margin: 0; font-size: 13px; color: var(--texto-3);
}

/* Navegación: la misma <nav> es barra inferior en móvil y superior en PC.
   EL AIRE ES PARTE DEL DISEÑO (2026-10-17): antes las tres pestañas iban pegadas y la activa era un bloque
   entero de un tercio de la barra. Ahora la barra tiene separación entre pestañas y la activa se marca con
   UNA pastilla compacta que viaja (`pestana-indicador`): el control sigue midiendo lo mismo (C2), pero lo
   que se ve respira. */
.pestanas {
  position: relative;
  max-width: var(--ancho); margin: 0 auto;
  display: flex; gap: 8px; padding: 0 10px 10px;
}

.pestana {
  /* 44 px de alto mínimo: WCAG 2.1 SC 2.5.5. */
  position: relative; z-index: 1;
  min-height: 44px;
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 12px;
  border: 1px solid transparent; border-radius: 14px;
  background: transparent; color: var(--texto-2);
  font: inherit; font-size: 14.5px; font-weight: 550;
  cursor: pointer;
  transition: background-color 160ms ease, color 60ms ease, border-color 160ms ease, transform 140ms ease;
}
.pestana:not([aria-current="page"]):hover { background: var(--sup-1); color: var(--texto); }
.pestana:active { transform: scale(.97); }
.pestana[aria-current="page"] { background: transparent; color: var(--acento); border-color: transparent; }
/* El color de la pestaña que se acaba de tocar se enciende YA, sin esperar a que el router termine:
   si una navegación anterior retira `aria-current` un instante, la clase mantiene el amarillo. */
.pestana.yendo { color: var(--acento); }
.pestana svg { width: 21px; height: 21px; flex: none; transition: transform 220ms cubic-bezier(.2,.8,.2,1); }
.pestana[aria-current="page"] svg { transform: translateY(-.5px) scale(1.06); }
.pestana > span { line-height: 1.05; }

/* LA PASTILLA QUE VIAJA. Es decorativa (`aria-hidden`), no recibe toques y no cambia el tamaño de nada.
   Su `transform` lo mueve el JS; aquí solo está su forma. */
.pestana-indicador {
  position: absolute; left: 0; top: 0; z-index: 0;
  pointer-events: none;
  border-radius: 14px;
  background: var(--acento-suave);
  border: 1px solid var(--borde);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .045);
  will-change: transform;
}

/* ------------------------------------------------------------------ principal */

main {
  flex: 1 1 auto; width: 100%; max-width: none; min-height: 0;
  margin: 0; padding: 0; display: flex;
}
main:focus { outline: none; }

.vista { position: relative; --gap-vista: 20px; display: flex; flex-direction: column; gap: var(--gap-vista); }

/* Un hijo de flex o de grid tiene min-width:auto, o sea que un contenido ancho
   (una tabla larga) puede estirar la columna y sacar la página de la pantalla.
   Esto es lo que hace que NADA se salga: el que tiene que desplazarse es la
   caja de la tabla, no la página. */
.vista > *, .rejilla > *, .datos-rejilla > *, .fila-herramientas > * { min-width: 0; }
.tabla-envoltura { max-width: 100%; }

.titulo { margin: 0; font-size: 28px; font-weight: 680; letter-spacing: -.02em; line-height: 1.2; }
.subtitulo { margin: 6px 0 0; color: var(--texto-2); font-size: 15px; }
.seccion-titulo {
  margin: 0; font-size: 13px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase;
  color: var(--texto-3);
}

.tarjeta {
  background: var(--sup-1);
  border: 1px solid var(--borde);
  border-radius: var(--radio-g);
  padding: 18px;
}

.vacio { color: var(--texto-2); }

/* ------------------------------------------------------------------ medidores */

.medidores {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
}

.medidor {
  background: var(--sup-1); border: 1px solid var(--borde);
  border-radius: var(--radio-g); padding: 15px 16px 14px;
  display: flex; flex-direction: column; gap: 9px; min-width: 0;
}
.medidor-cabeza { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.medidor-nombre { font-size: 13px; font-weight: 600; color: var(--texto-2); letter-spacing: .02em; }
.medidor-pct { font-size: 12.5px; color: var(--texto-3); }
.medidor-cifra { display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap; }
.medidor-valor { font-size: 28px; font-weight: 660; letter-spacing: -.02em; line-height: 1; }
.medidor-unidad { font-size: 13px; color: var(--texto-3); }
.medidor-meta { font-size: 12.5px; color: var(--texto-3); }
.medidor-resta { font-size: 13.5px; font-weight: 600; color: var(--texto-2); }
.medidor-resta.pasado { color: var(--texto); }

.barra {
  height: 6px; border-radius: 99px; background: var(--sup-2); overflow: hidden;
}
.barra-relleno {
  height: 100%; border-radius: 99px; background: var(--acento);
  transform-origin: left center;
  /* La interpolación del día la hace transform: scaleX desde el extremo izquierdo. Animar también `width`
     obligaría a layout/paint por frame; aquí el ancho se fija de golpe y se interpola el transform. */
  transition: none;
}

/* ------------------------------------------------------------------ tablas */

.tabla-envoltura {
  /* Las tablas anchas se desplazan AQUÍ dentro; la página nunca se sale. */
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  border: 1px solid var(--borde); border-radius: var(--radio-g);
  background: var(--sup-1);
}
table.datos { width: 100%; border-collapse: collapse; font-size: 14.5px; }
table.datos th, table.datos td { padding: 11px 14px; text-align: left; white-space: nowrap; }
table.datos thead th {
  font-size: 12px; font-weight: 650; letter-spacing: .05em; text-transform: uppercase;
  color: var(--texto-3); border-bottom: 1px solid var(--borde);
}
table.datos tbody tr + tr td { border-top: 1px solid var(--borde); }
table.datos td.num, table.datos th.num { text-align: right; }
table.datos td.texto { white-space: normal; min-width: 200px; max-width: 52ch; }
table.datos tbody tr:hover { background: var(--sup-2); }
table.datos caption { caption-side: top; text-align: left; padding: 14px 14px 0; color: var(--texto-3); font-size: 13px; }

.fila-total td { font-weight: 650; border-top: 1px solid var(--borde-fuerte) !important; }

/* ------------------------------------------------------------------ píldoras y botones */

.insignias { display: flex; flex-wrap: wrap; gap: 6px; }
.insignia {
  font-size: 12px; font-weight: 550; color: var(--texto-2);
  background: var(--sup-2); border: 1px solid var(--borde);
  border-radius: 99px; padding: 3px 10px;
}
.insignia.aviso { color: var(--acento); background: var(--acento-suave); border-color: transparent; }

.boton {
  min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 16px; border-radius: var(--radio);
  background: var(--sup-2); color: var(--texto);
  border: 1px solid var(--borde); font: inherit; font-size: 14.5px; font-weight: 550;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.boton:hover { border-color: var(--borde-fuerte); }
.boton.activo { background: var(--acento-suave); color: var(--acento); border-color: transparent; }

.segmentado { display: flex; gap: 6px; flex-wrap: wrap; }

.campo {
  min-height: 44px; width: 100%;
  padding: 10px 14px; border-radius: var(--radio);
  background: var(--sup-2); border: 1px solid var(--borde);
  color: var(--texto); font: inherit; font-size: 15px;
}
/* El marcador es texto que se lee: sobre el campo (--sup-2) el terciario se queda en 3,79:1, así que sube a
   --texto-2 (5,21:1). C5 no mide marcadores —no son nodos de texto—, pero es la misma regla del terciario. */
.campo::placeholder { color: var(--texto-2); }

.fila-herramientas { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.fila-herramientas .campo { flex: 1 1 240px; width: auto; }

/* ------------------------------------------------------------------ tarjetas de receta */

.rejilla { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(min(100%, 290px), 1fr)); }

.receta-tarjeta {
  display: flex; flex-direction: column; gap: 12px;
  background: var(--sup-1); border: 1px solid var(--borde);
  border-radius: var(--radio-g); padding: 18px;
  color: inherit;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.receta-tarjeta:hover { border-color: var(--borde-fuerte); background: var(--sup-2); text-decoration: none; }
/* Al pasar el ratón la tarjeta sube a --sup-2, y ahí sus textos terciarios (cifras y pie) caerían a 3,79:1:
   el estado también cuenta, aunque C5 mida solo la carga. Suben con la tarjeta a --texto-2 (5,21:1). */
.receta-tarjeta:hover .receta-cifra span,
.receta-tarjeta:hover .receta-pie { color: var(--texto-2); }
.receta-tarjeta h3 { margin: 0; font-size: 17px; font-weight: 640; line-height: 1.3; letter-spacing: -.01em; }
.receta-tarjeta p { margin: 0; font-size: 14px; color: var(--texto-2); }
.receta-tarjeta .descripcion {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.receta-cifras {
  display: flex; gap: 14px; flex-wrap: wrap;
  padding-top: 12px; border-top: 1px solid var(--borde);
}
.receta-cifra { display: flex; flex-direction: column; gap: 1px; }
.receta-cifra b { font-size: 16px; font-weight: 640; }
.receta-cifra span { font-size: 12px; color: var(--texto-3); letter-spacing: .04em; text-transform: uppercase; }
.receta-pie { display: flex; gap: 12px; flex-wrap: wrap; font-size: 13px; color: var(--texto-3); }

/* ------------------------------------------------------------------ ficha de receta */

.encabezado-receta { display: flex; flex-direction: column; gap: 12px; }

.datos-rejilla {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 130px), 1fr));
}
.dato { background: var(--sup-2); border: 1px solid var(--borde); border-radius: var(--radio); padding: 11px 13px; min-width: 0; }
/* `.dato` hoy no lo usa ninguna pantalla (lo dejó atrás el rediseño), pero se deja coherente con la regla del
   terciario: si vuelve, vuelve sin el 3,79:1 dentro. */
.dato dt { font-size: 12px; color: var(--texto-2); letter-spacing: .04em; text-transform: uppercase; margin: 0 0 3px; }
.dato dd { margin: 0; font-size: 16px; font-weight: 600; }
.dato dd small { font-weight: 400; color: var(--texto-2); font-size: 12.5px; }

.pasos { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; counter-reset: paso; }
.paso { display: flex; gap: 14px; align-items: flex-start; }
.paso-numero {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  background: var(--acento-suave); color: var(--acento);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 650;
}
.paso-cuerpo { min-width: 0; }
.paso-titulo { margin: 0; font-size: 17px; font-weight: 620; }
/* TIPOGRAFÍA DE LOS PASOS, SUBIDA CON MEDIDA. Las 12 referencias que se midieron están en 16-18 px
   (moda 18) y aquí estábamos en 14,5. Los pasos son lo que se lee con las manos mojadas, así que es
   donde el tamaño se gana. Cambiar el tamaño cambia contraste y desbordes: por eso se vuelve a pasar
   el verificador entero, no se da por hecho. */
.paso-texto { margin: 4px 0 0; color: var(--texto-2); font-size: 16px; }
.paso-imperativo { margin: 5px 0 0; color: var(--texto); font-size: 16.5px; font-weight: 550; }
.paso .chips { margin-top: 9px; }
.paso-meta { margin: 5px 0 0; font-size: 12.5px; color: var(--texto-3); }

.lista-simple { margin: 0; padding-left: 18px; color: var(--texto-2); font-size: 14.5px; }
.lista-simple li + li { margin-top: 6px; }
.lista-simple b, .lista-simple strong { color: var(--texto); }

/* ------------------------------------------------------------------ markdown */

.md { font-size: 15.5px; overflow-wrap: break-word; }
.md > *:first-child { margin-top: 0; }
.md > *:last-child { margin-bottom: 0; }
.md h1 { font-size: 26px; font-weight: 680; letter-spacing: -.02em; margin: 0 0 16px; line-height: 1.25; }
.md h2 { font-size: 20px; font-weight: 650; letter-spacing: -.01em; margin: 32px 0 12px; padding-top: 16px; border-top: 1px solid var(--borde); }
.md h3 { font-size: 17px; font-weight: 640; margin: 24px 0 8px; }
.md h4 { font-size: 15.5px; font-weight: 640; margin: 20px 0 6px; color: var(--texto-2); }
.md p { margin: 0 0 12px; }
.md ul, .md ol { margin: 0 0 14px; padding-left: 22px; }
.md li { margin-bottom: 5px; }
.md li > ul, .md li > ol { margin-top: 5px; }
.md hr { border: none; border-top: 1px solid var(--borde); margin: 28px 0; }
.md blockquote {
  margin: 0 0 14px; padding: 12px 16px;
  /* SIN FILO DE COLOR A LA IZQUIERDA (cuarta tanda, 2026-10-15 d). El usuario lo dijo con esas palabras:
     «no me gustan los cuadros que en el lado izquierdo tienen el color de acento… a veces veo este diseño
     de cuadro con el lado izquierdo amarillo». El acento de la casa es #d9a15e, un amarillo mostaza: ESE
     era el filo. El cuadro se lee por su FONDO y su BORDE neutros, no por una raya de color. Lo mide C58,
     que falla si vuelve a aparecer uno (en el CSS o pintado). */
  background: var(--sup-1); border: 1px solid var(--borde);
  border-radius: var(--radio); color: var(--texto-2);
}
.md blockquote p:last-child { margin-bottom: 0; }
.md code { background: var(--sup-2); border: 1px solid var(--borde); border-radius: 5px; padding: 1px 5px; font-size: 13.5px; }
.md pre {
  background: var(--sup-1); border: 1px solid var(--borde); border-radius: var(--radio);
  padding: 14px; overflow-x: auto; margin: 0 0 16px; font-size: 13.5px; line-height: 1.5;
}
.md pre code { background: none; border: none; padding: 0; }
.md strong { font-weight: 650; color: var(--texto); }
.md .tabla-envoltura { margin: 0 0 18px; }
.md table { width: 100%; border-collapse: collapse; font-size: 14px; }
.md th, .md td { padding: 9px 12px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--borde); }
.md thead th { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--texto-3); white-space: nowrap; }
.md tbody tr:last-child td { border-bottom: none; }
.md img { max-width: 100%; height: auto; border-radius: var(--radio); }
.md a.enlace-externo::after { content: " ↗"; font-size: 12px; color: var(--texto-3); }

/* ------------------------------------------------------------------ avisos */

.nota {
  /* Sin filo de acento a la izquierda (cuarta tanda): el cuadro se lee por fondo y borde neutros. */
  background: var(--sup-1); border: 1px solid var(--borde);
  border-radius: var(--radio); padding: 13px 16px; font-size: 14px; color: var(--texto-2);
}
.nota b { color: var(--texto); }
.nota code { background: var(--sup-2); border-radius: 4px; padding: 1px 5px; font-size: 13px; }

.cargando { color: var(--texto-3); font-size: 15px; padding: 30px 0; text-align: center; }
.error {
  background: var(--sup-1); border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio); padding: 16px; color: var(--texto);
}
.error h3 { margin: 0 0 6px; font-size: 16px; }
.error p { margin: 0; color: var(--texto-2); font-size: 14.5px; }

.migas { display: flex; gap: 8px; align-items: center; font-size: 13.5px; color: var(--texto-3); flex-wrap: wrap; }
/* Las migas son destinos de navegación, no enlaces dentro de una frase: cumplen los 44 px. */
.migas a {
  color: var(--texto-2); min-height: 44px; display: inline-flex; align-items: center;
  padding: 0 6px; margin: 0 -6px;
}
.migas a:hover { color: var(--acento); }

details.tarjeta > summary {
  min-height: 44px; display: flex; align-items: center; gap: 8px;
  cursor: pointer; font-size: 15px; font-weight: 600; list-style: none;
}
details.tarjeta > summary::-webkit-details-marker { display: none; }
details.tarjeta > summary::after {
  content: "▾"; margin-left: auto; color: var(--texto-3); font-size: 12px;
}
details.tarjeta[open] > summary::after { content: "▴"; }
details.tarjeta[open] > summary { border-bottom: 1px solid var(--borde); padding-bottom: 10px; margin-bottom: 4px; }

.pie {
  border-top: 1px solid var(--borde);
  max-width: var(--ancho); margin: 0 auto; width: 100%;
  padding: 18px 16px 26px;
  display: flex; flex-direction: column; gap: 6px;
  flex: none;
}
/* Si no hay nada que decir, el pie no ocupa alto: el pager se queda con todo el viewport. */
.pie:has(#pie-estado:empty) { display: none; }
.pie-texto { margin: 0; font-size: 12.5px; color: var(--texto-3); line-height: 1.5; }
.pie-estado { margin: 0; font-size: 12.5px; color: var(--texto-3); }

/* ==========================================================================
   Móvil: navegación ABAJO, al alcance del pulgar. Es la misma <nav>.
   ========================================================================== */
@media (max-width: 720px) {
  .cabecera { position: static; backdrop-filter: none; background: var(--fondo); }
  .cabecera-fila { padding-bottom: 12px; }

  .pestanas {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    max-width: none; margin: 0; gap: 6px; padding: 8px 8px calc(8px + env(safe-area-inset-bottom, 0px));
    background: var(--velo);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--borde);
  }
  .pestana {
    flex-direction: column; gap: 3px;
    min-height: 56px; padding: 8px 2px; font-size: 12px; font-weight: 550;
    border-radius: 14px;
  }
  .pestana svg { width: 22px; height: 22px; }

  /* RADIO = MARGEN = EL MISMO NÚMERO. Es una REGLA, no un valor: por eso el margen lateral en móvil
     es 16 px y el radio de tarjeta también (--radio-g: 16px). Si se separan deja de ser una regla y
     hay que acertar cada vez, que es lo que el §7 decidió evitar. */
  /* El padding vive en la PÁGINA (cada panel scrollea), no en main. */
  main { padding: 0; }
  .pagina { padding: 18px 16px calc(var(--nav-alto) + 56px + var(--alto-temporizadores, 0px) + env(safe-area-inset-bottom, 0px)); }
  .pie { padding: 10px 16px calc(var(--nav-alto) + 10px + env(safe-area-inset-bottom, 0px)); }

  .titulo { font-size: 23px; }
  .md h1 { font-size: 22px; }
  .md h2 { font-size: 18px; }
  .tarjeta { padding: 15px; }
  .medidor-valor { font-size: 25px; }
  table.datos th, table.datos td { padding: 10px 12px; }
}

@media (min-width: 721px) {
  /* En PC la navegación vive arriba, junto al título. */
  .pestanas { padding-bottom: 12px; }
  .pestana { flex: 0 0 auto; min-width: 120px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ==========================================================================
   Ficha de receta: la DECISIÓN delante, la JUSTIFICACIÓN plegada.
   ========================================================================== */

.cifras-fila {
  display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap;
  background: var(--sup-1); border: 1px solid var(--borde);
  border-radius: var(--radio-g); padding: 14px 18px;
}
.cifra { display: flex; align-items: baseline; gap: 5px; }
.cifra b { font-size: 24px; font-weight: 660; letter-spacing: -.02em; }
.cifra i { font-style: normal; font-size: 12.5px; color: var(--texto-3); }
.cifras-nota { margin-left: auto; font-size: 12.5px; color: var(--texto-3); }

.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chips-datos { margin-top: -6px; }
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 550; color: var(--texto-2);
  background: var(--sup-2); border: 1px solid var(--borde);
  border-radius: 99px; padding: 5px 11px;
}
.chip svg { width: 15px; height: 15px; flex: none; color: var(--acento); }
.chip b { color: var(--texto); font-weight: 620; }
/* El chip de tiempo es un BOTÓN: 44 px de alto, como todo lo que se pulsa. */
.chip-tiempo {
  min-height: 44px; padding: 10px 14px; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 550;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.chip-tiempo:hover { border-color: var(--borde-fuerte); }
.chip-tiempo.activo { background: var(--acento-suave); color: var(--acento); border-color: transparent; }
/* ESTE FUE EL FALLO DE C5, y lo cazó la medida, no la vista: el chip vive sobre --sup-2, donde --texto-3 da
   3,79:1 y el mínimo de texto normal es 4,5:1. Sube a --texto-2 (5,21:1). Con la paleta vieja daba 4,47:1
   —también por debajo— y con la anterior al rediseño, 4,60:1, que es el número que publicó la verificación v3. */
.chip-accion { color: var(--texto-2); font-size: 12px; }
.chip-flecha { color: var(--texto-2); font-size: 12px; }

/* Lista de ingredientes: una línea por ingrediente. */
.ingredientes { list-style: none; margin: 0; padding: 0; border: 1px solid var(--borde); border-radius: var(--radio-g); background: var(--sup-1); overflow: hidden; }
.ingrediente { display: flex; align-items: center; min-height: 44px; padding: 0 16px; }
.ingrediente + .ingrediente { border-top: 1px solid var(--borde); }
.ingrediente-cantidad { flex: none; width: 76px; font-weight: 620; font-size: 14px; }
.ingrediente-nombre { color: var(--texto-2); font-size: 14.5px; min-width: 0; }

/* LÍQUIDOS: la cantidad es un botón de 44 px que alterna ml ↔ g. El icono dice a qué unidad se cambia
   (peso → gramos, gota → mililitros) y el área táctil cumple el mínimo sin aumentar la fila. */
.ingrediente-cantidad.ingrediente-unidad {
  width: auto; min-width: 76px; min-height: 44px;
  display: flex; align-items: center; gap: 5px;
  padding: 0; margin: 0; border: 0; background: transparent;
  color: var(--texto); font: inherit; font-weight: 620; font-size: 14px;
  text-align: left; cursor: pointer;
}
.ingrediente-unidad svg { width: 16px; height: 16px; color: var(--texto-3); flex: none; }
.ingrediente-unidad:active svg { color: var(--acento); }
.ingrediente > details.mini { width: auto; flex: 1 1 auto; min-width: 0; }
.ingrediente > details.mini > summary { gap: 0; }

/* Plegables pequeños, dentro de una fila o de una lista. */
details.mini { width: 100%; }
details.mini > summary {
  min-height: 44px; display: flex; align-items: center; gap: 10px;
  cursor: pointer; list-style: none;
}
details.mini > summary::-webkit-details-marker { display: none; }
details.mini > summary::after { content: "＋"; margin-left: auto; color: var(--texto-3); font-size: 13px; }
details.mini[open] > summary::after { content: "－"; }
details.mini > p {
  margin: 0 0 12px; padding: 11px 13px; font-size: 13.5px; color: var(--texto-2);
  background: var(--sup-2); border-radius: var(--radio); border: 1px solid var(--borde);
}
details.mini > summary > .ingrediente-nombre { flex: 1 1 auto; }
.pliegue { margin-top: 12px; }
.pie-ficha { margin: 0; font-size: 12.5px; color: var(--texto-3); }

/* ==========================================================================
   Temporizadores: barra flotante, varios a la vez, cada uno con su etiqueta.
   ========================================================================== */

.temporizadores {
  position: fixed; z-index: 40;
  left: 50%; transform: translateX(-50%);
  bottom: calc(var(--nav-alto) + 14px + env(safe-area-inset-bottom, 0px));
  width: min(520px, calc(100vw - 24px));
  display: flex; flex-direction: column; gap: 8px;
  max-height: 46dvh; overflow-y: auto;
}
.temporizador {
  background: var(--sup-2); border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio-g); padding: 11px 14px;
}
/* SEXTA TANDA (punto 10) · AL ACABAR, EL TEMPORIZADOR NO PIERDE OPACIDAD. El usuario: «cuando este acaba no
   debería perder opacidad, debería mantenerse opaco». El fondo de «terminado» era `--acento-suave`, que es un
   rgba con un 14 % de alfa: el acento se veía a través y la pastilla parecía apagada. Ahora es una superficie
   sólida (`--sup-1`) con el borde de acento, y la cuenta en acento: se ve «terminado» por el color y el
   `+X:XX`, no por estar desvaído (medido: opacidad 1 y fondo sin alfa). */
.temporizador.terminado { border-color: var(--acento); background: var(--sup-1); }
.temporizador-cabeza { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.temporizador-etiqueta { font-size: 12.5px; color: var(--texto-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.temporizador-cuenta { font-size: 20px; font-weight: 660; letter-spacing: -.01em; flex: none; }
.temporizador.terminado .temporizador-cuenta { color: var(--acento); }
.temporizador-barra { height: 4px; border-radius: 99px; background: var(--sup-1); overflow: hidden; margin: 8px 0 10px; }
.temporizador-barra span { display: block; height: 100%; background: var(--acento); transition: width 250ms linear; }
.temporizador-botones { display: flex; gap: 8px; }
.temporizador-boton {
  min-height: 44px; flex: 1 1 0; padding: 10px 12px;
  /* OCTAVA TANDA (punto 3) · EL ICONO Y EL TEXTO, CENTRADOS Y CON SU SEPARACIÓN. «Reiniciar» llevaba el
     icono pegado a la palabra (iba en línea, sin `gap`, y el SVG se alineaba con la línea base del texto, así
     que además quedaba descentrado). Con `inline-flex` + `align-items: center` + `gap`, el icono y el texto
     comparten centro vertical y hay aire entre ellos, igual que en la pastilla del chip (7 px). */
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--sup-1); color: var(--texto-2); border: 1px solid var(--borde);
  border-radius: var(--radio); font: inherit; font-size: 13px; font-weight: 550; cursor: pointer;
}
.temporizador-boton svg { width: 15px; height: 15px; flex: none; }
.temporizador-boton:hover { border-color: var(--borde-fuerte); color: var(--texto); }

@media (min-width: 721px) {
  .temporizadores { bottom: 18px; }
}

/* Secciones plegables de un documento largo (compilado, listas, expediente).
   Los .md de este repositorio son el EXPEDIENTE: cada decisión con su porqué. Aquí se enseña
   la cabecera y la primera sección, y lo demás queda plegado pero a un toque. */
details.seccion-md { border-top: 1px solid var(--borde); margin-top: 20px; padding-top: 4px; }
details.seccion-md > summary {
  min-height: 44px; display: flex; align-items: center; gap: 8px;
  cursor: pointer; list-style: none;
}
details.seccion-md > summary::-webkit-details-marker { display: none; }
details.seccion-md > summary::after { content: "＋"; margin-left: auto; color: var(--texto-3); font-size: 13px; flex: none; }
details.seccion-md[open] > summary::after { content: "－"; }
.seccion-md-titulo { font-size: 20px; font-weight: 650; letter-spacing: -.01em; }
.seccion-md-cuerpo { padding-top: 6px; }

/* ==========================================================================
   Apuntes del día: FILAS, no tabla.
   Una tabla de siete columnas no cabe en 320 px y obligaba a arrastrarla de lado, y eso el usuario
   lo rechaza. Cada entrada es una fila de dos líneas: el dato que se mira (kcal) a la derecha y
   grande, y el qué debajo. Los importes comparten borde derecho, que es lo que hace legible una
   lista de cifras. Sin desplazamiento horizontal: o cabe, o no es una fila.
   ========================================================================== */

.apuntes { list-style: none; margin: 0; padding: 0; }
/* CERO SEPARADORES entre las filas de un mismo bloque. Medido en Revolut: 5 filas = 5 × 198 px
   exactos, sin padding vertical y sin una sola línea entre ellas. La división la hace el ESPACIO.
   (Antes llevaban `border-top`: era exactamente la muleta que el §7 manda quitar.) */
.apunte { padding: 15px 0; }
.apunte:first-child { padding-top: 4px; }
.apunte:last-child { padding-bottom: 4px; }
.apunte-fila { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; }
.apunte-fila + .apunte-fila { margin-top: 5px; }
.apunte-momento { font-size: 13px; color: var(--texto-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.apunte-kcal { flex: none; font-size: 22px; font-weight: 660; letter-spacing: -.02em; }
.apunte-kcal i { font-style: normal; font-size: 12px; font-weight: 500; color: var(--texto-3); margin-left: 4px; }
.apunte-secundaria { align-items: flex-start; }
.apunte-que { font-size: 15px; color: var(--texto); min-width: 0; flex: 1 1 auto; }
.apunte-que a { color: var(--texto); text-decoration: underline; text-decoration-color: var(--borde-fuerte); text-underline-offset: 3px; }
.apunte-macros { flex: none; text-align: right; font-size: 12.5px; color: var(--texto-3); }

/* BORRAR UNA ENTRADA (2026-10-30). La papelera va a la derecha de las kcal, con 44 px de área de toque y
   sin rojo hasta que se toca: treinta papeleras rojas en una lista no informan de nada. El primer toque
   cambia la fila por la confirmación (dentro de la propia fila, sin diálogo del navegador). */
/* La papelera va en la SEGUNDA línea (a la derecha de las macros), no en la primera: en la primera forma
   grupo de botones con el lápiz y el grupo dejaba de estar centrado (C72), y además competía con las kcal. */
.apunte-borrar {
  flex: none; width: 44px; height: 44px; margin: -12px -10px -12px 0;
  display: grid; place-items: center; align-self: center;
  border: 0; border-radius: 12px; background: transparent; color: var(--texto-3);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color 140ms ease, color 140ms ease;
}
.apunte-borrar svg { width: 17px; height: 17px; }
.apunte-borrar:hover, .apunte-borrar:focus-visible { color: var(--peligro); background: var(--sup-2); }
.apunte.confirmando { padding: 10px 12px; border-radius: 12px; background: var(--sup-2); }
.apunte.confirmando > :not(.apunte-confirmar) { display: none; }
.apunte-confirmar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.apunte-confirmar > span { flex: 1 1 auto; min-width: 0; font-size: 14px; color: var(--texto); }
.apunte-confirmar .boton { min-height: 44px; padding: 8px 14px; font-size: 13.5px; }
.apunte-confirmar-si { color: var(--peligro); border-color: var(--peligro); }
.apunte-confirmar-error { flex-basis: 100%; margin: 0; color: var(--peligro); font-size: 13px; }
.apunte-total { border-top: 1px solid var(--borde-fuerte); }
.apunte-total .apunte-kcal { color: var(--acento); }

/* En móvil, los macros de la segunda línea bajan debajo del qué: a 320 px no caben los dos. */
@media (max-width: 480px) {
  .apunte-secundaria { flex-direction: column; gap: 3px; }
  .apunte-macros { text-align: left; }
}

/* TABLAS DEL EXPEDIENTE: APILADAS POR DEFECTO, en TODOS los anchos.
   Las tablas de los .md son de 7 columnas A PROPÓSITO —para comparar una fila contra un fichero— y
   por eso NO se tocan en el documento. Pero esa capacidad no puede costarle a quien solo quiere leer
   la receta: por defecto son tarjetas (cero desplazamiento horizontal, sin excepciones) y en pantalla
   ancha hay un conmutador «Tabla» que las enseña de verdad. Las dos cosas, sin pagar ninguna.
   El corte a ojo falló dos veces (640 dejaba el fallo a 768; 900 lo dejaba a 1280): por eso ya no hay
   corte, se apila siempre y la tabla es lo que se pide a propósito. */
.md .tabla-envoltura { overflow-x: visible; border: none; background: none; }
.md table, .md thead, .md tbody, .md tr, .md th, .md td { display: block; width: auto; }
.md thead { display: none; }
.md tr { padding: 12px 0; }
.md tr + tr { margin-top: 10px; }
.md td { border-bottom: none; padding: 3px 0; text-align: left !important; }
.md td::before {
  content: attr(data-col);
  display: block; font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--texto-3); margin-bottom: 2px;
}
.md td:empty { display: none; }

/* El conmutador solo se enseña donde hay sitio para la tabla de verdad. Si no cabe, no está: un
   botón que no hace nada sería decorativo, y eso es peor que no tenerlo. */
.solo-ancho { display: none; }
@media (min-width: 901px) {
  .solo-ancho { display: flex; }
  .md.como-tabla .tabla-envoltura {
    overflow-x: auto; border: 1px solid var(--borde);
    background: var(--sup-1); border-radius: var(--radio-g);
  }
  .md.como-tabla table { display: table; width: 100%; border-collapse: collapse; }
  .md.como-tabla thead { display: table-header-group; }
  .md.como-tabla tbody { display: table-row-group; }
  .md.como-tabla tr { display: table-row; padding: 0; margin: 0; }
  .md.como-tabla th, .md.como-tabla td {
    display: table-cell; padding: 9px 12px; text-align: left;
    border-bottom: 1px solid var(--borde); vertical-align: top;
  }
  .md.como-tabla th { font-size: 12px; text-transform: uppercase; letter-spacing: .05em; color: var(--texto-3); white-space: nowrap; }
  .md.como-tabla td::before { content: none; }
}

/* ==========================================================================
   SIN BORDES EN LAS TARJETAS · decisión del 2026-10-14 (docs/webapp-diseno.md §7)
   El borde de 1 px es una muleta para cuando el espaciado no basta. Se quita de los CONTENEDORES y
   la jerarquía queda en el escalón de superficie, el espaciado y el color del texto.
   SE CONSERVAN las líneas que separan ELEMENTOS DE UNA LISTA (filas de un mismo bloque), porque ahí
   expresan una división real y no el contorno de una caja.
   Y se conservan en los CONTROLES: el contorno de un campo o un botón dice dónde se escribe o se
   pulsa; quitarlo ahí sería quitar información, no decoración.
   Si al quitar un borde algo se deshace, es información: falta espaciado o falta jerarquía.
   ========================================================================== */
.tarjeta, .medidor, .receta-tarjeta, .cifras-fila, .ingredientes, .apuntes,
.tabla-envoltura, .dato, .temporizador, details.mini > p {
  border: none;
}

/* ESTADOS: vacío, carga y error · criterio PROPIO, sin referencia que imitar.
   En 291 capturas de Revolut no apareció ninguno de los tres, así que no se copian: se diseñan. */
.esqueleto { display: flex; flex-direction: column; gap: 20px; }
.esqueleto-titulo { height: 34px; width: 58%; background: var(--sup-1); border-radius: var(--radio); }
.esqueleto-linea { height: 16px; width: 82%; background: var(--sup-1); border-radius: var(--radio); }
.esqueleto-rejilla {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
}
.esqueleto-tarjeta { height: 96px; background: var(--sup-1); border-radius: var(--radio-g); }
.esqueleto-alta { height: 200px; }
/* El latido SOLO si el sistema no ha pedido menos movimiento. */
@media (prefers-reduced-motion: no-preference) {
  .esqueleto-titulo, .esqueleto-linea, .esqueleto-tarjeta { animation: latido 1.5s ease-in-out infinite; }
}
@keyframes latido { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

.error { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.error h3 { margin: 0; font-size: 17px; }
.error p { margin: 0; color: var(--texto-2); font-size: 15px; }
.error-que-hacer { font-size: 13.5px; color: var(--texto-3); }
.error .boton { margin-top: 4px; }

/* ==========================================================================
   REDISEÑO MÓVIL · 2026-10-14 (encargo del usuario, punto por punto)
   Menos texto y más medida: lo que se consulta con las manos mojadas.
   Reglas que NO se rompen aquí: un solo acento, nada por debajo de 12 px,
   todo lo que se pulsa ≥ 44 px y contraste ≥ 4,5:1 (lo miden C5/C10/C2b).
   ========================================================================== */

/* El buscador se queda arriba al hacer scroll: es lo primero que se usa. */
.buscador-fijo {
  position: sticky; top: 0; z-index: 15;
  /* OCTAVA TANDA (puntos 1 y 4) · EL HUECO DE ABAJO, EL MISMO QUE EL DE ARRIBA DEL FILTRO (8 px). El `.vista`
     pone 20 px de `gap` entre la cabecera y la rejilla; con los 10 px de `padding-bottom` y los 6 de margen el
     hueco visible eran 36 px y el usuario lo vio «demasiado grande» en las dos pestañas. Se queda en
     20 − 12 = 8, que es exactamente el `margin-top` de `.filtros`: el hueco entre el buscador y los filtros,
     que es el que él puso de referencia. */
  margin: 0 -16px -8px; padding: 10px 16px 8px;
  background: var(--velo); backdrop-filter: blur(8px);
  /* SÉPTIMA TANDA (punto 4) · FUERA LA LÍNEA GRIS de debajo del buscador pegajoso: el fondo de la cabecera ya
     llega a los bordes (la capa fija) y este filo de 1 px sobraba. */
  border-bottom: 0;
  /* OCTAVA TANDA (punto 6) · LA FRANJA SE OCULTA AL BAJAR Y VUELVE AL SUBIR, con transición. La capa que pinta
     el fondo es su `::before` (`position: fixed`): al transformar la cabecera, esa capa pasa a colgar de ella
     —un ancestro con `transform` es el bloque contenedor de sus `fixed`—, así que se van las dos juntas y no
     queda un borde pintado en el sitio de antes. `prefers-reduced-motion: reduce` ya apaga TODAS las
     transiciones de la app con la regla global de más arriba, así que el respeto está garantizado y medido. */
  transition: transform 240ms cubic-bezier(.2,.7,.2,1);
}
.buscador-fijo.oculta { transform: translateY(-100%); }

/* Medidores compactos: la cifra manda; la barra mide el impacto de un vistazo. */
.medidor { padding: 12px 13px 11px; gap: 7px; }
.medidor-valor { font-size: 26px; }
.medidor-linea { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.barra { height: 8px; }

/* Impacto de cada entrada en el día, en barras (no solo números). */
.impacto-fila { display: flex; align-items: center; gap: 7px; margin-top: 6px; }
.impacto-etiqueta { flex: none; width: 2.4em; font-size: 12px; color: var(--texto-3); }
.impacto { flex: 1 1 0; min-width: 0; height: 7px; border-radius: 99px; background: var(--macro-pista); overflow: hidden; display: flex; }
/* DOS TRAMOS, Y CON ALTO GARANTIZADO. El gris es lo que ya llevabas del día y el color lo que aporta esta
   entrada, igual que en la barra de una receta (`.receta-macro`).
   ESTE FUE EL FALLO QUE EL USUARIO VIO EL 2026-10-15 («faltan ver las barras por entrada») y que ninguna
   medida cazó: las barras ESTABAN en el DOM, con su gris, su color y sus anchos correctos, pero medían
   **0 px de alto**. La barra era hija de `.impacto-celda`, que es una columna `flex`; con `flex: 1 1 0`, en
   una columna el `flex-basis: 0` manda sobre el `height` y el relleno se quedaba en 0. Los anchos seguían
   midiéndose bien, así que un criterio que solo mirara anchos habría dado PASA. Ahora el relleno va
   POSICIONADO (`top: 0; bottom: 0`) y el alto no depende de ningún reparto de flex: C54 mide el alto
   pintado, además del ancho. */
.impacto { position: relative; flex: none; height: 7px; border-radius: 99px; background: var(--macro-pista); overflow: hidden; }
.impacto span { position: absolute; top: 0; bottom: 0; border-radius: 99px; display: block; }
.impacto .impacto-previo { left: 0; background: var(--macro-gris); }
.impacto .impacto-aporta { background: var(--macro, var(--acento)); }
/* El exceso del día, en BLANCO y entre paréntesis, junto al porcentaje (séptima tanda, punto 1). */
.impacto-exceso { color: var(--texto); font-weight: 550; }
/* Y EL NÚMERO, EN UNA LÍNEA (octava tanda). El valor es «+57 % (+9 %)»: un texto corto —cifra con su unidad—
   que a 320 px se partía en dos líneas dentro de su caja de 67 px. Lo cazó C67, no la vista. */
.impacto-valor { flex: none; min-width: 3.6em; text-align: right; font-size: 12px; color: var(--texto-2); white-space: nowrap; }
/* A 320 px las CUATRO celdas del impacto miden 67 px cada una y el número con su exceso —«+1 % (+22 %)»—
   necesita ~75: con `nowrap` se salía de la tarjeta y lo recortaba el `overflow-x: clip` de `.ventana`. Lo
   vio la CAPTURA, no C6 —el recorte no desborda la página, así que `scrollWidth == clientWidth` seguía
   cumpliéndose—. En vez de bajar la letra por debajo de los 12 px (regla de la casa), a ≤ 360 px las cuatro
   celdas se reparten en DOS filas de dos: cada una mide ~140 px y el número entra entero. */
@media (max-width: 360px) {
  .impacto-fila { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
}
.impacto-celda { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 3px; }

/* En PC la cabecera se queda pegada arriba: el buscador se pega justo debajo. */
@media (min-width: 721px) { .buscador-fijo { top: 60px; } }
/* Y en PC, oculta, tiene que salir por ARRIBA del todo: con `top: 60px` un `-100 %` la dejaría asomando
   60 px por debajo del borde. Se sube su alto MÁS esos 60 px. */
@media (min-width: 721px) { .buscador-fijo.oculta { transform: translateY(calc(-100% - 60px)); } }

/* El total de la ficha para las raciones elegidas. Cada cifra con su unidad y su letra de macro es UN texto
   corto: `white-space: nowrap` evita que a 320 px se parta por la mitad («26 g» arriba y «G» abajo, que es
   como estaba). El párrafo sigue partiendo por los separadores « · », que es donde toca. Lo mide C67. */
.cifras-total { margin: 0; font-size: 13.5px; color: var(--texto-2); }
.cifras-total b { color: var(--texto); white-space: nowrap; }

/* Lista de recetas: fuera descripción y etiquetas; dentro, las cifras. */
.receta-tarjeta { gap: 10px; padding: 16px; }
.receta-macros { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.receta-macro b { display: block; font-size: 19px; font-weight: 660; letter-spacing: -.01em; }
.receta-macro span { display: block; font-size: 12px; color: var(--texto-3); }
.receta-datos { display: flex; gap: 12px; flex-wrap: wrap; font-size: 13.5px; color: var(--texto-2); }
.receta-datos b { color: var(--texto); font-weight: 640; }

/* Raciones: − y +, que recalculan cantidades, macros y la lista de la compra. */
.raciones { display: flex; align-items: center; gap: 6px; }
.raciones .boton { min-width: 44px; padding: 10px; font-size: 18px; font-weight: 660; }
.raciones-num { min-width: 4.5em; text-align: center; font-size: 15px; font-weight: 620; }
.raciones-num small { display: block; font-size: 12px; font-weight: 400; color: var(--texto-3); }

/* Pasos: iconos con su número, y la flecha cuando hay cambio. */
.chip b { font-variant-numeric: tabular-nums; }
.chip-tiempo.activo { background: var(--acento-suave); color: var(--acento); border-color: transparent; }
.chip-tiempo.activo .chip-accion { color: var(--acento); }

/* Checklist de la compra: producto · cantidad · precio, por secciones. */
.check { list-style: none; margin: 0; padding: 0; }
.check li { display: flex; align-items: flex-start; gap: 10px; min-height: 44px; padding: 9px 0; border-top: 1px solid var(--borde); }
.check li:first-child { border-top: none; }
.check input { flex: none; width: 44px; height: 44px; margin: 0; accent-color: var(--acento); }
.check-cuerpo { flex: 1 1 auto; min-width: 0; padding: 11px 0; }
.check-nombre { font-size: 14.5px; overflow-wrap: anywhere; }
.check-cant { display: block; font-size: 13px; color: var(--texto-2); overflow-wrap: anywhere; }
/* El precio CORTO no se parte nunca («4,90 €» en una línea: partirlo se leyó fatal en la captura del
   2026-10-14). El LARGO —el de la tabla de «lo que NO hay que comprar»— sí puede partirse, o estira la
   fila y saca la página de la pantalla (lo mide C6). */
.check-precio { flex: 0 0 auto; white-space: nowrap; text-align: right; font-size: 14.5px; font-weight: 620; }
.check-precio.largo { flex: 0 1 auto; min-width: 0; max-width: 55%; white-space: normal; overflow-wrap: anywhere; }
.check li.marcado .check-nombre { text-decoration: line-through; color: var(--texto-3); }

/* El lápiz de la hora. Deshabilitado mientras `registro.mjs editar` no exista. */
.lapiz {
  min-height: 44px; display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; padding: 0 6px;
  color: var(--texto-3); font: inherit; font-size: 13px; cursor: pointer;
}
.lapiz:disabled { cursor: not-allowed; opacity: .55; }
.lapiz svg { width: 17px; height: 17px; }

/* ==========================================================================
   PULIDO FINAL · 2026-10-15 (los cinco cosméticos del último ciclo)
   Van como SOBRESCRITURAS al final a propósito: así se lee de un tirón qué se
   cambió y por qué, sin tocar las reglas que ya estaban medidas.
   ========================================================================== */

/* 1 · El nombre de una receta, como mucho DOS líneas: tres empujaban la tarjeta y desalineaban las
   cifras respecto a las de al lado. Con el mínimo de dos líneas, todas las tarjetas casan. */
.receta-tarjeta h3 {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  min-height: 2.6em;
}

/* 2 · Las cuatro cifras de la ficha, en UNA fila a 390 px: eran cinco bloques en flex y el cuarto
   caía a una segunda línea. Ahora es una rejilla de cuatro columnas y «por ración» pasa a pie. */
.cifras-fila { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px 8px; align-items: baseline; }
.cifra b { font-size: 21px; }
.cifras-nota { grid-column: 1 / -1; font-size: 12px; }

/* 3 · Las filas de ingrediente no crecen por un nombre largo: dos líneas y puntos suspensivos. */
.ingrediente-nombre { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* 4 · El precio largo de «lo que NO hay que comprar» se parte en espacios (tres líneas ordenadas),
   no a mitad de palabra: `break-word` en vez de `anywhere`. */
.check-precio.largo { overflow-wrap: break-word; }

/* 5 · El baile de la tarjeta: el tiempo largo empujaba el coste a otra línea. Ahora la fila de datos
   es una rejilla fija —raciones a la izquierda, coste a la derecha y el TIEMPO en su propia línea—
   así que todas las tarjetas se leen igual, con tiempo corto o largo. */
.receta-datos { display: grid; grid-template-columns: auto auto; align-items: baseline; gap: 2px 12px; }
.receta-datos > span:nth-child(1) { grid-area: 1 / 1; }
.receta-datos > span:nth-child(2) { grid-area: 2 / 1 / 3 / 3; }
.receta-datos > span:nth-child(3) { grid-area: 1 / 2; justify-self: end; }

/* ==========================================================================
   FEEDBACK DEL USUARIO · 2026-10-15 · los 21 puntos de la app
   Un bloque por punto, para poder leerlo de un tirón. Va al final como
   SOBRESCRITURA a propósito: no se tocan las reglas que ya estaban medidas.
   Reglas que NO se rompen: un solo acento de marca, nada por debajo de 12 px,
   todo lo que se pulsa ≥ 44 px y contraste ≥ 4,5:1 (los miden C2/C5/C10).
   ========================================================================== */

/* PUNTO 1 · «en todas las pestañas en la parte inferior se puede ver una línea gris que sobra».
   Era el `border-top` de la barra de navegación: el velo de fondo ya la separa del contenido, así que
   la línea no informaba de nada. Fuera en móvil y en PC. */
.pestanas { border-top: none; }

/* PUNTO 5 y 17 · «la barra de búsqueda a veces se despega de la parte superior, sobre todo cuando
   subimos arriba del todo». Medido: a 19 px del borde con el scroll arriba (era el `padding-top` de
   `main`, que en móvil no lo tapa ninguna cabecera porque la nav es fija abajo) y a 0 al bajar → el
   salto que él ve. El arreglo es QUITAR EL DESFASE con un margen negativo igual al padding, no bajar
   el `top`: con `top: -18px` la barra se metía 18 px por debajo del borde. En PC, lo mismo con los
   20 px del `main` y los 60 de la cabecera pegada. */
.buscador-fijo { top: 0; margin-top: -18px; }
@media (min-width: 721px) { .buscador-fijo { top: 60px; margin-top: -20px; } }

/* PUNTO 3 · CADA MACRO CON SU COLOR. Cuatro colores, uno por macro, y el MISMO en las tres pantallas
   donde una macro se mide (los medidores de Hoy, el impacto de cada entrada y las barras de las
   tarjetas): si el color de la proteína cambia, cambia en las tres porque sale de aquí. El color NUNCA
   se usa para texto: las etiquetas siguen en --texto-2/--texto-3, que son las que pasan el contraste
   medido (C5). El color es de la BARRA, que es información gráfica.
   El gris es «lo que ya llevas comido»; el color, «lo que aporta esta receta». */
:root {
  /* LOS CUATRO HEX ESTÁN MEDIDOS, no elegidos a ojo: son los de MacroFactor, sacados contando píxeles
     saturados de sus capturas (ver `docs/webapp-referencias-macrofactor.md` §3): Energía #5A95F9,
     Proteína #FF8660, Grasa #FFC447, Carbohidratos #4CB179. Los cuatro salen idénticos en las tres
     pantallas donde se miden, y el usuario pidió las barras «al igual que en MacroFactor».
     Se copian los CUATRO colores y se copia su regla: **el color va en la barra, nunca en el texto** (las
     etiquetas siguen en los grises que pasan el contraste medido, C5). Un solo color de acento de marca
     (`--acento`) sigue mandando en lo demás. */
  --macro-kcal: #5a95f9;
  --macro-proteinas: #ff8660;
  --macro-grasas: #ffc447;
  --macro-carbohidratos: #4cb179;
  --macro-gris: rgba(255, 255, 255, .24);
  --macro-pista: #2b2e35;
}
@media (prefers-color-scheme: light) {
  :root {
    /* EL TEMA CLARO QUEDA FUERA DE ALCANCE, por decisión del usuario del 2026-10-15 («queremos ahorrarnos
       el tema claro de momento»). Se dejan los MISMOS hex de MacroFactor, que están medidos sobre SU fondo
       blanco `#FFFFFF`; sobre nuestro `#f7f7f5` los cuatro bajan del 3:1 de WCAG 1.4.11 (medido por el
       verificador: Energía 2,76 · Proteína 2,22 · Grasa 1,48 · HC 2,49) y **hoy ningún criterio lo cubre a
       propósito**: es un límite declarado, no un fallo escondido. Ver `docs/webapp-criterios.md`. */
    --macro-kcal: #5a95f9;
    --macro-proteinas: #ff8660;
    --macro-grasas: #ffc447;
    --macro-carbohidratos: #4cb179;
    --macro-gris: rgba(0, 0, 0, .22);
    --macro-pista: #e4e3df;
  }
}
.macro--kcal { --macro: var(--macro-kcal); }
.macro--proteinas { --macro: var(--macro-proteinas); }
.macro--grasas { --macro: var(--macro-grasas); }
.macro--carbohidratos { --macro: var(--macro-carbohidratos); }
.medidor .barra-relleno { background: var(--macro, var(--acento)); }

/* PUNTO 12 · LAS RACIONES, CENTRADAS Y APROVECHANDO LA LÍNEA (antes iban pegadas a la izquierda, con
   todo el hueco a la derecha). PUNTO 13 · y sin el botón de «volver a la ración de la receta»: ya no
   se pinta en `app.js`, así que no hay nada que esconder aquí. */
.raciones { justify-content: center; gap: 10px; }
.raciones-num { min-width: 5.5em; }

/* PUNTO 14 · LOS ICONOS DEL PASO, PRIMERO Y CENTRADOS. El paso deja de ser una fila con el número a la
   izquierda y pasa a ser una columna: arriba la fila de iconos —que se reparte sola en una o dos líneas
   y queda centrada—, debajo el título con su número y el texto. El texto NO se centra: la prosa larga
   se lee peor centrada, y el usuario pidió centrar los ICONOS.
   Y LO QUE SE VIO EN LA CAPTURA DEL CICLO 1, que es la parte que no se veía en el código: con los iconos
   arriba y sin separación entre pasos, la fila de iconos del paso 2 quedaba PEGADA al párrafo del paso 1
   y se leía como si fuera suya. Se arregla con PROXIMIDAD, que es la herramienta correcta: dentro del
   paso todo va junto (6 px) y entre pasos hay 22 px de aire más una línea fina que es una división de
   verdad —dos pasos distintos—, no el contorno de una caja. */
.paso { flex-direction: column; align-items: stretch; gap: 6px; }
.paso + .paso { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--borde); }
.paso .chips { justify-content: center; margin: 0; }
.paso-titulo { display: flex; align-items: baseline; gap: 9px; }
.paso .chip { background: var(--sup-2); }

/* PUNTO 6 · EL TIEMPO Y EL PRECIO CON SU ICONO (reloj y monedas), que es como se leen de un vistazo. */
.receta-dato { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.receta-dato svg { width: 16px; height: 16px; flex: none; color: var(--texto-3); }

/* PUNTO 8 · LAS MACROS, COMO BARRA CONTRA EL DÍA. Cada macro lleva su cifra y debajo una barra cuyo
   TOTAL es el objetivo diario: en gris lo que ya se ha comido hoy y en color lo que aporta la ración.
   Dos columnas en vez de cuatro: con cuatro, a 320 px cada barra mide 60 px y no dice nada. */
.receta-macros { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px; }
.receta-macro { display: grid; gap: 5px; min-width: 0; }
.receta-macro .receta-macro-cifra { display: flex; align-items: baseline; gap: 3px; min-width: 0; }
.receta-macro .receta-macro-cifra b { font-size: 19px; font-weight: 660; letter-spacing: -.01em; }
.receta-macro .receta-macro-cifra span { font-size: 12px; color: var(--texto-3); }
.receta-macro .macro-pista { display: flex; height: 6px; border-radius: 99px; background: var(--macro-pista); overflow: hidden; }
.receta-macro .macro-pista > span { display: block; height: 100%; }
.receta-macro .macro-ya { background: var(--macro-gris); }
.receta-macro .macro-esta { background: var(--macro, var(--acento)); }

/* La leyenda de las barras: dos cuadraditos que explican el gris y el color. Una línea, arriba.
   Los cuadraditos NO llevan texto dentro a propósito: un texto sobre el gris de la muestra no llega al
   4,5:1 que exige C5 (daba 3,01:1 en oscuro y 3,73:1 en claro). Las palabras van fuera. */
.leyenda-barras { margin: 0; }
.leyenda-gris, .leyenda-color { display: inline-block; width: 14px; height: 8px; border-radius: 99px; vertical-align: middle; margin-right: 4px; }

/* A 320 px las cuatro cifras de la ficha no caben en una línea y la unidad («g P», «g HC») se partía
   sola DEBAJO del número, cada una a una altura distinta: se veía en la captura del ciclo 2 a 320 px y
   parecía un descuido. Aquí se apila A PROPÓSITO —número arriba, unidad debajo, las cuatro iguales—, que
   es lo que se lee bien cuando no hay ancho. */
@media (max-width: 360px) {
  .cifras-fila { gap: 2px 6px; }
  .cifra { flex-direction: column; align-items: flex-start; gap: 0; }
  .cifra b { font-size: 21px; }
  .cifra i { margin-top: -1px; }
}
.leyenda-gris { background: var(--macro-gris); }
.leyenda-color { background: linear-gradient(90deg, var(--macro-kcal), var(--macro-proteinas), var(--macro-grasas), var(--macro-carbohidratos)); }

/* PUNTO 19 · LAS CASILLAS, MÁS PEQUEÑAS Y MEJOR DIBUJADAS. La casilla nativa se cambia por una caja de
   22 px con su tick; el CONTROL sigue midiendo toda la fila (el `input` es transparente y la cubre
   entera), así que el objetivo táctil de 44 px no se toca: lo que se pulsa es la fila, lo que se ve es
   la caja pequeña. */
.check li { position: relative; display: block; padding: 0; min-height: 52px; }
.check .check-input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.check-cuerpo {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center;
  gap: 2px 10px; min-height: 52px; padding: 9px 2px; cursor: pointer;
}
.check-caja {
  grid-row: 1 / 5; width: 22px; height: 22px; border-radius: 7px;
  border: 1.5px solid var(--borde-fuerte); background: var(--sup-2);
  display: flex; align-items: center; justify-content: center; transition: background 120ms, border-color 120ms;
}
.check-caja svg { width: 14px; height: 14px; opacity: 0; color: var(--fondo); }
.check-input:checked ~ .check-cuerpo .check-caja { background: var(--acento); border-color: var(--acento); }
.check-input:checked ~ .check-cuerpo .check-caja svg { opacity: 1; }
.check-nombre { grid-column: 2; font-size: 14.5px; overflow-wrap: anywhere; }
.check-cant { grid-column: 2; grid-row: 2; font-size: 12.5px; color: var(--texto-3); }
.check-precio { grid-column: 3; grid-row: 1 / 5; align-self: center; }
.check-resumen {
  display: flex; flex-wrap: wrap; gap: 4px 20px; margin: 12px 0 0; padding-top: 11px;
  border-top: 1px solid var(--borde-fuerte); font-size: 13.5px; color: var(--texto-2);
}
.check-resumen-etiqueta { color: var(--texto-3); margin-right: 6px; }
.check-resumen b { color: var(--texto); font-size: 15px; }

/* PUNTO 21 · «LO QUE NO HAY QUE COMPRAR (Y POR QUÉ)» NO ES UNA CHECKLIST: enseña el porqué de cada
   descarte, y no se marca nada porque no se compra. */
.descartes { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.descartes li { padding-left: 12px; border-left: 2px solid var(--borde-fuerte); }
.descarte-que { display: block; font-size: 14.5px; font-weight: 620; }
.descarte-porque { display: block; margin-top: 4px; font-size: 13.5px; color: var(--texto-2); }

/* PUNTO 21 · Y EL DESEMBOLSO FRENTE AL COSTE, como cifras (concepto → importe), no como filas que se
   marcan. */
.cifras-lista { margin: 0; display: grid; }
.cifras-lista > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 10px 0; border-top: 1px solid var(--borde);
}
.cifras-lista > div:first-child { border-top: none; }
.cifras-lista dt { margin: 0; font-size: 13.5px; color: var(--texto-2); }
.cifras-lista dd { margin: 0; font-size: 16px; font-weight: 650; white-space: nowrap; }

/* PUNTO 20 · La cuenta de la sección, junto a su título: «7» productos, «6» descartes. */
.seccion-cuenta { margin-left: 8px; font-size: 12.5px; color: var(--texto-3); font-weight: 500; }

/* PUNTO 2 · EL EDITOR DE LA HORA (el lápiz, que ya funciona). */
.lapiz { color: var(--texto-2); }
.lapiz:hover { color: var(--acento); }
.lapiz svg { color: var(--texto-3); }
.lapiz:hover svg { color: var(--acento); }
.editor-hora {
  display: grid; gap: 10px; margin-top: 12px; padding: 12px;
  background: var(--sup-2); border-radius: var(--radio); border: 1px solid var(--borde);
}
.editor-hora-campo { display: grid; gap: 6px; }
.editor-hora-etiqueta { font-size: 12.5px; color: var(--texto-2); }
.editor-hora-botones { display: flex; flex-wrap: wrap; gap: 8px; }
.editor-hora-botones .boton { display: inline-flex; align-items: center; gap: 6px; }
.editor-hora-botones svg { width: 16px; height: 16px; }
.editor-hora-error {
  margin: 0; padding: 9px 11px; border-radius: var(--radio-s);
  /* Sin filo de acento a la izquierda (cuarta tanda): el error se lee por su TEXTO y su caja neutra. */
  background: var(--sup-2); border: 1px solid var(--borde-fuerte); font-size: 13.5px;
}
/* TASK-49 · «escribe una hora»: el aviso está siempre, y cuando el campo se queda vacío se enciende y el
   botón de guardar se apaga. Un campo vacío no es una orden y no puede borrar nada. */
.editor-hora-aviso { margin: 0; font-size: 12px; color: var(--texto-3); }
.editor-hora.sin-hora .editor-hora-aviso { color: var(--texto); font-weight: 550; }
.editor-hora-nota { margin: 0; font-size: 12px; color: var(--texto-3); }
.editor-hora-nota code { background: var(--sup-1); border-radius: 4px; padding: 1px 5px; }
.editor-hora .boton[disabled] { opacity: .5; cursor: not-allowed; }

/* ==========================================================================
   TASK-52 · EL AVISO DE VERSIÓN NUEVA
   El usuario se quedó atrapado en la versión vieja sin saberlo ni poder salir.
   Este bloque es el que le dice qué pasa y le da la salida: va arriba (debajo
   de la cabecera), con el acento de la casa y sin tapar nada de la pantalla.
   ========================================================================== */
.aviso-version {
  max-width: var(--ancho); margin: 8px auto 0; padding: 12px 14px;
  /* SIN FILO DE ACENTO A LA IZQUIERDA (cuarta tanda). Es el cuadro que el usuario señaló: «no me gusta
     nada el diseño de la pill de este aviso… no me gustan los cuadros que en el lado izquierdo tienen el
     color de acento». Fondo y borde neutros; el aviso se lee por su texto y por sus botones. */
  background: var(--sup-1); border: 1px solid var(--borde-fuerte);
  border-radius: var(--radio);
  display: grid; gap: 9px;
}
.aviso-version-texto { margin: 0; font-size: 13.5px; }
.aviso-version-botones { display: flex; flex-wrap: wrap; gap: 8px; }
.aviso-version-botones .boton { min-height: 44px; }
.aviso-version-nota { margin: 0; font-size: 12px; color: var(--texto-2); }
/* TASK-92 · LA ACCIÓN CUANDO EL SERVIDOR ES VIEJO: reiniciar la webapp en el ordenador. No es un botón de la
   app (la app no puede reiniciar un proceso del ordenador), así que es un bloque de instrucción: el nombre del
   fichero en su tipografía de código, y el «¿Cómo?» al lado. Y los dos tiempos, que son dos hechos: desde
   cuándo lleva en marcha el servidor y a qué hora se cargó esta pantalla. */
.aviso-version-accion { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.aviso-version-accion-texto { font-size: 13.5px; }
.aviso-version-accion code, .aviso-version-como code { background: var(--sup-2); border-radius: 4px; padding: 1px 5px; font-size: 12.5px; }
.aviso-version-accion .boton { min-height: 44px; }
.aviso-version-como { margin: 0; font-size: 12.5px; color: var(--texto-2); }
.aviso-version-tiempos { margin: 0; font-size: 12.5px; color: var(--texto-2); }
.error-botones { display: flex; flex-wrap: wrap; gap: 8px; }
.error-botones .boton { min-height: 44px; }

/* ==========================================================================
   SEGUNDA TANDA DE FEEDBACK (2026-10-15 b) · los siete puntos de la app
   ========================================================================== */

/* PUNTO 7 · FUERA EL EFECTO MUELLE. `overscroll-behavior: none` es exactamente eso: al llegar al final
   (o al principio) la página no rebota ni encadena el desplazamiento al elemento de detrás. Va en `html` y
   en `body` porque el rebote puede quedar en cualquiera de los dos según el navegador. Lo que NO se puede
   medir aquí es la SENSACIÓN en un móvil de verdad: se mide la propiedad calculada (C53) y se dice. */
html, body { overscroll-behavior: none; }

/* PUNTO 3 · LA CINTA DE MOMENTOS, en la esquina superior derecha de la tarjeta: gris, con los iconos que
   la RECETA declare. Sin campo `momentos` no hay cinta: no se inventa nada. */
.receta-tarjeta { position: relative; }
.cinta-momentos {
  position: absolute; top: 10px; right: 10px;
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 7px; border-radius: 99px;
  background: var(--sup-2); border: 1px solid var(--borde);
}
.cinta-momentos svg { width: 16px; height: 16px; flex: none; }
.cinta-momentos .ico-amanecer { color: #ff9d4d; }
.cinta-momentos .ico-sol { color: #ffd24a; }
.cinta-momentos .ico-luna { color: #e8eaf0; }
/* Postre (2026-10-30): cuarto momento; el mismo tono en la cinta y en el desplegable. */
.cinta-momentos .ico-postre { color: #e59ac0; }
/* La cinta va arriba a la derecha, así que al título se le deja aire por ese lado. */
.receta-tarjeta h3 { padding-right: 76px; }

/* TERCERA TANDA · LA FLECHA DEL PASO LARGO, CON TRANSICIÓN. El texto se recorta por `max-height` (y no por
   `-webkit-line-clamp`) porque una altura solo se anima con un número: el script pone el alto del texto
   entero en píxeles al desplegar y lo quita al plegar. El degradado de abajo dice que hay más sin escribir
   nada, y la flecha gira 180° con la misma duración que crece el texto. */
.paso-texto-caja { display: grid; gap: 6px; justify-items: stretch; }
.paso-texto-caja .paso-texto.recortado {
  max-height: 9.6em; overflow: hidden; position: relative;
  transition: max-height 320ms ease;
  -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 78%, transparent 100%);
}
.paso-texto-caja.abierto .paso-texto.recortado {
  -webkit-mask-image: none; mask-image: none;
}
.boton.ampliar {
  justify-self: center; min-height: 44px; min-width: 64px; padding: 8px 14px;
  display: inline-flex; align-items: center; justify-content: center;
}
.boton.ampliar svg { width: 22px; height: 22px; transition: transform 320ms ease; }
.paso-texto-caja.abierto .boton.ampliar svg { transform: rotate(180deg); }

/* PUNTO 6 · EL PASO AL QUE TE DEVUELVE LA PASTILLA se marca un momento, para que no haya que buscarlo. */
.paso-destacado { border-radius: var(--radio); box-shadow: 0 0 0 2px var(--acento); transition: box-shadow 200ms; }

/* TERCERA TANDA · LA PASTILLA ENTERA LLEVA A LA RECETA, y el texto deja de ser un enlace: la zona pulsable
   es la cabeza y la barra del temporizador (el `<a>`), y los botones `+1 min` y `Quitar` se quedan fuera.
   Sin subrayado y con el color heredado: se comporta como un enlace y no lo parece. */
.temporizador-etiqueta { display: inline-flex; align-items: center; gap: 4px; }
.temporizador-ir { display: block; color: inherit; text-decoration: none; }
.temporizador-ir:hover .temporizador-cuenta { color: var(--acento); }

/* PUNTO 1 · A 320 PX LOS CUATRO MEDIDORES APILADOS NO CABEN. Medido con el día vacío a 320×640: sobraban
   223 px de scroll, y no era relleno —eran los cuatro medidores en una columna, 182 px cada uno—. En este
   ancho se compactan y el día vacío entra sin desplazarse. */
@media (max-width: 360px) {
  .vista { --gap-vista: 14px; }          /* el aire entre bloques también se aprieta: son 3 huecos */
  .medidor { padding: 8px 11px 7px; gap: 4px; }
  .medidor-valor { font-size: 22px; }
  .medidor-resta { font-size: 13px; }
  .barra { height: 7px; }
}

/* ==========================================================================
   TERCERA TANDA (2026-10-15, feedback C) · lo que se añadió aquí.
   ========================================================================== */

/* Un encabezado que SOLO existe para quien usa lector de pantalla: la pantalla de Hoy ya no lleva titular
   visible —el selector de día dice la fecha y tenerla dos veces era duplicar información— pero el
   documento sigue teniendo su h1 y la pantalla sigue teniendo nombre. */
.solo-lectores {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* COMPRA · la tarjeta de una lista: el título a la izquierda y, a la derecha, las dos cifras que se
   deciden al comprar (lo que cuesta la compra entera y lo que cuesta una ración). Antes ese hueco lo
   ocupaba la fecha, que no decidía nada. */
.lista-cabeza { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.lista-cifras {
  display: grid; gap: 4px; margin-top: 4px; padding-top: 9px;
  border-top: 1px solid var(--borde);
}
.lista-cifra { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.lista-cifra-etiqueta { font-size: 12.5px; color: var(--texto-3); }
/* EL DESEMBOLSO `X (Y)` ES UN TEXTO CORTO (cifra con su moneda) Y VA EN UNA LÍNEA (octava tanda, punto 5):
   a 320 px se partía en dos («11,10 € (23,25 €)» en una caja de 105 px). La etiqueta de al lado sí puede
   partirse; la cifra, no. Lo mide C67. */
.lista-cifra b { font-size: 15px; font-weight: 640; letter-spacing: -.01em; white-space: nowrap; }

/* LISTA · el coste consumido de cada línea (lo que gasta la receta), escalado con las raciones. Va debajo
   de la cantidad y NO es el precio del envase: ese se queda donde estaba, sin escalar.
   OJO CON LA REJILLA: `.check-cuerpo` es una rejilla de tres columnas en TODOS los anchos (nombre y
   cantidades en la 2, precio en la 3), así que cada línea nueva tiene que decir SU columna y SU fila. La
   primera versión de `.check-coste` metía esa colocación dentro del `@media (max-width: 360px)`, así que a
   390 px caía en la COLUMNA 1 —22 px— y el «gasta 0,68 €» salía partido en tres líneas. Se vio en la
   captura de la lista, no en el criterio. */
.check-coste { grid-column: 2; grid-row: 4; display: block; font-size: 12.5px; color: var(--texto-3); }

@media (max-width: 360px) {
  .lista-cifra b { font-size: 14.5px; }
}

/* ==========================================================================
   CUARTA TANDA (2026-10-15 d) · filtros, sin barras de scroll y movimiento.
   ========================================================================== */

/* 1 · EL DESPLEGABLE PERSONALIZADO («Filtrar por:» en Recetas y el día en Hoy). Un botón, un panel con
   opciones de 44 px, selección múltiple con su marca, y **scroll propio** en el panel: la lista de días
   puede ser larga y el `<select>` nativo no se puede pintar ni se puede leer entero a 320 px. */
.filtros { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 20px; }
.desplegable { position: relative; }
.desplegable-boton {
  min-height: 44px; max-width: 100%; display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-radius: var(--radio);
  background: var(--sup-2); border: 1px solid var(--borde);
  color: var(--texto); font: inherit; font-size: 14px; font-weight: 550; cursor: pointer;
}
.desplegable-boton:hover { border-color: var(--borde-fuerte); }
.desplegable-rotulo { color: var(--texto-2); flex: none; }
/* EL VALOR NO SE CORTA cuando hay sitio: el botón se ensancha y, si no cabe en la línea, la fila envuelve
   (`flex-wrap` en `.filtros` y `.fila-herramientas`). Antes llevaba un `max-width: 46vw` con puntos
   suspensivos y a 320 px la fecha del día salía cortada («mié, 14 oct 2026 · 1 entr…»): lo midió C60. */
.desplegable-valor { color: var(--texto); min-width: 0; overflow-wrap: anywhere; }
.desplegable-boton svg { width: 16px; height: 16px; flex: none; color: var(--texto-2); transition: transform 260ms cubic-bezier(.2,.8,.2,1); }
.desplegable-boton[aria-expanded="true"] svg { transform: rotate(180deg); }
.desplegable-panel {
  position: absolute; z-index: 40; top: calc(100% + 6px); left: 0;
  min-width: 100%; max-width: min(320px, 86vw); max-height: 55vh; overflow-y: auto;
  background: var(--sup-1); border: 1px solid var(--borde-fuerte); border-radius: var(--radio);
  padding: 6px; display: grid; gap: 2px; box-shadow: 0 10px 28px rgba(0, 0, 0, .38);
  scrollbar-width: none;
}
.desplegable-panel::-webkit-scrollbar { width: 0; height: 0; }
.desplegable-opcion {
  min-height: 44px; display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border: none; border-radius: var(--radio-s);
  background: none; color: var(--texto); font: inherit; font-size: 14.5px; text-align: left; cursor: pointer;
}
.desplegable-opcion:hover { background: var(--sup-2); }
.desplegable-opcion.elegida { background: none; font-weight: 550; }
.desplegable-opcion.elegida .desplegable-marca,
.desplegable-opcion.elegida .desplegable-marca svg { color: var(--texto-2); }
.desplegable-opcion svg { width: 18px; height: 18px; flex: none; color: var(--texto-2); }
.desplegable-opcion .ico-amanecer { color: #ff9d4d; }
.desplegable-opcion .ico-sol { color: #ffd24a; }
.desplegable-opcion .ico-luna { color: #e8eaf0; }
.desplegable-opcion .ico-postre { color: #e59ac0; }
.desplegable-texto { min-width: 0; }
.desplegable-nota { margin-left: auto; font-size: 12px; color: var(--texto-3); }
.desplegable-marca { display: inline-flex; color: var(--acento); }
.desplegable-marca svg { width: 16px; height: 16px; color: var(--acento); }

/* El interruptor del check de «solo macrodisponibles»: la caja es pequeña y el CONTROL mide toda la
   etiqueta (44 px), que es lo que se pulsa. */
.interruptor {
  min-height: 44px; display: inline-flex; align-items: center; gap: 9px;
  padding: 8px 12px; border-radius: var(--radio);
  background: var(--sup-2); border: 1px solid var(--borde);
  font-size: 14px; color: var(--texto); cursor: pointer;
}
.interruptor input { width: 20px; height: 20px; margin: 0; accent-color: var(--acento); flex: none; }
.filtro-cuenta { font-size: 13px; color: var(--texto-2); }

/* Las macros de la FICHA: mismas barras que la tarjeta, con el nombre de la macro delante para no confundir
   la cifra de la energía con la de la proteína. */
.receta-macros-ficha { margin-bottom: 2px; }
.receta-macros-ficha .receta-macro-cifra span { text-transform: none; letter-spacing: 0; }

/* 2 · LAS NEGRITAS DE LOS PASOS, EN BLANCO (cuarta tanda, punto 3). El `<strong>` heredaba el gris del
   párrafo (`--texto-2`), así que la negrita no destacaba por color: ahora usa el token de máximo contraste
   (`--texto`), el mismo del cuerpo. El `.md strong` ya lo hacía para los documentos; esto lo lleva a los
   pasos, que se pintan con el formateador en línea y no viven dentro de `.md`. Lo mide C61. */
.paso-texto strong, .paso-imperativo strong, .ingrediente-nombre strong { color: var(--texto); font-weight: 650; }

/* 2b · LAS UNIDADES A COMPRAR, en su fila de la lista. */
.check-unidades { grid-column: 2; grid-row: 3; display: block; font-size: 12.5px; color: var(--texto-2); }

/* El interruptor del check de «solo macrodisponibles»: la CAJA que se ve es pequeña (22 px), pero el
   CONTROL es toda la etiqueta —el `input` es transparente y la cubre entera—, que es lo que mide C2 y lo
   que se pulsa con el dedo. */
.interruptor { position: relative; }
.interruptor input { position: absolute; inset: -1px; width: auto; height: auto; margin: 0; opacity: 0; cursor: pointer; }
.interruptor-caja {
  width: 22px; height: 22px; flex: none; border-radius: 7px;
  border: 1.5px solid var(--borde-fuerte); background: var(--sup-1);
  display: inline-flex; align-items: center; justify-content: center; transition: background 120ms, border-color 120ms;
}
.interruptor-caja svg { width: 14px; height: 14px; opacity: 0; color: var(--fondo); }
.interruptor input:checked ~ .interruptor-caja { background: var(--acento); border-color: var(--acento); }
.interruptor input:checked ~ .interruptor-caja svg { opacity: 1; }

/* 3 · SIN BARRAS DE SCROLL, Y EL SCROLL SIGUE FUNCIONANDO. `scrollbar-width: none` (Firefox y Chrome
   modernos) y `::-webkit-scrollbar { width: 0 }` (el resto de Chrome/Safari). Se aplica también a los
   scrollers internos: el panel del desplegable y las cajas de tablas/código. Lo que NO se toca es el
   desplazamiento: se mide que la página sigue bajando. */
html { scrollbar-width: none; -ms-overflow-style: none; }
body { scrollbar-width: none; }
html::-webkit-scrollbar, body::-webkit-scrollbar { width: 0; height: 0; }
.tabla-envoltura, .md pre, .desplegable-panel, .cinta-momentos { scrollbar-width: none; }
.tabla-envoltura::-webkit-scrollbar, .md pre::-webkit-scrollbar,
.desplegable-panel::-webkit-scrollbar, .cinta-momentos::-webkit-scrollbar { width: 0; height: 0; }

/* 4 · LA PÍLDORA DEL TEMPORIZADOR NO TIENE ESTADO «SELECCIONADO» (cuarta tanda, punto 4). Lo que el usuario
   veía azul era el resaltado que el navegador pinta al TOCAR un enlace (`-webkit-tap-highlight-color`) y,
   en algunos navegadores, el fondo del `:active`. Se apaga el resaltado en todo lo que se pulsa; el FOCO
   DE TECLADO se mantiene (`:focus-visible`), que eso sí informa y no molesta al que toca. */
a, button, label, summary, .temporizador { -webkit-tap-highlight-color: transparent; }
.temporizador-ir, .temporizador-ir:active, .temporizador-ir:focus { background: none; }
.temporizador-ir:focus-visible { outline: 2px solid var(--acento); outline-offset: 3px; border-radius: var(--radio-s); }

/* 5 · MOVIMIENTO SUAVE (cuarta tanda, punto 5). Entre pestañas, un desplazamiento HORIZONTAL en el sentido
   en que se mueve la barra; al entrar en una tarjeta, una AMPLIACIÓN de la tarjeta y del contenido que
   llega. Todo con `animation` (no `transition`), para que `prefers-reduced-motion: reduce` lo apague con la
   regla global de arriba sin dejar estados a medias. */
@keyframes entra-derecha { from { transform: translateX(26px); opacity: .35; } to { transform: none; opacity: 1; } }
@keyframes entra-izquierda { from { transform: translateX(-26px); opacity: .35; } to { transform: none; opacity: 1; } }
@keyframes entra-ampliando { from { transform: scale(.985); opacity: .5; } to { transform: none; opacity: 1; } }
@keyframes ampliar-tarjeta { from { transform: scale(1); } 40% { transform: scale(.955); } to { transform: scale(1); } }
.vista.entra-derecha { animation: entra-derecha 220ms ease-out both; }
.vista.entra-izquierda { animation: entra-izquierda 220ms ease-out both; }
.vista.entra-ampliando { animation: entra-ampliando 240ms ease-out both; }
.receta-tarjeta.ampliando { animation: ampliar-tarjeta 260ms ease-out both; }

@media print {
  .pestanas, .pie, .saltar, .temporizadores, .segmentado { display: none; }
  body { background: #fff; color: #000; }
}

/* ==========================================================================
   QUINTA TANDA (2026-10-15 e · task-79) · lo que cambia aquí, punto por punto.
   ========================================================================== */

/* ==========================================================================
   EL PAGER NATIVO (2026-10-17)
   Tres paneles de 100 % de ancho dentro de un scroller horizontal del navegador:
   el dedo, la inercia, el snap y la goma los pone el COMPOSITOR. No hay
   transformaciones de JS sobre la pista. Cada panel tiene su propio scroll
   vertical, así que su scroll se conserva solo y no hay compensaciones.
   ========================================================================== */
.ventana { position: relative; width: 100%; height: 100%; overflow: hidden; }

.pista {
  display: flex;
  width: 100%; height: 100%;
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* `none` (no solo `contain`): en el borde del primer/último panel, la goma no debe encadenar con el
     gesto ATRÁS del navegador. La auditoría lo cazó: arrastrar a la derecha en Hoy sacaba de la app. */
  overscroll-behavior-x: none;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.pista::-webkit-scrollbar { display: none; }

.panel {
  position: relative;
  flex: 0 0 100%; width: 100%; height: 100%;
  overflow-y: auto; overflow-x: hidden;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.panel::-webkit-scrollbar { display: none; }

/* La página (la ruta actual de esa pestaña) va dentro del panel. El panel scrollea; la página solo mide. */
.pagina {
  width: 100%; max-width: var(--ancho); margin: 0 auto;
  padding: 20px 16px calc(40px + var(--alto-temporizadores, 0px) + env(safe-area-inset-bottom, 0px));
  box-sizing: border-box;
}
.aparcadero { position: absolute; top: 0; left: 0; right: 0; height: 0; overflow: hidden; visibility: hidden; pointer-events: none; }
.aparcadero > .pagina { position: absolute; top: 0; left: 0; right: 0; }

/* La franja ya no necesita capa fija: vive dentro de su panel, que ocupa el ancho del viewport. Su fondo
   local llega de borde a borde de la página y no hay ninguna capa `fixed` de una pestaña que pueda pintarse
   encima de otra. */
.buscador-fijo { background: var(--barra); backdrop-filter: none; }
.buscador-fijo::before { display: none; }
/* Botón de volver de una ficha o de una lista de la compra: pequeño, a la izquierda, 44 px de alto. */
.volver {
  display: inline-flex; align-items: center; align-self: flex-start; gap: 6px;
  min-height: 44px; padding: 0 10px 0 4px; margin: -6px 0 -10px;
  color: var(--texto-2); font-size: 13.5px; font-weight: 600; text-decoration: none;
  border-radius: 12px; background: transparent; border: 0;
  -webkit-tap-highlight-color: transparent;
}
.volver svg { width: 18px; height: 18px; flex: none; }
.volver:hover { color: var(--texto); background: var(--sup-1); }
.volver:focus-visible { outline: 2px solid var(--acento); outline-offset: 2px; }

.tabla-envoltura { touch-action: pan-x pan-y; }

/* NINGUNA pantalla entra con opacidad baja: eso era el fotograma negro. La que sale se desliza y se apaga;
   la que llega entra entera. */
@keyframes sale-izquierda { from { transform: none; opacity: 1; } to { transform: translateX(-26px); opacity: 0; } }
@keyframes sale-derecha { from { transform: none; opacity: 1; } to { transform: translateX(26px); opacity: 0; } }
@keyframes entra-derecha { from { transform: translateX(26px); } to { transform: none; } }
@keyframes entra-izquierda { from { transform: translateX(-26px); } to { transform: none; } }
@keyframes entra-ampliando { from { transform: scale(.985); } to { transform: none; } }

/* 1b · EL CAMBIO DE DÍA, PIEZA A PIEZA (punto 1): rápido (150 ms por pieza, pasos de 22 ms como mucho) y
   sin desplazamiento horizontal, así que no hay nada que recortar ni que reflowe. */
/* SÉPTIMA TANDA (punto 9) · SIN AZUL. El usuario: «el texto sale en azul al cambiar el momento». El azul era el de la SELECCIÓN del navegador: al tocar el campo se seleccionaba el texto y el sistema lo pintaba con su azul. Aquí se declara la selección con el acento de la casa, así que no hay azul del sistema en ninguna parte. */
::selection { background: var(--acento-suave); color: var(--texto); }

@keyframes sale-item { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-10px) scale(.995); } }
/* LA ENTRADA EMPIEZA VISIBLE (opacidad .35, no 0): con `from { opacity: 0 }`, el fotograma del cambio —en el
   que el contenido viejo ya se ha ido y las piezas nuevas todavía no han arrancado— dejaba la pantalla sin nada
   visible. Se midió con C70 al añadir el rótulo «Lo apuntado» y la fila del selector a la animación: racha de 2
   fotogramas (17 ms). Entrando desde .35 ninguna pieza está invisible en ningún fotograma, y el efecto de
   entrada uno por uno se mantiene (sigue habiendo desplazamiento y escalonado). */
@keyframes entra-item { from { opacity: .7; transform: translateY(14px) scale(.995); } to { opacity: 1; transform: none; } }

/* 2 · LAS BARRAS DE LAS ENTRADAS DEL DÍA, CONTINUAS (punto 2), como las de Recetas. El carril ya era una
   píldora con `overflow: hidden`; lo que las hacía «dos pastillas» era el radio en CADA tramo: al quitarle
   el radio a los tramos, el gris y el color quedan pegados y la barra se lee entera. */
.impacto span { border-radius: 0; }

/* 3 · LOS BOTONES DEL EDITOR DEL LÁPIZ, CENTRADOS (punto 3). */
.editor-hora-botones { justify-content: center; }

/* 4 · EL INTERRUPTOR DE «SOLO MACRODISPONIBLES», SOLO CON LA CASILLA CUANDO NO CABE (punto 10 de la sexta
   tanda, corregido en la octava). El nombre accesible no se pierde (va en el `aria-label` del `input`).
   LA CORRECCIÓN DE LA OCTAVA TANDA, con las palabras del usuario: «la caja de macrodisponibles se compacta
   (no de manera muy fluida) cuando le damos, pero eso no es lo que buscamos, queremos que se compacte cuando
   activamos los filtros y no cabe horizontalmente». Así que la regla ya NO es `input:checked` —el estado de
   la casilla no tiene nada que ver con el sitio—: la clase `compacto` la pone el JS **después de medir** si
   la fila de filtros cabe entera con el texto puesto. Si cabe, no se compacta; si no cabe, se recoge con la
   misma transición de antes. */
.interruptor { flex: none; }
.interruptor-texto {
  white-space: nowrap; overflow: hidden;
  max-width: 220px; opacity: 1;
  transition: max-width 260ms cubic-bezier(.22,.61,.36,1), opacity 200ms linear;
}
.interruptor.compacto .interruptor-texto { max-width: 0; opacity: 0; }
/* En la fila de filtros, el interruptor se va a la derecha (en móvil y en PC): es lo que pidió el usuario. */
.filtros .interruptor { margin-left: auto; }

/* 5 · LA LISTA DE LA COMPRA, CON LOS DATOS REPARTIDOS (punto 17). Fuera el «gasta X €»: la CANTIDAD y las
   UNIDADES van en la misma línea (que es lo que se mira al comprar) y el precio se queda en su columna de
   la derecha, centrado en la fila. La rejilla pasa de cuatro filas a dos. */
.check-datos { grid-column: 2; grid-row: 2; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 7px; }
.check-datos > * { grid-column: auto; grid-row: auto; }
.check-nombre { grid-row: 1; }
.check-caja { grid-row: 1 / 3; }
.check-precio { grid-row: 1 / 3; }

/* 6 · EL SELECTOR DE RACIONES DE LA LISTA DE LA COMPRA, CENTRADO (punto 12): se queda su propia línea y el
   contenido va centrado, en vez de caer a la izquierda debajo del título. */
.raciones-lista { flex-basis: 100%; justify-content: center; }

/* 7 · MÁS AIRE ENTRE LAS FILAS DE INGREDIENTES (punto 18). El alto de fila y la separación se miden. */
.ingrediente { min-height: 52px; padding: 7px 16px; }

/* 8 · LAS DOS CIFRAS DE LA RECETA (tiempo y coste por ración), CENTRADAS BAJO EL TÍTULO (punto 19). */
.ficha-datos { justify-content: center; }

/* 9 · EN LA TARJETA DE RECETAS, EL TIEMPO A LA IZQUIERDA Y EL COSTE A LA DERECHA CUANDO CABEN EN LA MISMA
   LÍNEA (punto 20). Aquí había una rejilla de dos columnas con las áreas puestas para TRES datos, y con dos
   —tiempo y coste— el coste caía siempre a una segunda fila: medido, las 7 tarjetas daban 2 filas. Con
   `flex-wrap` y `space-between`, cuando caben van los dos en la misma línea (tiempo a la izquierda, coste a
   la derecha) y cuando el tiempo es largo —los reposos de días— el coste baja a su línea y se queda a la
   izquierda. En qué anchos cabe se mide a 320/390/430, no se supone. */
.receta-datos { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px 12px; }
.receta-datos > span { flex: 0 1 auto; }
/* PUNTO 19 · LA FICHA NO ES UNA TARJETA: el usuario pidió el tiempo y el coste CENTRADOS debajo del título,
   y con `.ficha-datos` a secas (una clase, igual que `.receta-datos`, y escrita antes) ganaba la regla de
   arriba y las dos cifras se iban a las esquinas — medido el 2026-10-15 con la captura delante: huecos 0/0
   px, o sea el reparto de la tarjeta, no lo que él pidió. Compuesta (`receta-datos.ficha-datos`) SÍ gana, y
   el grupo queda centrado con aire en los dos lados y 28 px entre las dos cifras. */
.receta-datos.ficha-datos { justify-content: center; justify-items: center; column-gap: 28px; }

/* 10 · LO QUE SE PASA DEL PRESUPUESTO DEL DÍA, EN SU LÍNEA Y PEQUEÑO (punto 15): «(+12 P g)». */
.receta-macro-exceso { display: block; font-size: 12px; color: var(--texto-2); font-variant-numeric: tabular-nums; }

/* 11 · LA BARRA DE PESTAÑAS, OPACA (punto 16): sin transparencia ni desenfoque, así que el contenido que
   pasa por debajo no se ve a través. Vale para la barra inferior del móvil y para la cabecera del PC, que es
   donde vive la misma `<nav>`. */
.cabecera { background: var(--fondo); backdrop-filter: none; }
.pestanas { background: var(--barra); }
.pestana, .pestana:hover, .pestana:active, .pestana:focus { text-decoration: none; }

/* 12 · Y EN EL MÓVIL, LA BARRA INFERIOR ES UNA SUPERFICIE OPACA (pisa el `--velo` translúcido de antes). */
@media (max-width: 720px) {
  /* SEXTA TANDA (punto 2) · LA BARRA, MÁS OSCURA. El usuario: «queremos que el menú de pestañas sea un poco
     más oscuro para que en android no haya diferencia entre el menú y la barra inferior del sistema
     operativo». Estaba en `--sup-1` (#23252e), que es MÁS CLARO que el fondo de la página (#101115) y que la
     barra de navegación de Android en oscuro (negra): al lado se veía el salto. Ahora es #000: más oscura que
     el fondo y que cualquier superficie de la app (medido: su luminancia queda por debajo de la del fondo). */
  .pestanas { background: var(--barra); backdrop-filter: none; }
}

/* ==========================================================================
   DÉCIMA TANDA (2026-10-16 g) · LOS FILTROS DE RECETAS CON ICONOS Y EL LOGO DE MACROS.

   Palabras del usuario: «en Filtrar por: que en lugar de poner Desayuno, Comida, Cena ponga los iconos así
   ocupará menos y no tendremos que hacer que nada cambie de tamaño dinámicamente. Y en lugar de
   macrodisponibles pon un icono que sean 4 barras horizontales (azul, roja, etc.) representando las barras
   de macros y un check por encima… haz que las 4 barras tengan el estado de las 4 barras actuales».

   NADA de esto lleva media query de ancho: los tres iconos y el logo miden 44×44 SIEMPRE (WCAG 2.1 SC
   2.5.5) y la fila se queda en una línea a 320, 390 y 430 porque ningún ancho depende del estado elegido.
   ========================================================================== */

.momentos-filtro { display: flex; gap: 4px; margin-right: auto; }
.momento-boton {
  width: 44px; height: 44px; padding: 0; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--sup-1); color: var(--texto-3);
  cursor: pointer;
  transition: background-color 160ms ease, color 160ms ease, border-color 160ms ease;
}
.momento-boton svg { width: 21px; height: 21px; }
.momento-boton:hover { color: var(--texto-2); }
.momento-boton[aria-pressed="true"] { background: var(--acento-suave); color: var(--acento); border-color: transparent; }

/* EL LOGO DE LAS CUATRO BARRAS: cada barra es una macro, con SU color (los mismos tokens que las barras de
   las tarjetas: si el color de la proteína cambia, cambia en los tres sitios), y el relleno es el estado del
   día —lo que ya se lleva comido de esa macro sobre su objetivo—. Sin objetivo, la barra se queda vacía: no
   se inventa un denominador. */
.macro-logo {
  position: relative; flex: none;
  width: 44px; height: 44px; padding: 0;
  display: grid; place-items: center;
  border: 1px solid var(--borde); border-radius: var(--radio-s);
  background: var(--sup-1);
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease;
}
.macro-logo[aria-pressed="true"] { background: var(--acento-suave); border-color: transparent; }
.macro-logo-barras { display: flex; flex-direction: column; gap: 3px; width: 24px; }
.macro-logo-barra { display: block; height: 4px; border-radius: 99px; background: var(--macro-pista); overflow: hidden; }
.macro-logo-barra > i { display: block; height: 100%; border-radius: 99px; background: var(--macro); transition: width 240ms ease; }
/* EL CHECK, ENCIMA (en la esquina de arriba a la derecha) Y SIN MOVER NADA: aparece y desaparece con
   opacidad y escala, así que el control mide exactamente lo mismo pulsado y sin pulsar. */
.macro-logo-check {
  position: absolute; top: 0; right: 0;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--acento); color: var(--fondo);
  box-shadow: 0 0 0 2px var(--sup-1);
  opacity: 0; transform: scale(.55);
  transition: opacity 160ms ease, transform 160ms ease;
}
.macro-logo-check svg { width: 11px; height: 11px; }
.macro-logo[aria-pressed="true"] .macro-logo-check { opacity: 1; transform: none; }

/* ==========================================================================
   TANDA DE MOVIMIENTO · 2026-10-17
   Lo que se siente al tocar: pulsaciones que ceden, chevrons que giran con
   la misma curva que los paneles, casillas que dibujan su check y entradas
   que no aparecen de golpe. Todo con `transform`/`opacity` (nada de layout) y
   todo apagado por la regla global de `prefers-reduced-motion`.
   ========================================================================== */

.boton, .momento-boton, .macro-logo, .receta-tarjeta, .chip-tiempo,
.desplegable-boton, .interruptor {
  transition-property: background-color, border-color, color, transform, box-shadow;
  transition-duration: 160ms, 160ms, 160ms, 140ms, 160ms;
  transition-timing-function: ease, ease, ease, cubic-bezier(.2,.8,.2,1), ease;
}
.boton:active, .momento-boton:active, .macro-logo:active, .receta-tarjeta:active,
.chip-tiempo:active, .desplegable-boton:active, .interruptor:active {
  transform: scale(.97);
}

/* El check de las casillas se DIBUJA: el trazo empieza escondido y se completa cuando la casilla se marca.
   La caja sigue midiendo lo mismo (C40/C87 miden la caja, no el trazo). */
.check-caja svg path, .interruptor-caja svg path {
  stroke-dasharray: 24;
  stroke-dashoffset: 24;
  transition: stroke-dashoffset 190ms cubic-bezier(.2,.8,.2,1);
}
.check-input:checked ~ .check-cuerpo .check-caja svg path,
.interruptor input:checked ~ .interruptor-caja svg path { stroke-dashoffset: 0; }

/* La flecha del paso largo y la del desplegable giran con la misma curva que el panel que abren. */
.boton.ampliar svg { transition: transform 300ms cubic-bezier(.2,.8,.2,1); }

/* LA ENTRADA EN UNA FICHA: la pantalla se asienta (escala 0,985 y 6 px) mientras las piezas se escalonan
   por separado. La página no baja de opacidad 1: el fotograma oscuro que midió la auditoría no se repite. */
@keyframes entra-receta {
  from { transform: scale(.985) translateY(6px); opacity: 1; }
  to { transform: none; opacity: 1; }
}
.vista.entra-ampliando { transform-origin: top center; animation: entra-receta 280ms cubic-bezier(.16,.84,.24,1) both; }
/* Una pantalla con franja fija (la lista de la compra) no se escala: su capa `fixed` dejaría de colgar del
   viewport. Se abre con un asentamiento de opacidad mínimo; las piezas hacen el resto. */
@keyframes entra-documento { from { opacity: .985; } to { opacity: 1; } }
.vista.entra-documento { animation: entra-documento 280ms cubic-bezier(.16,.84,.24,1) both; }
/* ENTRADA DE PIEZAS EN CSS, no WAAPI: la animación es predeterminada y corre en el compositor aunque
   el hilo principal esté pintando la ficha. Curva fuerte de salida (Emil Kowalski), 240 ms y sin scale(0). */
@keyframes entra-pieza {
  from { opacity: .7; transform: translateY(12px) scale(.975); }
  to { opacity: 1; transform: none; }
}
.vista .entra-pieza { animation: entra-pieza 240ms cubic-bezier(.23, 1, .32, 1) both; animation-delay: var(--entra-retardo, 0ms); }

/* Entrada de página mínima: opacidad 0,985→1 en 140 ms, sin transformar el layer entero. Las piezas
   (CSS) son las que hacen la secuencia visible. */
@keyframes entra-pagina { from { opacity: .985; } to { opacity: 1; } }
.vista.entra-pagina { animation: entra-pagina 140ms cubic-bezier(.23, 1, .32, 1) both; }
@keyframes ampliar-tarjeta {
  0% { transform: scale(1); }
  38% { transform: scale(.955); }
  100% { transform: scale(1); }
}
.receta-tarjeta.ampliando { animation: ampliar-tarjeta 300ms cubic-bezier(.2,.8,.2,1) both; }

/* El aviso de versión entra desde arriba, sin tapar nada; si el sistema pide menos movimiento, aparece. */
@keyframes aviso-entra {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
.aviso-version { animation: aviso-entra 220ms cubic-bezier(.2,.8,.2,1) both; }

/* La apertura de una ficha no necesita una capa propia: la tarjeta hace su amago (`ampliar-tarjeta`) y la
   pantalla entra con `entra-receta`; las piezas se escalonan con `entraPiezasDeCuerpo`. */

/* EN PANTALLA TÁCTIL NO HAY «HOVER» QUE VALGA (2026-10-17, feedback: «si mantengo pulsada una tarjeta se
   queda más clara y no vuelve»). En un móvil, el navegador deja el `:hover` pegado después del toque; por eso
   una tarjeta se quedaba en `--sup-2` hasta tocar otra cosa. En un dispositivo sin ratón se devuelven los
   estados a su sitio; en uno con ratón se conserva el hover de siempre. */
@media (hover: none) {
  .receta-tarjeta:hover { background: var(--sup-1); border-color: var(--borde); text-decoration: none; }
  .receta-tarjeta:hover .receta-cifra span,
  .receta-tarjeta:hover .receta-pie { color: var(--texto-3); }
  .pestana:not([aria-current="page"]):hover { background: transparent; color: var(--texto-2); }
  .boton:hover { border-color: var(--borde); }
  .desplegable-boton:hover { border-color: var(--borde); }
  .momento-boton:hover { color: var(--texto-3); }
  .chip-tiempo:hover { border-color: var(--borde); }
  .desplegable-opcion:hover { background: none; }
  .lapiz:hover { color: var(--texto-2); }
  .lapiz:hover svg { color: var(--texto-3); }
  table.datos tbody tr:hover { background: transparent; }
}

/* El panel móvil ocupa el viewport entero y la barra de pestañas es fija abajo: la página reserva ese alto. */
@media (max-width: 720px) {
  .pagina {
    padding: 18px 16px calc(var(--nav-alto) + 56px + var(--alto-temporizadores, 0px) + env(safe-area-inset-bottom, 0px));
  }
}



/* ==========================================================================
   Cambio de pestaña desde la barra: View Transition (compositor, 120 Hz).
   La captura es del viewport, no de la ficha de 5.900 px; la barra va aparte
   y se queda quieta. El JS decide la dirección con html.vt-adelante / .vt-atras.
   ========================================================================== */
.pestanas { view-transition-name: barra-pestanas; }
::view-transition-old(barra-pestanas) { animation: none; opacity: 0; }
::view-transition-new(barra-pestanas) { animation: none; }

html.vt-adelante::view-transition-old(root) { animation: vt-sale-izquierda 220ms cubic-bezier(.2,.75,.25,1) both; }
html.vt-adelante::view-transition-new(root) { animation: vt-entra-derecha 220ms cubic-bezier(.2,.75,.25,1) both; }
html.vt-atras::view-transition-old(root) { animation: vt-sale-derecha 220ms cubic-bezier(.2,.75,.25,1) both; }
html.vt-atras::view-transition-new(root) { animation: vt-entra-izquierda 220ms cubic-bezier(.2,.75,.25,1) both; }

@keyframes vt-sale-izquierda { from { transform: translateX(0); } to { transform: translateX(-100%); } }
@keyframes vt-entra-derecha { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes vt-sale-derecha { from { transform: translateX(0); } to { transform: translateX(100%); } }
@keyframes vt-entra-izquierda { from { transform: translateX(-100%); } to { transform: translateX(0); } }

/* Ficha y lista de la compra: entran desde ABAJO, por detrás de la barra de pestañas, y salen hacia abajo.
   La captura es del viewport (no de la página entera) y la barra va en su grupo, quieta. */
html.vt-abrir::view-transition-old(root) { animation: none; }
html.vt-abrir::view-transition-new(root) { animation: vt-pagina-sube 360ms cubic-bezier(.2,.75,.25,1) both; }
/* Al cerrar, la ficha vieja tiene que quedar POR ENCIMA del listado nuevo para verse bajar. */
html.vt-cerrar::view-transition-old(root) { z-index: 2; animation: vt-pagina-baja 320ms cubic-bezier(.3,.7,.3,1) both; }
html.vt-cerrar::view-transition-new(root) { z-index: 1; animation: none; }
@keyframes vt-pagina-sube { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes vt-pagina-baja { from { transform: translateY(0); } to { transform: translateY(100%); } }

/* Entradas de «Lo apuntado»: las viejas se desvanecen hacia arriba y las nuevas suben desde abajo, en orden
   de arriba abajo con un desfase pequeño. */
@keyframes sale-apunte { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-10px); } }
@keyframes entra-apunte { from { opacity: .5; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.vista .apunte.sale-apunte { animation: sale-apunte 160ms cubic-bezier(.4,0,1,1) both; animation-delay: var(--retardo-apunte, 0ms); }
.vista .apunte.entra-apunte { animation: entra-apunte 240ms cubic-bezier(.22,1,.36,1) both; animation-delay: var(--retardo-apunte, 0ms); }

/* Al tocar la barra durante un swipe se apaga el snap unos instantes para que no devuelva el pager al
   panel hacia el que iba el gesto; el tween de JS lo lleva a la pestaña pulsada. */
#pista.sin-snap { scroll-snap-type: none; }

/* La barra de temporizadores queda fuera de la captura de la página y por ENCIMA de la ficha/lista:
   al abrir o cerrar una receta, la página sube por debajo y la barra no se mueve. */
.temporizadores { view-transition-name: temporizadores-cocina; }
::view-transition-group(temporizadores-cocina) { z-index: 2; }
::view-transition-old(temporizadores-cocina),
::view-transition-new(temporizadores-cocina) { animation: none; }

/* ==========================================================================
   COMPRA · DOS VISTAS: LISTAS Y DESPENSA (2026-10-18)
   ========================================================================== */
.compra-modo { margin: 8px 0 0; flex-wrap: nowrap; }
.compra-modo .boton { flex: 1 1 0; min-width: 0; white-space: nowrap; padding: 10px 8px; font-size: 13px; }

.despensa-cabeza { padding: 4px 0 14px; }
.despensa-nota { margin: 8px 0 4px; font-size: 13px; color: var(--texto-2); line-height: 1.4; }
.despensa-resumen { margin: 0 0 14px; font-size: 12px; color: var(--texto-3); }
.despensa-lista { list-style: none; margin: 0; padding: 0; border: 1px solid var(--borde); border-radius: var(--radio-g); background: var(--sup-1); overflow: hidden; }
.despensa-item {
  display: flex; align-items: center; gap: 12px; min-height: 58px; padding: 7px 14px;
  /* La barra de cantidad vive en el FONDO de la fila: se estira de izquierda a derecha según el
     porcentaje, sin ocupar espacio de contenido ni tapar el texto. */
  background-image: linear-gradient(var(--despensa-relleno), var(--despensa-relleno));
  background-repeat: no-repeat;
  background-size: var(--despensa-pct, 0%) 100%;
  transition: background-size 220ms cubic-bezier(.2, .8, .2, 1);
}
.despensa-item + .despensa-item { border-top: 1px solid var(--borde); }
.despensa-item-texto { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.despensa-nombre { color: var(--texto); font-size: 14.5px; font-weight: 600; overflow-wrap: anywhere; }
.despensa-envase { color: var(--texto-2); font-size: 12px; }
.despensa-editor { display: flex; align-items: center; gap: 8px; flex: none; color: var(--texto-2); font-size: 13px; }
.despensa-pct {
  width: 52px; min-height: 44px; padding: 6px 4px; border-radius: 10px;
  border: 1px solid var(--borde-fuerte); background: var(--sup-2); color: var(--texto);
  font: inherit; font-size: 16px; font-variant-numeric: tabular-nums; text-align: center;
}
.despensa-vacia { padding: 18px 0; color: var(--texto-2); font-size: 14px; }
.despensa-agotados { margin-top: 18px; }
.despensa-agotados > summary { min-height: 44px; display: flex; align-items: center; color: var(--texto-2); font-size: 13.5px; }
.despensa-agotados .despensa-lista { margin-top: 4px; }

.despensa-secciones { display: flex; flex-direction: column; gap: 20px; }
.despensa-seccion-titulo { margin: 0 0 7px; font-size: 13px; font-weight: 650; letter-spacing: .04em; text-transform: uppercase; color: var(--texto-2); }

/* Las filas de Compra usan la misma salida/entrada escalonada que «Lo apuntado» de Hoy. */
.vista [data-anima-fila].sale-apunte { animation: sale-apunte 160ms cubic-bezier(.4,0,1,1) both; animation-delay: var(--retardo-apunte, 0ms); }
.vista [data-anima-fila].entra-apunte { animation: entra-apunte 240ms cubic-bezier(.22,1,.36,1) both; animation-delay: var(--retardo-apunte, 0ms); }

/* Compra lleva buscador + los dos botones de vista: el hueco hasta la primera tarjeta se mantiene en los
   mismos 20 px que en Recetas (el padding extra compensa el bloque de botones). */
.buscador-fijo.buscador-compra { margin-bottom: 0; padding-bottom: 8px; }

/* El check de Listas/Despensa, en la esquina y sin cambiar el tamaño del botón. */
.compra-modo .boton { position: relative; }
.compra-check {
  position: absolute; top: 2px; right: 3px;
  width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--acento); color: var(--fondo);
  box-shadow: 0 0 0 2px var(--sup-1);
  opacity: 0; transform: scale(.55);
  pointer-events: none;
  transition: opacity 160ms ease, transform 160ms ease;
}
.compra-check svg { width: 11px; height: 11px; }
.compra-modo .boton.activo .compra-check { opacity: 1; transform: none; }

/* BORRAR UNA ENTRADA DE LA DESPENSA (2026-10-30). A la derecha del porcentaje, con 44 px de alto para el
   dedo aunque el icono sea de 17: el área de toque es lo que se pulsa, no el dibujo. El rojo solo aparece
   al pulsar —en reposo es gris, para que treinta papeleras no conviertan la lista en una alarma. */
.despensa-borrar {
  flex: none; width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: 12px; background: transparent; color: var(--texto-3);
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: background-color 140ms ease, color 140ms ease;
}
.despensa-borrar svg { width: 18px; height: 18px; }
.despensa-borrar:hover, .despensa-borrar:focus-visible { color: var(--peligro, #e2564a); background: var(--sup-2); }
.despensa-borrar:active { transform: scale(.94); }
.despensa-item { gap: 8px; }
/* El aviso de «Deshacer»: una franja, no un diálogo. Se va sola a los 9 s. */
.despensa-deshacer {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 12px; padding: 8px 10px 8px 12px;
  border: 1px solid var(--borde); border-radius: var(--radio-g);
  background: var(--sup-2); color: var(--texto-2); font-size: 13.5px; line-height: 1.35;
  animation: entra-apunte 220ms cubic-bezier(.22,1,.36,1) both;
}
.despensa-deshacer > span { flex: 1 1 auto; min-width: 0; }
.despensa-deshacer b { color: var(--texto); font-weight: 600; }
.despensa-deshacer .boton { flex: none; min-width: 44px; min-height: 44px; padding: 6px 12px; font-size: 13px; }
.despensa-deshacer .boton svg { width: 15px; height: 15px; }
/* Una entrada pasada de fecha: solo la parte de conservación en ámbar, sin rojo de alarma (no es una
   caducidad, es la conservación que declara la etiqueta una vez abierto). El envase se queda legible. */
.despensa-conserva { color: var(--texto-2); }
.despensa-item.despensa-caducado .despensa-conserva { color: var(--aviso); }

/* La pista del mini-carrusel de Compra: las dos vistas, una al lado de la otra, como dos paneles
   adyacentes del pager. La ventana recorta y la pista se desplaza entera. */
.compra-pista-ventana { width: 100%; overflow: hidden; }
.compra-pista { display: flex; width: 200%; align-items: flex-start; will-change: transform; }
.compra-pista > .compra-contenido { flex: 0 0 50%; width: 50%; min-width: 0; }

/* ==========================================================================
   EXPLORAR · chat de cocina (prototipo de diseño)
   La conversación vive en el panel; el compositor queda fijo encima de la barra
   de pestañas para poder escribir sin perder el hilo.
   ========================================================================== */
.explorar {
  display: flex; flex-direction: column; gap: 14px;
  position: relative;
  height: calc(100dvh - 20px - 40px - var(--alto-barra-temporizadores, 0px) - env(safe-area-inset-bottom, 0px));
  overflow: hidden;
}
.explorar-franja {
  flex: none; z-index: 20; margin: 0; padding: 0 0 8px;
  background: var(--fondo); transition: transform .24s ease;
}
.explorar .explorar-franja { position: relative; top: 0; margin: 0; padding-top: 0; }
.explorar-modo { width: 100%; }
/* LA BARRA DE EXPLORAR (2026-10-30): «Historial» a la izquierda (interruptor) y «Nuevo» a la derecha
   (acción). Los dos son botones de 44 px; ninguno lleva checkmark: el estado del interruptor lo dice
   `aria-pressed` y el color, y «Nuevo» no es un sitio donde estar. */
.explorar-barra { display: flex; align-items: center; gap: 8px; }
.explorar-boton { min-height: 44px; padding: 0 12px; gap: 6px; font-size: 13.5px; }
.explorar-boton svg { width: 16px; height: 16px; }
.explorar-boton[aria-pressed="true"] { background: var(--acento-suave); color: var(--acento); border-color: transparent; }
/* 2026-10-30 · Nuevo a la IZQUIERDA e Historial a la derecha (lo pidió el usuario). */
.explorar-boton-historial { margin-left: auto; }
.explorar-boton-nuevo:disabled { opacity: .45; cursor: default; }
/* BIENVENIDA AL ESTILO DE LA APP DE GEMINI (2026-10-30, vista en el móvil del usuario): un icono pequeño,
   un saludo GRANDE Y CENTRADO, y las sugerencias debajo. Sin burbuja, sin avatar y sin párrafo de
   instrucciones. Es texto de la PANTALLA, no un mensaje: vive fuera del hilo (`role="log"`), ocupa el
   hueco que queda libre y desaparece con el primer turno. */
.explorar-bienvenida {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 0 6px 44px; text-align: center;
}
.explorar-bienvenida[hidden] { display: none; }
.explorar-bienvenida-icono {
  width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 50%; background: var(--acento-suave); color: var(--acento);
}
.explorar-bienvenida-icono svg { width: 20px; height: 20px; }
.explorar-saludo {
  margin: 0; max-width: 22ch;
  font-size: 28px; line-height: 1.16; letter-spacing: -.02em; font-weight: 500; color: var(--texto);
}
.explorar-sugerencias { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 38ch; }
.explorar-sugerencia {
  min-height: 44px; padding: 10px 14px; border-radius: 99px;
  border: 1px solid var(--borde); background: var(--sup-2); color: var(--texto);
  font: inherit; font-size: 13.5px; line-height: 1.25; text-align: left; cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
  -webkit-tap-highlight-color: transparent;
}
.explorar-sugerencia:hover, .explorar-sugerencia:focus-visible { border-color: var(--borde-fuerte); }
.explorar-sugerencia:active { transform: scale(.985); background: var(--sup-1); }
.explorar-pista-ventana { flex: 1 1 auto; min-height: 0; overflow: hidden; position: relative; }
.explorar-pista {
  position: relative; width: 100%; height: 100%;
  overflow: hidden;
}
.explorar-vista {
  position: absolute; inset: 0; width: 100%; min-width: 0; height: 100%;
  display: flex; flex-direction: column; min-height: 0;
  will-change: transform;
}
.explorar-vista-oculta { display: none; }
.explorar-vista-chat { overflow: hidden; }
.explorar-vista-historial { overflow: hidden; padding: 2px 2px 0; }
.explorar-historial-cabeza {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 2px 0 10px;
}
.explorar-historial-cabeza h2 { margin: 0; font-size: 19px; line-height: 1.2; }
.explorar-historial-lista { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-bottom: 12px; }
.panel.explorar-modo-historial #chat-global { display: none; }
.panel.explorar-modo-historial .explorar {
  height: calc(100dvh - 20px - 40px - var(--alto-barra-temporizadores, 0px) - env(safe-area-inset-bottom, 0px) + 56px);
}
.explorar-franja-fila { display: flex; align-items: center; gap: 9px; min-height: 48px; }
.explorar-franja-marca {
  width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  border: 1px solid var(--borde); border-radius: 11px;
  background: var(--acento-suave); color: var(--acento);
}
.explorar-franja-marca svg { width: 18px; height: 18px; }
.explorar-franja-titulo { font-size: 16px; letter-spacing: -.01em; }
.explorar-franja-acciones { display: flex; gap: 6px; margin-left: auto; }
.explorar-accion {
  min-width: 44px; height: 44px; flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 0 9px; border: 1px solid var(--borde); border-radius: 13px;
  background: var(--sup-1); color: var(--texto-2); font: inherit; font-size: 12.5px; cursor: pointer;
}
.explorar-accion svg { width: 17px; height: 17px; }
.explorar-franja-acciones { min-width: 0; }
.explorar-accion:hover, .explorar-accion:focus-visible { border-color: var(--acento); color: var(--acento); outline: none; }
.explorar-contexto { display: flex; align-items: flex-start; padding-top: 6px; }
.explorar-contexto-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 0 10px; border: 1px solid var(--borde); border-radius: 11px;
  background: var(--sup-1); color: var(--texto-2); font: inherit; font-size: 12.5px;
  cursor: pointer;
}
.explorar-contexto-chip svg { width: 15px; height: 15px; }
.explorar-contexto-chip.activo { border-color: var(--acento); color: var(--acento); background: var(--acento-suave); }
.explorar-historial[hidden], .explorar-historial-velo[hidden] { display: none; }
.explorar-historial-velo {
  position: fixed; inset: 0; z-index: 29; background: rgba(0, 0, 0, .42);
  opacity: 0; transition: opacity .22s ease;
}
.explorar-historial-velo.abierto { opacity: 1; }
.explorar-historial {
  position: fixed; top: 0; bottom: calc(var(--nav-alto) + env(safe-area-inset-bottom, 0px)); left: 0; z-index: 30; width: min(86%, 340px);
  display: flex; flex-direction: column; gap: 12px; padding: 14px 13px 18px;
  border-right: 1px solid var(--borde-fuerte); background: var(--fondo);
  box-shadow: 12px 0 30px rgba(0, 0, 0, .3);
  transform: translateX(-105%); transition: transform .22s ease;
}
.explorar-historial.abierto { transform: none; }
.explorar-historial-cabeza { display: flex; align-items: center; gap: 8px; }
.explorar-historial-cabeza h2 { margin: 0; font-size: 19px; }
.explorar-historial-cabeza .explorar-accion { margin-left: auto; }
.explorar-historial-lista { display: flex; flex-direction: column; gap: 7px; overflow-y: auto; min-height: 0; }
.explorar-historial-item {
  display: flex; flex-direction: column; gap: 3px; width: 100%; min-height: 56px;
  padding: 9px 10px; border: 1px solid var(--borde); border-radius: 11px;
  background: var(--sup-1); color: var(--texto); font: inherit; text-align: left; cursor: pointer;
}
.explorar-historial-item strong { font-size: 13.5px; line-height: 1.25; overflow-wrap: anywhere; }
.explorar-historial-item span { color: var(--texto-2); font-size: 12px; }
.explorar-historial-item.activa { border-color: var(--acento); background: var(--acento-suave); }
.explorar-historial-vacio { color: var(--texto-2); font-size: 13px; line-height: 1.4; }
.explorar-parar {
  margin-top: 12px; min-height: 44px; width: 100%; padding: 0 12px;
  border: 1px solid var(--borde-fuerte); border-radius: 11px;
  background: transparent; color: var(--texto-2); font: inherit; font-size: 13px; cursor: pointer;
}
.explorar-parar:hover, .explorar-parar:focus-visible { border-color: var(--peligro); color: var(--peligro); outline: none; }
.explorar-progreso-card.cancelada { border-color: var(--borde-fuerte); }
.explorar-progreso-mini.cancelada { border-color: var(--borde-fuerte); }
.explorar-cabeza { display: flex; align-items: center; gap: 11px; padding: 2px 0 0; }
.explorar-marca {
  width: 46px; height: 46px; flex: none; border-radius: 15px;
  display: grid; place-items: center;
  background: linear-gradient(145deg, var(--acento-suave), var(--sup-1));
  border: 1px solid var(--borde); color: var(--acento);
}
.explorar-marca svg { width: 24px; height: 24px; }
.explorar-titulo { min-width: 0; }
.explorar-titulo h1 { margin: 0; font-size: 23px; line-height: 1.1; letter-spacing: -.02em; }
.explorar-titulo p { margin: 3px 0 0; color: var(--texto-2); font-size: 12.5px; }
.explorar-nueva {
  margin-left: auto; width: 44px; height: 44px; flex: none;
  display: grid; place-items: center; padding: 0;
  border: 1px solid var(--borde); border-radius: 14px;
  background: var(--sup-1); color: var(--texto-2);
  cursor: pointer;
}
.explorar-nueva svg { width: 19px; height: 19px; }
.explorar-hilo {
  display: flex; flex-direction: column; gap: 15px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 0 2px 70px 0; scrollbar-width: none; overscroll-behavior-y: contain;
}
.explorar-hilo::-webkit-scrollbar { display: none; }
.explorar-dia { margin: 0; text-align: center; font-size: 13px; color: var(--texto-2); }
.explorar-fila { display: flex; align-items: flex-start; gap: 8px; }
.explorar-fila-usuario { justify-content: flex-end; }
.explorar-avatar {
  width: 28px; height: 28px; flex: none; margin-top: 1px;
  display: grid; place-items: center; border-radius: 10px;
  background: var(--acento-suave); color: var(--acento);
}
.explorar-avatar svg { width: 16px; height: 16px; }
.explorar-bloque { min-width: 0; max-width: calc(100% - 36px); display: flex; flex-direction: column; gap: 9px; }
.explorar-fila-usuario .explorar-bloque { max-width: 84%; align-items: flex-end; }
.explorar-fila-widget .explorar-bloque { max-width: 100%; width: 100%; }
.explorar-burbuja {
  padding: 10px 13px; border-radius: 15px 15px 15px 5px;
  background: var(--sup-1); border: 1px solid var(--borde);
  color: var(--texto); font-size: 15px; line-height: 1.48;
}
.explorar-fila-usuario .explorar-burbuja {
  border-radius: 15px 15px 5px 15px;
  background: var(--acento-suave); border-color: transparent;
}
.explorar-burbuja-suelta { align-self: flex-start; }
/* Las sugerencias de la bienvenida tienen UNA sola definición, arriba (`.explorar-sugerencia`, píldora de
   99 px). Aquí había una segunda que la pisaba con radio 12 y 12,5 px: el componente se pintaba como
   rectángulo y el diseño no sabía cuál de las dos reglas mandaba (auditoría de diseño, 2026-10-30). */
.explorar-widget { background: var(--sup-1); border: 1px solid var(--borde); border-radius: 16px; overflow: hidden; }
.explorar-widget-cabeza { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 11px 13px 0; }
.explorar-widget-eyebrow { display: inline-flex; align-items: center; gap: 6px; color: var(--texto-2); font-size: 12px; font-weight: 650; letter-spacing: .04em; }
.explorar-widget-eyebrow svg { width: 14px; height: 14px; color: var(--acento); }
.explorar-widget-badge { border-radius: 99px; padding: 3px 8px; background: var(--sup-2); color: var(--texto); font-size: 12px; font-weight: 600; white-space: nowrap; }
.explorar-widget h2 { margin: 9px 13px 5px; font-size: 17px; line-height: 1.25; letter-spacing: -.01em; }
.explorar-widget-meta { display: flex; flex-wrap: wrap; gap: 7px 11px; margin: 0 13px; color: var(--texto-2); font-size: 13px; }
.explorar-widget-meta span { display: inline-flex; align-items: center; gap: 4px; }
.explorar-widget-meta svg { width: 13px; height: 13px; }
.explorar-macros { display: flex; flex-wrap: wrap; gap: 5px; padding: 10px 13px 3px; }
.explorar-macro { display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px; border-radius: 8px; background: var(--sup-2); color: var(--texto-2); font-size: 12px; }
.explorar-macro i { width: 6px; height: 6px; border-radius: 50%; background: var(--macro); }
.explorar-widget-acciones { display: flex; flex-wrap: wrap; gap: 7px; padding: 10px 13px 13px; }
.explorar-boton-principal, .explorar-boton-suave {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 8px 13px; border-radius: 11px;
  font: inherit; font-size: 13.5px; font-weight: 600; text-decoration: none; cursor: pointer;
}
.explorar-boton-principal { background: var(--acento); border: 1px solid transparent; color: var(--fondo); }
.explorar-boton-suave { background: var(--sup-2); border: 1px solid var(--borde); color: var(--texto-2); }
.explorar-lista-compra { list-style: none; margin: 8px 13px 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.explorar-lista-compra li { display: flex; align-items: center; gap: 8px; min-height: 34px; font-size: 13.5px; border-bottom: 1px solid var(--borde); }
.explorar-lista-compra li:last-child { border-bottom: 0; }
.explorar-lista-compra li b { margin-left: auto; color: var(--texto-2); font-size: 12.5px; font-weight: 500; }
.explorar-check { width: 19px; height: 19px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--acento-suave); color: var(--acento); }
.explorar-check svg { width: 11px; height: 11px; }
.explorar-compositor {
  position: relative; z-index: 1; flex: none;
  display: flex; flex-direction: column; gap: 7px;
  width: 100%; padding-top: 6px;
}
.panel[aria-hidden="true"] .explorar-compositor { display: none; }
.explorar-contexto { display: flex; gap: 6px; overflow-x: auto; padding: 2px; scrollbar-width: none; }
.explorar-contexto::-webkit-scrollbar { display: none; }
.explorar-contexto-chip {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  min-height: 44px; padding: 7px 10px; border-radius: 12px;
  border: 1px solid var(--borde); background: var(--sup-1);
  color: var(--texto-2); font: inherit; font-size: 12.5px; font-weight: 550; cursor: pointer;
}
.explorar-contexto-chip svg { width: 14px; height: 14px; color: var(--acento); }
.explorar-franja .explorar-contexto { align-items: flex-start; padding: 6px 0 0; }
.explorar-franja .explorar-contexto-chip { width: max-content; max-width: 100%; flex: 0 0 auto; align-self: flex-start; }
.explorar-contexto-chip.activo { background: var(--acento-suave); border-color: transparent; color: var(--texto); }
.explorar-caja {
  display: flex; align-items: center; gap: 4px;
  padding: 5px; border-radius: 18px; border: 1px solid var(--borde-fuerte);
  background: var(--sup-1); box-shadow: 0 10px 28px rgba(0, 0, 0, .25);
}
.explorar-adjuntar,
.explorar-enviar {
  width: 44px; height: 44px; flex: none; display: grid; place-items: center;
  border: 0; border-radius: 14px; background: transparent; color: var(--texto-2); cursor: pointer;
}
.explorar-adjuntar svg { width: 19px; height: 19px; }
.explorar-enviar { background: var(--acento); color: var(--fondo); }
.explorar-enviar svg { width: 19px; height: 19px; }
.explorar-entrada { flex: 1 1 auto; min-width: 0; height: 44px; padding: 0 4px; border: 0; background: transparent; color: var(--texto); font: inherit; font-size: 16px; }
.explorar-entrada::placeholder { color: var(--texto-2); }
.explorar-entrada:focus { outline: none; }
.explorar-caja:focus-within { border-color: var(--acento); box-shadow: 0 0 0 2px var(--acento-suave), 0 10px 28px rgba(0, 0, 0, .25); }
.explorar-nota { margin: 0; text-align: center; color: var(--texto-2); font-size: 12px; line-height: 1.3; }
.explorar-aviso { margin: 0; text-align: center; color: var(--texto); font-size: 12px; }

/* EL CLIP Y SUS FOTOS (2026-10-20). El menú sale hacia arriba, pegado al clip, y no empuja la caja:
   el compositor está fijo encima de la barra de pestañas y moverlo con cada apertura sería peor. */
.explorar-adjuntar-envoltura { position: relative; flex: none; display: flex; }
.explorar-adjuntar.con-adjuntos { color: var(--acento); background: var(--acento-suave); }
/* «Detener» (2026-10-30): ocupa el sitio de enviar mientras el agente trabaja, y va en peligro para que no se
   confunda con un envío. Tiene su propia regla: NO comparte la de `.explorar-adjuntar`. */
.explorar-detener { background: var(--peligro); color: var(--fondo); }
.explorar-detener svg { width: 18px; height: 18px; }
.explorar-menu-adjuntos {
  position: absolute; z-index: 30; left: 0; bottom: calc(100% + 9px);
  min-width: 218px; padding: 5px; border-radius: 14px;
  border: 1px solid var(--borde-fuerte); background: var(--sup-1);
  box-shadow: 0 14px 36px rgba(0, 0, 0, .32);
}
.explorar-menu-adjuntos[hidden] { display: none; }
.explorar-menu-adjuntos button, .explorar-menu-adjuntos-opcion {
  display: flex; align-items: center; gap: 9px; width: 100%;
  min-height: 44px; padding: 8px 10px; border: 0; border-radius: 10px;
  background: transparent; color: var(--texto); font: inherit; font-size: 13.5px;
  text-align: left; cursor: pointer; box-sizing: border-box;
}
.explorar-menu-adjuntos button:hover, .explorar-menu-adjuntos button:focus-visible,
.explorar-menu-adjuntos-opcion:hover, .explorar-menu-adjuntos-opcion:focus-visible { background: var(--sup-2); outline: none; }
.explorar-menu-adjuntos button svg, .explorar-menu-adjuntos-opcion svg { width: 17px; height: 17px; flex: none; color: var(--acento); }
/* Los inputs de archivo NO llevan `hidden`: en iOS Safari, un input `display:none` puede no abrir
   la cámara al activarlo desde una etiqueta. Se dejan como elementos reales de 44×44 px, invisibles
   y sin capturar el puntero (la etiqueta los activa); así también cumplen el objetivo táctil que mide
   el banco, en vez de aparecer como dos controles de 1×1 px. */
.explorar-archivo {
  position: absolute; left: 0; bottom: 0; width: 44px; height: 44px;
  opacity: 0; overflow: hidden; pointer-events: none;
}
/* Vista previa de la cámara: ocupa la pantalla, con el vídeo centrado y tres acciones grandes.
   Solo aparece cuando `getUserMedia` está disponible; si no, el menú abre el selector nativo. */
body.camara-abierta { overflow: hidden; }
.explorar-camara {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: center; justify-content: center;
  padding: 18px; background: rgba(4, 5, 8, .88);
}
.explorar-camara[hidden] { display: none; }
.explorar-camara-caja {
  width: min(100%, 720px); max-height: 100%;
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px; border-radius: 18px; background: var(--sup-1);
  border: 1px solid var(--borde-fuerte); box-shadow: 0 24px 70px rgba(0, 0, 0, .5);
}
.explorar-camara-video {
  display: block; width: 100%; min-height: 180px; max-height: 68dvh;
  object-fit: contain; border-radius: 12px; background: #000;
}
.explorar-camara-estado { margin: 0; color: var(--texto-2); font-size: 12.5px; line-height: 1.35; text-align: center; }
.explorar-camara-acciones { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.explorar-camara-acciones button { min-height: 44px; }
.explorar-camara-acciones button[disabled] { opacity: .5; cursor: not-allowed; }
.explorar-adjuntos { display: flex; gap: 7px; overflow-x: auto; padding: 2px 2px 4px; scrollbar-width: none; }
.explorar-adjuntos::-webkit-scrollbar { display: none; }
.explorar-adjuntos[hidden] { display: none; }
.explorar-adjunto {
  position: relative; flex: none; width: 78px; margin: 0;
  border: 1px solid var(--borde); border-radius: 12px; background: var(--sup-1);
  overflow: hidden;
}
.explorar-adjunto img { display: block; width: 78px; height: 58px; object-fit: cover; background: var(--sup-2); }
.explorar-adjunto figcaption {
  padding: 4px 6px 5px; color: var(--texto-2); font-size: 12px; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.explorar-adjunto-quitar {
  position: absolute; top: 0; right: 0; width: 44px; height: 44px;
  display: block; padding: 0; border: 0; border-radius: 0;
  background: transparent; color: #fff; cursor: pointer;
}
.explorar-adjunto-quitar::before {
  content: ""; position: absolute; top: 3px; right: 3px;
  width: 24px; height: 24px; border-radius: 50%; background: rgba(0, 0, 0, .62);
}
.explorar-adjunto-quitar svg { position: absolute; top: 9px; right: 9px; width: 12px; height: 12px; }
.explorar-adjuntos-estado { margin: 0; min-height: 0; color: var(--texto-2); font-size: 12px; line-height: 1.25; }
.explorar-adjuntos-estado:empty { display: none; }
.explorar-adjuntos-estado.error { color: var(--peligro, #ff8a7a); }
.chat-global.arrastrando .explorar-caja { border-color: var(--acento); background: var(--acento-suave); }
.explorar-fotos-mensaje { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.explorar-fotos-mensaje:first-child { margin-top: 0; }
.explorar-fotos-mensaje img { display: block; width: 104px; max-width: 100%; height: 78px; object-fit: cover; border-radius: 9px; border: 1px solid var(--borde); }
.explorar-texto-mensaje { margin: 0; }
.explorar-burbuja .explorar-texto-mensaje + .explorar-fotos-mensaje { margin-top: 6px; }

/* LAS TRES OPCIONES DE LA FASE DE EXPLORACIÓN. Cada una es un botón entero: en el móvil se pulsa
   sin apuntar, y el número va fuera del texto para que la lista se lea como una lista. */
.explorar-opciones { display: flex; flex-direction: column; gap: 8px; margin: 0 0 4px; }
.explorar-opcion {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px;
  padding: 9px 12px; border: 1px solid var(--borde); border-radius: 14px;
  background: var(--sup-2); color: var(--texto); font: inherit; text-align: left; cursor: pointer;
  transition: border-color .16s ease, background .16s ease;
}
.explorar-opcion:hover, .explorar-opcion:focus-visible { border-color: var(--acento); background: var(--sup-1); outline: none; }
.explorar-opcion-num {
  flex: none; width: 24px; height: 24px; display: grid; place-items: center;
  border-radius: 50%; background: var(--acento-suave); color: var(--acento);
  font-size: 12px; font-weight: 700;
}
.explorar-opcion-num svg { width: 12px; height: 12px; stroke-width: 2.2; }
.explorar-opcion-texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.explorar-opcion-texto b { font-size: 15px; line-height: 1.25; overflow-wrap: anywhere; }
.explorar-opcion-meta { color: var(--texto-2); font-size: 13px; line-height: 1.3; }
/* Lo que justifica la opción y sus ingredientes clave (2026-10-30): el servidor los mandaba y la tarjeta los
   tiraba, así que se elegía entre tres nombres sin el dato que los diferencia. */
.explorar-opcion-porque { color: var(--texto-2); font-size: 12.5px; line-height: 1.35; }
.explorar-opcion-ingredientes { color: var(--texto-3); font-size: 12px; line-height: 1.3; }
.explorar-opcion-descartar { border-style: dashed; background: transparent; }
/* El estado del guardado, dicho en la tarjeta (2026-10-30). */
.explorar-guardado { margin: 10px 0 0; font-size: 12.5px; line-height: 1.35; }
.explorar-guardado.si { color: var(--texto-2); }
.explorar-guardado.no { color: var(--aviso); }
.explorar-opcion-descartar .explorar-opcion-texto b { font-size: 13.5px; color: var(--texto-2); }
.explorar-opcion-descartar .explorar-opcion-num { background: var(--sup-2); color: var(--texto-2); }
@media (max-width: 720px) {
  .explorar { height: calc(100dvh - 18px - var(--nav-alto) - 56px - var(--alto-barra-temporizadores, 0px) - env(safe-area-inset-bottom, 0px)); }
}

/* La barra de chat es global: fuera del pager, siempre encima de la barra de pestañas, pero
   solo se muestra en Explorar. La franja de debajo es un degradado que la separa del contenido. */
.chat-global {
  position: absolute; z-index: 25; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--nav-alto) + var(--alto-barra-temporizadores, 0px) + env(safe-area-inset-bottom, 0px) + 10px);
  width: min(520px, calc(100vw - 24px));
  isolation: isolate;
}
.chat-global .explorar-caja { padding: 0; }
.chat-global::before {
  content: ""; position: absolute; z-index: -1; left: 50%; bottom: -10px;
  width: 100vw; height: calc(100% + 20px); transform: translateX(-50%);
  background: var(--fondo);
  pointer-events: none;
}


/* Respuestas reales del agente en Explorar. */
.explorar-burbuja-md .md { font-size: 15px; line-height: 1.5; }
.explorar-burbuja-md .md > :first-child { margin-top: 0; }
.explorar-burbuja-md .md > h2:first-child { padding-top: 0; border-top: 0; }
.explorar-burbuja-md .md > :last-child { margin-bottom: 0; }
.explorar-burbuja-md .md p { margin: 0 0 8px; }
.explorar-burbuja-md .md ul, .explorar-burbuja-md .md ol { margin: 0 0 8px; padding-left: 20px; }
.explorar-burbuja-md .md a { color: var(--acento); }
.explorar-burbuja-error { border-color: var(--borde-fuerte); color: var(--texto-2); }
.explorar-reintentar {
  align-self: flex-start; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--borde-fuerte); border-radius: 12px;
  background: var(--sup-1); color: var(--texto); font: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
}
.explorar-reintentar:hover, .explorar-reintentar:focus-visible { border-color: var(--acento); color: var(--acento); outline: none; }
.explorar-escribiendo { min-width: 58px; }
.explorar-puntos { display: inline-flex; align-items: center; height: 18px; }
.explorar-puntos::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--texto-2);
  box-shadow: 11px 0 0 var(--texto-2), 22px 0 0 var(--texto-2);
  animation: explorar-latido 900ms ease-in-out infinite;
}
@keyframes explorar-latido { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.explorar-fuentes { display: flex; flex-direction: column; gap: 1px; margin: 2px 2px 0; padding-top: 6px; border-top: 1px solid var(--borde); }
.explorar-fuentes-titulo { color: var(--texto-2); font-size: 12.5px; font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
.explorar-fuente {
  display: flex; align-items: center; min-height: 44px; min-width: 0; padding: 0 2px;
  color: var(--texto-2); font-size: 12px; line-height: 1.35; text-decoration: none;
  overflow-wrap: anywhere;
}
.explorar-fuente:hover, .explorar-fuente:focus-visible { color: var(--texto); text-decoration: underline; }

/* Widget de progreso de los subagentes: tarjeta en el hilo + barra compacta solo si la tarjeta no se ve.
   Rediseño 2026-10-20: minimalista, con padding real, sin icono de Explorar dentro, sin cabecera
   «RECETA», sin pie «Ahora: …» y sin subtítulo; el paso activo ya dice en qué fase está. */
.explorar-widget-progreso {
  border-color: var(--borde-fuerte);
  background: linear-gradient(160deg, var(--sup-1), var(--fondo));
  border-radius: 18px;
  padding: 16px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .16);
}
.explorar-widget-progreso h2 {
  margin: 0 0 12px; font-size: 19px; line-height: 1.25; letter-spacing: -.015em;
}
.explorar-widget-progreso .explorar-opciones { margin: 0; }
.explorar-progreso-pasos { list-style: none; display: flex; flex-direction: column; margin: 0; padding: 0; }
.explorar-paso {
  position: relative; display: grid; grid-template-columns: 24px minmax(0, 1fr);
  column-gap: 10px; padding: 0 0 14px; color: var(--texto-2);
  font-size: 14px; line-height: 1.35;
}
.explorar-paso:last-child { padding-bottom: 0; }
.explorar-paso:not(:last-child)::after {
  content: ""; position: absolute; left: 11px; top: 26px; bottom: 0;
  width: 2px; border-radius: 999px; background: var(--borde);
}
.explorar-paso.hecho:not(:last-child)::after { background: var(--acento); opacity: .5; }
.explorar-paso-marca {
  width: 24px; height: 24px; display: grid; place-items: center;
  position: relative; z-index: 1;
}
.explorar-paso-cuerpo { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-top: 1px; }
.explorar-paso-titulo { font-size: 14px; font-weight: 550; line-height: 1.3; }
.explorar-paso.activo .explorar-paso-titulo { color: var(--texto); font-weight: 650; }
.explorar-paso.hecho .explorar-paso-titulo { color: var(--texto-2); }
.explorar-paso.error .explorar-paso-titulo { color: var(--peligro); }
.explorar-paso-detalle { margin: 0; color: var(--texto-2); font-size: 13px; line-height: 1.35; }

/* LOS PUNTOS DEL STEPPER. Nada de "( )" ni "(*)": un círculo gris pendiente, uno relleno con
   check al completar, y un anillo de acento girando mientras se trabaja. */
.explorar-punto {
  width: 18px; height: 18px; border-radius: 50%; box-sizing: border-box;
  border: 2px solid var(--borde-fuerte); background: transparent;
  display: grid; place-items: center; flex: none;
}
.explorar-punto--hecho { width: 20px; height: 20px; border: 0; background: var(--acento); color: var(--fondo); }
.explorar-punto--hecho svg { width: 11px; height: 11px; stroke-width: 2.4; }
.explorar-punto--activo {
  width: 20px; height: 20px; border: 2px solid var(--acento-suave);
  border-top-color: var(--acento); border-right-color: var(--acento);
  animation: explorar-giro .9s linear infinite;
}
.explorar-punto--activo::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--acento);
}
.explorar-punto--espera { border-color: var(--acento); }
.explorar-punto--espera::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--acento);
}
.explorar-punto--error { width: 20px; height: 20px; border: 0; background: var(--peligro); color: var(--fondo); }
.explorar-punto--error svg { width: 10px; height: 10px; }
.explorar-progreso-card.error .explorar-punto--activo { animation: none; border-color: var(--peligro); }
.explorar-progreso-card.error .explorar-punto--activo::after { background: var(--peligro); }
@keyframes explorar-giro { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .explorar-punto--activo { animation: none; border-color: var(--acento); }
}
.explorar-progreso-card.error { border-color: var(--peligro, #ff8a7a); }
.explorar-progreso-card.listo { border-color: var(--acento); }
/* Mientras toca elegir, la lista de fases sobra: en un móvil de 390 px empujaba las opciones y el
   botón «Ninguna» contra el compositor. Las fases vuelven en cuanto hay elección. */
.explorar-progreso-card.eligiendo .explorar-progreso-pasos { display: none; }

.explorar-progreso-mini {
  display: none; position: sticky; top: 0; z-index: 9; align-items: center; gap: 9px;
  width: 100%; margin: 0 0 10px; padding: 10px 12px; border: 1px solid var(--borde);
  border-radius: 14px; background: var(--velo); backdrop-filter: blur(10px);
  color: var(--texto); font: inherit; font-size: 14px; text-align: left; cursor: pointer;
  box-shadow: 0 6px 16px rgba(0, 0, 0, .18);
}
.explorar-progreso-mini.visible { display: flex; }
.explorar-progreso-mini-marca { width: 18px; height: 18px; display: grid; place-items: center; flex: none; }
.explorar-progreso-mini .explorar-punto { width: 14px; height: 14px; }
.explorar-progreso-mini .explorar-punto--hecho,
.explorar-progreso-mini .explorar-punto--error { width: 16px; height: 16px; }
.explorar-progreso-mini .explorar-punto--hecho svg,
.explorar-progreso-mini .explorar-punto--error svg { width: 9px; height: 9px; }
.explorar-progreso-mini-texto { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 550; }
.explorar-progreso-mini-estado { margin-left: auto; color: var(--texto-2); font-size: 12.5px; text-transform: uppercase; letter-spacing: .05em; }
.explorar-progreso-mini.error { border-color: var(--peligro, #ff8a7a); }
.explorar-progreso-mini.listo { border-color: var(--acento); }
.explorar-progreso-mini.reconectando { border-color: var(--borde-fuerte); }
.explorar-progreso-mini.reconectando .explorar-progreso-mini-estado { color: var(--acento); }

/* DATOS DE ESTE MÓVIL (2026-10-30): el bloque de Hoy que dice dónde vive el registro, deja cambiarlo y
   saca/mete el export. Discreto a propósito: es la copia de seguridad, no la pantalla. */
.datos-movil { margin-top: 22px; }
.datos-movil .pliegue { padding-bottom: 4px; }
.datos-movil-botones { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 0; }
.datos-movil-botones .boton { min-height: 44px; padding: 8px 14px; font-size: 13.5px; }
.datos-movil .dato { margin: 10px 0 0; font-size: 13px; line-height: 1.45; color: var(--texto-2); }

/* APUNTAR UNA COMIDA (2026-10-30) — la hoja inferior y su botón. Patrón: fondo oscurecido, hoja pegada abajo,
   campos de 44 px y un solo botón principal. El foco de la hoja es el primer campo; Esc y el fondo la cierran. */
.seccion-cabeza { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.apuntar-boton {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  min-height: 44px; padding: 8px 14px; font-size: 13.5px;
}
.apuntar-boton svg { width: 16px; height: 16px; }
.hoja-fondo {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, .55);
  display: flex; align-items: flex-end;
}
.hoja {
  width: 100%; max-height: 86vh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--sup-1); border-top: 1px solid var(--borde-fuerte);
  border-radius: 20px 20px 0 0;
  padding: 14px 16px calc(18px + env(safe-area-inset-bottom));
  animation: entra-hoja 220ms ease-out;
}
@keyframes entra-hoja { from { transform: translateY(18px); opacity: .6; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .hoja { animation: none; } }
.hoja-barra { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.hoja-titulo { margin: 0; font-size: 17px; }
.hoja-cerrar {
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 0; border-radius: 12px; background: transparent; color: var(--texto-2); cursor: pointer;
}
.hoja-cerrar svg { width: 18px; height: 18px; }
.hoja-segmentos {
  display: flex; gap: 6px; margin: 12px 0 14px; padding: 4px;
  background: var(--sup-2, rgba(255, 255, 255, .06)); border-radius: 12px;
}
.hoja-segmento {
  flex: 1; min-height: 44px; border: 0; border-radius: 9px;
  background: transparent; color: var(--texto-2); font: inherit; font-size: 14px; cursor: pointer;
}
.hoja-segmento[aria-pressed="true"] { background: var(--sup-3, rgba(255, 255, 255, .12)); color: var(--texto-1); }
.hoja-etiqueta { display: block; margin: 12px 0 6px; font-size: 12.5px; color: var(--texto-2); }
.hoja-campo {
  width: 100%; min-height: 44px; padding: 8px 12px;
  border-radius: 12px; border: 1px solid var(--borde-fuerte);
  background: var(--sup-2, rgba(255, 255, 255, .06)); color: var(--texto-1);
  font: inherit; font-size: 15px;
}
.hoja-rejilla { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.hoja-guardar { width: 100%; margin-top: 16px; min-height: 48px; }
.hoja-aviso { color: var(--peligro); margin: 10px 0 0; font-size: 13px; }
.raciones-apuntar { margin-top: 10px; }

/* El enlace discreto a la pantalla de datos (2026-10-30): al final de Hoy, sin competir con nada. */
/* 44 px de alto y `--texto-2`: era un enlace de 41 px con `--texto-3` y no pasaba ni el toque (C2b) ni el
   contraste (C5, 3,79:1). */
.datos-enlace {
  display: inline-flex; align-items: center; min-height: 44px; margin-top: 20px;
  color: var(--texto-2); text-decoration: none; font-size: 13px;
}
.datos-enlace:hover { color: var(--texto-1); }
.datos-panel { margin-top: 14px; }
.datos-panel .seccion-titulo { margin-top: 18px; }
.datos-panel .dato { margin: 8px 0 0; }
.datos-movil-botones { justify-content: center; }

/* Con el día vacío, la tarjeta del vacío ES el botón (2026-10-30): una línea, 44 px, y la pestaña no crece. */
.apunte-vacio-boton {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 56px; padding: 10px 14px;
  border: 1px dashed var(--borde-fuerte); background: transparent;
  color: var(--texto-2); font: inherit; font-size: 14px; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.apunte-vacio-boton svg { width: 16px; height: 16px; flex: none; }

/* BOTÓN PRINCIPAL (2026-10-30): el único de la hoja de apuntar. No existía: se usaba la clase pero no había
   estilo, así que el botón salía como un botón normal. Fondo de acento y texto de fondo, como el de enviar. */
.boton.boton-principal { background: var(--acento); color: var(--fondo); border-color: transparent; font-weight: 600; }
.boton.boton-principal:active { filter: brightness(.94); }
.boton.boton-principal[disabled] { opacity: .6; }
