/* ============================================================
   MÉTODO 500 — RPG · Sistema de diseño
   Paleta: grafito cálido + acento "amanecer" (naranja→rosa; el nombre original de la
   app venía de entrenar a las 5:30 AM, de ahí el acento) en ratio 90/10, más un verde "energía" para estado/
   progreso. Tipografía: Space Grotesk para números grandes y títulos (carácter
   deportivo, geométrico) + Inter para texto de lectura + JetBrains Mono para
   etiquetas/datos técnicos. Pensado para verse como app nativa (Strava/Whoop/NTC),
   no plantilla healthtech genérica. Ver bloque "IDENTIDAD RPG ELEVADA" al final del
   archivo para el sistema de tarjetas/tipografía activo.
   ============================================================ */
/* Las fuentes NO se cargan aquí: un @import sólo se descubre después de bajar y parsear
   este archivo, así que encadenaba cuatro viajes en serie (HTML -> estilos.css -> CSS de
   Google -> woff2) antes de que el texto se viera con su tipografía. Ahora van como <link>
   en el <head> de index.html, junto a un preconnect a fonts.gstatic.com. */

:root {
  /* ---- GRAMÁTICA DE LUZ (ver el bloque del mismo nombre al final del archivo) ----
     La app se llama "Método 500" por entrenar a las 5:30 AM, el mapa se llama "El Camino
     del Alba" y los rangos son "Recluta del Alba"/"Capitán del Amanecer". Ese vocabulario
     ya existía; lo que faltaba era que la interfaz lo obedeciera. La regla, y de ella sale
     todo lo de abajo:

       LA LUZ SIGNIFICA "AHORA". Todo lo demás se retira.

     De ahí tres consecuencias concretas:
     1) UN solo elemento encendido por pantalla — el ámbar queda RESERVADO a la próxima
        acción. Antes se gastaba en el "+XP" de cada una de las 9 misiones, o sea que el
        color de marca aparecía nueve veces y ya no señalaba nada.
     2) Las superficies se separan por LUZ, no por línea. Una tarjeta se ve porque le da
        la luz (escalón de luminancia + reflejo superior), no porque tenga un filo
        dibujado. Eso es literalmente lo "suave": quitar los cantos. Por eso los tokens
        --line* de abajo son casi invisibles: bajarlos aquí ablanda de golpe los ~40
        `border: 1px solid var(--line)` repartidos por el archivo sin tocar ni una regla.
     3) Terminar APAGA, no enciende. Una misión cumplida se atenúa y se quita de en medio
        (.quest.done al final del archivo). La celebración sigue siendo un momento —el
        toast de XP, el golpe al jefe— pero deja de ocupar peso visual para siempre.
        Es lo contrario de lo que hace el género, y es a propósito: el premio por
        terminar algo es que deje de pedirte atención.

     Antes había SIETE familias de acento compitiendo (ámbar, coral, violeta, cian, verde,
     teal y oro). En 390px eso es aritméticamente incompatible con "suave". Ahora hay dos
     —cálida (alba = ahora) y fría (info = solo información)— más tres estados. Varios
     tokens viejos se mantienen con su nombre pero REAPUNTADOS a la familia nueva
     (--violet → gris, --gold → hermano del ámbar, --cyan → el neutro frío): así sus ~90
     usos se calman solos, sin tener que editar cada sitio y sin romper nada. Si vas a
     "restaurar" alguno a su color original, estás reintroduciendo una octava familia. */
  --bg: #0A0B10;            /* noche: azulada, no gris neutro — es el suelo del amanecer */
  --bg-elev: #101219;
  --panel: #15171F;
  --panel2: #1B1E28;
  --panel3: #232734;
  /* Casi invisibles a propósito: la separación la hace la luz, no la línea (ver arriba) */
  --line: rgba(255,255,255,.045);
  --line-soft: rgba(255,255,255,.028);
  --hairline: rgba(255,255,255,.07);
  --text: #F2EFE9;          /* blanco cálido: luz sobre una pared, no papel */
  --muted: #8A8FA0;         /* gris azulado: se retira hacia la noche en vez de competir */
  --amber: #e8935a;         /* acento de marca: punto medio del degradado amanecer */
  --amber-hi: #ffb15e;       /* extremo cálido del degradado */
  --amber-lo: #ef7d6e;       /* extremo rosado del degradado */
  --sunrise: linear-gradient(120deg, var(--amber-hi), var(--amber-lo));
  --coral: #DE7065;         /* estado: peligro/destructivo — el único que sí puede gritar */
  --info: #8FA3B8;          /* neutro frío: "esto es solo información", nunca una acción */
  --violet: #8A8FA0;        /* reapuntado a gris: el comentario viejo decía "neutralizado"
                               pero seguía siendo un violeta con vida propia */
  --cyan: var(--info);      /* reapuntado: era un séptimo acento haciendo de neutro */
  --green: #6FAE86;         /* éxito, desaturado: con "terminar apaga", pesa menos */
  /* Acento del perfil GLP-1: es su propia familia, separada del verde de "éxito" a
     propósito (aquí marca una sección, no un estado cumplido). Vivía como hex crudo
     repetido en 9 sitios del CSS y del JS, que era la única zona de la app sin token.
     Bajado de saturación (#2DD4A7 → #46B99B) para que no le gane al ámbar de marca. */
  --teal: #46B99B;          /* acento GLP-1: badges, bordes, títulos de sección */
  --teal-hi: #8FD9C6;       /* variante clara: texto sobre fondo teal oscuro */
  --teal-bg: #0F241F;       /* fondo de sección GLP-1 */
  --teal-line: #23503F;     /* borde de sección GLP-1 */
  --green-lo: #4A8F6B;
  --gold: #D69C5A;          /* reapuntado: hermano apagado del ámbar, no una familia aparte */
  /* Excepción deliberada y acotada a los anillos de progreso del dashboard (kcal/proteína/
     agua, estilo Apple Fitness/Whoop — pedido explícito de producto para que Inicio lea
     más "app de fitness real"). NO es una vuelta a las siete familias de acento de arriba:
     --mint/--aqua se usan SOLO dentro de .rings-card, en ningún otro componente, así que
     la regla de "un acento cálido + uno frío" se mantiene intacta en el resto de la app. */
  --mint: #3DD68C;          /* anillo de proteína */
  --aqua: #2FC2E8;          /* anillo de agua */
  /* Cajas de nota/alerta. Existían tres veces cada una, retecleadas a mano en CSS y en JS
     (#2A2410 vs #2A2210 delataba el copy-paste). Ahora hay un token por familia. */
  --note-info-bg: #141A24;   --note-info-line: #26374A;
  --note-warn-bg: #241E12;   --note-warn-line: #4E4324;
  --note-danger-bg: #261319; --note-danger-line: #5A2A31;
  /* ---- Ritmo: escalas reales donde antes había valores a ojo ----
     El espaciado usaba casi todos los enteros de 1 a 16px y el radio tenía 17 valores
     distintos (7, 9, 14, 18, 22...). No se nota como "un error" en ningún sitio concreto;
     se nota como que la app va apretada. Estas escalas se aplican en el bloque de
     gramática del final, que es donde vive el ritmo general (tarjeta, misión, título). */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px;
  --r1: 8px; --r2: 14px; --r3: 20px; --rp: 999px;
  /* ---- Escala tipográfica ----
     Piso de 10px, y reservado a versalitas con tracking (.mono-tag, .stat .l,
     .sobrio-divider, .grupo-mis): en caja alta y espaciadas se leen más grandes que su
     tamaño nominal. El texto normal no baja de 11px. Había un 8px y dos 9px que no se
     defendían a ninguna distancia de lectura, y un 9.5/11.5/19/21 que eran deriva, no
     escalones — colapsados a los pasos vecinos.
     Ahora sí hay tokens. No sustituyen los ~21 tamaños sueltos de un golpe (son
     demasiados sitios para tocarlos a ciegas, y el 12.5/13.5 sigue vivo donde estaba);
     los usa el bloque de gramática del final para fijar los tamaños que SÍ mandan en la
     jerarquía: título de tarjeta, nombre de misión, dato numérico, texto de apoyo. */
  --t-micro: 10.5px;  /* solo versalitas con tracking */
  --t-xs: 11px;  --t-s: 12px;  --t-m: 13px;  --t-b: 15px;
  --t-l: 17px;   --t-xl: 20px; --t-2xl: 26px; --t-3xl: 34px;
  --font-display: 'Space Grotesk', 'Inter', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;
  /* ---- La firma: el fondo amanece con tu día ----
     0 = noche (ninguna misión core cerrada), 1 = amanecer (día perfecto). Lo actualiza
     pintarAlba() en 16-inicio.js a partir de coreIds()/d.checks, que ya existían para el
     bonus de "día perfecto" — no hay estado nuevo que guardar ni que sincronizar.
     Es toda la gamificación dicha como atmósfera en lugar de como insignias. */
  --alba: 0;
  /* ---- Escala de elevación (4 niveles + el brillo de acento) ----
     Antes había dos escalas compitiendo: estos tokens (de los que --shadow-lift y
     --shadow-glow no se usaban en NINGÚN componente) y una decena de valores sueltos
     escritos a mano, con seis desenfoques distintos entre 10px y 34px. Ahora cada
     superficie elevada sale de aquí, así que subir o bajar la profundidad de toda la
     app es cambiar estas cinco líneas.
       card  → superficie en reposo (tarjeta, panel)
       lift  → algo despegado del fondo pero dentro del flujo (nodo de mapa, comida)
       pop   → flota por encima del contenido (arena del jefe, sheet, toast)
       stuck → la arena ya pegada arriba: se aplana para no tapar lo que pasa debajo
       glow  → único brillo de acento, reservado a la acción primaria */
  --shadow-card: 0 1px 2px rgba(0,0,0,.25);
  --shadow-lift: 0 4px 14px rgba(0,0,0,.28);
  --shadow-pop: 0 14px 32px rgba(0,0,0,.34);
  --shadow-stuck: 0 2px 10px rgba(0,0,0,.3);
  --shadow-glow: 0 8px 22px rgba(232,147,90,.30);
  /* Altura del HUD fijo. Incluye el safe-area superior (isla dinámica/notch del iPhone en
     modo instalado): así el body y la barra de pestañas se desplazan lo justo y el menú
     NO queda tapado detrás del HUD al hacer scroll hacia arriba. */
  --hud-h: calc(92px + env(safe-area-inset-top));
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--text);
  font-family: 'Inter', system-ui, sans-serif; -webkit-text-size-adjust: 100%; }
/* LA FIRMA: una sola fuente de luz, fija a la pantalla (no al documento), que amanece
   conforme cierras el día. --alba va de 0 a 1 (ver :root y pintarAlba() en 16-inicio.js).
   Va en un ::before con position:fixed y no como background-image del body a propósito:
   un degradado en el body se estira al alto TOTAL del documento, así que en la Ficha
   (8000px de scroll) la "luz" quedaba diluida en la nada y en el dashboard quedaba
   concentrada — la misma variable se veía distinta en cada pestaña. Fijo a la ventana,
   la luz es la de la habitación y no la de la página.
   El alfa se interpola con calc() dentro del rgba: verificado en Chromium, calc() sí
   resuelve en el canal alfa. La transición es lenta (1.6s) para que al marcar una misión
   se perciba como que la luz sube, no como un parpadeo. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(130% 62% at 50% -8%,
      rgba(255,177,94, calc(.030 + var(--alba) * .085)) 0%,
      rgba(239,125,110, calc(.014 + var(--alba) * .030)) 34%,
      transparent 68%);
  transition: background 1.6s cubic-bezier(.22,1,.36,1);
}
button { font-family: inherit; cursor: pointer; }
.display { font-family: var(--font-display); font-weight: 700; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; }
/* Etiqueta micro monoespaciada: tensión tipográfica frente a los títulos display */
.mono-tag { font-family: var(--font-mono); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }

/* ---------- HUD fijo ---------- */
#hud {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  /* Más translúcido que antes (.72 en vez de .8) porque ahora la luz del alba vive
     DETRÁS, en body::before: el HUD la filtra en vez de traer la suya. */
  background: rgba(16,18,25,.72);
  backdrop-filter: blur(22px) saturate(1.2);
  -webkit-backdrop-filter: blur(22px) saturate(1.2);
  border-bottom: 1px solid var(--line-soft);
  box-shadow: inset 0 -1px 0 rgba(255,255,255,.02);
  padding: calc(8px + env(safe-area-inset-top)) 14px 10px;
  transition: padding .28s cubic-bezier(.22,1,.36,1);
}
/* El HUD tenía su PROPIO resplandor de amanecer clavado al 8% de la izquierda, además
   del degradado del body al 15%. Dos focos de luz en ángulos distintos es justo lo que
   hace que una pantalla se vea "compuesta por partes". Ahora hay uno solo (body::before,
   centrado arriba) y el HUD simplemente lo deja pasar por su backdrop-filter. */
/* HUD compacto: se encoge al hacer scroll, como una app nativa */
#hud.compact { padding: calc(3px + env(safe-area-inset-top)) 14px 5px; }
#hud.compact .badge { width: 38px; height: 38px; }
#hud.compact .badge-inner { width: 32px; height: 32px; }
#hud.compact .badge-lvl { font-size: 14px; }
#hud.compact .badge-sub { display: none; }
#hud.compact .xpbar { height: 9px; margin-top: 3px; }
#hud.compact .xptext { display: none; }
#hud.compact .streak-num { font-size: 17px; }
#hud.compact .streak-lbl { display: none; }
#hud.compact .hud-rank { opacity: .7; }
#hud, #hud.compact { will-change: padding; }
#hud .badge, #hud .xpbar, #hud .streak-num, #hud .streak-lbl, #hud .badge-sub, #hud .xptext {
  transition: width .28s ease, height .28s ease, font-size .28s ease, opacity .2s ease; }
.hud-row { display: flex; align-items: center; gap: 12px; max-width: 720px; margin: 0 auto; }
/* insignia circular del jugador */
.badge {
  width: 54px; height: 54px; flex-shrink: 0; position: relative; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.badge-ring { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.badge-ring circle { fill: none; }
.badge-ring .ring-track { stroke: var(--panel2); stroke-width: 3; }
.badge-ring .ring-fill { stroke: url(#sunriseRingGrad); stroke-width: 3; stroke-linecap: round;
  transition: stroke-dashoffset .8s cubic-bezier(.22,1,.36,1); }
.badge.tier-plata .ring-fill { stroke: #C8D2E6; }
.badge.tier-oro .ring-fill { stroke: var(--gold); }
.badge.tier-diamante .ring-fill { stroke: var(--cyan); }
.badge.tier-leyenda .ring-fill { stroke: var(--violet); }
.badge-inner {
  width: 44px; height: 44px; border-radius: 50%;
  background: #0c0c0e;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.05);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  position: relative; z-index: 1;
}
.badge-lvl { font-size: 18px; color: var(--amber-hi); line-height: 1; }
.badge-sub { font-size: 10px; color: var(--muted); letter-spacing: 1px; }
/* ---------- El avatar reacciona a la racha (independiente del aro de nivel) ---------- */
#hudAvatar { transition: filter .4s ease; }
#hudAvatar.streak-cold { filter: grayscale(65%) brightness(.82); }
#hudAvatar.streak-warm { filter: none; }
#hudAvatar.streak-hot { filter: drop-shadow(0 0 4px rgba(255,178,94,.7)); }
#hudAvatar.streak-blazing { filter: none; }
#hudAvatar.streak-leyenda { filter: none; }
.hud-mood { position: absolute; bottom: -1px; right: -1px; z-index: 2; font-size: 11px; line-height: 1;
  background: var(--bg); border-radius: 50%; width: 18px; height: 18px;
  display: flex; align-items: center; justify-content: center; border: 2px solid #111113; }
.hud-mid { flex: 1; min-width: 0; }
.hud-title { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.hud-name { font-size: 15px; }
.hud-rank { font-size: 12px; color: var(--gold); text-transform: uppercase; letter-spacing: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.xpbar { position: relative; height: 15px; margin-top: 6px; border-radius: 8px;
  background: var(--panel2); border: 1px solid var(--line); overflow: hidden;
  box-shadow: inset 0 2px 4px rgba(0,0,0,.35); }
.xpfill { height: 100%; width: 0%; border-radius: 8px;
  background: var(--sunrise);
  transition: width .8s cubic-bezier(.22,1,.36,1); position: relative; }
.xpfill::after { content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,.28), transparent 55%); }
.xptext { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.7); letter-spacing: .3px; }
.hud-right { text-align: center; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: 1px; }
.streak-flame { display: flex; align-items: center; gap: 3px; }
.streak-num { font-size: 24px; font-weight: 700; color: var(--text); line-height: 1; letter-spacing: -.02em; }
.streak-num svg { color: var(--amber-hi); filter: drop-shadow(0 0 5px rgba(255,177,94,.5)); }
.streak-lbl { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
.mult { font-size: 10px; font-weight: 700; color: var(--green); }

/* ---------- Tabs ---------- */
/* ---------- Barra de pestañas (panel opaco, nunca transparente) ---------- */
#tabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  background: rgba(14,16,22,.82);
  backdrop-filter: blur(22px) saturate(1.2); -webkit-backdrop-filter: blur(22px) saturate(1.2);
  border-top: 1px solid var(--line-soft);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.03);
  padding-bottom: env(safe-area-inset-bottom); }
#tabs { display: flex; max-width: 720px; margin: 0 auto; }
.tab { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 7px 2px 8px; background: none; border: none; color: var(--muted); font-weight: 600; font-size: 10.5px;
  white-space: nowrap; transition: color .18s, transform .12s ease; }
.tab-ico { flex-shrink: 0; }
.tab:active { transform: scale(.92); }
.tab.on { color: var(--amber); }

/* ---------- Layout ---------- */
#main { max-width: 720px; margin: 0 auto; padding: 8px 14px calc(84px + env(safe-area-inset-bottom)); }
body { padding-top: var(--hud-h); }
.card { background: var(--panel); border: 1px solid rgba(255,255,255,.055); border-radius: 20px;
  padding: 16px; margin-bottom: 14px; }   /* la sombra la pone la regla global del final (--shadow-card) */
button, .tab, .stepbtn, .qcheck-btn { transition: transform .12s ease; }
button:active:not(.tab):not(.stepbtn) { transform: scale(.96); }
.card h3 { margin: 0 0 12px; font-size: 17px; font-weight: 700; letter-spacing: -.01em; font-family: var(--font-display); display: flex; align-items: center; gap: 7px; }
.card h3 svg { flex-shrink: 0; color: var(--amber-hi); }
.ios-row { display: flex; align-items: center; gap: 12px; padding: 12px 2px; border-bottom: 1px solid var(--line); }
.ios-row:last-child { border-bottom: none; }
.ios-row-ico { width: 30px; height: 30px; border-radius: 8px; display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; background: var(--amber); color: #1A1208; }
.ios-row-body { flex: 1; min-width: 0; }
.ios-row-title { font-size: 15px; font-weight: 600; color: var(--text); }
.ios-row-sub { font-size: 12.5px; color: var(--muted); margin-top: 1px; }
.ios-row-chev { color: var(--muted); flex-shrink: 0; }
.ios-row:active { background: var(--panel2); }
.hint { color: var(--muted); font-size: 14px; line-height: 1.5; }
.note { background: #10283A; border: 1px solid #1E4A63; border-left: 4px solid var(--cyan);
  border-radius: 16px; padding: 13px 15px; font-size: 15px; line-height: 1.6; margin-bottom: 14px;
  color: #F0F4FC; font-weight: 500; }

/* ---------- Misiones ---------- */
.quest { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--panel2); border: 1px solid rgba(255,255,255,.05); border-radius: 16px;
  padding: 12px 14px; margin-bottom: 9px; color: var(--text); position: relative;
  box-shadow: 0 1px 0 rgba(255,255,255,.02) inset;
  transition: border-color .25s, box-shadow .25s, opacity .25s, transform .12s ease, background .25s; }
.quest:active { transform: scale(.985); }
.quest.done { border-color: rgba(89,201,138,.35); background: linear-gradient(90deg, rgba(89,201,138,.09), var(--panel2) 26%);
  opacity: 1; box-shadow: none; }
.quest.locked { opacity: .45; }
.qcheck { width: 27px; height: 27px; border-radius: 9px; flex-shrink: 0;
  border: 2px solid var(--muted); display: flex; align-items: center; justify-content: center;
  color: var(--bg); font-weight: 800; font-size: 16px; transition: transform .2s, background .2s, border-color .2s; }
.quest.done .qcheck { background: var(--green); border-color: var(--green); box-shadow: 0 0 0 4px rgba(89,201,138,.14);
  animation: pop .35s cubic-bezier(.34,1.56,.64,1); }
@keyframes pop { 0% { transform: scale(.6);} 60% { transform: scale(1.25);} 100% { transform: scale(1);} }
.qname { flex: 1; font-size: 15px; font-weight: 600; }
.qname small { display: block; font-weight: 500; color: var(--muted); font-size: 12.5px; margin-top: 2px; line-height: 1.4; }
.qxp { font-size: 13.5px; font-weight: 700; color: var(--amber-hi); font-family: var(--font-display); }
/* Anillo de constancia por misión (score 0-100, suavizado exponencial) */
.qscore { width: 30px; height: 30px; flex-shrink: 0; position: relative; }
.qscore svg { display: block; }
.qscore-num { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 800; color: var(--muted); }
/* Misiones cuantificables (crédito parcial: agua/proteína) */
.quest.quant { flex-direction: column; align-items: stretch; gap: 9px; cursor: default; }
.quest-main { display: flex; align-items: center; gap: 12px; width: 100%; }
.qcheck-btn { background: none; border: none; padding: 0; margin: 0; flex-shrink: 0; cursor: pointer; line-height: 0; }
.quest-step { display: flex; align-items: center; gap: 10px; }
/* 44×44 real (no ampliado con pseudo-elemento): son los +/− de agua/proteína/calorías, se
   tocan muchas veces al día y la fila ya es alta, así que crecer no descuadra nada. */
.stepbtn { flex-shrink: 0; width: 44px; height: 44px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--panel); color: var(--text); font-size: 20px; font-weight: 700; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: background .15s, border-color .15s; }
.stepbtn:active { background: var(--panel2); border-color: var(--cyan); }
.step-track { position: relative; flex: 1; height: 28px; border-radius: 9px; background: var(--panel);
  border: 1px solid var(--line); overflow: hidden; }
.step-fill { position: absolute; top: 0; bottom: 0; left: 0; border-radius: 8px 0 0 8px;
  background: linear-gradient(90deg, var(--cyan), var(--violet)); opacity: .35; transition: width .25s ease; }
.step-val { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; color: var(--text); }
.quest.done .qxp { color: var(--green); }

/* texto flotante +XP (y también avisos/errores de la app: floatXP() es el toast
   genérico único, ver 02-juego.js). La duración real la pone floatXP() por elemento
   vía animation-duration inline (escala con el largo del texto); 1.1s aquí es solo
   el valor por default si algo no lo hiciera. */
.float-xp { position: fixed; z-index: 90; pointer-events: none;
  font-weight: 700; font-size: 16px; color: var(--amber);
  animation: floatUp 1.1s ease-out forwards; }
/* Visible (opacidad 1) del 12% al 80% de la duración sin importar cuánta sea —
   antes se pasaba fundiendo desde el 15% hasta el final, así que un mensaje largo
   se leía peor cuanto más tiempo se le daba en pantalla. Ahora el fundido de salida
   ocupa solo el último 20%, y alargar la duración sí alarga el tiempo de lectura real. */
@keyframes floatUp { 0% { opacity: 0; transform: translateY(6px) scale(.7);}
  12% { opacity: 1; transform: translateY(0) scale(1.1);}
  80% { opacity: 1; transform: translateY(-30px) scale(1);}
  100% { opacity: 0; transform: translateY(-52px) scale(1);} }

/* ---------- Level up ---------- */
/* ---------- Overlays (level up, jefe, reinicio) ---------- */
#levelup, .overlay { position: fixed; inset: 0; z-index: 100; display: none;
  align-items: center; justify-content: center; flex-direction: column;
  background: rgba(6,9,20,.88); backdrop-filter: blur(4px); }
#levelup.show, .overlay.show { display: flex; }

/* ---------- Sheets nativos (acciones rápidas: reiniciar día/aventura) ---------- */
.overlay.sheet { display: flex !important; align-items: flex-end; justify-content: center;
  background: rgba(6,9,20,.6); visibility: hidden; opacity: 0; pointer-events: none;
  transition: opacity .26s ease, visibility 0s linear .26s; }
.overlay.sheet.show { visibility: visible; opacity: 1; pointer-events: auto; transition: opacity .26s ease; }
.overlay.sheet .card { width: 100%; margin: 0 !important; border-radius: 24px 24px 0 0 !important;
  padding-top: 8px !important; padding-bottom: calc(20px + env(safe-area-inset-bottom)) !important;
  transform: translateY(100%); transition: transform .34s cubic-bezier(.22,1,.36,1);
  box-shadow: 0 -14px 32px rgba(0,0,0,.5); }   /* sheet: hacia ARRIBA, por eso no usa --shadow-pop */
.overlay.sheet.show .card { transform: translateY(0); }
.sheet-handle { width: 36px; height: 4px; border-radius: 2px; background: var(--line); margin: 0 auto 14px; }

/* ---------- Jefe (boss) ---------- */
.boss-card { background: linear-gradient(165deg, var(--panel3), var(--panel) 55%);
  border: 1px solid var(--line); border-radius: 22px; padding: 14px;
  margin-bottom: 14px; box-shadow: var(--shadow-pop), 0 1px 0 rgba(255,255,255,.04) inset;
  position: relative; overflow: hidden; }
.boss-row { display: flex; gap: 12px; align-items: center; }
.boss-sprite { font-size: 44px; flex-shrink: 0; filter: none; }
.boss-name { font-size: 16px; font-weight: 700; }
.boss-taunt { font-size: 13px; color: var(--muted); font-style: italic; margin-top: 2px; }
.hpbar { height: 13px; margin-top: 8px; border-radius: 7px; background: var(--panel2);
  border: 1px solid var(--line); overflow: hidden; position: relative; }
.hpfill { height: 100%; border-radius: 7px; transition: width .6s cubic-bezier(.22,1,.36,1);
  background: linear-gradient(90deg, var(--coral), #FF8FA3); }
.hptext { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 10px; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.8); }
.boss-cycle { position: absolute; top: 8px; right: 12px; font-size: 10px; color: var(--gold); }

/* ---------- Arena fija al hacer scroll ---------- */
/* El offset usa --hud-h (la MISMA variable que actualiza 16-inicio.js en cada scroll)
   en vez de un valor fijo: así, cuando el HUD se compacta, la arena sube con él en
   vivo. Antes el offset se calculaba una sola vez en JS (initStickyArena) con la
   altura del HUD expandido y nunca se refrescaba, así que al compactarse el HUD la
   arena se quedaba pegada más abajo de lo debido — dejando un hueco donde el
   divisor "Tu día" (el contenido siguiente) quedaba atrapado detrás de ella. */
.boss-card.sticky { position: sticky; top: calc(var(--hud-h) + 6px); z-index: 40; }
/* .stuck además ENCOGE la arena para ocupar menos pantalla — pero un elemento sticky
   reserva en el flujo EXACTAMENTE su alto actual, así que al encoger, todo lo que viene
   justo después (el divisor "Tu día") pasaba a quedar más arriba en el documento de lo
   que la arena, ya fijada en pantalla, todavía ocupaba visualmente: quedaba atrapado
   detrás de ella casi al primer scroll y nunca volvía a aparecer. El margin-bottom de
   abajo compensa esa diferencia de alto para que "Tu día" y lo siguiente sigan
   apareciendo justo debajo de la arena compacta.
   La primera versión de esto solo encogía sprites y ocultaba taunt/hint, dejando la
   arena de sprites, el VS y el battle-log completos: seguía ocupando ~280px de pantalla
   (un tercio de un iPhone) de forma permanente mientras se navegan las misiones, para un
   ahorro real de apenas 112px frente a la versión sin compactar — no valía la pena.
   Ahora, al pegarse arriba, sólo quedan nombre + barra de HP en una sola fila angosta
   (37px medidos en Chromium, contra los ~280px de la versión anterior): arena de sprites,
   VS, battle-log, taunt y hint se ocultan enteros. El display:flex
   en la propia tarjeta acomoda a nombre y barra lado a lado sin tocar el orden del HTML —
   son los únicos dos hijos visibles que quedan (boss-cycle sigue ahí pero es position:absolute,
   no participa del flex). */
/* margin-bottom no es un número que se pueda derivar a ojo — sale de medir en Chromium la
   posición ABSOLUTA en el documento (getBoundingClientRect()) de lo que viene justo después
   de la arena, justo EN el instante en que initStickyArena() (02-juego.js) activa .stuck, y
   ajustando el margen hasta que ese "salto" de tamaño no deje un hueco vacío perceptible.
   Llegó a estar en 269px (antes 313px) por sucesivas re-mediciones, pero ese número asumía
   que el salto ocurría con la arena YA pegada arriba — dejó de ser cierto cuando se agregó
   #bossSentinel ANTES de la tarjeta de anillos (progresoAnillosHTML, 06-render.js) sin mover
   el centinela junto a la arena: el observer de initStickyArena() activaba .stuck en cuanto
   se empezaba a hacer scroll, con la arena todavía a ~300px del HUD, sin llegar a pegarse de
   verdad — así que el margen de 269px quedaba "abierto" como hueco vacío durante casi todo el
   scroll, en vez de cerrarse al instante. Con el centinela ya pegado al inicio de la arena
   (ver el comentario en viewMisiones, 06-render.js), el salto vuelve a ocurrir cuando la arena
   de verdad está por pegarse arriba, y 100px alcanza para que no se vea hueco (medido con
   Playwright: ~20px de sobra en el peor caso, por el margen de error propio de
   IntersectionObserver). Si cambia la altura compacta, el padding/gap de esta regla, o vuelve
   a moverse #bossSentinel, hay que volver a medir con scroll real — no basta con restar a
   mano las dos alturas. */
.boss-card.stuck { box-shadow: var(--shadow-stuck);
  border-color: var(--line); margin-bottom: 100px;
  padding: 10px 14px; display: flex; align-items: center; gap: 10px; }
/* !important en .boss-hint: su <div> trae style="display:flex" inline (06-render.js) para su
   layout normal (ícono + texto + XP en negritas) — un estilo inline le gana a CUALQUIER regla
   de clase sin importar especificidad, así que sin !important esta ocultación no hacía nada
   y el hint se veía completo encima de la barra compacta. Comprobado con Chromium: sin esto,
   .boss-card.stuck seguía mostrando el párrafo completo del hint tapando la barra de HP. */
.boss-card.stuck .arena, .boss-card.stuck .battle-log, .boss-card.stuck .boss-taunt,
.boss-card.stuck .boss-cycle, .boss-card.stuck .enrage-tag { display: none; }
/* La arena grande (.arena, con el héroe/jefe a tamaño completo) se sigue ocultando al
   compactarse — un intento de ENCOGERLA con transform:scale() se descartó porque el propio
   scale(1.15-1.2) de .attack (ver attackDash más abajo) se salía del recorte overflow:hidden
   de esa caja y quedaba superpuesto como un "zoom" feo. En su lugar hay una SEGUNDA arena,
   .arena-mini (06-render.js, junto a #playerSprite/#bossSprite), con sprites A TAMAÑO REAL
   pequeño desde que se dibujan — no una versión encogida por CSS de los grandes — así que no
   hay ningún transform de ancestro que compense ni recorte que se escape: la embestida mide
   y anima directo sobre estos elementos chicos, igual que la arena grande mide y anima sobre
   los suyos. .arena-mini vive oculta el resto del tiempo y solo se muestra aquí, en .stuck. */
.arena-mini { display: none; }
.boss-card.stuck .arena-mini { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.boss-card.stuck .arena-mini .arena-vs { font-size: 8px; margin-bottom: 0; letter-spacing: 0; }
.boss-card.stuck .boss-hint { display: none !important; }
.boss-card.stuck .boss-name { font-size: 13px; flex-shrink: 0; max-width: 32%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.boss-card.stuck .hpbar { flex: 1; margin-top: 0; height: 10px; }
.boss-card.stuck .hptext { font-size: 9px; }

/* ---------- Arena de combate con profundidad 3D ---------- */
.arena { display: flex; align-items: flex-end; justify-content: space-between;
  padding: 14px 20px 18px; position: relative; min-height: 82px; margin-bottom: 10px;
  border-radius: 14px;
  background: radial-gradient(120% 100% at 50% 120%, rgba(232,147,90,.09), transparent 60%), var(--panel2);
  border: 1px solid var(--line-soft);
  overflow: hidden; }
.arena::after { content: none; }
.fighter-wrap { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; }
.fighter-player { line-height: 0; position: relative; z-index: 2; filter: none; }
.fighter-player svg { display: block; }
.fighter-shadow { position: absolute; bottom: -3px; left: 50%; width: 40px; height: 9px;
  transform: translateX(-50%); border-radius: 50%;
  background: rgba(0,0,0,.3); z-index: 1; }
/* Embestida: el héroe cruza la arena hasta el jefe al completar una misión. Se perdió al
   reemplazar la hoja de estilos completa (ver "Actualiza sistema de diseño CSS") y sin ella
   un ataque no se distingue de cualquier otro re-render — se restaura aquí. */
.fighter-player.attack { animation: attackDash .6s cubic-bezier(.3,.7,.4,1); }
@keyframes attackDash {
  0%, 100% { transform: translateX(0) scale(1); }
  30%  { transform: translateX(calc(var(--dist,150px) * .35)) scale(1.15); }
  52%  { transform: translateX(var(--dist,150px)) rotate(8deg) scale(1.2); }
  66%  { transform: translateX(var(--dist,150px)) rotate(-4deg) scale(1.1); }
}
.fighter-player.attack + .fighter-shadow { animation: shadowDash .6s ease; }
@keyframes shadowDash { 0%,100% { transform: translateX(-50%) scale(1);}
  52% { transform: translateX(calc(-50% + var(--dist,150px))) scale(1.3); opacity: .3; } }
.lpc-sprite { background-repeat: no-repeat; image-rendering: pixelated; image-rendering: crisp-edges; }
/* Vida del héroe pixel art: respiración (bob de 1 pixel, en steps para que se sienta
   de sprite, no de tween), salto de victoria y retroceso al deshacer una misión. */
.hero-breathe { transform-box: fill-box; animation: pxBob 1.7s steps(1) infinite; }
@keyframes pxBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-0.35px); } }
.fighter-player.victory { animation: pxVictory .9s ease; }
@keyframes pxVictory { 0%,100% { transform: translateY(0); } 25% { transform: translateY(-14px); }
  45% { transform: translateY(0); } 65% { transform: translateY(-8px); } 82% { transform: translateY(0); } }
.fighter-player.stagger { animation: pxStagger .5s ease; }
@keyframes pxStagger { 0%,100% { transform: translateX(0); } 30% { transform: translateX(-7px) rotate(-6deg); }
  65% { transform: translateX(-3px); } }
/* el enemigo también mira de frente con leve giro y sombra */
.boss-sprite { position: relative; z-index: 2; filter: none; }
.arena-vs { font-size: 12px; color: var(--muted); align-self: center; margin-bottom: 18px;
  font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
.slash { position: fixed; z-index: 93; pointer-events: none; font-size: 22px; color: var(--muted);
  animation: slashPop .4s ease-out forwards; }
@keyframes slashPop {
  0%   { opacity: 0; }
  40%  { opacity: 1; }
  100% { opacity: 0; }
}

/* ---------- Juice: golpes al jefe ---------- */
/* Igual que la embestida de arriba: la sacudida de la tarjeta y el "flinch" del sprite del
   jefe se perdieron con el reemplazo de la hoja de estilos, dejando solo un opacity:.85
   apenas perceptible como única señal de que un ataque conectó. */
.boss-card.hit { animation: bossShake .35s; }
.boss-card.crit { animation: bossShakeHard .45s; }
@keyframes bossShake { 0%,100% { transform: translateX(0);} 25% { transform: translateX(-5px);}
  55% { transform: translateX(4px);} 80% { transform: translateX(-2px);} }
@keyframes bossShakeHard { 0%,100% { transform: translateX(0) scale(1);} 20% { transform: translateX(-9px) scale(1.02);}
  45% { transform: translateX(8px);} 70% { transform: translateX(-4px);} }
.boss-card.hit .boss-sprite, .boss-card.crit .boss-sprite { animation: flinch .4s; }
@keyframes flinch { 0%,100% { filter: none; } 30% { filter: brightness(1.8) saturate(0); } }
.boss-card.hit, .boss-card.crit { opacity: .85; transition: opacity .25s ease; }
.float-crit { position: fixed; z-index: 90; pointer-events: none; font-weight: 700;
  font-size: 18px; color: var(--coral);
  animation: critPop 1.1s ease-out forwards; }
@keyframes critPop { 0% { opacity: 0; transform: translateY(6px);}
  18% { opacity: 1; transform: translateY(0);}
  100% { opacity: 0; transform: translateY(-40px);} }

/* ---------- Sprites PNG personalizados (pixel-art nítido) ---------- */
.pxsprite { display: block; image-rendering: pixelated; image-rendering: crisp-edges; object-fit: contain; -webkit-user-select: none; user-select: none; }

/* ---------- Sprite del jefe (SVG híbrido o PNG, animado) ---------- */
.boss-sprite svg, .boss-sprite img.pxsprite { display: block; }
.boss-svg .aura { display: none; }
.boss-card.enrage .boss-sprite svg, .boss-card.enrage .boss-sprite img.pxsprite { filter: none; }
.boss-card.enrage { border-color: var(--coral); box-shadow: none; }
.enrage-tag { font-weight: 700; font-size: 10px; color: #fff; background: var(--coral); border-radius: 6px;
  padding: 1px 6px; margin-left: 6px; vertical-align: middle; letter-spacing: .05em; box-shadow: none; }

/* ---------- Barra de vida sólida (segmentos + vida fantasma) ---------- */
.hpbar { height: 15px; }
.hpghost { position: absolute; inset: 0; height: 100%; border-radius: 7px;
  background: rgba(255,255,255,.28); transition: width .55s ease .18s; z-index: 1; }
.hpfill { position: relative; z-index: 2; }
.hp-segs { position: absolute; inset: 0; z-index: 3; pointer-events: none; border-radius: 7px;
  background: repeating-linear-gradient(90deg, transparent 0 calc(10% - 1px), rgba(0,0,0,.35) calc(10% - 1px) 10%); }
.hptext { z-index: 4; }
.hpbar.hp-low { box-shadow: inset 0 0 0 1px var(--coral); }

/* ---------- Auras de rango en la insignia (evolucionan con el nivel) ---------- */
.badge.tier-plata { box-shadow: 0 0 0 2px rgba(255,255,255,.25); }
.badge.tier-oro { box-shadow: 0 0 0 2px var(--gold); }
.badge.tier-diamante { box-shadow: 0 0 0 2px var(--cyan); }
.badge.tier-leyenda { box-shadow: 0 0 0 2px var(--violet); }

/* ---------- Mapa: El Camino del Alba ---------- */
.map-node { display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  border-radius: 18px; margin-bottom: 10px; border: 1px solid rgba(255,255,255,.05); background: var(--panel2);
  width: 86%; position: relative; box-shadow: var(--shadow-lift); }
.map-node.right { margin-left: 14%; }
.map-node::before { content: ""; position: absolute; left: 50%; bottom: -11px; width: 2px; height: 11px;
  background: var(--line); }
.map-node:last-child::before { display: none; }
.map-node.done { border-color: var(--green); opacity: .8; }
.map-node.now { border-color: var(--amber); box-shadow: 0 0 0 1px rgba(201,143,92,.35); }
.map-node.lock { opacity: .38; filter: grayscale(.9); }
.map-emoji { font-size: 30px; }
.map-name { font-size: 13px; font-weight: 700; }
.map-state { font-size: 12px; color: var(--muted); }
.ladder-row { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.ladder-row:last-child { border-bottom: none; }
.ladder-lvl { width: 52px; color: var(--muted); font-size: 12px; }
.ladder-row.got { color: var(--green); }
.ladder-row.next { color: var(--gold); font-weight: 700; }
.ladder-row.far { color: var(--muted); }

/* ---------- Animaciones dinámicas ---------- */
#main.enter { animation: tabIn .32s cubic-bezier(.22,1,.36,1); }
@keyframes tabIn { from { opacity: 0; transform: translateY(14px);} to { opacity: 1; transform: translateY(0);} }
.spark { position: fixed; width: 7px; height: 7px; border-radius: 50%; z-index: 92; pointer-events: none;
  animation: sparkFly .7s ease-out forwards; }
@keyframes sparkFly { 0% { opacity: 1; transform: translate(0,0) scale(1);}
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.2);} }
.xpbar.flash { animation: none; }

/* ---------- Estadísticas del día: bento de tarjetas (reemplaza la lista tipo "ladder-row"
   para macros/micronutrientes con un layout de app nativa de salud, más escaneable que una
   lista de líneas) ---------- */
.stat-bento { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.stat-tile { background: var(--panel2); border: 1px solid var(--line-soft); border-radius: 14px;
  padding: 10px 12px 11px; min-width: 0; }
.stat-tile-top { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.stat-tile-ico { flex-shrink: 0; display: flex; opacity: .9; }
.stat-tile-lbl { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat-tile-val { font-size: 20px; font-weight: 700; line-height: 1; letter-spacing: -.01em; }
.stat-tile-unit { font-size: 12px; font-weight: 500; color: var(--muted); margin-left: 3px; }
.stat-tile-bar { position: relative; height: 5px; border-radius: 3px; background: rgba(255,255,255,.06); margin-top: 8px; overflow: hidden; }
.stat-tile-fill { height: 100%; border-radius: inherit; transition: width .5s cubic-bezier(.22,1,.36,1); }
.stat-tile.over .stat-tile-val { color: var(--coral); }
.stat-tile-ref { font-size: 10.5px; color: var(--muted); margin-top: 4px; }
.stat-tile-ref.warn { color: var(--gold); }

/* ---------- Ranking ---------- */
.lb-head, .lb-row { display: grid; grid-template-columns: 34px 1fr 28px 62px 54px 28px;
  gap: 4px; align-items: center; padding: 9px 0; font-size: 13px; }
.lb-head { color: var(--muted); font-size: 11px; border-bottom: 1px solid var(--line);
  text-transform: uppercase; letter-spacing: .5px; }
.lb-row { border-bottom: 1px solid var(--line); }
.lb-row:last-child { border-bottom: none; }
.lb-row.me { background: rgba(201,143,92,.12); border: 1px solid rgba(201,143,92,.4);
  border-radius: 8px; padding-left: 4px; margin-left: -4px; }
.lb-pos { font-size: 15px; text-align: center; }
.lb-name { display: flex; align-items: center; gap: 6px; min-width: 0; }
.lb-nick { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lb-num { text-align: right; font-size: 13px; }
.rank-x { background: none; border: none; color: var(--muted); font-size: 14px; padding: 2px; }

/* ---------- Selector de avatar ---------- */
/* ---------- Asistente flotante (encuesta por pasos) ---------- */
.wz-dots { display: flex; gap: 6px; justify-content: center; margin-bottom: 14px; }
.wz-dot { width: 26px; height: 4px; border-radius: 2px; background: var(--line); transition: background .25s; }
.wz-dot.on { background: var(--amber); }
.wz-dot.done { background: var(--green); }
.wz-step { animation: wzIn .22s ease; }
@keyframes wzIn { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
/* Acordeón de rutina por día (un día abierto a la vez) */
.rut-dia { padding: 0; overflow: hidden; }
.rut-dia-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 15px 16px; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
.rut-dia-head:active { background: var(--panel2); }
.rut-dia-head h3 { font-size: 15px; }
.rut-dia.open .menu-chevron { transform: rotate(90deg); }
.rut-dia-body { padding: 0 16px 14px; }
/* Cuestionario condicional GLP-1 (perfil de mínimos: color teal, no rojo de "exceso") */
.glp1-panel { margin-top: 16px; padding: 14px; border-radius: 16px;
  background: rgba(45,212,167,.055); border: 1px solid rgba(45,212,167,.22); }
.glp1-acc { border-radius: 12px; background: var(--panel2); margin-bottom: 8px; overflow: hidden; }
.glp1-acc:last-child { margin-bottom: 0; }
.glp1-acc-head { display: flex; align-items: center; gap: 10px; padding: 12px 14px; cursor: pointer;
  user-select: none; -webkit-tap-highlight-color: transparent; }
.glp1-acc-head:active { background: rgba(255,255,255,.04); }
.glp1-acc-badge { width: 22px; height: 22px; border-radius: 7px; background: var(--teal); color: #062A22;
  font-weight: 800; font-size: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.glp1-acc-title { flex: 1; display: flex; flex-direction: column; gap: 2px; font-weight: 700; font-size: 13.5px; min-width: 0; }
.glp1-acc-sub { font-size: 12px; color: var(--muted); font-weight: 500; }
.glp1-acc-chev { color: var(--muted); transition: transform .2s; flex-shrink: 0; }
.glp1-acc.open .glp1-acc-chev { transform: rotate(90deg); }
.glp1-acc-body { padding: 2px 14px 14px; display: none; }
.glp1-acc.open .glp1-acc-body { display: block; }
.glp1-intro { background: var(--teal-bg); border: 1px solid var(--teal-line); border-left: 4px solid var(--teal);
  border-radius: 10px; padding: 10px 12px; font-size: 12.5px; line-height: 1.5; margin-bottom: 12px; }
.glp1-block { margin-bottom: 12px; }
.glp1-h { font-weight: 700; font-size: 12px; letter-spacing: 1px; text-transform: uppercase;
  color: var(--teal); margin: 4px 0 8px; }
.glp1-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.glp1-grid .fld { margin: 0; }
.glp1-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.glp1-chip { border: 1px solid var(--line); background: var(--panel2); color: var(--muted);
  border-radius: 999px; padding: 6px 12px; font-size: 12.5px; cursor: pointer;
  user-select: none; -webkit-tap-highlight-color: transparent; }
.glp1-chip.on { background: var(--teal-bg); border-color: var(--teal); color: var(--teal-hi); font-weight: 600; }
/* KPI/guía de reparto proteico (perfil de mínimos) */
.glp1-guia { background: var(--teal-bg); border: 1px solid var(--teal-line); border-radius: 12px; padding: 14px; margin-bottom: 10px; }
.glp1-guia-top { display: flex; justify-content: center; align-items: flex-start; gap: 28px; margin-bottom: 6px; }
.glp1-ring-col { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.glp1-kpi-lbl { font-size: 11px; letter-spacing: .5px; text-transform: uppercase; color: var(--teal-hi); opacity: .85; text-align: center; }
.glp1-guia-msg { font-size: 13px; line-height: 1.5; color: #C5CDE0; text-align: center; }
/* Alertas de sub-ingesta */
.glp1-alert { border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; border: 1px solid; }
.glp1-alert.warn { background: #2A2410; border-color: #6B5A1E; border-left: 4px solid var(--gold); }
.glp1-alert.red  { background: #2E1218; border-color: #7A2434; border-left: 4px solid var(--coral); }
.glp1-alert-h { font-weight: 800; font-size: 14px; margin-bottom: 4px; }
.glp1-alert.warn .glp1-alert-h { color: var(--gold); }
.glp1-alert.red .glp1-alert-h { color: var(--coral); }
.glp1-alert-b { font-size: 13px; line-height: 1.5; color: #EEF1F8; }
.glp1-rescates { margin: 8px 0 0; padding-left: 18px; font-size: 13px; line-height: 1.6; }
/* Ciclo de dosis y aviso médico: líneas delgadas DENTRO de la tarjeta principal (dashboard limpio) */
.glp1-ciclo-slim { font-size: 12.5px; line-height: 1.5; color: #C5CDE0; border-radius: 8px;
  padding: 8px 10px; margin-top: 9px; }
.glp1-ciclo-slim.dificil { background: #241A2E; border-left: 3px solid #A78BFA; }
.glp1-ciclo-slim.bueno   { background: #10283A; border-left: 3px solid var(--cyan); }
.glp1-medico-slim { font-size: 12px; line-height: 1.5; color: var(--muted);
  border-top: 1px dashed var(--teal-line); margin-top: 9px; padding-top: 8px; }
/* IMC automático en el paso 1 del asistente */
.pf-imc { background: var(--panel2); border: 1px solid var(--line); border-radius: 10px;
  padding: 8px 12px; font-size: 13px; line-height: 1.5; margin: 2px 0 8px; }
/* Fila de ejercicio en la rutina: nombre + tip + botón de video (para principiantes) */
.ej-row { display: flex; align-items: flex-start; gap: 8px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.ej-row:last-child { border-bottom: none; }
.ej-main { flex: 1; min-width: 0; }
.ej-nom { font-size: 15px; font-weight: 600; line-height: 1.35; }
.ej-reps { font-weight: 500; color: var(--muted); font-size: 13.5px; }
.ej-tip { font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.ej-video { flex-shrink: 0; background: var(--panel2); border: 1px solid var(--line); border-radius: 9px;
  color: var(--cyan); font-size: 12px; font-weight: 700; padding: 6px 9px; cursor: pointer; white-space: nowrap; }
.ej-video:active { background: var(--panel); }
/* Registro de series (peso × reps) por ejercicio, ver serieLoggerHTML() en 14-rutina-menu-ui.js */
.ej-ultima { margin-top: 4px; }
.ej-series { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.ej-serie-chip { display: inline-flex; align-items: center; gap: 4px; background: var(--panel2);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 4px 3px 9px; font-size: 12px; font-weight: 600; }
.ej-serie-chip button { background: none; border: none; color: var(--muted); font-size: 11px;
  cursor: pointer; padding: 2px 5px; line-height: 1; }
.ej-logger { display: flex; gap: 6px; margin-top: 6px; }
.ej-serie-input { width: 56px; flex: none; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 8px; padding: 6px 7px; font-size: 13px; text-align: center; color: inherit; }
.ej-serie-input:focus { border-color: var(--amber); }
.ej-serie-add { flex: none; background: var(--panel2); border: 1px solid var(--line); border-radius: 8px;
  color: var(--gold); font-size: 12px; font-weight: 700; padding: 6px 10px; cursor: pointer; white-space: nowrap; }
.ej-serie-add:active { background: var(--panel); }
/* Diagrama propio del ejercicio (visor de "Ver ejemplo") */
.ej-diag-wrap { max-width: 220px; margin: 8px auto 12px; color: var(--amber-hi); }
.ej-diag { width: 100%; height: auto; }
.ej-diag-a { animation: ejPoseA 1.6s steps(1) infinite; }
.ej-diag-b { animation: ejPoseB 1.6s steps(1) infinite; }
@keyframes ejPoseA { 0%, 45% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes ejPoseB { 0%, 45% { opacity: 0; } 50%, 100% { opacity: 1; } }
/* Foto real generada por IA (img/ejercicios/<slug>.png): una sola imagen cuadrada con
   las dos poses lado a lado ("A | B", no dos archivos). background-size:200% deja ver
   solo la mitad del ancho a la vez; la animación mueve background-position de la mitad
   izquierda a la derecha con el mismo timing steps(1) que .ej-diag-a/b, así que se ve
   como un cruce entre pose A y pose B. aspect-ratio 1/2 asume una fuente cuadrada
   (1024×1024) partida por la mitad — si el generador de imágenes produce otra
   proporción, ajustar este valor. */
.ej-diag-foto { position: relative; width: 100%; aspect-ratio: 1 / 2; border-radius: 10px;
  background-size: 200% 100%; background-position: 0% 0; background-repeat: no-repeat;
  animation: ejFotoSwap 1.6s steps(1) infinite; }
@keyframes ejFotoSwap { 0%, 45% { background-position: 0% 0; } 50%, 100% { background-position: 100% 0; } }
/* Consejo para evitar lesiones (visor de "Ver ejemplo"), debajo de la descripción */
.ej-seguridad { display: flex; align-items: flex-start; gap: 4px; margin-top: 8px; padding: 9px 10px;
  border-radius: 10px; background: rgba(224,122,95,.12); border: 1px solid rgba(224,122,95,.28);
  color: var(--coral); font-size: 12.5px; text-align: left; line-height: 1.4; }
/* Selector de días de descanso / nivel (paso 4 del onboarding) */
.cheat-row { margin: -4px 0 12px; }
.cheat-row .btn { width: 100%; }
.rest-grid { display: flex; flex-wrap: wrap; gap: 7px; margin: 6px 0; }
.rest-day { flex: 1; min-width: 40px; padding: 10px 6px; border-radius: 10px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--muted); font-weight: 700; font-size: 14px; cursor: pointer;
  transition: border-color .15s, background .15s, color .15s; }
.rest-day.nivel { min-width: 90px; font-size: 13px; }
.rest-day.on { border-color: var(--cyan); background: rgba(127,163,173,.16); color: var(--cyan); }
.pf-trainer { display: flex; gap: 9px; align-items: flex-start; margin-top: 12px; padding: 11px 12px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--panel2); font-size: 13.5px; cursor: pointer; }
.pf-trainer input { margin-top: 2px; width: 18px; height: 18px; flex-shrink: 0; }

.pick-grid { display: grid; grid-template-columns: 1fr; gap: 8px; }
.pick-grid.two { grid-template-columns: 1fr 1fr; }

/* Selector de suplementos (checkbox grid): onboarding paso 5 y tarjeta de Ficha */
.suple-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 6px 0 4px;
  max-height: 340px; overflow-y: auto; padding-right: 2px; }
.suple-item { display: flex; gap: 7px; align-items: center; padding: 8px 9px; border: 1px solid var(--line);
  border-radius: 10px; background: var(--panel2); font-size: 12.5px; line-height: 1.25; cursor: pointer;
  user-select: none; -webkit-tap-highlight-color: transparent; }
.suple-item input { width: 15px; height: 15px; flex-shrink: 0; accent-color: var(--cyan); }
.suple-item.on { border-color: var(--cyan); background: rgba(127,163,173,.12); color: var(--text); }
.suple-reminder { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px;
  padding: 9px 0; border-bottom: 1px solid var(--line); }
.suple-reminder:last-child { border-bottom: none; }
.suple-reminder-n { font-weight: 700; font-size: 13.5px; }
.suple-reminder-m { font-size: 12px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.pick { display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 11px 12px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--text); text-align: left; transition: border-color .15s, background .15s; }
.pick.on { border-color: var(--amber); background: rgba(201,143,92,.12); box-shadow: 0 0 0 1px var(--amber) inset; }
.pick-emo { font-size: 20px; }
.pick-t { font-weight: 700; font-size: 14px; }
.pick-d { font-size: 12px; color: var(--muted); line-height: 1.4; }

.hr-row { display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line); }
.hr-row:last-child { border-bottom: none; }
.hr-in { background: var(--panel2); border: 1px solid var(--line); border-radius: 9px;
  padding: 7px 10px; color: var(--text); font-size: 15px; font-family: inherit; }

.avatar-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.avatar-opt { display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 4px 9px; border-radius: 18px; background: var(--panel2);
  border: 2px solid transparent; box-shadow: var(--shadow-lift);
  transition: transform .15s ease, box-shadow .2s ease, border-color .2s ease; }
.avatar-opt:active { transform: scale(.95); }
.avatar-opt-plinth { width: 100%; aspect-ratio: 1; border-radius: 14px; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 28%, rgba(255,255,255,.07), transparent 70%), #101012; position: relative; overflow: hidden; }
.avatar-opt-plinth::after { content: ""; position: absolute; left: 50%; bottom: 6%; width: 62%; height: 12%; transform: translateX(-50%);
  background: radial-gradient(ellipse, rgba(0,0,0,.55), transparent 72%); }
/* ---------- Recetario ---------- */
.rec-card { padding: 0; overflow: hidden; }
.rec-foto { width: 100%; aspect-ratio: 16/10; object-fit: cover; display: block; }
.rec-noFoto { display: flex; align-items: center; justify-content: center; }
.rec-body { padding: 12px 13px 13px; }
.rec-head { display: flex; align-items: flex-start; gap: 8px; }
.rec-tag { font-size: 11px; font-weight: 700; border: 1px solid; border-radius: 12px; padding: 2px 8px; white-space: nowrap; }
.rec-macros { display: flex; gap: 12px; margin-top: 6px; font-size: 12.5px; color: var(--cyan); font-weight: 600; }
.rec-sec { margin-top: 10px; }
.rec-sec b { font-size: 12px; color: var(--amber); text-transform: uppercase; letter-spacing: .4px; }
.rec-txt { font-size: 13.5px; color: #D9E0EF; line-height: 1.55; margin-top: 4px; }
.rec-acciones { display: flex; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
.rec-btn { flex: 1; min-width: 64px; padding: 7px 8px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--text); font-size: 12.5px; font-weight: 600; }
.rec-btn.on { border-color: var(--amber); color: var(--amber); background: rgba(201,143,92,.12); }
.rec-btn.danger { flex: 0 0 auto; min-width: 40px; color: var(--coral); }
.rec-fotobtn { width: 100%; padding: 20px; margin-bottom: 12px; border-radius: 12px;
  border: 1px dashed var(--line); background: var(--panel2); color: var(--muted); font-size: 14px; }

/* ---------- Bitácora ---------- */
.bit-acciones { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.bit-add { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 12px 6px;
  border-radius: 12px; border: 1px dashed var(--line); background: var(--panel2);
  color: var(--text); font-size: 12px; font-weight: 600; }
.bit-add:active { background: rgba(201,143,92,.12); border-color: var(--amber); }
.bit-add:disabled { opacity: .5; }
.bit-filtros { display: flex; gap: 6px; overflow-x: auto; margin-bottom: 12px; scrollbar-width: none; }
.bit-filtros::-webkit-scrollbar { display: none; }
.bit-f { padding: 5px 11px; border-radius: 14px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--muted); font-size: 12px; white-space: nowrap; }
.bit-f.on { border-color: var(--amber); color: var(--amber); background: rgba(201,143,92,.12); }
.bit-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.bit-card { border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--panel2); }
.bit-img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
.bit-ph { display: flex; align-items: center; justify-content: center; font-size: 22px; color: var(--muted); }
.bit-meta { display: flex; align-items: center; padding: 6px 7px 2px; }
.bit-tipo { flex: 1; font-size: 11px; font-weight: 700; }
/* opacity .6 sobre un ícono de 13px sin fondo se leía como una marca perdida en la esquina de
   la tarjeta, no como un botón — se reportó que "no hay opción para eliminar registros" cuando
   sí la había, solo que nadie la encontraba. El fondo tenue + opacidad más alta lo hacen leerse
   como botón sin subirlo a un color de alarma (eso se reserva para .confirm, el segundo toque). */
.bit-x { background: rgba(255,255,255,.06); border: none; border-radius: 999px;
  font-size: 12px; padding: 4px 5px; opacity: .85; }
.bit-x.confirm { opacity: 1; color: var(--coral); font-weight: 700; font-size: 11px;
  background: rgba(201,123,118,.14); border-radius: 8px; padding: 3px 7px; }
/* Estado "analizando con IA": mensaje rotando + barra indeterminada (no hay progreso real que medir) */
.bit-ia-loading { color: var(--cyan); font-weight: 600; }
.bit-ia-bar { position: relative; margin-top: 6px; height: 4px; border-radius: 999px;
  background: #1C2238; overflow: hidden; }
.bit-ia-bar-fill { position: absolute; top: 0; left: -40%; width: 40%; height: 100%;
  border-radius: 999px; background: linear-gradient(90deg, transparent, var(--cyan), transparent);
  animation: iaSweep 1.1s ease-in-out infinite; }
@keyframes iaSweep { 0% { left: -40%; } 100% { left: 100%; } }
.bit-nota { width: 100%; background: none; border: none; border-top: 1px solid var(--line);
  padding: 6px 7px; color: var(--text); font-size: 12px; font-family: inherit; }
.bit-nota::placeholder { color: var(--muted); opacity: .7; }
/* Editor de pesos/cantidades de un análisis (sheet #ajusteModal). El input de gramos va
   PRIMERO y con ancho fijo para que todos queden alineados en columna: se corrige "de
   arriba a abajo" sin buscar el campo en cada renglón. */
.aj-lista { display: flex; flex-direction: column; gap: 8px; }
.aj-ing { display: flex; align-items: center; gap: 8px; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel2); }
.aj-ing.aj-fijo { opacity: .72; }
/* ".aj-ing input" y no ".aj-g" a secas: .meal-edit trae width:100% y está definido MÁS
   ABAJO en esta hoja, así que con la misma especificidad ganaría él y el campo se comería
   la fila entera (el nombre del ingrediente quedaba exprimido a 0 px de ancho). */
.aj-ing input.aj-g { width: 66px; flex: none; text-align: center; margin-top: 0; padding: 7px 6px; }
.aj-ing .aj-u { flex: none; font-size: 12px; }
.aj-ing .aj-n { flex: 1; min-width: 0; }
.aj-nombre { font-size: 13px; font-weight: 600; }
.aj-macro { font-size: 11px; }
.aj-ing.aj-agregado { border-left: 2px solid var(--gold); }
.aj-buscador { margin-top: 10px; padding: 10px; border-radius: 12px;
  background: var(--panel2); border: 1px solid var(--line); }
.aj-res { display: flex; align-items: center; gap: 8px; width: 100%; margin-top: 6px;
  padding: 8px 10px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--panel); color: var(--text); font-family: inherit; }
.aj-res:active { border-color: var(--gold); }
#ajReset.confirm { color: var(--coral); border-color: var(--coral); font-size: 12px; }
.aj-porciones { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; }
.aj-porciones::-webkit-scrollbar { display: none; }
.aj-tot { margin-top: 12px; padding: 10px 12px; border-radius: 12px;
  background: var(--panel2); border: 1px solid var(--line); }
.aj-tot-kcal { font-size: 22px; font-weight: 800; color: var(--gold); }
.aj-dif { font-size: 13px; font-weight: 700; margin-left: 6px; }
.aj-tot-macros { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 2px;
  font-size: 12px; color: var(--muted); }
.cam-btn { background: none; border: none; padding: 2px 5px; opacity: .65; display: inline-flex; align-items: center; }
.quest-wrap { position: relative; }
.quest-wrap .quest { padding-right: 14px; }
/* solo las misiones con botón de cámara reservan espacio extra a la derecha, para que
   el ícono 📸 no se encime con la XP ni con el anillo de constancia */
.quest-wrap .quest.has-cam { padding-right: 50px; }
.quest-cam { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); z-index: 2; }
.cam-btn:active { opacity: 1; }

.beb-grupo { border-left: 3px solid var(--line); padding-left: 10px; margin-bottom: 14px; }
.beb-tit { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 7px; }
.beb-item { margin-bottom: 9px; }
.beb-n { font-size: 14px; font-weight: 600; color: var(--text); }
.beb-k { font-size: 11px; color: var(--green); font-weight: 700; margin-left: 5px; }
.beb-p { font-size: 12.5px; color: var(--muted); line-height: 1.5; margin-top: 2px; }
.beb-nota { font-size: 12px; color: var(--gold); line-height: 1.5; margin-top: 3px; }
.bebida { margin-top: 6px; padding: 6px 9px; border-radius: 8px;
  background: rgba(127,163,173,.08); border: 1px solid rgba(127,163,173,.25); }
.bebida.open { background: rgba(127,163,173,.14); }
.bebida-top { display: flex; align-items: center; gap: 7px; }
.bebida-ico { font-size: 14px; }
.bebida-txt { flex: 1; font-size: 12.5px; color: #C8D4E6; line-height: 1.4;
  background: none; border: none; text-align: left; padding: 0; }
.bebida-k { color: var(--green); font-weight: 700; margin-left: 4px; }
.bebida-caret { color: var(--cyan); margin-left: 4px; font-size: 10px; }
.bebida-prep { margin-top: 7px; padding-top: 7px; border-top: 1px solid rgba(34,211,238,.22);
  font-size: 12.5px; color: #C8D4E6; line-height: 1.55; }
.bebida-nota { color: var(--gold); margin-top: 4px; }
.bebida-hid { color: var(--cyan); margin-top: 4px; font-weight: 600; }
.prep-toggle { display: block; width: 100%; margin-top: 6px; padding: 6px 10px;
  background: transparent; border: 1px dashed var(--line); border-radius: 8px;
  color: var(--muted); font-size: 12.5px; text-align: left; }
.prep-toggle:active { background: var(--panel2); }
.prep { margin-top: 8px; padding: 11px 12px; border-radius: 10px;
  background: var(--panel2); border: 1px solid var(--line); border-left: 3px solid var(--green); }
.prep-head { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; font-size: 13px; }
.prep-x { margin-left: auto; background: none; border: none; color: var(--muted); font-size: 14px; padding: 0 4px; }
.prep-steps { margin: 0; padding-left: 20px; }
.prep-steps li { font-size: 13.5px; line-height: 1.55; margin-bottom: 6px; color: #D9E0EF; }
.prep-steps li::marker { color: var(--green); font-weight: 700; }
.prep-note { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--muted); line-height: 1.5; }
.ing-list { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.ing { font-size: 12px; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 6px; padding: 2px 7px; color: var(--muted); white-space: nowrap; }
.ing b { color: var(--cyan); font-weight: 700; }
/* Ingrediente con sustitutos: tocable, muestra equivalentes de igual valor nutrimental */
.ing-sub { cursor: pointer; font-family: inherit; }
.ing-sub .ing-swap { color: var(--muted); font-weight: 700; margin-left: 1px; }
.ing-sub.on { border-color: var(--cyan); background: rgba(127,163,173,.14); }
.ing-sub.on .ing-swap { color: var(--cyan); }
.sub-panel { margin-top: 8px; padding: 9px 10px; border-radius: 10px; background: var(--panel);
  border: 1px dashed var(--line); }
.sub-op { background: rgba(74,222,128,.10); border-color: rgba(74,222,128,.4); color: var(--text); white-space: normal; }
.sub-op b { color: var(--green); }
/* min 44×44: va al final de filas que ya miden más que eso (nombre de receta + macros, o un
   input), así que fijar el mínimo no estira la fila — solo deja de ser un blanco de 24px. */
.swap-btn { background: var(--panel2); border: 1px solid var(--line); border-radius: 8px;
  padding: 4px 8px; font-size: 14px; margin-top: 4px; color: var(--text);
  min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.avatar-lbl { font-size: 11px; font-weight: 600; color: var(--muted); text-align: center; line-height: 1.1; }
.avatar-opt.sel { border-color: var(--amber); background: rgba(201,143,92,.12);
  box-shadow: 0 0 0 2px rgba(201,143,92,.25); }
.avatar-opt.sel .avatar-opt-plinth { background: #17130B; }
.avatar-opt.sel .avatar-lbl { color: var(--amber); }

/* ---------- Formulario de perfil / editor de menú ---------- */
.fld { display: block; margin-bottom: 10px; }
.fld span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 4px; letter-spacing: .5px; }
.fld-sel { width: 100%; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 12px; color: var(--text); font-size: 15px; font-family: inherit;
  -webkit-appearance: none; appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 16px) 18px, calc(100% - 11px) 18px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
/* Desplegable compacto para elegir la receta de cada tiempo del menú */
.meal-sel { width: 100%; margin-top: 7px; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 8px; padding: 6px 26px 6px 9px; color: var(--text); font-size: 12.5px; font-family: inherit;
  -webkit-appearance: none; appearance: none; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 14px) center, calc(100% - 9px) center;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
.meal-sel:focus { border-color: var(--violet); }
.meal-macros { margin-top: 8px; padding: 7px 9px; border-radius: 9px; background: var(--panel2);
  border: 1px solid var(--line); font-size: 12px; color: var(--muted); line-height: 1.5; }
.meal-macros b { color: var(--text); }
/* Stepper de porción de cada comida del menú (× factor) */
.porcion-row { display: flex; align-items: center; gap: 7px; margin-top: 8px; }
.pz-btn { width: 30px; height: 30px; flex: none; border-radius: 8px; border: 1px solid var(--line);
  background: var(--panel2); color: var(--text); font-size: 17px; font-weight: 700; line-height: 1; }
.pz-btn:disabled { opacity: .3; }
.pz-val { min-width: 40px; text-align: center; font-size: 13px; color: var(--cyan); }
.fld input, .meal-edit { width: 100%; background: var(--panel2); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 12px; color: var(--text); font-size: 15px; font-family: inherit; }
.fld input:focus, .meal-edit:focus { border-color: var(--amber); }
.meal-edit { font-size: 13px; margin-top: 3px; }
.lvl-burst { font-family: var(--font-display); font-weight: 700; font-size: 32px;
  background: var(--sunrise); -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: burst .5s ease-out; text-align: center; }
@keyframes burst { 0% { transform: scale(.85); opacity: 0;} 100% { transform: scale(1); opacity: 1;} }
.lvl-new { font-family: var(--font-display); font-weight: 700; font-size: 22px; color: var(--text); margin-top: 6px; }
.lvl-title { font-size: 13px; color: var(--muted); margin-top: 8px; letter-spacing: .1em; text-transform: uppercase; }
.lvl-btn { margin-top: 26px; background: var(--sunrise);
  border: none; color: #1c1208; font-weight: 700; font-size: 15px; padding: 12px 34px; border-radius: 24px;
  box-shadow: var(--shadow-glow); font-family: var(--font-display); }
.confetti { display: none; }

/* ---------- Logros ---------- */
.ach { display: flex; gap: 12px; align-items: center; padding: 12px 0; border-bottom: 1px solid var(--line); }
.ach:last-child { border-bottom: none; }
.ach-ico { width: 46px; height: 46px; border-radius: 12px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel3); color: var(--amber); }
.ach.locked .ach-ico { background: var(--panel2); filter: grayscale(1); opacity: .5; }
.ach.locked .ach-name, .ach.locked .ach-desc { color: var(--muted); }
.ach-name { font-size: 14px; font-weight: 700; }
.ach-desc { font-size: 14px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.ach-prog { font-size: 11px; color: var(--cyan); margin-top: 2px; }

/* toast de logro */
#toast { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(120px);
  z-index: 95; background: var(--panel2);
  border: 1px solid var(--line); border-radius: 14px; padding: 12px 18px;
  display: flex; gap: 10px; align-items: center; transition: transform .5s cubic-bezier(.22,1,.36,1);
  box-shadow: var(--shadow-card); max-width: 90vw; }
#toast.show { transform: translateX(-50%) translateY(0); }

/* ---------- Ficha / stats ---------- */
.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.stat { background: var(--panel2); border-radius: 12px; padding: 12px; }
.stat .v { font-family: inherit; font-weight: 700; font-size: 22px; color: var(--amber); }
.stat .l { font-size: 12px; color: var(--muted); margin-top: 2px; }
.bars { display: flex; align-items: flex-end; gap: 8px; height: 130px; margin-top: 10px; }
.barcol { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; height: 100%; justify-content: flex-end; }
.bar { width: 100%; border-radius: 6px 6px 2px 2px;
  background: var(--cyan); min-height: 3px;
  transition: height .6s ease; }
.bar-lbl { font-size: 10px; color: var(--muted); }
.bar-val { font-size: 10px; color: var(--cyan); }
.btnrow { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
/* min-height 44: con padding 11px + font 13px salía en 39px, por debajo del mínimo táctil.
   Es el botón genérico de toda la app, así que subirlo aquí arregla decenas de sitios. */
.btn { flex: 1; min-width: 130px; padding: 11px; border-radius: 12px; font-weight: 700; font-size: 13px;
  border: 1px solid var(--line); background: var(--panel2); color: var(--text);
  min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 4px; }
.btn.warn { border-color: var(--coral); color: var(--coral); }
.btn.primary { background: var(--amber); border: none; color: #14140f; }

/* ---------- Contenido de referencia ---------- */
.row { padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 15px; line-height: 1.5; }
.row:last-child { border-bottom: none; }
.meal-lbl { font-size: 12px; font-weight: 700; letter-spacing: 1px; color: var(--muted); text-transform: uppercase; }
.meal-lbl.hot { color: var(--coral); }
/* Cada comida como bloque separado, con acento de color por tiempo para distinguirlas de un vistazo */
.meal-card { background: var(--panel2); border: 1px solid rgba(255,255,255,.05); border-radius: 16px;
  padding: 12px 13px 12px 16px; margin-bottom: 11px; box-shadow: var(--shadow-lift); }
.meal-card:last-child { margin-bottom: 0; }
.meal-card .meal-lbl { display: block; font-size: 12.5px; margin-bottom: 3px; }
.meal-des { box-shadow: inset 4px 0 0 0 var(--amber); }   .meal-des .meal-lbl { color: var(--amber); }
.meal-com { box-shadow: inset 4px 0 0 0 var(--violet); }  .meal-com .meal-lbl { color: var(--violet); }
.meal-cen { box-shadow: inset 4px 0 0 0 var(--cyan); }    .meal-cen .meal-lbl { color: var(--cyan); }
.meal-col { box-shadow: inset 4px 0 0 0 var(--coral); }   .meal-col .meal-lbl { color: var(--coral); }
/* Acordeón de días del menú: solo un día visible a la vez, más limpio en móvil */
.menu-dia { padding: 0; overflow: hidden; }
.menu-dia-head { padding: 16px; cursor: pointer; user-select: none; -webkit-tap-highlight-color: transparent; }
.menu-dia-head:active { background: var(--panel2); }
.menu-dia-body { padding: 0 16px 16px; }
.menu-chevron { display: inline-block; font-size: 18px; color: var(--muted); transition: transform .18s ease; }
.menu-dia.open .menu-chevron { transform: rotate(90deg); }
.menu-dia-hoy { font-size: 10px; font-weight: 700; letter-spacing: .5px; color: var(--bg); background: var(--gold);
  border-radius: 6px; padding: 1px 6px; margin-left: 8px; vertical-align: middle; }
/* Acordeón por comida dentro de un día: cada tiempo se despliega individualmente */
.meal-acc { padding: 0; overflow: hidden; }
.meal-head { display: flex; align-items: center; gap: 10px; width: 100%; background: none; border: none;
  color: var(--text); text-align: left; padding: 11px 13px 11px 16px; cursor: pointer;
  -webkit-tap-highlight-color: transparent; font: inherit; }
.meal-head:active { background: var(--panel); }
.meal-head-n { font-size: 14px; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.meal-ligera { font-size: 10px; font-weight: 700; letter-spacing: .3px; color: var(--cyan); background: rgba(34,211,238,.14);
  border: 1px solid rgba(34,211,238,.4); border-radius: 6px; padding: 0 5px; margin-left: 6px; vertical-align: middle; }
.meal-head-r { display: flex; align-items: center; gap: 7px; flex-shrink: 0; }
.meal-chevron { font-size: 17px; }
.meal-acc.open .meal-chevron { transform: rotate(90deg); }
.meal-body { padding: 0 13px 13px 16px; }
.meal-body .ing-list { margin-top: 2px; }
.meal-actions { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
.slider-row { margin-bottom: 14px; }
.slider-row input { width: 100%; accent-color: var(--amber); }
.slider-head { display: flex; justify-content: space-between; align-items: center; }
.slider-val { font-family: 'Russo One'; font-size: 20px; color: var(--amber); }
.small-scale { display: flex; justify-content: space-between; color: var(--muted); font-size: 13px; }
.checkline { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--panel2); border: 1px solid var(--line); border-radius: 10px;
  padding: 11px 13px; margin-bottom: 8px; color: var(--text); }
.checkline .qcheck { width: 22px; height: 22px; border-radius: 7px; font-size: 13px; }
.checkline.done { border-color: var(--green); }
.checkline.done .qcheck { background: var(--green); border-color: var(--green); }

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

/* ---------- Inventario ---------- */
.item-row { display: flex; gap: 12px; align-items: center; padding: 11px 10px; margin-bottom: 9px;
  background: var(--panel2); border: 1px solid var(--line); border-left: 4px solid var(--line);
  border-radius: 10px; }
.item-row.off { opacity: .65; }
.item-ico { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; }
.item-name { font-weight: 700; font-size: 15px; }
.item-qty { color: var(--gold); font-size: 13px; margin-left: 4px; }
.item-desc { font-size: 13px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.item-use { flex: 0 0 auto; min-width: 64px; padding: 8px 12px; }

/* ---------- Cuadro de mensajes de batalla ---------- */
.battle-log { margin-top: 10px; min-height: 40px; padding: 9px 12px; border-radius: 8px;
  background: #05070F; border: 1px solid var(--line); font-size: 14px; line-height: 1.5; color: #F0F4FC; }
.battle-cursor { display: inline-block; width: 9px; height: 13px; background: #F0F4FC; margin-left: 3px;
  animation: blink 1s steps(1) infinite; vertical-align: -2px; }
@keyframes blink { 50% { opacity: 0; } }

/* ============================================================
   ACCESIBILIDAD: foco de teclado visible (WCAG 2.1 AA · 2.4.7)
   ------------------------------------------------------------
   Un solo anillo de foco consistente en toda la app (ambos temas).
   :focus-visible sólo se activa con teclado/lector de pantalla,
   no con clic de mouse, así que no ensucia la UI táctil.
   ============================================================ */
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 4px; }
.qcheck-btn:focus-visible, .avatar-opt:focus-visible, .stepbtn:focus-visible,
.tab:focus-visible, .pick:focus-visible { outline-offset: 1px; }

/* ============================================================
   IDENTIDAD RPG ELEVADA — lenguaje visual ÚNICO de toda la app
   ------------------------------------------------------------
   RPG conservado a propósito (XP, jefe, insignias) pero ejecutado con
   el mismo rigor que un producto SaaS de alta gama: superficies de
   grafito cálido con borde hiper-fino, sombra difusa + luz superior
   (glass sutil), un solo acento dominante por zona y microetiquetas
   monoespaciadas que le dan tensión a la tipografía display. Estas
   reglas son GLOBALES y se colocan al final del stylesheet para ganar
   el cascade sin necesidad de !important.
   ============================================================ */
.card, .quest, .stat, .note, .glp1-guia, .glp1-alert {
  border: 1px solid var(--line); border-radius: 20px; background: var(--panel);
  box-shadow: var(--shadow-card);
}
.quest { border-radius: 16px; background: var(--panel2); }
.note { border-left: 3px solid var(--cyan); background: var(--panel); }
.glp1-alert.warn { border-left: 3px solid var(--gold); background: var(--panel); }
.glp1-alert.red { border-left: 3px solid var(--coral); background: var(--panel); }
.stat { background: var(--panel2); box-shadow: none; padding: 14px 12px; }
/* Bento asimétrico: la primera tarjeta de stats domina, la segunda es de apoyo —
   rompe la fila de columnas idénticas sin depender de cuántos elementos rindan. */
.stat-grid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 10px; }
.stat-grid .stat:only-child { grid-column: 1 / -1; }
.pick-grid.two { grid-template-columns: 1.2fr 1fr; }
/* Tarjetas "salud" (ficha, rutina, menú, compras, bitácora, recetario, bienestar) llevan un
   acento frío (cian/verde); las de "juego" (misiones, mapa, objetos, ranking, logros) mantienen
   el acento cálido (ámbar/violeta) — separa visualmente los dos lenguajes sin cambiar el layout. */
#main[data-cat="salud"] .stat .v { color: var(--cyan); }
#main { animation: mainFade .2s ease-out; }
@keyframes mainFade { from { opacity: 0;} to { opacity: 1;} }
/* Tipografía: encabezados display compactos y con tensión (Russo One ya aporta peso
   geométrico); las etiquetas de contexto usan mono en mayúsculas para el contraste. */
.card h3 { text-transform: none; letter-spacing: -.01em; font-size: 16px; font-weight: 700; color: var(--text); }
.stat .v { font-family: var(--font-display); font-weight: 700; font-size: 26px; letter-spacing: -.02em; color: var(--text); }
.stat .l { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }
.qxp { font-family: var(--font-display); font-weight: 700; }
/* Checkbox de misión: círculo plano en vez de casilla con esquinas */
.qcheck { border-radius: 50%; border: 2px solid var(--panel3); }
.quest.done .qcheck { border-color: var(--green); }
/* Barra de crédito parcial (agua/proteína/calorías): pill plana con degradado, sin marco */
.step-track { border: none; border-radius: 999px; background: var(--panel3); height: 30px; }
.step-fill { border-radius: 999px; opacity: 1; background: var(--sunrise); }
.stepbtn { border-radius: 50%; border: none; background: var(--panel3); }
/* Ficha: gráfica de barras XP, botones y cuenta también en tarjeta plana */
.bar { background: var(--cyan); }
/* Botones y filas (Editar perfil, Cuenta, avatar): borde hiper-fino + leve luz superior */
.btn { border-radius: 14px; border: 1px solid var(--line); background: var(--panel2); color: var(--text);
  box-shadow: none; font-family: var(--font-display); font-weight: 600; }
.btn.primary { background: var(--sunrise); border: none; color: #1c1208;
  box-shadow: var(--shadow-glow); }
.btn.warn { background: rgba(226,104,95,.1); border-color: rgba(226,104,95,.35); color: var(--coral); }
.row { border-bottom: 1px solid var(--line-soft); }
/* Separador con propósito: marca la transición entre "tu batalla" y "tu día" */
.sobrio-divider { display: flex; align-items: center; gap: 10px; margin: 4px 0 14px; }
.sobrio-divider::before, .sobrio-divider::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }
.sobrio-divider span { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .18em;
  text-transform: uppercase; color: var(--muted); }
/* Encabezado que parte las misiones en "Comidas de hoy" / "Metas del día". Deliberadamente
   más discreto que .sobrio-divider (sin las líneas laterales): ese marca el corte grande entre
   la arena y el día; estos solo agrupan dentro de la misma lista y no deben competir con él. */
.grupo-mis { display: flex; align-items: center; margin: 16px 0 8px; padding: 0 2px; }
.grupo-mis span { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
/* Tarjeta de referencia plegable (Macros/Micros de hoy). La cabecera es el control: 44px de
   alto real, con el resumen del día a la derecha para que plegada siga informando. */
.card-ref { padding: 0; overflow: hidden; }
.ref-head { display: flex; align-items: center; gap: 10px; padding: 13px 16px; cursor: pointer;
  user-select: none; min-height: 44px; }
/* El resumen va DEBAJO del título, no a su lado: lado a lado, "Micronutrientes de hoy" +
   "Sodio 1450 / tope 2300 mg" no caben en 390px — el título partía en dos líneas y el
   resumen se salía de la tarjeta. Apilados, el ancho deja de importar y esto aguanta
   cualquier largo de título (el inglés y el español no miden lo mismo). */
.ref-head-l { flex: 1; min-width: 0; }
.ref-head h3 { margin: 0; }
.ref-resumen { margin-top: 3px; font-family: var(--font-display); font-size: 15px; font-weight: 700;
  color: var(--text); font-variant-numeric: tabular-nums; }
.ref-resumen-u { font-family: 'Inter', system-ui, sans-serif; font-size: 12px; font-weight: 500; color: var(--muted); }
.ref-chevron { flex-shrink: 0; display: inline-block; font-size: 18px; color: var(--muted); transition: transform .18s ease; }
.ref-chevron.open { transform: rotate(90deg); }
.ref-body { padding: 0 16px 16px; }
/* Cabecera colapsable del panel GLP-1 (dashboard) */
.glp1-header { display: flex; align-items: center; gap: 10px; padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 16px; background: var(--panel); margin-bottom: 8px; cursor: pointer;
  user-select: none; -webkit-tap-highlight-color: transparent; }
.glp1-header-t { font-weight: 700; font-size: 15px; color: var(--text); flex: 1; }
.glp1-resumen { font-size: 13px; font-weight: 700; color: var(--teal-hi); }
.glp1-chevron { display: inline-block; font-size: 18px; color: var(--muted); transition: transform .18s ease; }
.glp1-chevron.open { transform: rotate(90deg); }
/* Anillo grande (piso GLP-1, KPI del día): anillo de progreso */
.kpi-ring { position: relative; width: 84px; height: 84px; flex-shrink: 0; }
.kpi-ring svg { display: block; transform: rotate(-90deg); }
.kpi-ring-txt { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.kpi-ring-num { font-size: 20px; font-weight: 800; color: var(--text); line-height: 1.05; }
.kpi-ring-unit { font-family: var(--font-mono); font-size: 10px; color: var(--muted); font-weight: 600; letter-spacing: .04em; }

/* ---------- Arena de batalla: RPG elevado — fantasía violeta contenida al 10% ---------- */
.boss-card { background: linear-gradient(165deg, var(--panel3), var(--panel) 55%);
  border: 1px solid var(--line); border-radius: 22px;
  box-shadow: var(--shadow-pop), 0 1px 0 rgba(255,255,255,.04) inset; }
.boss-card.stuck { box-shadow: var(--shadow-stuck);
  border-color: var(--line); }
.arena { background: radial-gradient(120% 100% at 50% 120%, rgba(232,147,90,.09), transparent 60%), var(--panel2);
  border: 1px solid var(--line-soft);
  border-radius: 14px; }
.arena::after { content: none; }
.arena-vs { color: var(--muted); font-family: var(--font-mono); letter-spacing: .16em; }
.fighter-shadow { background: rgba(0,0,0,.3); }
.boss-name { background: none; border: none; box-shadow: none; padding: 0; color: var(--text);
  font-family: inherit; font-weight: 700; letter-spacing: normal; }
.boss-taunt { color: var(--muted); }
.boss-cycle { font-family: var(--font-mono); letter-spacing: .05em; color: var(--muted); }
.hpbar { border: none; border-radius: 999px; background: var(--panel3); }
.hpbar::after { content: none; }
.hpfill { border-radius: 999px; }
.battle-log { border: 1px solid var(--line-soft); border-radius: 14px; background: var(--bg-elev); color: var(--text); }
.battle-cursor { background: var(--amber); }
.boss-hint { color: var(--muted); }
.boss-hint b { color: var(--amber) !important; }

/* ============================================================
   TENSIÓN TIPOGRÁFICA — microetiquetas monoespaciadas
   ------------------------------------------------------------
   Contraste de escala: los números/títulos display quedan pesados y
   compactos; las etiquetas de contexto (nivel, racha, macros, tags)
   pasan a mono en mayúsculas — el mismo recurso en toda la app en vez
   de variaciones sueltas de sans en mayúsculas.
   ============================================================ */
.badge-sub, .streak-lbl, .meal-lbl, .rec-tag, .bit-tipo, .ladder-lvl,
.item-qty, .lb-head, .glp1-h, .glp1-kpi-lbl, .beb-tit {
  font-family: var(--font-mono); letter-spacing: .06em;
}
/* la insignia de nivel gana tensión: número display grande junto a "NV" en mono chico */
.badge-lvl { font-family: inherit; letter-spacing: normal; }

/* ============================================================
   PANEL ÚNICO GLP-1 — agrupa header + anillos + alertas + dosis
   ------------------------------------------------------------
   Antes cada pieza (header, anillos, alerta de sub-ingesta, aviso de
   dosis) era su propia tarjeta elevada con margen propio, así que se
   veían como 3-4 tarjetas sueltas apiladas. Ahora glp1-dash es LA
   tarjeta y las piezas internas pierden borde/fondo/sombra propios,
   separándose solo con una línea divisoria — un panel, no varios.
   ============================================================ */
.glp1-dash { border: 1px solid var(--line); border-radius: 20px; background: var(--panel);
  box-shadow: var(--shadow-card); margin-bottom: 14px; overflow: hidden; }
.glp1-dash .glp1-header { border: none; border-radius: 0; background: none; margin-bottom: 0; }
.glp1-dash .glp1-guia { border: none; border-radius: 0; background: none; box-shadow: none;
  margin-bottom: 0; padding: 14px 16px 16px; }
.glp1-dash .glp1-alert { border-radius: 0; margin-bottom: 0; border: none; box-shadow: none;
  border-top: 1px solid var(--line-soft); padding: 13px 16px; }
.glp1-dash .glp1-alert.warn { background: rgba(207,154,99,.07); border-left: 3px solid var(--gold); }
.glp1-dash .glp1-alert.red { background: rgba(201,123,118,.07); border-left: 3px solid var(--coral); }
.glp1-dash #glp1-body { border-top: 1px solid var(--line-soft); }


/* ============================================================
   ÁREA TÁCTIL MÍNIMA (44px) — ampliación sin cambio visual
   ------------------------------------------------------------
   Estos tres controles TIENEN que seguir viéndose chicos: la ✕ vive dentro de una
   píldora de 12px, y el atajo de cámara va incrustado en la fila de la misión. Crecer
   el botón deformaría el componente, así que se amplía solo el área que recibe el
   toque, con un pseudo-elemento centrado que no ocupa espacio en el layout (el
   equivalente web del hitSlop de iOS/Android).
   Nota: .bit-x vive dentro de .bit-card, que tiene overflow:hidden — la parte del área
   que se sale de la tarjeta queda recortada, pero la que se expande hacia la foto sí
   cuenta, y aun recortada es varias veces mayor que los ~16px de antes.
   .qcheck-btn (la casilla de 27px de las misiones cuantificables) entró aquí tras medirla
   con Chromium: es el gesto de "meta cumplida", el más repetido de la app, y era el más
   chico de la pantalla. La casilla se sigue viendo de 27px; solo el área crece.
   ============================================================ */
/* :not(.quest-cam) en .cam-btn: la cámara del dashboard NO usa position:relative de aquí,
   usa position:absolute de .quest-cam (right:12px, centrada en la fila de la misión). Como
   ambas reglas tienen la misma especificidad y ésta venía después en el archivo, se comía
   el absolute y la cámara caía al flujo normal, huérfana, debajo de la tarjeta de comida en
   vez de sobre ella — bug real visto en pantalla, no hipotético. El .cam-btn suelto del menú
   (sin .quest-cam) sigue necesitando su propio position:relative para centrar el ::after. */
.ej-serie-chip button, .bit-x, .cam-btn:not(.quest-cam), .qcheck-btn { position: relative; }
.ej-serie-chip button::after, .bit-x::after, .cam-btn::after, .qcheck-btn::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%); width: 44px; height: 44px;
}

/* ============================================================
   ALTURA TÁCTIL MÍNIMA EN CONTROLES DE FORMULARIO Y CHIPS
   ------------------------------------------------------------
   Medidos con Chromium a 390px: todos caían entre 26px y 41px. Los del acordeón de
   rutina (.ej-serie-input / .ej-serie-add / .ej-video, 28-29px) son los peores porque
   son EXACTAMENTE los que se usan de pie en el gimnasio, entre series y con las manos
   sudadas — ahí un blanco de 29px se falla seguido.
   Va al final del stylesheet, junto al resto de reglas que ganan el cascade sin
   !important; solo fija el mínimo, no toca padding ni tipografía, así que ninguno
   cambia de aspecto salvo por ser más alto.
   ============================================================ */
.ej-serie-input, .ej-serie-add, .ej-video, .bit-f, .prep-toggle,
.fld input, .fld-sel, .meal-edit, .suple-item { min-height: 44px; }
/* .suple-item (restricciones/alergias y suplementos): la casilla mide 15px, pero el blanco
   real es el <label> completo que la envuelve — con una línea de texto quedaba en 39px. */
/* Los que son <button> necesitan además centrar su contenido al crecer. */
.ej-serie-add, .ej-video, .bit-f { display: inline-flex; align-items: center; justify-content: center; }
.prep-toggle { display: flex; align-items: center; }

/* Falla del análisis con IA: banner que se queda. Antes el error iba en el mismo floatXP que
   celebra "+10 XP" — duraba unos segundos y se lo perdía justo quien había dejado el teléfono
   para fotografiar el plato, sin quedar rastro de que algo falló ni forma de reintentar. */
.bit-ia-error { margin-top: 6px; padding: 8px 10px; border-radius: 10px; font-size: 12px;
  line-height: 1.45; color: var(--text); background: rgba(226,104,95,.10);
  border: 1px solid rgba(226,104,95,.35); border-left: 3px solid var(--coral); }
.bit-ia-error-t { font-weight: 700; color: var(--coral); margin-bottom: 2px; }

/* ============================================================
   GRAMÁTICA DE LUZ — "la luz significa AHORA"
   ------------------------------------------------------------
   Este bloque es la contraparte del comentario largo de :root: allá se define la
   paleta, aquí se aplica la regla. Va al final por la misma razón que los bloques
   anteriores (gana la cascada sin !important) y, como ellos, ES LA VERDAD sobre el
   aspecto de los componentes que toca: si una tarjeta se ve distinta de lo que dice
   su regla original, mira aquí antes de "arreglar" la de arriba.

   Diagnóstico del que sale, medido y no a ojo: en el dashboard había SEIS acentos
   activos al mismo tiempo y el "+XP" ámbar aparecía nueve veces; en la lista de compras
   lo más brillante de la pantalla eran las CANTIDADES (rosa, cian, verde) mientras la
   casilla que de verdad se toca era un círculo gris. O sea: el color se gastaba en lo
   que se lee, no en lo que se hace. Nada de eso sobraba por cantidad de información
   —sobraba por énfasis.
   ============================================================ */

/* ---- 1. Las superficies se separan por LUZ, no por línea ----
   El borde se va y en su lugar queda un reflejo superior de 1px (inset): es la lectura
   de "algo que sobresale porque le da la luz desde arriba", que es lo que hace un canto
   real. Junto con el escalón de luminancia de --bg → --panel alcanza de sobra para
   distinguir una tarjeta, y sin filos la pantalla se ablanda entera de un golpe. */
.card, .quest, .stat, .stat-tile, .map-node, .bit-card, .rec-card,
.glp1-dash, .glp1-header, .glp1-guia, .glp1-acc, .aj-ing, .aj-tot, .aj-buscador,
.pf-imc, .pf-trainer, .suple-item, .pick, .checkline, .btn, .item-row {
  border-color: transparent;
  box-shadow: var(--shadow-card), inset 0 1px 0 rgba(255,255,255,.05);
}
/* Las que llevan acento a la izquierda conservan ESE borde y pierden los otros tres:
   la barrita de color sí es información (aviso/error/nota), el marco no lo era. */
.note, .glp1-alert, .glp1-ciclo-slim, .bit-ia-error, .ej-seguridad, .prep, .beb-grupo {
  border-top-color: transparent; border-right-color: transparent; border-bottom-color: transparent;
}
/* Cajas de nota: una familia de tokens en vez de tres pares de hex retecleados */
.note { background: var(--note-info-bg); border-left-color: var(--info); color: var(--text); }
.glp1-alert.warn, .glp1-dash .glp1-alert.warn { background: var(--note-warn-bg); border-left-color: var(--gold); }
.glp1-alert.red,  .glp1-dash .glp1-alert.red  { background: var(--note-danger-bg); border-left-color: var(--coral); }
.glp1-ciclo-slim.bueno   { background: var(--note-info-bg); border-left-color: var(--info); }
/* Era #A78BFA: un violeta vivo, hermano de las auras de jefe, dentro de una tarjeta de
   dosis médica — justo la "fantasía RPG" que --violet decía haber retirado. */
.glp1-ciclo-slim.dificil { background: var(--note-warn-bg); border-left-color: var(--gold); }

/* ---- 2. Ritmo: una escala en vez de valores a ojo ---- */
.card { padding: var(--s4); margin-bottom: var(--s3); border-radius: var(--r3); }
.card h3 { font-size: var(--t-l); margin-bottom: var(--s3); }
.hint { font-size: var(--t-m); }
.quest { border-radius: var(--r2); padding: var(--s3) var(--s3); margin-bottom: var(--s2); }
.stat, .stat-tile, .map-node, .glp1-acc { border-radius: var(--r2); }
.btn, .rec-btn, .bit-add, .ej-video, .ej-serie-add { border-radius: var(--r2); }

/* ---- 3. La fila de misión: el átomo de toda la app ----
   Antes cada fila traía cinco cosas con color propio (franja, título, ✓, anillo con
   cifra, "+XP" ámbar, cámara) repetidas nueve veces. Ahora la fila tiene UN dato
   dominante —el número— y el acento aparece exactamente una vez por pantalla. */

/* 3a. Terminar APAGA. La misión cumplida pierde fondo y sombra: se funde con la página
   en vez de quedarse encendida en verde compitiendo con lo que falta. El ✓ verde se
   queda (es la prueba de que pasó), pero deja de venir con tarjeta propia.
   Se usa color explícito y NO opacity: opacity apaga también el ✓ y hace impredecible
   el contraste del texto; --muted mide 5.7:1 sobre el panel y eso sí se puede sostener. */
.quest.done { background: transparent; box-shadow: none; border-color: transparent; }
.quest.done .qname { color: var(--muted); font-weight: 500; }
/* Sin opacity en NINGÚN texto de la fila: atenuar con opacity se ve bien y mide mal.
   Medido en el DOM renderizado, --muted al 60-75% sobre el fondo de la fila cae a
   2.87:1 y 3.87:1 — por debajo de AA para 12px. Lo que apaga la fila es que pierde
   fondo y sombra, no que su texto se vuelva ilegible; --muted a plena opacidad mide
   6.1:1 y se lee igual de "ya está". */
.quest.done .qxp { color: var(--muted); }
.quest.done .qcheck { background: var(--green); border-color: var(--green); box-shadow: none; }

/* 3b. UNA cosa encendida: la próxima misión pendiente (marcada desde 06-render.js).
   Es el único sitio de la pantalla donde aparece el ámbar de marca. */
.quest.next {
  background: linear-gradient(180deg, rgba(255,177,94,.055), transparent 70%), var(--panel2);
  box-shadow: var(--shadow-lift), inset 0 0 0 1px rgba(255,177,94,.20), inset 0 1px 0 rgba(255,255,255,.06);
}
.quest.next .qcheck { border-color: var(--amber); }
.quest.next .qxp { color: var(--amber); opacity: 1; }
.quest.next .qscore { color: var(--amber); }
.quest.next .step-fill { background: var(--sunrise); opacity: 1; }

/* 3c. El número manda, la XP susurra. Es la inversión deliberada: la XP es la moneda del
   juego y el gramaje es el dato de salud — esta es una app de nutrición que además es un
   juego, no al revés. El "120 / 180 g" era 12.5px blanco sobre relleno naranja (1.79:1,
   la peor falla de contraste de la app); ahora es el elemento más grande de su fila. */
/* El relleno normal es NEUTRO, no un ámbar tenue: probado en Chromium, un cálido a baja
   opacidad encima de una superficie fría da un pardo apagado —lodo, no "progreso"— y
   además volvía a gastar el color de marca en una barra que aparece tres veces. Blanco a
   .07 se lee limpio como "esta parte ya está" y deja el degradado amanecer para la única
   misión encendida (.quest.next, arriba). */
.step-track { background: var(--bg-elev); height: 34px; }
.step-fill { background: rgba(255,255,255,.07); opacity: 1; }
.step-val { font-family: var(--font-display); font-size: var(--t-b); font-weight: 700;
  color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.qxp { font-family: var(--font-display); font-size: var(--t-s); font-weight: 600;
  color: var(--muted); }
.qname { font-size: var(--t-b); }
.qname small { font-size: var(--t-s); }
/* El anillo de constancia tomaba verde/ámbar/coral según el valor: tres colores más por
   fila, nueve veces. Ahora hereda el color de la fila (currentColor desde 06-render.js),
   así que solo la misión encendida lo muestra en ámbar. */
.qscore { color: var(--muted); }
.qscore-num { color: var(--muted); font-weight: 700; }
/* La casilla es LO QUE SE TOCA, así que tiene que verse tocable. El bloque RPG la había
   dejado en --panel3 (#232734), casi indistinguible del fondo de su propia fila: medido en
   pantalla, el control más repetido de la app era también el menos visible. Sube a un aro
   blanco tenue — presencia sin gastar color, que es lo que este sistema reserva. */
.qcheck { border-color: rgba(255,255,255,.24); }
.quest.done .qcheck { border-color: var(--green); }

/* ---- 4. Se retira el color decorativo ----
   Los cuatro tiempos de comida tenían franja ámbar/violeta/cian/coral. La etiqueta ya
   dice "DESAYUNO": el color no añadía información, solo cuatro acentos más por pantalla. */
.meal-card { box-shadow: var(--shadow-card), inset 3px 0 0 0 rgba(255,255,255,.10), inset 0 1px 0 rgba(255,255,255,.04);
  border-color: transparent; border-radius: var(--r2); }
.meal-des, .meal-com, .meal-cen, .meal-col { box-shadow: var(--shadow-card), inset 3px 0 0 0 rgba(255,255,255,.10), inset 0 1px 0 rgba(255,255,255,.04); }
.meal-des .meal-lbl, .meal-com .meal-lbl, .meal-cen .meal-lbl, .meal-col .meal-lbl { color: var(--muted); }
.meal-lbl.hot { color: var(--coral); }   /* "zona de riesgo" sí es una alerta real */
/* El día de hoy en el menú: era una píldora dorada sólida gritando desde el acordeón */
.menu-dia-hoy { background: none; color: var(--amber); border: 1px solid rgba(255,177,94,.35); }

/* ---- 5. Fallas de contraste WCAG (medidas, no estimadas) ----
   Las tres eran el mismo error: texto blanco fijo encima de un relleno claro. Y el número
   siempre cae sobre el tramo MÁS claro del degradado, que es el peor caso posible. */
/* .xptext — 1.79:1. Sacar el número del relleno lo arregla de raíz y además adelgaza la
   barra, que es lo que pide el brief. overflow:visible para que el texto salga del track;
   .xpfill ya trae su propio border-radius, así que no necesitaba el clip. */
.xpbar { height: 7px; overflow: visible; border: none; border-radius: var(--rp);
  background: var(--panel3); box-shadow: none; }
.xpfill { border-radius: var(--rp); }
.xpfill::after { display: none; }        /* el brillo superior no se lee en 7px */
.xptext { position: absolute; top: 100%; left: 0; right: 0; inset: auto 0 auto 0;
  margin-top: 3px; justify-content: flex-end;
  font-size: var(--t-micro); font-weight: 600; color: var(--muted);
  text-shadow: none; letter-spacing: .02em; }
#hud.compact .xpbar { height: 5px; }
/* .hptext — 2.16:1. Mismo remedio en la tarjeta completa; en la barra compacta el número
   simplemente se va (es un estado de vistazo: la longitud de la barra ya lo dice). */
.hpbar { overflow: visible; }
.hptext { position: absolute; top: 100%; left: 0; right: 0; margin-top: 3px;
  justify-content: flex-end; font-size: var(--t-micro); font-weight: 600;
  color: var(--muted); text-shadow: none; }
.boss-card.stuck .hptext { display: none; }
.boss-card.stuck .hpbar { overflow: hidden; }
/* .enrage-tag — 3.29:1 y sin text-shadow que lo disimulara. Texto oscuro sobre el coral: 5.64:1 */
.enrage-tag { color: #2A0F0C; font-weight: 800; }

/* ---- 6. El toast ya no tapa lo que celebras ----
   Estaba en bottom:28px, o sea encima de la barra de pestañas y de media tarjeta de
   misión. Con varias misiones seguidas (el uso normal) tapaba justo lo que acababas de
   completar. Ahora se apoya arriba de la barra. */
/* OJO con el par bottom/transform: el estado oculto del toast es un translateY, y subir el
   bottom SIN subir ese desplazamiento deja el toast asomado permanentemente al fondo de la
   pantalla (regresión real, vista al ganar un objeto). El valor viejo era 120px fijos, que
   alcanzaban con bottom:28px pero no con éste. Se deriva de la geometría en vez de ser un
   número mágico: 100% es la ALTURA DEL PROPIO TOAST, así que sigue saliendo entero aunque el
   contenido crezca a dos líneas — que es justo lo que pasa con los nombres largos de objeto. */
#toast { bottom: calc(84px + env(safe-area-inset-bottom)); box-shadow: var(--shadow-pop);
  transform: translateX(-50%) translateY(calc(100% + 84px + env(safe-area-inset-bottom) + 24px)); }
#toast.show { transform: translateX(-50%) translateY(0); }

/* ---- 7. Detalles que quedaban fuera de cualquier sistema ---- */
/* 'Russo One' nunca estuvo en el <link> de fuentes de index.html: caía a system-ui desde
   hace tiempo. Se usa la display real, que sí está cargada. */
.slider-val { font-family: var(--font-display); font-weight: 700; }
/* El diagrama del ejercicio era el único blanco puro de toda la app, dentro de un modal
   oscuro: un salto de contraste que rompía la calma justo en la pantalla más enfocada. */
.ej-diag-wrap { background: var(--panel2); border-radius: var(--r2); padding: var(--s2); }
/* El foco de teclado seguía al viejo --cyan; ahora es el ámbar de marca, que es el color
   que en este sistema significa "aquí estás". */
:focus-visible { outline-color: var(--amber); }
/* "+130 XP de botín" era, medido en pantalla, lo más brillante de la mitad superior del
   dashboard — y no es una acción: es el dato de cuánto suelta el jefe al morir. Competía
   de frente con la única misión encendida, que sí lo es. El !important replica el de la
   regla original (el <div> del hint trae style inline desde 06-render.js). */
.boss-hint b { color: var(--text) !important; }
/* Lo mismo que .quest.done: tachar un ingrediente de la compra lo APAGA. Antes le ponía
   un marco verde, o sea que la lista terminaba más encendida cuanto más avanzabas. */
.checkline.done { border-color: transparent; background: transparent; box-shadow: none; }
/* El icono de CADA título de tarjeta iba en --amber-hi (regla global .card h3 svg). Son
   siete en la Ficha y tres en el dashboard: el color de "ahora" repartido como adorno en
   una etiqueta. El icono acompaña al título, no señala una acción — y el título ya está
   en display 17px, que es jerarquía de sobra. */
.card h3 svg { color: var(--muted); }
/* Existía una regla que teñía los números de la Ficha de frío y los de las pestañas de
   "juego" de cálido (#main[data-cat="salud"] .stat .v). Era una forma de tener DOS acentos
   cuando había siete colores sueltos; con un solo acento reservado a "ahora", teñir un
   número de nivel o de XP total ya no dice nada — y en blanco se leen mejor, que es lo que
   se le pide a la cifra grande de una tarjeta de estadística. */
#main[data-cat="salud"] .stat .v, .stat .v { color: var(--text); }

/* ---- 8. La luz respeta la preferencia de movimiento reducido ----
   El bloque genérico de prefers-reduced-motion apaga transiciones con *, pero body::before
   pinta un degradado que igual CAMBIA de valor al completar misiones; sin transición el
   salto es instantáneo, que es peor. Aquí se congela en un valor medio fijo. */
@media (prefers-reduced-motion: reduce) {
  body::before { background: radial-gradient(130% 62% at 50% -8%, rgba(255,177,94,.055), transparent 68%); }
}

/* ============================================================
   ANILLOS DE PROGRESO + JEFE ATENUADO — pedido de producto: que Inicio lea más como
   una app de fitness/wellness real (Apple Fitness/Whoop) y menos como la pantalla de
   combate de un RPG, sin tocar la mecánica (el jefe, el XP y la racha siguen intactos
   por debajo). Va al final por la misma razón que el bloque de arriba: gana la cascada
   sobre las reglas de .boss-card/.quest definidas más arriba en este archivo.
   ============================================================ */
/* Anillos concéntricos (kcal/proteína/agua), nuevo elemento dominante de la pantalla —
   el lugar que antes ocupaba la arena de combate a tamaño completo. */
.rings-card { background: radial-gradient(120% 100% at 50% -10%, rgba(232,147,90,.08), transparent 55%), var(--panel);
  border-radius: var(--r3); padding: var(--s5) var(--s4) var(--s4); margin-bottom: var(--s3);
  box-shadow: var(--shadow-card), inset 0 1px 0 rgba(255,255,255,.05); text-align: center; }
.rings-wrap { position: relative; width: 190px; height: 190px; margin: 0 auto var(--s2); }
.rings-wrap svg { width: 100%; height: 100%; transform: rotate(-90deg); display: block; }
.rings-center { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; }
.rings-pct { font-size: 28px; line-height: 1; }
.rings-lbl { font-size: var(--t-xs); color: var(--muted); margin-top: 4px; }
.rings-legend { display: flex; justify-content: center; gap: var(--s4); margin-top: var(--s3); }
.ring-leg { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.ring-leg i { width: 8px; height: 8px; border-radius: 50%; margin-bottom: 1px; }
.ring-leg-v { font-family: var(--font-mono); font-size: var(--t-s); font-weight: 700; color: var(--text); }
.ring-leg-k { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--muted); }

/* El jefe se queda, pero deja de ser lo primero que se ve: sprites más chicos (ver
   ARENA_HERO_SZ en 02-juego.js y el tamaño pasado a bossSVG en 06-render.js), tarjeta
   más plana y sin el --shadow-pop que antes lo hacía flotar sobre el resto de la pantalla. */
.boss-card { padding: var(--s3) var(--s4); box-shadow: var(--shadow-card), inset 0 1px 0 rgba(255,255,255,.05); }
.boss-card .arena { padding-top: 0; padding-bottom: var(--s2); }
.boss-name { font-size: var(--t-b); }
.boss-taunt { font-size: var(--t-s); }

/* Lista de misiones: de "tarjeta por fila" a checklist plano con línea divisoria — el
   dato (nombre + XP) sigue siendo el mismo, pero la fila pendiente deja de traer su
   propio fondo/relieve; solo la fila .next (la gramática de luz de arriba) conserva
   presencia propia, que es justo el punto: una sola cosa con peso visual. */
.quest { background: transparent; box-shadow: none; border-radius: 0;
  border-bottom: 1px solid var(--line-soft); padding: var(--s3) var(--s1); margin-bottom: 0; }
.quest:last-child { border-bottom: none; }
.quest.next { border-radius: var(--r2); border-bottom-color: transparent; padding: var(--s3); }
.quest.done { border-bottom-color: var(--line-soft); }

/* ============================================================
   iOS: 16px MÍNIMO EN TODO CAMPO ENFOCABLE — no es estética, es un bug
   ------------------------------------------------------------
   Safari en iOS hace ZOOM AUTOMÁTICO al enfocar un input/select/textarea cuyo
   font-size calculado sea menor a 16px. Antes no se notaba porque el viewport
   llevaba maximum-scale=1/user-scalable=no, que lo impedía... y que se quitó a
   propósito en la tanda 374692d porque bloquear el zoom incumple WCAG 1.4.4 y le
   pega justo a quien necesita acercarse para leer gramos en letra chica.
   El efecto secundario no se vio entonces: al quitar esos flags, iOS empezó a
   hacer el zoom de entrada y —esto es lo grave— NO vuelve a alejarse al salir del
   campo. Reportado desde un iPhone real: al tocar "Correo" en el login la pantalla
   se ampliaba, y al entrar, el dashboard quedaba ampliado y descuadrado el resto
   de la sesión. Los campos del login son .fld input, que medía 15px.

   La salida NO es devolver maximum-scale: eso reintroduce el problema de
   accesibilidad que la tanda anterior arregló bien. Es que ningún campo enfocable
   baje de 16px, que es el umbral exacto que mira iOS.

   SI VAS A BAJAR ALGUNO DE ESTOS VALORES PORQUE "SE VE GRANDE", ESTÁS
   REINTRODUCIENDO EL ZOOM. El tamaño de la caja se ajusta con padding/width, no
   bajando el font-size.

   Checkbox y radio no disparan el zoom, por eso no están aquí. Los tres campos que
   traían font-size en línea (peso, fecha de peso y el selector de comparación de la
   bitácora) se arreglaron en su origen: un estilo inline le gana a esta regla.
   ============================================================ */
.fld input, .fld-sel, .meal-edit, .hr-in, .ej-serie-input, .bit-nota, .aj-ing input.aj-g,
input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="date"], input[type="search"], input[type="tel"], input[type="url"],
select, textarea { font-size: 16px; }

/* ============================================================
   PANTALLA DE ALBA — login/registro con la misma atmósfera de amanecer que
   pintarAlba() ya usa en el resto de la app, más un lema rotativo (LEMAS_LOGIN
   en 15-auth-ui.js) para que la puerta de entrada no repita siempre el mismo
   texto. Antes #authScreen era una card genérica sin nada del acento ámbar de
   marca; el resto de la app ya resolvió esa gramática, esta pantalla se había
   quedado fuera. Va al final por la misma razón que los bloques anteriores:
   gana la cascada sobre .card/.display definidos arriba.
   ============================================================ */
.auth-card { position: relative; overflow: hidden; padding-top: 28px; }
.auth-alba { position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background: radial-gradient(120% 70% at 50% 8%, rgba(255,177,94,.22), transparent 60%),
              radial-gradient(90% 50% at 50% 0%, rgba(239,125,110,.14), transparent 65%); }
.auth-emblem { position: relative; z-index: 1; display: flex; justify-content: center; margin-bottom: 6px; }
.auth-emblem svg { filter: drop-shadow(0 0 14px rgba(255,177,94,.5)); animation: authEmberPulse 3.6s ease-in-out infinite; }
@keyframes authEmberPulse {
  0%, 100% { filter: drop-shadow(0 0 10px rgba(255,177,94,.35)); }
  50% { filter: drop-shadow(0 0 20px rgba(255,177,94,.65)); }
}
.auth-word { position: relative; z-index: 1; text-align: center; margin: 0 0 8px; }
.auth-hook { position: relative; z-index: 1; text-align: center; font-size: 13.5px; line-height: 1.55;
  color: var(--muted); max-width: 34ch; margin: 0 auto; transition: opacity .18s ease; }
.auth-hook.swap { opacity: 0; }
.auth-shuffle-btn { position: relative; z-index: 1; display: flex; align-items: center; gap: 5px;
  margin: 8px auto 16px; padding: 5px 11px; min-height: 28px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--amber-hi); background: rgba(255,177,94,.08); border: 1px solid rgba(255,177,94,.28);
  border-radius: 999px; width: auto; }
.auth-shuffle-btn:hover { background: rgba(255,177,94,.15); }
.auth-shuffle-btn svg { transition: transform .3s ease; }
.auth-shuffle-btn.spin svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .auth-emblem svg { animation: none; }
}
