/* ==========================================================================
   assets/css/front.css - Tienda de cervezas artesanales y mezcales
   ========================================================================== */

/* Paleta tomada del logo de la marca (productosyidentidad/logoheader.svg).
   El manual maneja dos familias:
     · Verde petróleo  → #274d5b (oscuro), #3f6c7e (medio), #4e8691 (claro)
     · Ámbar / fuego   → #d46112 (rojo), #e6710a, #ef7d00, #f6a118, #fcbe0e
   El petróleo se usa para las superficies de marca (cabecera, pie) y el ámbar
   para la acción (botones, precios, acentos). */
:root {
    /* --- Marca: petróleo --- */
    --brand-deep: #1d3a45;   /* derivado de #274d5b, para fondos */
    --brand-dark: #274d5b;
    --brand: #3f6c7e;
    --brand-light: #4e8691;

    /* --- Marca: ámbar / fuego --- */
    --brand-red: #d46112;
    --brand-flame: #e6710a;
    --brand-orange: #ef7d00;
    --brand-amber: #f6a118;
    --brand-gold: #fcbe0e;

    /* --- Tokens de interfaz ---
       Se mantienen los nombres existentes para no tocar las vistas, pero ahora
       apuntan a los colores del manual.
       El cuerpo de acción usa #b8500c (derivado del #d46112 del logo) porque el
       naranja puro con texto blanco solo alcanza 3.1:1 de contraste, por debajo
       del mínimo accesible de 4.5:1. Este tono llega a 5.0:1. */
    --color-primary: #b8500c;
    --color-primary-dark: #9c3f06;
    --color-accent: var(--brand-amber);

    /* Texto cálido sobre superficies claras */
    --color-dark: #1c1917;
    --color-body: #44403c;
    --color-muted: #78716c;

    --color-border: #e7e5e4;
    --color-bg: #fafaf9;
    --color-bg-alt: #f5f5f4;
    --color-success: #16a34a;
    --color-danger: #dc2626;

    --radius: 12px;
    --radius-sm: 8px;

    /* ------------------------------------------------------------------
       SISTEMA DE RADIOS — unificado
       ------------------------------------------------------------------
       Antes había 5, 6, 10, 12, 999 y 3 px conviviendo: la tarjeta de producto
       medía 3px, la de categoría 12, el buscador 10 y los botones del banner
       999 (pastilla). Sin un criterio, la interfaz se lee como parches.

       Criterio de la dirección industrial: ESQUINA FIRME. Un objeto de
       destilería no es una pastilla. Los tres radios útiles son:
         · --radius-xs   2px  filetes, chips pequeños, marcas de esquina
         · --radius-card 4px  tarjetas y superficies
         · --radius-ctl  6px  controles (botones, inputs, selects)
       El círculo (50%) y la pastilla se reservan para lo que de verdad es
       circular (avatares, puntos) o para el control segmentado de cantidad. */
    --radius-xs: 2px;
    --radius-card: 4px;
    --radius-ctl: 6px;

    /* Altura de control unificada: botones, inputs y selects al mismo alto.
       La cabecera ya usaba este recurso (`--header-alto-fila`); ahora es un
       criterio de todo el sitio y no una excepción de la barra. */
    --control-h: 42px;
    --control-h-sm: 36px;

    /* Tonos de apoyo derivados del ámbar de la marca, para fondos sutiles
       (avisos, campos activos, etiquetas) que no deben competir con el color
       de acción. */
    --brand-tint: #fdf6ee;        /* fondo cálido muy claro */
    --brand-tint-soft: #fcecd9;   /* fondo ámbar claro */
    --brand-tint-strong: #f9ddb6; /* ámbar claro marcado */
    --brand-ink: #8a3e08;         /* texto oscuro de marca sobre los tints */

    --shadow-sm: 0 1px 3px rgba(28, 25, 23, .08);
    --shadow: 0 4px 16px rgba(28, 25, 23, .10);
    --shadow-lg: 0 12px 32px rgba(28, 25, 23, .14);

    /* ------------------------------------------------------------------
       DIRECCIÓN VISUAL: industrial / destilería
       ------------------------------------------------------------------
       La paleta NO se toca: petróleo + ámbar vienen del manual de marca, están
       verificados en contraste y el logo exige fondo oscuro. Lo que cambia es
       la VOZ tipográfica y el tratamiento de superficies, que es donde el
       catálogo se veía genérico.

       Regla de la dirección: «rótulo de destilería».
         · Titulares  → Oswald (condensada, en mayúsculas, con tracking).
         · Datos      → IBM Plex Mono (graduación, volumen, precios).
         · Texto      → Oswald/Plex de apoyo; nada de system-ui en titulares.

       Las pilas incluyen reserva por si el CDN de Google Fonts no responde:
       la página no depende de la red para ser legible. */

    /* Titulares: condensada de rótulo. La reserva usa las serifas que ya
       existían (Georgia y compañía) para no quedarse en un sans genérico.
       El tema (`helpers/theme.php`) reescribe esta pila, así que la reserva
       tiene que ir DENTRO del valor de `--font-display`. */
    --font-display: "Oswald", "Haettenschweiler", "Arial Narrow", Georgia, "Times New Roman", serif;

    /* Datos técnicos y precios: monoespaciada, lectura de ficha de producto. */
    --font-mono: "IBM Plex Mono", "Consolas", "Liberation Mono", monospace;

    /* Cuerpo: se mantiene la pila del sistema, que es la más legible en texto
       largo y no cuesta una petición extra. */
    --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    /* Ritmo tipográfico. Se define una escala explícita en lugar de dejar que
       cada componente improvise su tamaño: es lo que hace que la interfaz se
       lea como un sistema y no como una acumulación de parches. */
    --tracking-label: .14em;   /* etiquetas y rótulos en mayúsculas */
    --tracking-tight: -.01em;  /* titulares grandes */

    --space-1: .25rem;
    --space-2: .5rem;
    --space-3: .75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;

    --rule: 1px solid var(--color-border);       /* filete fino, aire de plano */
    --rule-strong: 2px solid var(--color-dark);  /* filete grueso, énfasis */

    /* Transiciones unificadas: el movimiento debe sentirse de una pieza. */
    --ease-out: cubic-bezier(.22, .61, .36, 1);
    --dur-fast: .15s;
    --dur: .25s;
    --dur-slow: .4s;

    /* ------------------------------------------------------------------
       ATMÓSFERA
       ------------------------------------------------------------------
       Ambas guías coinciden en lo mismo: un fondo plano y vacío es lo que
       hace que una tienda parezca una plantilla. Se resuelve con una textura
       generada con CSS (sin imágenes que descargar) en lugar de un color
       liso.

       El «grano» es un SVG en línea codificado como data-URI: pesa ~200 bytes,
       no pide red y no se puede romper por una imagen que falte. Se mantiene
       en opacidades muy bajas (2-4 %) porque el objetivo es dar materia a la
       superficie, no ensuciar el texto.

       La trama es de líneas diagonales a 45°, el mismo motivo que ya usa el
       banner de respaldo. Repetir el motivo es lo que convierte una decisión
       en un sistema. */
    --grano: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.35'/%3E%3C/svg%3E");
    --trama: repeating-linear-gradient(135deg,
        rgba(29, 58, 69, .045) 0 1px,
        transparent 1px 12px);
    /* Malla de degradado para superficies destacadas (petróleo muy diluido). */
    --malla: radial-gradient(120% 90% at 12% 0%,
        rgba(63, 108, 126, .10) 0%,
        transparent 58%);
}

/* ---------- Base ---------- */
body {
    font-family: var(--font-body);
    color: var(--color-body);
    /* Fondo con atmósfera: la trama diagonal sobre el color base. Antes era un
       blanco roto plano, que es justo lo que hace que todo se vea como una
       plantilla. La textura es sutil a propósito: se percibe, no se lee. */
    background-color: var(--color-bg);
    background-image: var(--trama);
    background-attachment: fixed;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Jerarquía de titulares unificada. Antes cada sección elegía su fuente, así que
   la página no tenía una voz única. Con esto, cualquier titular nuevo ya nace
   dentro del sistema sin tocar CSS. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    color: var(--color-dark);
    letter-spacing: var(--tracking-tight);
}

.site-main { flex: 1; }

/* ---------- Barra de progreso de lectura ----------
   Marca cuánto queda de la ficha. Se pinta solo en la ficha de producto (lo
   decide `wrapper.php`): en el catálogo no aporta y añade ruido.

   Va `fixed` justo debajo de la cabecera, que es `sticky`, así que acompaña
   durante todo el recorrido. La posición la fija `front.js` midiendo la altura
   real de la cabecera, porque esa altura cambia con el ancho de pantalla (la
   barra superior se pliega en móvil).

   La barra se mueve con `transform: scaleX` (lo hace GSAP), NO con `width`: el
   ancho obligaría a recalcular la maquetación en cada fotograma y da tirones.
   Por eso el elemento interior mide el 100 % y se escala. */
.scroll-progress {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    height: 3px;
    z-index: 1029;            /* por debajo de la cabecera, que usa 1030 */
    pointer-events: none;     /* es decorativa: no debe interceptar clics */
    background: transparent;
    /* `hidden` recorta la barra interior mientras está escalada a 0, para que no
       asome un filo de 1px por el redondeo del subpíxel. */
    overflow: hidden;
}

.scroll-progress-bar {
    height: 100%;
    width: 100%;
    /* ⚠️ El degradado necesita `background-size` MAYOR que el elemento para que
       `background-position` tenga recorrido. Sin esto, con un degradado a
       `auto`, mover la posición NO hace nada (el degradado ya llena el ancho
       completo): el efecto se vería congelado.
       Con el 200 % de ancho, desplazar la posición de 0 % a 100 % recorre los
       tonos de un extremo al otro. */
    background: linear-gradient(90deg, var(--brand-flame), var(--brand-gold), var(--brand-flame));
    background-size: 200% 100%;
    transform: scaleX(0);
    transform-origin: left center;
    /* Avisa al navegador de que esto va a animarse, para que lo suba a su propia
       capa y no repinte el resto. Se limita a este elemento: abusar de
       `will-change` consume memoria. */
    will-change: transform;
}

/* Sin JavaScript la barra se queda en `scaleX(0)`, o sea invisible. Es lo
   correcto: es orientación, no contenido. Nada depende de ella. */

a { color: var(--color-primary); text-decoration: none; }
a:hover { color: var(--color-primary-dark); }

.btn-primary {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
    font-family: var(--font-display);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: .88rem;
    /* Radio del sistema, no el de Bootstrap: el botón de acción debe tener la
       misma esquina firme que el resto de controles de la tienda. */
    border-radius: var(--radius-ctl);
}
.btn-primary:hover, .btn-primary:focus {
    background-color: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
}
.btn-outline-primary {
    color: var(--color-primary);
    border-color: var(--color-primary);
    font-family: var(--font-display);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: .88rem;
    border-radius: var(--radius-ctl);
}
.btn-outline-primary:hover {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
}
.page-link { color: var(--color-primary); }
.page-item.active .page-link {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
}

/* ==========================================================================
   CAPA DE CONTROLES
   ==========================================================================
   `front.css` NO definía ni un solo estilo de formulario: los inputs, selects
   y áreas de texto eran Bootstrap puro (radio 6px, alto variable). Eso es lo
   que hacía que el checkout y la cuenta se vieran «de otro sitio» respecto a
   la tienda.

   Aquí se unifican alto, radio, borde y foco con el sistema. El FOCO se
   resuelve con `box-shadow` y no con `outline` para que no desplace nada, y
   lleva el ámbar de marca: sobre fondo claro, `#b8500c` (5.01:1) es el que
   pasa AA como indicador. */

.form-control,
.form-select {
    min-height: var(--control-h);
    border-radius: var(--radius-ctl);
    border-color: var(--color-border);
    font-size: .92rem;
    color: var(--color-dark);
}
.form-control::placeholder { color: var(--color-muted); }

.form-control:focus,
.form-select:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(184, 80, 12, .16);
}

/* Etiquetas de formulario: mismo rotulo en monoespaciada que el resto de datos
   del sitio, para que el checkout no parezca otra aplicación. */
.form-label {
    font-family: var(--font-mono);
    font-size: .74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--brand);
    margin-bottom: var(--space-2);
}

/* Casillas y radios: el color de marca en lugar del azul por defecto. */
.form-check-input:checked {
    background-color: var(--color-primary);
    border-color: var(--color-primary);
}
.form-check-input:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(184, 80, 12, .16);
}

/* ---- Paginación: cuadrada y firme ---- */
.pagination { gap: 2px; }
.page-link {
    min-width: var(--control-h-sm);
    height: var(--control-h-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-xs) !important;
    font-family: var(--font-mono);
    font-size: .84rem;
}

/* ---------- Barra superior ----------
   Va encima de la cabecera petróleo, así que se usa un tono más profundo
   para que se distingan sin romper la unidad de color. */
.topbar {
    background: #142b34;
    color: rgba(255, 255, 255, .88);
    font-size: .8rem;
    letter-spacing: .01em;
}
.topbar i { color: var(--brand-gold); }

/* En móvil se pliega al bajar. La transición es sobre `max-height` y no sobre
   `height` porque la altura real del texto cambia con el ancho de pantalla:
   animar un valor fijo daría un salto en cuanto cambiara el número de líneas. */
@media (max-width: 991.98px) {
    .topbar {
        overflow: hidden;
        max-height: 60px;
        transition: max-height .3s ease, opacity .25s ease, padding .3s ease;
    }

    /* `is-collapsed` la pone header-scroll.js */
    .topbar.is-collapsed {
        max-height: 0;
        opacity: 0;
        padding-top: 0 !important;
        padding-bottom: 0 !important;
    }
}

/* ---------- Cabecera ----------
   Fondo petróleo de la marca: el logotipo trae el nombre en blanco y el
   emblema en tonos petróleo/ámbar, así que está diseñado para fondo oscuro.
   Sobre blanco el texto desaparecería.

   REDISEÑO: se quitó el borde inferior (la sombra ya separa la cabecera del
   contenido) y se unificó la ALTURA de todo lo que va en la fila. Antes el
   buscador medía 38px, el carrito 40 y la cuenta 42: tres alturas distintas en
   la misma línea, que es lo que hacía que se viera descuadrada. */
.site-header {
    --header-alto-fila: 42px;   /* una sola altura para buscador, cuenta y carrito */
    --header-radio: 10px;       /* un solo radio para todos los elementos */

    background: linear-gradient(180deg, var(--brand-dark) 0%, var(--brand-deep) 100%);
    position: sticky;
    top: 0;
    z-index: 1030;
    box-shadow: 0 2px 12px rgba(29, 58, 69, .28);
    transition: box-shadow .3s ease, background .3s ease;
}

.site-header .navbar {
    padding-top: .6rem;
    padding-bottom: .6rem;
    /* La altura de la barra la mandan los elementos de dentro, y todos miden
       `--header-alto-fila`, así que no hace falta fijarla a mano. */
    gap: .5rem;
}

/* ---- Estado compacto al bajar ----
   La clase la pone header-scroll.js.

   ⚠️ EL ALTO NO CAMBIA. ESTA ES LA CLAVE DE TODO EL ASUNTO.

   Antes, `is-compact` reducía los paddings del navbar y el alto del logo: la
   cabecera pasaba de 75px a 54px. Pero es `position: sticky`, así que OCUPA
   ESPACIO EN EL FLUJO: al encoger, todo el contenido de debajo sube 21px y el
   navegador reajusta el scroll. Resultado: la página daba un salto cada vez que
   se cruzaba el umbral, y al ir y venir el gesto se realimentaba («baja y sube
   muy rápido»).

   Medido antes de arreglarlo, al cambiar de sabor: la cabecera pasaba por las
   alturas 52, 64, 65, 66, 67…75 mientras el scroll oscilaba en bucle.

   Con el alto fijo, compactar SOLO cambia cosas que no ocupan espacio:
   la sombra y la escala del logo (`transform`, que no provoca reflujo). El
   efecto se sigue viendo, pero nada se mueve de sitio. */
.site-header.is-compact {
    box-shadow: 0 6px 22px rgba(15, 30, 36, .38);
}

/* Se mantiene el mismo padding que en estado normal: es lo que fija el alto */
.site-header.is-compact .navbar {
    padding-top: .6rem;
    padding-bottom: .6rem;
}

.site-header.is-compact .navbar-nav .nav-link {
    padding-top: .5rem;
    padding-bottom: .5rem;
}

/* El logo se encoge con `transform` (escala), que NO altera la maquetación */
.site-header.is-compact .brand-logo {
    --logo-escala: .74;   /* 46px * .74 ≈ 34px, el alto de antes */
}

/* El navbar solo anima la sombra: su padding NO cambia, porque eso alteraría
   el alto de la cabecera y con él la posición del contenido. */
.site-header .navbar {
    transition: box-shadow .3s ease;
}

/* El logo se encoge con `transform` (escala) en lugar de con `height`: el
   resultado visual es el mismo pero no altera la maquetación ni el scroll.
   Se usa una variable para poder ajustarlo desde el estado compacto. */
.brand-logo {
    height: 46px;
    width: auto;
    display: block;
    transform: scale(var(--logo-escala, 1));
    transition: transform .3s ease;
}

/* El contenedor del logo reserva siempre el alto grande, para que la cabecera
   no encoja aunque el logo se encoja. */
.navbar-brand {
    min-height: 46px;
    display: flex;
    align-items: center;
}

/* ⚠️ Se anima `--logo-escala` y no `transform` directamente: si se pusiera
   `transform: scale(1.05)` aquí, PISARÍA la escala del estado compacto y el logo
   daría un salto de tamaño al pasar el ratón en la cabecera compacta. */
.navbar-brand:hover .brand-logo {
    --logo-escala: 1.05;
}

.navbar-brand:focus-visible {
    outline: 2px solid var(--brand-gold);
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}

/* ---- Enlaces del menú: subrayado que crece desde el centro ----
   Se usa un pseudo-elemento y no `border-bottom` para poder animarlo sin que el
   alto del enlace cambie (con border, el texto saltaría al pasar el ratón). */
.site-header .navbar-nav .nav-link {
    position: relative;
    font-weight: 500;
    font-size: .92rem;
    color: rgba(255, 255, 255, .82);
    padding: .5rem .9rem;
    transition: color .2s ease;
}

.site-header .navbar-nav .nav-link::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: .15rem;
    width: 0;
    height: 2px;
    border-radius: 2px;
    background: var(--brand-gold);
    transform: translateX(-50%);
    transition: width .25s cubic-bezier(.4, 0, .2, 1);
}

.site-header .navbar-nav .nav-link:hover,
.site-header .navbar-nav .nav-link.active {
    color: #fff;
    /* Sin fondo: el subrayado ya marca, y una caja por enlace era justo lo que
       hacía que el menú se viera cargado. */
    background: transparent;
}

.site-header .navbar-nav .nav-link:hover::after,
.site-header .navbar-nav .nav-link.active::after {
    width: calc(100% - 1.8rem);
}

/* El enlace al sitio principal es una salida, no una sección: se distingue con
   el icono y no lleva subrayado, para que no compita con la navegación real. */
.site-header .nav-link--externo {
    color: rgba(255, 255, 255, .62);
}

.site-header .nav-link--externo i {
    font-size: .68em;
    margin-left: .3rem;
    opacity: .7;
}

.site-header .nav-link--externo::after {
    display: none;
}

.site-header .nav-link--externo:hover {
    color: #fff;
}

/* El botón hamburguesa necesita contraste sobre el fondo oscuro */
.site-header .navbar-toggler {
    border: 0;
    padding: .4rem .55rem;
    border-radius: var(--header-radio);
    transition: background .2s ease;
}

.site-header .navbar-toggler:hover {
    background: rgba(255, 255, 255, .10);
}

.site-header .navbar-toggler-icon {
    filter: invert(1) brightness(1.8);
    width: 1.3em;
    height: 1.3em;
}

.site-header .navbar-toggler:focus-visible {
    box-shadow: 0 0 0 .2rem rgba(252, 190, 14, .45);
    outline: none;
}

/* En móvil y tablet el menú se despliega dentro de la cabecera.
   Como los enlaces son blancos, el panel necesita fondo de marca propio:
   sin él quedaría texto blanco sobre el fondo claro de la página (invisible).
   La entrada se anima a mano (Bootstrap no anima el colapso de una barra). */
@media (max-width: 991.98px) {
    .site-header .navbar-collapse {
        background: var(--brand-dark);
        margin-top: .6rem;
        padding: .5rem .75rem 1rem;
        border-radius: var(--header-radio);
        border: 1px solid rgba(255, 255, 255, .10);
        max-height: calc(100vh - 150px);
        overflow-y: auto;
        /* Animación propia de apertura */
        animation: navPanelIn .22s ease both;
    }

    @keyframes navPanelIn {
        from { opacity: 0; transform: translateY(-8px); }
        to   { opacity: 1; transform: none; }
    }

    .site-header .navbar-collapse .nav-link {
        padding: .7rem .75rem;
    }

    /* Subrayado fuera en móvil: aquí los enlaces se pulsan, no se señalan */
    .site-header .navbar-collapse .nav-link::after {
        display: none;
    }

    .site-header .navbar-collapse .nav-link.active {
        background: rgba(255, 255, 255, .12);
        border-radius: var(--radius-sm);
    }

    .site-header .navbar-collapse .dropdown-menu {
        background: rgba(255, 255, 255, .06);
        border: none;
        box-shadow: none;
        padding: .25rem 0;
    }
    .site-header .navbar-collapse .dropdown-item {
        color: rgba(255, 255, 255, .82);
        padding: .45rem .75rem;
    }
    .site-header .navbar-collapse .dropdown-item:hover,
    .site-header .navbar-collapse .dropdown-item:focus {
        background: rgba(255, 255, 255, .12);
        color: #fff;
    }
    .site-header .navbar-collapse .dropdown-item i { color: var(--brand-gold); }
    .site-header .navbar-collapse .dropdown-divider {
        border-color: rgba(255, 255, 255, .14);
    }
}

/* ---------- Buscador ---------- */

/* Se abandona el `input-group` de Bootstrap: sus dos piezas traían radios y
   bordes distintos entre sí (6px arriba, borde solo por un lado) y no había
   forma de que casaran con los botones. Ahora es una sola caja con el icono
   dentro. */
.header-search {
    width: 230px;
    transition: width .3s cubic-bezier(.4, 0, .2, 1);
}

.search-field {
    position: relative;
    display: flex;
    align-items: center;
    height: var(--header-alto-fila, 42px);
    background: rgba(255, 255, 255, .10);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: var(--header-radio, 10px);
    transition: background .2s ease, border-color .2s ease, box-shadow .2s ease;
}

.search-field i {
    position: absolute;
    left: .7rem;
    font-size: .88rem;
    color: rgba(255, 255, 255, .60);
    pointer-events: none;
    transition: color .2s ease;
}

.search-field input {
    width: 100%;
    height: 100%;
    padding: .5rem .75rem .5rem 2.15rem;
    background: transparent;
    border: 0;
    outline: none;
    font-size: .88rem;
    color: #fff;
}

.search-field input::placeholder {
    color: rgba(255, 255, 255, .55);
}

/* Al enfocar, la caja se aclara y se ensancha (el ensanchado lo hace el
   contenedor .header-search, que es quien tiene el ancho). */
.search-field:focus-within {
    background: rgba(255, 255, 255, .18);
    border-color: var(--brand-gold);
    box-shadow: 0 0 0 .2rem rgba(252, 190, 14, .25);
}

.search-field:focus-within i {
    color: var(--brand-gold);
}

.header-search:focus-within {
    width: 290px;
}

/* ---------- Botones de cuenta y carrito ---------- */

/* Una sola receta para los dos: misma altura, mismo radio, misma transición.
   Antes el carrito no tenía borde, la cuenta sí, y las alturas no coincidían. */
.site-header .btn-account,
.site-header .btn-cart {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: var(--header-alto-fila);
    padding: 0 1rem;
    font-size: .9rem;
    font-weight: 600;
    border-radius: var(--header-radio);
    border: 1px solid transparent;
    white-space: nowrap;
    transition: background .2s ease, border-color .2s ease, transform .15s ease;
}

.site-header .btn-account {
    background: rgba(255, 255, 255, .10);
    border-color: rgba(255, 255, 255, .20);
    color: #fff;
}

.site-header .btn-account:hover,
.site-header .btn-account:focus,
.site-header .btn-account.show {
    background: rgba(255, 255, 255, .20);
    border-color: rgba(255, 255, 255, .38);
    color: #fff;
}

/* El carrito es la única llamada a la acción de la cabecera, así que es el
   único con color pleno. */
.site-header .btn-cart {
    background: var(--color-primary);
    color: #fff;
    margin-left: .5rem;
}

.site-header .btn-cart:hover {
    background: var(--color-primary-dark);
    color: #fff;
}

/* Los dos se hunden un poco al pulsarlos: es la respuesta que confirma que el
   toque llegó, antes de que la página cambie. */
.site-header .btn-account:active,
.site-header .btn-cart:active {
    transform: scale(.96);
}

.site-header .btn-account:focus-visible,
.site-header .btn-cart:focus-visible {
    outline: none;
    box-shadow: 0 0 0 .2rem rgba(252, 190, 14, .45);
}

/* La flecha del desplegable la dibuja Bootstrap con currentColor (sale blanca
   sola). Se anula su margen para que el espaciado lo controle el `gap`. */
.site-header .btn-account.dropdown-toggle::after {
    margin-left: .35rem;
}

/* ---------- Acciones de móvil (lupa y carrito) ----------
   Van en la barra, a la derecha del logo, y no dentro del desplegable: buscar y
   ver el carrito son acciones de primer nivel, y esconderlas tras la
   hamburguesa obliga a un paso de más justo cuando se acaba de agregar algo. */
.header-actions-mobile {
    display: flex;
    align-items: center;
    gap: .4rem;
}

/* En móvil los botones del desplegable van en fila al final y ocupan todo el
   ancho: son las acciones, y apuntarles desde una fila estrecha es incómodo. */
@media (max-width: 991.98px) {
    .site-header .navbar-collapse .btn-account,
    .site-header .navbar-collapse .btn-cart {
        width: 100%;
        margin: .35rem 0 0;
    }

    .site-header .navbar-collapse .dropdown {
        width: 100%;
    }
}

/* ---------- Botón de icono suelto (la lupa en móvil) ---------- */
.site-header .btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--header-alto-fila);
    height: var(--header-alto-fila);
    flex: 0 0 auto;
    padding: 0;
    background: rgba(255, 255, 255, .10);
    border: 1px solid rgba(255, 255, 255, .20);
    border-radius: var(--header-radio);
    color: #fff;
    font-size: 1rem;
    transition: background .2s ease, transform .15s ease;
}

.site-header .btn-icon:hover {
    background: rgba(255, 255, 255, .20);
    color: #fff;
}

.site-header .btn-icon:active {
    transform: scale(.94);
}

.site-header .btn-icon:focus-visible {
    outline: none;
    box-shadow: 0 0 0 .2rem rgba(252, 190, 14, .45);
}

/* Modificador del carrito de móvil.
   ⚠️ Va DESPUÉS de la base `.btn-icon`: con la misma especificidad (0,2,0) gana
   la regla que aparece más tarde en el archivo. Definido antes, el fondo
   translúcido de la base pisaba el color de acción y el carrito salía sin
   destacar. El carrito es la única llamada a la acción de la barra. */
.site-header .btn-icon--cart {
    position: relative;
    background: var(--color-primary);
    border-color: var(--color-primary);
}

.site-header .btn-icon--cart:hover {
    background: var(--color-primary-dark);
    border-color: var(--color-primary-dark);
}

/* ---------- Insignia del carrito ---------- */

.cart-badge {
    position: absolute;
    top: -7px;
    right: -7px;
    background: var(--brand-gold);
    color: var(--brand-deep);
    font-size: .68rem;
    font-weight: 700;
    min-width: 20px;
    height: 20px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
    /* Anillo del color de la cabecera: separa la insignia del botón naranja
       sin necesidad de un borde duro. */
    box-shadow: 0 0 0 2px var(--brand-deep);
}

/* El botón del carrito necesita ser el ancla de la insignia */
.site-header .btn-cart {
    position: relative;
}

/* Hueco del icono del carrito. Existe para poder girar el dibujo: Bootstrap
   Icons pinta el símbolo en un pseudo-elemento ::before, así que rotar el <i>
   no lo movería. Girando este contenedor, sí.

   SIN `will-change: transform`: se probó y crea una capa de composición en la
   que la rotación de una animación corta no llega a pintarse (el elemento se
   quedaba inamovible). Para medio segundo de gesto, dejar que el navegador
   decida es más seguro que prometerle una capa. */
.site-header .btn-cart-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

/* Balanceo del carrito al agregar algo.
   Es el respaldo para cuando GSAP no está disponible (CDN caído): cart.js usa
   GSAP si puede y esta clase si no. Cubre los dos carritos: el de escritorio
   (.btn-cart) y el de móvil (.btn-icon--cart). */
.site-header .btn-cart.is-shaking .btn-cart-icon,
.site-header .btn-icon--cart.is-shaking .btn-cart-icon {
    animation: cartShake .7s ease;
}

@keyframes cartShake {
    0%, 100% { transform: rotate(0); }
    15%      { transform: rotate(-14deg); }
    30%      { transform: rotate(12deg); }
    45%      { transform: rotate(-9deg); }
    60%      { transform: rotate(6deg); }
    80%      { transform: rotate(-3deg); }
}

/* Entrada de la cabecera y la barra superior al cargar la página.
   Solo la primera vez: `both` mantiene el estado inicial hasta que arranca,
   así no se ve un parpadeo de «ya pintado y luego animado». */
.topbar {
    animation: headerDropIn .45s ease both;
}

.site-header {
    animation: headerDropIn .5s ease .05s both;
}

@keyframes headerDropIn {
    from { opacity: 0; transform: translateY(-100%); }
    to   { opacity: 1; transform: none; }
}

/* ---------- Capa de búsqueda (móvil) ---------- */

.search-layer {
    position: fixed;
    inset: 0;
    z-index: 1090;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 1rem;
    padding-top: 12vh;
    background: rgba(20, 43, 52, .96);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    animation: searchLayerIn .2s ease both;
}

@keyframes searchLayerIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.search-layer[hidden] {
    display: none;
}

.search-layer-inner {
    position: relative;
    width: 100%;
    max-width: 520px;
    animation: searchBoxIn .26s cubic-bezier(.2, .9, .3, 1.1) both;
}

@keyframes searchBoxIn {
    from { opacity: 0; transform: translateY(-12px) scale(.98); }
    to   { opacity: 1; transform: none; }
}

/* Dentro de la capa la caja es grande y clara: aquí el buscador es el
   protagonista, al contrario que en la barra. */
.search-layer .search-field {
    height: 56px;
    background: #fff;
    border-color: transparent;
}

.search-layer .search-field input {
    color: var(--color-dark);
    font-size: 1.05rem;
    padding-left: 2.6rem;
}

.search-layer .search-field input::placeholder {
    color: var(--color-muted);
}

.search-layer .search-field i {
    color: var(--color-muted);
    left: .9rem;
    font-size: 1.05rem;
}

.search-layer-close {
    position: absolute;
    top: -3rem;
    right: 0;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, .12);
    border: 1px solid rgba(255, 255, 255, .22);
    border-radius: 50%;
    color: #fff;
    transition: background .2s ease;
}

.search-layer-close:hover {
    background: rgba(255, 255, 255, .24);
}

.search-layer-hint {
    margin: .9rem 0 0;
    text-align: center;
    font-size: .82rem;
    color: rgba(255, 255, 255, .62);
}

/* ==================== CUENTA DEL CLIENTE ==================== */

/* Encabezado de la página de cuenta.
   Antes era un h1 y un párrafo sueltos sobre el fondo, sin punto de anclaje
   visual: la página se veía plana y sin relación con la tienda. Ahora lleva el
   petróleo de la cabecera y el icono en un disco, así entrar a la cuenta se
   siente parte de la misma casa. */
.account-hero {
    position: relative;
    text-align: center;
    padding: 2.5rem 1.5rem 2.25rem;
    margin-bottom: 1.75rem;
    border-radius: var(--radius);
    background: linear-gradient(135deg, var(--brand-deep) 0%, var(--brand-dark) 55%, var(--brand) 100%);
    color: #fff;
    box-shadow: var(--shadow);
    overflow: hidden;
}

/* Halo dorado tenue en la esquina: da profundidad sin cargar la vista */
.account-hero::after {
    content: "";
    position: absolute;
    top: -60%;
    right: -12%;
    width: 320px;
    height: 320px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(252, 190, 14, .22) 0%, transparent 70%);
    pointer-events: none;
}

.account-hero-icon {
    width: 62px;
    height: 62px;
    margin: 0 auto .9rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(255, 255, 255, .14);
    border: 1px solid rgba(255, 255, 255, .22);
    font-size: 1.6rem;
    color: var(--brand-gold);
}

.account-hero h1 {
    position: relative;
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3.4vw, 1.9rem);
    margin-bottom: .5rem;
}

.account-hero p {
    position: relative;
    max-width: 52ch;
    margin: 0 auto;
    color: rgba(255, 255, 255, .82);
    font-size: .95rem;
}

.account-intro p { max-width: 560px; margin-inline: auto; }

/* Lista de beneficios: el motivo por el que conviene tener cuenta. Sin esto, un
   formulario de registro solo parece un trámite. */
.account-benefit-list li {
    display: flex;
    gap: .75rem;
    padding: .65rem 0;
    border-bottom: 1px solid var(--color-border);
}
.account-benefit-list li:last-child { border-bottom: none; }

.account-benefit-list i {
    flex: 0 0 auto;
    font-size: 1.15rem;
    color: var(--brand-orange);
    margin-top: .1rem;
}
.account-benefit-list strong { display: block; font-size: .9rem; }
.account-benefit-list span { font-size: .82rem; color: var(--color-muted); }

.account-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    flex-wrap: wrap;
}

.account-stat { text-align: center; }
.account-stat .card-body { padding: 1rem .75rem; }
.account-stat-value {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--brand-dark);
    line-height: 1.2;
}
.account-stat-label {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-muted);
}

/* Fila de pedido dentro del panel: número a la izquierda, total a la derecha */
.account-order-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    padding: .6rem 0;
    border-bottom: 1px solid var(--color-border);
}
.account-order-row:last-child { border-bottom: none; }

/* ---------- Aviso de cuenta en el checkout ----------
   Azul suave cuando el cliente ya entró (información) y ámbar de marca cuando
   es una invitación para invitados. En ningún caso bloquea el formulario. */
.checkout-account-note {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    padding: .7rem .9rem;
    margin-bottom: 1rem;
    font-size: .87rem;
    color: var(--brand-ink);
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: var(--radius-sm);
}

.checkout-account-note i {
    font-size: 1.05rem;
    color: var(--brand-orange);
    flex: 0 0 auto;
}

.checkout-account-note.is-logged {
    color: #14532d;
    background: #f0fdf4;
    border-color: #bbf7d0;
}
.checkout-account-note.is-logged i { color: #16a34a; }

/* ---------- Invitación a crear cuenta tras comprar ---------- */
.post-purchase-account {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 1.5rem;
    padding: 1rem 1.1rem;
    background: linear-gradient(135deg, var(--brand-tint) 0%, var(--brand-tint-soft) 100%);
    border: 1px solid var(--brand-tint-strong);
    border-radius: var(--radius);
}

.post-purchase-account-icon {
    flex: 0 0 auto;
    width: 46px;
    height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: #fff;
    color: var(--brand-orange);
    font-size: 1.3rem;
}

.post-purchase-account-body { flex: 1 1 auto; }
.post-purchase-account-body h2 { color: var(--brand-ink); }

.post-purchase-account-actions {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .25rem;
}

@media (max-width: 767.98px) {
    .post-purchase-account {
        flex-direction: column;
        text-align: center;
    }
    .post-purchase-account-actions { width: 100%; }
    .post-purchase-account-actions .btn-primary { width: 100%; }
}

.cart-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    background: var(--brand-gold);
    color: var(--brand-deep);
    font-size: .68rem;
    font-weight: 700;
    min-width: 20px;
    height: 20px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 5px;
}

/* Desplegables sobre la cabecera oscura */
.site-header .dropdown-menu {
    border-color: var(--color-border);
    box-shadow: var(--shadow);
    border-radius: var(--radius-sm);
}
.site-header .dropdown-item {
    padding: .5rem .9rem;
    border-radius: 6px;
    margin: 0 .25rem;
    width: auto;
}
.site-header .dropdown-item:hover,
.site-header .dropdown-item:focus {
    background: #eef4f6;
    color: var(--brand-dark);
}
.site-header .dropdown-item i { color: var(--brand); }

/* ---------- Banner principal ---------- */
.hero-banner { position: relative; color: #fff; }

/* Altura del banner según el dispositivo.
   Cada tramo se configura por separado desde el admin (Banners → Altura por
   dispositivo). Si un tramo no tiene valor propio, el modelo lo rellena con el
   del tramo mayor cercano, así que `--banner-h-*` siempre llega definido.
   Se usa el ancho de la ventana como criterio, igual que los breakpoints del
   resto del sitio. */
.hero-swiper {
    height: var(--banner-h-desktop, var(--banner-height, 520px));

    /* Tope de seguridad: aunque se configure una altura muy grande, el banner
       nunca debe superar la pantalla del dispositivo. Se aplica solo en las
       pantallas pequeñas (abajo), para no recortar el banner del inicio en
       un monitor de escritorio. */
}

@media (max-width: 1199.98px) {
    .hero-swiper {
        height: var(--banner-h-laptop, var(--banner-height, 520px));
        max-height: 90vh;
    }
}

@media (max-width: 991.98px) {
    .hero-swiper {
        height: var(--banner-h-tablet, var(--banner-height, 520px));
        max-height: 85vh;
    }
}

@media (max-width: 767.98px) {
    .hero-swiper {
        height: var(--banner-h-mobile, var(--banner-height, 520px));
        max-height: 75vh;
    }
}

.hero-slide { position: relative; overflow: hidden; }

.hero-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    /* Sobreescala para el paralaje: al desplazarse la imagen hacia abajo, sin
       este margen aparecería una franja vacía por el borde superior.
       ⚠️ Se usa la propiedad `scale` SUELTA, no `transform: scale()`: GSAP
       anima `transform` en esta misma imagen para el paralaje y, si la escala
       fuera parte de `transform`, GSAP la reescribiría al inicializar y el
       margen desaparecería. Son dos propiedades independientes que se componen,
       así que no se pelean. */
    scale: 1.08;
}

.hero-overlay {
    position: absolute;
    inset: 0;
}

.hero-content {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    z-index: 2;
}
.hero-content--left  { justify-content: flex-start; text-align: left; }
.hero-content--center { justify-content: center; text-align: center; }
.hero-content--right { justify-content: flex-end; text-align: right; }

.hero-content .container { max-width: 780px; }

.hero-title {
    font-family: var(--font-display);
    font-size: clamp(1.9rem, 5vw, 3.4rem);
    font-weight: 700;
    line-height: 1.1;
    margin-bottom: .8rem;
    text-shadow: 0 2px 16px rgba(0, 0, 0, .35);
}

.hero-subtitle {
    font-size: clamp(1rem, 2vw, 1.25rem);
    margin-bottom: 1.6rem;
    opacity: .95;
    text-shadow: 0 1px 8px rgba(0, 0, 0, .3);
}

.hero-btn {
    font-family: var(--font-display);
    font-weight: 600;
    padding: .75rem 1.75rem;
    /* Era 999px (pastilla). Se pasa al radio de control del sistema: un botón
       de esquina firme es lo coherente con la dirección industrial, y de paso
       deja de parecer un botón de SaaS genérico. */
    border-radius: var(--radius-ctl);
    border: 2px solid transparent;
    text-transform: uppercase;
    letter-spacing: .06em;
    font-size: .92rem;
}
.hero-btn--primary { background: var(--color-primary); color: #fff; }
.hero-btn--primary:hover { background: var(--color-primary-dark); color: #fff; }
.hero-btn--light { background: #fff; color: var(--color-dark); }
.hero-btn--light:hover { background: #f5f5f4; }
.hero-btn--dark { background: var(--color-dark); color: #fff; }
.hero-btn--outline { background: transparent; color: #fff; border-color: #fff; }
.hero-btn--outline:hover { background: #fff; color: var(--color-dark); }

.hero-nav {
    color: #fff;
    background: rgba(0, 0, 0, .35);
    width: 46px;
    height: 46px;
    border-radius: 50%;
    backdrop-filter: blur(4px);
}
.hero-nav::after { font-size: 1.1rem; font-weight: 700; }
.hero-nav:hover { background: rgba(0, 0, 0, .6); }

.hero-dots .swiper-pagination-bullet {
    background: #fff;
    opacity: .6;
    width: 9px;
    height: 9px;
}
.hero-dots .swiper-pagination-bullet-active {
    opacity: 1;
    background: var(--color-primary);
    width: 26px;
    border-radius: 5px;
}

/* Banner alternativo sin slides */
.hero-fallback {
    background: linear-gradient(135deg, var(--brand-deep) 0%, var(--brand-dark) 55%, var(--brand-red) 100%);
    color: #fff;
    padding: 5rem 0;
}
.hero-fallback-title {
    font-family: var(--font-display);
    font-size: clamp(2rem, 5vw, 3.2rem);
    font-weight: 700;
}
.hero-fallback-subtitle {
    font-size: 1.15rem;
    opacity: .9;
    max-width: 620px;
    margin: 0 auto;
}

/* ---------- Banner en cabeceras de sección ----------
   El mismo componente del inicio, pero más bajo: en las páginas de catálogo y
   categoría el banner presenta la sección, no debe ocupar toda la pantalla. */
.hero-banner--compact .hero-title--compact {
    font-size: clamp(1.5rem, 3.4vw, 2.3rem);
}
.hero-banner--compact .hero-subtitle {
    font-size: clamp(.95rem, 1.6vw, 1.1rem);
    margin-bottom: 1.1rem;
}
.hero-banner--compact .hero-btn {
    padding: .6rem 1.4rem;
    font-size: .95rem;
}

/* Cabecera de sección cuando esa ubicación no tiene banner propio.
   Mantiene la identidad de marca para que la página no quede sin título.

   Se le añade un TRAMA de líneas diagonales muy tenue: da atmósfera sin tocar
   un solo color de marca y sin imágenes que descargar (la dirección pide
   superficies con textura, no fondos planos vacíos). */
.hero-banner--fallback {
    background:
        repeating-linear-gradient(135deg,
            rgba(255, 255, 255, .03) 0 1px,
            transparent 1px 11px),
        linear-gradient(135deg, var(--brand-deep) 0%,
            var(--brand-dark) 60%, var(--brand) 100%);
    color: #fff;
    min-height: var(--banner-height, 260px);
    display: flex;
    align-items: center;
}

/* Titular del banner: rótulo condensado.
   REGLA DE CAJA ALTA (deliberada, no accidental):
     · Llevan caja alta los TÍTULOS DE SECCIÓN (banner de catálogo, cabecera de
       categoría/marca): son rótulos, y en un rótulo la caja alta es lo natural.
     · NO la llevan los TÍTULOS FUNCIONALES de página (.page-title en carrito,
       checkout y cuenta): ahí el usuario está leyendo y operando, y un titular
       en mayúsculas sostenidas cansa y alarga el texto.
   Con `.page-title` fuera del grupo, las tres páginas de flujo mantienen caja
   normal sin renunciar a la tipografía de la dirección. */
.hero-fallback-heading,
.hero-title--compact {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: var(--tracking-tight);
    font-weight: 600;
}

/* Título funcional de página: mismo tipo, caja normal, un poco más de aire. */
.page-title {
    font-family: var(--font-display);
    letter-spacing: var(--tracking-tight);
    font-weight: 600;
}

.hero-fallback-inner {
    width: 100%;
    padding: 2rem 0;
}

/* ⚠️ BUG CORREGIDO: este titular salía CASI NEGRO sobre el fondo petróleo oscuro
   del banner, o sea prácticamente invisible.

   La causa: `.hero-banner--fallback` fijaba `color: #fff` en el <SECTION>, pero
   el encabezado hereda de una regla MÁS ESPECÍFICA — la global de encabezados,
   que declara `color: var(--color-dark)` — porque un color declarado gana sobre
   uno heredado. El blanco se quedaba a medio camino: el subtítulo y las migas sí
   lo tomaban, el titular no.

   Se detectó porque el dueño reportó que este título «se veía mal»; al medirlo
   en el navegador salió rgb(28, 25, 23) sobre un degradado que va de #1d3a45 a
   #3f6c7e: contraste 1.1:1 en el peor punto.

   El blanco da 5.74:1 en el peor punto, así que es el color correcto AQUÍ. NO se
   pone el naranja de marca: sobre este fondo daría 2.08:1 (2.8 veces peor que el
   blanco) y el titular se perdería. El naranja es para los fondos CLAROS.

   ⚠️ Este comentario va FUERA de la regla a propósito. Dentro, sus propias
   llaves rompen cualquier comprobación que use `[^}]*` para leer las
   declaraciones: es una trampa que costó dos diagnósticos. */
.hero-fallback-heading {
    font-family: var(--font-display);
    font-size: clamp(1.7rem, 4vw, 2.7rem);
    font-weight: 700;
    margin-bottom: .35rem;
    line-height: 1.15;
    color: #fff;
}

.hero-fallback-sub {
    font-size: clamp(.95rem, 1.8vw, 1.1rem);
    opacity: .88;
    margin-bottom: 0;
    max-width: 640px;
}

/* Migas de pan sobre el fondo oscuro del banner */
.breadcrumb-light {
    --bs-breadcrumb-divider-color: rgba(255, 255, 255, .5);
    margin-bottom: .85rem;
    font-size: .84rem;
}
.breadcrumb-light .breadcrumb-item,
.breadcrumb-light .breadcrumb-item a {
    color: rgba(255, 255, 255, .78);
    text-decoration: none;
}
.breadcrumb-light .breadcrumb-item a:hover { color: #fff; text-decoration: underline; }
.breadcrumb-light .breadcrumb-item.active { color: #fff; }
.breadcrumb-light .breadcrumb-item + .breadcrumb-item::before { color: rgba(255, 255, 255, .45); }

/* ---------- Secciones ---------- */
.section { padding: 3.5rem 0; }

/* RITMO DE LA PÁGINA.
   Antes todas las secciones tenían el mismo peso: mismo fondo, mismo aire,
   mismo encabezado. Eso es lo que hace que la home se lea como una lista
   larga en vez de como un recorrido.

   Ahora las bandas alternan: la sección con `.section-alt` se separa con una
   malla de degradado en lugar de un color plano, y lleva filetes arriba y
   abajo para que se lea como una franja y no como un cambio de color suelto. */
.section-alt {
    background-color: var(--color-bg-alt);
    background-image: var(--malla), var(--trama);
    border-top: var(--rule);
    border-bottom: var(--rule);
}

.section-header { margin-bottom: 1.75rem; }

/* Título de sección como RÓTULO DE CATÁLOGO.
   Antes era un titular grande y suelto. Ahora lleva una marca corta en ámbar
   delante (barra vertical), que es el recurso de las etiquetas de destilería y
   lo que da al ojo un punto de anclaje repetido.

   Se aplica en las páginas VIVAS («Opiniones de clientes» en el detalle, los
   títulos del carrito y la cuenta). La portada propia está retirada: su vista
   sigue en disco, pero `route=home` redirige al catálogo. */
.section-title {
    font-family: var(--font-display);
    font-size: clamp(1.25rem, 2.6vw, 1.7rem);
    font-weight: 600;
    /* ⚠️ Naranja de marca pedido por el dueño, igual que la barra y que el título
       del paquete.

       Se usa la VARIABLE `--brand-orange` (#ef7d00) y no el hex, porque ese valor
       se cambia desde Configuración → Colores; con el hex fijo, este título se
       quedaría anclado al naranja viejo mientras el resto de la tienda cambiaría.

       DATO MEDIDO (con la misma función de contraste que usa el sistema de temas):
         sobre tarjeta blanca ......... 2.76:1
         sobre el fondo del cuerpo .... 2.64:1
         sobre el fondo alterno ....... 2.53:1
       WCAG pide 3:1 para texto grande y 4.5:1 para texto normal. Este título va
       de 20 px (móvil) a 27 px (escritorio) con peso 600, así que en escritorio
       entra en «texto grande» pero se queda corto, y en móvil se aleja más.

       El dueño lo eligió a sabiendas: es el color de marca y unifica los títulos
       con la barra. Si algún día se quiere cumplir AA sin salir del naranja,
       `#d97200` da 3.03:1 en el peor fondo y es casi idéntico a la vista
       (mismo tono 32°, 4 puntos menos de luminosidad). */
    color: var(--brand-orange);
    margin-bottom: .25rem;
    text-transform: uppercase;
    letter-spacing: var(--tracking-tight);
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

/* Marca de sección: barra vertical. Puro CSS, sin iconos ni imágenes.
   Va del MISMO naranja que el texto: antes el texto era negro y la barra ámbar
   más oscura, así que había dos tonos en el mismo rótulo. */
.section-title::before {
    content: "";
    flex: 0 0 auto;
    width: 3px;
    height: 1.15em;
    background: var(--brand-orange);
}

/* Los iconos de Bootstrap que algunas secciones metían dentro del título se
   ocultan: con la barra ámbar ya hay una marca, y dos marcas seguidas se
   estorban. El `<i>` se deja en el marcado (no se rompe nada si se quiere
   recuperar), pero no se pinta. */
.section-title .bi { display: none; }

.section-subtitle {
    color: var(--color-muted);
    margin-bottom: 0;
    font-size: .95rem;
}

.link-view-all {
    color: var(--color-primary);
    font-weight: 600;
    font-size: .9rem;
    gap: .35rem;
    align-items: center;
}
.link-view-all:hover { gap: .6rem; }

.page-header-bar {
    background: linear-gradient(135deg, var(--brand-deep) 0%, var(--brand-dark) 60%, var(--brand) 100%);
    color: #fff;
    padding: 2.5rem 0 2rem;
}
.page-title {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 4vw, 2.2rem);
    font-weight: 700;
    margin-bottom: .25rem;
}
.page-subtitle { color: rgba(255, 255, 255, .82); margin-bottom: 0; }

.breadcrumb-nav { padding: 1rem 0 0; }
.breadcrumb { font-size: .85rem; margin-bottom: 0; }

/* ---------- Tarjetas de producto ----------
   ELEMENTO FIRMA de la dirección «industrial / destilería».

   En vez de rehacer el marcado, se apoya en lo que la tarjeta YA emite: marca,
   origen y atributos (graduación, volumen). Eso es, de hecho, una ficha técnica
   de producto, y es exactamente el lenguaje visual de una etiqueta de
   destilería: etiqueta pequeña en mayúsculas, filete fino y dato en
   monoespaciada.

   Se evitan a propósito las tres salidas fáciles que la dirección prohíbe:
   esquinas muy redondeadas, sombra flotante y elevación al pasar el ratón. Un
   objeto industrial no flota: se sostiene sobre una rejilla y reacciona con
   precisión. */
.product-card {
    background: #fff;
    border: 1px solid var(--color-border);
    /* Radio pequeño: el aire de destilería es de esquina firme, no de pastilla. */
    border-radius: 3px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}

.product-card:hover {
    /* 2px de subida en lugar de 4: un gesto medido. El énfasis lo lleva el
       filete inferior, no el desplazamiento. */
    transform: translateY(-2px);
    box-shadow: var(--shadow);
    border-color: var(--brand);
}

/* Filete de acento en la base al pasar el ratón. Es el «momento memorable»
   de la tarjeta: un trazo que se dibuja, no un salto ni un parpadeo.
   Se descartó el filete con la barra ámbar en los títulos de sección: en el
   catálogo hay una por producto, y repetir el mismo trazo decenas de veces
   dejaba de ser un acento para convertirse en ruido. */
.product-card::after {
    content: "";
    display: block;
    height: 2px;
    background: var(--brand-flame);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--dur-slow) var(--ease-out);
}
.product-card:hover::after { transform: scaleX(1); }

.product-card-link { display: block; color: inherit; flex: 1; }
.product-card-link:hover { color: inherit; }

.product-card-image {
    position: relative;
    /* ⚠️ CUADRADO (1/1), no 4/5.
       El 4:5 —que se puso en el rediseño «industrial» para dar protagonismo a
       la botella— recortaba el 20 % DEL ANCHO de las fotos. Con una botella
       centrada el recorte se come aire y no se nota, pero con las FOTOS DE
       PAQUETE (varias botellas en fila) cortaba las botellas de los extremos.
       Medido en el catálogo real: marco 264×330, foto cuadrada 600×600,
       fracción de ancho visible 0.80 → 20 % perdido.

       Las fotos de este catálogo son cuadradas (600×600 las cervezas,
       1000×1000 y 1599×1600 los paquetes), así que 1:1 las muestra ENTERAS.
       Para el ajuste fino sigue estando el panel de encuadre del admin. */
    aspect-ratio: 1 / 1;
    overflow: hidden;
    background: var(--color-bg-alt);
}

/* Filete inferior de la imagen: separa la fotografía de la ficha técnica,
   igual que la línea impresa de una etiqueta. */
.product-card-image::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: rgba(28, 25, 23, .3);
}
.product-card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .35s;
}

/* «Ver la foto completa»: la foto entra entera en el marco cuadrado.
   Es la opción para los PAQUETES, cuya foto trae varias botellas en fila y con
   `cover` perdía las de los extremos. Se cambia solo `object-fit`, que no
   afecta a la maquetación: el marco sigue siendo el mismo cuadrado para todas
   las tarjetas, así que la rejilla del catálogo no se descuadra.
   Las franjas que quedan arriba y abajo llevan el fondo del marco, no un color
   inventado. */
.product-card-image--contain img { object-fit: contain; }
/* Con «ver la foto completa», ampliar al pasar el ratón recortaría justo lo que
   se quiere mostrar, así que el gesto se reduce a un asentamiento leve.
   ⚠️ Va en la MISMA regla que el zoom normal y no en una aparte: con dos reglas
   separadas y la misma especificidad, la de abajo (la general) anularía a la
   del modo «completa». La clase del modo y el `:hover` viven juntos a
   propósito. */
.product-card:hover .product-card-image img { transform: scale(1.06); }
.product-card:hover .product-card-image--contain img { transform: scale(1.03); }

.product-image-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #d6d3d1;
    font-size: 2.5rem;
}

/* Etiquetas superpuestas sobre la imagen del producto (descuento y promoción).
   El contenedor las apila en columna, así que cualquier número de etiquetas
   se acomoda sin solaparse entre sí. */
.product-badges {
    position: absolute;
    top: .6rem;
    left: .6rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .3rem;
    z-index: 2;
    max-width: calc(100% - 1.2rem);
    pointer-events: none;
}

.badge-discount {
    background: var(--color-danger);
    color: #fff;
    font-size: .72rem;
    font-weight: 700;
    padding: .22rem .5rem;
    border-radius: 6px;
    text-transform: uppercase;
    letter-spacing: .03em;
    line-height: 1.2;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.badge-soldout {
    position: absolute;
    inset: 0;
    background: rgba(28, 25, 23, .6);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    letter-spacing: .05em;
    font-size: .95rem;
}

.product-card-body { padding: var(--space-4) var(--space-4) var(--space-2); }

/* Marca: rótulo de etiqueta. Mayúsculas pequeñas y tracking amplio, como el
   nombre del destilador impreso en el papel. */
.product-brand {
    font-family: var(--font-display);
    font-size: .68rem;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
    color: var(--brand);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.product-name {
    font-family: var(--font-display);
    font-size: 1.06rem;
    font-weight: 600;
    color: var(--color-dark);
    margin-bottom: var(--space-2);
    line-height: 1.15;
    letter-spacing: var(--tracking-tight);
    /* Mayúsculas: es la seña de identidad de la dirección. Un titular de
       catálogo en caja alta se lee como rótulo, no como párrafo. */
    text-transform: uppercase;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.3em;
}

.product-origin {
    font-family: var(--font-mono);
    font-size: .68rem;
    color: var(--color-muted);
    margin-bottom: var(--space-2);
    letter-spacing: .02em;
}

/* Atributos: la ficha técnica.
   Se pasan de «píldoras grises de radio 5px» a datos separados por filetes
   verticales. Es el cambio que más rompe el parecido con una plantilla
   genérica: un dato técnico no necesita fondo, necesita jerarquía y
   alineación. */
.product-attrs {
    display: flex;
    gap: 0;
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
    padding-top: var(--space-2);
    border-top: var(--rule);
}
.attr {
    font-family: var(--font-mono);
    font-size: .7rem;
    background: none;
    color: var(--color-dark);
    padding: 0;
    font-weight: 500;
    letter-spacing: .02em;
}
/* Filete separador SOLO entre datos, nunca al principio ni al final. */
.attr + .attr {
    margin-left: var(--space-3);
    padding-left: var(--space-3);
    border-left: var(--rule);
}
.attr i {
    color: var(--brand);
    margin-right: .2rem;
}

.product-price {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.price-old {
    font-family: var(--font-mono);
    font-size: .78rem;
    color: var(--color-muted);
    text-decoration: line-through;
}
/* El precio es el dato que decide la compra, así que va en monoespaciada y con
   más peso: dentro de una ficha técnica, el número importante se marca. */
.price-current {
    font-family: var(--font-mono);
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-dark);
    letter-spacing: -.02em;
}

.product-card-footer {
    padding: 0 .9rem .9rem;
    margin-top: auto;
}

/* Cantidad + agregar en la misma fila cuando caben. flex-wrap permite que el
   botón baje a una segunda línea por sí solo en tarjetas estrechas.
   Por qué con flex y no con media queries: la tarjeta mide 221 px tanto en 768
   como en 992 px, pero 266 en 1200 y 311 en 1440, y eso no depende solo del
   ancho de la ventana (influyen las columnas del grid y la barra de filtros).
   Con puntos de quiebre por viewport el botón quedaba en 84 px a 992 px y el
   texto de la animación bajaba a 6.6 px, ilegible. */
.card-buy-row {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: .4rem;
}

/* Cursor apuntando al botón, no al input: en una tarjeta estrecha el campo
   numérico es incómodo de enfocar y el cliente casi siempre usa + / −. */
.card-buy-row .qty-input { cursor: pointer; }

/* Al apilarse, el selector ocupa todo el ancho y reparte los botones */
.card-buy-row .qty-selector { flex: 0 0 auto; }

.btn-add-cart {
    /* flex-basis 120px con flex-grow: crece si hay sitio, y si no cabe junto al
       selector baja a la línea siguiente. */
    flex: 1 1 120px;
    min-width: 0;
    /* Contiene el hueco del icono y la animación superpuesta */
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    background: var(--color-dark);
    color: #fff;
    border: none;
    font-weight: 600;
    font-size: .85rem;
    padding: .55rem .8rem;
    border-radius: var(--radius-sm);
    transition: background .15s;
    white-space: nowrap;
}
.btn-add-cart:hover { background: var(--color-primary); color: #fff; }
.btn-add-cart:disabled { opacity: .6; }

/* ---- Foco de teclado en los controles de compra ----
   ⚠️ BUG DE ACCESIBILIDAD CORREGIDO: el botón «Agregar al carrito» no tenía
   ningún indicador de foco. Se detectó navegando con Tab (no con `.focus()`
   programático, que no dispara `:focus-visible`): al llegar al botón,
   `outline` era `none 0px` y `box-shadow` `none`, así que quien navega con
   teclado no tenía forma de saber dónde estaba.

   Se resuelve con `box-shadow` y no con `outline` para que el anillo se dibuje
   por fuera sin alterar la maquetación de la fila (el botón comparte fila con
   el selector de cantidad). El color es el ámbar de marca, que sobre el oscuro
   del botón y sobre el blanco de la tarjeta se ve en ambos casos. */
.btn-add-cart:focus-visible,
.btn-buy:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px #fff, 0 0 0 5px var(--color-primary);
}

/* La animación del icono vive en assets/css/add-to-cart-anim.css */
.btn-buy { position: relative; }

/* Selector compacto para las tarjetas (el normal mide 36+48+36 px) */
.qty-selector-sm .qty-btn { width: 30px; height: 38px; font-size: .85rem; }
.qty-selector-sm .qty-input { width: 38px; height: 38px; font-size: .9rem; }

/* Cuando el selector salta a su propia fila (tarjeta estrecha), se reparte el
   ancho completo: los botones + y − quedan cómodos de pulsar con el pulgar en
   lugar de apretados en una esquina. */
.card-buy-row .qty-selector:only-of-type { min-width: 96px; }

/* En pantallas pequeñas el botón ocupa el ancho completo de la fila */
@media (max-width: 575.98px) {
    .card-buy-row > .btn-add-cart { flex-basis: 100%; }
    .qty-selector-sm .qty-btn { width: 40px; }
    .btn-add-label { display: inline; }
}

/* ---------- Carrusel de productos (home) ---------- */
.products-swiper { padding-bottom: 2.5rem; }
.products-swiper .swiper-slide { height: auto; }
.products-swiper .product-card { height: 100%; }

.products-nav {
    color: var(--color-dark);
    background: #fff;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    box-shadow: var(--shadow);
    top: 42%;
}
.products-nav::after { font-size: .95rem; font-weight: 700; }
.products-nav:hover { background: var(--color-primary); color: #fff; }

.products-dots { bottom: 0; }
.products-dots .swiper-pagination-bullet { background: var(--color-muted); }
.products-dots .swiper-pagination-bullet-active { background: var(--color-primary); }

/* ---------- Categorías ----------
   La tarjeta de categoría es una SUPERFICIE, no una ficha de producto: así
   que puede permitirse algo más de presencia. Se unifica el radio con el
   sistema (4px, esquina firme) y se cambia la elevación por un gesto de
   filete, igual que en la tarjeta de producto. */
.category-card {
    display: block;
    background: #fff;
    border: var(--rule);
    border-radius: var(--radius-card);
    overflow: hidden;
    color: inherit;
    height: 100%;
    position: relative;
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out);
}
.category-card::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    height: 3px;
    width: 100%;
    background: var(--brand-flame);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--dur-slow) var(--ease-out);
}
.category-card:hover {
    border-color: var(--brand);
    box-shadow: var(--shadow);
    color: inherit;
}
.category-card:hover::after { transform: scaleX(1); }

.category-card-image {
    aspect-ratio: 4 / 3;
    background: var(--color-bg-alt);
    overflow: hidden;
}
.category-card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.category-card-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.5rem;
    color: var(--color-accent);
    background: linear-gradient(135deg, var(--brand-tint-soft) 0%, var(--brand-tint-strong) 100%);
}

.category-card-body { padding: var(--space-4); }
.category-card-body h3 {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    margin-bottom: .15rem;
    color: var(--color-dark);
    text-transform: uppercase;
    letter-spacing: var(--tracking-tight);
}
/* El contador de producto en monoespaciada, como el resto de datos del sitio. */
.category-count {
    font-family: var(--font-mono);
    font-size: .72rem;
    color: var(--color-muted);
}

/* ---------- Marcas ---------- */
.brands-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 1rem;
}

.brand-item {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    border: var(--rule);
    border-radius: var(--radius-card);
    padding: 1.25rem 1rem;
    min-height: 92px;
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out);
}
.brand-item:hover {
    border-color: var(--brand);
    box-shadow: var(--shadow-sm);
}
.brand-item img {
    max-width: 100%;
    max-height: 60px;
    object-fit: contain;
    filter: grayscale(1);
    opacity: .75;
    transition: filter .25s, opacity .25s;
}
.brand-item:hover img { filter: none; opacity: 1; }
.brand-name-text {
    font-weight: 600;
    color: var(--color-body);
    text-align: center;
    font-size: .9rem;
}

/* ---------- Compra mínima (home) ----------
   ⚠️ BANNER CORREGIDO.

   Antes era un degradado de naranja de acción a ámbar (`#b8500c` → `#f6a118`)
   con el texto en blanco. En el extremo ámbar, blanco sobre `#f6a118` da
   aproximadamente 2:1 de contraste: por debajo del mínimo AA de 4.5:1. El
   texto era ilegible en la mitad derecha, y con el degradado no se sabe dónde
   cae cada palabra.

   La solución es la de la propia marca: el PETRÓLEO es la superficie (que ya
   exige el logo) y el ámbar queda como acento. Así el banner pasa a ser una
   banda oscura premium, con contraste de sobra, y además crea el ritmo que
   faltaba al final de la página. */
.min-order-section { padding-top: 0; }

.min-order-banner {
    background-color: var(--brand-deep);
    background-image:
        radial-gradient(120% 140% at 88% 10%,
            rgba(252, 190, 14, .18) 0%,
            transparent 55%),
        var(--trama);
    color: #fff;
    border-radius: var(--radius-card);
    border-left: 4px solid var(--brand-gold);
    padding: 1.75rem;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    box-shadow: var(--shadow-lg);
}
.min-order-icon {
    font-size: 2.5rem;
    color: var(--brand-gold);
    line-height: 1;
}
.min-order-text { flex: 1; min-width: 240px; }
.min-order-text h3 {
    font-family: var(--font-display);
    font-size: 1.3rem;
    margin-bottom: .3rem;
    text-transform: uppercase;
    letter-spacing: var(--tracking-tight);
}
/* Texto corrido sobre petróleo: se sube la opacidad del cuerpo porque sobre
   `--brand-deep` el .95 anterior bajaba del mínimo en texto pequeño. */
.min-order-text p { color: rgba(255, 255, 255, .92); }
.min-order-text strong { color: var(--brand-gold); }
.min-order-action { flex-shrink: 0; }

.min-order-note {
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: var(--radius-sm);
    padding: .85rem 1rem;
    color: var(--brand-ink);
    display: flex;
    align-items: center;
    gap: .6rem;
}

/* ---------- Detalle de producto ---------- */
.product-gallery { position: sticky; top: 90px; }

.product-carousel { position: relative; }

.carousel-main {
    border-radius: var(--radius);
    overflow: hidden;
    background: #fff;
    border: 1px solid var(--color-border);
}

.carousel-image-wrapper {
    position: relative;
    aspect-ratio: 1 / 1;
    overflow: hidden;
}

.carousel-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ---------- Ajuste de encuadre por imagen (admin) ----------
   El formulario de producto permite ajustar cada foto con barras deslizables:
   la proporción del marco, el zoom y la posición del encuadre. El parcial
   `_carousel.php` emite las cuatro variables y aquí se aplican.

   Solo se aplica cuando la imagen TIENE ajuste (`data-has-fit`). Las imágenes
   sin ajuste no llevan ni el atributo ni las variables: se quedan con la
   proporción del tema y la foto centrada, exactamente como antes de existir
   esta función. Esa es la razón de separar «sin ajuste» (null en la base de
   datos) de «ajuste con los valores por defecto». */
.carousel-image-wrapper[data-has-fit] {
    /* ⚠️ La proporción se guarda como ALTO / ANCHO, que es como se piensa al
       ajustarla (subir el valor = marco más alto). `aspect-ratio` de CSS espera
       ANCHO / ALTO, de ahí la inversión: `1 / var(--fit-ratio)`.
       Con 1.33 (más alta) sale `1 / 1.33` = 0.75 de ancho/alto: al revés de lo
       que parece, pero es lo correcto. Confundir esta inversión hace que el
       control «más alta» produzca un marco más ancho. */
    aspect-ratio: 1 / var(--fit-ratio, 1);
}

.carousel-image-wrapper[data-has-fit] .carousel-image {
    transform: scale(var(--fit-zoom, 1));
    transform-origin: var(--fit-pos-x, 50%) var(--fit-pos-y, 50%);
}

/* ⚠️ El ajuste del administrador MANDA sobre el zoom decorativo del tema.
   Sin esto, en un carrusel de tipo «zoom» el `:hover` pisaría el transform del
   ajuste y al pasar el ratón la foto daría un salto al encuadre por defecto.
   El zoom decorativo se reescribe más abajo para multiplicarse en lugar de
   sustituir: ver `.product-carousel--zoom`. */

/* Con «ver la foto completa» en el detalle, la foto entra entera en el marco.
   Igual que en la tarjeta, se cambia solo `object-fit`: el marco conserva su
   tamaño, así que nada se descuadra. */
.product-carousel--fit-contain .carousel-image { object-fit: contain; }

/* Con movimiento reducido, el ajuste se ve igual pero sin transición. */
@media (prefers-reduced-motion: reduce) {
    .carousel-image-wrapper[data-has-fit] .carousel-image {
        transition: none;
    }
}

/* Tipo zoom: se amplía al pasar el cursor.
   Ajuste del administrador y zoom decorativo del tema se MULTIPLICAN.
   No se dejan como dos reglas separadas porque la del tema va después en la
   hoja y, con la misma especificidad, anularía la del ajuste: al pasar el ratón
   la foto daría un salto al encuadre por defecto.
   Con `--fit-zoom` a 1 por defecto, una imagen sin ajuste se comporta
   exactamente como antes.

   ⚠️ Las tres variantes del `:hover` van SEGUIDAS y de más específica a menos.
   Con la misma especificidad gana la última, así que si la de «foto completa»
   se pusiera antes que la general, la general la anularía y al pasar el ratón
   volvería a recortar lo que se acababa de dejar ver. */
.product-carousel--zoom .carousel-image { transition: transform .5s ease; }
.product-carousel--zoom.product-carousel--fit-contain .carousel-image-wrapper:hover .carousel-image {
    transform: scale(calc(var(--fit-zoom, 1) * 1.06));
}
.product-carousel--zoom .carousel-image-wrapper:hover .carousel-image {
    transform: scale(calc(var(--fit-zoom, 1) * 1.35));
}

.zoom-hint {
    position: absolute;
    bottom: .75rem;
    right: .75rem;
    background: rgba(28, 25, 23, .72);
    color: #fff;
    font-size: .72rem;
    padding: .3rem .6rem;
    border-radius: 6px;
    display: flex;
    align-items: center;
    gap: .3rem;
    pointer-events: none;
    backdrop-filter: blur(4px);
}

.carousel-nav {
    color: var(--color-dark);
    background: rgba(255, 255, 255, .92);
    width: 40px;
    height: 40px;
    border-radius: 50%;
    box-shadow: var(--shadow-sm);
}
.carousel-nav::after { font-size: .95rem; font-weight: 700; }
.carousel-nav:hover { background: #fff; }

.carousel-dots { bottom: .75rem; }
.carousel-dots .swiper-pagination-bullet { background: #fff; opacity: .6; }
.carousel-dots .swiper-pagination-bullet-active {
    background: var(--color-primary);
    opacity: 1;
    width: 22px;
    border-radius: 5px;
}

.carousel-badges {
    position: absolute;
    top: .75rem;
    left: .75rem;
    display: flex;
    flex-direction: column;
    gap: .35rem;
    z-index: 2;
}
.carousel-badge {
    color: #fff;
    font-size: .74rem;
    font-weight: 700;
    padding: .25rem .6rem;
    border-radius: 6px;
    align-self: flex-start;
    text-transform: uppercase;
    letter-spacing: .03em;
}

/* Miniaturas */
.carousel-thumbs .swiper-slide {
    width: 74px;
    height: 74px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    border: 2px solid var(--color-border);
    cursor: pointer;
    opacity: .6;
    transition: opacity .2s, border-color .2s;
}
.carousel-thumbs .swiper-slide-thumb-active {
    border-color: var(--color-primary);
    opacity: 1;
}
.thumb-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Información del producto */
.product-info-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: .6rem;
}

.product-brand-link {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .82rem;
    font-weight: 600;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
}
.brand-logo-sm { max-height: 22px; }

.product-title {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3.5vw, 2.1rem);
    font-weight: 700;
    color: var(--color-dark);
    line-height: 1.2;
    margin-bottom: .85rem;
}

.product-specs {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: 1rem;
}
/* Especificaciones del detalle: misma ficha técnica que la tarjeta
   (monoespaciada y esquina firme), para que la ficha se lea igual en la rejilla
   y en la página del producto. */
.spec-item {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    background: none;
    border: var(--rule);
    border-radius: var(--radius-xs);
    padding: .3rem .6rem;
    font-family: var(--font-mono);
    font-size: .74rem;
    color: var(--color-dark);
}
.spec-item i { color: var(--brand); }

.promo-badges-list {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: 1rem;
}
.promo-badge-item {
    background: var(--brand-tint-soft);
    color: var(--brand-ink);
    font-family: var(--font-mono);
    font-size: .72rem;
    font-weight: 600;
    padding: .28rem .55rem;
    border-radius: var(--radius-xs);
}

.product-price-box {
    display: flex;
    align-items: baseline;
    gap: .7rem;
    flex-wrap: wrap;
    padding: 1rem 0;
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: 1.25rem;
}
.price-old-lg {
    font-family: var(--font-mono);
    font-size: 1.1rem;
    color: var(--color-muted);
    text-decoration: line-through;
}
/* ⚠️ El precio del detalle usaba `--font-display` (George/Oswald) mientras la
   tarjeta de la rejilla usaba `--font-mono`: el mismo dato salía con dos
   tipografías distintas según la página. Se unifica en monoespaciada, que es
   la regla del sistema para los datos. */
.price-current-lg {
    font-family: var(--font-mono);
    font-size: 2rem;
    font-weight: 600;
    color: var(--color-dark);
    line-height: 1;
    letter-spacing: -.02em;
}
.price-save {
    background: #dcfce7;
    color: #166534;
    font-size: .78rem;
    font-weight: 600;
    padding: .25rem .6rem;
    border-radius: 6px;
}
.price-save-pct {
    opacity: .75;
    margin-left: .15rem;
}

.min-qty-notice {
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-left: 4px solid var(--color-accent);
    border-radius: var(--radius-sm);
    padding: .9rem 1rem;
    display: flex;
    gap: .75rem;
    align-items: flex-start;
    margin-bottom: 1.25rem;
    color: var(--brand-ink);
}
.min-qty-notice i { font-size: 1.25rem; color: var(--color-accent); }

.product-buy-form { margin-bottom: 1.5rem; }

.product-description {
    margin: 1.5rem 0;
    padding-top: 1.25rem;
    border-top: 1px solid var(--color-border);
    line-height: 1.7;
    color: var(--color-body);
}

.product-guarantees {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: .75rem;
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--color-border);
}
.guarantee-item {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .82rem;
    color: var(--color-muted);
}
.guarantee-item i { font-size: 1.15rem; color: var(--color-primary); }

/* ---------- Selector de cantidad ---------- */
.qty-selector {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: #fff;
}

.qty-btn {
    background: transparent;
    border: none;
    width: 36px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-body);
    font-size: .95rem;
    cursor: pointer;
    transition: background .15s;
}
.qty-btn:hover { background: var(--color-bg-alt); color: var(--color-primary); }
.qty-btn:active { background: var(--brand-tint-soft); }

/* ⚠️ ACCESIBILIDAD: el campo central del selector tampoco tenía indicador de
   foco (se detectó recorriendo la página con Tab). El `outline: none` de abajo
   se puso para quitar el anillo feo del navegador, pero no se sustituyó por
   nada: quien navega con teclado se perdía en el selector.
   Se repone en `:focus-visible`, que NO se dispara con el ratón, así que el
   clic sigue viéndose igual que antes. El fondo ámbar claro se mantiene para
   conservar la señal de «estoy editando esto». */
.qty-input:focus-visible {
    outline: none;
    background: var(--brand-tint);
    box-shadow: inset 0 0 0 2px var(--color-primary);
}

.qty-input {
    width: 48px;
    height: 38px;
    border: none;
    border-left: 1px solid var(--color-border);
    border-right: 1px solid var(--color-border);
    text-align: center;
    font-weight: 600;
    color: var(--color-dark);
    -moz-appearance: textfield;
}
.qty-input::-webkit-outer-spin-button,
.qty-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty-input:focus { outline: none; background: var(--brand-tint); }

.qty-selector-lg .qty-btn { width: 46px; height: 50px; font-size: 1.1rem; }
.qty-selector-lg .qty-input { width: 62px; height: 50px; font-size: 1.1rem; }

/* La fila de compra no se estira más de lo necesario: un botón que ocupara todo
   el ancho del contenedor (624 px en escritorio) quedaría desproporcionado
   frente al selector de cantidad. La animación no influye aquí, porque solo se
   reproduce dentro del hueco del icono y no cambia el tamaño del botón. */
.buy-row {
    display: flex;
    gap: .75rem;
    align-items: stretch;
    flex-wrap: wrap;
    max-width: 560px;
}

/* Ancho máximo por equilibrio visual con el selector de cantidad; 64 px de alto
   dan un objetivo táctil cómodo. El ancho es holgado para el texto «Agregar al
   carrito» (184 px) en todos los casos. */
.buy-row .btn-buy {
    flex: 1 1 auto;
    max-width: 380px;
    min-height: 64px;
    font-weight: 600;
}

.buy-hint {
    margin-top: .6rem;
    font-size: .85rem;
    color: var(--color-muted);
}

/* ---------- Arma tu paquete ---------- */
.pack-builder {
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: var(--shadow-sm);
}

/* ---------------------------------------------------------------------------
   ENCABEZADO DEL PAQUETE — el título manda, el progreso acompaña
   ---------------------------------------------------------------------------
   ⚠️ POR QUÉ CAMBIÓ (reporte del dueño: «ese título no es llamativo, no se nota»)

   Tenía tres problemas medidos, no supuestos:

   1. ERA EL TITULAR MÁS DÉBIL DE LA FICHA (21.6 px). «Opiniones de clientes»,
      que es una sección secundaria, medía 27.2 px. Un bloque de CONVERSIÓN
      (armar el paquete) no puede tener menos presencia que una de opiniones.

   2. NO USABA LA MARCA DEL SISTEMA. Todo rótulo del sitio lleva una barra ámbar
      vertical delante (`.section-title::before`); este no la tenía, así que no
      se leía como «otra sección del mismo catálogo» sino como un bloque suelto.

   3. COMPETÍA EN LA MISMA FILA CON EL PANEL DE PROGRESO.
      `justify-content: space-between` ponía título y progreso a la misma altura
      y con peso parecido, y el ojo no encontraba dónde anclar. **Esa era la
      causa real de que no se notara**, más que el tamaño.

   La solución NO es inventar un diseño nuevo: es aplicar el recurso que ya usa
   el resto de la tienda (dirección «rótulo de destilería»).
   --------------------------------------------------------------------------- */
.pack-builder-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1.25rem 2rem;
    flex-wrap: wrap;
    padding-bottom: 1.1rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--color-border);
}

/* El título ocupa su propia línea SIEMPRE: así el panel de progreso no puede
   subirse a su lado y robarle el anclaje al ojo. */
.pack-builder-heading { flex: 1 1 100%; }

.pack-builder-title {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-family: var(--font-display);
    /* Escala fluida como el resto de titulares del sitio, y con más peso que
       antes: 21.6 px → hasta 30 px. */
    font-size: clamp(1.5rem, 3.4vw, 1.9rem);
    font-weight: 700;
    line-height: 1.1;
    /* ⚠️ Naranja pedido por el dueño, a juego con la barra.
    
       Se usa la VARIABLE `--brand-orange` (#ef7d00) y no el hex, por la misma
       razón que en la barra: ese valor se cambia desde Configuración → Colores,
       y con el hex fijo el título se quedaría anclado al color viejo.
    
       DATO MEDIDO: #ef7d00 sobre el blanco de la tarjeta da **2.76:1**, por
       debajo del 3:1 que WCAG pide para texto grande (este título es de 30 px y
       pesa 700, así que le aplica el umbral de texto grande, no el de 4.5:1).
       El dueño lo eligió a sabiendas: el naranja es el color de marca y a este
       tamaño se lee. Si algún día se quiere cumplir AA sin salir del naranja,
       `#d97200` da 3.30:1 y es casi idéntico a la vista. */
    color: var(--brand-orange);
    text-transform: uppercase;
    letter-spacing: var(--tracking-tight);
    margin-bottom: .35rem;
}

/* Marca de sección: la misma barra vertical de `.section-title`, el recurso que
   da al ojo un punto de anclaje repetido en todo el catálogo.

   Va en `--brand-orange` (#ef7d00) y NO en `--brand-flame` (#e6710a) como el
   resto de barras del sitio: es la decisión del dueño para este bloque, que es
   el de más peso de la ficha. Al usar la VARIABLE y no el código hex, si algún
   día cambia el color de acción desde el panel, esta barra acompaña. */
.pack-builder-title::before {
    content: "";
    flex: 0 0 auto;
    width: 4px;
    height: 1.05em;
    background: var(--brand-orange);
}

/* El icono de la caja se retira del título: con la barra ámbar ya hay una marca,
   y dos marcas seguidas se estorban (mismo criterio que `.section-title .bi`). */
.pack-builder-title .bi { display: none; }

.pack-builder-subtitle {
    color: var(--color-muted);
    font-size: .95rem;
    /* Se alinea con el texto del título, no con la barra: así la barra queda
       como un filete que recorre el bloque, que es el efecto de rótulo. */
    padding-left: calc(4px + var(--space-3));
}

.pack-builder-progress {
    /* Ya no compite con el título: baja a su propia línea, a la derecha. */
    flex: 1 1 260px;
    max-width: 340px;
    min-width: 200px;
    margin-left: auto;
}
.progress-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .5rem;
    font-size: .85rem;
    margin-bottom: .35rem;
}

/* El contador de piezas: es el dato VIVO del bloque (cambia al seleccionar), así
   que se le da peso de cifra. Va en monoespaciada como el resto de datos
   técnicos del sitio (precios, graduación, volumen). */
.pack-count { display: inline-flex; align-items: baseline; gap: .35rem; }
.pack-count-value {
    font-family: var(--font-mono);
    font-size: 1.25rem;
    font-weight: 600;
    line-height: 1;
    color: var(--brand-dark);
    /* Ancho fijo por dígito: al cambiar de 0 a 12 no baila el texto de al lado. */
    font-variant-numeric: tabular-nums;
    min-width: 1.4ch;
    text-align: right;
}
.pack-count-label { color: var(--color-muted); }

/* Indicador de piezas SUGERIDAS.
   Se distingue del mínimo real a propósito: es una recomendación, no un
   requisito. Antes esto decía «mínimo 6» y se leía como una obligación. */
.pack-suggest-hint {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .12rem .5rem;
    font-size: .74rem;
    color: var(--brand-ink);
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: 999px;
    cursor: help;
}

.pack-suggest-hint i {
    color: var(--brand-orange);
    font-size: .8rem;
}

/* Línea informativa con el mínimo real de compra y lo que ya hay en el carrito */
.pack-hints {
    margin-top: .4rem;
    line-height: 1.35;
}
.pack-hints small { font-size: .74rem; }

.pack-grid { margin-bottom: 0; }

.pack-card {
    position: relative;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    height: 100%;
    display: flex;
    flex-direction: column;
    transition: border-color .2s, box-shadow .2s;
}
.pack-card:hover { border-color: var(--color-primary); }

.pack-card.is-selected {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(230, 113, 10, .18);
}

.pack-card.is-current { border-color: var(--color-accent); }

.pack-badge-current {
    position: absolute;
    top: .4rem;
    left: .4rem;
    background: var(--color-accent);
    color: #fff;
    font-size: .62rem;
    font-weight: 700;
    padding: .18rem .45rem;
    border-radius: 5px;
    z-index: 2;
    text-transform: uppercase;
    letter-spacing: .03em;
}

.pack-image {
    aspect-ratio: 1 / 1;
    overflow: hidden;
    background: var(--color-bg-alt);
}
.pack-image img { width: 100%; height: 100%; object-fit: cover; }
.pack-image-placeholder {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #d6d3d1;
    font-size: 1.75rem;
}

.pack-info {
    padding: .65rem .7rem .75rem;
    flex: 1;
    display: flex;
    flex-direction: column;
}

.pack-name {
    font-size: .84rem;
    font-weight: 600;
    color: var(--color-dark);
    line-height: 1.3;
    margin-bottom: .2rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 2.4em;
}

.pack-brand {
    font-size: .68rem;
    color: var(--color-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: .3rem;
}

.pack-meta {
    display: flex;
    align-items: baseline;
    gap: .35rem;
    margin-bottom: .5rem;
}
.pack-price { font-weight: 700; color: var(--color-dark); font-size: .95rem; }
.pack-price-old {
    font-size: .72rem;
    color: var(--color-muted);
    text-decoration: line-through;
}

.pack-out {
    font-size: .74rem;
    color: var(--color-danger);
    font-weight: 600;
    margin-top: auto;
}

.pack-min-hint {
    font-size: .66rem;
    color: var(--color-muted);
    margin-top: .3rem;
    text-align: center;
}

.pack-builder .qty-selector { width: 100%; margin-top: auto; }
.pack-builder .qty-btn { flex: 1; }
.pack-builder .qty-input { width: 44px; }

.pack-builder-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--color-border);
}

.pack-summary { font-size: .9rem; }
.pack-summary-line {
    display: flex;
    justify-content: space-between;
    gap: 1.5rem;
    min-width: 220px;
}
.pack-summary-line + .pack-summary-line { margin-top: .2rem; }
.pack-summary-line strong { color: var(--color-dark); }

.pack-actions { display: flex; gap: .6rem; flex-wrap: wrap; }

/* ---------- Filtros ---------- */
/* ---------- Filtros ----------
   Panel lateral con aire de índice de catálogo impreso: filete grueso bajo el
   título y etiquetas en monoespaciada, alineadas con la ficha de la tarjeta. */
.filters-sidebar {
    background: #fff;
    border: var(--rule);
    border-radius: 3px;
    padding: var(--space-5);
    position: sticky;
    top: 90px;
}

.filters-title {
    font-family: var(--font-display);
    font-size: .95rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: var(--rule-strong);
}

.filter-group { margin-bottom: var(--space-5); }

.filter-label {
    display: block;
    font-family: var(--font-mono);
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--brand);
    margin-bottom: var(--space-2);
}

.filter-options { display: flex; flex-direction: column; gap: .3rem; }

.filter-option {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .87rem;
    cursor: pointer;
    padding: .18rem 0;
}
.filter-option input {
    cursor: pointer;
    accent-color: var(--color-primary);
}

.active-filters {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .4rem;
}
.filter-chip {
    background: var(--brand-tint-soft);
    color: var(--brand-ink);
    font-family: var(--font-mono);
    font-size: .72rem;
    font-weight: 600;
    padding: .22rem .55rem;
    border-radius: var(--radius-xs);
}
.filter-clear {
    font-size: .78rem;
    color: var(--color-danger);
    font-weight: 600;
}

.subcategory-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.subcategory-chip {
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: .4rem .9rem;
    font-size: .85rem;
    color: var(--color-body);
    font-weight: 500;
    transition: all .18s;
}
.subcategory-chip:hover {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}

/* ---------- Código de descuento (carrito) ----------
   Va dentro del resumen, encima de los totales. Es un bloque discreto: el código
   es un extra, no debe competir con el botón de terminar la compra. */
.coupon-box {
    padding-bottom: var(--space-4);
    border-bottom: var(--rule);
}

.coupon-applied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: var(--radius-xs);
}

.coupon-applied-info {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
}

.coupon-applied-info i {
    font-size: 1.25rem;
    color: var(--brand-flame);
    flex-shrink: 0;
}

.coupon-applied-info strong {
    letter-spacing: .04em;
    color: var(--brand-ink);
}

/* El campo del código en monoespaciada: es un dato que se copia, no texto. */
.coupon-box .form-control {
    font-family: var(--font-mono);
    font-size: .85rem;
}

/* ---------- Carrito ---------- */
.cart-items { border-radius: var(--radius); overflow: hidden; }

.cart-item {
    display: grid;
    grid-template-columns: 80px 1fr auto auto auto;
    gap: 1rem;
    align-items: center;
    padding: 1rem 1.15rem;
    border-bottom: 1px solid var(--color-border);
}
.cart-item:last-child { border-bottom: none; }
.cart-item--warning { background: var(--brand-tint); }

.cart-item-image img,
.cart-image-placeholder {
    width: 80px;
    height: 80px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
}
.cart-image-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg-alt);
    color: #d6d3d1;
    font-size: 1.5rem;
}

.cart-item-name {
    font-size: .95rem;
    font-weight: 600;
    margin-bottom: .15rem;
    line-height: 1.3;
}
.cart-item-name a { color: var(--color-dark); }
.cart-item-name a:hover { color: var(--color-primary); }

.cart-item-brand {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-muted);
    margin-bottom: .2rem;
}

.cart-item-price { font-size: .82rem; color: var(--color-muted); }

.cart-item-alert {
    font-size: .74rem;
    color: var(--brand-ink);
    font-weight: 600;
    margin-top: .25rem;
}

.cart-item-promo {
    font-size: .74rem;
    color: var(--color-success);
    margin-top: .25rem;
    display: flex;
    align-items: center;
    gap: .3rem;
}

.cart-item-total { text-align: right; min-width: 78px; }
.line-old {
    display: block;
    font-size: .74rem;
    color: var(--color-muted);
    text-decoration: line-through;
}
.line-total { font-weight: 700; color: var(--color-dark); }

.btn-remove {
    background: transparent;
    border: none;
    color: var(--color-muted);
    font-size: 1.05rem;
    padding: .35rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color .15s, background .15s;
}
.btn-remove:hover { color: var(--color-danger); background: #fef2f2; }

/* Regalos */
.cart-gifts .gift-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem 0;
}
.gift-item-image img,
.gift-item-image i {
    width: 48px;
    height: 48px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f0fdf4;
    color: var(--color-success);
    font-size: 1.25rem;
}
.gift-item-image img { background: none; }

/* ==================== ELECCIÓN DE REGALO ====================
   El panel donde el cliente escoge su obsequio. La tarjeta se marca entera con
   el color de éxito porque todo lo que contiene es «esto es gratis»: verde en
   el borde y en el fondo tenue lo distingue de un producto de pago sin
   necesidad de explicarlo. */
.gift-picker {
    border: 1px solid #bbf7d0;
    background: linear-gradient(180deg, #f0fdf4 0%, #fff 60%);
}

.gift-picker .card-header { border-bottom-color: #dcfce7; }

.gift-picker-hint { margin-bottom: 0; }

.gift-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: .6rem;
}

/* La opción entera es el <label>: se puede pulsar en cualquier parte de la
   tarjeta y no solo en el círculo, que en móvil es un blanco muy pequeño. */
.gift-option {
    position: relative;
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .6rem .7rem;
    border: 2px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: #fff;
    cursor: pointer;
    transition: border-color .15s, background .15s, transform .15s;
}

.gift-option:hover {
    border-color: #86efac;
    background: #f7fee7;
}

.gift-option:has(input:focus-visible) {
    outline: 2px solid var(--color-success);
    outline-offset: 2px;
}

/* El círculo nativo se oculta pero SIGUE existiendo: es el que envía el dato y
   el que mantiene el comportamiento del teclado y lectores de pantalla. */
.gift-option input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    margin: 0;
    pointer-events: none;
}

.gift-option-image {
    flex: 0 0 48px;
    width: 48px;
    height: 48px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f0fdf4;
    color: var(--color-success);
    font-size: 1.25rem;
}

.gift-option-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.gift-option-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.gift-option-info strong {
    font-size: .88rem;
    color: var(--color-dark);
}

.gift-option-price {
    font-size: .78rem;
    color: var(--color-success);
    font-weight: 600;
}

/* Marcador de selección: un círculo a la derecha que se rellena al elegir. */
.gift-option-check {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: transparent;
    font-size: .8rem;
    transition: background .15s, border-color .15s, color .15s;
}

.gift-option:has(input:checked) {
    border-color: var(--color-success);
    background: #f0fdf4;
}

.gift-option:has(input:checked) .gift-option-check {
    background: var(--color-success);
    border-color: var(--color-success);
    color: #fff;
}

.gift-option.is-chosen {
    border-color: var(--color-success);
    background: #f0fdf4;
}

/* ==================== PROGRESO HACIA OTROS REGALOS ====================
   Los tramos que aún no se alcanzan. Gris y con candado a propósito: es una
   invitación, no un error, y no debe competir visualmente con el regalo que el
   cliente ya puede llevarse. */
.gift-progress {
    border: 1px dashed #e7e5e4;
    background: var(--color-bg-alt);
}

.gift-progress-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.gift-progress-list li {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .85rem;
    color: var(--color-muted);
}

.gift-progress-list li i { color: #a8a29e; }

.gift-progress-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gift-progress-need {
    flex: 0 0 auto;
    font-weight: 600;
    font-size: .78rem;
    color: var(--color-primary);
    background: #fff7ed;
    border-radius: 999px;
    padding: .1rem .55rem;
}

@media (max-width: 575.98px) {
    .gift-picker-grid { grid-template-columns: 1fr; }
}

/* Resumen del carrito.
   El sticky se aplica con la clase .is-sticky, que añade el JS solo cuando el
   bloque cabe entero en la pantalla. Así el aviso de edad viaja junto al
   resumen y no se le encima al hacer scroll, y en pantallas bajas el resumen
   se desplaza con la página en lugar de dejar contenido inalcanzable. */
.cart-summary-wrap,
.checkout-summary {
    position: static;
}

.is-sticky {
    position: sticky;
    top: 90px;
}

/* El resumen del carrito no debe superar la pantalla cuando está fijo */
.cart-summary-wrap.is-sticky { max-height: calc(100vh - 110px); overflow-y: auto; }

.checkout-summary.is-sticky { top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; }

/* La lista de artículos del checkout se acota para dejar sitio al total y al
   botón de confirmar. Con un tope más bajo el resumen cabe entero incluso en
   laptops de 768 px de alto, así que puede fijarse y el botón siempre se ve. */
.checkout-items {
    max-height: min(34vh, 300px);
    overflow-y: auto;
}

.summary-list { margin-bottom: 0; }
.summary-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: .45rem 0;
    font-size: .9rem;
}
.summary-row dt { font-weight: 400; color: var(--color-muted); margin-bottom: 0; }
.summary-row dd { margin-bottom: 0; font-weight: 600; color: var(--color-dark); }

.summary-row--discount dd { color: var(--color-success); }
.summary-row--gift dd { color: var(--color-success); }

.summary-row--total {
    border-top: 2px solid var(--color-border);
    margin-top: .6rem;
    padding-top: .85rem;
    font-size: 1.1rem;
}
.summary-row--total dt { font-weight: 700; color: var(--color-dark); }
.summary-row--total dd {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 700;
}

.btn-link-info {
    background: none;
    border: none;
    color: var(--color-muted);
    padding: 0 .2rem;
    font-size: .8rem;
    cursor: pointer;
}

.promo-detail-box {
    background: var(--color-bg-alt);
    border-radius: var(--radius-sm);
    padding: .65rem .8rem;
    margin: .35rem 0;
}
.promo-detail-item {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .8rem;
    padding: .18rem 0;
}

.secure-note {
    text-align: center;
    font-size: .78rem;
    color: var(--color-muted);
    margin-top: .85rem;
}

.free-shipping-hint {
    background: #f0fdf4;
    border: 1px solid #bbf7d0;
    border-radius: var(--radius-sm);
    padding: .85rem 1rem;
    color: #166534;
}

/* ---------- Checkout ---------- */
.checkout-card { border-radius: var(--radius); }

.step-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--color-primary);
    color: #fff;
    font-size: .72rem;
    font-weight: 700;
    margin-right: .4rem;
}

.checkout-item {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .55rem 0;
    border-bottom: 1px solid var(--color-border);
}
.checkout-item:last-child { border-bottom: none; }

.checkout-item-image {
    position: relative;
    width: 52px;
    height: 52px;
    flex-shrink: 0;
}
.checkout-item-image img,
.checkout-item-image > i {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg-alt);
    color: #d6d3d1;
}
.checkout-item-qty {
    position: absolute;
    top: -6px;
    right: -6px;
    background: var(--color-dark);
    color: #fff;
    font-size: .66rem;
    font-weight: 700;
    min-width: 19px;
    height: 19px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.checkout-item-info { flex: 1; min-width: 0; }
.checkout-item-name {
    font-size: .85rem;
    font-weight: 600;
    color: var(--color-dark);
    line-height: 1.3;
}
.checkout-item-price { font-weight: 600; font-size: .88rem; white-space: nowrap; }

.checkout-gifts {
    background: #f0fdf4;
    border-radius: var(--radius-sm);
    padding: .6rem .75rem;
    margin-top: .6rem;
}
.checkout-gift {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .82rem;
    color: #166534;
}

.shipping-notice {
    background: var(--color-bg-alt);
    border-radius: var(--radius-sm);
    padding: .85rem 1rem;
    display: flex;
    gap: .75rem;
    align-items: flex-start;
    font-size: .85rem;
}
.shipping-notice i { font-size: 1.2rem; color: var(--color-primary); }

/* ---------- Cotizador de envío ---------- */
.shipping-quoter {
    border-top: 1px solid var(--color-border);
    padding-top: 1.1rem;
}

.shipping-quoter-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    margin-bottom: .85rem;
    flex-wrap: wrap;
}
.shipping-quoter-head strong { font-size: .92rem; color: var(--color-dark); }

/* Cada opción de entrega es un radio con aspecto de tarjeta */
.shipping-option {
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .8rem .9rem;
    border: 2px solid var(--color-border);
    border-radius: var(--radius-sm);
    margin-bottom: .55rem;
    cursor: pointer;
    transition: border-color .15s, background .15s;
    background: #fff;
}
.shipping-option:hover { border-color: var(--color-primary); background: var(--brand-tint); }
.shipping-option.is-selected {
    border-color: var(--color-primary);
    background: var(--brand-tint);
}

/* El radio real se oculta: la tarjeta entera es clicable */
.shipping-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.shipping-option-icon {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg-alt);
    color: var(--color-primary);
    font-size: 1.05rem;
    flex-shrink: 0;
}
.shipping-option.is-selected .shipping-option-icon {
    background: var(--color-primary);
    color: #fff;
}

.shipping-option-body { flex: 1; min-width: 0; }
.shipping-option-name {
    font-weight: 600;
    font-size: .9rem;
    color: var(--color-dark);
    margin-bottom: .1rem;
}
.shipping-option-meta {
    font-size: .78rem;
    color: var(--color-muted);
}

.shipping-option-price {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--color-dark);
    white-space: nowrap;
}
.shipping-option-price.is-free { color: var(--color-success); }

/* Detalle de la bodega cuando el cliente elige recoger */
.shipping-pickup-detail {
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: var(--radius-sm);
    padding: .8rem .9rem;
    margin: -.1rem 0 .55rem;
    font-size: .82rem;
    color: var(--brand-ink);
}
.shipping-pickup-detail strong { display: block; margin-bottom: .15rem; }
.shipping-pickup-detail i { margin-right: .3rem; }

/* En la barra lateral, el envío elegido */
.summary-row--shipping-chosen dt { color: var(--color-body); }

@media (max-width: 575.98px) {
    .shipping-option { flex-wrap: wrap; }
    .shipping-option-price { width: 100%; text-align: right; }
}

.payment-pending-note {
    background: #eff6ff;
    border-radius: var(--radius-sm);
    padding: .7rem .85rem;
    margin-top: .85rem;
    color: #1e40af;
    display: flex;
    gap: .5rem;
    align-items: flex-start;
}

/* ---------- Confirmación de pedido ---------- */
.order-confirmation { max-width: 1000px; margin: 0 auto; }

.confirmation-header { margin-bottom: 1rem; }

.confirmation-icon {
    width: 76px;
    height: 76px;
    border-radius: 50%;
    background: #dcfce7;
    color: var(--color-success);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.4rem;
    margin: 0 auto 1rem;
}

.confirmation-title {
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 4vw, 2.2rem);
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: .4rem;
}

.confirmation-subtitle { color: var(--color-muted); }

.confirmation-number {
    display: inline-flex;
    flex-direction: column;
    background: #fff;
    border: 1px dashed var(--color-primary);
    border-radius: var(--radius-sm);
    padding: .6rem 1.5rem;
    margin-top: 1rem;
}
.confirmation-number strong { font-size: 1.15rem; color: var(--color-primary); }

.confirm-item {
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .85rem 1.15rem;
    border-bottom: 1px solid var(--color-border);
}
.confirm-item:last-child { border-bottom: none; }
.confirm-item--gift { background: #f0fdf4; }

.confirm-item-image img,
.confirm-item-image > i {
    width: 56px;
    height: 56px;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-bg-alt);
    color: #d6d3d1;
}
.confirm-item-info { flex: 1; }
.confirm-item-name { font-weight: 600; font-size: .9rem; color: var(--color-dark); }
.confirm-item-price { font-weight: 700; white-space: nowrap; }

/* Enlace para reseñar desde la confirmación del pedido. Discreto: es una
   invitación, no una llamada a la acción que compita con el pedido. */
.confirm-item-review {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin-top: .35rem;
    font-size: .78rem;
    color: var(--brand-ink);
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: 999px;
    padding: .18rem .6rem;
    transition: all .15s;
}

.confirm-item-review:hover {
    color: #fff;
    background: var(--color-primary);
    border-color: var(--color-primary);
}

.confirm-item-review i { color: var(--brand-amber); }
.confirm-item-review:hover i { color: #fff; }

.status-info { display: flex; flex-direction: column; gap: .5rem; }
.status-row { display: flex; justify-content: space-between; align-items: center; }

/* ---------- Estados vacíos ----------
   Antes esto era un icono gris al 30% de opacidad flotando sobre la página,
   sin fondo ni límites: se veía desnudo y triste. Ahora es una tarjeta con
   un disco de color de marca detrás del icono, para que el vacío se lea como
   un estado cuidado y no como una página rota.

   Sin `max-width` propio a propósito: cada vista decide su ancho. El carrito y
   el 404 lo limitan con `.empty-state-narrow`, y el grid de productos lo deja
   a lo ancho porque ya va dentro de su propia columna. */
.empty-state-lg {
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--color-muted);
}

/* Ancho cómodo para leer: ni una línea larguísima ni una caja estrecha */
.empty-state-narrow { max-width: 620px; margin-inline: auto; }

/* Disco con degradado de marca detrás del icono */
.empty-state-icon {
    width: 84px;
    height: 84px;
    margin: 0 auto .25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--brand-tint) 0%, var(--brand-tint-soft) 100%);
    border: 1px solid var(--brand-tint-strong);
}

.empty-state-icon i {
    font-size: 2.2rem;
    /* Se usa el naranja de marca en lugar del gris al 30%: da color sin
       gritar, y el icono sigue leyéndose como elemento secundario. */
    color: var(--brand-orange);
}

/* Variante para errores (500): el rojo comunica que algo falló de verdad,
   sin el dramatismo de un rojo saturado a pantalla completa. */
.empty-state-icon--danger {
    background: #fef2f2;
    border-color: #fecaca;
}
.empty-state-icon--danger i { color: var(--color-danger); }

.empty-state-lg h3 {
    font-family: var(--font-display);
    color: var(--color-dark);
    font-size: 1.35rem;
    margin-top: 1rem;
}

.empty-state-lg p {
    max-width: 42ch;
    margin-inline: auto;
}

/* El bloque de acciones se separa del texto para que los botones respiren */
.empty-state-actions {
    display: flex;
    gap: .5rem;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}

/* Variante sin tarjeta: para cuando el estado vacío ya va dentro de una
   tarjeta (listados del admin, grids con filtros). Evita el borde doble. */
.empty-state-lg.empty-state-bare {
    background: transparent;
    border: none;
    box-shadow: none;
}

/* Versión compacta, para huecos pequeños (una columna, un panel lateral) */
.empty-state-lg.empty-state-sm {
    padding: 1.75rem 1rem;
}
.empty-state-lg.empty-state-sm .empty-state-icon {
    width: 64px;
    height: 64px;
}
.empty-state-lg.empty-state-sm .empty-state-icon i { font-size: 1.6rem; }
.empty-state-lg.empty-state-sm h3 { font-size: 1.05rem; }

/* ---------- Sugerencias del carrito vacío ----------
   Van debajo del estado vacío y reutilizan la tarjeta de producto completa
   (con su selector y su botón), así el cliente puede llenar el carrito ahí
   mismo en lugar de tener que volver al catálogo. */
.cart-suggestions {
    margin-top: 3rem;
}

.cart-suggestions-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
    padding-bottom: .75rem;
    border-bottom: 1px solid var(--color-border);
}

.cart-suggestions-head h2 {
    font-family: var(--font-display);
    color: var(--color-dark);
}

.cart-suggestions-head i { color: var(--brand-orange); }

/* ==================== AVISO DE EDAD (18+) ====================
   El modal se pinta siempre en el HTML; aquí se mantiene oculto. El script del
   <head> añade `.age-gate-pending` al documento cuando hace falta preguntar.

   IMPORTANTE: el bloqueo es real, no solo visual. Se aplican tres capas:
     1. `overflow: hidden` en html/body → no se puede desplazar el contenido.
     2. El modal cubre toda la ventana con fondo opaco.
     3. `pointer-events: none` + `aria-hidden` al contenido de detrás, para que
        no se pueda pulsar nada ni llegue a un lector de pantalla.
   Solo ocultar el modal no bastaría: con el teclado se seguiría llegando a los
   botones de compra que hay detrás. */

.age-gate {
    display: none;
}

/* ---------- Estado: pendiente de respuesta ---------- */
.age-gate-pending,
.age-gate-pending body {
    overflow: hidden;
    /* Sin esto, en iOS el fondo se sigue desplazando bajo el modal */
    position: relative;
    height: 100%;
}

.age-gate-pending .age-gate {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 2000;
    align-items: center;
    justify-content: center;
    padding: 1.25rem;
    /* Fondo de marca casi opaco: deja intuir la tienda detrás, sin distraer */
    background: rgba(20, 40, 48, .93);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    overflow-y: auto;
}

/* La tienda no se puede usar mientras esté bloqueada */
.age-gate-pending .topbar,
.age-gate-pending .site-header,
.age-gate-pending .site-main,
.age-gate-pending .site-footer {
    pointer-events: none;
    user-select: none;
}

/* ---------- Estado: ya confirmó ---------- */
.age-gate-passed .age-gate {
    display: none;
}

/* ---------- Tarjeta ---------- */
.age-gate-card {
    position: relative;
    width: 100%;
    max-width: 480px;
    margin: auto;
    /* Sin relleno arriba: la banda de la marca ocupa ese sitio y llega hasta el
       borde. El relleno superior lo pone `.age-gate-panel`. */
    padding: 0 1.75rem 1.75rem;
    background: #fff;
    border-radius: var(--radius);
    box-shadow: 0 24px 60px rgba(15, 30, 36, .45);
    text-align: center;
    overflow: hidden;
}

/* La franja de color de marca de arriba ya no hace falta: ahora la sustituye la
   banda del logotipo, que cumple la misma función y además identifica la tienda. */
.age-gate-card::before {
    display: none;
}

/* ---------- Banda con el logotipo ---------- */
.age-gate-brand {
    /* Se sale del relleno de la tarjeta para ocupar todo el ancho */
    margin: 0 -1.75rem 1.1rem;
    padding: 1.35rem 1rem;
    /* El mismo degradado que la cabecera: el logo está dibujado para este fondo
       (su texto es blanco) y así el aviso y la tienda se ven como la misma casa. */
    background: linear-gradient(180deg, var(--brand-dark) 0%, var(--brand-deep) 100%);
}

.age-gate-logo {
    height: 58px;
    width: auto;
    display: block;
    margin: 0 auto;
}

.age-gate-badge {
    width: 68px;
    height: 68px;
    margin: 0 auto .9rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--brand-tint) 0%, var(--brand-tint-soft) 100%);
    border: 1px solid var(--brand-tint-strong);
    font-size: 1.9rem;
    color: var(--brand-orange);
}

/* ---------- Paneles ---------- */
/* ⚠️ El panel de CONFIRMACIÓN no lleva relleno arriba: la banda del logo está
   dentro de él y tiene que llegar hasta el borde superior de la tarjeta. Con
   `padding-top` aquí, la banda quedaba flotando 20px más abajo y se veía una
   franja blanca entre el borde y el degradado. */
.age-gate-panel[data-age-panel="ask"] {
    padding-top: 0;
}

/* El panel de BLOQUEO no tiene banda, así que sí necesita su propio relleno
   arriba para que el escudo no quede pegado al borde. */
.age-gate-panel--denied {
    padding-top: 2rem;
}

.age-gate-badge--denied {
    background: #fef2f2;
    border-color: #fecaca;
    color: var(--color-danger);
}

.age-gate-tag {
    display: inline-block;
    margin-bottom: .6rem;
    padding: .22rem .7rem;
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--brand-ink);
    background: var(--brand-tint);
    border: 1px solid var(--brand-tint-strong);
    border-radius: 999px;
}

.age-gate-title {
    font-family: var(--font-display);
    font-size: clamp(1.25rem, 4vw, 1.55rem);
    color: var(--color-dark);
    margin-bottom: .6rem;
}

.age-gate-text {
    font-size: .92rem;
    color: var(--color-muted);
    margin-bottom: 1.5rem;
}

.age-gate-actions {
    display: flex;
    flex-direction: column;
    gap: .6rem;
}

.age-gate-actions .btn {
    width: 100%;
}

.age-gate-legal {
    margin: 1.25rem 0 0;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
    font-size: .76rem;
    color: var(--color-muted);
    display: flex;
    align-items: flex-start;
    gap: .4rem;
    text-align: left;
}

.age-gate-legal i {
    color: var(--brand-amber);
    flex: 0 0 auto;
    margin-top: .1rem;
}

/* En pantallas con poca altura (móvil horizontal), el modal puede no caber.
   Se reduce el relleno para que los botones sigan siendo alcanzables.
   La banda del logo también se estrecha: es lo que menos aporta cuando falta
   espacio, y los botones son lo que hay que poder pulsar. */
@media (max-height: 620px) {
    .age-gate-brand { padding: .7rem 1rem; margin-bottom: .8rem; }
    .age-gate-logo { height: 38px; }
    .age-gate-panel { padding-top: .75rem; }
    .age-gate-panel--denied { padding-top: 1.25rem; }
    .age-gate-badge { width: 54px; height: 54px; font-size: 1.5rem; margin-bottom: .6rem; }
    .age-gate-text { margin-bottom: 1rem; }
    .age-gate-legal { display: none; }
}

/* Al imprimir no tiene sentido el aviso */
@media print {
    .age-gate { display: none !important; }
}

/* ---------- Pie ----------
   REDISEÑO. Qué estaba mal, medido en el navegador:

   1. El tagline y el copyright usaban `.text-muted` de Bootstrap: un gris
      OSCURO pensado para fondos claros. Sobre el petróleo daba **1.28:1** de
      contraste (el mínimo accesible es 4.5:1). Eran dos renglones invisibles, y
      eso es lo que hacía que el pie pareciera sucio sin saber por qué.
      → Ahora hay colores propios del pie, con contraste verificado.

   2. El aviso de «mayores de 18» iba en ROJO sobre el verde petróleo. Rojo y
      petróleo son casi complementarios: vibran juntos y se leen como un error.
      → Ahora en ámbar de marca, que es el color de aviso que ya usa la tienda.

   3. Las columnas usaban la rejilla de Bootstrap (`col-lg-4/2/3/3`), así que el
      contenido quedaba a distinta altura dentro de cajas iguales.
      → Ahora es una rejilla propia: marca + 3 columnas de enlaces.

   4. No había jerarquía: los cuatro bloques pesaban igual.
      → Franja de confianza arriba, cuerpo, y línea inferior separada.

   El fondo mantiene el petróleo de la cabecera para cerrar la página con el
   color de marca. El logotipo lleva el nombre en blanco: necesita fondo oscuro. */
.site-footer {
    background: var(--brand-deep);
    color: var(--footer-text);
    padding: 0 0 1.5rem;
    margin-top: 4rem;

    /* Paleta del pie en un solo sitio. Los valores NO son arbitrarios: cada uno
       está elegido para pasar el contraste mínimo sobre `--brand-deep` (#1d3a45).

         --footer-text  rgba(255,255,255,.80) →  7.9:1  ✅ AAA en texto pequeño
         --footer-muted rgba(255,255,255,.62) →  5.2:1  ✅ AA
         (el dorado #fcbe0e ya daba 7.18:1 y se mantiene)

       Un `opacity` bajo sobre blanco es la forma habitual de «apagar» texto en
       fondos oscuros, pero se pasa pronto de largo: con .5 el contraste cae a
       3.6:1 y deja de cumplir. Por eso los valores están fijados y comentados. */
    --footer-text: rgba(255, 255, 255, .80);
    --footer-muted: rgba(255, 255, 255, .62);
    --footer-line: rgba(255, 255, 255, .14);
}

/* Franja de marca en el borde superior.
   Repite el degradado que ya usa la tarjeta del aviso de edad
   (petróleo → azul medio → dorado). El extremo oscuro se funde con el fondo y
   el dorado remata contra el contenido claro de arriba, así que el pie no
   empieza con un corte seco. Es el mismo recurso de marca, no uno nuevo. */
.site-footer::before {
    content: "";
    display: block;
    height: 4px;
    background: linear-gradient(90deg,
        var(--brand-deep) 0%,
        var(--brand) 45%,
        var(--brand-gold) 100%);
}

/* ---------- Franja de confianza ----------
   Los tres datos que quitan dudas antes de comprar. Va pegada al borde superior
   con un borde inferior que la separa del resto: es lo primero que se lee. */
.footer-trust {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem 2rem;
    list-style: none;
    margin: 0 0 2rem;
    padding: 1.25rem 0;
    border-bottom: 1px solid var(--footer-line);
}

.footer-trust li {
    display: flex;
    align-items: center;
    gap: .55rem;
    font-size: .875rem;
    color: var(--footer-text);
}

.footer-trust i {
    color: var(--brand-gold);
    font-size: 1.15rem;
    flex-shrink: 0;
}

.footer-trust strong { color: #fff; }

/* ---------- Cuerpo: marca + columnas ----------
   `minmax(0, 1fr)` en la primera columna impide que un correo o una dirección
   larga estiren la rejilla y descuadren las columnas de enlaces. */
.footer-main {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 2fr);
    gap: 2.5rem 3rem;
    padding-bottom: 1.75rem;
}

.footer-brand { max-width: 340px; }

.footer-logo {
    height: 46px;
    width: auto;
    margin-bottom: 1rem;
}

.footer-tagline {
    font-size: .9rem;
    line-height: 1.6;
    color: var(--footer-muted);
    margin-bottom: 1.25rem;
}

.footer-contact {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .55rem;
}

.footer-contact li {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    font-size: .875rem;
    color: var(--footer-text);
}

/* Ancho fijo para los iconos: así los textos quedan alineados en columna.
   Antes cada icono medía lo suyo y los renglones salían en zigzag. */
.footer-contact i {
    color: var(--brand-amber);
    width: 1rem;
    text-align: center;
    flex-shrink: 0;
    margin-top: .15rem;
}

/* ---------- Columnas de enlaces ---------- */
.footer-nav {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2rem;
}

.footer-heading {
    color: var(--brand-gold);
    font-size: .78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    margin-bottom: .9rem;
}

.footer-links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .5rem;
}

.footer-links a {
    color: var(--footer-muted);
    font-size: .875rem;
    text-decoration: none;
    transition: color .15s ease, padding-left .15s ease;
}

/* El desplazamiento al pasar el cursor da una señal de «esto es pulsable» sin
   añadir subrayado ni cambiar el color a un tono que baje el contraste. */
.footer-links a:hover,
.footer-links a:focus-visible {
    color: #fff;
    padding-left: .25rem;
}

.footer-ext {
    font-size: .7rem;
    opacity: .7;
    margin-left: .15rem;
}

/* ---------- Línea inferior ---------- */
.footer-bottom {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: .6rem 1.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--footer-line);
}

.footer-copy {
    margin: 0;
    font-size: .82rem;
    color: var(--footer-muted);
}

.footer-legal {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: .8rem;
    color: var(--footer-muted);
}

.footer-legal li {
    display: flex;
    align-items: center;
    gap: .4rem;
}

.footer-legal i { color: var(--brand-amber); }

/* ---------- Enlaces del pie (incluido el contacto) ----------
   Se declara al final para que gane en los empates de especificidad: el bloque
   anterior de `.site-footer a` tenía la misma que `.footer-links a` y el
   resultado dependía del orden. Un solo sitio para el color de enlace del pie. */
.site-footer a {
    color: var(--footer-muted);
    text-decoration: none;
    transition: color .15s ease;
}

.site-footer a:hover,
.site-footer a:focus-visible {
    color: #fff;
}

/* ---------- Responsive ----------
   El pie pasa de 2 columnas a apilado, y las columnas de enlaces bajan antes
   que el resto porque son lo primero que se puede leer en dos filas. */
@media (max-width: 991.98px) {
    .footer-main {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    .footer-brand { max-width: none; }

    .footer-trust {
        gap: .6rem 1.5rem;
        padding: 1rem 0;
        margin-bottom: 1.75rem;
    }
}

@media (max-width: 575.98px) {
    .site-footer {
        padding-bottom: 1.25rem;
        margin-top: 3rem;
    }

    /* Dos columnas de enlaces en móvil: en una sola fila el pie se hace
       interminable, y en una sola columna tampoco caben los 6-7 enlaces. */
    .footer-nav {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1.5rem;
    }

    .footer-trust {
        flex-direction: column;
        align-items: flex-start;
        gap: .5rem;
    }

    .footer-bottom {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* ---------- Animaciones GSAP ----------
   Los elementos marcados con data-animate empiezan ocultos y GSAP los revela
   al entrar en pantalla. Las redes de seguridad evitan que el contenido quede
   invisible si el JS falla:
     .no-js          → no se ejecutó el JS
     .no-gsap        → GSAP no cargó desde el CDN
     .prefers-reduced-motion → el usuario pidió menos animación */
[data-animate] { opacity: 0; }
.no-js [data-animate],
.no-gsap [data-animate] { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    [data-animate] { opacity: 1 !important; transform: none !important; }
}

/* La cabecera también respeta la preferencia: se queda donde está, sin bajar ni
   sacudirse. La animación de entrada y el balanceo son decorativos; el pliegue
   y el compactado siguen funcionando porque esos SÍ sirven para leer mejor. */
@media (prefers-reduced-motion: reduce) {
    /* El filete de la tarjeta es decorativo: si se pide menos movimiento, se
       muestra ya dibujado en lugar de animarse. Nunca se deja a medias. */
    .product-card::after {
        transition: none;
        transform: scaleX(1);
    }

    .topbar,
    .site-header { animation: none; }

    .site-header .btn-cart.is-shaking .btn-cart-icon { animation: none; }

    .search-layer,
    .search-layer-inner,
    .site-header .navbar-collapse { animation: none; }

    /* El ensanchado del buscador se mantiene (ayuda a escribir), pero sin
       transición que lo alargue. */
    .header-search,
    .brand-logo,
    .site-header .navbar-nav .nav-link::after { transition-duration: .01ms; }
}

/* ==========================================================================
   RESEÑAS DE PRODUCTO
   ========================================================================== */

.reviews-section {
    /* Un borde superior separa las opiniones del bloque de compra: sin él, la
       sección parece continuación del producto y no una parte aparte. */
    border-top: 1px solid var(--color-border);
}

/* La cabecera es pegajosa (sticky). Sin esto, al saltar a #resenas o a
   #escribir-resena el navegador alinea el destino con el borde superior de la
   ventana y la cabecera tapa justo el encabezado o el formulario al que se
   quería llegar. */
.reviews-section,
.review-form-wrap {
    scroll-margin-top: 90px;
}

/* ---------- Sin opiniones todavía ---------- */
.reviews-empty {
    text-align: center;
    padding: 2.5rem 1.5rem;
    background: var(--color-bg-alt);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
}

.reviews-empty i {
    font-size: 2.2rem;
    color: var(--brand-amber);
    display: block;
    margin-bottom: .75rem;
}

.reviews-empty h3 {
    font-family: var(--font-display);
    font-size: 1.2rem;
    color: var(--color-dark);
    margin-bottom: .4rem;
}

.reviews-empty p {
    color: var(--color-muted);
    font-size: .92rem;
}

/* ---------- Resumen (nota + desglose) ---------- */
.reviews-summary {
    display: grid;
    grid-template-columns: 180px 1fr;
    gap: 2rem;
    align-items: center;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.reviews-score {
    text-align: center;
    padding-right: 1.5rem;
    border-right: 1px solid var(--color-border);
}

.reviews-score-number {
    font-family: var(--font-display);
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    color: var(--color-dark);
}

.reviews-score-stars {
    color: var(--brand-amber);
    font-size: 1.05rem;
    margin: .4rem 0 .25rem;
    letter-spacing: .06em;
}

.reviews-score-count {
    font-size: .8rem;
    color: var(--color-muted);
}

.reviews-breakdown {
    display: flex;
    flex-direction: column;
    gap: .45rem;
}

.review-bar-row {
    display: grid;
    grid-template-columns: 46px 1fr 34px;
    align-items: center;
    gap: .6rem;
    font-size: .82rem;
    color: var(--color-muted);
}

.review-bar-label {
    display: flex;
    align-items: center;
    gap: .25rem;
    justify-content: flex-end;
    white-space: nowrap;
}

.review-bar-label i { color: var(--brand-amber); font-size: .75rem; }

.review-bar-track {
    height: 8px;
    background: var(--color-bg-alt);
    border-radius: 999px;
    overflow: hidden;
}

.review-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--brand-amber) 0%, var(--brand-orange) 100%);
    border-radius: 999px;
    /* El ancho inicial es 0 para que la barra crezca al aparecer: comunica la
       proporción mejor que una barra ya dibujada. */
    transition: width .6s ease;
}

.review-bar-count {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ---------- Orden ---------- */
.reviews-toolbar {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.review-order-link {
    font-size: .82rem;
    padding: .3rem .75rem;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-body);
    background: #fff;
    transition: all .15s;
}

.review-order-link:hover {
    border-color: var(--brand-amber);
    color: var(--color-dark);
}

.review-order-link.active {
    background: var(--brand-tint);
    border-color: var(--brand-tint-strong);
    color: var(--brand-ink);
    font-weight: 600;
}

/* ---------- Lista de opiniones ---------- */
.review-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.review-item {
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 1.15rem 1.25rem;
}

/* La propia se marca con un filo ámbar, para reconocerla de un vistazo */
.review-item--mine {
    border-left: 3px solid var(--brand-amber);
    background: var(--brand-tint);
}

.review-item-head {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    margin-bottom: .65rem;
}

.review-avatar {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--brand-dark);
    color: #fff;
    font-weight: 700;
    font-size: .95rem;
}

.review-item-meta { flex: 1 1 auto; min-width: 0; }

.review-item-date {
    font-size: .78rem;
    color: var(--color-muted);
    margin-top: .1rem;
}

.review-item-stars {
    flex: 0 0 auto;
    color: var(--brand-amber);
    font-size: .85rem;
    letter-spacing: .05em;
}

.review-item-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-dark);
    margin-bottom: .35rem;
}

.review-item-comment {
    font-size: .92rem;
    color: var(--color-body);
    margin-bottom: .75rem;
    /* Respeta los saltos de línea escritos por el cliente sin desbordar */
    overflow-wrap: anywhere;
}

.review-item-foot {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-top: .6rem;
    border-top: 1px solid var(--color-border);
}

.review-helpful {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .28rem .7rem;
    font-size: .78rem;
    color: var(--color-muted);
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    transition: all .15s;
}

.review-helpful:hover {
    color: var(--color-dark);
    border-color: var(--brand-amber);
    background: var(--brand-tint);
}

/* El voto negativo es un icono suelto: no compite con el positivo */
.review-helpful--no { padding: .28rem .55rem; }

.review-helpful-locked {
    font-size: .78rem;
    color: var(--color-success);
}

.badge-verified {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .7rem;
    font-weight: 600;
    padding: .18rem .5rem;
    border-radius: 999px;
    color: #15803d;
    background: #dcfce7;
    border: 1px solid #bbf7d0;
}

.badge-mine {
    font-size: .7rem;
    font-weight: 600;
    padding: .18rem .5rem;
    border-radius: 999px;
    color: var(--brand-ink);
    background: var(--brand-tint-soft);
    border: 1px solid var(--brand-tint-strong);
}

/* ---------- Paginación ---------- */
.reviews-pagination {
    display: flex;
    justify-content: center;
    gap: .35rem;
    margin-top: 1.25rem;
}

.review-page-link {
    min-width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 .5rem;
    font-size: .85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: #fff;
    color: var(--color-body);
}

.review-page-link:hover { border-color: var(--brand-amber); color: var(--color-dark); }

.review-page-link.active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
    font-weight: 600;
}

/* Deshabilitado pero SIN `pointer-events: none`: así sigue siendo enfocable y
   el usuario de teclado no pierde la posición al llegar al extremo. */
.review-page-link.disabled {
    opacity: .45;
    cursor: not-allowed;
}

/* ---------- Formulario ---------- */
.review-form-wrap {
    margin-top: 2rem;
    padding: 1.5rem;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.review-form-title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    color: var(--color-dark);
    margin-bottom: 1rem;
}

.review-field { margin-bottom: 1.1rem; }

.review-field .form-label {
    font-weight: 600;
    font-size: .88rem;
    color: var(--color-dark);
}

.review-form-actions {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

/* ---------- Selector de estrellas ----------
   Radios reales ocultos con las estrellas encima: funciona sin JavaScript y
   mantiene la navegación por teclado (flechas dentro del radiogroup).

   Se recorre en orden inverso (5→1) con `row-reverse` para que el pintado de
   estrellas salga bien con selectores de hermanos: al pasar por la estrella 3
   se iluminan las ANTERIORES en el DOM, que con el orden invertido son las de
   su izquierda. Sin invertir, se iluminarían las de su derecha. */
.star-input {
    position: relative;
    display: inline-flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
    gap: .15rem;
}

/* Radios ocultos con la técnica «visually hidden»: fuera de la vista pero SIN
   `display: none`, para que sigan recibiendo el foco y la validación `required`
   del navegador siga funcionando. Con `position: absolute` a secas, el input de
   1px quedaba encima de una estrella e interceptaba su clic. */
.star-input input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.star-input label {
    font-size: 1.9rem;
    line-height: 1;
    color: #d6d3d1;
    cursor: pointer;
    transition: color .12s;
    /* Sin `transform` al pasar el ratón: agrandar la estrella desplaza las
       vecinas y el clic acaba cayendo en la equivocada. El color ya da el
       mismo aviso sin mover nada. */
}

.star-input label:hover,
.star-input label:hover ~ label,
.star-input input:checked ~ label {
    color: var(--brand-amber);
}

.star-input input:focus-visible + label {
    outline: 2px solid var(--color-primary);
    outline-offset: 3px;
    border-radius: 4px;
}

/* ---------- Invitación a entrar para opinar ---------- */
.review-login-invite {
    text-align: center;
    padding: .5rem 0;
}

.review-login-icon {
    width: 58px;
    height: 58px;
    margin: 0 auto .85rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--brand-tint) 0%, var(--brand-tint-soft) 100%);
    border: 1px solid var(--brand-tint-strong);
    color: var(--brand-orange);
    font-size: 1.5rem;
}

.review-login-invite h3 {
    font-family: var(--font-display);
    font-size: 1.2rem;
    color: var(--color-dark);
    margin-bottom: .5rem;
}

.review-login-invite p {
    max-width: 460px;
    margin: 0 auto 1.1rem;
    font-size: .92rem;
    color: var(--color-muted);
}

/* ---------- Nota en las tarjetas de producto ---------- */
.product-rating {
    display: flex;
    align-items: center;
    gap: .3rem;
    margin-top: .3rem;
    font-size: .78rem;
    line-height: 1;
}

.product-rating-stars {
    color: var(--brand-amber);
    letter-spacing: .03em;
}

.product-rating-count {
    color: var(--color-muted);
    font-size: .74rem;
}

/* ---------- Responsive ---------- */
@media (max-width: 767.98px) {
    .reviews-summary {
        grid-template-columns: 1fr;
        gap: 1.25rem;
        padding: 1.25rem;
    }

    .reviews-score {
        padding-right: 0;
        padding-bottom: 1.25rem;
        border-right: 0;
        border-bottom: 1px solid var(--color-border);
    }

    .reviews-score-number { font-size: 2.4rem; }

    .review-item-head { flex-wrap: wrap; }
    .review-item-stars { width: 100%; }

    .review-form-wrap { padding: 1.15rem; }
    .review-form-actions .btn { width: 100%; }
    .review-form-actions .small { width: 100%; text-align: center; }
}

/* ==========================================================================
   SELECTOR DE SABORES
   ========================================================================== */

/* Destino del ancla al cambiar de sabor. La cabecera es pegajosa, así que sin
   este margen el selector quedaría tapado al llegar desde otro sabor. */
.flavor-anchor {
    scroll-margin-top: 90px;
}

.flavor-selector {
    margin: 1.25rem 0;
    padding: 1rem;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}

.flavor-selector-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .5rem;
    margin-bottom: .75rem;
}

.flavor-selector-title {
    font-weight: 700;
    font-size: .92rem;
    color: var(--color-dark);
}

.flavor-selector-title i { color: var(--brand-orange); }

.flavor-selector-count {
    font-size: .76rem;
    color: var(--color-muted);
}

.flavor-list {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.flavor-item {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .3rem .75rem .3rem .3rem;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: #fff;
    color: var(--color-body);
    transition: border-color .15s, background .15s, transform .15s;
}

a.flavor-item:hover {
    border-color: var(--brand-amber);
    background: var(--brand-tint);
    color: var(--color-dark);
    transform: translateY(-1px);
}

a.flavor-item:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* El sabor que se está viendo. No es un enlace: es el estado actual. */
.flavor-item.is-current {
    border-color: var(--brand-dark);
    background: var(--brand-tint);
    font-weight: 700;
    color: var(--color-dark);
    cursor: default;
}

/* Agotado: se sigue mostrando (saber que existe es útil) pero sin invitar a
   pulsarlo. No se usa `pointer-events: none` porque el enlace debe seguir
   siendo enfocable y navegable con teclado. */
.flavor-item.is-out {
    opacity: .55;
}

.flavor-dot {
    width: 28px;
    height: 28px;
    flex: 0 0 28px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .78rem;
    font-weight: 700;
    line-height: 1;
    /* El fondo y el color del texto los pone el servidor en línea: el texto se
       invierte a negro sobre los colores claros para que siempre se lea. */
    border: 1px solid rgba(0, 0, 0, .12);
}

.flavor-item.is-current .flavor-dot {
    /* Un filo doble marca el actual sin cambiar su color, que es el dato */
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--brand-dark);
}

.flavor-name {
    font-size: .84rem;
    white-space: nowrap;
}

.flavor-out-tag {
    font-size: .66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--color-danger);
}

.flavor-hint {
    margin: .85rem 0 0;
    font-size: .78rem;
    color: var(--color-muted);
}

.flavor-hint i { color: var(--brand-amber); }

@media (max-width: 575.98px) {
    .flavor-item { padding-right: .6rem; }
    .flavor-name { font-size: .8rem; }
    .flavor-dot { width: 26px; height: 26px; flex-basis: 26px; }
}

/* ==========================================================================
   CAMBIO DE SABOR SIN RECARGA
   ==========================================================================
   El bloque del producto se atenúa mientras llega el sabor nuevo. Es un cambio
   lo bastante rápido como para no necesitar una rueda de carga, pero sin ninguna
   señal el cliente pulsa y no ve nada durante un instante: la atenuación es la
   confirmación de que el clic se registró. */
[data-product-block] {
    transition: opacity .18s ease;
}

[data-product-block].is-swapping {
    opacity: .45;
    /* Evita que un doble clic aproveche el hueco mientras se sustituye */
    pointer-events: none;
}

/* Con «movimiento reducido» el cambio es instantáneo: sin fundido, el contenido
   se sustituye y ya. */
@media (prefers-reduced-motion: reduce) {
    [data-product-block] {
        transition: none;
    }
}

/* El selector de sabores no se atenúa con el resto: si el cliente cambia de
   idea y quiere volver al sabor anterior, debe poder pulsar de inmediato. */
[data-product-block].is-swapping .flavor-selector {
    opacity: 1;
    pointer-events: auto;
}

/* ==========================================================================
   TARJETA «AGREGADO AL CARRITO»
   ========================================================================== */

/* Se inserta vacía en el DOM y solo se ve cuando tiene la clase `is-visible`:
   al no existir en el HTML inicial no ocupa sitio ni intercepta clics cuando
   no toca. */
#cart-card {
    position: fixed;
    /* 120px despeja la cabecera en sus DOS estados: con la barra superior
       visible (28 + 79 = 107) y ya pegada arriba (79). Un valor menor dejaba la
       tarjeta encima de la barra de navegación, tapándola, porque la tarjeta
       tiene más z-index que la cabecera. */
    top: 120px;
    right: 1rem;
    z-index: 1080;
    width: min(340px, calc(100vw - 2rem));
    pointer-events: none;
    opacity: 0;
    transform: translateY(-14px) scale(.97);
    transition: opacity .3s ease, transform .3s cubic-bezier(.2, .9, .3, 1.2);
}

#cart-card.is-visible {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

.cart-card-box {
    position: relative;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 12px 32px rgba(28, 25, 23, .18);
    padding: 1rem 1rem .9rem;
    overflow: hidden;
}

/* Franja superior con el degradado de marca, igual que el aviso de edad y el
   resto de superficies destacadas de la tienda. */
.cart-card-box::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: linear-gradient(90deg, var(--brand-deep) 0%, var(--brand) 45%, var(--brand-gold) 100%);
}

.cart-card-close {
    position: absolute;
    top: .6rem;
    right: .6rem;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--color-muted);
    font-size: .72rem;
    cursor: pointer;
    transition: background .15s, color .15s;
}

.cart-card-close:hover {
    background: var(--color-bg-alt);
    color: var(--color-dark);
}

.cart-card-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .75rem;
    padding-right: 1.5rem;
}

/* El check en el verde de «correcto» que ya usa la tienda. No se usa el petróleo
   de marca aquí a propósito: este disco comunica «hecho», y para eso el verde
   es el color que el visitante ya tiene aprendido. */
.cart-card-check {
    width: 30px;
    height: 30px;
    flex: 0 0 30px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, #22c55e 0%, var(--color-success) 100%);
    color: #fff;
    font-size: .85rem;
    /* Late una vez al aparecer: llama la atención sin ser molesto */
    animation: cartCardPop .45s cubic-bezier(.2, 1.4, .4, 1) .15s backwards;
}

@keyframes cartCardPop {
    0%   { transform: scale(.3); }
    60%  { transform: scale(1.18); }
    100% { transform: scale(1); }
}

.cart-card-title {
    font-weight: 700;
    font-size: .9rem;
    color: var(--color-dark);
}

.cart-card-product {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .6rem;
    margin-bottom: .85rem;
    background: var(--color-bg-alt);
    border-radius: var(--radius-sm);
}

.cart-card-thumb {
    width: 46px;
    height: 46px;
    flex: 0 0 46px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: #fff;
    border: 1px solid var(--color-border);
    color: var(--brand-orange);
    font-size: 1.1rem;
}

.cart-card-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.cart-card-info {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: .1rem;
}

.cart-card-name {
    font-size: .84rem;
    font-weight: 600;
    color: var(--color-dark);
    /* Dos líneas como máximo: un nombre largo no debe desbordar la tarjeta */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.cart-card-name:hover { color: var(--color-primary); text-decoration: underline; }

.cart-card-price {
    font-size: .86rem;
    font-weight: 700;
    /* El tono OSCURO del color de acción y no el normal: sobre el fondo gris de
       la ficha del producto, el normal se quedaba en 4.59:1 —aprobado pero sin
       margen—. Este sube a 6.16:1. */
    color: var(--color-primary-dark);
}

.cart-card-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    width: 100%;
    padding: .55rem 1rem;
    font-size: .85rem;
    font-weight: 600;
    color: #fff;
    background: var(--color-primary);
    border-radius: var(--radius-sm);
    transition: background .15s;
}

.cart-card-btn:hover {
    background: var(--color-primary-dark);
    color: #fff;
}

/* En móvil la barra superior y la cabecera suman lo mismo, así que basta con
   ocupar todo el ancho disponible y bajar un poco más por si el menú está
   desplegado. */
@media (max-width: 575.98px) {
    #cart-card {
        top: 116px;
        right: .75rem;
        left: .75rem;
        width: auto;
    }
}

/* Sin animaciones para quien pide movimiento reducido: la tarjeta sigue
   apareciendo y desapareciendo, pero sin desplazamiento ni rebote. */
@media (prefers-reduced-motion: reduce) {
    #cart-card { transition: opacity .2s; transform: none; }
    .cart-card-check { animation: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 991.98px) {
    /* La regla antigua del buscador ya no aplica: ahora vive en la capa */
    .product-gallery { position: static; }
}

@media (max-width: 767.98px) {
    .section { padding: 2.25rem 0; }
    .hero-title { font-size: 1.6rem; }
    .hero-subtitle { font-size: .95rem; }

    .cart-item {
        grid-template-columns: 64px 1fr auto;
        grid-template-areas:
            "image info remove"
            "image qty total";
        gap: .6rem;
        padding: .85rem;
    }
    .cart-item-image { grid-area: image; }
    .cart-item-image img,
    .cart-image-placeholder { width: 64px; height: 64px; }
    .cart-item-info { grid-area: info; }
    .cart-item-qty { grid-area: qty; }
    .cart-item-total { grid-area: total; text-align: right; }
    .cart-item-remove { grid-area: remove; }

    .buy-row { flex-direction: column; }
    .qty-selector-lg { width: 100%; justify-content: space-between; }
    .btn-buy { width: 100%; }

    .pack-builder { padding: 1rem; }
    .pack-builder-footer { flex-direction: column; align-items: stretch; }
    .pack-summary-line { min-width: 0; }
    .pack-actions { flex-direction: column; }
    .pack-actions .btn { width: 100%; }

    /* El panel de progreso pasa a ocupar todo el ancho: con el título ya en su
       propia línea arriba, dejarlo a 200 px en un móvil lo comprimiría sin
       motivo. */
    .pack-builder-progress {
        flex: 1 1 100%;
        max-width: none;
        min-width: 0;
        margin-left: 0;
    }
    .pack-builder-title { font-size: 1.4rem; }

    .min-order-banner { flex-direction: column; text-align: center; }
    .min-order-action { width: 100%; }
    .min-order-action .btn { width: 100%; }

    .product-name { font-size: .88rem; }
    .price-current { font-size: 1rem; }

    .confirm-item { flex-wrap: wrap; }
    .confirm-item-price { width: 100%; text-align: right; }
}

/* ==================== RECETAS Y VIDEOS ==================== */
/* Reproductor incrustado (YouTube, TikTok, Instagram, Facebook, Vimeo).
   La proporción la decide el formato del video: 16:9 o vertical 9:16. */
.video-embed {
    position: relative;
    width: 100%;
    background: var(--color-dark);
    border-radius: var(--radius-card);
    overflow: hidden;
}
.video-embed--horizontal { aspect-ratio: 16 / 9; }
.video-embed--vertical {
    aspect-ratio: 9 / 16;
    max-width: 420px;
    margin-inline: auto;
}
.video-embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.recipe-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: 3px;
    overflow: hidden;
    color: inherit;
    text-decoration: none;
    transition: border-color var(--dur) var(--ease-out),
                box-shadow var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out);
}
.recipe-card:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow);
    transform: translateY(-2px);
    color: inherit;
}
.recipe-card__media {
    position: relative;
    aspect-ratio: 4 / 3;
    background: var(--brand-tint);
    overflow: hidden;
}
.recipe-card__media--vertical { aspect-ratio: 4 / 5; }
.recipe-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
.recipe-card__placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    font-size: 2.5rem;
    color: var(--brand-ink);
}
.recipe-card__play {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 52px;
    height: 52px;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(28, 25, 23, .65);
    color: #fff;
    font-size: 1.6rem;
    transition: background var(--dur) var(--ease-out);
}
.recipe-card:hover .recipe-card__play { background: var(--color-primary); }
.recipe-card__provider {
    position: absolute;
    left: .5rem;
    bottom: .5rem;
    padding: .15rem .5rem;
    border-radius: var(--radius-xs);
    background: rgba(28, 25, 23, .7);
    color: #fff;
    font-family: var(--font-mono);
    font-size: .7rem;
    letter-spacing: .04em;
}
.recipe-card__body { padding: .85rem .9rem 1rem; }
.recipe-card__title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    line-height: 1.25;
    margin: 0 0 .35rem;
    color: var(--color-dark);
}
.recipe-card__summary {
    font-size: .85rem;
    color: var(--color-muted);
    margin: 0 0 .4rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.recipe-card__meta { font-size: .78rem; color: var(--color-muted); }

.recipe-heading {
    font-family: var(--font-display);
    font-size: 1.35rem;
    margin: 0 0 .75rem;
}
.recipe-ingredients,
.recipe-steps {
    padding-left: 1.25rem;
    margin-bottom: 1.75rem;
}
.recipe-ingredients li,
.recipe-steps li { margin-bottom: .45rem; }
.recipe-steps li::marker {
    font-family: var(--font-mono);
    color: var(--color-primary);
    font-weight: 600;
}
.recipe-cover { width: 100%; object-fit: cover; }
