/*
 * Cafjeraly Website Styles
 * Green Earth Color Palette
 */

:root {
    /* ═══════ PALETA LEGACY ═══════
       No renombrar: ~2000 líneas de este archivo dependen de estos nombres. */
    --color-1: #1c5e21;  /* Parsley - verde oscuro primario */
    --color-2: #3c8b3d;  /* Goblin - verde medio */
    --color-3: #7ebe7e;  /* De York - verde claro */
    --color-4: #c3a692;  /* Indian Khaki - beige */
    --color-5: #d17d3d;  /* Raw Sienna - naranja */
    --color-6: #4b2e05;  /* Seal Brown - café oscuro */

    --white: #ffffff;
    --black: #1a1a1a;
    --gray-light: #f8f9fa;
    --gray-medium: #e9ecef;
    --gray-dark: #6c757d;

    --spacing-xs: 0.5rem;
    --spacing-sm: 1rem;
    --spacing-md: 2rem;
    --spacing-lg: 4rem;
    --spacing-xl: 6rem;

    --transition: all 0.3s ease;   /* legacy; el código nuevo usa --dur-* / --ease-* */

    /* ═══════ MARCA EXTENDIDA ═══════
       --green-900 no es decorativo: #1c5e21 sobre vidrio translúcido da 3.6:1
       (falla AA). #143f18 da 6.1:1 en el peor caso sobre foto. */
    --green-900: #143f18;
    --green-800: #1c5e21;
    --green-600: #3c8b3d;
    --green-300: #7ebe7e;
    --green-50:  #f2f7f1;
    --cacao-900: #33200a;
    --cacao-700: #4b2e05;
    --sienna-600: #b8652c;   /* más oscuro que --color-5: cumple AA sobre blanco */
    --sienna-500: #d17d3d;

    /* ═══════ SUPERFICIES / TEXTO / BORDES ═══════ */
    --surface:        #ffffff;
    --surface-sunken: #f7f8f6;
    --surface-warm:   #faf7f3;                                       /* fallback estático */
    --surface-warm:   color-mix(in oklab, var(--color-4) 16%, #fffdfb);
    --surface-deep:   #14401a;
    --surface-deep:   color-mix(in oklab, var(--color-1) 86%, var(--color-6));
    --surface-brand:  var(--green-50);

    --text:          #17201a;
    --text-muted:    #5b6660;
    --text-subtle:   #86918b;
    --text-on-brand: #ffffff;
    --text-on-glass: var(--green-900);   /* ÚNICO color de texto permitido sobre vidrio */

    --hairline:      rgb(75 46 5 / .12);
    --hairline:      color-mix(in oklab, var(--color-6) 12%, transparent);
    --border:        rgba(23, 32, 26, 0.10);
    --border-strong: rgba(23, 32, 26, 0.18);

    /* ═══════ MATERIAL DE VIDRIO ═══════
       Calibrado para una píldora clara flotando sobre foto verde/café.
       El alpha mínimo de .62 es una restricción de accesibilidad, no estética. */
    --glass-bg:        rgba(250, 252, 249, 0.62);
    --glass-bg-strong: rgba(250, 252, 249, 0.80);
    --glass-bg-soft:   rgba(255, 255, 255, 0.38);
    --glass-bg-dark:   rgba(20, 63, 24, 0.55);
    --glass-bg-warm:   rgba(184, 101, 44, 0.58);

    --glass-blur:       18px;
    --glass-blur-deep:  28px;
    --glass-blur-soft:  10px;
    --glass-saturate:   180%;
    --glass-brightness: 106%;
    /* OJO: el filtro NO se compone aquí. Una custom property sustituye sus
       var() en el punto donde se DECLARA, así que componerlo en :root
       congelaría --glass-blur a 18px y los overrides por componente
       (.glass-card, .nav.is-scrolled .nav-pill) no harían nada. Se compone
       en .glass, en el punto de uso. */

    --glass-border-color: rgba(255, 255, 255, 0.55);
    --glass-edge: linear-gradient(
        140deg,
        rgba(255,255,255,0.90) 0%,
        rgba(255,255,255,0.35) 28%,
        rgba(255,255,255,0.08) 55%,
        rgba(255,255,255,0.45) 100%
    );
    --glass-sheen: linear-gradient(
        180deg,
        rgba(255,255,255,0.45) 0%,
        rgba(255,255,255,0.10) 42%,
        rgba(255,255,255,0.00) 70%
    );
    --glass-highlight: inset 0 1px 0 0 rgba(255,255,255,0.85),
                       inset 0 -1px 0 0 rgba(255,255,255,0.22);

    --glass-shadow:
        0 1px 2px rgba(18, 38, 22, 0.06),
        0 8px 24px -6px rgba(18, 38, 22, 0.14),
        0 20px 48px -12px rgba(18, 38, 22, 0.16);
    --glass-shadow-lifted:
        0 2px 4px rgba(18, 38, 22, 0.08),
        0 14px 32px -8px rgba(18, 38, 22, 0.20),
        0 28px 64px -16px rgba(18, 38, 22, 0.22);

    /* ═══════ ELEVACIÓN (superficies opacas) ═══════
       Dos capas siempre — tight + wide — nunca una sola mancha borrosa. */
    --shadow-xs: 0 1px 2px rgb(20 40 20 / .04);
    --shadow-sm: 0 1px 2px rgb(20 40 20 / .05), 0 10px 24px -14px rgb(20 40 20 / .22);
    --shadow-md: 0 2px 4px rgb(20 40 20 / .06), 0 16px 34px -18px rgb(20 40 20 / .28);
    --shadow-lg: 0 2px 4px rgb(20 40 20 / .06), 0 26px 52px -22px rgb(20 40 20 / .34);
    --shadow-xl: 0 8px 16px rgb(18 38 22 / .08), 0 28px 64px -16px rgb(18 38 22 / .22);
    --shadow-brand: 0 8px 24px -6px rgba(28, 94, 33, 0.32);

    /* ═══════ RADIOS ═══════ */
    --radius-xs:   6px;
    --radius-sm:   10px;
    --radius-md:   14px;
    --radius-lg:   22px;
    --radius-xl:   34px;
    --radius-pill: 999px;

    /* ═══════ MOVIMIENTO ═══════ */
    --dur-instant: 90ms;
    --dur-fast:    180ms;
    --dur-base:    320ms;
    --dur-slow:    620ms;
    --dur-slower:  900ms;

    --ease-out:         cubic-bezier(0.22, 1.00, 0.36, 1.00);  /* expo-out, el caballo de batalla */
    --ease-in-out:      cubic-bezier(0.65, 0.00, 0.35, 1.00);
    --ease-spring:      cubic-bezier(0.34, 1.56, 0.64, 1.00);  /* overshoot: el indicador del nav */
    --ease-spring-soft: cubic-bezier(0.20, 1.10, 0.35, 1.00);
    --ease-glass:       cubic-bezier(0.16, 1.00, 0.30, 1.00);  /* asentamiento largo y pesado */

    /* ═══════ TIPOGRAFÍA ═══════
       Orden del fallback: webfont primero, sistema al final. El bug anterior era
       poner 'Arial'/'Calibri' delante — resuelven siempre y tapaban la webfont. */
    --font-display: 'Fraunces', 'Playfair Display', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
    --font-primary: 'DM Sans', 'Open Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

    --fs-xs:   clamp(0.75rem,  0.72rem + 0.15vw,  0.8125rem);
    --fs-sm:   clamp(0.875rem, 0.85rem  + 0.12vw, 0.9375rem);
    --fs-base: clamp(1rem,     0.96rem  + 0.19vw, 1.0625rem);
    --fs-md:   clamp(1.125rem, 1.06rem  + 0.28vw, 1.25rem);
    --fs-lg:   clamp(1.3rem,   1.18rem  + 0.52vw, 1.5rem);
    --fs-xl:   clamp(1.5rem,   1.30rem  + 0.87vw, 2rem);
    --fs-2xl:  clamp(1.9rem,   1.15rem  + 2.70vw, 3.15rem);
    --fs-3xl:  clamp(2.2rem,   1.30rem  + 4.00vw, 4.2rem);
    --fs-4xl:  clamp(2.6rem,   1.10rem  + 6.40vw, 5.5rem);

    --lh-tight: 1.1;
    --lh-snug:  1.25;
    --lh-base:  1.6;
    --lh-loose: 1.75;

    --tracking-tight: -0.022em;
    --tracking-snug:  -0.012em;
    --tracking-wide:   0.04em;
    --tracking-caps:   0.16em;

    /* ═══════ RITMO ═══════ */
    --section-pad: clamp(3.5rem, 2rem + 6vw, 8rem);
    --gutter:      clamp(1.25rem, 0.75rem + 2vw, 3rem);
    --measure:     62ch;

    /* ═══════ GEOMETRÍA DEL NAV — fuente única de verdad ═══════ */
    --nav-h:       64px;
    --nav-top:     1.25rem;
    --nav-gap:     0.75rem;
    --nav-clear:   calc(var(--nav-h) + var(--nav-top) * 2);
    --nav-z:       1000;
    --nav-sheet-z: 1200;
}

/* El estado de scroll encoge la geometría desde un solo sitio. */
.nav.is-scrolled {
    --nav-h: 56px;
    --nav-top: 0.625rem;
}

@media (max-width: 968px) {
    :root { --nav-h: 54px; --nav-top: 0.75rem; }
    .nav.is-scrolled { --nav-h: 50px; --nav-top: 0.5rem; }
}

/* Registradas para que calc() tenga tipo y valor inicial garantizado.
   Deben ir a nivel raíz, nunca dentro de @media. */
@property --aos-delay { syntax: '<time>';   inherits: false; initial-value: 0ms; }
@property --i         { syntax: '<number>'; inherits: false; initial-value: 0;   }

/* Reset & Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    font-size: 16px;
}

body {
    font-family: var(--font-primary);
    font-size: var(--fs-base);
    color: var(--text);
    line-height: var(--lh-base);
    background: var(--surface);
    font-optical-sizing: auto;
    font-synthesis-weight: none;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    /* `clip` y no `hidden`: hidden convierte <body> en contenedor de scroll, lo
       que rompe el muestreo de backdrop-filter en Safari y estorba al bloqueo
       de scroll del menú móvil. */
    overflow-x: clip;
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    text-decoration: none;
    color: inherit;
    transition: var(--transition);
}

ul {
    list-style: none;
}

/* Tipografía global. Antes ningún elemento usaba de verdad --font-display:
   'Arial' encabezaba el stack y resolvía siempre. */
h1, h2, h3,
.hero-title, .section-title, .cta-title, .page-header h1 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: var(--lh-tight);
    letter-spacing: var(--tracking-tight);
    text-wrap: balance;
}

h4, h5, h6 {
    font-family: var(--font-primary);
    font-weight: 600;
    line-height: var(--lh-snug);
}

p { text-wrap: pretty; }

/* El sitio no tenía NINGÚN estilo de foco. :where() da especificidad 0 para que
   cualquier componente pueda sobreescribirlo sin !important. */
:where(a, button, input, textarea, select, [tabindex]):focus-visible {
    outline: 2px solid var(--green-900);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* Los anclas deben librar la píldora flotante. Sustituye al `offsetTop - 80`
   de main.js y arregla el scrollIntoView de goToFeaturedProducts(). */
:target,
[id] { scroll-margin-top: calc(var(--nav-clear) + var(--spacing-sm)); }

/* Container */
.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacing-md);
}

/* ═══════════════════════════════════════════════════════════
   PRIMITIVAS DE VIDRIO
   Toda superficie de vidrio del sitio compone desde .glass.
   El material se ajusta por componente sobreescribiendo --glass-*.
   ═══════════════════════════════════════════════════════════ */

.glass {
    position: relative;
    /* Base opaca: es lo único que reciben los navegadores sin backdrop-filter. */
    background-color: rgba(250, 252, 249, 0.94);
    box-shadow: var(--glass-shadow), var(--glass-highlight);
    isolation: isolate;
}

/* Borde especular de 1px, con mask-composite para que sea un gradiente y no
   un color plano. */
.glass::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: var(--glass-edge);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
    pointer-events: none;
}

/* Brillo interno: la luz que se apoya sobre el vidrio.
   IMPORTANTE: .glass ocupa ::before Y ::after. Ningún elemento con .glass
   puede usar pseudo-elementos para su propio contenido — sobreescribir sólo
   `content` hereda position/inset/z-index/opacity de estas reglas. Si hace
   falta un icono, va en el markup. */
.glass::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: var(--glass-sheen);
    opacity: 0.7;
    pointer-events: none;
}

/* En positivo a propósito. Con `@supports not` la regla por defecto sería la
   translúcida, y cualquier motor que parsee backdrop-filter sin pintarlo
   (algunos WebView embebidos) dejaría el texto ilegible. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .glass {
        background-color: var(--glass-bg);
        -webkit-backdrop-filter: blur(var(--glass-blur))
                                 saturate(var(--glass-saturate))
                                 brightness(var(--glass-brightness));
                backdrop-filter: blur(var(--glass-blur))
                                 saturate(var(--glass-saturate))
                                 brightness(var(--glass-brightness));
    }
}

.glass-card {
    --glass-blur: var(--glass-blur-soft);
    border-radius: var(--radius-lg);
    padding: var(--spacing-md);
    transition:
        transform  var(--dur-base) var(--ease-spring-soft),
        box-shadow var(--dur-base) var(--ease-out);
}
.glass-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--glass-shadow-lifted), var(--glass-highlight);
}

.glass-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 0.85rem 1.75rem;
    border: 0;
    border-radius: var(--radius-pill);
    font-family: var(--font-primary);
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-snug);
    color: var(--text-on-glass);
    cursor: pointer;
    transition:
        transform  var(--dur-fast) var(--ease-spring-soft),
        box-shadow var(--dur-base) var(--ease-out),
        background var(--dur-base) var(--ease-out);
}
.glass-btn:hover  { transform: translateY(-2px); box-shadow: var(--glass-shadow-lifted), var(--glass-highlight); }
.glass-btn:active { transform: translateY(0) scale(0.98); }

/* Sobre foto: vidrio claro tintado y texto blanco. */
.glass-btn--onmedia {
    --glass-bg: rgba(255, 255, 255, 0.18);
    --glass-edge: linear-gradient(140deg, rgba(255,255,255,.95), rgba(255,255,255,.25) 50%, rgba(255,255,255,.6));
    color: var(--white);
}
.glass-btn--brand { --glass-bg: rgba(20, 63, 24, 0.62); color: var(--white); }

.glass-badge {
    --glass-blur: var(--glass-blur-soft);
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.35rem 0.85rem;
    border-radius: var(--radius-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--text-on-glass);
    box-shadow: var(--shadow-sm), var(--glass-highlight);
}
.glass-badge--dark { --glass-bg: var(--glass-bg-dark); color: var(--white); }
.glass-badge--warm { --glass-bg: var(--glass-bg-warm); color: var(--white); }

/* El anillo de foco necesita un halo blanco para sobrevivir sobre vidrio. */
.nav-link:focus-visible,
.glass-btn:focus-visible,
.nav-brand:focus-visible {
    border-radius: var(--radius-pill);
    box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.9);
}

/* ═══════════════════════════════════════════════════════════
   NAVEGACIÓN — píldora de vidrio flotante
   Sustituye al bloque .navbar / .solid-navbar / .navbar-logo-* completo.
   ═══════════════════════════════════════════════════════════ */

.skip-link {
    position: fixed;
    top: 0;
    left: 50%;
    transform: translate(-50%, -150%);
    z-index: calc(var(--nav-sheet-z) + 10);
    padding: 0.75rem 1.5rem;
    background: var(--green-900);
    color: var(--white);
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    font-weight: 600;
    transition: transform var(--dur-base) var(--ease-out);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

.nav {
    position: fixed;
    top: var(--nav-top);
    left: 0;
    right: 0;
    z-index: var(--nav-z);
    display: flex;
    justify-content: center;
    padding: 0 var(--spacing-sm);
    pointer-events: none;            /* la barra no debe comerse clics del héroe */
    transition: top var(--dur-slow) var(--ease-glass);
}

.nav-pill {
    pointer-events: auto;
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    height: var(--nav-h);
    padding: 0 var(--nav-gap) 0 calc(var(--nav-gap) + 0.25rem);
    border-radius: var(--radius-pill);
    max-width: min(100%, 980px);
    transition:
        height          var(--dur-slow) var(--ease-glass),
        max-width       var(--dur-slow) var(--ease-glass),
        background      var(--dur-slow) var(--ease-out),
        box-shadow      var(--dur-slow) var(--ease-out),
        backdrop-filter var(--dur-slow) var(--ease-out);
}

/* Al hacer scroll la píldora NO se vuelve blanca: se condensa y engrosa.
   CRÍTICO: nada aquí puede cambiar la geometría DENTRO de .nav-links, o el
   indicador se desincroniza a media transición. Sólo .nav-pill y .nav-logo. */
.nav.is-scrolled .nav-pill {
    --glass-bg: var(--glass-bg-strong);
    --glass-blur: var(--glass-blur-deep);
    max-width: min(100%, 880px);
    box-shadow: var(--glass-shadow-lifted), var(--glass-highlight);
}

.nav-brand {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex-shrink: 0;
    border-radius: var(--radius-pill);
    transition: transform var(--dur-base) var(--ease-spring-soft);
}
.nav-brand:hover  { transform: scale(1.03); }
.nav-brand:active { transform: scale(0.98); }

.nav-logo {
    height: calc(var(--nav-h) - 26px);
    width: auto;
    display: block;
    transition: height var(--dur-slow) var(--ease-glass);
    /* Silueta a propósito. La píldora es SIEMPRE una superficie clara, y el
       archivo que hay hoy en site_config.logo es line-art blanco (luminancia
       253), invisible sobre ella — de hecho `logo` y `logo_white` apuntan al
       mismo archivo. Como la marca es un pictograma monocromo, la silueta es
       la lectura correcta y aguanta cualquier archivo que suba el admin.
       Si algún día se sube un logo oscuro o a color y se prefiere tal cual,
       basta con borrar este filter. El footer no lo lleva: ahí el logo blanco
       va sobre verde y funciona. */
    filter: brightness(0) opacity(0.8);
}

/* El logo es un pictograma sin letras: sin esto la píldora pierde el nombre. */
.nav-wordmark {
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-snug);
    color: var(--text-on-glass);
    white-space: nowrap;
}

.nav-links {
    position: relative;              /* offsetParent del indicador */
    display: flex;
    align-items: center;
    gap: 0.125rem;
    margin: 0;
    padding: 0;
    list-style: none;
    isolation: isolate;
}

/* El indicador vive DENTRO de .nav-links, no de .nav-pill. Así el estado de
   scroll puede cambiar padding, max-width, alto y logo de la píldora sin
   invalidar su geometría medida: el <ul> se mueve en bloque. */
.nav-indicator {
    position: absolute;
    top: 50%;
    left: 0;
    z-index: -1;                     /* detrás del texto del enlace */
    height: 36px;
    width: var(--ind-w, 0px);
    margin-top: -18px;
    border-radius: var(--radius-pill);
    background: linear-gradient(140deg, var(--green-800) 0%, var(--green-600) 100%);
    box-shadow:
        0 2px 8px -2px rgba(28, 94, 33, 0.45),
        inset 0 1px 0 rgba(255,255,255,0.25);
    transform: translate3d(var(--ind-x, 0px), 0, 0);
    opacity: var(--ind-o, 0);
    transition:
        transform var(--dur-slow) var(--ease-spring),
        width     var(--dur-slow) var(--ease-spring),
        opacity   var(--dur-fast) var(--ease-out);
    will-change: transform, width;
}
/* Suprime el "vuelo" en la primera pintura (lo pone y quita el JS). */
.nav-links.is-measuring .nav-indicator { transition: none !important; }

.nav-link {
    position: relative;
    display: block;
    padding: 0.5rem 0.95rem;
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-snug);
    white-space: nowrap;
    color: var(--text-on-glass);
    border-radius: var(--radius-pill);
    transition: color var(--dur-base) var(--ease-out);
}

/* El enlace que tiene el indicador debajo lleva el texto invertido. */
.nav-link.is-active,
.nav-link:hover,
.nav-link:focus-visible { color: var(--white); }

/* Al pasar por otro enlace, el activo debe soltar el texto blanco. */
.nav-links:has(.nav-link:hover) .nav-link.is-active:not(:hover),
.nav-links:has(.nav-link:focus-visible) .nav-link.is-active:not(:focus-visible) {
    color: var(--text-on-glass);
}
/* Mismo estado sin :has() — el JS refleja la clase .is-tracking. */
.nav-links.is-tracking .nav-link.is-active:not(:hover):not(:focus-visible) {
    color: var(--text-on-glass);
}

.nav-burger {
    display: none;
    position: relative;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    background: transparent;
    border: 0;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out);
}
.nav-burger:hover { background: rgba(20, 63, 24, 0.08); }

.nav-burger-bar {
    position: absolute;
    left: 50%;
    width: 19px;
    height: 2px;
    margin-left: -9.5px;
    border-radius: 2px;
    background: var(--text-on-glass);
    transition:
        transform var(--dur-base) var(--ease-spring-soft),
        top       var(--dur-base) var(--ease-out);
}
.nav-burger-bar:nth-child(1) { top: 16px; }
.nav-burger-bar:nth-child(2) { top: 22px; }

.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(1) { top: 19px; transform: rotate(45deg); }
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(2) { top: 19px; transform: rotate(-45deg); }

@media (max-width: 968px) {
    .nav-pill   { width: 100%; justify-content: space-between; padding-right: 0.35rem; }
    .nav-links  { display: none; }
    .nav-burger { display: block; }
}
@media (max-width: 420px) {
    .nav-wordmark { display: none; }
}

/* ── Sheet móvil ─────────────────────────────────────────── */
.nav-sheet {
    position: fixed;
    inset: 0;
    z-index: var(--nav-sheet-z);
    /* .nav lleva pointer-events:none para no comerse los clics del héroe, y el
       sheet es hijo suyo: sin esto hereda `none` y sus enlaces se ven pero no
       son objetivo de clic. */
    pointer-events: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(var(--nav-clear) + var(--spacing-md)) var(--spacing-md) var(--spacing-lg);
    background: rgba(250, 252, 249, 0.86);
    opacity: 0;
    visibility: hidden;
    transition:
        opacity    var(--dur-base) var(--ease-out),
        visibility 0s linear var(--dur-base);
}
/* El atributo [hidden] lo gestiona el JS como señal de accesibilidad; quien
   oculta de verdad es visibility, y eso es lo que permite animar la salida. */
.nav-sheet[hidden] { display: flex; }

.nav-sheet.is-open {
    opacity: 1;
    visibility: visible;
    transition:
        opacity    var(--dur-base) var(--ease-out),
        visibility 0s;
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .nav-sheet {
        background: rgba(250, 252, 249, 0.72);
        -webkit-backdrop-filter: blur(var(--glass-blur-deep)) saturate(var(--glass-saturate));
                backdrop-filter: blur(var(--glass-blur-deep)) saturate(var(--glass-saturate));
    }
}

.nav-sheet-inner {
    width: 100%;
    max-width: 480px;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
}

.nav-sheet-links {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.nav-sheet-link {
    display: block;
    padding: 0.9rem 1.25rem;
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 600;
    letter-spacing: var(--tracking-tight);
    color: var(--text-on-glass);
    border-radius: var(--radius-lg);
    opacity: 0;
    transform: translateY(18px) scale(0.97);
    transition:
        opacity    var(--dur-slow) var(--ease-out),
        transform  var(--dur-slow) var(--ease-spring-soft),
        background var(--dur-fast) var(--ease-out);
}
.nav-sheet.is-open .nav-sheet-link { opacity: 1; transform: none; }

.nav-sheet-links li:nth-child(1) .nav-sheet-link { transition-delay: 60ms; }
.nav-sheet-links li:nth-child(2) .nav-sheet-link { transition-delay: 110ms; }
.nav-sheet-links li:nth-child(3) .nav-sheet-link { transition-delay: 160ms; }
.nav-sheet-links li:nth-child(4) .nav-sheet-link { transition-delay: 210ms; }
.nav-sheet-links li:nth-child(5) .nav-sheet-link { transition-delay: 260ms; }

.nav-sheet-foot { opacity: 0; transition: opacity var(--dur-slow) var(--ease-out) 320ms; }
.nav-sheet.is-open .nav-sheet-foot { opacity: 1; }

.nav-sheet-link:hover,
.nav-sheet-link:focus-visible { background: rgba(20, 63, 24, 0.07); }

.nav-sheet-link.is-active {
    color: var(--white);
    background: linear-gradient(140deg, var(--green-800), var(--green-600));
    box-shadow: 0 4px 14px -4px rgba(28, 94, 33, 0.45);
}

.nav-sheet-tagline {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--fs-sm);
    color: var(--text-muted);
    text-align: center;
    margin-top: var(--spacing-sm);
}

.nav-sheet-foot .glass-btn { width: 100%; }

@media (min-width: 969px) {
    .nav-sheet { display: none !important; }
}

/* Bloqueo de scroll en <html>: body lleva overflow-x y se pisarían. */
html.nav-locked,
html.nav-locked body { overflow: hidden; }

/* Las páginas sin héroe a sangre necesitan dejar sitio a la píldora.
   Sustituye a la clase .solid-navbar, que ya no tiene sentido: la píldora es
   siempre de vidrio, no hay estado "transparente vs sólida". */
body.page-flush main { padding-top: var(--nav-clear); }

/* Messages */
.messages-container {
    position: fixed;
    top: calc(var(--nav-clear) + var(--spacing-xs));
    right: var(--spacing-md);
    z-index: 1001;
    max-width: 400px;
}

.alert {
    padding: var(--spacing-sm) var(--spacing-md);
    margin-bottom: var(--spacing-sm);
    border-radius: 8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    animation: slideIn 0.3s ease;
}

.alert-success {
    background: var(--color-3);
    color: var(--color-1);
}

.alert-error {
    background: #f8d7da;
    color: #721c24;
}

.alert-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    padding: 0 var(--spacing-xs);
}

@keyframes slideIn {
    from { transform: translateX(100%); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════
   HÉROE
   ═══════════════════════════════════════════════════════════ */
.hero-section {
    position: relative;
    display: grid;
    align-content: end;              /* el texto se ancla abajo, no al centro */
    height: 100vh;
    min-height: 620px;
    margin-top: 0;                   /* la píldora flota encima: va a sangre */
    padding-block-end: clamp(3rem, 2rem + 5vw, 7rem);
    overflow: clip;
    isolation: isolate;
    color: var(--white);
}
@supports (height: 100svh) {
    /* svh evita el salto cuando la barra del navegador se colapsa en móvil */
    .hero-section { height: 100svh; max-height: 1120px; }
}

.hero-image {
    position: absolute;
    inset: 0;
    z-index: -2;
    background-size: cover;
    background-position: center 45%;  /* los sujetos de las fotos se sientan arriba */
    background-repeat: no-repeat;
}

/* Tres capas en vez del lavado diagonal plano:
   1) rampa superior corta, para que la píldora tenga contraste sobre fotos claras
   2) rampa inferior de legibilidad, que sigue al texto
   3) tinte de marca suave, para que la foto siga leyéndose "verde Cafjeraly" */
.hero-overlay {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to bottom, rgb(8 22 10 / .42) 0%, rgb(8 22 10 / 0) 24%),
        linear-gradient(to top,    rgb(8 22 10 / .80) 0%,
                                   rgb(8 22 10 / .42) 34%,
                                   rgb(8 22 10 / 0)   72%),
        linear-gradient(to top, color-mix(in oklab, var(--color-1) 62%, transparent) 0%,
                                transparent 60%);
}

.hero-content {
    position: relative;
    z-index: 2;
    width: 100%;        /* sin esto el flex/grid item encoge y .container nunca
                           llega a sus 1200px: el texto quedaba descentrado */
    color: var(--white);
}

.hero-content .container {
    display: flex;
    flex-direction: column;
    align-items: start;
    text-align: start;               /* editorial abajo-izquierda, no centrado */
    gap: clamp(.5rem, .3rem + .6vw, 1rem);
}

/* El subtítulo pasa a ser el eyebrow sobre el H1. Sólo con `order`: cero
   cambios de markup. */
.hero-subtitle {
    order: -1;
    font-family: var(--font-primary);
    font-size: clamp(.72rem, .66rem + .2vw, .85rem);
    font-weight: 600;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--white) 76%, transparent);
    margin: 0 0 .25rem;
}
.hero-subtitle::before {
    content: '';
    display: inline-block;
    width: 28px;
    height: 1px;
    margin-inline-end: .85rem;
    vertical-align: .32em;
    background: color-mix(in srgb, var(--white) 55%, transparent);
}

.hero-title {
    font-family: var(--font-display);
    font-size: var(--fs-4xl);
    font-weight: 700;
    line-height: .96;
    letter-spacing: -.028em;
    text-wrap: balance;
    max-width: 18ch;
    margin: 0;
    text-shadow: none;               /* de eso se encarga el scrim */
}

.hero-description {
    font-size: clamp(1rem, .95rem + .35vw, 1.2rem);
    line-height: 1.65;
    max-width: 46ch;
    margin: .5rem 0 0;
    color: color-mix(in srgb, var(--white) 86%, transparent);
    text-wrap: pretty;
}

.hero-cta {
    margin-top: clamp(1rem, .6rem + 1.4vw, 2rem);
    padding: 1rem 2.25rem;
    font-size: var(--fs-base);
    font-weight: 600;
}
/* La flecha va en un <span> del markup y no en ::after: .glass ya usa AMBOS
   pseudo-elementos (::before = borde especular, ::after = brillo interno).
   Un `.hero-cta::after { content: '→' }` sólo sobreescribía `content` y
   heredaba position:absolute, inset:0, z-index:-1 y opacity:.7 del brillo:
   la flecha salía arriba a la izquierda, detrás del texto y translúcida. */
.btn-arrow {
    display: inline-block;
    transition: transform var(--dur-base) var(--ease-out);
}
.hero-cta:hover .btn-arrow { transform: translateX(4px); }

/* Indicador de scroll, sin markup */
.hero-section.first::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: clamp(1.25rem, 2vh, 2.25rem);
    translate: -50% 0;
    width: 1px;
    height: 46px;
    background: linear-gradient(to bottom,
        color-mix(in srgb, var(--white) 0%, transparent),
        color-mix(in srgb, var(--white) 70%, transparent));
    transform-origin: top;
    animation: scroll-hint 2.4s var(--ease-in-out) infinite;
}
@keyframes scroll-hint {
    0%, 100% { transform: scaleY(.35); opacity: .35; }
    50%      { transform: scaleY(1);   opacity: 1;   }
}

/* Héroes 2+: dos pantallas completas antes de cualquier contenido es hostil,
   así que degradan a bandas editoriales. La clase .first ya existía en la
   plantilla, así que esto no toca el markup. */
.hero-section:not(.first) {
    height: auto;
    min-height: clamp(420px, 58svh, 660px);
    max-height: none;
}
.hero-section:not(.first) .hero-title { font-size: var(--fs-2xl); }
.hero-section:not(.first)::after      { display: none; }
.hero-section:not(.first):nth-of-type(even) .hero-content .container {
    align-items: end;
    text-align: end;
}

@media (prefers-reduced-motion: no-preference) {
    .hero-section.first .hero-image { animation: ken-burns 24s var(--ease-in-out) both; }
    @keyframes ken-burns { from { scale: 1; } to { scale: 1.07; } }
}

/* Entrada del héroe por CSS y no por el motor de revelado: es contenido
   above-the-fold y no debe depender de que un observer llegue a tiempo. */
@keyframes hero-rise {
    from { opacity: 0; transform: translate3d(0, 26px, 0); }
    to   { opacity: 1; transform: none; }
}

.hero-section.first .hero-subtitle,
.hero-section.first .hero-title,
.hero-section.first .hero-description,
.hero-section.first .hero-cta,
.page-header h1,
.page-header p {
    animation: hero-rise var(--dur-slower) var(--ease-out) both;
}
.hero-section.first .hero-title       { animation-delay: 60ms;  }
.hero-section.first .hero-subtitle    { animation-delay: 140ms; }
.hero-section.first .hero-description { animation-delay: 280ms; }
.hero-section.first .hero-cta         { animation-delay: 400ms; }
.page-header h1 { animation-delay: 80ms;  }
.page-header p  { animation-delay: 200ms; }
/* ═══════════════════════════════════════════════════════════
   BOTONES
   Siguen sólidos a propósito: el vidrio sobre una sección blanca no tiene
   nada que refractar y degrada a un rectángulo gris, además de fallar
   contraste. El vidrio se reserva para superficies sobre foto.
   ═══════════════════════════════════════════════════════════ */
.btn-primary,
.btn-secondary,
.btn-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    padding: .95rem 1.85rem;
    border-radius: var(--radius-pill);
    font-weight: 600;
    font-size: var(--fs-base);
    text-align: center;
    border: 1px solid transparent;
    cursor: pointer;
    /* Explícita y no `all`: transicionar `all` anima también propiedades de
       layout y provoca saltos al cambiar tamaños. */
    transition:
        transform        var(--dur-fast) var(--ease-spring-soft),
        box-shadow       var(--dur-base) var(--ease-out),
        background-color var(--dur-base) var(--ease-out),
        border-color     var(--dur-base) var(--ease-out),
        color            var(--dur-base) var(--ease-out);
}

.btn-primary {
    background: var(--color-1);
    color: var(--white);
    box-shadow:
        inset 0 1px 0 rgb(255 255 255 / .17),
        0 1px 2px rgb(0 0 0 / .10),
        0 14px 30px -16px color-mix(in oklab, var(--color-1) 70%, transparent);
}
.btn-primary:hover {
    background: var(--color-2);
    transform: translateY(-2px);
    box-shadow:
        inset 0 1px 0 rgb(255 255 255 / .20),
        0 2px 4px rgb(0 0 0 / .12),
        0 22px 44px -18px color-mix(in oklab, var(--color-1) 78%, transparent);
}
.btn-primary:active { transform: translateY(0) scale(.985); }

.btn-secondary {
    background: var(--surface);
    border-color: color-mix(in oklab, var(--color-6) 20%, transparent);
    color: var(--color-6);
    box-shadow: inset 0 1px 0 rgb(255 255 255 / .55), var(--shadow-xs);
}
.btn-secondary:hover {
    background: var(--surface-warm);
    border-color: color-mix(in oklab, var(--color-6) 34%, transparent);
    transform: translateY(-2px);
    box-shadow: var(--shadow-sm);
}
.btn-secondary:active { transform: translateY(0) scale(.985); }

.btn-outline {
    background: transparent;
    color: var(--color-1);
    border-color: color-mix(in oklab, var(--color-1) 40%, transparent);
}
.btn-outline:hover {
    background: var(--color-1);
    color: var(--white);
    border-color: var(--color-1);
}

/* ═══════════════════════════════════════════════════════════
   SECCIONES
   Ritmo de papel cálido alternando --surface / --surface-warm. Se retiran los
   filetes ::before y los degradados verticales: el cambio de superficie ya es
   el separador, y el #f8f9fa de Bootstrap era frío para una marca de café.
   ═══════════════════════════════════════════════════════════ */
section { padding-block: var(--section-pad); }

.value-section     { background: var(--surface-warm); }
.featured-products { background: var(--surface); position: relative; }
.process-section   { background: var(--surface-warm); position: relative; }
.about-preview     { background: var(--surface); position: relative; }
.featured-recipes  { background: var(--surface-warm); }

.featured-products::before,
.about-preview::before,
.process-section::before { content: none; }

/* ── Cabeceras de sección ────────────────────────────────── */
.section-header {
    display: flex;
    justify-content: space-between;
    align-items: end;
    gap: var(--gutter);
    flex-wrap: wrap;
    margin-block-end: clamp(2rem, 1.2rem + 3vw, 4.5rem);
    padding-block-start: clamp(1rem, .6rem + 1.2vw, 2rem);
    border-block-start: 1px solid var(--hairline);   /* filete editorial */
}

.section-title {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 700;
    line-height: 1.04;
    letter-spacing: var(--tracking-tight);
    color: var(--color-1);
    text-wrap: balance;
    max-width: 20ch;
    margin: 0 auto;
    padding: 0;
    text-align: center;
}

/* La barrita de degradado de 80x3px era el elemento más 2019 de la página. */
.section-title::after { content: none; }

/* Eyebrow desde un atributo: sin elementos nuevos, funciona en todos lados. */
.section-title[data-eyebrow]::before {
    content: '— ' attr(data-eyebrow);
    display: block;
    margin-block-end: .9rem;
    font-family: var(--font-primary);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: color-mix(in oklab, var(--color-2) 82%, var(--color-6));
}

/* Dentro de .section-header hay un enlace "Ver todos" a la derecha: ahí el
   título va a la izquierda. Suelto, sigue centrado. */
.section-header .section-title { margin-inline: 0; text-align: start; }

.section-subtitle {
    font-size: clamp(1rem, .95rem + .35vw, 1.15rem);
    line-height: var(--lh-loose);
    color: var(--text-muted);
    max-width: 58ch;
    margin: 1.1rem auto 0;
    text-align: center;
    text-wrap: pretty;
}
.section-header .section-subtitle { margin-inline: 0; text-align: start; }

.section-link {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    flex-shrink: 0;
    padding-block-end: .35rem;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--color-1);
    border-block-end: 1px solid color-mix(in oklab, var(--color-1) 28%, transparent);
    transition:
        color        var(--dur-base) var(--ease-out),
        border-color var(--dur-base) var(--ease-out),
        gap          var(--dur-base) var(--ease-out);
}
.section-link:hover { color: var(--color-2); border-color: var(--color-2); gap: .85rem; }

/* ═══════════════════════════════════════════════════════════
   ¿POR QUÉ ELEGIRNOS?
   Nota de datos: 3 de las 4 filas de ValueProposition no tienen ni icono ni
   imagen. Cualquier diseño que se apoye en el icono se ve roto hoy, así que
   esas filas reciben un número de índice editorial vía :has().
   ═══════════════════════════════════════════════════════════ */
.value-section { background: var(--surface-warm); counter-reset: value; }

.value-grid {
    display: grid;
    /* min() y no un minmax pelado: a 320px el 280px fijo desbordaba. */
    grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
    gap: clamp(1rem, .6rem + 1.4vw, 1.75rem);
    margin-block-start: clamp(2rem, 1.2rem + 3vw, 4rem);
}

.value-card {
    position: relative;
    counter-increment: value;
    display: flex;
    flex-direction: column;
    padding: clamp(1.5rem, 1rem + 1.6vw, 2.25rem);
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-lg);
    box-shadow: none;                  /* hairline en reposo, sombra en hover */
    text-align: start;                 /* el cuerpo centrado es difícil de leer */
    overflow: clip;
    transition:
        transform    var(--dur-base) var(--ease-out),
        box-shadow   var(--dur-base) var(--ease-out),
        border-color var(--dur-base) var(--ease-out);
}
.value-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-sm);
    border-color: color-mix(in oklab, var(--color-3) 45%, transparent);
}

/* Convierte un hueco de datos en decisión de diseño, sin tocar DB ni plantilla.
   Ocupa el MISMO hueco que el chip de icono y en el flujo, no absoluto: así las
   cuatro tarjetas comparten ritmo y el número no puede solaparse con el título. */
.value-card:not(:has(.value-icon, .value-image))::before {
    content: counter(value, decimal-leading-zero);
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    margin: 0 0 clamp(1rem, .8rem + .6vw, 1.5rem);
    border-radius: var(--radius-md);
    background: color-mix(in oklab, var(--color-3) 18%, transparent);
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: color-mix(in oklab, var(--color-1) 72%, transparent);
}

/* min-width/height mantienen el chip cuadrado aunque Font Awesome no cargue
   y el <i> colapse a tamaño cero. */
.value-icon {
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    min-width: 52px;
    min-height: 52px;
    margin: 0 0 clamp(1rem, .8rem + .6vw, 1.5rem);
    border-radius: var(--radius-md);
    background: color-mix(in oklab, var(--color-3) 24%, transparent);
    color: var(--color-1);
    font-size: 1.35rem;
}

.value-image {
    aspect-ratio: 4 / 3;
    height: auto;
    width: auto;
    margin: calc(clamp(1.5rem, 1rem + 1.6vw, 2.25rem) * -1)
            calc(clamp(1.5rem, 1rem + 1.6vw, 2.25rem) * -1)
            clamp(1rem, .8rem + .6vw, 1.5rem);
    border-radius: 0;
    overflow: clip;
    background: color-mix(in oklab, var(--color-4) 22%, var(--white));
}
.value-image img { width: 100%; height: 100%; object-fit: cover; object-position: center 45%; }

.value-card h3 {
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 1.05rem + .4vw, 1.4rem);
    line-height: 1.2;
    letter-spacing: var(--tracking-snug);
    color: var(--color-1);
    text-wrap: balance;
    margin-block-end: .6rem;
}
.value-card p { color: var(--text-muted); line-height: var(--lh-loose); text-wrap: pretty; margin: 0; }

/* ═══════════════════════════════════════════════════════════
   TARJETAS DE PRODUCTO Y RECETA — un solo esqueleto
   ═══════════════════════════════════════════════════════════ */
.products-grid,
.recipes-grid {
    display: grid;
    gap: clamp(1rem, .6rem + 1.4vw, 1.75rem);
    margin-block-start: clamp(1.5rem, 1rem + 2vw, 3rem);
    grid-auto-rows: 1fr;               /* filas de altura igual */
}
.products-grid { grid-template-columns: repeat(auto-fill, minmax(min(270px, 100%), 1fr)); }
.recipes-grid  { grid-template-columns: repeat(auto-fill, minmax(min(310px, 100%), 1fr)); }

.product-card,
.recipe-card {
    display: grid;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-lg);
    box-shadow: none;
    overflow: clip;
    isolation: isolate;
    transition:
        transform    var(--dur-base) var(--ease-out),
        box-shadow   var(--dur-base) var(--ease-out),
        border-color var(--dur-base) var(--ease-out);
}
.product-card:hover,
.recipe-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--shadow-lg);
    border-color: color-mix(in oklab, var(--color-3) 40%, transparent);
}

/* .product-link y .recipe-link no tenían ninguna regla: la tarjeta entera no
   era clicable y el precio no se alineaba abajo. */
.product-link,
.recipe-link {
    display: grid;
    grid-template-rows: auto 1fr;
    height: 100%;
    color: inherit;
}
.product-link:focus-visible,
.recipe-link:focus-visible { outline-offset: -3px; }

.product-image,
.recipe-image {
    position: relative;
    width: 100%;
    height: auto;
    overflow: clip;
    background: color-mix(in oklab, var(--color-4) 20%, var(--white));
}
.product-image { aspect-ratio: 4 / 5; }   /* vertical: fotos de empaque */
.recipe-image  { aspect-ratio: 3 / 2; }   /* apaisado: fotos de plato */

.product-image img,
.recipe-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 45%;
    /* 1.1 era demasiado: delataba la baja resolución de las subidas. */
    transition: transform 620ms var(--ease-out), filter 620ms var(--ease-out);
}
.product-card:hover .product-image img,
.recipe-card:hover  .recipe-image img { transform: scale(1.045); filter: saturate(1.05); }

.product-info,
.recipe-info {
    display: flex;
    flex-direction: column;
    padding: clamp(1.15rem, .9rem + 1vw, 1.65rem);
    gap: .45rem;
}
.product-pricing { margin-block-start: auto; padding-block-start: .75rem; }

.product-category {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--color-2);
    margin: 0;
}
.product-category::before {
    content: '';
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
}

.product-name,
.recipe-title {
    font-family: var(--font-display);
    font-size: clamp(1.1rem, 1rem + .4vw, 1.35rem);
    line-height: 1.22;
    letter-spacing: var(--tracking-snug);
    color: var(--color-1);
    text-wrap: balance;
    margin: 0;
}

.product-description,
.recipe-description {
    font-size: var(--fs-sm);
    line-height: 1.6;
    color: var(--text-muted);
    text-wrap: pretty;
    margin: 0;
}

/* ── Badges de vidrio ────────────────────────────────────── */
.product-badge {
    position: absolute;
    z-index: 3;
    inset-block-start: 12px;
    inset-inline-end: 12px;
    padding: .42rem 1rem;
    border-radius: var(--radius-pill);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .02em;
    border: 1px solid rgb(255 255 255 / .35);
    box-shadow: 0 2px 10px rgb(0 0 0 / .18), inset 0 1px 0 rgb(255 255 255 / .28);
    background: color-mix(in srgb, var(--color-4) 78%, transparent);
    color: var(--black);
    animation: badge-in 520ms var(--ease-out) 220ms both;
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .product-badge {
        -webkit-backdrop-filter: blur(var(--glass-blur-soft)) saturate(140%);
                backdrop-filter: blur(var(--glass-blur-soft)) saturate(140%);
    }
}

/* Especificidad de dos clases para poder borrar los dos !important que tenía
   .sale-badge sólo para ganarle a .product-badge. */
.product-badge.sale-badge {
    background: color-mix(in srgb, var(--color-5) 84%, transparent);
    color: var(--white);
    font-weight: 700;
    letter-spacing: .04em;
    /* El `pulse` infinito se retira: latía para siempre y leía como anuncio. */
}

/* A la izquierda para que nunca choque con el badge de oferta. */
.product-badge.roast-type-badge-overlay {
    inset-inline-start: 12px;
    inset-inline-end: auto;
    background: color-mix(in srgb, var(--color-1) 72%, transparent);
    color: var(--white);
    cursor: pointer;
    transition: background var(--dur-base) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.product-badge.roast-type-badge-overlay:hover {
    background: color-mix(in srgb, var(--color-1) 88%, transparent);
    transform: translateY(-1px);
}

@keyframes badge-in { from { opacity: 0; transform: translateY(-6px) scale(.92); } }

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .product-badge { background: var(--color-4); }
    .product-badge.sale-badge { background: var(--color-5); }
    .product-badge.roast-type-badge-overlay { background: var(--color-1); }
}

/* ── Recetas: scrim y meta ───────────────────────────────── */
.recipe-image::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    height: 45%;
    background: linear-gradient(to top, rgb(8 22 10 / .48), transparent);
    pointer-events: none;
}
.recipe-badge {
    position: absolute;
    z-index: 2;
    inset-block-end: 12px;
    inset-inline-start: 12px;
    padding: .35rem .85rem;
    border-radius: var(--radius-pill);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .04em;
    color: var(--white);
    background: color-mix(in srgb, var(--color-1) 66%, transparent);
    border: 1px solid rgb(255 255 255 / .28);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .recipe-badge {
        -webkit-backdrop-filter: blur(var(--glass-blur-soft)) saturate(130%);
                backdrop-filter: blur(var(--glass-blur-soft)) saturate(130%);
    }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .recipe-badge { background: var(--color-1); }
}

.recipe-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-block-start: auto;
    padding-block-start: .9rem;
    border-block-start: 1px solid var(--hairline);
    font-size: var(--fs-sm);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.recipe-meta span { display: inline-flex; align-items: center; gap: .4rem; }
.recipe-meta svg  { opacity: .55; }

/* ── Precios ─────────────────────────────────────────────── */
.product-price {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--color-6);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.015em;
    margin: 0;
}

/* Product Pricing */
.product-pricing {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.product-price-original {
    font-size: 1.1rem;
    color: var(--gray-medium);
    text-decoration: line-through;
    font-weight: 400;
    margin: 0;
}

.product-price-sale {
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--color-1);
    margin: 0;
    line-height: 1;
}

.product-savings {
    font-size: 0.9rem;
    color: var(--color-3);
    font-weight: 600;
    margin: 0;
    font-style: italic;
}

/* Mercado Libre Button */
.btn-mercado-libre {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-size: 1.1rem;
    padding: 16px 32px;
    background: var(--color-1);
    box-shadow: 0 4px 15px rgba(28, 94, 33, 0.3);
}

.btn-mercado-libre:hover {
    background: var(--color-2);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(28, 94, 33, 0.4);
}

.btn-mercado-libre svg {
    width: 24px;
    height: 24px;
}

/* ═══════════════════════════════════════════════════════════
   LÍNEA DE PROCESO
   Es la sección más repetitiva (8 pasos). Fuera la tarjeta blanca; entra
   riel + número sticky + columnas alternadas.
   Nota: las clases {% cycle 'left' 'right' %} llevaban en la plantilla desde
   siempre pero NO tenían ninguna regla CSS. Aquí por fin se cablean.
   ═══════════════════════════════════════════════════════════ */
.process-timeline {
    --rail-col: clamp(56px, 6vw, 88px);
    --rail-x: calc(var(--rail-col) / 2);
    position: relative;
    max-width: 1100px;
    margin-inline: auto;
    padding-block: clamp(1.5rem, 1rem + 2vw, 3rem);
    counter-reset: step;
}

.process-section .section-subtitle { font-style: italic; }

/* Riel estático */
.process-timeline::before {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: var(--rail-x);
    width: 2px;
    background: color-mix(in oklab, var(--color-1) 13%, transparent);
}
/* Relleno ligado al scroll. CSS puro; donde no hay soporte simplemente no se ve. */
.process-timeline::after {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: var(--rail-x);
    width: 2px;
    background: linear-gradient(to bottom, var(--color-2), var(--color-1));
    transform-origin: top;
    transform: scaleY(0);
}
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .process-timeline::after {
            animation: rail-fill linear both;
            animation-timeline: view();
            animation-range: entry 55% exit 45%;
        }
        @keyframes rail-fill { from { transform: scaleY(0); } to { transform: scaleY(1); } }
    }
}

.process-step {
    display: grid;
    grid-template-columns: var(--rail-col) minmax(0, 1fr) minmax(0, 1fr);
    column-gap: clamp(1.5rem, 1rem + 2.2vw, 3.25rem);
    row-gap: 1rem;
    align-items: start;
    margin-block-end: clamp(3rem, 2rem + 4vw, 6.5rem);
    background: none;
    padding: 0;
    border-radius: 0;
    box-shadow: none;
    /* Sin content-visibility a propósito: aplica `contain: style`, que aísla
       los contadores CSS. Con él, cada paso reiniciaba su contador y el
       eyebrow salía "PASO 01" en los ocho. La numeración correcta vale más
       que ahorrar render en una lista de ocho elementos. */
}
.process-step:hover { transform: none; box-shadow: none; }

.process-content,
.process-image { grid-row: 1; }
.process-content { align-self: center; }   /* el texto es corto y la fila la
                                              marca la imagen: centrado, el
                                              hueco se reparte en vez de
                                              acumularse debajo */   /* ambos en la MISMA fila: el orden del DOM es
                                     numero -> imagen -> texto, y con fila
                                     automatica el texto caia a la fila 2 */
.process-step.left  .process-content { grid-column: 2; }
.process-step.left  .process-image   { grid-column: 3; }
.process-step.right .process-content { grid-column: 3; }
.process-step.right .process-image   { grid-column: 2; }
/* about.html no usa el cycle: por defecto, disposición "left". */
.process-step:not(.left):not(.right) .process-content { grid-column: 2; }
.process-step:not(.left):not(.right) .process-image   { grid-column: 3; }

/* El número se queda fijo mientras su paso pasa, y suelta en el siguiente:
   da sensación de posición dentro de una lista larga. */
.process-number {
    grid-column: 1;
    grid-row: 1 / -1;
    position: sticky;
    top: calc(var(--nav-clear) + clamp(1rem, 3vh, 2.5rem));
    display: grid;
    place-items: center;
    width: var(--rail-col);
    height: var(--rail-col);
    border-radius: 50%;
    background: var(--surface-warm);
    border: 2px solid color-mix(in oklab, var(--color-1) 30%, transparent);
    color: var(--color-1);
    font-family: var(--font-display);
    font-size: clamp(1.15rem, .9rem + .8vw, 1.6rem);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    box-shadow: none;
    transition:
        background-color var(--dur-base) var(--ease-out),
        border-color     var(--dur-base) var(--ease-out),
        color            var(--dur-base) var(--ease-out);
}
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .process-number {
            animation: step-active steps(1, jump-none) both;
            animation-timeline: view();
            animation-range: cover 18% cover 82%;
        }
        @keyframes step-active {
            50% { background: var(--color-1); border-color: var(--color-1); color: var(--white); }
        }
    }
}

.process-image {
    width: 100%;
    height: auto;
    border-radius: var(--radius-lg);
    overflow: clip;
    box-shadow: var(--shadow-sm);
    background: color-mix(in oklab, var(--color-4) 20%, var(--white));
}
/* Recorte alternado: 8 pasos idénticos leen como una lista; alternando, no. */
.process-step.left  .process-image { aspect-ratio: 3 / 2; }
.process-step.right .process-image { aspect-ratio: 1 / 1; }
.process-step:not(.left):not(.right) .process-image { aspect-ratio: 3 / 2; }
.process-image img { width: 100%; height: 100%; object-fit: cover; }
.process-image:hover img { transform: none; }   /* aquí las imágenes no son enlaces */

.process-content { padding-block-start: .25rem; }
.process-content h3 {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 1.15rem + 1vw, 2rem);
    line-height: 1.12;
    letter-spacing: -.018em;
    color: var(--color-1);
    text-wrap: balance;
    margin-block-end: .85rem;
}
.process-content h3::before {
    content: 'Paso ' counter(step, decimal-leading-zero);
    counter-increment: step;
    display: block;
    margin-block-end: .5rem;
    font-family: var(--font-primary);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: color-mix(in oklab, var(--color-2) 75%, transparent);
}
.process-content p {
    font-size: 1.02rem;
    line-height: 1.78;
    color: var(--text-muted);
    max-width: 46ch;
    text-wrap: pretty;
}

@media (max-width: 860px) {
    .process-timeline { --rail-col: 44px; }
    .process-step {
        grid-template-columns: var(--rail-col) minmax(0, 1fr);
        margin-block-end: clamp(2.5rem, 2rem + 3vw, 4rem);
    }
    .process-step .process-content,
    .process-step .process-image { grid-column: 2 !important; grid-row: auto !important; }
    .process-step .process-image { aspect-ratio: 16 / 10 !important; }
    .process-number { grid-row: 1; font-size: 1rem; }
}

/* ═══════════════════════════════════════════════════════════
   FILAS "QUIÉNES SOMOS"
   ═══════════════════════════════════════════════════════════ */
.about-preview,
.about-section { counter-reset: aboutrow; }

.about-row {
    display: grid;
    grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
    gap: clamp(2rem, 1.2rem + 4vw, 5.5rem);
    align-items: center;
    padding: 0;
    border-radius: 0;
    background: none;
    counter-increment: aboutrow;
    /* Igual que en .process-step: content-visibility aislaría este contador. */
}
/* Los tintes :nth-child estaban rotos en about.html: cada fila va en su propio
   .container, así que todas eran :nth-child(1) y recibían el mismo verde. */
.about-row:nth-child(odd),
.about-row:nth-child(even) { background: none; }

.about-row + .about-row { margin-block-start: clamp(3.5rem, 2rem + 6vw, 9rem); }

/* `order` en vez de `direction: rtl`: el rtl era un bug latente sobre el
   rich-text que produce |linebreaks (puntuación y enlaces en línea). */
.about-row.reverse { direction: ltr; }
.about-row.reverse > * { direction: ltr; }
.about-row.reverse .about-image { order: -1; }

/* AboutSection.image es nullable: sin esto la fila desperdicia media rejilla. */
.about-row:not(:has(.about-image)) { grid-template-columns: minmax(0, 1fr); }
.about-row:not(:has(.about-image)) .about-content { max-width: 68ch; margin-inline: auto; }

.about-content { max-width: 52ch; }
.about-content h2 {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.85rem);
    line-height: 1.08;
    letter-spacing: var(--tracking-tight);
    color: var(--color-1);
    text-wrap: balance;
    margin-block-end: 1.1rem;
}
.about-content h2::before {
    content: counter(aboutrow, decimal-leading-zero);
    display: block;
    margin-block-end: .75rem;
    font-family: var(--font-primary);
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: var(--tracking-caps);
    color: color-mix(in oklab, var(--color-2) 72%, transparent);
}
.about-text {
    font-size: 1.05rem;
    line-height: 1.78;
    color: var(--text-muted);
    text-wrap: pretty;
    margin-block-end: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
}
.about-text p + p { margin-block-start: 1em; }

.about-image {
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 5;
    border-radius: var(--radius-xl);
    overflow: clip;
    box-shadow: var(--shadow-lg);
    background: color-mix(in oklab, var(--color-4) 20%, var(--white));
    transition: none;
}
.about-image img { width: 100%; height: 100%; object-fit: cover; object-position: center 40%; }

@media (max-width: 860px) {
    .about-row { grid-template-columns: minmax(0, 1fr); gap: clamp(1.5rem, 1rem + 2vw, 2.5rem); }
    .about-row.reverse .about-image { order: 0; }
    .about-image { aspect-ratio: 3 / 2; }
}

/* ═══════════════════════════════════════════════════════════
   TESTIMONIOS
   El slider pasa a scroll-snap: se lleva por delante el parseo de la matriz
   de transform y regala swipe táctil y teclado. window.slideTestimonials
   conserva la firma porque hay onclick inline en home.html que la llaman.
   ═══════════════════════════════════════════════════════════ */
.testimonials-section {
    background: var(--surface-deep);
    color: color-mix(in srgb, var(--white) 92%, transparent);
}
.testimonials-section .section-title { color: var(--white); }
.testimonials-section .section-title[data-eyebrow]::before {
    color: color-mix(in srgb, var(--color-3) 90%, transparent);
}

.testimonials-slider {
    display: flex;
    gap: clamp(1rem, .6rem + 1.4vw, 1.75rem);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    margin-block-start: clamp(1.5rem, 1rem + 2vw, 3rem);
    padding-block-end: .5rem;
}
.testimonials-slider::-webkit-scrollbar { display: none; }

/* display:contents saca al track del layout y deja las tarjetas como hijas
   directas de .testimonials-slider.
   Es necesario, no cosmético: con el track como flex item su ancho es
   indefinido, así que el `min(100%, 560px)` de la tarjeta no podía resolver el
   porcentaje y caía al ancho de su contenido — 516px dentro de un contenedor
   de 421 en móvil. Colgando del slider, que sí tiene ancho definido, el 100%
   resuelve bien. El gap pasa a venir del slider. */
.testimonials-track {
    display: contents;
}

.testimonial-card {
    flex: 0 0 min(100%, 560px);
    scroll-snap-align: center;
    background: rgb(255 255 255 / .08);
    border: 1px solid rgb(255 255 255 / .12);
    padding: clamp(1.75rem, 1.2rem + 2vw, 3rem);
    border-radius: var(--radius-lg);
    text-align: center;
}

.testimonial-rating { margin-block-end: var(--spacing-sm); font-size: 1.15rem; letter-spacing: .1em; }
.testimonial-rating .star        { color: rgb(255 255 255 / .25); }
.testimonial-rating .star.filled { color: var(--color-4); }

.testimonial-content {
    font-family: var(--font-display);
    font-size: clamp(1.05rem, 1rem + .45vw, 1.3rem);
    font-style: italic;
    line-height: 1.65;
    margin-block-end: var(--spacing-md);
    text-wrap: pretty;
}

.testimonial-author { display: flex; align-items: center; justify-content: center; gap: var(--spacing-sm); }
.testimonial-image  { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; }
.testimonial-name   { font-weight: 700; font-size: var(--fs-base); }
.testimonial-role   { font-size: var(--fs-sm); opacity: .72; }

.slider-controls { display: flex; justify-content: center; gap: .75rem; margin-block-start: var(--spacing-md); }
.slider-btn {
    width: 48px; height: 48px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: rgb(255 255 255 / .10);
    border: 1px solid rgb(255 255 255 / .18);
    color: var(--white);
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    transition: background var(--dur-base) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.slider-btn:hover { background: rgb(255 255 255 / .2); transform: translateY(-2px); }

/* ═══════════════════════════════════════════════════════════
   CTA — de banda a panel embebido
   ═══════════════════════════════════════════════════════════ */
.cta-section {
    background: var(--surface);
    padding-block: clamp(3rem, 2rem + 4vw, 6rem);
    text-align: center;
}
.cta-section > .container {
    position: relative;
    isolation: isolate;
    overflow: clip;
    max-width: 1100px;
    padding: clamp(2.5rem, 1.5rem + 5vw, 6rem) clamp(1.5rem, 1rem + 3vw, 4rem);
    border-radius: var(--radius-xl);
    border: 1px solid color-mix(in oklab, var(--color-6) 14%, transparent);
    background:
        radial-gradient(90% 120% at 82% 8%,
            color-mix(in oklab, var(--color-5) 16%, transparent) 0%, transparent 62%),
        linear-gradient(158deg,
            color-mix(in oklab, var(--color-4) 44%, #fff) 0%,
            color-mix(in oklab, var(--color-4) 90%, #fff) 100%);
    box-shadow: var(--shadow-sm);
}
.cta-title {
    font-family: var(--font-display);
    font-size: clamp(1.9rem, 1.2rem + 3vw, 3.4rem);
    line-height: 1.05;
    letter-spacing: -.026em;
    color: var(--color-6);
    text-wrap: balance;
    max-width: 18ch;
    margin-inline: auto;
    margin-block-end: 1rem;
}
.cta-text {
    font-size: clamp(1rem, .95rem + .4vw, 1.18rem);
    line-height: var(--lh-loose);
    color: color-mix(in oklab, var(--color-6) 78%, transparent);
    max-width: 48ch;
    margin: 0 auto clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
    text-wrap: pretty;
}
.cta-buttons { display: flex; gap: .85rem; justify-content: center; flex-wrap: wrap; }

/* ═══════════════════════════════════════════════════════════
   FOOTER — sin un solo cambio de markup
   ═══════════════════════════════════════════════════════════ */
.footer {
    background: var(--surface-deep);
    color: color-mix(in srgb, var(--white) 88%, transparent);
    padding-block: clamp(3.5rem, 2rem + 5vw, 6.5rem) clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
    border-block-start: 1px solid color-mix(in srgb, var(--white) 8%, transparent);
}

/* auto-fit daba 4 columnas iguales y apretaba el tagline. */
.footer-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2rem, 1.2rem + 3vw, 4rem);
    margin-block-end: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}
@media (min-width: 640px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 980px) {
    .footer-grid { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.25fr); }
}

.footer-logo { height: 52px; width: auto; margin-block-end: 1.25rem; }
.footer-tagline {
    font-size: var(--fs-sm);
    line-height: var(--lh-loose);
    max-width: 34ch;
    color: color-mix(in srgb, var(--white) 66%, transparent);
    margin-block-end: 1.5rem;
    text-wrap: pretty;
}
.footer-title {
    font-family: var(--font-primary);
    font-size: .73rem;
    font-weight: 600;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: color-mix(in srgb, var(--white) 55%, transparent);
    margin-block-end: 1.15rem;
}

.footer-links { display: flex; flex-direction: column; gap: .7rem; }
/* Subrayado animado con background-size: sin layout shift ni repintado del texto. */
.footer-links a,
.footer-contact a {
    display: inline;
    font-size: var(--fs-sm);
    color: color-mix(in srgb, var(--white) 82%, transparent);
    background-image: linear-gradient(currentColor, currentColor);
    background-size: 0% 1px;
    background-position: 0 100%;
    background-repeat: no-repeat;
    transition: color var(--dur-base) var(--ease-out), background-size 340ms var(--ease-out);
}
.footer-links a:hover,
.footer-contact a:hover { color: var(--white); background-size: 100% 1px; }

.footer-social { display: flex; gap: .65rem; }
.social-link {
    width: 44px; height: 44px;      /* 40px quedaba por debajo del objetivo táctil */
    display: grid; place-items: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--white) 6%, transparent);
    border: 1px solid color-mix(in srgb, var(--white) 14%, transparent);
    color: color-mix(in srgb, var(--white) 82%, transparent);
    transition:
        background-color var(--dur-base) var(--ease-out),
        border-color     var(--dur-base) var(--ease-out),
        color            var(--dur-base) var(--ease-out),
        transform        var(--dur-fast) var(--ease-out);
}
.social-link:hover {
    background: var(--color-4);
    border-color: var(--color-4);
    color: var(--color-6);
    transform: translateY(-2px);
}
.social-link svg { width: 20px; height: 20px; flex-shrink: 0; }

/* WhatsApp con el número a la vista: mucha gente no pulsa un icono suelto
   porque no sabe qué hay detrás. Deja de ser círculo y pasa a píldora. */
.social-link-wa {
    width: auto;
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding-inline: .9rem;
    border-radius: var(--radius-pill);
}
.social-link-label {
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-snug);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
/* La píldora es mucho más ancha que los iconos: la fila debe poder partirse. */
.footer-social { flex-wrap: wrap; }

.footer-contact { display: flex; flex-direction: column; gap: .9rem; }
.footer-contact li { display: flex; align-items: start; gap: .65rem; font-size: var(--fs-sm); }
.footer-contact svg { flex-shrink: 0; margin-block-start: 3px; opacity: .55; }

.footer-bottom {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    padding-block-start: clamp(1.5rem, 1rem + 1.5vw, 2.25rem);
    border-block-start: 1px solid color-mix(in srgb, var(--white) 11%, transparent);
    text-align: start;
    font-size: var(--fs-sm);
    color: color-mix(in srgb, var(--white) 58%, transparent);
}
.footer-location { margin: 0; opacity: 1; font-size: inherit; }
@media (max-width: 560px) { .footer-bottom { justify-content: center; text-align: center; } }

/* ═══════════════════════════════════════════════════════════
   CABECERA DE PÁGINAS INTERNAS
   ═══════════════════════════════════════════════════════════ */
.page-header {
    position: relative;
    display: grid;
    align-content: end;
    isolation: isolate;
    overflow: clip;
    min-height: clamp(320px, 44svh, 480px);
    /* Atada al token, no a un 80 mágico. */
    padding-block: calc(var(--nav-clear) + clamp(3.5rem, 2rem + 6vw, 7rem))
                   clamp(2.5rem, 1.75rem + 3vw, 4.5rem);
    /* Esquinas inferiores redondeadas: lee como tarjeta bajo una píldora flotante. */
    border-end-start-radius: clamp(20px, 3.5vw, 44px);
    border-end-end-radius:   clamp(20px, 3.5vw, 44px);
    color: var(--white);
    text-align: start;
    background: linear-gradient(152deg, var(--color-1) 0%,
                color-mix(in oklab, var(--color-1) 62%, var(--color-6)) 100%);
}
.page-header::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to bottom, rgb(8 22 10 / .38) 0%, rgb(8 22 10 / 0) 26%),
        linear-gradient(to top,    rgb(8 22 10 / .72) 0%, rgb(8 22 10 / .30) 46%,
                                   rgb(8 22 10 / .05) 80%);
}
.page-header.has-bg-image {
    background-size: cover;
    background-position: center 42%;
    background-repeat: no-repeat;
}
.page-header.has-bg-image::before {
    background:
        linear-gradient(to bottom, rgb(8 22 10 / .42) 0%, rgb(8 22 10 / 0) 24%),
        linear-gradient(to top,    rgb(8 22 10 / .78) 0%, rgb(8 22 10 / .38) 42%,
                                   rgb(8 22 10 / .08) 78%),
        linear-gradient(to top, color-mix(in oklab, var(--color-1) 52%, transparent), transparent 58%);
}
/* width:100% es obligatorio: .page-header es grid y .container lleva
   `margin: 0 auto`. Con márgenes automáticas el grid item no se estira, se
   ajusta al contenido y queda centrado — el título salía centrado aunque
   text-align fuera `start`. */
.page-header .container { position: relative; z-index: 2; width: 100%; }
.page-header h1 {
    font-family: var(--font-display);
    font-size: var(--fs-3xl);
    line-height: 1.02;
    letter-spacing: -.028em;
    text-wrap: balance;
    max-width: 17ch;
    margin-block-end: .85rem;
    text-shadow: none;
}
.page-header p {
    font-size: clamp(1rem, .95rem + .4vw, 1.22rem);
    line-height: 1.6;
    max-width: 48ch;
    color: color-mix(in srgb, var(--white) 84%, transparent);
    opacity: 1;
    text-wrap: pretty;
}

/* ═══════════════════════════════════════════════════════════
   CONTACTO
   ═══════════════════════════════════════════════════════════ */
.contact-section { padding-block: var(--section-pad); }

.contact-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    gap: clamp(2rem, 1.2rem + 3.5vw, 4.5rem);
    align-items: start;
}
@media (max-width: 860px) { .contact-grid { grid-template-columns: minmax(0, 1fr); } }

.contact-form-container h2,
.contact-info h2 {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 1.2rem + .9vw, 1.9rem);
    color: var(--color-1);
    margin-block-end: clamp(1.25rem, 1rem + 1vw, 2rem);
}

.contact-form { display: flex; flex-direction: column; gap: 1.15rem; }
.form-group   { display: flex; flex-direction: column; gap: .45rem; }

.form-group label {
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: color-mix(in oklab, var(--color-1) 88%, transparent);
}

.form-group input,
.form-group textarea {
    padding: .875rem 1rem;
    border: 1px solid color-mix(in oklab, var(--color-6) 18%, transparent);
    border-radius: var(--radius-md);
    background: var(--surface);
    font-family: inherit;
    font-size: 1rem;                 /* nunca por debajo de 16px: iOS hace zoom al enfocar */
    line-height: 1.5;
    color: var(--text);
    transition: border-color var(--dur-base) var(--ease-out),
                box-shadow   var(--dur-base) var(--ease-out);
}
.form-group textarea { resize: vertical; min-height: 9rem; }

.form-group input:focus-visible,
.form-group textarea:focus-visible {
    outline: none;
    border-color: var(--color-1);
    box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-2) 16%, transparent);
}

/* :user-invalid sólo salta DESPUÉS de que el usuario interactúe, al contrario
   que :invalid, que pintaría de rojo todos los obligatorios al cargar.
   Sustituye al validateContactForm() que estaba muerto en main.js. */
.form-group input:user-invalid,
.form-group textarea:user-invalid {
    border-color: #b3261e;
    box-shadow: 0 0 0 4px rgb(179 38 30 / .1);
}

.contact-info {
    position: sticky;
    top: calc(var(--nav-clear) + 1rem);
    background: var(--surface-warm);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    padding: clamp(1.5rem, 1.2rem + 1.6vw, 2.5rem);
}
@media (max-width: 860px) { .contact-info { position: static; } }

.contact-item { display: flex; gap: 1rem; margin-block-end: 1.5rem; }
.contact-icon {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-md);
    background: color-mix(in oklab, var(--color-3) 22%, transparent);
    font-size: 1.25rem;
}
.contact-item h3 {
    font-family: var(--font-primary);
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-block-end: .25rem;
}

.social-links-large { display: flex; gap: .65rem; margin-block-start: 2rem; }
.social-btn {
    flex: 1;
    padding: .8rem;
    border-radius: var(--radius-pill);
    background: var(--color-1);
    color: var(--white);
    text-align: center;
    font-weight: 600;
    font-size: var(--fs-sm);
    transition: background var(--dur-base) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.social-btn:hover { background: var(--color-2); transform: translateY(-2px); }

/* ═══════════════════════════════════════════════════════════
   FILTRO DE CATEGORÍAS
   ═══════════════════════════════════════════════════════════ */
.category-filter {
    display: flex;
    gap: .6rem;
    flex-wrap: nowrap;               /* en móvil scrollea en vez de envolver */
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    padding-block: .25rem;
    margin-block-end: clamp(2rem, 1.5rem + 2vw, 3.5rem);
    /* Desvanece el borde para que se lea como scrolleable */
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 40px), transparent 100%);
}
.category-filter::-webkit-scrollbar { display: none; }
@media (min-width: 860px) {
    .category-filter { flex-wrap: wrap; justify-content: center; overflow: visible; mask-image: none; }
}

.category-btn {
    flex-shrink: 0;
    scroll-snap-align: start;
    padding: .6rem 1.25rem;
    border-radius: var(--radius-pill);
    border: 1px solid color-mix(in oklab, var(--color-1) 22%, transparent);
    background: var(--surface);
    color: var(--color-1);
    font-size: var(--fs-sm);
    font-weight: 600;
    white-space: nowrap;
    transition: background-color var(--dur-base) var(--ease-out),
                color            var(--dur-base) var(--ease-out),
                border-color     var(--dur-base) var(--ease-out);
}
.category-btn:hover {
    border-color: var(--color-1);
    background: color-mix(in oklab, var(--color-3) 15%, transparent);
}
.category-btn.active {
    background: var(--color-1);
    color: var(--white);
    border-color: var(--color-1);
    box-shadow: 0 8px 20px -12px color-mix(in oklab, var(--color-1) 80%, transparent);
}

/* ═══════════════════════════════════════════════════════════
   PAGINACIÓN
   ═══════════════════════════════════════════════════════════ */
.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: .75rem;
    margin-block-start: clamp(2.5rem, 2rem + 3vw, 4.5rem);
    padding-block-start: clamp(1.5rem, 1rem + 2vw, 2.5rem);
    border-block-start: 1px solid var(--hairline);
}
.pagination-btn {
    padding: .65rem 1.35rem;
    border-radius: var(--radius-pill);
    border: 1px solid color-mix(in oklab, var(--color-1) 22%, transparent);
    background: var(--surface);
    color: var(--color-1);
    font-size: var(--fs-sm);
    font-weight: 600;
    transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.pagination-btn:hover { background: var(--color-1); color: var(--white); }
/* .pagination-info y el <span> pelado de recipes.html no tenían ningún estilo */
.pagination-info,
.pagination > span {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════
   DETALLE DE PRODUCTO
   ═══════════════════════════════════════════════════════════ */
.product-detail {
    padding-block: calc(var(--nav-clear) + clamp(1.5rem, 1rem + 2.5vw, 3.5rem))
                   clamp(3rem, 2rem + 4vw, 6rem);
}

/* El panel de compra acompaña mientras se recorre la galería. */
@media (min-width: 980px) {
    .product-details { position: sticky; top: calc(var(--nav-clear) + 1rem); align-self: start; }
}

.product-detail-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    gap: clamp(2rem, 1.2rem + 3.5vw, 4.5rem);
    align-items: start;
    margin-top: 0;
}
@media (max-width: 980px) { .product-detail-grid { grid-template-columns: minmax(0, 1fr); } }

.main-product-image {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;             /* sustituye a los 500px fijos */
    object-fit: cover;
    object-position: center 45%;
    border-radius: var(--radius-xl);
    background: color-mix(in oklab, var(--color-4) 18%, var(--white));
    margin-bottom: var(--spacing-sm);
}

.product-thumbnails {
    display: flex;
    gap: var(--spacing-sm);
    flex-wrap: wrap;
}

.thumbnail {
    width: 72px;
    height: 72px;
    object-fit: cover;
    border-radius: var(--radius-md);
    cursor: pointer;
    /* outline en vez de border: el borde de 3px provocaba un salto de layout
       de 6px cada vez que cambiaba la miniatura activa */
    border: 0;
    outline: 2px solid transparent;
    outline-offset: 2px;
    opacity: .68;
    transition: outline-color var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}

.thumbnail:hover,
.thumbnail.active { outline-color: var(--color-1); opacity: 1; }

/* En el detalle el badge va EN EL FLUJO, no superpuesto sobre una imagen, así
   que no lleva .product-badge y necesita su propio estilo completo. */
.product-details .sale-badge {
    display: inline-flex;
    align-items: center;
    margin-bottom: var(--spacing-sm);
    padding: .45rem 1.1rem;
    border-radius: var(--radius-pill);
    background: var(--sienna-600);
    color: var(--white);
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .04em;
}

/* Product Detail - Pricing */
.product-details .product-pricing {
    margin: var(--spacing-xs) 0;
    padding: var(--spacing-xs) var(--spacing-md);
    background: var(--surface-warm);
    border-radius: 12px;
    border-left: 4px solid var(--color-1);
}

.product-details .product-price-original {
    font-size: 1.2rem;
}

.product-details .product-price-sale {
    font-size: 2.5rem;
    margin: 8px 0;
}

.product-details .product-savings {
    font-size: 1rem;
    padding: 6px 12px;
    background: var(--color-3);
    color: var(--white);
    border-radius: 6px;
    display: inline-block;
}

.product-details .product-price {
    font-size: 2rem;
    color: var(--color-1);
    margin: var(--spacing-xs) 0;
}

.product-actions {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-sm);
    margin-top: var(--spacing-md);
}

.product-features {
    margin-top: var(--spacing-md);
    padding: var(--spacing-md);
    background: var(--gray-light);
    border-radius: 8px;
}

.product-features ul {
    list-style: disc;
    margin-left: var(--spacing-md);
}

.product-features li {
    margin-bottom: var(--spacing-xs);
}

/* ═══════════════════════════════════════════════════════════
   DETALLE DE RECETA
   .recipe-detail no tenía ninguna regla: sólo recibía section{padding} y el
   contenido quedaba debajo de la navbar.
   ═══════════════════════════════════════════════════════════ */
.recipe-detail {
    padding-block: calc(var(--nav-clear) + clamp(1.5rem, 1rem + 2vw, 3rem))
                   clamp(3rem, 2rem + 4vw, 6rem);
}

.recipe-hero {
    width: 100%;
    height: auto;
    aspect-ratio: 21 / 9;            /* sustituye a los 400px fijos */
    min-height: 240px;
    border-radius: var(--radius-xl);
    overflow: clip;
    box-shadow: var(--shadow-lg);
    background: color-mix(in oklab, var(--color-4) 18%, var(--white));
    margin-top: 0;
}

.recipe-hero img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.recipe-header {
    text-align: center;
    margin: var(--spacing-lg) 0;
}

.recipe-meta-large {
    display: flex;
    justify-content: center;
    gap: var(--spacing-lg);
    margin-top: var(--spacing-md);
}

.meta-item {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    font-size: 1.1rem;
}

.meta-item span:first-child {
    font-size: 1.5rem;
}

.recipe-content-grid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: var(--spacing-lg);
    margin-bottom: var(--spacing-lg);
}

.recipe-ingredients,
.recipe-instructions {
    background: var(--gray-light);
    padding: var(--spacing-md);
    border-radius: 12px;
}

.recipe-ingredients h2,
.recipe-instructions h2 {
    color: var(--color-1);
    margin-bottom: var(--spacing-sm);
}

.recipe-ingredients ul,
.recipe-instructions ol {
    margin-left: var(--spacing-md);
}

.recipe-ingredients li,
.recipe-instructions li {
    margin-bottom: var(--spacing-sm);
    line-height: 1.6;
}

/* Utilities */
.bg-light {
    background: var(--gray-light);
}

.bg-white {
    background: var(--white);
}

.no-results {
    text-align: center;
    padding: var(--spacing-xl);
    color: var(--gray-dark);
    font-size: 1.2rem;
}

/* ═══════════════════════════════════════════════════════════
   MOTOR DE REVELADO
   API de atributos sin cambios: data-aos + data-aos-delay siguen funcionando.
   Nuevo: data-stagger en un contenedor escalona a sus hijos vía --i.

   El estado oculto está gateado en `html.js`, que añade main.js en cuanto
   arranca. Sin ese gate, un main.js que falle o venga bloqueado dejaba toda
   la página bajo el héroe invisible.
   ═══════════════════════════════════════════════════════════ */

.js [data-aos],
.js [data-stagger] > * {
    opacity: 0;
    transition-property: opacity, transform, filter;
    transition-duration: var(--dur-slow);
    transition-timing-function: var(--ease-out);
    transition-delay: var(--aos-delay, 0ms);
    will-change: opacity, transform;
}

.js [data-aos].aos-animate,
.js [data-stagger].aos-animate > * {
    opacity: 1;
    transform: none;
    filter: blur(0);
    will-change: auto;          /* libera la capa del compositor al terminar */
}

/* Variantes existentes */
.js [data-aos="fade-up"]    { transform: translate3d(0, 28px, 0); }
.js [data-aos="fade-right"] { transform: translate3d(-36px, 0, 0); }
.js [data-aos="fade-left"]  { transform: translate3d(36px, 0, 0); }

/* Se usaba en plantillas pero nunca tuvo variante: sólo hacía fade. */
.js [data-aos="fade-down"]  { transform: translate3d(0, -22px, 0); }

/* Nuevas */
.js [data-aos="scale-in"]   { transform: scale(.94); }
.js [data-aos="blur-in"]    { transform: scale(1.012); filter: blur(10px); }

/* clip-path no interpola hacia `none`, así que el estado final debe ser un
   inset() explícito. Sólo en imágenes y titulares: clip-path recorta también
   el box-shadow, nunca sobre una tarjeta con sombra. */
.js [data-aos="clip-up"] {
    clip-path: inset(0 0 100% 0);
    transform: translate3d(0, 14px, 0);
    transition-property: opacity, transform, clip-path;
}
.js [data-aos="clip-up"].aos-animate { clip-path: inset(0 0 0 0); }

/* Escalonado por CSS. Debe ir DESPUÉS de la regla base: misma especificidad,
   decide el orden de fuente. min() aplana la cola para que la tarjeta 12 de
   una página paginada no llegue 840ms tarde. */
.js [data-stagger] > * {
    --stagger-step: 70ms;
    transform: translate3d(0, 28px, 0);
    transition-delay: calc(min(var(--i, 0), 7) * var(--stagger-step) + var(--aos-delay, 0ms));
}

/* Responsive Design */
@media (max-width: 968px) {
    .product-detail-grid,
    .about-row,
    .contact-grid,
    .recipe-content-grid {
        grid-template-columns: 1fr;
    }

    .about-row {
        padding: var(--spacing-md);
        gap: var(--spacing-md);
    }

    .hero-section {
        min-height: 500px;
    }

    /* Process steps - tablet layout */
    .process-step {
        grid-template-columns: 60px 1fr;
        gap: var(--spacing-md);
        margin-bottom: var(--spacing-lg);
        padding: var(--spacing-md);
    }

    .process-number {
        width: 60px;
        height: 60px;
        font-size: 1.4rem;
        grid-row: 1 / 3;
    }

    .process-image {
        height: 200px;
        grid-column: 2;
    }

    .process-content {
        grid-column: 2;
    }

    .process-content h3 {
        font-size: 1.4rem;
        margin-top: var(--spacing-sm);
    }

    .process-content p {
        font-size: 1rem;
    }
}

@media (max-width: 640px) {
    :root {
        --spacing-lg: 2.5rem;
        --spacing-xl: 3.5rem;
    }

    section {
        padding: var(--spacing-md) 0;
    }

    .process-section,
    .about-preview,
    .featured-recipes {
        padding: var(--spacing-md) 0;
    }

    /* Process steps - mobile layout */
    .process-step {
        grid-template-columns: 50px 1fr;
        gap: var(--spacing-xs);
        padding: var(--spacing-sm);
        margin-bottom: var(--spacing-md);
    }

    .process-number {
        width: 50px;
        height: 50px;
        font-size: 1.2rem;
    }

    .about-row {
        padding: var(--spacing-sm);
        margin-bottom: var(--spacing-md);
    }

    .products-grid,
    .recipes-grid,
    .value-grid {
        gap: var(--spacing-xs);
    }

    .process-image {
        grid-column: 1 / -1;
        height: 180px;
    }

    .process-content {
        grid-column: 1 / -1;
    }

    .process-content h3 {
        font-size: 1.3rem;
    }
}

/* Product Tagline Styles */
.product-tagline {
    font-size: 0.8rem;
    color: var(--gray-dark);
    font-style: italic;
    margin-top: 0.5rem;
    line-height: 1.4;
}

.product-tagline-detail {
    font-size: 0.85rem;
    color: var(--gray-dark);
    font-style: italic;
    margin-top: 0.5rem;
    margin-bottom: 1rem;
    padding: 0.75rem;
    background-color: var(--gray-light);
    border-left: 3px solid var(--color-2);
    border-radius: 4px;
    line-height: 1.5;
}

.product-short-description {
    font-size: 1.1rem;
    color: var(--color-6);
    margin: 1rem 0;
    font-weight: 500;
}

/* Roast Type Badge (for product listing) */
.roast-type-badge {
    display: inline-block;
    background: linear-gradient(135deg, var(--color-1), var(--color-2));
    color: var(--white);
    padding: 0.4rem 1rem;
    border-radius: 20px;
    font-size: 0.85rem;
    font-weight: 600;
    margin-top: 0.5rem;
    cursor: pointer;
    border: none;
    transition: var(--transition);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}

.roast-type-badge:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    background: linear-gradient(135deg, var(--color-2), var(--color-3));
}

/* Roast Type Modal */
.roast-modal {
    display: none;
    position: fixed;
    z-index: 2000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: auto;
    background-color: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
}

.roast-modal-content {
    background-color: var(--white);
    margin: 5% auto;
    padding: 2rem;
    border-radius: 12px;
    max-width: 600px;
    position: relative;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
    animation: modalSlideIn 0.3s ease-out;
}

@keyframes modalSlideIn {
    from {
        transform: translateY(-50px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.roast-modal-close {
    position: absolute;
    right: 1rem;
    top: 1rem;
    color: var(--gray-dark);
    font-size: 2rem;
    font-weight: bold;
    background: none;
    border: none;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: var(--transition);
}

.roast-modal-close:hover,
.roast-modal-close:focus {
    color: var(--color-1);
    background-color: var(--gray-light);
}

.roast-modal-content h2 {
    color: var(--color-1);
    margin-bottom: 0.5rem;
    font-size: 2rem;
}

.roast-modal-content h3 {
    color: var(--color-2);
    margin-bottom: 1.5rem;
    font-size: 1.3rem;
    font-weight: 400;
}

.roast-characteristics {
    display: grid;
    gap: 1.5rem;
    margin-top: 1.5rem;
}

.roast-char {
    padding: 1rem;
    background-color: var(--gray-light);
    border-left: 4px solid var(--color-2);
    border-radius: 4px;
}

.roast-char h4 {
    color: var(--color-1);
    margin-bottom: 0.5rem;
    font-size: 1.1rem;
}

.roast-char p {
    color: var(--color-6);
    line-height: 1.6;
}

/* Roast Type Section (for product detail page) */
.roast-type-section {
    margin: 2rem 0;
    padding: 1.5rem;
    background-color: var(--gray-light);
    border-radius: 8px;
    border: 1px solid var(--gray-medium);
}

.roast-type-section h3 {
    color: var(--color-1);
    margin-bottom: 1rem;
    font-size: 1.5rem;
}

.roast-type-detail h4 {
    color: var(--color-2);
    font-size: 1.2rem;
    margin-bottom: 1rem;
}

.roast-english {
    color: var(--gray-dark);
    font-weight: 400;
    font-size: 1rem;
}

.roast-characteristics-detail {
    display: grid;
    gap: 1rem;
    margin-top: 1rem;
}

.roast-char-item {
    padding: 1rem;
    background-color: var(--white);
    border-left: 3px solid var(--color-3);
    border-radius: 4px;
    line-height: 1.6;
}

.roast-char-item strong {
    color: var(--color-1);
    display: block;
    margin-bottom: 0.3rem;
}

/* Responsive adjustments for roast info */
@media (max-width: 768px) {
    .roast-modal-content {
        margin: 10% 5%;
        padding: 1.5rem;
    }

    .roast-modal-content h2 {
        font-size: 1.5rem;
    }

    .roast-modal-content h3 {
        font-size: 1.1rem;
    }

    .roast-type-section {
        padding: 1rem;
    }
}

/* Promotion Banner */
.promotion-banner {
    background: linear-gradient(135deg, var(--color-5), #e89850);
    color: var(--white);
    padding: 1rem 1.5rem;
    border-radius: 8px;
    margin-bottom: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    box-shadow: 0 4px 15px rgba(209, 125, 61, 0.3);
    font-size: 1.1rem;
    font-weight: 600;
    text-align: center;
    animation: pulse 2s infinite;
}

.promotion-banner i {
    font-size: 1.5rem;
    animation: bounce 2s infinite;
}

@keyframes pulse {
    0%, 100% {
        transform: scale(1);
    }
    50% {
        transform: scale(1.02);
    }
}

@keyframes bounce {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-5px);
    }
}

@media (max-width: 768px) {
    .promotion-banner {
        font-size: 0.95rem;
        padding: 0.75rem 1rem;
    }

    .promotion-banner i {
        font-size: 1.2rem;
    }
}
/* Floating Alert */
.floating-alert {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    max-width: 350px;
    background: linear-gradient(135deg, var(--color-5), #e89850);
    color: var(--white);
    padding: 1.25rem;
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(209, 125, 61, 0.4);
    z-index: 998;
    opacity: 0;
    transform: translateX(400px);
    transition: all 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
    display: flex;
    align-items: flex-start;
    gap: 1rem;
}

.floating-alert.show {
    opacity: 1;
    transform: translateX(0);
}

.floating-alert-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background: rgba(255, 255, 255, 0.3);
    border: none;
    color: var(--white);
    font-size: 1.5rem;
    line-height: 1;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    cursor: pointer;
    transition: var(--transition);
    display: flex;
    align-items: center;
    justify-content: center;
}

.floating-alert-close:hover {
    background: rgba(255, 255, 255, 0.5);
    transform: rotate(90deg);
}

.floating-alert-icon {
    font-size: 2rem;
    animation: float 3s ease-in-out infinite;
    flex-shrink: 0;
}

.floating-alert-text {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.5;
    padding-right: 1.5rem;
}

@keyframes float {
    0%, 100% {
        transform: translateY(0px);
    }
    50% {
        transform: translateY(-10px);
    }
}

@media (max-width: 768px) {
    .floating-alert {
        bottom: 1rem;
        right: 1rem;
        left: 1rem;
        max-width: calc(100% - 2rem);
    }

    .floating-alert-text {
        font-size: 0.9rem;
    }

    .floating-alert-icon {
        font-size: 1.5rem;
    }
}
/* ═══════════════════════════════════════════════════════════
   BOTÓN VOLVER ARRIBA
   Antes se inyectaba desde main.js con style.cssText, que gana a cualquier
   regla CSS por especificidad inline. Ahora es una clase de verdad.
   ═══════════════════════════════════════════════════════════ */

.back-to-top {
    position: fixed;
    z-index: 990;
    inset-block-end: clamp(1rem, 3vh, 2rem);
    inset-inline-end: clamp(1rem, 3vw, 2rem);
    width: 48px;
    height: 48px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 50%;
    background: var(--color-1);
    color: var(--white);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px) scale(.9);
    transition:
        opacity    var(--dur-base) var(--ease-out),
        transform  var(--dur-base) var(--ease-spring),
        visibility 0s linear var(--dur-base);
}

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .back-to-top {
        background: color-mix(in srgb, var(--color-1) 78%, transparent);
        -webkit-backdrop-filter: blur(var(--glass-blur-soft)) saturate(150%);
                backdrop-filter: blur(var(--glass-blur-soft)) saturate(150%);
    }
}

.back-to-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}

.back-to-top:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px); }

/* El toast promocional vive en las mismas coordenadas: colisionaban. */
body:has(.floating-alert.show) .back-to-top { transform: translateY(-140px); }
body:has(.floating-alert.show) .back-to-top:hover { transform: translateY(-142px); }

/* ═══════════════════════════════════════════════════════════
   TRANSICIONES ENTRE PÁGINAS
   Mejora progresiva pura: donde no hay soporte (Firefox hoy) no hace nada,
   ni siquiera un error. Es navegación multipágina de Django, así que esto
   sustituye al parpadeo blanco entre páginas sin una línea de JS.
   ═══════════════════════════════════════════════════════════ */
@view-transition { navigation: auto; }

/* Sin nombre propio, la píldora entraría en el snapshot de la raíz y haría
   cross-fade en CADA navegación: parecería que parpadea. Con nombre se anima
   por separado y, al ser idéntica en todas las páginas, se queda quieta. */
.nav { view-transition-name: nav; }

::view-transition-old(root) { animation: vt-out 140ms var(--ease-in-out) both; }
::view-transition-new(root) { animation: vt-in  240ms var(--ease-out) both; }
@keyframes vt-out { to   { opacity: 0; } }
@keyframes vt-in  { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) { animation: none !important; }
}

/* ═══════════════════════════════════════════════════════════
   PREFERENCIAS DEL SISTEMA
   Al final del archivo a propósito: gana por orden de fuente.
   ═══════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    html { scroll-behavior: auto; }

    .js [data-aos],
    .js [data-stagger] > * {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
        clip-path: none !important;
        transition-delay: 0s !important;
    }

    /* Los tres bucles infinitos que el sitio corría sin condición. */
    .sale-badge,
    .promotion-banner,
    .promotion-banner i,
    .floating-alert-icon { animation: none !important; }
}

/* Quien activa "reducir transparencia" en iOS/macOS normalmente lo necesita. */
@media (prefers-reduced-transparency: reduce) {
    .glass,
    .nav-pill,
    .glass-card,
    .glass-btn,
    .glass-badge {
        -webkit-backdrop-filter: none !important;
                backdrop-filter: none !important;
        background-color: rgba(250, 252, 249, 0.98) !important;
    }
    .glass::after { display: none; }
    .nav-sheet {
        background: rgba(250, 252, 249, 0.99) !important;
        -webkit-backdrop-filter: none !important;
                backdrop-filter: none !important;
    }
    .glass-badge--dark   { background-color: var(--green-800) !important; }
    .glass-badge--warm   { background-color: var(--sienna-600) !important; }
    .glass-btn--onmedia  { background-color: rgba(20, 63, 24, 0.92) !important; }
}

@media (prefers-contrast: more) {
    :root {
        --glass-border-color: rgba(20, 63, 24, 0.45);
        --glass-bg:  rgba(250, 252, 249, 0.92);
        --text-muted: #3c4741;
        --hairline:   rgba(23, 32, 26, 0.28);
    }
}

@media print {
    [data-aos],
    [data-stagger] > * {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
    }
}
