@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;350;400;500;600&family=IBM+Plex+Mono:wght@300;400&display=swap');
/* El @import va OBLIGATORIAMENTE en la LÍNEA 1: un @import solo puede ir precedido
   de @charset y @layer. Debajo de cualquier regla de estilo el navegador lo descarta
   en silencio, las fuentes no se descargan y todo el paquete tipográfico cae a la
   sans del sistema con las métricas equivocadas. Es la URL de la landing MÁS el peso
   600 de Inter, que la landing no pide: .gt-kcal, .gt-bar-val y el <b> de .i-size-val
   declaran font-weight:600 y sin esa cara Chrome coge la Medium y la engorda
   SINTÉTICAMENTE (mismo avance —308,69px en la prueba—, 28% más de tinta), así que
   ninguna negrita de la app sería una cara real. Como el avance no cambia, pedirla no
   mueve ninguna reserva anti-salto. El resto es idéntico a la landing (300/350/400/500
   de Inter, 300/400 del mono, display=swap, mismo orden de familias) y, como las dos
   viven en robertoer215.github.io, el CSS de Google y los woff2 ya están en caché para
   quien llega desde el CTA "Arma tu plato", que es el recorrido real. display=swap
   evita el texto invisible durante la descarga. */

/* El fallback va con métrica ajustada a propósito: Inter es 6,1% más ancha que
   la Helvetica del sistema, y TODAS las reservas anti-salto de esta hoja están
   medidas con Inter cargada. Sin size-adjust, la ventana de display=swap (y
   cualquier fallo de red) las invalida. */
@font-face{font-family:'Inter fallback';src:local('Helvetica Neue'),local('Arial');size-adjust:106%;ascent-override:96.9%;descent-override:24.2%;line-gap-override:0%}
@font-face{font-family:'Plex fallback';src:local('Menlo'),local('Courier New');size-adjust:104%}

*{box-sizing:border-box;margin:0;padding:0}
:root{
  /* ═══ TIPOGRAFÍA — las dos familias de la marca, ahora cargadas de verdad ═══ */
  --sans:'Inter','Inter fallback',ui-sans-serif,system-ui,sans-serif;
  --mono:'IBM Plex Mono','Plex fallback',ui-monospace,monospace;

  /* ═══ LIENZO — parchment y stone EXACTOS de la landing ═══ */
  --bg:#FCFAF5;           /* era #FAFAF8, un blanco gris FRÍO. Es --parchment, sin inventar nada */
  --surface:#F0EBE2;      /* era #F4F2EE. Es --stone. OJO: el QR trae el viejo cocido en app.js:1057 */
  --border:#E6DED1;       /* era #E2DDD6. Filete ESTRUCTURAL entre celdas: 1,28:1, no necesita más */
  --border-strong:#8C7756;/* era #C8C0B4 (1,72:1, insuficiente). Contorno de CONTROL: 4,12:1 sobre --bg,
                             3,62 sobre --surface, 3,71 sobre --accent-soft — los tres con margen real */

  /* ═══ TINTA — rampa cálida de barro, cuatro escalones por luminancia ═══ */
  --text:#5F2D0E;         /* era #1a1a18, negro de navegador. Es --clay de la landing. 10,78:1 */
  --muted-ink:#6B4A2F;    /* era #6F6C67 (gris frío, 5,00). Ahora 7,61:1 */
  --muted:#7B5B3E;        /* era #8A8680 = 3,46:1, REPROBABA AA. Ahora 5,91:1 (5,18 sobre --surface).
                             Solo sobrevive donde el barrido final no llega: los dígitos de .s-dot y
                             .psn-dot, .mt-btn, .st-btn, .res-mac y .terms-btn-icon */
  --light:#826342;        /* era #B8B2AA = 2,01:1, el peor par de la app. Ahora 5,28:1 sobre --bg,
                             4,63 sobre --surface (el hover de .obj-card/.act-card) y 4,76 sobre
                             --accent-soft: pasaría AA en los tres fondos.
                             PERO NO PINTA UN SOLO PÍXEL, y conviene saberlo antes de fiarse de esta
                             rampa: los once selectores que lo usan (.tagline, .s-lbl, .eyebrow,
                             .sec-lbl, .od, .ad, .meta-ey, .mn-unit, .cat-ht, .res-sub, .gap-lbl)
                             están TODOS en una de las dos listas de color del barrido del final, que
                             empata en especificidad (0-1-0) y gana por orden de fuente: los unifica
                             en --muted-ink. O sea que la rampa se DECLARA en cuatro escalones y
                             RENDERIZA en dos. El token se conserva porque retirarlo obliga a tocar
                             once reglas para cero píxeles de diferencia; la jerarquía la llevan de
                             hecho el tamaño y la familia (mono en mayúscula vs Inter), no el color */

  /* ═══ NARANJA — la misma escalera de la landing, repartida por función ═══ */
  --accent:#C05A1F;       /* SIN TOCAR = --orange. Ahora solo CONTORNO: bordes, filetes, aros de foco.
                             4,26:1 sobre --bg, por encima del 3:1 que pide un elemento no textual */
  --accent-ink:#AE511C;   /* = --orange-ink. RELLENO de todo lo "elegido": blanco encima 5,26:1.
                             Sobre --accent el blanco da 4,446 y NO pasa AA a 9-13px */
  --accent-deep:#8F400F;  /* = --orange-deep de la landing (su línea 20, "hover del CTA pequeño"): el
                             tercer escalón NO es nuevo, ya existía y tiene ahí el mismo papel. Hover
                             del relleno (blanco 7,22:1) y .gt-kcal sobre la banda --surface, donde
                             --accent-ink se queda en 4,42 y no llega (este da 6,08:1) */
  --accent-soft:#F5EDE4;  /* SIN TOCAR. No se empuja hacia ember a propósito: es el fondo de .icard.sel,
                             .nudge, .cocina-disc y .meta-warn, y con #FAE3CE --accent-ink caería a 4,24 */
  --ember:#FFD3A8;        /* NUEVO = --ember. Lavado de badges; tinta --text encima da 8,10:1 */
  --ember-dot:#D2691E;    /* = --ember-dot de la landing. Solo el punto del logotipo: es la única
                             marca gráfica de la identidad y es decorativa, no lleva texto encima */
  --danger:#AA3123;       /* era #C0392B escrito a mano en tres sitios (5,20:1). Ahora 6,35:1 sobre --bg
                             y 5,57 sobre --surface, y se separa por luminancia del naranja del acento */

  /* ═══ MACROS — tres canales cromáticos, los tres AA ═══ */
  --green:#356B4A;        /* era #3A7D6E teal (4,63). Ahora 6,00:1 sobre --bg, 4,69 sobre el riel */
  --blue:#3D5F91;         /* era #4A6FA5 (4,89). Ahora 6,21:1 sobre --bg, 4,85 sobre el riel.
                             Sigue siendo el único tono frío: la marca no tiene azul, pero los
                             carbohidratos necesitan un canal propio y cambiarlo rompería el código P/C/G */
  --amber:#8C6510;        /* era #C07A1F = 3,32:1, REPROBABA. Y a 34° era casi el mismo naranja que
                             --accent, así que "grasas" y "acción" eran el mismo color. Ahora 5,05:1
                             sobre --bg y 3,95 sobre el riel (antes 2,57, incumplimiento real) */

  /* ═══ FORMA — una sola escala, tres escalones ═══ */
  --r-sm:12px;            /* control y medios (lo que en la landing es el input de .form-field) */
  --r-md:16px;            /* panel. 16 y no 24 porque la app apila hasta 13 cajas por pantalla */
  --r-pill:9999px;        /* botones, badges, toggles y barras: el gesto de marca más reconocible */

  /* ═══ ELEVACIÓN — solo dos, ambas cálidas, ninguna neutra ═══ */
  --lift-cta:0 12px 30px -12px rgba(192,90,31,.7);        /* literal de .invite-cta; rgba = --orange */
  --lift-cta-hover:0 18px 38px -14px rgba(174,81,28,.8);  /* literal; rgba = --orange-ink */
  --lift-sticky:0 8px 20px -10px rgba(95,45,14,.35);      /* DERIVADA de --clay: la landing no tiene
                                                             barra sticky de la que copiar */

  /* ═══ RITMO ═══ */
  --gutter:40px;          /* 2.5rem aparecía cinco veces en cuatro reglas: por eso nadie lo bajó nunca
                             en móvil. Baja a 20px en @media (max-width:560px) */
}
/* font-family, font-size, weight y line-height son los mismos del body de la
   landing. El line-height:1.4 se HEREDA a .sz-pill y .rec-lbl, que son divs con
   role=button: por eso las dos llevan line-height en px más abajo. */
body{font-family:var(--sans);font-size:16px;font-weight:400;line-height:1.4;background:var(--bg);color:var(--text);min-height:100vh}
.app{max-width:720px;margin:0 auto;padding-bottom:64px}
.header{padding:2.5rem var(--gutter) 24px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:flex-end}
/* El logotipo es .brand de la landing tal cual (Inter 500 / 17px), no una versión
   espaciada de Georgia: es lo primero que ve quien entra desde el CTA de la web.
   El ::after es su .brand i: el punto de 7px en --ember-dot que la landing pega a
   COSECHA en el nav y en el pie. Va con display:flex + gap:4px como allí; medido, no
   mueve la línea base (el .logo sigue en 23,8px de alto y el .header en 87,98). */
.logo{font-family:var(--sans);font-size:17px;font-weight:500;letter-spacing:-.2px;text-transform:uppercase;display:flex;align-items:center;gap:4px}
.logo::after{content:'';width:7px;height:7px;border-radius:50%;background:var(--ember-dot);flex-shrink:0}
/* La misma cadena que la landing pone en Inter 350 a 13px: sale del barrido de mono
   del final porque era la ÚNICA cadena monoespaciada de la app en caja baja, y el mono
   aquí es el rótulo en mayúscula con tracking y nada más. */
.tagline{font-size:13px;letter-spacing:-.26px;color:var(--light);font-family:var(--sans);font-weight:350}
/* La banda va en --surface y NO en --bg: era del mismo color que la página y el
   contenido parecía tocarla al hacer scroll. .gt-kcal en --accent-deep porque
   --accent-ink sobre --surface se queda en 4,42:1 y a 14px hace falta 4,5. */
.global-tracker{position:sticky;top:0;z-index:100;background:var(--surface);border-bottom:1px solid var(--border-strong);padding:.875rem var(--gutter);display:none;box-shadow:var(--lift-sticky)}
.global-tracker.visible{display:block}
.gt-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;gap:12px}
.gt-lbl{font-size:9px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted)}
.gt-kcal{font-family:var(--sans);font-size:14px;font-weight:600;color:var(--accent-deep);flex:0 0 auto;white-space:nowrap}
.gt-bars{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.gt-bar-wrap{display:flex;flex-direction:column;gap:6px;min-width:0}
/* .gt-bar-top ENVUELVE en vez de recortar la etiqueta con ellipsis: probado, con
   ellipsis 'Proteína' se lee 'P…' en los cuatro anchos de teléfono. */
.gt-bar-top{display:flex;justify-content:space-between;flex-wrap:wrap;column-gap:8px;align-content:flex-start}
.gt-bar-lbl{font-size:8px;letter-spacing:1px;text-transform:uppercase;font-family:var(--sans);color:var(--muted-ink)}
.gt-bar-val{font-size:8px;font-family:var(--sans);color:var(--text)}
/* Que ningún control enfocado aterrice debajo de la barra fija. */
.icard,.sz-pill,.ss-pill,.btn-ajustar,.btn,.btn-add,.mt-btn,.st-btn{scroll-margin-top:140px}
/* El radio va en la PISTA, no en el relleno: el relleno se anima con scaleX y un
   radio propio se vería aplastado (a scaleX(.3) un radio de 4px mide 1,2px).
   El riel se queda CLARO y la visibilidad la da el filete inset: cualquier gris
   oscuro suficiente para 3:1 contra la crema hunde los tres rellenos contra él.
   El -webkit-mask es el seguro contra el fallo de Safari al recortar un hijo
   compuesto por transform dentro de overflow:hidden + border-radius. */
.bar-bg{height:8px;background:var(--border);border-radius:var(--r-pill);overflow:hidden;box-shadow:inset 0 0 0 1px var(--border-strong);-webkit-mask-image:radial-gradient(#fff,#000)}
/* El modo IA reescribe estas barras en CADA toque. Animar `width` obliga a un
   reflow por toque e incumple la regla de animar solo opacity y transform, así
   que la barra ocupa el 100% y lo que se anima es la escala horizontal. */
.bar-fill{height:100%;width:100%;border-radius:0;transform-origin:left center;transform:scaleX(0);transition:transform .25s cubic-bezier(.22,.61,.36,1)}
/* .bover lleva trama porque --amber y --accent están a 1,28:1 (1,23 en
   deuteranopia): sin ella, pasarse de grasa no se ve. */
.bp{background:var(--green)}.bc{background:var(--blue)}.bg2{background:var(--amber)}.bover{background-color:var(--accent)!important;background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.55) 0 2px,transparent 2px 4px)!important}
.stepper{display:flex;align-items:center;padding:24px var(--gutter) 0}
/* 44x44 reales: es navegación de verdad (onclick=goStep/goResumen) y medía 38x43.
   El min-width no descuadra el stepper porque .s-line se lleva el resto con flex:1. */
.s-node{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;cursor:pointer;min-height:44px;min-width:44px}
.s-line{flex:1;height:1px;background:var(--border);margin:0 10px;margin-bottom:14px}
.s-dot{width:22px;height:22px;border-radius:50%;border:1px solid var(--border-strong);display:flex;align-items:center;justify-content:center;font-size:9px;font-family:var(--sans);color:var(--muted);background:var(--bg);transition:background-color .25s,border-color .25s,color .25s}
/* El contorno se queda en --accent (umbral 3:1, da 4,26) y la CIFRA de dentro baja a
   --accent-ink: como texto el umbral es 4,5 y 4,26 no llega; --accent-ink da 5,04. */
.s-dot.active{border-color:var(--accent);color:var(--accent-ink)}
.s-dot.done{background:var(--accent-ink);border-color:var(--accent-ink);color:#fff}
.s-lbl{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;color:var(--light);font-family:var(--sans);transition:color .3s}
.s-lbl.active{color:var(--accent)}
.screen{display:none;padding:2.5rem var(--gutter);animation:rise .35s ease}
.screen.active{display:block}
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
.eyebrow{font-size:9px;letter-spacing:3px;text-transform:uppercase;color:var(--light);font-family:var(--sans);margin-bottom:12px}
/* Inter 300 con tracking negativo = el display de la landing. */
.stitle{font-size:24px;font-weight:300;letter-spacing:-.9px;line-height:1.1;margin-bottom:8px}
.ssub{font-family:var(--sans);font-size:14px;font-weight:350;letter-spacing:-.3px;color:var(--muted-ink);line-height:1.55;margin-bottom:2rem}
.divider{height:1px;background:var(--border);margin:40px 0}
.sec-lbl{font-size:9px;letter-spacing:2.5px;text-transform:uppercase;color:var(--light);font-family:var(--sans);margin-bottom:.75rem;padding-bottom:.5rem;border-bottom:1px solid var(--border)}
label{font-size:9px;letter-spacing:2px;text-transform:uppercase;color:var(--muted);font-family:var(--sans)}
/* 16px y no 15: por debajo de 16, Safari en iOS amplía la página al enfocar y se
   queda así. El borde inferior va en --border-strong porque --border da 1,29:1 y
   un campo cuyo único límite no se ve no se lee como campo.
   %237B5B3E es --muted cocido a mano: un data-URI no admite var(), así que si
   cambia el token hay que cambiarlo AQUÍ también. */
input,select{background:transparent;border:none;border-bottom:1px solid var(--border-strong);color:var(--text);padding:8px 0;font-size:16px;font-family:var(--sans);font-weight:400;letter-spacing:-.2px;width:100%;outline:none;transition:border .2s;-webkit-appearance:none;font-variant-numeric:tabular-nums}
input:focus,select:focus{border-bottom-color:var(--accent)}
select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%237B5B3E'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 4px center;padding-right:20px;cursor:pointer}
select option{font-family:sans-serif;background:var(--bg)}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;margin-bottom:24px}
.fg{display:flex;flex-direction:column;gap:7px}
/* Rejillas: radio en el CONTENEDOR + overflow:hidden, porque las celdas son fondos
   planos que deben sangrar hasta el canto. minmax(0,1fr) y NO un font-size menor:
   'Sedentario' y 'Rendimiento' no tienen punto de corte y con minmax(auto,1fr)
   estiraban su pista, dejando la rejilla de 5 con celdas desiguales. Siguen siendo
   4 y 5 columnas en todos los anchos. */
.obj-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1px;background:var(--border);border:1px solid var(--border);margin-bottom:24px;border-radius:var(--r-sm);overflow:hidden}
.obj-card{background:var(--bg);padding:16px 4px;text-align:center;cursor:pointer;transition:background .2s}
.obj-card:hover{background:var(--surface)}
/* Reparto del naranja, no cambio: --accent-ink es el RELLENO de todo lo "elegido"
   (blanco encima 5,26:1; sobre --accent eran 4,446 y no pasa AA a 9px) y --accent
   se queda para contornos, filetes y aros de foco, donde el umbral es 3:1 y da 4,26. */
.obj-card.selected{background:var(--accent-ink)}
.obj-card.selected .on,.obj-card.selected .od{color:#fff}
.obj-card.selected .od{color:rgba(255,255,255,.92)}
.on{font-size:11px;font-family:var(--sans);font-weight:500;color:var(--text);margin-bottom:2px}
.od{font-size:9px;color:var(--light);font-family:var(--sans)}
.act-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:1px;background:var(--border);border:1px solid var(--border);margin-bottom:24px;border-radius:var(--r-sm);overflow:hidden}
.act-card{background:var(--bg);padding:12px 4px;text-align:center;cursor:pointer;transition:background .2s}
.act-card:hover{background:var(--surface)}
.act-card.selected{background:var(--accent-ink)}
.act-card.selected .an,.act-card.selected .ad{color:#fff}
.act-card.selected .ad{color:rgba(255,255,255,.92)}
.an{font-size:10px;font-family:var(--sans);font-weight:500;color:var(--text);margin-bottom:1px}
.ad{font-size:9px;color:var(--light);font-family:var(--sans)}
.meta-panel{border:1px solid var(--border);padding:24px;margin-bottom:24px;border-radius:var(--r-md)}
.meta-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1.25rem}
.meta-ey{font-size:9px;letter-spacing:2px;text-transform:uppercase;color:var(--light);font-family:var(--sans);margin-bottom:3px}
.meta-ctx{font-size:12px;color:var(--muted);font-family:var(--sans)}
/* Ni un padding tocado en los badges: a 9999px el radio se recorta a la mitad de
   la altura y los cuatro ya son píldora completa. El ember va en los badges y
   --accent-soft se queda como está: llevarlo a ember hundiría --accent-ink encima
   de él de 4,54 a 4,24:1. */
.meta-tag{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;font-family:var(--sans);padding:5px 12px;background:var(--ember);border:1px solid var(--ember);border-radius:var(--r-pill);color:var(--text)}
.meta-nums{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border-top:1px solid var(--border);padding-top:1.25rem}
.mn{text-align:center;border-right:1px solid var(--border)}
.mn:last-child{border-right:none}
.mn-val{font-size:26px;font-weight:300;letter-spacing:-1px;line-height:1}
.mn-unit{font-size:10px;color:var(--light);font-family:var(--sans)}
.mn-lbl{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;font-family:var(--sans);margin-top:5px}
/* .k en --accent-ink y no en --accent: es el rótulo 'ENERGÍA' a 12px, o sea texto con
   umbral 4,5, y --accent se queda en 4,26. Sus tres hermanos ya pasaban (6,00/6,21/5,05). */
.mn-lbl.p{color:var(--green)}.mn-lbl.c{color:var(--blue)}.mn-lbl.g{color:var(--amber)}.mn-lbl.k{color:var(--accent-ink)}
.meta-warn{margin-top:1rem;padding:.75rem 1rem;border:1px solid var(--amber);border-radius:var(--r-sm);background:var(--accent-soft);font-family:var(--sans);font-size:11px;line-height:1.5;color:var(--text)}
.cat-sec{margin-bottom:24px}
.cat-hd{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.75rem;padding-bottom:.5rem;border-bottom:1px solid var(--border)}
.cat-nm{font-size:10px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--text)}
.cat-ht{font-size:10px;color:var(--light);font-family:var(--sans)}
/* Bordes por celda en vez de "gap sobre fondo": con un número impar de ingredientes
   (proteína son 3) la celda sobrante ya no se pinta como un bloque gris. Por eso
   NO se recorta con overflow:hidden en el contenedor: con bordes por celda tres de
   las cuatro esquinas se quedarían sin trazo. El redondeo de móvil va abajo, en su
   media query, y se resuelve dándole contorno completo al contenedor. */
.items-grid{display:grid;grid-template-columns:1fr 1fr;gap:0;border-top:1px solid var(--border);border-left:1px solid var(--border)}
.icard{background:var(--bg);cursor:pointer;transition:background .2s;position:relative;display:flex;flex-direction:column;overflow:hidden;border-right:1px solid var(--border);border-bottom:1px solid var(--border)}
.icard:hover{background:var(--surface)}
.icard.sel{background:var(--accent-soft)}
.i-photo{position:relative;aspect-ratio:4/3;overflow:hidden;background:var(--surface)}
.i-img{width:100%;height:100%;object-fit:cover;object-position:center;display:block;transition:transform .28s ease-out}
/* El zoom solo donde hay puntero fino: en móvil se quedaba pegado tras el toque.
   Esta regla tiene que quedarse AQUÍ, antes del bloque de reduced-motion: empata en
   especificidad con el .icard:hover .i-img{transform:none} del final y solo pierde
   por orden de fuente. Si se escribe al final, reduce deja de apagar el zoom. */
@media (hover:hover) and (pointer:fine){.icard:hover .i-img{transform:scale(1.045)}}
/* Velo superior: el check tiene que leerse también sobre las fotos más claras.
   El velo va en --clay con alfa y no en el negro azulado de antes. */
.i-photo::after{content:'';position:absolute;inset:0 0 auto 0;height:60px;background:linear-gradient(180deg,rgba(95,45,14,.34),transparent);pointer-events:none}
/* El aro de seleccionado va en un pseudo-elemento: un inset box-shadow sobre .i-photo
   se pinta por debajo del <img> hijo y no se vería. */
.i-photo::before{content:'';position:absolute;inset:0;z-index:1;pointer-events:none;box-shadow:inset 0 0 0 0 var(--accent);transition:box-shadow .2s}
/* El pulso de recálculo sale del box-shadow inset porque el inset se pinta DEBAJO
   de los hijos y .i-photo (~75% del alto) lo tapaba entero por arriba: se veía una
   U. z-index:3 por encima del check (2) y del aro de selección (1). Esta regla debe
   ir ANTES de .recalc::after: empatan en especificidad. */
.icard::after{content:'';position:absolute;inset:0;z-index:3;pointer-events:none;border:2px solid var(--accent);opacity:0}
.i-body{padding:16px}
.i-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:8px}
.i-name{font-size:13px;color:var(--text);line-height:1.3}
.i-price{font-size:12px;color:var(--accent-ink);font-family:var(--sans);font-weight:500}
.i-check{width:20px;height:20px;border-radius:50%;border:1px solid rgba(255,255,255,.85);background:rgba(95,45,14,.28);transition:background-color .2s,border-color .2s;position:absolute;top:10px;right:10px;z-index:2;display:flex;align-items:center;justify-content:center}
.i-check::after{content:'';width:8px;height:8px;border-radius:50%;background:#fff;transform:scale(0);transition:transform .2s cubic-bezier(.34,1.3,.64,1)}
.icard.sel .i-check{background:var(--accent-ink);border-color:#fff}
.icard.sel .i-check::after{transform:scale(1)}
.icard.sel .i-photo::before{box-shadow:inset 0 0 0 3px var(--accent)}
.i-macros{display:flex;gap:12px;margin-bottom:4px}
.mp{font-size:10px;color:var(--muted-ink);font-family:var(--sans)}
.mp b{color:var(--text);font-weight:500;font-style:normal}
/* MODO IA — el tamaño dejó de ser una pregunta y pasó a ser una respuesta.
   Las píldoras ya no se abren al SELECCIONAR (eso hacía crecer la tarjeta 47 px):
   ahora solo las revela "Ajustar", que es una acción aparte y deliberada. */
/* Hasta seis opciones (Pequeña · Estándar · Grande · ×2 · ×3 · ×4) en una rejilla
   de tres columnas: a 375 px la tarjeta va a una columna y cada píldora mide ~83 px,
   44 de alto, con 8 px de separación. Sigue siendo revelación progresiva. */
.size-pills{display:none;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:12px}
.icard.ajustando .size-pills{display:grid}
/* 12px reales y 44px de alto: antes eran 9px en un target de 24px, que incumplía
   readable-font-size y touch-target-size a la vez. El radio es COMPLETO aquí: la tapa
   recta solo se justifica donde hay filete que la explique, y filete solo lleva UNA de
   las seis píldoras. Por eso el radio de solo-abajo baja a .sz-rec, que es su sitio. */
.sz-pill{min-height:44px;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 4px;text-align:center;background:var(--bg);border:1px solid var(--border-strong);border-radius:var(--r-sm);cursor:pointer;font-family:var(--mono);font-size:12px;letter-spacing:.02em;line-height:16px;text-transform:uppercase;color:var(--muted-ink);transition:background .2s}
.sz-pill:hover{background:var(--surface)}
.sz-pill.sz-on{background:var(--text);color:#fff}
/* Aquí SÍ hay filete, y por eso aquí vive la tapa recta: el mismo trazo de 2px que
   marca el tamaño resuelto en .i-size-val, que con radio completo se curvaría en
   capucha y rompería ese par.
   El padding-top de 5px NO es cosmético: ese borde es 1px más grueso que el de las
   demás y con box-sizing:border-box la pila natural (2+6+16+2+12+6+1) da 45px, que
   REBASA el suelo de 44. Como .size-pills es rejilla, la fila entera se estiraba a 45
   y el grupo medía 97; al fijar un tamaño a mano desaparecía 'Resuelto' con su clase
   .sz-rec y el grupo caía a 96, moviendo 1px la tarjeta y todo lo de abajo en CADA
   toque. Con 5+6 las seis píldoras miden 44 exactos y el grupo no se mueve. */
.sz-pill.sz-rec{border-top:2px solid var(--accent);padding-top:5px;border-radius:0 0 var(--r-sm) var(--r-sm)}
/* Con la píldora ya elegida el fondo es --text: el filete naranja desaparecería
   contra él, así que el recomendado se marca en --ember. */
.sz-pill.sz-rec.sz-on{border-top:2px solid var(--ember)}
/* La palabra en vez de un punto: el punto no comunicaba nada por sí solo. */
.rec-lbl{display:block;font-family:var(--mono);font-size:12px;letter-spacing:.02em;line-height:12px;text-transform:uppercase;color:var(--accent-ink);margin-top:2px;white-space:nowrap}
.sz-pill.sz-on .rec-lbl{color:#fff}
.sugg-box{border:1px solid var(--border);margin-bottom:24px;border-radius:var(--r-md)}
.sugg-hd{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px}
.sugg-badge{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;font-family:var(--sans);padding:4px 10px;background:var(--ember);border:1px solid var(--ember);border-radius:var(--r-pill);color:var(--text)}
.sugg-desc{font-size:11px;color:var(--muted);font-family:var(--sans)}
.sugg-item{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;gap:16px;align-items:flex-start}
.sugg-item:last-child{border-bottom:none}
.sugg-thumb{width:76px;height:76px;flex-shrink:0;overflow:hidden;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm)}
.sugg-img{width:100%;height:100%;object-fit:cover;display:block}
.sugg-main{flex:1;min-width:0}
.sugg-name{font-size:13px;color:var(--text);margin-bottom:3px}
.sugg-macro-tag{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;font-family:var(--sans);color:var(--accent);margin-bottom:6px}
.sugg-why{font-size:11px;color:var(--muted);font-family:var(--sans);margin-bottom:10px;line-height:1.5}
.sugg-controls{display:flex;align-items:center;gap:10px}
/* Hasta ocho tamaños (½ … ×4) en los extras: rejilla de cuatro columnas que parte
   en dos filas, con 36 px de alto por píldora en vez de una tira aplastada. */
.sugg-sizes{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--border);border:1px solid var(--border);flex:1;border-radius:var(--r-sm);overflow:hidden}
.ss-pill{min-height:36px;display:flex;align-items:center;justify-content:center;padding:6px 4px;text-align:center;background:var(--bg);cursor:pointer;font-size:9px;letter-spacing:1px;text-transform:uppercase;font-family:var(--sans);color:var(--muted);transition:background .2s}
/* El -4px es OBLIGATORIO con el recorte de .sugg-sizes: con -2px el radio de 11
   se come el vértice del aro de foco. */
.ss-pill:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}
.ss-pill:hover{background:var(--surface)}
.ss-pill.ss-on{background:var(--text);color:#fff}
.sugg-price{font-size:13px;color:var(--accent-ink);font-family:var(--sans);font-weight:500;white-space:nowrap}
.btn-add{font-family:var(--sans);font-size:12px;font-weight:500;letter-spacing:-.2px;text-transform:none;padding:12px 18px;min-height:44px;border-radius:var(--r-pill);cursor:pointer;transition:background-color .2s,color .2s,border-color .2s,transform .18s;border:none;white-space:nowrap}
.btn-add.off{background:var(--text);color:var(--bg)}
.btn-add.off:hover{background:var(--accent-ink)}
.btn-add.on{background:transparent;color:var(--muted-ink);border:1px solid var(--border-strong)}
.btn-add.on:hover{color:var(--text);border-color:var(--border-strong)}
.sugg-ok{padding:1.25rem;display:flex;align-items:center;gap:12px}
.sugg-ok-lbl{font-size:12px;color:var(--muted);font-family:var(--sans)}
.sugg-ok-mark{font-size:10px;color:var(--green);border:1px solid var(--green);width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.res-wrap{border:1px solid var(--border);margin-bottom:1.5rem;border-radius:var(--r-md);overflow:hidden}
.res-item{display:flex;justify-content:space-between;align-items:flex-start;padding:16px 20px;border-bottom:1px solid var(--border)}
.res-item:last-child{border-bottom:none}
.res-left{display:flex;gap:12px;align-items:center;min-width:0}
.res-thumb{width:46px;height:46px;flex-shrink:0;overflow:hidden;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm)}
.res-img{width:100%;height:100%;object-fit:cover;display:block}
.res-name{font-size:13px;color:var(--text);margin-bottom:2px}
.res-sub{font-size:10px;color:var(--light);font-family:var(--sans)}
.res-extra-tag{font-size:8px;letter-spacing:1.5px;text-transform:uppercase;font-family:var(--sans);background:var(--ember);border:1px solid var(--ember);border-radius:var(--r-pill);color:var(--text);padding:2px 7px;display:inline-block;margin-bottom:4px}
.res-right{text-align:right;flex-shrink:0;margin-left:12px}
.res-macs{display:flex;gap:6px;justify-content:flex-end;margin-bottom:3px}
.res-mac{font-size:9px;font-family:var(--sans);color:var(--muted)}
.res-price{font-size:15px;color:var(--accent-ink);font-family:var(--sans);font-weight:500}
.res-total{padding:16px 20px;background:var(--surface);display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--border)}
.res-total-lbl{font-size:9px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted)}
.res-total-val{font-size:24px;font-weight:300;letter-spacing:-.9px;color:var(--accent-ink)}
.gap-wrap{border:1px solid var(--border);margin-bottom:1.5rem;border-radius:var(--r-md)}
.gap-hd{padding:16px 20px;border-bottom:1px solid var(--border);font-size:9px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted)}
.gap-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0}
.gap-blk{padding:16px 4px;text-align:center;border-right:1px solid var(--border)}
.gap-blk:last-child{border-right:none}
.gap-num{font-size:14px;font-weight:500;font-family:var(--sans);line-height:1.3}
/* .over pintaba '8g de más' del MISMO verde que 'En tu meta' (clsMacro,
   app.js:1093): pasarse parecía un acierto. El color dice en meta / fuera de
   meta y nada más; la dirección la llevan las palabras que escribe fmtMacro. */
.gap-num.ok{color:var(--green)}
.gap-num.off,.gap-num.over,.gap-num.under{color:var(--danger)}
.gap-lbl{font-size:8px;letter-spacing:1px;text-transform:uppercase;font-family:var(--sans);color:var(--light);margin-top:3px}
.qr-section{border:1px solid var(--border);margin-bottom:1.5rem;border-radius:var(--r-md);overflow:hidden}
.qr-hd{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}
.qr-hd-lbl{font-size:9px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted)}
.qr-hd-tag{font-size:9px;letter-spacing:1px;text-transform:uppercase;font-family:var(--sans);background:var(--ember);border:1px solid var(--ember);border-radius:var(--r-pill);color:var(--text);padding:4px 10px}
.qr-body{display:grid;grid-template-columns:auto 1fr;gap:0}
/* El ancho fijo va de la mano de la reserva de .qr-pedido: esta columna es 'auto' en
   .qr-body y sin él el id del pedido la ensancha de 169 a 183px al llegar la
   confirmación. 169px es lo que ya medía: 120 del canvas + 48 de padding + 1 de filete. */
.qr-code-wrap{width:169px;padding:1.5rem;border-right:1px solid var(--border);display:flex;flex-direction:column;align-items:center;gap:.75rem;background:var(--surface)}
.qr-code-wrap p{font-size:9px;letter-spacing:1px;text-transform:uppercase;font-family:var(--sans);color:var(--muted);text-align:center}
/* mix-blend-mode:darken porque app.js:1057 cocina el QR con colorLight:'#F4F2EE'
   (el --surface VIEJO) y ese color vive en JS. darken hace mínimo por canal: los
   módulos claros colapsan contra el fondo cálido y los oscuros sobreviven, así que
   el código sigue escaneando. VERIFICAR con un móvil real antes de publicar; si
   darken fallara, la salida sin tocar JS es .qr-code-wrap{background:#F4F2EE}. */
#qr-canvas{width:120px;height:120px;mix-blend-mode:darken}
.qr-instructions{padding:1.5rem}
.qr-inst-title{font-size:10px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted);margin-bottom:1rem;padding-bottom:.5rem;border-bottom:1px solid var(--border)}
.qr-inst-item{display:flex;gap:12px;margin-bottom:.875rem;align-items:flex-start}
.qr-inst-item:last-child{margin-bottom:0}
.qr-inst-num{font-size:9px;font-family:var(--sans);color:var(--accent-ink);border:1px solid var(--border-strong);width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;margin-top:1px}
.qr-inst-text{font-size:12px;color:var(--text);line-height:1.5}
.qr-inst-detail{font-size:10px;color:var(--muted);font-family:var(--sans);margin-top:2px}
.btn-row{display:flex;justify-content:space-between;align-items:center;margin-top:32px;padding-top:24px;border-top:1px solid var(--border)}
/* En frase y a 13px, como los CTA de la landing. Los rótulos ya vienen en caja
   baja del HTML, así que text-transform:none no cambia ninguna palabra, y en
   frase el botón ENCOGE (147px -> 125px en 'Calcular con fórmula'). Lista de
   transiciones explícita en vez de 'all': 'all' interpolaba outline-color y
   outline-width (el aro de foco aparecía con un fundido de 250ms). */
.btn{font-family:var(--sans);font-size:13px;font-weight:500;letter-spacing:-.3px;text-transform:none;padding:12px 24px;min-height:44px;border-radius:var(--r-pill);cursor:pointer;border:none;transition:background-color .25s,color .25s,border-color .25s,box-shadow .25s,transform .18s}
/* Regla del sistema: --border es filete ESTRUCTURAL entre celdas (1,29:1, no
   necesita más) y --border-strong es contorno de CONTROL (4,12:1, umbral 3:1). */
.btn-ghost{background:transparent;color:var(--muted-ink);border:1px solid var(--border-strong)}
.btn-ghost:hover{color:var(--text);border-color:var(--border-strong)}
/* Primario en naranja de marca (18-sep-2026): en el perfil, Continuar, el toggle
   de modo y la actividad elegida iban en negro junto a las tarjetas de objetivo
   ya naranjas. El relleno es ahora --accent-ink (blanco encima 5,26:1; sobre
   --accent se quedaba en 4,45 y no pasa AA) y el hover baja un tercer paso a
   --accent-deep (6,60:1). El halo es la única sombra de marca, cálida. */
.btn-main{background:var(--accent-ink);color:#fff;box-shadow:var(--lift-cta)}
.btn-main:hover{background:var(--accent-deep);transform:translateY(-2px);box-shadow:var(--lift-cta-hover)}
.btn-main:active{transform:translateY(0) scale(.985)}
.plato-subnav{display:flex;flex-direction:column;align-items:center;gap:.75rem;padding:24px 0;margin-bottom:8px}
.psn-steps{display:flex;align-items:center}
.psn-dot{width:22px;height:22px;border-radius:50%;border:1px solid var(--border-strong);display:flex;align-items:center;justify-content:center;font-size:9px;font-family:var(--sans);color:var(--muted);background:var(--bg);flex-shrink:0;transition:background-color .25s,border-color .25s,color .25s}
.psn-dot.psn-active{border-color:var(--accent);color:var(--accent-ink)}
.psn-dot.psn-done{background:var(--accent-ink);border-color:var(--accent-ink);color:#fff}
.psn-line{width:28px;height:1px;background:var(--border)}
.psn-lbl{font-size:16px;font-weight:400;letter-spacing:-.4px;color:var(--text)}
/* box-shadow inset y NO border: el border añadiría 2px al modelo de caja y el
   botón saltaría justo al habilitarse. El halo de --lift-cta se apaga aquí a
   propósito: un CTA con brillo que no se puede pulsar es una promesa falsa. */
.btn-main:disabled{background:var(--surface);color:var(--muted-ink);box-shadow:inset 0 0 0 1px var(--muted-ink);cursor:not-allowed;transform:none}
.btn-main:disabled:hover{background:var(--surface);transform:none;box-shadow:inset 0 0 0 1px var(--muted-ink)}
.mode-toggle{display:flex;gap:1px;background:var(--border);border:1px solid var(--border);margin-bottom:24px;border-radius:var(--r-pill)}
.mt-btn{flex:1;padding:11px 8px;text-align:center;background:var(--bg);cursor:pointer;font-family:var(--sans);font-size:13px;font-weight:500;letter-spacing:-.3px;text-transform:none;color:var(--muted);transition:background .2s}
.mt-btn:hover{background:var(--surface)}
.mt-btn.mt-active{background:var(--accent-ink);color:#fff}
.manual-note{font-size:12px;color:var(--muted);font-family:var(--sans);line-height:1.6;margin-bottom:24px;padding:12px 16px;border:1px solid var(--border);background:var(--surface);border-radius:var(--r-md)}
.sub-toggle{display:flex;gap:1px;background:var(--border);border:1px solid var(--border);margin-bottom:1.5rem;border-radius:var(--r-pill)}
.st-btn{flex:1;padding:9px 8px;text-align:center;background:var(--bg);cursor:pointer;font-family:var(--sans);font-size:13px;font-weight:500;letter-spacing:-.3px;text-transform:none;color:var(--muted);transition:background .2s}
.st-btn:hover{background:var(--surface)}
.st-btn.st-active{background:var(--accent-ink);color:#fff}
/* Los toggles son <button> (teclado y aria-pressed): fuera el cromo del navegador,
   y 44 px de alto, que con 9px de letra y 11px de padding se quedaban en 35. */
.mt-btn,.st-btn{border:0;-webkit-appearance:none;appearance:none;min-height:44px;line-height:1.35}
/* Toggles: el radio va en las CELDAS de los extremos, NUNCA overflow:hidden en el
   contenedor: son <button> y el recorte mordía su aro de foco. Las dos curvas
   (contenedor y celda) quedan concéntricas. */
.mt-btn:first-child,.st-btn:first-child{border-radius:var(--r-pill) 0 0 var(--r-pill)}
.mt-btn:last-child,.st-btn:last-child{border-radius:0 var(--r-pill) var(--r-pill) 0}
.mt-btn:focus-visible,.st-btn:focus-visible{outline:2px solid var(--accent);outline-offset:-3px}
/* Errores de formulario en el formulario, no en un alert(): bajo los campos y
   con el campo subrayado en rojo. --danger sobre el fondo da 6,35:1. */
.form-error{font-family:var(--sans);font-size:12px;line-height:1.5;color:var(--danger);margin:-.75rem 0 1.25rem}
.form-error:empty{display:none}
input.invalid{border-bottom-color:var(--danger)}
/* Las kcal derivadas de los macros, en vivo, pegadas a los campos.
   El line-height en px es OBLIGATORIO: 12px x el 1.4 heredado del body dan 16,8px
   y la reserva de 16px reventaría. */
.manual-kcal{font-family:var(--sans);font-size:12px;line-height:16px;color:var(--muted-ink);margin:-1rem 0 1.5rem;min-height:16px}
.terms-wrap{margin-top:24px;padding:24px;border:1px solid var(--border);background:var(--surface);border-radius:var(--r-md)}
.terms-title{font-size:9px;letter-spacing:2px;text-transform:uppercase;font-family:var(--sans);color:var(--muted);margin-bottom:.75rem}
.terms-text{font-size:12px;color:var(--muted);font-family:var(--sans);line-height:1.7;margin-bottom:1.25rem}
.terms-accept-btn{width:100%;display:flex;align-items:center;gap:12px;padding:14px;background:var(--bg);border:1px solid var(--border-strong);border-radius:var(--r-sm);cursor:pointer;transition:background-color .2s,border-color .2s,transform .18s;font-family:var(--sans);text-align:left}
.terms-accept-btn:hover{border-color:var(--accent);background:#fff}
.terms-accept-btn.accepted{background:var(--accent-soft);border-color:var(--accent)}
.terms-btn-icon{font-size:16px;color:var(--muted);line-height:1;transition:color .2s;flex-shrink:0}
/* El glifo va dentro de un <span>: el navegador lo trata como TEXTO y le aplica 4,5,
   no el 3:1 de un icono. Con --accent sobre el fondo .accepted se quedaba en 3,84. */
.terms-accept-btn.accepted .terms-btn-icon{color:var(--accent-ink)}
.terms-accept-btn span:last-child{font-size:10px;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);transition:color .2s}
.terms-accept-btn.accepted span:last-child{color:var(--accent);font-weight:500}
/* En móvil dos columnas dejan la foto en ~145px: se pierde el detalle del plato,
   que es justo lo que la foto tiene que comunicar. Una sola columna y más ancha. */
@media (max-width:560px){
  /* --gutter existe porque 2.5rem aparecía cinco veces en cuatro reglas: por eso
     nadie lo bajó nunca en móvil. A 375px el contenido pasa de 295 a 335px, y ese
     13,6% extra es lo que hace que los 12px de cuerpo quepan sin partir líneas.
     NO publicar ninguna subida de tamaño sin esto. */
  :root{--gutter:20px}
  .header{padding:24px var(--gutter) 20px}
  .stepper{padding:20px var(--gutter) 0}
  .global-tracker{padding:12px var(--gutter)}
  .screen{padding:24px var(--gutter) 32px}
  .app{padding-bottom:40px}
  /* Redondeo de las tarjetas SOLO en una columna: en dos, con un número impar de
     ingredientes la esquina inferior derecha del bloque está VACÍA y la silueta
     quedaría asimétrica. Se le da contorno completo al contenedor y cada tarjeta
     se redondea sola. 15px = 16 menos el borde de 1px: curvas concéntricas. */
  .items-grid{grid-template-columns:1fr;border:1px solid var(--border);border-radius:var(--r-md)}
  .icard{border-right:none}
  .icard:first-child{border-top-left-radius:15px;border-top-right-radius:15px}
  .icard:last-child{border-bottom:none;border-bottom-left-radius:15px;border-bottom-right-radius:15px}
  .i-photo{aspect-ratio:16/9}
  .sugg-thumb{width:60px;height:60px}
  /* La miniatura le quita ancho a la fila de controles: sin esto los tamaños,
     el precio y "+ Agregar" no caben en una línea y el botón se sale de la tarjeta. */
  .sugg-controls{flex-wrap:wrap;gap:8px}
  .sugg-sizes{flex:1 1 100%}
}
/* Reserva de la fila rótulo+valor de la banda fija, en SU propia consulta y no dentro
   del bloque de 560: con los rótulos a 12px la fila envuelve, pero solo hasta 439px
   con la cifra llena de tres dígitos ('120/120g'). Colgada de 560 dejaba 17,2px de
   aire muerto entre 440 y 560 y un escalón de 13,2px al cruzar la frontera. El límite
   es 439 y NO 430: entre 431 y 439 la fila SIGUE envolviendo y cortar antes cambia una
   regresión cosmética por una funcional. */
@media (max-width:439px){.gt-bar-top{min-height:34px}}

/* ═══════════════════════════════════════════════════════════════════════════
   MODO IA — el tamaño como respuesta
   ═══════════════════════════════════════════════════════════════════════════ */

/* A2 · CIFRAS TABULARES. Los gramos y los precios ahora cambian en cada toque:
   sin anchura fija por dígito los números bailan en horizontal a cada render. */
.i-price,.i-size-val,.i-fit,.mp b,.gt-bar-val,.gt-kcal,.res-price,.res-macs,.sugg-price,
.gap-num,.res-total-val,.mn-val,.meta-tag,.cocina-body,.cocina-propuesta,.qr-pedido{font-variant-numeric:tabular-nums}

/* ═══ COCINA · el plato se cierra contra n8n ═══
   El hueco nace con el resumen y con su altura reservada: cuando llega la
   respuesta cambia el contenido, nunca la caja. Solo se anima opacity. */
.cocina .gap-hd{display:flex;justify-content:space-between;align-items:center;gap:10px}
.cocina-estado{display:flex;align-items:center;gap:6px;white-space:nowrap;color:var(--muted-ink)}
.cocina-estado::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}
.cocina[data-estado="confirmando"] .cocina-estado::before{animation:latir 1.6s ease-in-out infinite}
.cocina[data-estado="confirmado"] .cocina-estado{color:var(--green)}
.cocina[data-estado="sin_confirmar"] .cocina-estado{color:var(--muted-ink)}
.cocina[data-estado="sin_confirmar"] .cocina-estado::before{background:transparent;border:1px solid currentColor}
.cocina[data-estado="demo"] .cocina-estado{color:var(--accent-ink)}
/* 268 px = 32 de padding + 13 líneas de 18px (12px x line-height 1.5). NO son 12
   líneas: el escalado lineal del máximo declarado antes (193px con 11px de letra)
   da 244px, que deja un cuarto de línea de margen, y los 6px de margin entre <p>
   no escalan con el font-size.
   ANTES DE PUBLICAR: volver a renderizar las 40 explicaciones reales en esta caja
   y tomar p100 + 1 línea. Estos números salen de escalar un máximo declarado, no
   de medir el corpus otra vez. Si el p100 supera 236px de contenido, subir a 286
   (14 líneas). */
.cocina-body{padding:16px 20px;min-height:268px;font-family:var(--sans);font-size:12px;line-height:1.5;color:var(--muted-ink)}
.cocina-body p{margin:0 0 6px}
.cocina-body p:last-child{margin-bottom:0}
.cocina-texto{color:var(--text)}
.cocina-aviso{color:var(--accent-ink)}
/* La discrepancia: las dos cifras, línea a línea. Es el único bloque que puede
   crecer, y solo cuando cocina calculó distinto: la pantalla ya cambia ahí. */
.cocina-disc{margin-top:10px;padding:10px 12px;border:1px solid var(--accent);background:var(--accent-soft);color:var(--text);border-radius:var(--r-sm)}
.cocina-disc-hd{font-size:9px;letter-spacing:1.5px;text-transform:uppercase;color:var(--accent);margin-bottom:6px}
/* El esqueleto crece con la caja: 8 barras de 9px + 7 márgenes de 16px = 184px,
   que tiene que quedar DENTRO de los 268px sin dejar un agujero visible (52px de
   hueco a 375 y 430px). El número de barras vive en app.js (SKEL(8)) y no se toca
   desde aquí, así que lo que escala con la reserva es el margen: ver la consulta de
   340px, donde 16px dejaban media caja vacía. */
.cocina-skel span{display:block;height:9px;border-radius:var(--r-pill);background:var(--border);margin-bottom:16px;animation:latir 1.6s ease-in-out infinite}
.cocina-skel span:nth-child(1){width:92%}.cocina-skel span:nth-child(2){width:78%}.cocina-skel span:nth-child(3){width:86%}.cocina-skel span:nth-child(4){width:64%}.cocina-skel span:nth-child(5){width:90%}.cocina-skel span:nth-child(6){width:70%}.cocina-skel span:nth-child(7){width:84%}.cocina-skel span:nth-child(8){width:44%}
.cocina-skel span:last-child{margin-bottom:0}
@keyframes latir{0%,100%{opacity:.35}50%{opacity:.9}}
/* La propuesta reservada es la MISMA tarjeta que va a llegar, con su contenido
   oculto (solo ocupa) y unas barras pintadas encima: al llegar solo cambia lo
   que hay dentro, y las dos miden lo mismo porque tienen la misma estructura. */
.cocina-propuesta[data-estado="reservado"] .sugg-main>*{visibility:hidden}
.cocina-propuesta[data-estado="reservado"] .sugg-main{background:repeating-linear-gradient(to bottom,var(--border) 0 9px,transparent 9px 22px) 0 0/82% 100% no-repeat;animation:latir 1.6s ease-in-out infinite}
.cocina-propuesta .btn-add:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* A 320 px el texto parte en más líneas: 320 px = 32 de padding + 16 líneas de
   18px. Con la métrica vieja las explicaciones reales llegaban a 243px de
   contenido; hay que REMEDIR con Inter cargada y el gutter nuevo, no escalar. */
/* A 320px la reserva sube a 320px y el esqueleto seguía midiendo 184: el agujero se
   DUPLICABA a 104px, media caja en blanco durante los 4-6s de espera y justo en la
   pantalla más estrecha. Con 23px de margen el esqueleto da 233px y el hueco 55px, la
   misma proporción que a 375px. */
@media (max-width:340px){.cocina-body{min-height:320px}.cocina-skel span{margin-bottom:23px}}
/* "Total a pagar · según cocina" es más largo: que se parta la etiqueta, no la cifra. */
.res-total-val{white-space:nowrap;flex-shrink:0;margin-left:12px}
/* 49px = TRES líneas de mono a 12px x 1.35 (48,6px), medidas, no calculadas: el id
   real que devuelve n8n ('Pedido PED-20260920170527-P01C01V01G01', 38 caracteres) no
   cabe en dos en una columna de 169px — el mono de 12px mete ~16 caracteres por línea.
   Con la reserva de 34px la caja saltaba 14,56px en el momento exacto en que llega la
   confirmación de cocina, que es lo único que este invariante existe para impedir.
   El width:100% es la otra mitad del arreglo, junto con el ancho fijo de .qr-code-wrap:
   sin ellos la contribución max-content del id ensancha la columna 'auto' de .qr-body
   de 169 a 183px y la sección entera crece 69,59px.
   Aquí NO se declaran font-size ni font-family a propósito: el barrido de micro-rótulos
   del final los pisa a 12px IBM Plex Mono con la misma especificidad, así que cualquier
   valor escrito aquí sería letra muerta (lo era: decía 9px Inter y renderizaba 12 mono). */
.qr-pedido{min-height:49px;width:100%;color:var(--muted-ink);text-align:center;word-break:break-all;line-height:1.35}

/* A3 · La tarjeta responde a otra pregunta. Ya no "¿cuánto?" sino "¿qué tan
   cerca me deja?". El pie tiene ALTURA FIJA y el mismo alto esté o no elegida
   la tarjeta: es lo que garantiza que seleccionar no mueva ni un pixel. */
/* Las dos filas llevan min-height FIJA y existen en todas las tarjetas, elegidas
   o no. Esa es la garantía de que seleccionar no mueva un solo pixel: lo que
   cambia es el contenido, nunca la caja.
   El line-height:15px en px es OBLIGATORIO: sin él, el 1.4 heredado del body da
   16,8px con 12px de letra y la reserva de 15px revienta. */
.i-fit{min-height:15px;font-size:12px;line-height:15px;font-family:var(--sans);color:var(--muted-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
/* Aquí ponía justo al revés de lo que pasa: app.js:534 devuelve {txt:'',cierra:false}
   cuando la tarjeta está ELEGIDA, así que 'Cierra tu meta' solo se pinta en tarjetas NO
   elegidas, o sea sobre --bg y no sobre --accent-soft. Y el 4,18:1 que justificaba
   bajar un paso es el del --green VIEJO (#3A7D6E): el --green actual da 6,00:1 sobre
   --bg y 5,40:1 sobre --accent-soft, pasa AA en los dos. No hacía falta ningún hex a
   mano —era el único de la hoja fuera del :root— y el token vuelve a su sitio. */
.i-fit.cierra{color:var(--green)}
.i-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:44px}
/* Continuidad deliberada con .sz-rec: el mismo filete naranja de 2px que marcaba
   "Recomendado" en las píldoras marca ahora el tamaño resuelto. */
.i-size-val{flex:1;min-width:0;font-size:11px;letter-spacing:.5px;text-transform:uppercase;
  font-family:var(--sans);color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  border-top:2px solid var(--accent);padding-top:5px}
/* En la tarjeta no elegida el filete se apaga: el tamaño aún es una hipótesis. */
.icard:not(.sel) .i-size-val{border-top-color:var(--border);color:var(--muted-ink)}
/* Categoría al tope de módulos: la tarjeta no promete nada y lo dice. El velo
   sube de .55 a .7 para que el texto atenuado siga siendo legible, y el precio
   se devuelve a opacidad plena: es un dato, no una promesa. */
.icard.tope{cursor:default}
.icard.tope .i-photo{opacity:.55}
.icard.tope .i-body>*:not(.i-fit){opacity:.7}
.icard.tope .i-price{opacity:1}
.icard.tope .i-fit{color:var(--muted-ink)}
.icard.tope:hover{background:var(--bg)}
.icard.tope:hover .i-img{transform:none}
.qr-fallo{font-family:var(--sans);font-size:10px;color:var(--muted-ink);padding:1rem;text-align:center}
/* El número de porciones en negrita: "3 PORCIONES · 390 G" se lee de un vistazo. */
.i-size-val b{font-weight:600}

/* A6 · "Ajustar" — revelación progresiva. Quien no lo toque nunca sabrá que
   existe; quien lo toque recupera el control completo. 44×44 reales. */
.btn-ajustar{min-width:44px;min-height:44px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:1px solid var(--border-strong);border-radius:var(--r-pill);color:var(--muted-ink);
  font-family:var(--sans);font-size:13px;font-weight:500;letter-spacing:-.2px;cursor:pointer;flex-shrink:0;transition:background .2s,border-color .2s}
.btn-ajustar:hover{background:var(--surface);border-color:var(--accent)}
/* Abierto = relleno, pero en --muted-ink y no en --text: con --text este toggle
   secundario daba 10,78:1 contra los 5,04:1 del CTA primario de la misma pantalla, o
   sea pesaba el DOBLE que la acción principal. Con --muted-ink el blanco encima da
   7,94:1 y se sigue leyendo como 'abierto' sin competir con 'Siguiente'. */
.btn-ajustar[aria-expanded="true"]{background:var(--muted-ink);border-color:var(--text);color:#fff}
.btn-ajustar:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.icard:not(.sel) .btn-ajustar{visibility:hidden;pointer-events:none}
/* `hidden` tiene que ganar al display:inline-flex del botón: en la tarjeta de un extra no hay nada que ajustar. */
.btn-ajustar[hidden]{display:none}
.icard:focus-visible{outline:2px solid var(--accent);outline-offset:-3px}
.icard.tope:focus-visible{outline-color:var(--muted-ink)}
/* Con offset negativo el aro se pinta DENTRO de la caja, y .i-photo es position:relative
   con z-index auto: la foto (los primeros ~213px de los 367 de la tarjeta) se pinta en
   la capa de descendientes posicionados, por encima del outline del ancestro, y se come
   el tramo superior y los laterales. Solo se veía aro en el ~42% del perímetro.
   El ::after de la tarjeta ya existe con inset:0 y z-index:3 para el pulso de recálculo,
   así que el aro se completa encendiéndolo, con un halo blanco interior para que también
   se lea sobre las fotos oscuras.
   Se deja SIN animation:none a propósito: .recalc::after es una ANIMACIÓN y las
   animaciones pisan cualquier declaración normal, así que si la tarjeta enfocada
   recalcula, el pulso sigue corriendo sus 300ms —no se pierde— y el aro vuelve al
   acabar. Apagarlo aquí sería cambiar un defecto de foco por uno de feedback. */
.icard:focus-visible::after{opacity:1;box-shadow:inset 0 0 0 2px rgba(255,255,255,.95)}

/* A5 · La línea de porqué. Convierte el control que se quitó en inteligencia
   percibida en vez de en pérdida de control.
   Filete vertical en el <span> (app.js:645 siempre lo envuelve) en vez del guion
   de 14px del ::before: marca el bloque entero aunque tenga tres líneas y no
   necesita el translateY(-4px) que hacía falta para alinearlo con la primera. */
.porque{font-family:var(--sans);font-size:12px;line-height:1.45;padding:8px 0 0;display:flex;gap:0}
.porque::before{display:none}
.porque>span{display:block;border-left:2px solid var(--accent);padding-left:10px;color:var(--text)}
.porque:empty{display:none}

/* ═══ GRASAS CUBIERTAS · aviso del paso de grasa saludable ═══
   Nace con el paso (nunca se inserta a mitad: no hay salto) y solo cambia su
   texto al elegir o quitar una grasa. Título y texto reservan altura para que
   el cambio de estado tampoco mueva nada. Solo se anima opacity.
   El padding se queda en 20px (1.25rem son 20px exactos): el ancho del texto NO
   cambia y los min-height:calc() de abajo siguen valiendo. Con 24 habría que
   remedirlos. */
.nudge{border:1px solid var(--accent);background:var(--accent-soft);padding:20px;margin-bottom:24px;border-radius:var(--r-md)}
/* Dentro del aviso el fondo ya es --accent-soft y el badge de ember perdería el canto. */
.nudge .sugg-badge{border-color:var(--accent)}
.nudge-hd{margin-bottom:.6rem}
.nudge-title{font-family:var(--sans);font-size:16px;font-weight:500;letter-spacing:-.4px;line-height:1.3;min-height:calc(16px * 1.3);margin-bottom:.4rem;color:var(--text)}
.nudge-text{font-family:var(--sans);font-size:12px;line-height:1.55;min-height:calc(12px * 1.55 * 2);color:var(--muted-ink);margin-bottom:.75rem}
.nudge-title,.nudge-text{transition:opacity .18s ease-out}
.nudge-btn{min-height:44px;display:inline-flex;align-items:center}
.nudge-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* A 375 px el título parte en dos líneas y el texto en cuatro; a 320, en cinco.
   Los valores no cambian con el rediseño, pero el cambio de familia los invalida:
   hay que RECONFIRMARLOS con Inter cargada (medido da 41,59px el título y 74,38px
   el texto a 375px, 92,97px a 320px), no darlos por buenos. */
@media (max-width:560px){.nudge-title{min-height:calc(16px * 1.3 * 2)}.nudge-text{min-height:calc(12px * 1.55 * 4)}}
@media (max-width:340px){.nudge-text{min-height:calc(12px * 1.55 * 5)}}
/* Y por ARRIBA de 560 la reconfirmación también faltaba: entre 561 y 573px manda la
   regla base de 2 líneas, pero el texto del estado 'encima' necesita 3 en Inter, así
   que al tocar una grasa el aviso encogía 18,59px con el dedo todavía en la pantalla.
   El límite es 573 y NO 574: a 574 el texto ya cabe en dos líneas y un pixel más de
   banda solo metería 18,6px de aire muerto. */
@media (min-width:561px) and (max-width:573px){.nudge-text{min-height:calc(12px * 1.55 * 3)}}

/* A4 · El recálculo tiene que verse, o la app parece hacer cosas a espaldas del
   usuario. Solo opacity y transform: nunca width ni height.
   .mp entra en el crossfade: setTexto (app.js:632) le pone opacity 0 y lo devuelve
   a 1 dos rAF después, y sin transición eso es un parpadeo, no un fundido. */
.i-price,.i-size-val,.i-fit,.mp{transition:opacity .18s ease-out}
.recalc::after{animation:pulseBorder .3s ease-out}
@keyframes pulseBorder{
  0%{opacity:0}
  40%{opacity:1}
  100%{opacity:0}
}

/* ═══════════════════════════════════════════════════════════════════════════
   REPASO TIPOGRÁFICO Y DE FOCO — va AL FINAL y ANTES de prefers-reduced-motion.
   Estos bloques barren de una vez los tamaños, familias y colores que arriba
   quedaron repartidos regla a regla.
   ═══════════════════════════════════════════════════════════════════════════ */

/* El mono es el rótulo en mayúscula con tracking, y nada más: es el único papel
   que IBM Plex Mono tiene en la landing. La mayúscula monoespaciada mide ~0,6em
   contra ~0,72em de la proporcional, así que subir de 9 a 12px sale casi gratis
   de ancho. .gt-bar-lbl, .gap-lbl y .mn-lbl bajan a .02em porque viven en celdas
   de rejilla donde 'Proteína' es una palabra que no se puede partir. */
.eyebrow,.sec-lbl,.s-lbl,label,.gt-lbl,.gt-bar-lbl,.meta-ey,.mn-lbl,.cat-nm,.sugg-badge,
.sugg-macro-tag,.meta-tag,.res-total-lbl,.res-extra-tag,.gap-hd,.gap-lbl,.qr-hd-lbl,
.qr-hd-tag,.qr-inst-title,.qr-code-wrap p,.qr-pedido,.terms-title,.cocina-disc-hd,
.terms-accept-btn span:last-child{font-family:var(--mono);font-size:12px;font-weight:400;letter-spacing:.04em;line-height:1.35}
/* el color: a 12px aplica 4,5:1 sin excepción.
   .cat-nm NO entra: es el TÍTULO de la sección de ingredientes y su --text ya daba
   10,78:1, o sea que no había nada que corregir. Al barrerlo quedaba del mismo color
   que su propia pista .cat-ht, que es más larga y va en Inter proporcional, y pesaba
   más que el título. Se queda en la lista de mono de arriba, así que conserva sus 12px
   de IBM Plex Mono; lo que recupera es el escalón de color. */
.eyebrow,.sec-lbl,.s-lbl,label,.gt-lbl,.gt-bar-lbl,.meta-ey,.gap-hd,.gap-lbl,.qr-hd-lbl,
.qr-inst-title,.res-total-lbl,.terms-title,.qr-code-wrap p,.qr-pedido,
.terms-accept-btn span:last-child,.tagline{color:var(--muted-ink)}
.sugg-macro-tag,.cocina-disc-hd,.s-lbl.active,.terms-accept-btn.accepted span:last-child{color:var(--accent-ink)}
/* los dos que necesitan aire para no forzar su celda */
.gt-bar-lbl,.gap-lbl,.mn-lbl{letter-spacing:.02em}

/* El resto del cuerpo a 12px Inter: se acaban los 9 y 10px de texto de lectura.
   .rec-lbl NO entra aquí aunque comparta tamaño: es un micro-rótulo en mayúscula
   y se queda en mono con su line-height:12px en px, sin el cual el 1.4 heredado del
   body le daría 16,8. Ojo: lo que sostiene los 44px de .sz-pill NO es esa pila, sino
   el padding-top:5px de .sz-rec, que compensa su borde de 2px (ver arriba).
   .i-size-val y .ss-pill tampoco entran: siguen en text-transform:uppercase y este
   barrido les imponía -.2px, o sea tracking NEGATIVO en una versal, matando el .5px y
   el 1px que llevaban escritos a mano. Van justo debajo con su tracking positivo.
   Los !important pisan estilos EN LÍNEA de app.js (333, 731, 1096): no hay otra forma
   desde la hoja. */
.mp,.sugg-desc,.sugg-why,.qr-inst-detail,.form-error,.meta-warn,.qr-fallo,.cat-ht,
.res-sub,.res-mac,.mn-unit,.od,.ad,.on,.an,.sugg-ok-lbl,.gt-bar-val{font-family:var(--sans);font-size:12px;letter-spacing:-.2px}
/* Las dos versales del cuerpo: mismo tamaño y misma familia que el barrido de arriba,
   pero el tracking al derecho. Probado a 320px: .i-foot se queda en 44px y el aire
   extra lo absorbe el ellipsis de .i-size-val, que ya va con nowrap y min-width:0. */
.i-size-val,.ss-pill{font-family:var(--sans);font-size:12px;letter-spacing:.5px}
.gt-bar-val{font-weight:600}
.mn-unit{font-size:12px!important}   /* app.js:333 lo pinta con style="font-size:9px" en línea */
.sugg-ok-lbl[style]{font-size:12px!important;color:var(--muted-ink)!important}  /* inline de app.js:731 */
.qr-inst-text span[style]{font-size:12px!important}  /* el '(extra)' inline de app.js:1096 */
.qr-inst-text{--accent:var(--accent-ink)}  /* alcanza el color de ese inline sin !important */
/* color de lo que estaba en --light (2,01:1) o --muted (3,46:1) */
.od,.ad,.res-sub,.mn-unit,.cat-ht,.sugg-desc,.sugg-why,.qr-inst-detail,.meta-ctx,
.manual-note,.terms-text,.sugg-ok-lbl,.ss-pill{color:var(--muted-ink)}
/* 'Sedentario' y 'Rendimiento' no tienen punto de corte: con minmax(0,1fr) en las
   rejillas y hyphens:auto la palabra se parte bien en vez de estirar su pista. */
.on,.an,.od,.ad{hyphens:auto}

/* Display: Inter 300/500 con el tracking negativo de la marca.
   La .tagline ya no necesita aquí su text-transform:none: se le quitó el uppercase en
   la propia regla de arriba, al devolverla a Inter 350 como en la landing. */
.i-name,.sugg-name,.res-name{font-weight:500;letter-spacing:-.2px}
.qr-inst-text{letter-spacing:-.2px}

/* El foco de teclado. outline y NO box-shadow: es lo único que sobrevive al modo
   de contraste forzado, donde el box-shadow se descarta y el outline:none de input
   dejaría el campo sin foco. Los tres outline-color en blanco son para los
   controles cuyo fondo ES naranja: con offset negativo el aro se dibujaba dentro y
   quedaba a 1,00:1 contra su propio relleno.
   .btn-main:focus-visible tiene que ir DESPUÉS de .btn:focus-visible: empatan y se
   deciden por orden de fuente (y todos los .btn-main del HTML llevan también .btn,
   así que heredan de ahí el ancho y el estilo del trazo). */
.btn:focus-visible,.btn-add:focus-visible,.sz-pill:focus-visible,.terms-accept-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.btn-main:focus-visible{outline-color:var(--text);outline-offset:3px}
.mt-btn.mt-active:focus-visible,.st-btn.st-active:focus-visible,.ss-pill.ss-on:focus-visible{outline-color:#fff}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--accent-ink);outline-offset:2px}
input.invalid:focus-visible{outline-color:var(--danger)}

/* Estado pulsado: no existía ninguno. .sz-pill y .btn-ajustar NO llevan scale a
   propósito: viven dentro de .icard, que también es clicable, y sus handlers hacen
   stopPropagation en el CLICK, no en el mousedown; si el dedo se suelta en la
   franja que libera el encogido, el click sube a la tarjeta y tocar un tamaño
   deselecciona el ingrediente. */
.btn:not(:disabled):active,.btn-add:active,.terms-accept-btn:active{transform:scale(.97)}
.sz-pill:not(.sz-on):active,.btn-ajustar:not([aria-expanded="true"]):active{background:var(--surface)}
.mt-btn:not(.mt-active):active,.st-btn:not(.st-active):active,.ss-pill:not(.ss-on):active{background:var(--border);color:var(--text)}
.obj-card:not(.selected):active,.act-card:not(.selected):active{background:var(--accent-soft)}

/* Enumerar selectores dejaba fuera todo lo preexistente: el check al seleccionar,
   la entrada de pantalla, los puntos del stepper y las propias barras de macros
   seguían moviéndose con reduce activo. Se apaga TODO y luego se exceptúa nada. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;
    scroll-behavior:auto!important;
  }
  .icard:hover .i-img{transform:none}
  /* El selector se repite IDÉNTICO, con su :not(:disabled): una media query no
     suma especificidad y .btn:not(:disabled):active pesa 0-3-0, así que un
     .btn:active de 0-2-0 NO lo ganaría y el botón principal seguiría encogiendo. */
  .btn:not(:disabled):active,.btn-add:active,.terms-accept-btn:active{transform:none}
  /* El hover del primario levanta 2px: con reduce y las duraciones a .01ms eso deja de
     ser un fundido de 250ms y pasa a ser un SALTO instantáneo al pasar el puntero.
     Empata en 0-2-0 con la regla de arriba y gana por orden de fuente. */
  .btn-main:hover{transform:none}
}

/* ── Shell de pestañas · Pedir / Diario / Entrenar ──────────────────────────
   La tabbar es fija abajo (patrón de app móvil); el padding del body reserva
   su espacio para que ningún contenido quede tapado. Solo tokens existentes. */
body{padding-bottom:calc(64px + env(safe-area-inset-bottom))}
.vista-modulo[hidden]{display:none}
.tabbar{position:fixed;left:0;right:0;bottom:0;z-index:100;display:flex;background:var(--surface);border-top:1px solid var(--border);padding-bottom:env(safe-area-inset-bottom)}
.tab-btn{flex:1;min-height:56px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;background:none;border:0;cursor:pointer;color:var(--muted-ink);font-family:var(--sans);font-size:11px;letter-spacing:.4px}
.tab-btn svg{width:22px;height:22px}
/* --accent-deep: --accent-ink sobre --surface se queda en 4,43 y AA pide 4,5
   (mismo arreglo que .gt-kcal, documentado arriba en la hoja). */
.tab-btn[aria-current="page"]{color:var(--accent-deep)}
.tab-btn:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.btn-diario{display:block;width:100%;min-height:48px;margin-top:10px;background:none;border:1px solid var(--accent);color:var(--accent-ink);border-radius:var(--r-md);font-family:var(--sans);font-size:13px;cursor:pointer}
.btn-diario:disabled{opacity:.6;cursor:default}
.btn-diario.ok{border-color:var(--green);color:var(--green)}
.btn-diario:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.modulo-error{color:var(--muted-ink);font-family:var(--sans);font-size:13px;padding:24px 16px;text-align:center}

/* ── Pantalla Hoy · puerta de entrada ─────────────────────────────────────── */
main[hidden]{display:none}
.hoy-resumen{margin-top:14px}
.hoy-kcal{font-family:var(--mono, 'IBM Plex Mono', monospace);font-size:12px;color:var(--text);font-variant-numeric:tabular-nums}
.hoy-barras{padding:14px 20px 18px;display:grid;gap:12px}
.hoy-sin-meta{margin-top:14px;padding:16px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);display:grid;gap:12px;justify-items:start}
/* display:grid le gana al [hidden] del navegador: sin esta regla la caja
   "Crear mi perfil" se pintaba SIEMPRE, también con el perfil ya creado. */
.hoy-sin-meta[hidden]{display:none}
/* El encabezado del panel de Hoy reusa .gap-hd, que solo es flex en cocina:
   sin esto la cifra se pegaba al rótulo ("TU DÍA0 / 2256 KCAL"). */
.hoy-resumen .gap-hd{display:flex;justify-content:space-between;align-items:center;gap:10px}
.hoy-nota{margin:0;padding:0 20px 16px}
.hoy-acciones{margin-top:14px;display:grid;gap:10px}
.hoy-card{display:flex;gap:14px;align-items:center;min-height:64px;padding:14px 16px;width:100%;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);cursor:pointer;text-align:left;font-family:var(--sans)}
.hoy-card svg{width:26px;height:26px;color:var(--accent-ink);flex-shrink:0}
.hoy-card-accent{border-color:var(--accent)}
.hoy-card:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.hc-t{font-size:14px;font-weight:600;color:var(--text)}
.hc-s{font-size:12px;color:var(--muted-ink);margin-top:2px;line-height:1.5}
.hoy-ultimo{margin-top:14px}

/* ── Correcciones de la auditoría r2 ─────────────────────────────────────── */
/* hidden SIEMPRE gana: tres bugs distintos venían de reglas de autor con
   display pisando el [hidden] del navegador. Se corta la clase entera. */
[hidden]{display:none!important}
/* Hoy era la única vista sin gutter: su contenido pegaba al borde físico. */
#vista-hoy{padding:2.5rem var(--gutter) 1.5rem}
/* En modo demo no llega respuesta de cocina: la reserva de 268px dejaba un
   hueco vacío permanente bajo dos líneas de texto. */
.cocina[data-estado="demo"] .cocina-body{min-height:0}

/* ── Correcciones de la auditoría r4 ─────────────────────────────────────── */
h1.stitle,h2.stitle{margin-top:0}
/* La pestaña activa no puede distinguirse SOLO por color (1,10:1 entre tonos):
   peso y una barra superior la marcan también en escala de grises. */
.tab-btn[aria-current="page"]{font-weight:600;box-shadow:inset 0 2px 0 var(--accent-deep)}
/* El foco de teclado nunca queda debajo de la tabbar ni de la barra de
   descanso (WCAG 2.4.11): el desplazamiento al enfocar respeta su altura. */
html{scroll-padding-bottom:calc(72px + env(safe-area-inset-bottom))}
html:has(.en-descanso:not([hidden])){scroll-padding-bottom:calc(180px + env(safe-area-inset-bottom))}
/* En Hoy y Diario las barras van en una sola columna ancha: la reserva de dos
   líneas del tracker de Pedir dejaba cada rótulo pegado a la barra de arriba. */
.hoy-barras .gt-bar-top,.dia-barras .gt-bar-top{min-height:0}
.hoy-editar{display:block;min-height:44px;margin:0 20px 8px;padding:0;background:none;border:0;color:var(--accent-ink);font-family:var(--sans);font-size:13px;cursor:pointer;text-align:left}
.hoy-editar:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* El botón del diario ahora va ARRIBA del resumen. */
#btn-diario-plato{margin:0 0 16px}

/* ═══ Hoy cálida (2-oct-2026) ═══════════════════════════════════════════════
   Saludo según la hora, el día en un anillo sobre lavado --ember, fotos del
   menú y la semana. Solo tokens; los únicos colores derivados son mezclas de
   tokens (color-mix) para los círculos de icono. Contraste medido: --text y
   --muted-ink sobre --ember 8,10 y 5,72; texto naranja sobre --ember SOLO en
   --accent-deep (5,20). Movimiento: solo transform/opacity y --pd del anillo;
   el barrido de prefers-reduced-motion lo deja todo en .01ms. */
@property --pd{syntax:'<number>';inherits:false;initial-value:0}
.hoy-saludo{font-size:30px;margin-bottom:6px}
.hoy-frase{margin-bottom:20px}
/* Tu día */
.hoy-dia{margin-top:4px;padding:18px 18px 16px;border-radius:var(--r-md);border:1px solid var(--border);background:linear-gradient(160deg,var(--ember) 0%,var(--accent-soft) 58%,var(--bg) 100%);box-shadow:var(--lift-sticky)}
.hoy-dia-hd{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:6px}
.hoy-dia-t{margin:0;font-family:var(--mono);font-size:12px;font-weight:400;letter-spacing:.04em;text-transform:uppercase;color:var(--text)}
.hoy-dia .hoy-editar{margin:0;color:var(--accent-deep);font-size:13px;text-decoration:underline;text-underline-offset:3px}
.hoy-anillo-fila{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:8px;margin:6px 0 16px}
.hoy-lado{display:flex;flex-direction:column;align-items:center;gap:2px;text-align:center}
.hoy-lado-n{font-size:20px;font-weight:500;color:var(--text);font-variant-numeric:tabular-nums}
.hoy-lado-l{font-family:var(--mono);font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted-ink)}
.hoy-anillo{--pd:0;position:relative;width:132px;aspect-ratio:1;border-radius:50%;background:conic-gradient(var(--accent-ink) calc(var(--pd) * 1turn),var(--bg) 0);transition:--pd .8s cubic-bezier(.2,.8,.2,1)}
.hoy-anillo-over{background:var(--accent-deep)}
.hoy-anillo-c{position:absolute;inset:11px;border-radius:50%;background:var(--bg);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;text-align:center}
.hoy-anillo-n{font-size:26px;font-weight:500;letter-spacing:-.6px;color:var(--text);font-variant-numeric:tabular-nums;line-height:1}
.hoy-anillo-l{font-size:11px;line-height:1.25;color:var(--muted-ink);max-width:76px}
.hoy-macros{display:grid;gap:10px}
.hoy-mac{display:grid;grid-template-columns:72px 1fr 68px;align-items:center;gap:10px}
.hoy-mac-l{font-family:var(--mono);font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted-ink)}
.hoy-mac-v{font-size:12px;color:var(--text);text-align:right;font-variant-numeric:tabular-nums}
.hoy-mac .bar-bg{background:var(--bg)}
.hoy-dia .hoy-nota{padding:0;margin:8px 0 0;color:var(--muted-ink)}
/* Sesión en curso: urgente, arriba */
.hoy-ultimo{margin:0 0 14px}
.hoy-retomar{display:flex;align-items:center;gap:12px;width:100%;min-height:56px;padding:12px 16px;border:1px solid var(--green);border-radius:var(--r-md);background:var(--bg);cursor:pointer;text-align:left;font-family:var(--sans)}
.hoy-retomar span:last-child{display:flex;flex-direction:column;gap:2px}
.hoy-retomar b{font-size:14px;font-weight:600;color:var(--text)}
.hoy-retomar small{font-size:12px;color:var(--muted-ink)}
.hoy-retomar-pt{width:10px;height:10px;border-radius:50%;background:var(--green);flex-shrink:0;animation:latir 1.6s ease-in-out infinite}
/* Acciones: icono en círculo de color, chevron, prensado */
.hoy-acciones{margin-top:18px;gap:10px}
.hoy-card{gap:14px;min-height:72px;padding:12px 14px;background:var(--bg);transition:transform .15s,background-color .2s}
.hoy-card:hover{background:var(--surface)}
.hoy-card:active{transform:scale(.985)}
.hoy-card-accent{border-color:var(--accent);background:var(--accent-soft)}
.hoy-card-txt{flex:1;min-width:0;display:flex;flex-direction:column}
.hoy-ico{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.hoy-card .hoy-ico svg{width:22px;height:22px}
.hoy-ico-pedir{background:var(--ember)}
.hoy-ico-pedir svg{color:var(--accent-ink)}
.hoy-ico-diario{background:color-mix(in srgb,var(--green) 16%,var(--bg))}
.hoy-ico-diario svg{color:var(--green)}
.hoy-ico-entrenar{background:color-mix(in srgb,var(--blue) 16%,var(--bg))}
.hoy-ico-entrenar svg{color:var(--blue)}
.hoy-chev{width:18px;height:18px;color:var(--muted-ink);flex-shrink:0}
.hc-t{font-weight:500}
/* Secciones */
.hoy-sec-t{margin:0;font-family:var(--mono);font-size:12px;font-weight:400;letter-spacing:.04em;text-transform:uppercase;color:var(--text)}
/* Tu semana */
.hoy-semana{margin-top:26px}
.hoy-sem-dias{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;list-style:none;margin:12px 0 8px;padding:0}
.hoy-sem-dia{display:flex;flex-direction:column;align-items:center;gap:6px}
.hoy-sem-l{font-family:var(--mono);font-size:12px;color:var(--muted-ink);text-transform:uppercase}
.hoy-sem-hoy .hoy-sem-l{color:var(--text);font-weight:600}
.hoy-sem-pt{width:28px;height:28px;border-radius:50%;background:var(--surface);border:1px solid var(--border)}
.hoy-sem-pt.con-comida{background:var(--accent-ink);border-color:var(--accent-ink)}
.hoy-sem-pt.con-entreno{box-shadow:0 0 0 3px var(--bg),0 0 0 5px var(--green)}
.hoy-sem-hoy .hoy-sem-pt{outline:1px dashed var(--border-strong);outline-offset:9px}
.hoy-sem-ley{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px;margin:4px 0 0;font-size:12px;color:var(--muted-ink)}
.hoy-pt{display:inline-block;width:10px;height:10px;border-radius:50%}
.hoy-pt-comida{background:var(--accent-ink)}
.hoy-pt-entreno{box-shadow:inset 0 0 0 2px var(--green);margin-left:6px}
/* Del menú: carrusel con foto y macros; se asoma la siguiente tarjeta */
.hoy-menu{margin-top:26px}
.hoy-menu-hd{display:flex;align-items:center;justify-content:space-between;gap:12px}
.hoy-menu-ver{min-height:44px;padding:0 4px;background:none;border:0;color:var(--accent-deep);font-family:var(--sans);font-size:13px;cursor:pointer;text-decoration:underline;text-underline-offset:3px}
.hoy-carrusel{display:flex;gap:12px;list-style:none;margin:8px calc(-1 * var(--gutter)) 0;padding:4px var(--gutter) 12px;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding:0 var(--gutter);scrollbar-width:none}
.hoy-carrusel::-webkit-scrollbar{display:none}
.hoy-carrusel li{flex:0 0 172px;scroll-snap-align:start}
.hoy-plato{display:flex;flex-direction:column;gap:4px;width:100%;padding:0 0 12px;border:1px solid var(--border);border-radius:var(--r-md);background:var(--bg);overflow:hidden;text-align:left;cursor:pointer;font-family:var(--sans);transition:transform .15s}
.hoy-plato:active{transform:scale(.98)}
.hoy-plato img{width:100%;aspect-ratio:4/3;height:auto;object-fit:cover;display:block;background:var(--surface);margin-bottom:6px}
.hoy-plato-cat{padding:0 12px;font-family:var(--mono);font-size:12px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted-ink)}
.hoy-plato-n{padding:0 12px;font-size:14px;font-weight:500;line-height:1.3;color:var(--text);min-height:36px}
.hoy-plato-mac{display:flex;align-items:baseline;gap:8px;padding:0 12px;font-size:12px;font-variant-numeric:tabular-nums}
.hoy-plato-mac b{font-weight:600}
.m-p{color:var(--green)}.m-c{color:var(--blue)}.m-g{color:var(--amber)}
.hoy-plato-pr{margin-left:auto;color:var(--text);font-weight:500}
/* Bienvenida (primera visita) */
.hoy-bienvenida{margin-top:4px;border:1px solid var(--border);border-radius:var(--r-md);background:var(--accent-soft);overflow:hidden;box-shadow:var(--lift-sticky)}
.hoy-bv-foto{width:100%;aspect-ratio:16/9;height:auto;object-fit:cover;display:block;background:var(--surface)}
.hoy-bv-cuerpo{padding:18px}
.hoy-bv-t{margin:0 0 12px;font-size:20px;font-weight:400;letter-spacing:-.4px;line-height:1.25;color:var(--text)}
.hoy-bv-pasos{margin:0 0 16px;padding-left:20px;font-size:14px;line-height:1.6;color:var(--muted-ink)}
.hoy-bv-pasos b{color:var(--text);font-weight:500}
.hoy-bv-cta{width:100%}
.hoy-retomar:focus-visible,.hoy-plato:focus-visible,.hoy-menu-ver:focus-visible,.hoy-dia .hoy-editar:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
