/* =============================================================================
   JUSTACANASTA V6 — SISTEMA DE DISEÑO "INVERNADERO" (MÉXICO · $ MXN)
   -----------------------------------------------------------------------------
   Tema principal: papel crema #FFFEFC, tinta forestal #0F3E17 y paneles
   tintados de keylime/salvia/pizarra (referencia: DESIGN.md "Ease Health").
   La profundidad sale de las CAPAS DE COLOR, no de las sombras: no hay
   `box-shadow`, ni degradados radiales, ni `backdrop-filter`.
   Tipografía: serif editorial (Cormorant Garamond, local en vendor/fuentes)
   para títulos y sans del sistema para la interfaz.
   El tema oscuro "Alacena" y el de alto contraste siguen disponibles en
   Configuración (html[data-tema="alacena" | "contraste"]).
   Un único archivo a propósito: el proyecto no tiene build ni bundler, así que
   dividir el CSS solo agregaría peticiones HTTP. En su lugar está dividido en
   secciones numeradas (usa Ctrl+F con el número para saltar).

   ÍNDICE
   01. Tokens ................. fuentes, colores, tipografía, espaciado, radios
   02. Temas elegibles ........ html[data-tema="alacena" | "contraste"]
   03. Base y accesibilidad ... reset, foco visible, scrollbars, movimiento
   04. Estructura ............. sidebar, contenido, barra y nav de celular
   05. Cabecera de vista ...... .header-top y títulos de página
   06. Rejillas ................ .grid-cards-*, .grid-*
   07. Tarjetas ............... .card-square, .card-pantry-item, .card-hero-green...
   08. Métricas y etiquetas ... .metrica, .etiqueta-mini, .tarjeta-*
   09. Badges y controles ..... .badge-*, .chip, .segmented, .stepper, .avisos-*
   10. Botones
   11. Formularios
   12. Modal de acceso ........ login / registro
   13. Avisos y toasts
   14. Estados ................ cargando, esqueleto, vacío
   15. Secciones y barras
   16. Menú IA y recetario .... .platillo, .receta-pasos
   17. Estadísticas ........... .grafico-caja, .leyenda-color
   18. Compras y tiendas
   19. Escáner ................ .video-wrap
   20. Responsive ............. 1100px, 880px, 520px
   21. Preferencias ........... reduced-motion
   22. Utilidades ............. separaciones puntuales (.mt-*) y `.oculto`
   23. Tour de bienvenida .... modal de primeros pasos (.tour-*)

   Reglas del sistema (ver documentacion/DISENO.md para el porqué de cada una):
   - Todo dato va en TARJETA CUADRADA dentro de una rejilla; nunca listas planas.
   - Solo 3 colores semánticos: verde = bueno/ahorro, ámbar = por vencer,
     rojo = merma/error. Los demás colores son neutros del tema.
   - Jerarquía por capas, no por sombra: lienzo crema → tarjeta keylime →
     bloque interior crema → panel de salvia. Un borde de color NO separa
     tarjetas; las separa el tinte (regla del DESIGN.md).
   - Serif solo en títulos (`h1..h3`, `.hero-titulo`); la interfaz (botones,
     etiquetas, cifras, nombres de tarjeta) va en sans.
   - Los estados `:hover` van SIEMPRE dentro de `@media (hover: hover)` y pegados
     a su componente (no en un bloque al final: eso rompería el orden de la
     cascada). En una pantalla táctil el navegador "pega" el `:hover` después de
     un toque y el elemento se queda viéndose seleccionado sin estarlo.
   - El contenido OCUPA TODO el ancho disponible (`#vista-activa`): al alejar el
     zoom o en un monitor ancho, las rejillas ganan columnas en vez de dejar
     franjas muertas a los lados. La comodidad de lectura se protege en los
     bloques de texto (`.page-subtitle`, `.hero-texto` con `max-width` en ch).
   - Alto `100dvh` con respaldo `100vh` y ancho `100%`, nunca `100vw`: `vh` mide
     la ventana completa (la barra del navegador del celular tapa la nav) y `vw`
     cuenta la barra de desplazamiento.
   ============================================================================= */

/* =============================================================================
   01. TOKENS
   ============================================================================= */

/* Serif de títulos, servida desde el proyecto (no desde Google Fonts): la app
   abre igual sin internet. Un solo archivo variable cubre de 300 a 700; el
   `unicode-range` deja que el navegador baje solo el subconjunto que necesita. */
@font-face {
    font-family: 'Cormorant Garamond';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('vendor/fuentes/cormorant-garamond-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Cormorant Garamond';
    font-style: normal;
    font-weight: 300 700;
    font-display: swap;
    src: url('vendor/fuentes/cormorant-garamond-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    /* --- Superficies: capas de papel tintado ---
       Nivel 0 = papel crema; nivel 1 = tarjeta keylime; los bloques interiores
       (campos, platillos, integrantes) vuelven al papel. La jerarquía se ve
       por el TINTE, no por la sombra: así lo pide el DESIGN.md. */
    --bg-main: #FFFEFC;
    --bg-main-rgb: 255, 254, 252;
    /* Tinta para los tintes neutros (hover, esqueletos, barras). */
    --slate-rgb: 58, 74, 62;
    --bg-sidebar: #E1F4DF;
    --bg-card: #E1F4DF;
    --bg-card-hover: #D6EDD8;
    --bg-input: #FFFEFC;
    --bg-elevada: #FFFEFC;
    --border-color: #D8E2D4;
    --border-suave: #EFEEEB;
    --border-fuerte: #B9CCB6;
    /* El hero no lleva borde en el tema claro (lo separa el relleno de salvia). */
    --border-hero: transparent;

    /* --- Paneles tintados de la marca (capas 1-4 del DESIGN.md) ---
       `--panel-sage` es el bloque de más peso (hero); `--panel-slate` es el
       contrapunto frío para las vistas de producto. En los temas oscuros se
       mapean a las tarjetas para que ningún componente se quede sin color. */
    --panel-keylime: #E1F4DF;
    --panel-mint: #CFE7D3;
    --panel-sage: #B1DBB8;
    --panel-slate: #B6CED5;

    /* --- Marca y acción: una sola tinta forestal ---
       El DESIGN.md pide un único verde saturado: titulares, enlaces, botones,
       bordes y focos. El texto que va ENCIMA de un relleno es papel crema.
       `--accion-clara` conserva su nombre por compatibilidad, pero en este
       tema es el relleno oscuro (el botón principal). Números MEDIDOS con el
       script de contraste, no estimados (ver documentacion/DISENO.md §2). */
    --marca: #0F3E17;
    --marca-rgb: 15, 62, 23;
    --marca-texto: #0F3E17;
    --accion: #0F3E17;
    --accion-rgb: 15, 62, 23;
    --accion-clara: #0F3E17;
    --accion-clara-hover: #0C2F10;
    --texto-sobre-accion: #FFFEFC;

    /* --- Texto ---
       Carbón para el cuerpo (no negro puro) y verdes apagados para lo
       secundario. Medidos sobre papel, keylime y salvia: el más flojo de los
       tres usos de texto pasa de 4.5:1 en todas las capas. */
    --text-fuerte: #222222;
    --text-muted: #445248;
    --text-suave: #5C685F;

    /* --- Semánticos: por vencer / merma / bueno ---
       Tintas oscuras sobre fondos translúcidos: en un tema claro el texto del
       badge no puede ser pastel (se perdería sobre el papel). El rojo sigue
       siendo más puro que el verde de marca para que una merma no se lea como
       un adorno. */
    --rojo-rgb: 176, 58, 44;
    --rojo-fuerte: #B03A2C;
    --ambar-rgb: 176, 118, 18;
    --badge-red-bg: rgba(var(--rojo-rgb), 0.10);
    --badge-red-border: rgba(var(--rojo-rgb), 0.30);
    --badge-red-text: #8C2A20;
    --badge-orange-bg: rgba(var(--ambar-rgb), 0.12);
    --badge-orange-border: rgba(var(--ambar-rgb), 0.32);
    --badge-orange-text: #7A4E05;
    --badge-green-bg: rgba(var(--accion-rgb), 0.10);
    --badge-green-border: rgba(var(--accion-rgb), 0.28);
    --badge-green-text: #1B5A29;

    /* --- Solo para gráficas (dan variedad sin tocar la interfaz) ---
       Rampa terrosa: verde bosque, salvia, oliva, tierra, ladrillo y pizarra.
       Las nueve pasan de 3:1 sobre la tarjeta keylime, así que se distinguen
       también en escala de grises y no introducen tonos fuera del invernadero. */
    --grafica-1: #0F3E17;
    --grafica-2: #2F6B3D;
    --grafica-3: #4F8A5B;
    --grafica-4: #8C6B3F;
    --grafica-5: #B03A2C;
    /* Del 6 al 9 solo se usan cuando una gráfica tiene más de cinco categorías
       (el JS las cicla). Están aquí y no en el JS para que el color siga
       saliendo de un token: el día que se retoque la paleta se retoca en un
       sitio, no en dos (ver corrección 105 en ANALISIS.md). */
    --grafica-6: #4A6B8A;
    --grafica-7: #6E8C7A;
    --grafica-8: #A0653A;
    --grafica-9: #7A6A4F;

    /* --- Velo del diálogo de acceso ---
       En el tema claro es papel OPACO: el acceso es la primera pantalla, no un
       diálogo encima de la app, y así no se transparenta el armazón vacío
       (sidebar, barra de celular) que hay detrás. Los temas oscuros usan el velo
       de tinta de siempre. */
    --velo-modal: #FFFEFC;

    /* --- Marcas ajenas y negro de cámara (no son del tema) ---
       El logo de WhatsApp conserva su verde solo en el ícono de la marca
       (--whatsapp); su BOTÓN usa la acción forestal porque un relleno neón
       sería un cuarto acento y rompería el invernadero. El negro puro es el
       fondo del visor de la cámara: ahí SÍ conviene el negro absoluto, porque
       el video se recorta contra él y un gris del tema teñiría las orillas. */
    --whatsapp: #25D366;
    --bg-camara: #000;

    /* --- Espaciado (base 4px) --- */
    --sp-1: 0.75rem;   /* 12px - base */
    --sp-2: 1rem;      /* 16px */
    --sp-3: 1.5rem;    /* 24px */
    --sp-4: 2rem;      /* 32px */
    --sp-5: 3rem;      /* 48px */
    --sp-6: 4rem;      /* 64px */
    --sp-7: 6rem;      /* 96px */

    /* --- Radios ---
       El DESIGN.md fija 14 px para tarjetas y botones, 7 px para navegación y
       999 px para badges. Los tres tamaños son tokens: ningún componente
       escribe un radio suelto. */
    --r-sm: 7px;
    --r-md: 14px;
    --r-lg: 14px;
    --r-xl: 14px;
    --r-2xl: 18px;
    --r-full: 9999px;

    /* --- Sombras / Elevación ---
       El sistema es plano a propósito: la profundidad la dan las capas de
       color. Los tokens se conservan (y valen `none`) para que ningún
       componente tenga que preguntarse de qué tema viene. */
    --sh-1: none;
    --sh-2: none;
    --sh-3: none;
    --sh-ring: 0 0 0 2px var(--accion-clara);                  /* focus ring */

    /* --- Tipografía ---
       Serif editorial para títulos (Cormorant Garamond, servida desde
       `publico/vendor/fuentes/`, licencia OFL) y sans del sistema para todo lo
       demás. Cero dependencia de internet. */
    --ff-base: system-ui, -apple-system, 'Segoe UI Variable', 'Segoe UI', Roboto, sans-serif;
    --ff-titulos: 'Cormorant Garamond', 'Iowan Old Style', 'Palatino Linotype', 'Book Antiqua', Palatino, Georgia, serif;
    --ff-mono: 'JetBrains Mono Variable', 'JetBrains Mono', monospace;
    /* El serif del diseño va en 300; el tema oscuro sube a 600 para conservar
       el contraste de su paleta. */
    --fw-titulos: 300;

    --fs-xs: 0.75rem;           /* 12px - labels, badges */
    --fs-sm: 0.875rem;          /* 14px - body small, secondary */
    --fs-md: clamp(0.95rem, 0.9rem + 0.25vw, 1.05rem);  /* 15-17px - base */
    --fs-lg: clamp(1.05rem, 1rem + 0.35vw, 1.2rem);     /* 17-19px - subheadings */
    --fs-xl: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);   /* 20-24px - section titles */
    --fs-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);        /* 24-32px - KPIs, hero */
    --fs-hero: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);     /* 32-56px - hero */

    /* Interlineado por papel: títulos, texto corrido y texto largo. Van SIN
       unidad a propósito: así el alto de línea escala con el tamaño de letra
       (un 24px fijo no lo hace). */
    --lh-tight: 1.2;
    --lh-base: 1.55;
    --lh-relaxed: 1.7;

    /* Grosores por papel. El 900 es el de las cifras de dinero (precios, montos):
       la pila del sistema lo tiene, y es lo que hace que un número destaque sin
       subir el tamaño. `--fw-medium` se retiró: estaba definido y no lo usaba
       nadie (séptima tanda). */
    --fw-normal: 400;
    --fw-bold: 600;
    --fw-black: 700;
    --fw-heavy: 900;

    /* --- Estructura --- */
    --ancho-sidebar: 264px;
    /* Medida de lectura: el ancho máximo de un bloque de texto, en "ch" (caracteres).
       El contenido ocupa todo el ancho de la pantalla, así que sin esto un párrafo en
       un monitor de 1900 px tendría renglones interminables. */
    --medida-texto: 74ch;
    --alto-barra-movil: 56px;
    --alto-nav-inferior: 62px;

    /* --- Movimiento --- */
    --tr-rapida: 0.15s ease;
    --tr-media: 0.22s ease;

    /* --- Capas (z-index ordenado, nunca números sueltos) --- */
    --z-toast: 200;
    --z-modal: 150;
    --z-tour: 300;
    --z-hoja: 120;
    --z-nav: 100;
}

/* =============================================================================
   02. TEMAS ELEGIBLES (Configuración)
   El tema principal es "Invernadero" (claro) y vive en `:root`. Aquí están los
   dos temas oscuros: "Alacena" (cocina de barro) y "Contraste". Ambos comparten
   la misma estructura y solo cambian los tokens de color: ningún componente
   sabe en qué tema está.
   ============================================================================= */
html[data-tema="alacena"],
html[data-tema="contraste"] {
    --bg-main: #17130F;
    --bg-main-rgb: 23, 19, 15;
    --slate-rgb: 205, 191, 169;
    --bg-sidebar: #1B1611;
    --bg-card: #221C16;
    --bg-card-hover: #2B241C;
    --bg-input: #1A1511;
    --bg-elevada: #271F18;
    --border-color: rgba(243,234,219,0.10);
    --border-suave: rgba(243,234,219,0.06);
    --border-fuerte: rgba(243,234,219,0.17);
    --border-hero: rgba(201,99,66,0.35);

    /* Los paneles del tema claro se mapean a las capas oscuras: el hero vuelve
       a ser una tarjeta y los bloques interiores suben un escalón. */
    --panel-keylime: #221C16;
    --panel-mint: #2B241C;
    --panel-sage: #221C16;
    --panel-slate: #271F18;
    --velo-modal: rgba(23,19,15,0.94);

    --marca: #C96342;
    --marca-rgb: 201, 99, 66;
    --marca-texto: #E08A67;
    --accion: #A6B874;
    --accion-rgb: 166, 184, 116;
    --accion-clara: #C3D193;
    --accion-clara-hover: #D2DEAA;
    --texto-sobre-accion: #1E2410;

    --text-fuerte: #F3EADB;
    --text-muted: #CDBFA9;
    --text-suave: #AC9C85;

    --rojo-rgb: 226, 112, 95;
    --rojo-fuerte: #E2705F;
    --ambar-rgb: 224, 164, 88;
    --badge-red-bg: rgba(var(--rojo-rgb), 0.18);
    --badge-red-border: rgba(var(--rojo-rgb), 0.4);
    --badge-red-text: #F09B8C;
    --badge-orange-bg: rgba(var(--ambar-rgb), 0.18);
    --badge-orange-border: rgba(var(--ambar-rgb), 0.4);
    --badge-orange-text: #EDBC7C;
    --badge-green-bg: rgba(var(--accion-rgb), 0.2);
    --badge-green-border: rgba(var(--accion-rgb), 0.45);
    --badge-green-text: #B7C98A;

    --grafica-1: #A6B874;
    --grafica-2: #D97A57;
    --grafica-3: #E0A458;
    --grafica-4: #8FB3AD;
    --grafica-5: #E2705F;
    --grafica-6: #C0A2C8;
    --grafica-7: #7E9CC0;
    --grafica-8: #C9B24A;
    --grafica-9: #B0A08A;

    /* En oscuro sí hay sombras: son el relieve de una cocina de noche. */
    --sh-1: 0 1px 2px rgba(0, 0, 0, 0.15);
    --sh-2: 0 4px 12px rgba(0, 0, 0, 0.18);
    --sh-3: 0 12px 28px rgba(0, 0, 0, 0.22);

    /* El serif sube a 600: sobre tinta, un trazo de 300 se deshace. */
    --fw-titulos: 600;
}

html[data-tema="contraste"] {
    --bg-main: #0A0806;
    --bg-main-rgb: 10, 8, 6;
    --slate-rgb: 220, 208, 190;
    --bg-sidebar: #0E0B08;
    --bg-card: #14100C;
    --bg-card-hover: #1C1712;
    --bg-input: #110D09;
    --bg-elevada: #191410;
    --border-color: #574A3C;
    --border-suave: #40362B;
    --border-fuerte: #6E5D4A;
    --border-hero: #E08A67;
    --panel-keylime: #14100C;
    --panel-mint: #1C1712;
    --panel-sage: #14100C;
    --panel-slate: #191410;
    --text-fuerte: #FFFFFF;
    --text-muted: #E2D6C4;
    --text-suave: #C4B7A4;
    /* En el tema de contraste la separación es el objetivo: el barro y el olivo
       suben un escalón para leerse sobre el casi-negro. */
    --marca: #E08A67;
    --marca-rgb: 224, 138, 103;
    --marca-texto: #F0A587;
    --accion: #C3D193;
    --accion-rgb: 195, 209, 147;
    --accion-clara: #E0E9C4;
    --accion-clara-hover: #EEF3DC;
    --texto-sobre-accion: #141A0A;
    --badge-red-text: #FCA5A5;
    --badge-orange-text: #FCD34D;
    --badge-green-text: #D6E4B0;
}

/* =============================================================================
   03. BASE Y ACCESIBILIDAD
   ============================================================================= */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    background-color: var(--bg-main);
    color: var(--text-fuerte);
    font-family: var(--ff-base);
    font-size: var(--fs-md);
    /* `--lh-base`, no `--lh-texto`: ese token no existe desde que los
       interlineados se renombraron por papel, así que el cuerpo se estaba
       pintando con el interlineado del navegador (ver corrección 105). */
    line-height: var(--lh-base);
    /* `dvh` mide el alto que SE VE: con `vh` la barra del navegador del celular
       se come la nav inferior. El `vh` de la línea de arriba es el respaldo
       para navegadores que todavía no entienden `dvh`. */
    height: 100vh;
    height: 100dvh;
    display: flex;
    overflow: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    transition: background-color 0.25s ease, color 0.25s ease;
}

/* Números de precios y métricas alineados en columna. */
.metrica,
.precio-compra,
.tienda-precio,
.metrica-sub {
    font-variant-numeric: tabular-nums;
}

h1, h2, h3 {
    /* Serif editorial para los títulos: es la mitad de la personalidad del
       sistema (el DESIGN.md pide 300 y tracking negativo al crecer). La otra
       mitad es la sans de la interfaz, que se queda en los componentes. */
    font-family: var(--ff-titulos);
    font-weight: var(--fw-titulos);
    line-height: var(--lh-tight);
    /* Reparte las palabras para que no quede una sola colgando en la última
       línea. Mejora progresiva: el navegador que no la entiende la ignora. */
    text-wrap: balance;
}

/* `h4` es el nivel de un nombre dentro de una tarjeta (integrante, producto):
   eso es interfaz, no portada. Va en sans para leerse a 14-16 px. */
h4 {
    font-family: var(--ff-base);
    font-weight: var(--fw-bold);
    line-height: var(--lh-tight);
}

/* Foco visible para navegar con teclado (no se ve al usar el ratón). */
:focus-visible {
    outline: 2px solid var(--accion);
    outline-offset: 2px;
    border-radius: var(--r-sm);
}

/* Scrollbars discretas y del color del borde. */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-fuerte); border-radius: var(--r-full); }
::-webkit-scrollbar-thumb:hover { background: rgba(var(--slate-rgb), 0.4); }
* { scrollbar-width: thin; scrollbar-color: var(--border-fuerte) transparent; }

::selection { background: rgba(var(--marca-rgb), 0.3); }

/* Texto que solo leen los lectores de pantalla (accesibilidad de la carga). */
.sr-solo {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Utilidades genéricas de una sola regla (evitan estilos inline en el HTML). */
.crece { flex: 1; min-width: 0; }
.texto-mayusculas { text-transform: uppercase; }
.con-boton-ojo { padding-right: 2.5rem; }
.icono-whatsapp { color: var(--whatsapp); }

.sidebar-user > i { font-size: var(--fs-sm); color: var(--text-muted); }

/* =============================================================================
   04. ESTRUCTURA
   ============================================================================= */
.app-layout {
    display: flex;
    /* `100%` y no `100vw`: `vw` cuenta también la barra de desplazamiento y
       saca una franja horizontal. `dvh` con `vh` de respaldo, igual que en
       `body`, para que la barra del navegador del celular no tape la nav. */
    width: 100%;
    height: 100vh;
    height: 100dvh;
}

/* --- Sidebar lateral (escritorio) ---
   Es un panel keylime: en el tema claro la navegación se separa del papel por
   TINTE (no por sombra), y el destino activo se rellena con la tinta forestal. */
.sidebar {
    width: var(--ancho-sidebar);
    background-color: var(--bg-sidebar);
    border-right: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: var(--sp-5) var(--sp-3);
    flex-shrink: 0;
}

.sidebar-brand {
    /* La marca es una portada: serif editorial, no la sans del panel. */
    font-family: var(--ff-titulos);
    font-size: 1.5rem;
    font-weight: var(--fw-titulos);
    letter-spacing: -0.02em;
    color: var(--marca-texto);
    margin-bottom: var(--sp-5);
    padding-left: var(--sp-2);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}

.sidebar-brand .logo-icono {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
}

/* Con 9 pestañas el bloque superior se desplaza en pantallas bajas. */
.sidebar > div:first-child {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: var(--sp-1);
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-bottom: var(--sp-2);
}

.sidebar-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 0.7rem var(--sp-2);
    border-radius: var(--r-sm);
    color: var(--text-muted);
    background: transparent;
    border: none;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-normal);
    width: 100%;
    text-align: left;
    transition: background-color var(--tr-rapida), color var(--tr-rapida);
}

.sidebar-item i {
    width: 1.1rem;
    text-align: center;
    font-size: 0.95rem;
    flex-shrink: 0;
}

/* Solo donde hay ratón: en táctil este `:hover` se queda pegado tras el toque. */
@media (hover: hover) {
    .sidebar-item:hover {
        color: var(--text-fuerte);
        background-color: rgba(var(--slate-rgb), 0.08);
    }
}

/* Destino activo = relleno de tinta y texto de papel. Es la misma relación
   papel/tinta de los badges del DESIGN.md: no hay un segundo color de marca. */
.sidebar-item.activo {
    background-color: var(--accion-clara);
    color: var(--texto-sobre-accion);
    font-weight: var(--fw-bold);
}

/* En los temas oscuros el relleno es claro y el texto oscuro: la barra lateral
   de barro conserva su marca lateral. En el tema claro sobra (el bloque ya
   está relleno) y por eso se apaga. */
html[data-tema="alacena"] .sidebar-item.activo::before,
html[data-tema="contraste"] .sidebar-item.activo::before {
    content: '';
    position: absolute;
    left: -0.3rem;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 55%;
    border-radius: var(--r-full);
    background-color: var(--marca);
}

.sidebar-user {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-1);
    border-top: 1px solid var(--border-color);
    padding-top: var(--sp-3);
    cursor: pointer;
    border-radius: var(--r-md);
    transition: background-color var(--tr-rapida);
    /* Es un <button> (se abre con teclado): se le quita la piel del navegador
       para que siga viéndose como la tarjeta de perfil del sidebar. */
    width: 100%;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
}

@media (hover: hover) { .sidebar-user:hover { background-color: rgba(var(--slate-rgb), 0.08); } }

.sidebar-salir { border-top: 0; padding-top: var(--sp-1); }
.sidebar-salir .user-avatar { background-color: rgba(var(--rojo-rgb), 0.14); color: var(--rojo-fuerte); }

.user-avatar {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
    border-radius: 50%;
    background-color: var(--accion-clara);
    color: var(--texto-sobre-accion);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: var(--fw-black);
    font-size: var(--fs-sm);
}

.user-datos { flex: 1; overflow: hidden; }
.user-nombre {
    display: block;
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}
.user-rol { display: block; font-size: var(--fs-xs); color: var(--text-muted); }

/* --- Área principal --- */
.main-content {
    flex: 1;
    /* Sin esto, un hijo ancho (una gráfica, una palabra larga) empuja el panel
       y aparece la barra horizontal aunque la rejilla sí sepa encogerse. */
    min-width: 0;
    overflow-y: auto;
    padding: var(--sp-6) var(--sp-6) var(--sp-7);
}

/* El contenido ocupa TODO el ancho útil. Antes se limitaba a 1280 px y quedaba
   centrado: en un monitor ancho (o al alejar el zoom) sobraban franjas vacías a los
   lados. Las rejillas reparten ese espacio en más columnas, que es lo que se quiere. */
#vista-activa {
    width: 100%;
    animation: aparecer 0.25s ease;
}

@keyframes aparecer {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}

/* --- Navegación de celular (se activa en la sección 20) --- */
.barra-movil { display: none; }
.nav-inferior { display: none; }
.hoja-mas { display: none; }

/* =============================================================================
   05. CABECERA DE VISTA
   ============================================================================= */
.header-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--sp-4);
    flex-wrap: wrap;
    margin-bottom: var(--sp-5);
}

.page-title {
    /* Escala editorial del DESIGN.md (heading 40 px), sin perder el clamp
       fluido para que en el celular no se coma la pantalla. */
    font-size: clamp(2rem, 1.65rem + 1.3vw, 2.5rem);
    font-weight: var(--fw-titulos);
    letter-spacing: -0.02em;
    line-height: 1.1;
    /* Tinta forestal: el título de cada vista es lo que le da identidad a la
       pantalla. Medido en 12.1:1 sobre el papel. */
    color: var(--marca-texto);
}

/* Subtítulos de sección dentro de una misma vista (Recetario, Dieta...). */
.header-top h2.page-title { font-size: var(--fs-xl); }

.page-subtitle {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    margin-top: var(--sp-1);
    max-width: var(--medida-texto);
}

/* =============================================================================
   06. REJILLAS
   ============================================================================= */
/* Las pistas `1fr` tienen un mínimo automático: un título largo, un badge sin
   partir o el lienzo de una gráfica pueden empujarlas más allá del contenedor.
   `minmax(0, 1fr)` deja que la pista se encoja; el `min-width: 0` de los hijos
   permite que su contenido se parta o se desplace dentro, no que ensanche la
   rejilla. Es la causa de los desbordes de tablet y celular. */
.grid-cards-4 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-5);
}

.grid-cards-3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-5);
}

.grid-cards-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-4);
    margin-bottom: var(--sp-5);
}

.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }

.grid-cards-2 > *,
.grid-cards-3 > *,
.grid-cards-4 > *,
.grid-2 > *,
.grid-3 > *,
.tablero > * { min-width: 0; }

/* --- Tablero de Inicio: rejilla de 12 columnas que reparte el ancho real.
   Por defecto cada bloque ocupa la fila completa (hero y fila de KPIs); la
   parte de abajo se reparte 8/12 + 4/12 para que las tarjetas no queden
   estiradas ni sobre espacio muerto a la derecha. --- */
.tablero {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--sp-5);
    align-items: start;
}

.tablero > * { grid-column: span 12; }

.tablero-urgente { grid-column: span 8; }
.tablero-acciones { grid-column: span 4; }

/* Dentro del tablero la separación la marca el hueco (gap) de la rejilla:
   si cada rejilla interna sumara su propio margen, la columna corta dejaría
   un hueco visible al lado de la larga. */
.tablero .grid-cards-2,
.tablero .grid-cards-3,
.tablero .grid-cards-4,
.tablero .seccion-inventario { margin-bottom: 0; }

/* Pila vertical: tarjetas una debajo de otra (columna de acciones). */
.pila { display: grid; gap: var(--sp-3); }

/* =============================================================================
   07. TARJETAS
   ============================================================================= */

/* --- Tarjeta cuadrada estándar (el bloque base de todo el sistema) ---
   28-42 px de aire del DESIGN.md; 32 px es el punto que aguanta datos densos
   sin que la tarjeta se sienta apretada. */
.card-square {
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--r-xl);
    padding: var(--sp-4);
    /* Un correo, un código o una palabra sin espacios no debe ensanchar la
       tarjeta: se parte dentro de su columna. */
    overflow-wrap: break-word;
}

/* --- Tarjeta de producto / indicador --- */
.card-pantry-item {
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--r-xl);
    padding: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    overflow-wrap: break-word;
    transition: border-color var(--tr-rapida), background-color var(--tr-rapida);
}

/* Al pasar el ratón la tarjeta sube un escalón de tinte (no de sombra).
   Los KPIs quedan fuera: no se pulsan, no deben prometerlo. */
@media (hover: hover) {
    .card-pantry-item:not(.kpi):hover {
        border-color: var(--border-fuerte);
        background-color: var(--bg-card-hover);
    }
}

/* Semáforo de caducidad (mismo código de color que los badges).
   Fondo plano y borde del color del estado: antes llevaba un degradado que, a
   poco que hubiera varias tarjetas urgentes, teñía la pantalla de rojo. */
.card-pantry-item.urgente {
    border-color: var(--badge-red-border);
    background: var(--bg-card);
    border-left: 3px solid var(--rojo-fuerte);
}

.card-pantry-item.pronto {
    border-color: var(--badge-orange-border);
    background: var(--bg-card);
    border-left: 3px solid rgb(var(--ambar-rgb));
}

.card-pantry-item.ganadora {
    border-color: var(--accion);
    border-left: 3px solid var(--accion);
}

/* --- Indicador con icono (KPIs). Rellena el hueco y da lectura rápida. --- */
.card-pantry-item.kpi {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    min-height: 92px;
    /* 24 y no 32: en una fila de cuatro, el precio largo ($6,741.00) necesita
       el hueco; con 32 el número se metía debajo del icono. */
    padding: var(--sp-3);
}

.kpi-texto { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }

.kpi-icono {
    flex-shrink: 0;
    width: 42px;
    height: 42px;
    border-radius: var(--r-md);
    display: grid;
    place-items: center;
    font-size: 1rem;
    background-color: rgba(var(--slate-rgb), 0.08);
    color: var(--accion-clara);
}

.kpi-icono.verde { background-color: rgba(var(--accion-rgb), 0.12); color: var(--accion-clara); }
.kpi-icono.rojo { background-color: rgba(var(--rojo-rgb), 0.12); color: var(--badge-red-text); }
.kpi-icono.mint { background-color: rgba(var(--accion-rgb), 0.10); color: var(--accion-clara); }

/* --- Tarjeta destacada (hero) ---
   En el tema claro es el panel de salvia del DESIGN.md: el bloque de más peso
   de la vista, separado por RELLENO (sin borde de color y sin sombra). En los
   temas oscuros vuelve a ser una tarjeta con su borde de barro. */
.card-hero-green {
    position: relative;
    overflow: hidden;
    background: var(--panel-sage);
    border: 1px solid var(--border-hero);
    border-radius: var(--r-xl);
    padding: var(--sp-5);
    color: var(--text-fuerte);
}

.card-hero-green .hero-texto:last-child { margin-bottom: 0; }

/* Variante en fila: ícono grande a la izquierda y texto a la derecha. */
.hero-fila { display: flex; align-items: center; gap: var(--sp-4); }
.hero-icono { font-size: 2.4rem; color: var(--accion-clara); line-height: 1; }
/* Una cifra es interfaz, no portada: sans y peso alto para que se lea de lejos. */
.hero-numero {
    font-family: var(--ff-base);
    font-size: var(--fs-2xl);
    font-weight: var(--fw-heavy);
    letter-spacing: -0.02em;
    margin: 0;
}

/* --- Tarjeta-acción: un <button> con apariencia de tarjeta (Inicio) --- */
.card-accion {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
    text-align: left;
    cursor: pointer;
    font: inherit;
    color: inherit;
    transition: border-color var(--tr-rapida), background-color var(--tr-rapida),
        box-shadow var(--tr-rapida), transform var(--tr-rapida);
}

/* Se levanta y se ilumina: deja claro que toda la tarjeta es pulsable.
   El foco de teclado lo pinta la regla global :focus-visible. */
@media (hover: hover) {
    .card-accion:hover {
        border-color: var(--accion);
        background-color: var(--bg-card-hover);
        box-shadow: var(--sh-2);
        transform: translateY(-2px);
    }
}

.card-accion:active { transform: translateY(0); }

/* Título de una tarjeta-acción = interfaz, no portada: sans 600. */
.card-accion h3 { font-family: var(--ff-base); font-size: var(--fs-md); font-weight: var(--fw-bold); }
.card-accion .metrica-sub { line-height: 1.35; }

.icono-grande { font-size: 2.2rem; color: var(--accion); }

/* --- Borde discontinuo: zona de carga / ticket vacío --- */
.borde-discontinuo {
    border: 2px dashed var(--border-color);
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-6) var(--sp-4);
}

/* --- Tarjeta de día del menú --- */
.card-dia { display: flex; flex-direction: column; gap: var(--sp-2); }

/* --- Recetario --- */
.card-receta {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-4);
}

/* --- Producto detectado en el ticket: tarjeta seleccionable --- */
.card-ticket {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-3);
    cursor: pointer;
    transition: border-color var(--tr-rapida), opacity var(--tr-rapida);
}

@media (hover: hover) { .card-ticket:hover { border-color: var(--accion); } }
.card-ticket.sin-seleccion { opacity: 0.5; }

.card-ticket input[type="checkbox"],
.ticket-check {
    margin-top: 0.2rem;
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    accent-color: var(--accion);
    cursor: pointer;
}

.card-ticket strong { display: block; font-size: var(--fs-md); font-weight: var(--fw-bold); }
.card-ticket .badge { margin-left: var(--sp-1); }
.card-ticket .metrica-sub { display: block; margin-top: 0.2rem; }

/* Lista de productos detectados por la IA en el ticket. */
.ticket-lista {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    max-height: 340px;
    overflow-y: auto;
    padding-right: 0.15rem;
}

/* --- Proporción por categoría (Estadísticas) --- */
.card-categoria { display: flex; flex-direction: column; gap: var(--sp-1); }

/* --- Integrante de la familia (Configuración) --- */
.card-miembro {
    display: flex;
    gap: var(--sp-3);
    align-items: flex-start;
    background-color: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--sp-3);
}

.card-miembro.eres-tu { border-color: var(--accion); background-color: rgba(var(--accion-rgb), 0.07); }

.avatar-mini {
    flex: 0 0 auto;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(var(--marca-rgb), 0.18);
    color: var(--accion-clara);
    font-size: var(--fs-sm);
    font-weight: var(--fw-black);
}

/* =============================================================================
   08. MÉTRICAS Y ETIQUETAS
   ============================================================================= */
.metrica {
    /* Una cifra es interfaz: sans, aunque el elemento sea un <h2> (los KPIs de
       Inicio lo son). Si heredara el serif de los títulos, los precios saldrían
       con cifras de viejo estilo y se leerían peor. */
    font-family: var(--ff-base);
    font-size: var(--fs-2xl);
    font-weight: var(--fw-black);
    letter-spacing: -0.02em;
    color: var(--text-fuerte);
    line-height: 1.1;
    /* Cifras de ancho fijo: al actualizarse un precio, los dígitos no bailan. */
    font-variant-numeric: tabular-nums;
}

.metrica.verde { color: var(--accion-clara); }
.metrica.rojo { color: var(--badge-red-text); }
.metrica.mint { color: var(--accion-clara); }

/* Cifra en una tarjeta chica: el mismo número, un par de escalones abajo. */
.metrica.chica { font-size: var(--fs-lg); }

.metrica-sub { font-size: var(--fs-xs); color: var(--text-muted); }

.etiqueta-mini {
    /* El "eyebrow" del DESIGN.md: 11 px, 600, 0.08em, mayúsculas y tinta
       forestal. Es un marcador de navegación, no decoración. */
    font-size: 0.6875rem;
    color: var(--marca-texto);
    font-weight: var(--fw-bold);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.tarjeta-cabecera {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--sp-2);
    /* En una tarjeta angosta (tablet/celular) el badge baja en vez de empujar
       la tarjeta fuera de su columna. */
    flex-wrap: wrap;
    margin-bottom: var(--sp-2);
}

/* Un nombre de tarjeta (producto, tienda, integrante) es interfaz: sans 600.
   El serif se reserva para los títulos de sección y las portadas. */
.tarjeta-titulo {
    font-family: var(--ff-base);
    font-size: var(--fs-lg);
    font-weight: var(--fw-bold);
}
/* Título de tarjeta al nivel del texto de apoyo (listas densas). */
.tarjeta-titulo.chica { font-size: var(--fs-sm); }
.tarjeta-sub { font-size: var(--fs-sm); color: var(--text-muted); }

/* Código de invitación de la familia: el dato más grande de su tarjeta. Va en
   sans de ancho fijo (es un código que se copia, no una portada). */
.codigo-invitacion {
    font-family: var(--ff-base);
    font-size: var(--fs-2xl);
    font-weight: var(--fw-heavy);
    letter-spacing: 0.12em;
    color: var(--accion-clara);
    /* Es un código: se lee de un tirón, nunca partido en dos renglones. */
    white-space: nowrap;
}

/* Cuando el código y el botón no caben, el botón baja pero se queda a la
   derecha (el código manda). */
#btn-nuevo-codigo { margin-left: auto; }

/* Título de un bloque dentro de una tarjeta (un formulario, un resultado):
   un escalón más chico que el título de la tarjeta y separado de lo que sigue. */
.bloque-titulo { font-size: var(--fs-lg); font-weight: var(--fw-titulos); margin-bottom: var(--sp-4); }

.tarjeta-acciones {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-2);
    /* Mismo motivo que la cabecera: precio + contador + botón caben o bajan. */
    flex-wrap: wrap;
    border-top: 1px solid var(--border-suave);
    padding-top: var(--sp-3);
    margin-top: var(--sp-3);
}

.acciones-cabecera { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.acciones-iconos { display: flex; gap: var(--sp-1); }

.hero-titulo {
    font-size: var(--fs-hero);
    font-weight: var(--fw-titulos);
    letter-spacing: -0.03em;
    line-height: 1.05;
    margin: var(--sp-2) 0;
}
.hero-texto { font-size: var(--fs-sm); color: var(--text-muted); line-height: var(--lh-base); text-wrap: pretty; margin-bottom: var(--sp-4); max-width: var(--medida-texto); }

/* =============================================================================
   09. BADGES Y CONTROLES
   ============================================================================= */
.badge {
    font-size: var(--fs-xs);
    padding: 0.3rem 0.7rem;
    border-radius: var(--r-full);
    font-weight: var(--fw-bold);
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}

.badge-red { background-color: var(--badge-red-bg); border: 1px solid var(--badge-red-border); color: var(--badge-red-text); }
.badge-orange { background-color: var(--badge-orange-bg); border: 1px solid var(--badge-orange-border); color: var(--badge-orange-text); }
.badge-green { background-color: var(--badge-green-bg); border: 1px solid var(--badge-green-border); color: var(--badge-green-text); }
/* Etiqueta neutra = etiqueta de papel: fondo crema y texto de tinta. Es el
   "pill badge" del DESIGN.md, separado de los tres colores semánticos. */
.badge-cat { background-color: var(--bg-elevada); color: var(--text-muted); border: 1px solid var(--border-suave); }
.badge-mint { background-color: rgba(var(--accion-rgb), 0.10); border: 1px solid var(--accion-clara); color: var(--accion-clara); }

/* Chips de filtro */
.barra-filtros { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-bottom: var(--sp-5); }
/* El buscador se estira y empuja a los chips; en pantalla chica los chips
   bajan solos (el contenedor ya tiene `flex-wrap`). */
.barra-filtros .input-icon-wrapper { flex: 1; min-width: 220px; }

.chip {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border-color);
    border-radius: var(--r-full);
    padding: 0.45rem 0.85rem;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    cursor: pointer;
    transition: background-color var(--tr-rapida), color var(--tr-rapida), border-color var(--tr-rapida);
}

@media (hover: hover) { .chip:hover { color: var(--text-fuerte); background: var(--bg-card-hover); } }
/* Filtro activo: misma relación tinta/papel que el destino activo del menú. */
.chip.activo {
    background: var(--accion-clara);
    border-color: var(--accion-clara);
    color: var(--texto-sobre-accion);
}

/* Control segmentado (pestañas internas: Inventario | Agregar | Escanear) */
.segmented {
    display: inline-flex;
    /* Los botones se acomodan en varios renglones en vez de forzar un ancho
       mínimo mayor que la tarjeta (era el desborde de Configuración en 390 px). */
    flex-wrap: wrap;
    gap: 0.2rem;
    background-color: var(--bg-input);
    padding: 0.28rem;
    border-radius: var(--r-md);
    border: 1px solid var(--border-color);
    margin-bottom: var(--sp-5);
    max-width: 100%;
}

.seg-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    padding: 0.5rem 1rem;
    border-radius: var(--r-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    white-space: nowrap;
    transition: background-color var(--tr-rapida), color var(--tr-rapida);
}

@media (hover: hover) { .seg-btn:hover { color: var(--text-fuerte); } }
/* La pestaña activa se rellena con la tinta (el botón principal del sistema). */
.seg-btn.activo { background-color: var(--accion-clara); color: var(--texto-sobre-accion); }

/* Pestañas del modal de acceso */
.tabs-container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-2);
    background-color: var(--bg-input);
    padding: 0.25rem;
    border-radius: var(--r-md);
    border: 1px solid var(--border-color);
    margin-bottom: var(--sp-5);
}

.tab-btn {
    padding: 0.5rem;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    border-radius: var(--r-sm);
    border: none;
    cursor: pointer;
    background: transparent;
    color: var(--text-muted);
    transition: background-color var(--tr-rapida), color var(--tr-rapida);
}

.tab-btn.activo { background-color: var(--accion-clara); color: var(--texto-sobre-accion); }

/* Contador de cantidad (lista de compras) */
.stepper {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    background-color: var(--bg-elevada);
    border: 1px solid var(--border-color);
    border-radius: var(--r-full);
    padding: 0.15rem;
}

.stepper button {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background: transparent;
    color: var(--accion);
    font-size: 0.95rem;
    font-weight: var(--fw-heavy);
    cursor: pointer;
    line-height: 1;
}

@media (hover: hover) { .stepper button:hover:not(:disabled) { background-color: rgba(var(--marca-rgb), 0.15); } }
.stepper button:disabled { color: var(--text-muted); cursor: not-allowed; }
.stepper span { min-width: 1.6rem; text-align: center; font-size: var(--fs-sm); font-weight: var(--fw-black); }
.stepper input {
    width: 2.6rem;
    border: 0;
    background: transparent;
    color: var(--text-fuerte);
    font: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-black);
    text-align: center;
}

/* Interruptores de avisos (Configuración) */
.fila-switch {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background-color: var(--bg-input);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    cursor: pointer;
    margin-bottom: 0.45rem;
}

.fila-switch input { width: 16px; height: 16px; accent-color: var(--accion); cursor: pointer; }
.fila-switch i { color: var(--accion-clara); }

/* Estado de los canales de aviso (Configuración) */
.avisos-canales {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin: var(--sp-3) 0 var(--sp-2);
}

.avisos-acciones {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-top: var(--sp-2);
}

/* =============================================================================
   10. BOTONES
   ============================================================================= */
.btn-mint,
.btn-outline,
.btn-whatsapp,
.btn-icon-action {
    font-family: inherit;
    cursor: pointer;
    transition: background-color var(--tr-rapida), border-color var(--tr-rapida), color var(--tr-rapida), opacity var(--tr-rapida);
}

.btn-mint {
    background-color: var(--accion-clara);
    color: var(--texto-sobre-accion);
    font-weight: var(--fw-bold);
    border: 1px solid transparent;
    /* Botón principal del DESIGN.md: 14 px de alto de relleno y 14 de radio. */
    padding: 0.85rem 1.35rem;
    border-radius: var(--r-md);
    font-size: var(--fs-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
}

@media (hover: hover) { .btn-mint:hover { background-color: var(--accion-clara-hover); } }
.btn-mint:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-outline {
    background: transparent;
    color: var(--text-fuerte);
    border: 1px solid var(--border-fuerte);
    padding: 0.55rem 0.95rem;
    border-radius: var(--r-md);
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

@media (hover: hover) { .btn-outline:hover { background-color: var(--bg-card-hover); border-color: var(--text-muted); } }

/* Botón que solo lleva un icono (borrar receta, quitar artículo...) */
.btn-icon-action {
    background: rgba(var(--slate-rgb), 0.08);
    border: 1px solid var(--border-color);
    color: var(--text-muted);
    width: 32px;
    height: 32px;
    border-radius: var(--r-sm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

@media (hover: hover) { .btn-icon-action:hover { color: var(--text-fuerte); background: rgba(var(--slate-rgb), 0.16); } }
@media (hover: hover) { .btn-icon-action.danger:hover { color: var(--badge-red-text); background: rgba(var(--rojo-rgb), 0.15); border-color: var(--rojo-fuerte); } }

.btn-whatsapp { background-color: var(--accion-clara); color: var(--texto-sobre-accion); font-weight: var(--fw-bold); border: 1px solid var(--accion-clara); }
@media (hover: hover) { .btn-whatsapp:hover { background-color: var(--accion-clara-hover); border-color: var(--accion-clara-hover); } }

.btn-mini { padding: 0.4rem 0.75rem; font-size: var(--fs-xs); }
.btn-ancho { width: 100%; }

/* =============================================================================
   11. FORMULARIOS
   ============================================================================= */
.form-group { margin-bottom: var(--sp-4); }

.form-label {
    display: block;
    font-size: 0.8125rem;
    font-weight: var(--fw-bold);
    color: var(--text-fuerte);
    margin-bottom: 0.35rem;
}

.input-icon-wrapper { position: relative; display: flex; align-items: center; }
.input-icon-wrapper i.icon-left {
    position: absolute;
    left: var(--sp-3);
    color: var(--text-muted);
    font-size: var(--fs-sm);
    pointer-events: none;
}

/* El campo es una etiqueta de papel: fondo crema sobre la tarjeta keylime.
   El borde es el token "fuerte" para que se vea sobre el papel; el foco lo
   pinta con la tinta forestal. */
.form-input,
.form-select {
    width: 100%;
    /* Un input es hijo de rejilla/flex: sin esto su ancho mínimo puede empujar
       la columna (pasaba con el teléfono dentro de la tarjeta de Configuración). */
    min-width: 0;
    background-color: var(--bg-input);
    border: 1px solid var(--border-fuerte);
    border-radius: var(--r-md);
    padding: 0.8rem var(--sp-2);
    font-family: inherit;
    font-size: var(--fs-md);
    color: var(--text-fuerte);
    outline: none;
    transition: border-color var(--tr-rapida), background-color var(--tr-rapida);
}

.form-input::placeholder { color: var(--text-suave); }
.form-input:focus, .form-select:focus { border-color: var(--accion); background-color: var(--bg-elevada); }
/* Chrome/Edge pintan de azul los campos autocompletados e ignoran el fondo del
   CSS. Se repinta el campo con el color del sistema (sombra interior opaca) y
   se conserva el texto de tinta: si no, el primer campo del login rompe el tema. */
.form-input:-webkit-autofill,
.form-input:-webkit-autofill:hover,
.form-input:-webkit-autofill:focus {
    -webkit-text-fill-color: var(--text-fuerte);
    -webkit-box-shadow: 0 0 0 1000px var(--bg-input) inset;
    caret-color: var(--text-fuerte);
}
.input-icon-wrapper .form-input { padding-left: 2.6rem; }

/* Campo estrecho (un teléfono, un precio) que no debe estirarse con la rejilla. */
.campo-angosto { max-width: 220px; }

.form-select option { background-color: var(--bg-card); color: var(--text-fuerte); }

/* Rejilla del formulario de compras: se adapta sola y nunca desborda. */
.form-rejilla {
    display: grid;
    grid-template-columns: minmax(160px, 2fr) minmax(120px, 1fr) minmax(0, 0.8fr) minmax(120px, 1.2fr) auto;
    gap: var(--sp-2);
    align-items: center;
}

.form-rejilla > * { min-width: 0; }

/* Botón para mostrar/ocultar contraseña */
.btn-eye {
    position: absolute;
    right: 0.85rem;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0;
    font-size: var(--fs-md);
}
@media (hover: hover) { .btn-eye:hover { color: var(--text-fuerte); } }

.phone-wrapper { display: flex; gap: var(--sp-2); }

.select-lada {
    width: 105px;
    flex-shrink: 0;
    background-color: var(--bg-input);
    border: 1px solid var(--border-fuerte);
    border-radius: var(--r-md);
    padding: 0.8rem 0.5rem;
    color: var(--text-fuerte);
    outline: none;
    font-family: inherit;
    font-size: var(--fs-sm);
}

/* Medidor de fuerza de la contraseña */
.password-meter-bar {
    height: 4px;
    width: 100%;
    background-color: var(--border-color);
    border-radius: var(--r-full);
    overflow: hidden;
    margin-top: var(--sp-2);
}

.password-meter-fill {
    height: 100%;
    width: 0%;
    transition: width 0.3s ease, background-color 0.3s ease;
    /* Relleno por defecto (débil). El módulo lo cambia según la fuerza; el
       color de cada nivel sale de los mismos tokens semánticos. */
    background-color: var(--rojo-fuerte);
}

.requisitos-lista {
    list-style: none;
    margin: var(--sp-2) 0 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.3rem;
}

.req-item { font-size: var(--fs-xs); color: var(--badge-red-text); display: flex; align-items: center; gap: 0.3rem; }
.req-item.cumplido { color: var(--accion); }

/* =============================================================================
   12. MODAL DE ACCESO
   Es la portada del producto: dos columnas, panel keylime con la promesa y el
   formulario sobre papel. En el celular queda una sola columna y se oculta la
   vista previa para que el primer campo no quede a dos pantallas de distancia.
   ============================================================================= */
.modal-overlay {
    position: fixed;
    inset: 0;
    background-color: var(--velo-modal);
    z-index: var(--z-modal);
    display: flex;
    /* `flex-start` + `margin:auto` de la tarjeta: centra cuando cabe y NO
       recorta el borde superior cuando el formulario es más alto que la
       pantalla (el caso del registro en un celular). */
    align-items: flex-start;
    justify-content: center;
    padding: var(--sp-4);
    overflow-y: auto;
    /* Al llegar al final del diálogo, la rueda del ratón NO sigue desplazando la
       vista que quedó detrás: el modal es un mundo aparte. */
    overscroll-behavior: contain;
}

.modal-card {
    background-color: var(--bg-main);
    border: 1px solid var(--border-suave);
    border-radius: var(--r-xl);
    padding: 0;
    width: 100%;
    max-width: 1040px;
    box-shadow: var(--sh-3);
    margin: auto;
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    overflow: hidden;
}

/* Diálogo de consumo parcial (café de 500 g, aceite de 1 L…). */
.modal-consume {
    width: 100%;
    max-width: 420px;
    margin: auto;
    padding: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.consume-opciones {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-2);
}

.consume-opcion {
    padding: var(--sp-2);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    background-color: var(--bg-input);
    color: var(--text-fuerte);
    font: inherit;
    font-weight: var(--fw-bold);
    cursor: pointer;
}

@media (hover: hover) {
    .consume-opcion:hover { border-color: var(--border-fuerte); background-color: var(--panel-keylime); }
}

/* --- Columna de marca --- */
.marca-auth {
    background-color: var(--panel-keylime);
    padding: var(--sp-6) var(--sp-5);
    text-align: left;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--sp-2);
}

.auth-logo {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    color: var(--marca-texto);
    font-family: var(--ff-titulos);
    font-size: 1.5rem;
    font-weight: var(--fw-titulos);
    letter-spacing: -0.02em;
}

.marca-auth .logo-cuadro {
    width: 44px;
    height: 44px;
    background: var(--bg-elevada);
    color: var(--marca-texto);
    border: 1px solid var(--border-suave);
    border-radius: var(--r-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    flex-shrink: 0;
}

/* El titular de la portada: el tamaño más grande del sistema. */
#titulo-auth {
    font-size: clamp(2.2rem, 1.7rem + 1.8vw, 3.25rem);
    font-weight: var(--fw-titulos);
    line-height: 1.02;
    letter-spacing: -0.02em;
    color: var(--marca-texto);
}

/* El "eyebrow" se separa del logo y se pega al titular. */
.marca-auth .etiqueta-mini { margin-top: var(--sp-3); }

#subtitulo-auth {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    line-height: var(--lh-base);
    max-width: 38ch;
    margin-top: var(--sp-1);
}

/* Tres promesas, con el mismo ícono del glosario que usa la app. */
.auth-beneficios {
    list-style: none;
    display: grid;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
}

.auth-beneficios li {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-sm);
    color: var(--text-fuerte);
}

.auth-beneficios i {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    font-size: 0.72rem;
    background-color: var(--bg-elevada);
    border: 1px solid var(--border-suave);
    color: var(--marca-texto);
}

/* Vista previa de la app: un "product preview" de papel sobre el panel, como
   el DESIGN.md. Es decorativa (los datos son de ejemplo) y va `aria-hidden`. */
.auth-preview {
    margin-top: var(--sp-4);
    padding: var(--sp-3);
    background-color: var(--bg-elevada);
    border-radius: var(--r-lg);
    display: grid;
    gap: 0.55rem;
}

.auth-preview-titulo {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-2);
    padding-bottom: 0.55rem;
    border-bottom: 1px solid var(--border-suave);
}

.auth-preview-fila {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: var(--fs-xs);
    color: var(--text-muted);
}

.auth-preview-fila i {
    width: 1rem;
    text-align: center;
    color: var(--marca-texto);
}

.auth-preview-fila strong {
    margin-left: auto;
    color: var(--text-fuerte);
    font-weight: var(--fw-bold);
    font-variant-numeric: tabular-nums;
}

/* --- Columna del formulario --- */
.auth-cuerpo {
    background-color: var(--bg-main);
    padding: var(--sp-6) var(--sp-5);
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.auth-cuerpo .tabs-container { margin-bottom: var(--sp-4); }

.btn-enviar-auth {
    width: 100%;
    padding: 1rem;
    margin-top: var(--sp-2);
    background-color: var(--accion-clara);
    color: var(--texto-sobre-accion);
    font-size: var(--fs-md);
}

.pie-auth {
    text-align: center;
    margin-top: var(--sp-5);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--border-suave);
}

.enlace-auth {
    background: none;
    border: none;
    color: var(--marca-texto);
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}
@media (hover: hover) { .enlace-auth:hover { color: var(--text-fuerte); } }

/* =============================================================================
   13. AVISOS Y TOASTS
   ============================================================================= */
.mensaje-alerta {
    padding: var(--sp-3) var(--sp-3);
    border-radius: var(--r-md);
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    margin-bottom: var(--sp-4);
    text-align: center;
}

.mensaje-alerta.error { background-color: rgba(var(--rojo-rgb), 0.10); border: 1px solid var(--rojo-fuerte); color: var(--badge-red-text); }
.mensaje-alerta.exito { background-color: rgba(var(--accion-rgb), 0.10); border: 1px solid var(--accion); color: var(--accion-clara); }
.mensaje-alerta.info {
    background-color: rgba(var(--marca-rgb), 0.08);
    border: 1px solid var(--accion-clara);
    color: var(--accion-clara);
    text-align: left;
    font-weight: var(--fw-normal);
    line-height: var(--lh-base);
}

.mensaje-alerta.info code {
    background-color: rgba(var(--slate-rgb), 0.10);
    padding: 0.05rem 0.3rem;
    border-radius: 0.35rem;
    font-size: var(--fs-xs);
}

.toasts-contenedor {
    position: fixed;
    bottom: var(--sp-5);
    right: var(--sp-5);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    z-index: var(--z-toast);
    max-width: min(340px, calc(100% - 2rem));
}

.toast {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    background-color: var(--bg-elevada);
    border: 1px solid var(--border-fuerte);
    border-radius: var(--r-md);
    padding: var(--sp-3) var(--sp-4);
    font-size: var(--fs-sm);
    font-weight: var(--fw-bold);
    box-shadow: var(--sh-3);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

.toast.visible { opacity: 1; transform: translateY(0); }
.toast-exito { border-color: var(--accion); color: var(--accion-clara); }
.toast-exito i { color: var(--accion); }
.toast-error { border-color: var(--rojo-fuerte); color: var(--badge-red-text); }
.toast-error i { color: var(--rojo-fuerte); }
.toast-info { color: var(--text-muted); }

/* =============================================================================
   14. ESTADOS: CARGA, ESQUELETO Y VACÍO
   ============================================================================= */
.cargando {
    color: var(--text-muted);
    font-size: var(--fs-md);
    padding: var(--sp-7) var(--sp-4);
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
}

/* Esqueletos: llenan el hueco mientras llegan los datos del servidor, así la
   página nunca se ve "vacía" ni da un salto al pintar el contenido. */
.esqueleto { display: grid; gap: var(--sp-4); }

.esqueleto-linea {
    height: 0.7rem;
    border-radius: var(--r-full);
    background: linear-gradient(90deg, var(--bg-card-hover) 25%, rgba(var(--slate-rgb), 0.14) 37%, var(--bg-card-hover) 63%);
    background-size: 400% 100%;
    animation: brillo 1.4s ease-in-out infinite;
    margin-bottom: var(--sp-2);
}

.esqueleto-linea.corta { width: 45%; }
.esqueleto-linea.media { width: 70%; }
.esqueleto-linea.alta { height: 1.6rem; }

.esqueleto-tarjeta {
    background-color: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--r-xl);
    padding: var(--sp-5);
}

@keyframes brillo {
    0% { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

/* Estado vacío: un cuadro con icono en círculo, no un hueco blanco. */
.estado-vacio {
    text-align: center;
    padding: var(--sp-7) var(--sp-5);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-height: 210px;
}

.estado-vacio i {
    font-size: 1.5rem;
    color: var(--accion-clara);
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background-color: rgba(var(--marca-rgb), 0.10);
    border: 1px solid var(--border-color);
    margin-bottom: var(--sp-1);
}

.estado-vacio h3 { font-size: var(--fs-lg); font-weight: var(--fw-titulos); }
.estado-vacio p { font-size: var(--fs-sm); color: var(--text-muted); max-width: 46ch; }
.estado-vacio .btn-mint, .estado-vacio .btn-outline { margin-top: var(--sp-2); }

/* Variante "todo en orden": el mismo cuadro, pero en verde de logro. */
.estado-vacio.exito i {
    color: var(--accion);
    background-color: rgba(var(--accion-rgb), 0.12);
    border-color: rgba(var(--accion-rgb), 0.28);
}

/* =============================================================================
   15. SECCIONES Y BARRAS
   ============================================================================= */
.seccion-inventario { margin-bottom: var(--sp-6); }

.seccion-cabecera {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-3);
    margin-bottom: var(--sp-4);
    flex-wrap: wrap;
}

.seccion-cabecera h2,
.seccion-cabecera h3 {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-lg);
    font-weight: var(--fw-titulos);
}

.seccion-cabecera h2 i,
.seccion-cabecera h3 i { color: var(--accion-clara); font-size: var(--fs-sm); }

/* En la despensa el título de cada grupo hereda el color de su semáforo —el
   mismo del badge de al lado—, que llega como `data-nivel`. */
.seccion-cabecera h2 i.icono-mini,
.seccion-cabecera h3 i.icono-mini { font-size: var(--fs-xs); }
.seccion-cabecera h2 i.rojo { color: var(--badge-red-text); }
.seccion-cabecera h2[data-nivel="rojo"] { color: var(--badge-red-text); }
.seccion-cabecera h2[data-nivel="ambar"] { color: var(--badge-orange-text); }
.seccion-cabecera h2[data-nivel="verde"] { color: var(--badge-green-text); }
/* El punto del semáforo repite el color del título: el color nunca es el único
   mensaje (el texto y el badge ya lo dicen), pero si va, va completo. */
.seccion-cabecera h2[data-nivel="rojo"] i { color: var(--badge-red-text); }
.seccion-cabecera h2[data-nivel="ambar"] i { color: var(--badge-orange-text); }
.seccion-cabecera h2[data-nivel="verde"] i { color: var(--badge-green-text); }

/* Variante pegada: cuando lo que sigue (una lista) ya trae su propio aire. */
.seccion-cabecera.pegada { margin-bottom: var(--sp-2); }

.titulo-seccion { font-size: var(--fs-lg); font-weight: var(--fw-titulos); margin-bottom: var(--sp-3); }
/* El ícono de un título de tarjeta va en barro: agrupa sin competir con el
   verde de acción ni con los semáforos. */
.titulo-seccion i { color: var(--marca-texto); }

/* Barra de proporción (uso de categorías, avance de compra) */
.barra-progreso {
    height: 0.35rem;
    border-radius: var(--r-full);
    background-color: var(--border-color);
    overflow: hidden;
    margin: var(--sp-1) 0;
}

.barra-progreso > span { display: block; height: 100%; border-radius: var(--r-full); background-color: var(--accion); transition: width 0.4s ease; }

/* Nota/sugerencia con acento a la izquierda */
.motivo-sugerencia {
    background-color: rgba(var(--marca-rgb), 0.10);
    border-left: 3px solid var(--accion);
    border-radius: var(--r-sm);
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-xs);
    color: var(--accion-clara);
    margin-top: var(--sp-3);
    line-height: var(--lh-base);
}

/* Panel embebido (formulario de WhatsApp dentro de una tarjeta) */
.panel-inline {
    background-color: var(--bg-input);
    border: 1px dashed var(--border-color);
    border-radius: var(--r-md);
    padding: var(--sp-3) var(--sp-4);
}

/* =============================================================================
   16. MENÚ IA Y RECETARIO
   ============================================================================= */
.platillo {
    background-color: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--sp-3);
}

.platillo-cabecera {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
}

.platillo-nombre { display: block; font-size: var(--fs-md); font-weight: var(--fw-bold); margin-top: 0.2rem; }

.platillo-detalle { margin-top: var(--sp-2); }

.platillo-detalle summary {
    cursor: pointer;
    font-size: var(--fs-xs);
    font-weight: var(--fw-bold);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--accion-clara);
    list-style: none;
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.platillo-detalle summary::-webkit-details-marker { display: none; }
.platillo-detalle summary::before { content: '\f0da'; font-family: 'Font Awesome 6 Free'; font-weight: var(--fw-heavy); font-size: 0.6rem; }
.platillo-detalle[open] summary::before { content: '\f0d7'; }

.platillo-detalle p {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    line-height: var(--lh-base);
    margin-top: var(--sp-2);
}

/* Pasos de preparación numerados: la IA devuelve una lista y así se lee mejor
   que un párrafo corrido (antes solo decía "calienta esto y agrega esto"). */
.receta-pasos {
    margin: var(--sp-2) 0 0;
    padding-left: 0;
    list-style: none;
    counter-reset: paso;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.receta-pasos li {
    counter-increment: paso;
    position: relative;
    padding-left: 1.85rem;
    font-size: var(--fs-sm);
    color: var(--text-muted);
    line-height: var(--lh-base);
}

.receta-pasos li::before {
    content: counter(paso);
    position: absolute;
    left: 0;
    top: 0.05rem;
    width: 1.3rem;
    height: 1.3rem;
    border-radius: 50%;
    background-color: rgba(var(--marca-rgb), 0.15);
    color: var(--accion-clara);
    border: 1px solid var(--border-color);
    font-size: var(--fs-xs);
    font-weight: var(--fw-black);
    display: grid;
    place-items: center;
}

.receta-pasos strong { color: var(--accion-clara); font-weight: var(--fw-bold); }

/* =============================================================================
   17. ESTADÍSTICAS
   ============================================================================= */
.grafico-caja { position: relative; height: 260px; width: 100%; }

.leyenda-color {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    margin-right: 0.3rem;
    vertical-align: middle;
}

/* =============================================================================
   18. COMPRAS Y TIENDAS
   ============================================================================= */
.card-item-compra {
    background-color: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--r-lg);
    padding: var(--sp-3) var(--sp-4);
    transition: border-color var(--tr-media), opacity var(--tr-media);
}

.card-item-compra.comprado { opacity: 0.55; }
.card-item-compra.comprado .tarjeta-titulo { text-decoration: line-through; }

.check-compra {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    cursor: pointer;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    font-weight: var(--fw-bold);
}

.check-compra input { width: 16px; height: 16px; accent-color: var(--accion); cursor: pointer; }

.meta-compra { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }

.pie-compra {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    margin-top: var(--sp-3);
    flex-wrap: wrap;
}

.precio-compra { font-size: var(--fs-lg); font-weight: var(--fw-heavy); color: var(--accion-clara); }

.card-comparativa { display: flex; flex-direction: column; }

.card-tienda-opcion {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    background-color: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--r-md);
    padding: var(--sp-2) var(--sp-3);
}

.card-tienda-opcion.mejor { border-color: var(--accion); background-color: rgba(var(--accion-rgb), 0.08); }
.card-tienda-opcion.mejor .tienda-nombre,
.card-tienda-opcion.mejor .tienda-precio { color: var(--accion-clara); }

.tienda-nombre { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-muted); }
.tienda-precio { font-size: 0.95rem; font-weight: var(--fw-heavy); }

/* =============================================================================
   19. ESCÁNER
   ============================================================================= */
.video-wrap {
    width: 100%;
    border-radius: var(--r-md);
    overflow: hidden;
    margin: var(--sp-3) 0;
    border: 1px solid var(--border-color);
    /* Negro puro a propósito: el visor de la cámara se recorta contra él y un
       gris del tema teñiría las orillas del video. */
    background-color: var(--bg-camara);
    min-height: 180px;
}

.video-wrap video { width: 100%; display: block; }

/* =============================================================================
   20. RESPONSIVE
   ============================================================================= */

/* Tablet: 3 columnas pasan a 2. */
@media (max-width: 1100px) {
    .grid-cards-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .main-content { padding: var(--sp-5) var(--sp-5) var(--sp-6); }

    /* El formulario de compras pasa de 5 columnas a 2: sus campos ya no caben
       junto al sidebar en una tablet y el botón baja a su propio renglón. */
    .form-rejilla { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .form-rejilla .btn-mint { grid-column: 1 / -1; width: 100%; }

    /* El tablero pierde la columna lateral: las secciones recuperan el ancho
       completo, una debajo de otra. */
    .tablero-urgente,
    .tablero-acciones { grid-column: span 12; }
}

/* Celular y tablet vertical: la navegación se va abajo, como una app. */
@media (max-width: 880px) {
    .app-layout { flex-direction: column; }

    /* La barra lateral de 9 pestañas no cabe: se reemplaza por barra superior
       + navegación inferior con las 5 acciones principales y una hoja "Más". */
    .sidebar { display: none; }

    .barra-movil {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: var(--sp-3);
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        height: var(--alto-barra-movil);
        padding: 0 var(--sp-4);
        background-color: var(--bg-main);
        border-bottom: 1px solid var(--border-color);
        z-index: var(--z-nav);
    }

    .barra-movil-marca {
        display: flex;
        align-items: center;
        gap: var(--sp-2);
        font-family: var(--ff-titulos);
        font-weight: var(--fw-titulos);
        font-size: 1.4rem;
        letter-spacing: -0.02em;
        color: var(--marca-texto);
    }

    .barra-movil-marca .logo-icono { width: 24px; height: 24px; }

    .barra-movil-avatar {
        width: 34px;
        height: 34px;
        border-radius: 50%;
        background-color: var(--accion-clara);
        color: var(--texto-sobre-accion);
        border: none;
        font-family: inherit;
        font-weight: var(--fw-black);
        font-size: var(--fs-sm);
        display: grid;
        place-items: center;
        cursor: pointer;
    }

    .nav-inferior {
        display: flex;
        align-items: stretch;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: var(--alto-nav-inferior);
        padding-bottom: env(safe-area-inset-bottom);
        background-color: var(--bg-main);
        border-top: 1px solid var(--border-color);
        z-index: var(--z-nav);
    }

    .nav-inferior-item {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 0.15rem;
        background: none;
        border: none;
        font-family: inherit;
        font-size: 0.62rem;
        font-weight: var(--fw-bold);
        color: var(--text-muted);
        cursor: pointer;
        padding: 0;
    }

    .nav-inferior-item i { font-size: 1.05rem; }
    .nav-inferior-item.activo { color: var(--accion); }
    .nav-inferior-item:active { background-color: rgba(var(--slate-rgb), 0.08); }

    /* Hoja inferior con las pestañas que no entran en la barra. */
    .hoja-mas:not(.oculto) {
        display: flex;
        align-items: flex-end;
        position: fixed;
        inset: 0;
        background-color: rgba(var(--bg-main-rgb), 0.75);
        z-index: var(--z-hoja);
    }

    .hoja-mas-panel {
        width: 100%;
        max-height: 82dvh;
        overflow-y: auto;
        background-color: var(--bg-sidebar);
        border-top: 1px solid var(--border-color);
        border-radius: var(--r-xl) var(--r-xl) 0 0;
        padding: var(--sp-5) var(--sp-4) calc(var(--sp-5) + env(safe-area-inset-bottom));
        display: flex;
        flex-direction: column;
        gap: var(--sp-2);
        animation: subir 0.22s ease;
    }

    @keyframes subir {
        from { transform: translateY(100%); }
        to { transform: none; }
    }

    .hoja-mas-titulo {
        font-size: var(--fs-xs);
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: var(--text-muted);
        font-weight: var(--fw-bold);
        padding-left: var(--sp-2);
        margin-bottom: var(--sp-1);
    }

    .hoja-mas-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
        gap: var(--sp-2);
    }

    /* Cada sección es una tarjeta con ícono, nombre y para qué sirve: la hoja
       deja de ser una lista de palabras que nadie asocia con nada. */
    .hoja-opcion {
        display: grid;
        grid-template-columns: 2rem 1fr;
        grid-template-rows: auto auto;
        column-gap: var(--sp-3);
        align-items: center;
        width: 100%;
        padding: var(--sp-3);
        background-color: var(--bg-elevada);
        border: 1px solid var(--border-color);
        border-radius: var(--r-md);
        color: var(--text-fuerte);
        font: inherit;
        text-align: left;
        cursor: pointer;
    }

    .hoja-opcion > i {
        grid-row: 1 / 3;
        justify-self: center;
        font-size: 1.15rem;
        color: var(--accion);
    }

    .hoja-opcion-titulo { font-size: var(--fs-sm); font-weight: var(--fw-black); line-height: var(--lh-tight); }
    .hoja-opcion-texto { font-size: var(--fs-xs); color: var(--text-muted); line-height: var(--lh-tight); }

    .hoja-opcion-salir {
        display: flex;
        justify-content: center;
        gap: var(--sp-2);
        margin-top: var(--sp-2);
        background-color: transparent;
        color: var(--text-muted);
    }

    .hoja-opcion-salir .hoja-opcion-titulo { font-weight: var(--fw-bold); }

    @media (hover: hover) {
        .hoja-opcion:hover { border-color: var(--border-fuerte); background-color: var(--panel-keylime); }
        .hoja-opcion-salir:hover { background-color: transparent; }
    }

    /* El contenido respira entre las dos barras fijas. */
    .main-content {
        padding: calc(var(--alto-barra-movil) + var(--sp-4)) var(--sp-4)
                 calc(var(--alto-nav-inferior) + var(--sp-5));
    }

    .header-top { margin-bottom: var(--sp-4); }
    /* El titular sigue siendo una portada en el celular: serif 300 a ~32 px,
       no el tamaño de una etiqueta. */
    .page-title { font-size: clamp(1.9rem, 1.45rem + 2.2vw, 2.3rem); }
    .header-top h2.page-title { font-size: var(--fs-xl); }
    .header-top > .btn-mint, .header-top > .btn-outline { width: 100%; }

    .grid-cards-3,
    .grid-cards-2,
    .grid-2,
    .grid-3 { grid-template-columns: minmax(0, 1fr); }

    /* El tablero se vuelve una sola columna. */
    .tablero { gap: var(--sp-4); }

    .form-rejilla { grid-template-columns: minmax(0, 1fr); }
    .form-rejilla .btn-mint { width: 100%; }

    .toasts-contenedor { bottom: calc(var(--alto-nav-inferior) + var(--sp-4)); right: var(--sp-4); left: var(--sp-4); }

    /* El acceso pasa a una columna: primero la promesa, luego el formulario.
       Se ocultan la vista previa y las promesas para acercar el primer campo. */
    .modal-card { grid-template-columns: 1fr; max-width: 540px; }
    .marca-auth { padding: var(--sp-5) var(--sp-4); }
    .auth-preview,
    .auth-beneficios { display: none; }
    #titulo-auth { font-size: 2.25rem; margin-top: var(--sp-2); }
    .auth-cuerpo { padding: var(--sp-5) var(--sp-4); }
    .grafico-caja { height: 220px; }
}

/* Celular chico: aún menos decoración. */
@media (max-width: 520px) {
    .card-square, .card-pantry-item { padding: var(--sp-4); }
    .estado-vacio { padding: var(--sp-6) var(--sp-4); min-height: 180px; }
    .requisitos-lista { grid-template-columns: 1fr; }
    .hero-titulo { font-size: var(--fs-lg); }
    .metrica { font-size: var(--fs-xl); }

    /* La portada ocupa la pantalla completa: no hay borde que redondear. */
    .modal-overlay { padding: 0; align-items: flex-start; }
    .modal-card { border: 0; border-radius: 0; min-height: 100%; }
    .marca-auth { padding: max(var(--sp-4), env(safe-area-inset-top)) var(--sp-4) var(--sp-4); }
    .auth-cuerpo { padding: var(--sp-4) var(--sp-3) max(var(--sp-5), env(safe-area-inset-bottom)); }

    /* El código de familia cabe en un renglón junto a su botón. */
    .codigo-invitacion { font-size: var(--fs-xl); letter-spacing: 0.08em; }
}

/* =============================================================================
   21. PREFERENCIAS DEL USUARIO
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }
}

/* =============================================================================
   22. UTILIDADES
   Separaciones puntuales que antes iban como `style="…"` dentro de las vistas.
   Solo espaciado, y siempre con un token: si lo que hay que separar ya es un
   componente, lleva su propia clase (un `.mt-*` solo cuando no hay otra).
   ============================================================================= */
.mt-1 { margin-top: var(--sp-1); }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-5 { margin-top: var(--sp-5); }
.mt-6 { margin-top: var(--sp-6); }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-3 { margin-bottom: var(--sp-3); }
.mb-5 { margin-bottom: var(--sp-5); }
.m-0 { margin: 0; }
.mb-0 { margin-bottom: 0; }
.my-2 { margin-top: var(--sp-2); margin-bottom: var(--sp-2); }
.centrado { text-align: center; }
.rejilla-arriba { align-content: start; }
/* Tarjetas de distinto alto en la MISMA rejilla: cada una mide lo suyo en vez de
   estirarse hasta la más alta (si no, la corta se queda con un hueco abajo). */
.tarjetas-arriba { align-items: start; }

/* Fila con las orillas separadas (un dato a la izquierda, su botón a la derecha). */
.fila-entre { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* Se apaga y se enciende desde JS (pestañas, cámara, hojas). */
.oculto { display: none !important; }

/* =============================================================================
   23. TOUR DE BIENVENIDA
   Panel flotante de primeros pasos. Va cambiando la vista de la app y explica
   cada sección. Se muestra una vez por navegador; Configuración lo reabre.
   ============================================================================= */
.tour-panel {
    position: fixed;
    right: var(--sp-4);
    bottom: var(--sp-4);
    z-index: var(--z-tour);
    width: min(370px, calc(100% - var(--sp-4) * 2));
    max-height: calc(100dvh - var(--sp-5) * 2);
    overflow-y: auto;
    background: var(--bg-elevada);
    border: 1px solid var(--border-fuerte);
    border-radius: var(--r-lg);
    padding: var(--sp-4);
    color: var(--text-fuerte);
}

/* El título de la vista que se está explicando. */
.tour-foco {
    outline: 3px solid var(--accion);
    outline-offset: 6px;
    border-radius: var(--r-md);
}

.tour-icono {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    margin-bottom: var(--sp-3);
    border-radius: var(--r-full);
    background: var(--panel-sage);
    color: var(--accion);
    font-size: var(--fs-lg);
}

.tour-paso {
    margin: 0 0 var(--sp-1);
    color: var(--text-muted);
    font-size: var(--fs-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.tour-titulo {
    margin: 0 0 var(--sp-2);
    font-family: var(--ff-titulos);
    font-size: var(--fs-xl);
    font-weight: var(--fw-titulos);
    line-height: var(--lh-tight);
    color: var(--marca-texto);
}

.tour-texto {
    margin: 0;
    color: var(--text-muted);
    font-size: var(--fs-sm);
    line-height: var(--lh-base);
}

.tour-puntos {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-1);
    margin: var(--sp-4) 0;
}

.tour-punto {
    width: 8px;
    height: 8px;
    border-radius: var(--r-full);
    background: var(--border-fuerte);
    transition: width var(--tr-rapida), background-color var(--tr-rapida);
}

.tour-punto.activo {
    width: 22px;
    background: var(--accion);
}

.tour-acciones {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

.tour-nav {
    display: flex;
    gap: var(--sp-2);
}

.tour-saltar {
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-muted);
    font: inherit;
    font-size: var(--fs-sm);
    text-decoration: underline;
    cursor: pointer;
}

.tour-saltar:hover { color: var(--text-fuerte); }

/* En el celular el tour es una hoja compacta. Va al final de la sección para
   que estas reglas ganen sobre las base (misma especificidad, después manda). */
@media (max-width: 880px) {
    .tour-panel {
        left: var(--sp-3);
        right: var(--sp-3);
        bottom: calc(var(--sp-5) + 56px);
        width: auto;
        max-height: 58dvh;
        padding: var(--sp-3);
    }

    /* El ícono y los 33 puntos se comían media pantalla. El paso ya dice
       "Paso 1 de 33", así que en el celular sobran. */
    .tour-icono { display: none; }
    .tour-puntos { display: none; }
    .tour-titulo { font-size: var(--fs-lg); }
    .tour-texto { font-size: var(--fs-xs); }
    .tour-acciones {
        position: sticky;
        bottom: 0;
        background: var(--bg-elevada);
        padding-top: var(--sp-2);
    }
    .tour-foco { scroll-margin-top: 72px; }
}
