/* cartasgrupo — frontend público (solo lectura)
   Siempre modo claro. Sin frameworks ni imports externos.
   Colores del restaurante llegan como custom properties inline en .carta
   (--color-cerrado, --color-activo, --color-secundario) y la tipografía
   como font-family inline en el mismo elemento. */

:root {
    --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

* {
    box-sizing: border-box;
}

html,
body {
    margin: 0;
    padding: 0;
}

body {
    background: #f4f4f2;
    color: #111;
}

.carta-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    height: 64px;
    padding: 0 1rem;
    /* El color de fondo real llega inline desde CartaRenderer (elegido en
       Configuración por restaurante); #fff es solo el valor de reserva
       antes de que cargue ese inline style. */
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

/* CartaRenderer añade esta clase cuando el color de header elegido es
   oscuro (brillo percibido bajo): el botón "volver" y el nombre del
   restaurante (cuando no hay logo) pasan a claros para seguir siendo
   legibles. El logo en sí se resuelve aparte, sirviendo directamente el
   logo en blanco de Configuración si existe. */
.carta-header--oscuro .carta-header-volver a,
.carta-header--oscuro .carta-header-volver button {
    color: #fff;
}

.carta-header--oscuro .carta-header-volver a:hover,
.carta-header--oscuro .carta-header-volver button:hover {
    background: rgba(255, 255, 255, 0.15);
}

.carta-header--oscuro .carta-header-logo span {
    color: #fff;
}

.carta-header-volver {
    justify-self: start;
    position: relative;
}

.carta-header-volver a,
.carta-header-volver button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 999px;
    color: #333;
    transition: background-color 140ms ease;
    /* .carta-menu-boton es un <button>, no un <a>: sin resetear esto se ve
       con el fondo/borde por defecto del navegador en vez de "solo icono"
       como el botón "volver" que sustituye. */
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
}

.carta-header-volver a:hover,
.carta-header-volver button:hover {
    background: #f4f4f2;
}

.carta-header-volver a[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    top: 50%;
    left: calc(100% + 0.6rem);
    transform: translateY(-50%) translateX(-4px);
    white-space: nowrap;
    background: #201c1a;
    color: #fff;
    font-size: 0.8rem;
    font-weight: 600;
    padding: 0.4rem 0.7rem;
    border-radius: 6px;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 140ms ease, transform 140ms ease;
    z-index: 10;
}

.carta-header-volver a[data-tooltip]:hover::after,
.carta-header-volver a[data-tooltip]:focus-visible::after {
    opacity: 1;
    visibility: visible;
    transform: translateY(-50%) translateX(0);
}

.carta-header-volver .icono {
    width: 22px;
    height: 22px;
}

.carta-header-logo {
    justify-self: center;
    display: flex;
    align-items: center;
    min-width: 0;
}

/* Caja de tamaño FIJO (ancho y alto, no solo un tope de ancho): con solo
   height + max-width, un logo muy ancho y bajo (p. ej. 466×74, ratio 6:1)
   choca antes contra max-width que contra height, y su altura renderizada
   acababa encogida muy por debajo de la de un logo más cuadrado — distinto
   restaurante, logo de distinto tamaño en la misma cabecera. object-fit:
   contain dentro de una caja con las dos medidas fijas encaja cada logo
   entero (sin recortar ni deformar) siempre en el mismo hueco, sea cual
   sea su proporción. Mismo criterio que .live-selector-item-logo en
   admin.css para el selector de restaurantes de Live móvil. */
.carta-header-logo img {
    display: block;
    width: 250px;
    height: 54px;
    object-fit: contain;
}

.carta-header-logo span {
    font-weight: 700;
    font-size: 1.1rem;
    white-space: nowrap;
}

.carta-header-traductor {
    justify-self: end;
    display: flex;
    align-items: center;
}

/* El widget de GTranslate ("float") se autoposiciona con position:fixed
   e inline styles propios, ignorando por completo dónde está su div
   ancla en el DOM. Se fuerza aquí a encajar dentro de .carta-header
   (verticalmente centrado) y se reduce su tamaño por defecto, que es
   bastante más grande de lo que necesita esta barra. */
#gt_float_wrapper {
    top: 12px !important;
    right: 1rem !important;
}

/* Modo tablet (ver CartaRenderer::renderBodega()): arriba a la derecha ya
   lo ocupa la cabecera propia (logo + filtros), así que aquí el selector
   de idioma va abajo a la derecha en su lugar — junto al buscador, no
   pisando la cabecera. Selector body.cuerpo-bodega-tablet, no
   .carta--tablet: #gt_float_wrapper cuelga directo de <body>, no de
   .carta, así que un descendiente de .carta--tablet nunca lo alcanzaría. */
body.cuerpo-bodega-tablet #gt_float_wrapper {
    top: auto !important;
    bottom: 12px !important;
}

/* El div-ancla en sí (ver CartaRenderer::renderBodega()) no debe
   ocupar ni pintar nada — pero NO con display:none/hidden: el propio
   #gt_float_wrapper del widget cuelga COMO HIJO suyo pese a ser
   position:fixed, y display:none en un ancestro se lleva por delante a
   los descendientes fixed también. Colapsado a 0×0 + overflow:hidden sí
   lo saca de la vista sin tocar ese descendiente. */
body.cuerpo-bodega-tablet .gtranslate_wrapper {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* Modo embed de la carta normal (ver CartaRenderer::render() con
   $modoEmbed, activado con ?embed=1 — pensado para empotrarse en un
   <iframe> compacto de altura FIJA en otra web, ver Configuración →
   General → "Insertar en tu web"). Dos versiones según el ancho, las DOS
   siempre presentes en el HTML (ver render()), cambiadas aquí por CSS:
   - Escritorio (por defecto): sin cabecera propia — .carta ya no necesita
     el hueco de 64px de arriba, y el botón de categorías/selector de
     idioma van sueltos flotando (ver más abajo). Este es un <iframe>
     normal insertado en mitad del scroll de la página.
   - Móvil (@media más abajo): cabecera completa, igual que la carta
     normal (con logo incluido). En móvil este ?embed=1 vive dentro de un
     POPUP a pantalla completa que
     Elementor abre con un botón "Ver carta" — NO en mitad del scroll de la
     página. Antes se probó esta misma cabecera completa dentro de un
     <iframe> normal (como en escritorio) y resultó errática en
     Safari/iPhone real (el contenido podía acabar tapando su propia
     cabecera, sin forma de recuperarla, por competir por el scroll con el
     resto de la web) — dentro de un popup no hay ese scroll exterior con
     el que competir, así que no aplica. */
body.cuerpo-carta-embed .carta-header {
    display: none;
}

body.cuerpo-carta-embed {
    /* <body> en sí NO hace scroll — el propio <iframe> ya trae una altura
       fija en su código de inserción, y el scroll para ver el resto del
       contenido vive dentro de .carta (ver más abajo), no aquí. Sin esto,
       con contenido más alto que el iframe habría DOS scrolls posibles
       (el de <body> y el de .carta), confuso y con el primero encima
       tapando al segundo. */
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    /* Transparente (pisa el gris de "body {" de más arriba): pensado para
       empotrarse en la web del restaurante, no en una pestaña suelta —
       con fondo propio se vería como una caja gris encima del diseño de
       esa web en vez de fundirse con él. */
    background: transparent;
}

.carta.carta--embed {
    margin-top: 0;
    /* Altura fija (no min-height, que dejaría crecer .carta sin límite):
       el hueco a la derecha de la web que lo aloja suele ser compacto —
       ver el scroll interno de aquí abajo para el resto del contenido, no
       un <iframe> cada vez más alto según el restaurante tenga más o
       menos categorías. */
    height: 100vh;
    height: 100dvh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Transparente (pisa el #fff de .carta base) — mismo motivo que
       body.cuerpo-carta-embed de arriba. */
    background: transparent;
}

/* Botón de categorías flotante del modo embed (ver CartaRenderer::render()):
   mismo icono que en la cabecera normal, pero sin cabecera que lo aloje va
   suelto arriba a la izquierda, con fondo propio (la cabecera normal no
   necesita esto porque YA es una barra de color) — position:fixed dentro
   del iframe se autoposiciona respecto a SU PROPIO viewport, igual que
   #gt_float_wrapper arriba a la derecha (ver más abajo), así que los dos
   conviven sin pisarse. */
.carta-menu-boton--flotante {
    position: fixed;
    top: 12px;
    left: 1rem;
    z-index: 1000;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: none;
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
    color: #333;
    cursor: pointer;
    padding: 0;
    transition: background-color 140ms ease;
}

.carta-menu-boton--flotante:hover {
    background: #f4f4f2;
}

.carta-menu-boton--flotante .icono {
    width: 22px;
    height: 22px;
}

/* .subcategoria-titulo (más abajo) se queda "sticky" para parar justo
   debajo de lo que haya fijo arriba — en escritorio (sin cabecera propia
   en este modo) eso es el borde superior del iframe sin más. El "top" de
   un elemento sticky se mide desde el borde del PADDING de su contenedor
   con scroll (.carta--embed, que es quien tiene overflow-y:auto aquí), y
   el padding-top de 2rem que trae .carta de base dejaba el título pegado
   32px más abajo del borde real con top:0 a secas — top negativo, igual a
   ese padding, lo cancela. Aviso conocido, no arreglable desde aquí: si la
   web que lo aloja tiene su propia cabecera fija por encima con más
   z-index, esta tapará el título en el instante concreto en que el iframe
   (que no es fijo, se mueve con el scroll de ESA página) pase por debajo
   suyo — ninguna página puede controlar lo que haya por encima del iframe
   que la aloja. */
.carta--embed .subcategoria-titulo {
    top: -2rem;
}

/* Móvil: cabecera completa en vez de los dos iconos sueltos (ver el
   comentario grande de "Modo embed" más arriba: aquí SIEMPRE es un popup a
   pantalla completa, no un iframe normal en mitad del scroll de la
   página) — mismo corte de 480px que ya usa el resto de esta carta. */
@media (max-width: 480px) {
    body.cuerpo-carta-embed .carta-header {
        display: grid;
    }

    .carta-menu-boton--flotante {
        display: none;
    }

    /* Con cabecera visible (64px, fixed dentro del iframe igual que en la
       carta normal) .carta--embed necesita el mismo hueco de arriba que
       ella compensaba antes en modo embed — igual que .carta a secas en
       el resto de la carta (ver más arriba, margin-top:64px de base). */
    .carta.carta--embed {
        margin-top: 64px;
        height: calc(100vh - 64px);
        height: calc(100dvh - 64px);
    }

    /* OJO: NO hace falta sumar aquí los 64px de la cabecera — el
       margin-top de arriba ya baja la caja entera de .carta--embed hasta
       justo debajo de ella, así que "pegarse arriba del todo DE LA CAJA"
       (mismo objetivo que en escritorio) ya cae exactamente debajo de la
       cabecera sin más. Solo cambia el padding a cancelar: 1rem aquí (ver
       @media (max-width:480px) de .carta más abajo), no los 2rem de
       escritorio. */
    .carta--embed .subcategoria-titulo {
        top: -1rem;
    }
}

.gt_float_switcher,
.gt-selected {
    background: transparent !important;
    box-shadow: none !important;
}

.gt-current-lang {
    padding: 0 0.6rem !important;
    height: 46px;
    display: flex;
    align-items: center;
    background: transparent !important;
    box-shadow: none !important;
    border-radius: 999px;
    transition: background-color 140ms ease;
}

.gt-current-lang:hover {
    background: #f4f4f2 !important;
}

.gt-current-lang img {
    width: 25px !important;
    height: 25px !important;
}

.gt_options {
    background: #fff !important;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12) !important;
    border-radius: 8px !important;
    overflow: hidden;
    margin-top: 0.35rem;
}

.gt-lang-code {
    font-size: 0.92rem !important;
}

.gt_options a {
    font-size: 0.98rem !important;
    padding: 0.55rem 0.85rem !important;
}

.gt_options img {
    width: 22px !important;
    height: 22px !important;
}

/* En pantallas estrechas (móviles) el logo centrado y el selector de
   idioma, que se autoposiciona a una distancia fija del borde, no caben
   los dos a la vez y se solapan. Se reduce el logo y se deja el selector
   solo con la bandera (sin el código "ES") para que quepa todo. */
@media (max-width: 480px) {
    .carta-header {
        padding: 0 0.65rem;
    }

    .carta-header-volver a {
        width: 34px;
        height: 34px;
    }

    .carta-header-logo img {
        width: 150px;
        height: 48px;
    }

    .carta-header-logo span {
        font-size: 0.95rem;
    }

    #gt_float_wrapper {
        right: 0.65rem !important;
    }

    .gt-current-lang {
        height: 40px;
        padding: 0 0.4rem !important;
    }

    .gt-current-lang img {
        width: 22px !important;
        height: 22px !important;
    }

    .gt-lang-code,
    .gt_float_switcher-arrow {
        display: none !important;
    }

    .gt_options {
        left: auto !important;
        right: 0 !important;
        max-width: calc(100vw - 1.3rem);
    }
}

.carta {
    background: #fff;
    max-width: 900px;
    margin: 64px auto 0;
    padding: 2rem 2.5rem 4rem;
    line-height: 1.4;
    /* Con poco contenido (típicamente la Bodega, con solo un par de vinos)
       .carta termina antes de llegar al final de la pantalla, y por debajo
       se ve el fondo gris de <body> — un hueco que nunca se notaba en la
       carta normal porque ahí siempre hay contenido de sobra para superar
       el alto de la pantalla. calc(...- 64px) porque el margin-top de
       arriba (el hueco de la cabecera fija) no debe contar como parte de
       este alto mínimo, o sobraría scroll de más en cualquier página,
       incluida una carta larga. */
    min-height: calc(100vh - 64px);
    min-height: calc(100dvh - 64px);
}

/* Slider de imágenes (Configuración → "Slider de imágenes"), a todo lo
   ancho como la cabecera fija — mismo truco de "borde a borde" que el
   acordeón activo (ver .subcategoria[open] .subcategoria-titulo): margin
   negativo igual al padding de .carta para salir hasta el borde, en las
   cuatro direcciones (arriba también, para que quede pegado a la cabecera
   fija, la primera cosa que se ve al entrar). Si no hay imágenes
   CartaRenderer::renderSlider() no pinta nada, así que esta regla nunca
   deja un hueco vacío de fondo gris. */
.carta-slider {
    position: relative;
    margin: -2rem -2.5rem 2.5rem;
    aspect-ratio: 16 / 7;
    max-height: 420px;
    background: #eee;
    overflow: hidden;
}

/* Scroll nativo con snap en vez de un carro animado a mano con JS: da
   swipe/inercia gratis en móvil (y arrastre con rueda/trackpad en
   escritorio) sin reimplementar gestos táctiles. carta-slider.js solo
   traduce eso a los puntos activos y programa el scroll al pulsar
   flechas/puntos. */
.carta-slider-pista {
    display: flex;
    height: 100%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.carta-slider-pista::-webkit-scrollbar {
    display: none;
}

.carta-slider-diapositiva {
    flex: 0 0 100%;
    height: 100%;
    margin: 0;
    scroll-snap-align: start;
}

.carta-slider-diapositiva img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.carta-slider-flecha {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    cursor: pointer;
    transition: background 160ms var(--ease-out), transform 160ms var(--ease-out);
}

.carta-slider-flecha:hover,
.carta-slider-flecha:focus-visible {
    background: rgba(0, 0, 0, 0.55);
}

.carta-slider-flecha:active {
    transform: translateY(-50%) scale(0.93);
}

.carta-slider-flecha .icono {
    width: 1.3rem;
    height: 1.3rem;
}

.carta-slider-flecha--prev {
    left: 0.85rem;
}

.carta-slider-flecha--next {
    right: 0.85rem;
}

.carta-slider-puntos {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0.85rem;
    display: flex;
    justify-content: center;
    gap: 0.5rem;
}

.carta-slider-punto {
    width: 0.5rem;
    height: 0.5rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.55);
    cursor: pointer;
    transition: background 160ms var(--ease-out), transform 160ms var(--ease-out);
}

.carta-slider-punto[aria-current="true"] {
    background: #fff;
    transform: scale(1.35);
}

/* Página de Reservas: el HTML pegado en Configuración es normalmente un
   <iframe> de ancho fijo del propio agregador (TheFork, CoverManager...) —
   sin este tope se salía del contenedor y aparecía scroll horizontal en
   pantallas estrechas. */
.reservas-contenido iframe,
.reservas-contenido img {
    max-width: 100%;
}

/* Página de Bodega (bodega.php): TODAS las botellas van en un único
   slider, una centrada con la siguiente asomando al lado — mismo scroll
   nativo con snap que .carta-slider (swipe/inercia gratis), pero con la
   botella centrada (scroll-snap-align:center) en vez de a pantalla
   completa, y el padding lateral de la pista es lo que deja "asomar" a las
   vecinas en vez de recortarlas en el borde. Las subcategorías (Blancos,
   Tintos...) son filtros por encima del slider, no sliders separados. */
/* La página entera de la Bodega deja de tener scroll de página: cabecera
   fija arriba, menú de subcategorías fijo justo debajo (primera fila del
   grid de .categoria-bodega, ver más abajo) y buscador fijo abajo (ver
   .bodega-buscador) — la botella en medio ocupa exactamente el hueco que
   sobra entre las tres, ni más ni menos, como una app y no como una web
   con scroll. Solo en esta página (:has detecta .bodega-buscador); la
   carta normal, con su propio scroll de toda la vida, no se toca. */
html:has(.bodega-buscador),
body:has(.bodega-buscador) {
    height: 100%;
    overflow: hidden;
}

.carta:has(.bodega-buscador) {
    height: calc(100dvh - 64px);
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* display:grid con "auto" para el menú de subcategorías y "1fr" para el
   slider en vez de alturas en píxeles adivinadas: si el menú lleva una
   letra mucho más grande (Configuración → Bodega → tamaño de fuente), esa
   fila "auto" crece sola y el slider cede exactamente lo que haga falta,
   sin tener que recalcular nada a mano. grid-row explícito en cada hijo
   (no según el orden en el HTML) porque cuando solo hay una subcategoría
   .bodega-filtros ni siquiera se pinta (ver renderCategoriaBodega en
   CartaRenderer.php) — sin fijarlo, el slider ocuparía él solo la
   primera fila ("auto", la que se ajusta al contenido) en vez de la
   segunda ("1fr", la que reparte el hueco sobrante), perdiendo el
   alto que le toca. */
/* .categoria.categoria-bodega, no solo .categoria-bodega: la regla base
   .categoria (más abajo en el archivo) pone margin-bottom:2.5rem con la
   MISMA especificidad (una sola clase) — por orden de aparición en el
   fichero ganaría ella y volvería el margen que aquí se quita a
   propósito. Encadenar las dos clases sube la especificidad y lo deja a
   salvo del orden. */
.categoria.categoria-bodega {
    display: grid;
    /* minmax(0, 1fr), no "1fr" a secas — el mínimo automático de una pista
       de grid es "auto" (el tamaño de su contenido) salvo que se acote a
       mano: sin el minmax(0, ...), tanto la columna como la fila del
       slider crecían para caber TODAS las botellas puestas en fila (miles
       de píxeles), en vez de quedarse en el ancho/alto real del hueco
       disponible — el típico caso "un scroller horizontal dentro de un
       grid se sale de madre" de CSS Grid. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    flex: 1;
    min-height: 0;
    margin-bottom: 0;
    padding: 0 2.5rem;
    overflow: hidden;
}

/* Antes envolvía en varias líneas centradas; con más de 3-4 subcategorías
   eso empuja el slider de botellas cada vez más abajo. Ahora es una tira
   horizontal deslizable (mismo mecanismo de scroll nativo con snap que
   .bodega-slider-pista) que no crece en alto pase lo que pase. Sin gap ni
   padding lateral: los botones van pegados unos a otros formando una
   cinta continua, no chips sueltos. margin lateral negativo (mismo truco
   de "borde a borde" que .carta-slider) para que llegue a los dos bordes
   de la pantalla pese al padding de .categoria-bodega — el top ya no
   necesita margen negativo: al ser la primera fila del grid, sin padding
   vertical en .categoria-bodega, ya nace pegada a la cabecera fija. */
.bodega-filtros {
    display: flex;
    /* flex-start es el valor SEGURO por defecto (sin él, y sin JS, un
       "justify-content:center" normal deja el primer filtro completamente
       inalcanzable en cuanto los filtros no caben en una línea — probado
       en el propio navegador, no cae solo a flex-start como cabría
       esperar de un "safe centering"). Centrar de verdad solo tiene
       sentido cuando SÍ caben todos en el ancho disponible (el modo
       tablet, más ancho, es el caso típico) — carta-bodega.js añade
       .bodega-filtros--cabe cuando lo comprueba y confirma que no hace
       falta scroll (ver esa clase más abajo). Así, si ese script no
       llegara a ejecutarse (bloqueador de contenido, fallo de red...),
       la página se queda en el estado sin roturas en vez del que puede
       esconder contenido. */
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    grid-row: 1;
    margin: 0 -2.5rem 1rem;
}

/* Ver el comentario de arriba: centrar de verdad solo cuando JS ha
   confirmado que todos los filtros caben sin necesidad de scroll. */
.bodega-filtros.bodega-filtros--cabe {
    justify-content: center;
}

.bodega-filtros::-webkit-scrollbar {
    display: none;
}

.bodega-filtro {
    -webkit-appearance: none;
    appearance: none;
    flex: 0 0 auto;
    scroll-snap-align: start;
    white-space: nowrap;
    padding: 0.85rem 1.6rem;
    /* margin-left negativo (salvo el primero) en vez de gap:0 a secas —
       cada botón conserva su propio borde de 1px, pero se superpone 1px
       con el del vecino y se ve como una única línea compartida, no un
       hueco ni un borde doble. El z-index en :hover/activo evita que ese
       solape esconda el borde resaltado del botón sobre el que estás. */
    margin-left: -1px;
    position: relative;
    border: 1px solid var(--color-secundario, #999);
    border-radius: 0;
    background: none;
    color: var(--color-secundario, #666);
    font: inherit;
    font-size: 1rem;
    font-weight: var(--peso-medio, 600);
    cursor: pointer;
    transition: background-color 140ms ease, color 140ms ease, border-color 140ms ease;
}

.bodega-filtro:first-child {
    margin-left: 0;
}

.bodega-filtro--activo,
.bodega-filtro:hover {
    position: relative;
    z-index: 1;
    background: var(--color-activo);
    border-color: var(--color-activo);
    color: #fff;
}

/* Modo tablet: pastillas sueltas con hueco entre ellas (como en
   linajevalencia.com), no la tira unida de siempre (borde a borde,
   margin-left negativo para compartir el borde con la vecina) — con más
   ancho real disponible ya no hace falta apretarlas para que quepan.
   margin:0 (pisa el -2.5rem/1rem de la regla base): ahora vive dentro de
   .bodega-tablet-cabecera, no como hijo directo de .categoria-bodega, así
   que ya no le toca bandear ella sola hasta los bordes ni separar por
   debajo — lo primero ya no se quiere (el logo necesita su propio hueco a
   la izquierda) y lo segundo lo pone el gap de la cabecera. */
.carta--tablet .bodega-filtros {
    gap: 0.6rem;
    margin: 0;
}

.carta--tablet .bodega-filtro {
    margin-left: 0;
    border-radius: 8px;
    border-width: 1.5px;
    /* Menos relleno que 0.85rem/1.6rem de la regla base — con la cabecera
       ya con su propio alto (logo + margin-top de más abajo), las
       pastillas no necesitan tanto aire propio. Más específica que el
       font-size en px que cada restaurante configura en Apariencia (misma
       clase, pero SIN el .carta--tablet delante), así que gana siempre
       aquí sin necesitar !important. Las dimensiones reales de este modo
       son 1280×800 (no 1200×800) — con ese ancho real y una tipografía de
       trazo regular (serif normal, no condensada), 8-9 subcategorías caben
       con este tamaño y dejan además un margen cómodo antes de necesitar
       deslizar. */
    padding: 0.42rem 0.9rem;
    font-size: 0.98rem;
}

/* Logo arriba-izquierda, filtros llevándose el resto de la fila — sin
   cabecera fija en este modo (ver renderBodega()), es el único sitio
   donde puede ir el logo. Grid de 2 columnas (no flex): la del logo es
   "auto" (su propio ancho de contenido, nunca menos — con "1fr" a los
   1200px reales de este modo, un logo ancho hacía que el algoritmo de
   grid encogiera esa columna por debajo de su contenido, cortándolo). La
   de los filtros es la única "1fr": se lleva todo el hueco que sobra, y
   son los propios filtros (con su scroll horizontal + centrado automático
   ya existente, ver justify-content/--cabe en .bodega-filtros) quienes
   deciden si caben centrados o hace falta deslizar. .bodega-tablet-
   cabecera ocupa la primera fila del grid de .categoria-bodega (la que
   antes ocupaba .bodega-filtros ella sola); margin-top la baja del borde
   superior, que antes quedaba pegada del todo. */
.carta--tablet .bodega-tablet-cabecera {
    grid-row: 1;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 1.25rem;
    margin-top: 1.5rem;
    margin-bottom: 1rem;
    /* Cancela el padding de 2.5rem de .categoria-bodega (bleed a los dos
       bordes reales) y pone en su lugar solo 10px — el logo queda justo a
       esa distancia del borde, no a los 2.5rem que sigue teniendo el
       resto del contenido (slider, etc). */
    margin-left: -2.5rem;
    margin-right: -2.5rem;
    padding-left: 10px;
    padding-right: 10px;
}

/* max-height, no height fija: el logo real de cada restaurante tiene su
   propia proporción (algunos casi cuadrados, otros un rótulo ancho) — con
   max-height a la misma altura que una pastilla de filtro ya calculada
   (0.5rem padding × 2 + ~1.4rem de línea de texto ≈ el resultado de abajo)
   cada uno se encoge a lo ancho que le toque sin desbordar la fila. */
.carta--tablet .bodega-tablet-logo {
    grid-column: 1;
    justify-self: start;
    max-height: 2.4rem;
    width: auto;
}

/* Etiquetas (D.O., uva...) flotando sobre el slider (ver
   CartaRenderer::renderTagsFlotantesBodega()) — sin caja ni fondo propio,
   pedido tal cual ("sin fondo, flotando"). .bodega-slider (su padre en el
   HTML) ya tiene position:relative, así que top/left anclan aquí sin
   necesitar ningún ajuste de más. Empieza oculto (atributo hidden en el
   PHP); carta-bodega.js lo muestra/oculta según haya o no etiquetas que
   ofrecer. */
.bodega-tags-flotantes {
    position: absolute;
    top: 0;
    /* 10px del borde real de la página, no del borde interior de
       .bodega-slider — cancela los 2.5rem de padding de .categoria-bodega
       (su ancestro), mismo criterio de "10px del borde" que ya usan el
       logo y el contador de la cabecera. */
    left: calc(10px - 2.5rem);
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.55rem;
    max-width: 220px;
}

.bodega-tags-flotantes[hidden] {
    display: none;
}

/* Ya no es un botón que abre nada — es el título de este bloque, así que
   aparece y desaparece junto con las etiquetas (mismo hidden de arriba),
   pedido tal cual. */
.bodega-tags-flotantes-titulo {
    margin: 0;
    color: var(--color-secundario, #666);
    font-size: 0.85rem;
    font-weight: var(--peso-medio, 600);
}

/* Columna, no fila con wrap: una etiqueta por línea, pedido tal cual. */
.bodega-tags-flotantes-lista {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.55rem;
}

/* Mismo diseño que los botones de subcategoría de la cabecera (ver
   .carta--tablet .bodega-filtro más arriba): borde fino en
   --color-secundario, sin relleno en reposo, y relleno sólido en
   --color-activo con texto blanco al pasar el ratón o marcar la
   etiqueta — pedido tal cual ("dales el diseño de los botones del
   header"). */
.bodega-tag-flotante {
    -webkit-appearance: none;
    appearance: none;
    border: 1.5px solid var(--color-secundario, #999);
    border-radius: 8px;
    background: none;
    color: var(--color-secundario, #666);
    font: inherit;
    font-size: 1rem;
    font-weight: var(--peso-medio, 600);
    padding: 0.35rem 1.1rem;
    cursor: pointer;
    transition: background-color 100ms ease, border-color 100ms ease, color 100ms ease;
}

.bodega-tag-flotante:hover {
    background: var(--color-activo);
    border-color: var(--color-activo);
    color: #fff;
}

.bodega-tag-flotante--activo {
    background: var(--color-activo);
    border-color: var(--color-activo);
    color: #fff;
}

.bodega-tags-flotantes-reiniciar {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
    padding: 0;
    border: none;
    background: none;
    color: var(--color-activo);
    font: inherit;
    font-size: 0.82rem;
    font-weight: var(--peso-medio, 600);
    text-align: left;
    cursor: pointer;
}

.bodega-tags-flotantes-reiniciar:hover {
    text-decoration: underline;
}

.carta--tablet .bodega-filtros {
    grid-column: 2;
}

/* Modo tablet: el contador ya no vive junto a .bodega-buscador (como
   hermano de la caja) sino DENTRO de .bodega-buscador-caja, después del
   botón "X" (ver CartaRenderer::renderBuscadorBodega()) — un hijo más de
   ese flex, pegado al borde derecho porque el input (flex:1 1 auto, regla
   base) se lleva todo el hueco sobrante antes de llegar a él. Con esto
   .bodega-buscador en sí no necesita ningún ajuste propio en tablet: sigue
   centrando su única caja igual que en modo normal. */
.carta--tablet .bodega-buscador-input {
    /* Más grande que las 0.95rem de la regla base — a 1200px reales hay
       sitio de sobra y se lee mejor. */
    font-size: 1.2rem;
}

/* Mismo contador que en modo normal (ver la regla base más abajo), pero
   con el texto heredado (más grande) en vez del tamaño propio de 0.78rem
   — para no verse enano junto al input recién agrandado a 1.2rem — y un
   pelín menos padding. */
.carta--tablet .bodega-buscador-contador {
    padding: 0.3rem 0.75rem;
    font-size: inherit;
}

.bodega-slider {
    position: relative;
    grid-row: 2;
    min-height: 0;
    height: 100%;
}

.bodega-slider-pista {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    height: 100%;
    gap: 1.5rem;
    /* 25% a cada lado dejan un hueco central del 50% para la botella (ver
       flex-basis:100% más abajo, que se resuelve contra ESTE hueco, no
       contra el ancho total) — suficiente para que asome la vecina a los
       lados (no son un "margen vacío": un flex item nunca se recorta en
       el borde de este padding, solo en el borde real de la pista) — el
       ancho real de la foto lo recupera el "sangrado" del marco (ver
       .bodega-botella-imagen-marco), no este padding. Con el hueco
       centrado (mismo padding a los dos lados), la primera/última botella
       también caen ya centradas en reposo sin tener que forzar el
       scroll. */
    padding: 0 25%;
}

/* Modo tablet (?tablet=1, ver CartaRenderer::renderBodega()): pensado para
   empotrar esta página en un <iframe> de otra web (1200×800). Antes esto
   se intentaba detectar solo con media queries (ancha Y baja a la vez, el
   rango típico de un hueco de iframe), pero eso depende del tamaño REAL
   del navegador que la muestra — abierta suelta en una pestaña normal
   (mucho más alta que 800px) esas media queries nunca se activaban, así
   que la cabecera seguía saliendo y las vecinas se quedaban casi ocultas.
   Con la clase, el servidor decide de una vez (ni pinta la cabecera, ver
   el propio renderBodega — esto de aquí es solo el ajuste de estilos) y
   el resultado es el mismo la mires como la mires. */
/* .carta.carta--tablet:has(.bodega-buscador), no .carta--tablet a secas:
   .carta:has(.bodega-buscador) (más arriba, ver el "sin scroll de
   página") ya pone su propio height:calc(100dvh - 64px) con la MISMA
   especificidad que un simple ".carta--tablet" (dos clases) — a igual
   especificidad gana el orden de aparición en el fichero, no cuál es
   "más nueva" a ojo, así que sin encadenar también :has(...) aquí (que sí
   suma especificidad de verdad) este override podía perder pese a estar
   escrito después. Como el modo tablet solo existe en la Bodega, .carta
   siempre trae bodega-buscador cuando trae carta--tablet — no cambia a
   qué aplica, solo lo deja a salvo del orden. */
.carta.carta--tablet:has(.bodega-buscador) {
    /* Sin la cabecera fija que compensar (renderBodega() ni la pinta en
       este modo), .carta ya no necesita el hueco de 64px arriba. */
    margin-top: 0;
    height: 100dvh;
    /* A todo lo ancho del iframe que la aloje, no limitada a los 900px de
       la carta normal — con más ancho real disponible, la botella y sus
       vecinas tienen más sitio para respirar. */
    max-width: none;
}

.carta--tablet .bodega-slider-pista {
    /* Carriles bastante más estrechos que en el resto de la carta (ver
       .bodega-slider-pista, más abajo, 25% de padding): con 1200px reales
       de ancho hay sitio para que asomen DOS vecinas a cada lado, no solo
       una — carta-bodega.js ya sabe apagar/encoger progresivamente la
       segunda (distancia 2 "slots"), esto es solo lo que deja sitio de
       verdad para que quepan dentro de lo visible. */
    padding: 0 40%;
}

.bodega-slider-pista::-webkit-scrollbar {
    display: none;
}

.bodega-botella {
    flex: 0 0 100%;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Centra el grupo (imagen + nombre + precio + tags + botón) en el alto
       disponible en vez de amontonarlo arriba (flex-start, el valor por
       defecto) — sin esto, todo el hueco que sobra tras el botón se
       acumulaba entero debajo, pegando la botella al menú de arriba. */
    justify-content: center;
    text-align: center;
    /* Sin alto propio: lo hereda por "stretch" (el valor por defecto de
       align-items) del alto real de .bodega-slider-pista, que a su vez
       viene del hueco que le cede el grid de .categoria-bodega — así toda
       la botella (imagen + nombre + precio + tags + botón) cabe siempre
       en lo que sobra de pantalla, sin desbordar ni pedir scroll vertical
       (ver la fila "1fr" en .categoria-bodega, más arriba). */
    /* opacity/transform reales los pone carta-bodega.js en cada frame de
       scroll (botella centrada = normal, vecinas = 50% opacidad y 80% de
       tamaño) — estos son solo el valor de reserva antes de que corra el
       JS o si llegara a fallar. transform-origin:center para que el
       encogido no desplace la botella hacia un lado. */
    opacity: 1;
    transform: scale(1);
    transform-origin: center;
}

/* display:flex de arriba (origen "autor") gana por defecto sobre el
   display:none de [hidden] del navegador (origen "user agent") pese a que
   ambos tengan la misma especificidad — igual que .modal-ficha-vino[open]
   más abajo, hay que forzarlo a mano para que los filtros puedan ocultar
   botellas de verdad. */
.bodega-botella[hidden] {
    display: none;
}

/* flex:0 1 auto, NO flex:1 1 auto — con grow:1 el marco absorbía TODO el
   hueco sobrante del slider (ver la fila "1fr" de .categoria-bodega) aunque
   la foto no lo necesitara, así que en pantallas altas el nombre/precio
   quedaban muy separados de la botella (el hueco sobrante quedaba metido
   DENTRO del marco, debajo de la foto). Con grow:0 el marco solo pide el
   alto real de la foto — nombre/precio/tags/botón la siguen pegados — y el
   sobrante se va entero al final, después del botón, donde no se nota (es
   solo aire antes del buscador). min-height:0 sigue siendo imprescindible
   con shrink:1: sin él, un flex-item en columna no se encoge nunca por
   debajo del alto natural de su contenido y la imagen desbordaría en
   pantallas bajas — con él, si el hueco total no alcanza, el marco (y la
   foto dentro, gracias a max-height:100% + object-fit:contain) se encoge
   en vez de desbordar. */
/* width:150% + margin-left:-25% (no width:100%): .bodega-botella ahora es
   más estrecha que antes (70% de la pista, no 100% del hueco — ver
   .bodega-slider-pista) para dejar sitio a que asome la vecina a los
   lados, pero eso encogía de paso la foto, que ya no llegaba a ocupar el
   alto disponible (se quedaba corta de ancho antes que de alto). El marco
   "se sale" de su propia botella hacia los dos lados por igual (150% de
   ancho, centrado) para recuperar el tamaño real de foto de antes sin
   tener que ensanchar la botella entera (que volvería a tapar a la
   vecina) — como la vecina, a esa distancia, ya está bastante reducida y
   con la mitad de opacidad, un ligero solape con el borde de su silueta
   no se nota.
   align-self:flex-start (no el align-items:center que hereda de
   .bodega-botella): con un ancho mayor que el propio padre, el
   align-items del padre centra la caja "de fuera hacia dentro" contando
   el margin-left NEGATIVO como si redujera el tamaño total a centrar, y
   el resultado queda desplazado a la izquierda en vez de centrado de
   verdad — con align-self:flex-start el margin-left manda solo (posición
   = borde del padre + margin-left), sin ese doble cálculo. */
.bodega-botella-imagen-marco {
    position: relative;
    flex: 0 1 auto;
    min-height: 0;
    width: 150%;
    margin-left: -25%;
    display: flex;
    align-items: flex-start;
    align-self: flex-start;
    justify-content: center;
    margin-bottom: 0.75rem;
}

/* Centrada de verdad sobre la foto (no sobre el marco, que es 150% más
   ancho que la propia botella para dejar asomar a la vecina, ver el
   comentario de arriba): 50%+transform en vez de top/left fijos, así el
   centrado no depende de medir nada a mano y sigue centrado pase lo que
   pase con el tamaño real de la foto (recortada, sin foto, distintas
   proporciones...). */
.bodega-botella-agotado {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) rotate(-8deg);
    z-index: 1;
    padding: 0.55rem 1.4rem;
    border-radius: 999px;
    background: #fef3c7;
    color: #92400e;
    font-size: 1.15rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
}

/* La foto se apaga (no se oculta ni se recorta) para que se note de un
   vistazo que ese vino no está disponible sin dejar de reconocerse cuál
   es — mismo criterio que un producto agotado en una tienda online. */
.bodega-botella--agotado .bodega-botella-imagen,
.bodega-botella--agotado .bodega-botella-imagen--vacia {
    filter: grayscale(0.6) opacity(0.55);
}

/* width Y height en auto, con max-width Y max-height a la vez (no una
   altura fija ni al 100%): el navegador calcula solo el tamaño más grande
   que cabe en las dos direcciones sin deformar la proporción real de la
   foto (recortada a 400×600 desde el admin, ver ImagenProcesador::
   recortarLateral) — así funciona tanto si el ancho manda (pantallas
   estrechas) como si manda el alto (el marco de arriba, que ahora sí
   tiene un tope real). Fijar SOLO una de las dos (un alto fijo en vh, o
   forzar height:100% aquí) fue justo el bug ya resuelto dos veces esta
   sesión: crea una caja con proporción distinta a la de la imagen y dejaba
   margen vacío alrededor en vez de aprovecharlo. */
.bodega-botella-imagen {
    display: block;
    width: auto;
    height: auto;
    max-width: min(420px, 100%);
    max-height: 100%;
    object-fit: contain;
}

/* Mismo criterio que la imagen real de arriba (width/height en auto,
   max-width Y max-height a la vez) para que el hueco que deja una botella
   sin foto coincida exactamente con el que ocuparía una CON foto — con
   aspect-ratio 2/3 (la misma proporción 400×600 del recorte) en vez de un
   tamaño fijo, el navegador calcula solo cuál de las dos cotas manda. */
.bodega-botella-imagen--vacia {
    width: auto;
    height: auto;
    max-width: min(420px, 100%);
    max-height: 100%;
    aspect-ratio: 2 / 3;
    border-radius: 8px;
    background: color-mix(in srgb, var(--color-secundario, #999) 12%, transparent);
}

.bodega-botella-nombre {
    font-weight: var(--peso-fuerte, 700);
    font-size: 1.35rem;
    line-height: 1.3;
}

.bodega-botella-precio {
    font-size: 1.1rem;
    font-weight: var(--peso-medio, 600);
    margin-top: 0.4rem;
}

.bodega-botella-tags {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem;
    margin-top: 0.5rem;
}

.bodega-botella-tag {
    font-size: 0.75rem;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-secundario, #999) 14%, transparent);
    color: var(--color-secundario, #666);
}

/* Más pequeño que antes (menos padding, letra más chica) y con más
   carácter: relleno del color de acento en vez de solo el contorno, con
   una sombra suave a juego y un pequeño "hundido" al pulsar (transform
   scale) para que se note que ha respondido al toque — no un simple
   cambio de color en :hover, que en móvil (sin ratón) nunca se ve. */
.bodega-botella-boton {
    -webkit-appearance: none;
    appearance: none;
    margin-top: 1rem;
    padding: 0.45rem 1.3rem;
    border: 1px solid var(--color-activo);
    border-radius: 999px;
    background: var(--color-activo);
    color: #fff;
    font: inherit;
    font-size: 0.82rem;
    font-weight: var(--peso-medio, 600);
    cursor: pointer;
    box-shadow: 0 3px 10px color-mix(in srgb, var(--color-activo) 35%, transparent);
    transition: transform 140ms var(--ease-out), box-shadow 140ms ease, background-color 140ms ease;
}

.bodega-botella-boton:hover {
    background: color-mix(in srgb, var(--color-activo) 88%, black);
}

.bodega-botella-boton:active {
    transform: scale(0.95);
    box-shadow: 0 1px 4px color-mix(in srgb, var(--color-activo) 35%, transparent);
}

.bodega-slider-flecha {
    position: absolute;
    top: 40%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.3rem;
    height: 2.3rem;
    border: 1px solid #eee;
    border-radius: 50%;
    background: #fff;
    color: #333;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    transition: background 160ms var(--ease-out), transform 160ms var(--ease-out);
}

.bodega-slider-flecha:hover,
.bodega-slider-flecha:focus-visible {
    background: #f5f5f5;
}

.bodega-slider-flecha:active {
    transform: translateY(-50%) scale(0.93);
}

.bodega-slider-flecha .icono {
    width: 1.15rem;
    height: 1.15rem;
}

.bodega-slider-flecha--prev {
    left: 0.25rem;
}

.bodega-slider-flecha--next {
    right: 0.25rem;
}

/* Barra de búsqueda de la Bodega: último hijo del flex-column de .carta
   (ver más arriba), no position:fixed — con la página entera sin scroll y
   .carta a la altura exacta del viewport, quedarse como último elemento
   normal del flujo la deja pegada abajo igual de bien que fixed, pero sin
   tener que adivinar su alto para reservarle hueco aparte (si el texto
   del placeholder ocupa dos líneas en una pantalla muy estrecha, por
   ejemplo, el hueco se ajusta solo). Filtra las botellas ya pintadas en
   la página sin ir al servidor (ver carta-bodega.js), así que no hay
   ningún estado de carga que mostrar. */
/* Sin fondo/blur propio: .carta (su contenedor) ya es blanco sólido y
   .bodega-buscador es su último hijo normal del flujo, no algo flotando
   ENCIMA de contenido — el blur semitransparente de antes solo dejaba ver
   un ligero cambio de tono (el blanco al 85% mezclado con lo que hubiera
   detrás) que se leía como una caja de más, no como parte de la página. */
.bodega-buscador {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 0.85rem 1rem calc(0.85rem + env(safe-area-inset-bottom, 0px));
}

/* Contador "X de Y" (carta-bodega.js lo mantiene al día con la botella
   centrada del slider): vive DENTRO de la propia caja de búsqueda, al
   final del todo, después del botón "X" (ver
   CartaRenderer::renderBuscadorBodega()) — mismo sitio en los dos modos.
   flex-shrink:0: nunca se encoge para dejarle sitio al input, aunque el
   texto de búsqueda sea largo. [hidden] hasta que el JS calcula el primer
   valor real. */
.bodega-buscador-contador {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 0.35rem;
    margin: 0;
    padding: 0.3rem 0.85rem;
    border: 1.5px solid var(--color-activo);
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-secundario, #999) 14%, transparent);
    color: var(--color-activo);
    font-size: 0.78rem;
    font-weight: var(--peso-medio, 600);
    white-space: nowrap;
    opacity: 0.8;
}

.bodega-buscador-contador[hidden] {
    display: none;
}

.bodega-buscador-contador .icono {
    width: 0.85rem;
    height: 0.85rem;
    flex-shrink: 0;
}

.bodega-buscador-contador strong {
    font-weight: var(--peso-fuerte, 700);
    /* tabular-nums: al pasar de botella en botella el primer número
       cambia de ancho (1, 12...) — sin esto la pastilla entera "tiembla"
       de ancho en cada swipe en vez de quedarse quieta. */
    font-variant-numeric: tabular-nums;
}

.bodega-buscador-caja {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    max-width: 480px;
    padding: 0.7rem 1.15rem;
    border-radius: 999px;
    background: #fff;
    border: 1.5px solid color-mix(in srgb, var(--color-activo) 20%, transparent);
    box-shadow: 0 4px 16px color-mix(in srgb, var(--color-activo) 10%, transparent);
    transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms var(--ease-out);
}

.bodega-buscador-caja:focus-within {
    border-color: var(--color-activo);
    box-shadow: 0 4px 20px color-mix(in srgb, var(--color-activo) 24%, transparent);
    transform: scale(1.015);
}

@media (prefers-reduced-motion: reduce) {
    .bodega-buscador-caja {
        transition: border-color 140ms ease, box-shadow 140ms ease;
    }

    .bodega-buscador-caja:focus-within {
        transform: none;
    }
}

.bodega-buscador-caja > .icono {
    flex: 0 0 auto;
    width: 1.1rem;
    height: 1.1rem;
    color: var(--color-activo);
}

.bodega-buscador-input {
    flex: 1 1 auto;
    min-width: 0;
    border: none;
    outline: none;
    background: none;
    font: inherit;
    font-size: 0.95rem;
    color: #222;
}

.bodega-buscador-input::placeholder {
    color: color-mix(in srgb, var(--color-secundario, #999) 80%, transparent);
}

/* Quita la lupa/aspa nativas de type="search" en Chrome/Safari — ya
   ponemos las nuestras (icono fijo a la izquierda, botón propio a la
   derecha) a juego con el resto de la Bodega, no las del navegador. */
.bodega-buscador-input::-webkit-search-decoration,
.bodega-buscador-input::-webkit-search-cancel-button {
    display: none;
}

.bodega-buscador-limpiar {
    -webkit-appearance: none;
    appearance: none;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-secundario, #999) 15%, transparent);
    color: var(--color-secundario, #666);
    cursor: pointer;
    transition: background-color 140ms ease, color 140ms ease;
}

.bodega-buscador-limpiar:hover {
    background: var(--color-activo);
    color: #fff;
}

.bodega-buscador-limpiar .icono {
    width: 0.7rem;
    height: 0.7rem;
}

.bodega-buscador-limpiar[hidden] {
    display: none;
}

.bodega-buscador-vacio {
    margin: 0;
    font-size: 0.82rem;
    color: var(--color-secundario, #666);
    text-align: center;
}

.bodega-buscador-vacio[hidden] {
    display: none;
}

/* Ficha del vino (modal-ficha-vino en carta-bodega.js): mismo mecanismo
   que .modal-foto (native <dialog>, showModal()/close()). Sin la foto de
   la botella — ya se ve grande en el slider de detrás, justo debajo del
   botón que abre esta ficha — así que aquí todo el espacio es para el
   texto: nombre/precio/tags y el acordeón, con más aire y letra más
   grande que antes. */
.modal-ficha-vino {
    border: none;
    border-radius: 16px;
    padding: 0;
    width: min(560px, calc(100% - 2rem));
    /* height fijo, no max-height: al abrir/cerrar una sección del acordeón
       cambia cuánto contenido hay dentro, y un <dialog> nativo se recentra
       en la pantalla cada vez que cambia de alto (por el margin:auto de la
       hoja de estilos del navegador) — con solo un tope (max-height) se
       veía la ficha entera subir y bajar de golpe con cada clic. Con un
       alto fijo, la caja no se mueve nunca; lo que no cabe hace scroll
       dentro de .modal-ficha-vino-info (overflow-y:auto de abajo). */
    height: min(560px, calc(100% - 3rem));
    overflow: hidden;
    background: #fff;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
    opacity: 1;
    transform: scale(1);
    transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out), overlay 200ms allow-discrete, display 200ms allow-discrete;
}

/* display SOLO cuando [open] (showModal() lo añade) — igual que
   .carta-menu[open]: un <dialog> cerrado ya es display:none por la hoja de
   estilos del navegador, y ponerlo sin condicionar a [open] en la regla de
   arriba anulaba eso, dejando la ficha (vacía) ocupando sitio en la página
   desde que carga, antes de abrirla nunca. */
.modal-ficha-vino[open] {
    display: flex;
    flex-direction: column;
}

@starting-style {
    .modal-ficha-vino[open] {
        opacity: 0;
        transform: scale(0.95);
    }
}

/* Foto de la botella dentro de la ficha: solo en modo tablet (ver más
   abajo) — fuera de tablet la ficha se abre encima de la propia botella,
   ya grande en el slider de detrás, así que no hace falta repetirla
   aquí. El elemento vive siempre en el DOM (lo rellena carta-bodega.js
   igual en los dos modos) para no duplicar el <dialog> entero por esto. */
.modal-ficha-vino-imagen {
    display: none;
}

/* Ficha de dos columnas (foto a la izquierda, texto a la derecha) como
   en linajevalencia.com — más ancha que la ficha de una sola columna de
   siempre para que la foto tenga sitio de verdad sin dejar el texto
   apretado. */
.carta--tablet .modal-ficha-vino {
    width: min(920px, calc(100% - 4rem));
    height: min(620px, calc(100% - 3rem));
}

.carta--tablet .modal-ficha-vino[open] {
    flex-direction: row;
}

.carta--tablet .modal-ficha-vino-imagen {
    display: block;
    flex: 0 0 40%;
    width: 100%;
    height: 100%;
    /* contain, no cover: las fotos ya vienen recortadas 2:3 desde el
       admin (ImagenProcesador::recortarLateral) — cover recortaría de
       más si el hueco no encaja exacto en esa proporción; contain
       siempre enseña la botella entera, como el resto de la Bodega. */
    object-fit: contain;
    background: #f4f4f2;
}

.modal-ficha-vino::backdrop {
    background: rgba(20, 16, 15, 0.7);
    opacity: 1;
    transition: opacity 200ms var(--ease-out), display 200ms allow-discrete, overlay 200ms allow-discrete;
}

@starting-style {
    .modal-ficha-vino[open]::backdrop {
        opacity: 0;
    }
}

.modal-ficha-vino-info {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* padding-top de sobra para que el botón cerrar (position:absolute,
       arriba a la derecha) nunca se monte sobre el nombre — antes ese
       margen lo daba la foto de la botella, que ya no está. */
    padding: 3rem 1.1rem 1.5rem;
    color: #111;
}

/* min-width:0 — en modo tablet .modal-ficha-vino-info pasa a ser un
   hijo en fila (junto a la foto, no encima), mismo motivo de siempre:
   sin esto un flex-item nunca se encoge por debajo del ancho de su
   propio contenido y podía forzar overflow horizontal en la ficha. */
.carta--tablet .modal-ficha-vino-info {
    min-width: 0;
    padding: 2rem 1.75rem 1.75rem;
}

/* Mismo par de colores que .bodega-botella-agotado (ver más abajo) — un
   color fijo, no uno derivado de la marca del restaurante (--color-activo):
   "agotado" es un aviso, no parte de la identidad visual de la carta. */
.modal-ficha-vino-agotado {
    display: inline-block;
    margin: 0 0 0.6rem;
    padding: 0.25rem 0.7rem;
    border-radius: 999px;
    background: #fef3c7;
    color: #92400e;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.modal-ficha-vino-agotado[hidden] {
    display: none;
}

.modal-ficha-vino-nombre {
    margin: 0 0 0.5rem;
    font-size: 1.65rem;
    font-weight: 700;
    line-height: 1.25;
}

.modal-ficha-vino-precio {
    margin: 0 0 0.9rem;
    font-size: 1.2rem;
    font-weight: var(--peso-medio, 600);
    color: var(--color-secundario, #666);
}

.modal-ficha-vino-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1.1rem;
}

.modal-ficha-vino-tags[hidden] {
    display: none;
}

.modal-ficha-vino-tag {
    font-size: 0.85rem;
    padding: 0.3rem 0.8rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-secundario, #999) 14%, transparent);
    color: var(--color-secundario, #666);
}

/* Acordeón de la ficha (Información, Elaboración, Ficha de cata...): un
   número variable de <details> construidos en carta-bodega.js a partir del
   JSON de data-vino-secciones — nativo, sin JS propio para abrir/cerrar.
   Antes era una lista con líneas finas entre secciones y un "+/-" de
   texto; ahora cada sección es su propia tarjeta (fondo + esquinas
   redondeadas), y en vez de cambiar de símbolo de golpe, la flecha en su
   círculo gira al abrir/cerrar — se distingue mejor de un vistazo con
   varias secciones y se ve más cuidado. */
.modal-ficha-vino-acordeon {
    margin-top: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.65rem;
}

.modal-ficha-vino-acordeon details {
    border-radius: 10px;
    background: #faf8f6;
    overflow: hidden;
}

.modal-ficha-vino-acordeon details[open] {
    background: color-mix(in srgb, var(--color-activo) 6%, #faf8f6);
}

.modal-ficha-vino-acordeon summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 1rem 0.85rem;
    font-weight: var(--peso-fuerte, 700);
    font-size: 1.08rem;
    cursor: pointer;
    list-style: none;
    /* Sin esto, Chrome/Safari de móvil pintan un rectángulo azul
       semitransparente encima del summary un instante al tocarlo (el
       resaltado táctil por defecto) — con el cambio de sección de más
       arriba (name compartido) eso se veía como un "flash" azul cada vez
       que se abría una sección nueva. */
    -webkit-tap-highlight-color: transparent;
}

.modal-ficha-vino-acordeon summary:focus-visible {
    outline: 2px solid var(--color-activo);
    outline-offset: -2px;
}

.modal-ficha-vino-acordeon summary::-webkit-details-marker {
    display: none;
}

.modal-ficha-vino-acordeon details[open] summary {
    color: var(--color-activo);
}

/* Flecha en su propio círculo — dos elementos, no uno: el círculo de
   fondo (el span) y la propia flecha (su ::after, dos bordes en ángulo
   rotados 45°) van por separado a propósito. Antes la flecha era un
   carácter de texto (›) rotado con CSS — un glifo de fuente no es
   perfectamente simétrico respecto a su propio centro, así que al
   rotarlo se veía descentrado dentro del círculo, y además cambiaba
   según la fuente elegida por cada restaurante. Una flecha hecha de
   bordes (geometría pura, no tipografía) siempre queda centrada igual,
   sin depender de ninguna fuente. */
.modal-ficha-vino-acordeon-flecha {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-activo) 12%, transparent);
    transition: transform 200ms var(--ease-out), background-color 200ms ease;
}

.modal-ficha-vino-acordeon-flecha::after {
    content: "";
    /* -1px: el propio grosor del borde (2px) desplaza el centro visual
       del "gancho" ligeramente respecto al cuadrado que lo genera —
       este ajuste, a diferencia del que hacía falta con el glifo de
       texto, es fijo y geométrico (siempre los mismos 2px de borde), no
       depende de ninguna fuente ni cambia entre restaurantes. */
    width: 0.5rem;
    height: 0.5rem;
    margin-top: -0.15rem;
    border-right: 2px solid var(--color-activo);
    border-bottom: 2px solid var(--color-activo);
    transform: rotate(45deg);
}

.modal-ficha-vino-acordeon details[open] .modal-ficha-vino-acordeon-flecha {
    transform: rotate(180deg);
}

/* El contenido de cada sección llega como HTML ya saneado (mismo editor y
   mismo saneado que .plato-descripcion, ver CartaRenderer::
   sanitizarDescripcion() y carta-bodega.js) — puede traer <p>/<ul>/<ol>,
   no solo texto plano, así que estas reglas cubren esos casos igual que
   .plato-descripcion en vez de asumir un único párrafo. */
.modal-ficha-vino-acordeon-contenido {
    padding: 0 0.85rem 1.15rem;
    font-size: 0.98rem;
    line-height: 1.6;
    color: #333;
}

.modal-ficha-vino-acordeon-contenido p,
.modal-ficha-vino-acordeon-contenido ul,
.modal-ficha-vino-acordeon-contenido ol {
    margin: 0.4rem 0;
    padding-left: 1.25rem;
}

.modal-ficha-vino-acordeon-contenido p {
    padding-left: 0;
}

.modal-ficha-vino-acordeon-contenido p:first-child,
.modal-ficha-vino-acordeon-contenido ul:first-child,
.modal-ficha-vino-acordeon-contenido ol:first-child {
    margin-top: 0;
}

.modal-ficha-vino-acordeon-contenido p:last-child,
.modal-ficha-vino-acordeon-contenido ul:last-child,
.modal-ficha-vino-acordeon-contenido ol:last-child {
    margin-bottom: 0;
}

.modal-ficha-vino-acordeon-contenido li {
    margin-bottom: 0.15rem;
}

.modal-ficha-vino-cerrar {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 1;
    background: rgba(0, 0, 0, 0.5);
    border: none;
    color: #fff;
    font-size: 1.8rem;
    line-height: 1;
    padding: 0.2rem 0.6rem;
    cursor: pointer;
    border-radius: 6px;
    transition: background-color 140ms ease;
}

.modal-ficha-vino-cerrar:hover {
    background: rgba(0, 0, 0, 0.75);
}

@media (max-width: 480px) {
    .bodega-slider-pista {
        gap: 1rem;
    }

    .bodega-slider-flecha {
        width: 2rem;
        height: 2rem;
    }

    /* Mismo motivo que .carta-slider en este breakpoint: menos padding
       lateral en pantallas estrechas, así que el margen negativo de
       .bodega-filtros (que debe llegar a los dos bordes) tiene que
       encogerse a juego. .categoria.categoria-bodega, no solo
       .categoria-bodega: la regla base de más arriba ya usa el selector
       compuesto (dos clases) para ganarle a .categoria por especificidad,
       así que este override necesita la misma especificidad o pierde
       pese a estar dentro de un @media más específico en apariencia (los
       @media no suman especificidad). */
    .categoria.categoria-bodega {
        padding: 0 0.75rem;
    }

    .bodega-filtros {
        margin: 0 -0.75rem 1rem;
    }
}

.categoria {
    margin-bottom: 2.5rem;
    /* Igual que .subcategoria: sin esto, un salto desde el menú de
       categorías (o cualquier futuro enlace a #categoria-N) deja el
       título tapado bajo la cabecera fija (64px). */
    scroll-margin-top: 64px;
}

.categoria:last-child {
    margin-bottom: 0;
}

/* Envuelve el título de categoría junto a su imagen opcional
   (.categoria-imagen): el borde inferior vive aquí (no en .categoria-titulo)
   para que quede debajo de los dos, no solo del texto. position:relative +
   z-index:0 abre un contexto de apilamiento propio (mismo motivo que
   .plato/.plato-grupo) para que el z-index negativo de .categoria-imagen
   quede contenido aquí dentro, pintándose detrás del título en vez de
   escaparse a competir con otras categorías. overflow:hidden recorta la
   imagen a los bordes de la cabecera. */
.categoria-cabecera {
    position: relative;
    z-index: 0;
    overflow: hidden;
    display: flex;
    align-items: center;
    min-height: 4.5rem;
    gap: 0.6rem;
    border-bottom: 1px solid var(--color-activo);
    padding: 0.75rem 0 0.5rem;
    margin: 0 0 1.25rem;
}

.categoria-titulo {
    font-size: 1.75rem;
    font-weight: var(--peso-fuerte, 700);
    color: var(--color-activo);
}

/* Imagen opcional de categoría a modo de fondo de la cabecera: pegada al
   borde derecho (posicionada respecto a .categoria-cabecera), ocupando la
   mitad de la fila. Mismo mecanismo que .plato-foto-fondo pero en espejo
   (degradado hacia la izquierda en vez de hacia la derecha) y sin botón ni
   modal de zoom — aquí es solo un fondo decorativo, no la protagonista de
   una ficha clicable. */
.categoria-imagen {
    position: absolute;
    inset: 0 0 0 auto;
    width: 50%;
    border-radius: 0;
    object-fit: cover;
    -webkit-mask-image: linear-gradient(to left, rgba(0, 0, 0, 1) 15%, rgba(0, 0, 0, 0) 88%);
    mask-image: linear-gradient(to left, rgba(0, 0, 0, 1) 15%, rgba(0, 0, 0, 0) 88%);
    z-index: -1;
}

.subcategorias[data-acordeon] {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.subcategoria {
    border-radius: var(--radio-acordeon, 8px);
    /* Sin esto, el scrollIntoView() de acordeon.js deja el título de la
       subcategoría justo debajo del header fijo (64px), tapado por él. */
    scroll-margin-top: 64px;
}

.subcategoria summary {
    list-style: none;
    cursor: pointer;
}

.subcategoria summary::-webkit-details-marker {
    display: none;
}

.subcategoria-titulo {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 0.85rem;
    min-height: 56px;
    padding: 1.15rem 1.5rem;
    background: var(--color-cerrado);
    color: #fff;
    font-weight: var(--peso-fuerte, 700);
    font-size: 1.05rem;
    border-radius: var(--radio-acordeon, 8px);
    /* Al abrirse, este título queda fijo arriba mientras se hace scroll por
       sus platos, hasta llegar al final de esta subcategoría (el propio
       <details> es el límite del "containing block" de la sticky). top
       coincide con la altura del header fijo (64px) para que se pare justo
       debajo de él, no debajo tapado por él. */
    position: sticky;
    top: 64px;
    z-index: 2;
    transition: border-radius 200ms var(--ease-in-out), margin 200ms var(--ease-in-out), padding 200ms var(--ease-in-out);
}

/* El nombre de la subcategoría es un <h3> real (antes un <span> sin más,
   ver CartaRenderer::renderSubcategoria) — para SEO/accesibilidad, no por
   estética: visualmente debe seguir viéndose exactamente igual que el
   resto de .subcategoria-titulo (icono + texto en una fila), así que se
   le quita todo el estilo por defecto del navegador (margen, negrita y
   tamaño propios de un h3) y hereda del contenedor flex en su lugar. */
.subcategoria-titulo h3 {
    margin: 0;
    font: inherit;
    color: inherit;
}

/* Activa (abierta): a todo lo ancho, igual que la cabecera fija (.carta-header),
   en vez del ancho normal recortado por el padding lateral de .carta — margin
   negativo igual a ese padding la saca hasta el borde, y el mismo valor
   vuelve como padding para que el texto no quede pegado al borde. Sin
   cantos redondeados, a juego con ese "borde a borde". Al cerrarse (sin
   [open]) recupera su ancho y radio normales, definidos arriba. */
.subcategoria[open] .subcategoria-titulo {
    background: var(--color-activo);
    border-radius: 0;
    margin-left: -2.5rem;
    margin-right: -2.5rem;
    padding-left: 2.5rem;
    padding-right: 2.5rem;
}

.subcategoria-icono {
    font-size: 1.3rem;
    line-height: 1;
    font-weight: var(--peso-fuerte, 700);
    flex: 0 0 auto;
}

.subcategoria-icono::before {
    content: '+';
}

.subcategoria[open] .subcategoria-icono::before {
    content: '\2212';
}

/* Icono/imagen opcional de subcategoría: mismo tratamiento que
   .categoria-imagen (miniatura circular, sin fundido ni modal), un poco
   más pequeña para caber cómoda en la fila de 56px de min-height. */
.subcategoria-imagen {
    flex: 0 0 auto;
    width: 1.9rem;
    height: 1.9rem;
    border-radius: 50%;
    object-fit: cover;
}

/* Truco de animación de altura con CSS puro: el wrapper es un grid de una
   fila cuyo alto (0fr↔1fr) se anima; acordeon.js dispara el cambio y
   controla el momento exacto de poner/quitar el atributo [open]. */
.platos-wrapper {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 320ms var(--ease-in-out);
    overflow-anchor: none;
}

.platos-wrapper > .platos {
    overflow: hidden;
    min-height: 0;
}

.platos {
    padding: 1rem 0.25rem 0.25rem;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.plato,
.plato-grupo {
    position: relative;
    /* z-index (no solo position:relative) es lo que de verdad abre un
       contexto de apilamiento propio: sin él, el z-index:-1 de
       .plato-foto-fondo no queda contenido aquí dentro y "se escapa" a
       competir con hermanos fuera de esta ficha (otro .plato, el fondo de
       la página...), quedando la foto tapada por completo en vez de solo
       detrás de su propio texto. */
    z-index: 0;
    background: #fff;
    border-radius: 6px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
    padding: 0.9rem 1.1rem;
    /* overflow:hidden recorta la foto de fondo (si la hay) a las esquinas
       redondeadas de la ficha; no afecta al box-shadow, que se pinta fuera
       de la propia caja. */
    overflow: hidden;
}

/* Foto del plato a modo de fondo: pegada al borde izquierdo de la ficha
   (posicionada respecto a .plato/.plato-grupo, que son overflow:hidden y
   position:relative), sin recorte propio ni radio — el de la ficha ya la
   recorta. Un degradado (mask-image) la desvanece a alfa 0 antes de llegar
   al texto, así que no hace falta un borde duro entre foto y contenido. */
.plato-foto-fondo {
    position: absolute;
    inset: 0 auto 0 0;
    width: 100px;
    border: none;
    padding: 0;
    margin: 0;
    cursor: zoom-in;
    background: none;
    -webkit-appearance: none;
    appearance: none;
    /* Negativo (no solo 0): dentro del mismo contexto de apilamiento que
       crea position:relative en .plato, así pinta por debajo del texto —
       que es contenido normal, sin position — en vez de encima, que es
       donde iría un elemento position:absolute por defecto. Sin esto el
       texto quedaría tapado por la foto en la zona donde ahora se pisan. */
    z-index: -1;
}

.plato-foto-fondo img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    -webkit-mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 15%, rgba(0, 0, 0, 0) 88%);
    mask-image: linear-gradient(to right, rgba(0, 0, 0, 1) 15%, rgba(0, 0, 0, 0) 88%);
}

/* El texto arranca al 60% de la foto (60px de sus 100px de ancho), montado
   sobre la parte que ya se está desvaneciendo (ver mask-image de arriba)
   en vez de dejar la foto y el texto sin tocarse. Se superponen a
   propósito — el z-index negativo de .plato-foto-fondo es lo que hace que
   el texto (contenido normal, sin position) se pinte por encima. */
.plato:has(.plato-foto-fondo),
.plato-grupo:has(.plato-foto-fondo) {
    padding-left: 60px;
}
/* Hueco extra abajo SOLO cuando hay número de alérgenos (ahora clavado en
   la esquina, fuera del flujo normal): sin esto, una descripción larga
   podría terminar su última línea justo debajo del número. */
.plato:has(.plato-alergenos) {
    padding-bottom: 1.5rem;
}

.plato-cabecera {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
}

.plato-titulo {
    font-weight: var(--peso-fuerte, 700);
    color: #000;
    flex: 1 1 auto;
    min-width: 0;
}

.plato-puntos {
    flex: 1 1 auto;
    min-width: 0.75rem;
    border-bottom: 1px dotted #999;
    transform: translateY(-4px);
}

.plato-precio {
    font-weight: var(--peso-medio, 600);
    white-space: nowrap;
    color: #000;
    flex: 0 0 auto;
}

.plato-descripcion {
    display: block;
    color: var(--color-secundario);
    font-style: italic;
    font-size: 0.9rem;
    margin-top: 0.3rem;
}

.plato-descripcion p,
.plato-descripcion ul,
.plato-descripcion ol {
    margin: 0.4rem 0;
    padding-left: 1.25rem;
}

.plato-descripcion p {
    padding-left: 0;
}

.plato-descripcion p:first-child,
.plato-descripcion ul:first-child,
.plato-descripcion ol:first-child {
    margin-top: 0;
}

.plato-descripcion p:last-child,
.plato-descripcion ul:last-child,
.plato-descripcion ol:last-child {
    margin-bottom: 0;
}

.plato-descripcion li {
    margin-bottom: 0.15rem;
}

/* Pegado a la esquina inferior derecha de la ficha (no en su propia línea
   a lo ancho) para que lea como una marca discreta de la ficha, no como
   una línea más de contenido. */
.plato-alergenos {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    right: 0.4rem;
    bottom: 0.3rem;
    display: block;
    width: auto;
    background: none;
    border: none;
    padding: 0;
    text-align: right;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    font: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    color: #666;
    margin-top: 0;
    cursor: pointer;
}

.plato-alergenos:hover {
    color: var(--color-activo);
}

.plato-grupo-titulo {
    display: flex;
    align-items: baseline;
    font-weight: var(--peso-fuerte, 700);
    color: #000;
}

.plato-grupo-titulo::after {
    content: '';
    display: inline-block;
    flex: 1;
    margin: 0 0.5rem;
    border-bottom: 1px dotted #999;
    transform: translateY(-4px);
}

.variante {
    position: relative;
    padding: 0.35rem 0 0.35rem 0.75rem;
    border-top: 1px solid #eee;
}

.variante:has(.variante-alergenos) {
    padding-bottom: 1.2rem;
}

.variante:first-child {
    border-top: none;
}

.variante-cabecera {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
}

.variante-nombre {
    font-weight: var(--peso-medio, 600);
    color: #000;
    flex: 1 1 auto;
    min-width: 0;
}

.variante-puntos {
    flex: 1 1 auto;
    min-width: 0.75rem;
    border-bottom: 1px dotted #ccc;
    transform: translateY(-4px);
}

.variante-precio {
    font-weight: var(--peso-medio, 600);
    white-space: nowrap;
    color: #000;
    flex: 0 0 auto;
}

.variante-descripcion {
    display: block;
    color: var(--color-secundario);
    font-style: italic;
    font-size: 0.85rem;
    margin-top: 0.15rem;
}

.variante-descripcion p,
.variante-descripcion ul,
.variante-descripcion ol {
    margin: 0.3rem 0;
    padding-left: 1.1rem;
}

.variante-descripcion p {
    padding-left: 0;
}

.variante-descripcion p:first-child,
.variante-descripcion ul:first-child,
.variante-descripcion ol:first-child {
    margin-top: 0;
}

.variante-descripcion p:last-child,
.variante-descripcion ul:last-child,
.variante-descripcion ol:last-child {
    margin-bottom: 0;
}

/* Móvil: más ancho para los títulos largos (menos relleno dentro de cada
   ficha, sin puntitos, fichas a 8px de los bordes de la pantalla). La foto
   y su hueco a la izquierda (60px, regla de arriba con :has) no cambian. */
@media (max-width: 480px) {
    .plato,
    .plato-grupo {
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    /* Sin puntitos entre nombre y precio: en móvil los nombres largos van
       a dos o tres líneas y los puntos solo les quitaban ancho. */
    .plato-puntos,
    .variante-puntos,
    .plato-grupo-titulo::after {
        display: none;
    }

    .plato-cabecera,
    .variante-cabecera {
        gap: 0.75rem;
    }

    .variante {
        padding-left: 0.4rem;
    }

    /* Fichas a 8px de los bordes de la pantalla (la carta tiene 12px de
       margen, así que la lista se estira hasta el borde y se compensa con
       relleno; .platos recorta lo que se sale, por el acordeón). */
    .platos {
        margin-left: -0.75rem;
        margin-right: -0.75rem;
        padding-left: 8px;
        padding-right: 8px;
    }
}

.variante-alergenos {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    right: 0;
    bottom: 0.15rem;
    display: block;
    width: auto;
    background: none;
    border: none;
    padding: 0;
    text-align: right;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    font: inherit;
    font-size: 0.7rem;
    font-weight: 600;
    color: #777;
    margin-top: 0;
    cursor: pointer;
}

.variante-alergenos:hover {
    color: var(--color-activo);
}

.categoria-alergenos {
    margin-top: 0.5rem;
}

.boton-leyenda-alergenos {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    border: none;
    text-align: left;
    font: inherit;
    cursor: pointer;
    position: static;
}

/* Modal de alérgenos: se reutiliza tanto para la leyenda completa (sin
   nada resaltado) como para el detalle de un plato concreto (con sus
   números en rojo), según qué lo haya abierto. */
.modal-alergenos {
    border: none;
    border-radius: 12px;
    padding: 0;
    width: min(600px, calc(100% - 2rem));
    max-height: min(640px, calc(100% - 4rem));
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
    opacity: 1;
    transform: scale(1);
    transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out), overlay 200ms allow-discrete, display 200ms allow-discrete;
}

@starting-style {
    .modal-alergenos[open] {
        opacity: 0;
        transform: scale(0.95);
    }
}

.modal-alergenos::backdrop {
    background: rgba(20, 16, 15, 0.55);
    opacity: 1;
    transition: opacity 200ms var(--ease-out), display 200ms allow-discrete, overlay 200ms allow-discrete;
}

@starting-style {
    .modal-alergenos[open]::backdrop {
        opacity: 0;
    }
}

.modal-alergenos-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.5rem;
    background: var(--color-activo);
    color: #fff;
}

.modal-alergenos-cabecera h2 {
    margin: 0;
    font-size: 1.6rem;
    font-weight: 700;
}

.modal-alergenos-cerrar {
    -webkit-appearance: none;
    appearance: none;
    background: none;
    border: none;
    color: #fff;
    font-size: 1.6rem;
    line-height: 1;
    padding: 0.2rem 0.4rem;
    cursor: pointer;
    border-radius: 6px;
    transition: background-color 140ms ease;
}

.modal-alergenos-cerrar:hover {
    background: rgba(255, 255, 255, 0.15);
}

.leyenda-alergenos-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.1rem 1.25rem;
    padding: 1.5rem;
    overflow-y: auto;
    max-height: calc(min(640px, 100vh - 4rem) - 4rem);
}

.leyenda-alergenos-item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    min-width: 0;
}

.leyenda-alergenos-icono {
    display: flex;
    width: 1.6rem;
    height: 1.6rem;
    flex-shrink: 0;
    color: #ccc;
    transition: color 160ms ease;
}

.leyenda-alergenos-icono svg {
    width: 100%;
    height: 100%;
}

.leyenda-alergenos-numero {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 1.9rem;
    height: 1.9rem;
    padding: 0 0.3rem;
    border: 1.5px solid #e9cdd0;
    border-radius: 6px;
    color: #cd9aa0;
    font-weight: 700;
    font-size: 0.95rem;
    flex-shrink: 0;
    transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease;
}

.leyenda-alergenos-etiqueta {
    color: #999;
    font-size: 0.9rem;
    line-height: 1.2;
    transition: color 160ms ease, font-weight 160ms ease;
}

.leyenda-alergenos-item.activo .leyenda-alergenos-icono {
    color: var(--color-activo);
}

.leyenda-alergenos-item.activo .leyenda-alergenos-numero {
    background: var(--color-activo);
    border-color: var(--color-activo);
    color: #fff;
}

.leyenda-alergenos-item.activo .leyenda-alergenos-etiqueta {
    color: #111;
    font-weight: 700;
}

/* Foto del plato ampliada: mismo mecanismo que .modal-alergenos (native
   <dialog>, showModal()/close() en plato-foto.js), pero sin cabecera
   propia — la imagen ocupa el modal, con su título/descripción a modo de
   pie debajo, y el botón de cerrar flota encima de la imagen. Columna flex
   para que la imagen (flex:1 1 auto, min-height:0) ceda el espacio que
   necesite el pie en vez de desbordar el modal en fotos muy verticales. */
.modal-foto {
    border: none;
    padding: 0;
    width: min(560px, calc(100% - 2rem));
    max-height: calc(100% - 4rem);
    overflow: visible;
    background: transparent;
    opacity: 1;
    transform: scale(1);
    transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out), overlay 200ms allow-discrete, display 200ms allow-discrete;
    /* Los gestos con el dedo sobre la foto ampliada son solo para pasar de
       plato (plato-foto.js): sin esto, el navegador los usaba también para
       desplazar la carta de detrás, que se movía al deslizar. */
    touch-action: none;
    overscroll-behavior: contain;
}

/* Con la foto ampliada abierta, la carta de detrás no se desplaza. */
html:has(.modal-foto[open]) {
    overflow: hidden;
}

/* display SOLO cuando [open] (showModal() lo añade) — igual que
   .carta-menu[open] y .modal-ficha-vino[open]: un <dialog> cerrado ya es
   display:none por la hoja de estilos del navegador, y ponerlo sin
   condicionar a [open] en la regla de arriba anulaba eso, dejando el
   modal (vacío) ocupando sitio en la página desde que carga, antes de
   abrirlo nunca. */
.modal-foto[open] {
    display: flex;
    flex-direction: column;
}

@starting-style {
    .modal-foto[open] {
        opacity: 0;
        transform: scale(0.95);
    }
}

.modal-foto::backdrop {
    background: rgba(20, 16, 15, 0.7);
    opacity: 1;
    transition: opacity 200ms var(--ease-out), display 200ms allow-discrete, overlay 200ms allow-discrete;
}

@starting-style {
    .modal-foto[open]::backdrop {
        opacity: 0;
    }
}

/* La tarjeta blanca (foto + pie): el <dialog> de alrededor es
   transparente para que el contador pueda ir fuera, debajo. */
.modal-foto-caja {
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border-radius: 12px;
    background: #fff;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
}

.modal-foto-imagen {
    display: block;
    width: 100%;
    flex: 1 1 auto;
    min-height: 0;
    object-fit: contain;
}

.modal-foto-pie {
    flex: 0 0 auto;
    padding: 0.9rem 1.25rem 1.1rem;
    background: #fff;
    color: #111;
}

.modal-foto-titulo {
    margin: 0 0 0.3rem;
    font-size: 1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

.modal-foto-descripcion {
    margin: 0;
    font-size: 0.85rem;
    font-style: italic;
    color: #666;
}

.modal-foto-descripcion[hidden] {
    display: none;
}

.modal-foto-cerrar {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background: rgba(0, 0, 0, 0.5);
    border: none;
    color: #fff;
    font-size: 1.6rem;
    line-height: 1;
    padding: 0.2rem 0.55rem;
    cursor: pointer;
    border-radius: 6px;
    transition: background-color 140ms ease;
}

.modal-foto-cerrar:hover {
    background: rgba(0, 0, 0, 0.75);
}

/* "3 / 8 en Paellas": posición del plato dentro de su subcategoría al
   recorrer las fotos (plato-foto.js). */
/* Fuera de la tarjeta, debajo y centrado, sobre el fondo oscuro. */
.modal-foto-contador {
    flex: none;
    margin: 0.75rem 0 0;
    text-align: center;
    font-size: 0.8rem;
    letter-spacing: 0.02em;
    color: rgba(255, 255, 255, 0.9);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    font-variant-numeric: tabular-nums;
}

.modal-foto-contador[hidden] {
    display: none;
}

/* Flechas anterior/siguiente: solo en dispositivos con ratón; en móvil se
   pasa deslizando el dedo sobre la foto. Centradas sobre la foto (40% del
   alto, no 50%, porque el pie ocupa la parte de abajo del modal). */
.modal-foto-paso {
    -webkit-appearance: none;
    appearance: none;
    position: absolute;
    top: 40%;
    transform: translateY(-50%);
    width: 2.4rem;
    height: 2.4rem;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0 0 0.15rem;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    font-size: 1.8rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 140ms ease, transform 140ms ease;
}

.modal-foto-paso--anterior {
    left: 0.5rem;
}

.modal-foto-paso--siguiente {
    right: 0.5rem;
}

@media (hover: hover) and (pointer: fine) {
    .modal-foto-paso:not([hidden]) {
        display: flex;
    }
}

.modal-foto-paso:hover {
    background: rgba(0, 0, 0, 0.75);
}

.modal-foto-paso:active {
    transform: translateY(-50%) scale(0.94);
}

.modal-foto-paso:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}

/* Menú de categorías (botón hamburguesa de la cabecera): mismo mecanismo
   que .modal-alergenos (native <dialog>, showModal()/close() en
   carta-menu.js), pero anclado al borde izquierdo en vez de centrado, para
   que se lea como un panel que entra deslizando y no como un modal más. */
.carta-menu {
    position: fixed;
    inset: 0 auto 0 0;
    margin: 0;
    /* Ancho pegado al contenido (el enlace de categoría más largo, ver
       white-space:nowrap en .carta-menu-lista a más abajo) en vez de un
       ancho fijo — max-width solo de seguridad para un nombre de
       categoría extremo, no forma parte de lo pedido. */
    width: fit-content;
    max-width: 85vw;
    height: 100%;
    max-height: none;
    border: none;
    padding: 0;
    box-shadow: 6px 0 30px rgba(0, 0, 0, 0.2);
    /* Animado a mano por carta-menu.js con la clase --visible (mismo
       patrón que acordeon.js: clase + setTimeout), no con @starting-style/
       allow-discrete sobre [open] — esa técnica, combinada con el scroll
       que dispara un clic en una categoría, dejaba ver la página haciendo
       scroll debajo mientras el panel todavía se cerraba "por su cuenta":
       dos movimientos a la vez es lo que se leía como "efecto raro". Con
       JS controlando cuándo termina de verdad la animación (y el scroll
       esperando a que termine antes de empezar, ver carta-menu.js), solo
       hay un movimiento a la vez. */
    opacity: 0;
    transform: translateX(-16px);
    transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}

/* display SOLO cuando [open] (showModal() lo añade): un <dialog> cerrado
   ya es display:none por la hoja de estilos del navegador — poner
   display:flex sin condicionar a [open] en la regla de arriba anulaba
   eso y dejaba el menú visible desde que carga la página. */
.carta-menu[open] {
    display: flex;
    flex-direction: column;
}

.carta-menu--visible {
    opacity: 1;
    transform: translateX(0);
}

.carta-menu::backdrop {
    background: rgba(20, 16, 15, 0.55);
    opacity: 0;
    transition: opacity 220ms var(--ease-out);
}

.carta-menu--visible::backdrop {
    opacity: 1;
}

.carta-menu-cabecera {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    background: var(--color-activo);
    color: #fff;
    flex-shrink: 0;
}

/* Logo del restaurante en vez del texto "Categorías" — igual que
   .carta-header-logo img, con una caja de tamaño fijo (object-fit:
   contain) para que logos de proporciones muy distintas encajen igual,
   pero topada a un ancho máximo bajo: el ancho de la ficha ya lo decide
   .carta-menu-lista (ver arriba), el logo no debe ser lo que lo empuje. */
.carta-menu-cabecera img {
    display: block;
    max-width: 150px;
    max-height: 34px;
    width: auto;
    height: auto;
    object-fit: contain;
}

.carta-menu-cabecera span {
    font-weight: 700;
    font-size: 1.1rem;
    white-space: nowrap;
}

.carta-menu-cerrar {
    -webkit-appearance: none;
    appearance: none;
    background: none;
    border: none;
    color: #fff;
    font-size: 1.6rem;
    line-height: 1;
    padding: 0.2rem 0.4rem;
    cursor: pointer;
    border-radius: 6px;
    transition: background-color 140ms ease;
}

.carta-menu-cerrar:hover {
    background: rgba(255, 255, 255, 0.15);
}

.carta-menu-lista {
    list-style: none;
    margin: 0;
    padding: 0.5rem 0;
    overflow-y: auto;
}

.carta-menu-lista a {
    display: block;
    /* white-space:nowrap es lo que hace que .carta-menu (width:fit-content)
       se acople exactamente al ancho de la categoría más larga en vez de
       envolver su texto en dos líneas y quedarse corto. El +10px extra a
       la derecha es el margen pedido, aparte del padding normal. */
    white-space: nowrap;
    padding: 0.9rem calc(1.25rem + 10px) 0.9rem 1.25rem;
    color: #111;
    text-decoration: none;
    font-weight: 600;
    font-size: 1.05rem;
    border-left: 3px solid transparent;
    transition: background-color 140ms ease, border-color 140ms ease;
}

.carta-menu-lista a:hover {
    background: #f4f4f2;
    border-left-color: var(--color-activo);
}

/* Enlace "volver al restaurante": añadido al final de la lista de
   categorías (con la misma url de Configuración que antes vivía en la
   cabecera), separado visualmente con un borde superior para que no se
   confunda con una categoría más. Icono + texto en línea, a diferencia
   del resto de enlaces (solo texto). */
/* Reservas y Volver llevan icono + texto en línea (a diferencia del resto
   de enlaces de la lista, solo texto) — Reservas se lee como una categoría
   más (mismo color/peso, sin separador); Volver, al ser una salida del
   todo del sitio, sí lleva línea separadora encima. */
.carta-menu-reservas a,
.carta-menu-bodega a,
.carta-menu-volver a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.carta-menu-volver a {
    border-top: 1px solid #eee;
    margin-top: 0.5rem;
    color: #555;
}

.carta-menu-reservas .icono,
.carta-menu-bodega .icono,
.carta-menu-volver .icono {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

@media (max-width: 480px) {
    .carta {
        width: 100%;
        max-width: 100%;
        padding: 1rem 0.75rem 3rem;
    }

    /* Mismo truco de "borde a borde" que en desktop, con el padding de
       .carta en este breakpoint (1rem arriba, 0.75rem a los lados). Menos
       alto que en escritorio: en un móvil estrecho, 420px de foto empuja
       la primera categoría fuera de la pantalla inicial. */
    .carta-slider {
        margin: -1rem -0.75rem 2rem;
        aspect-ratio: 4 / 3;
        max-height: 320px;
    }

    .carta-slider-flecha {
        width: 2.1rem;
        height: 2.1rem;
    }

    .categoria-titulo {
        font-size: 1.35rem;
    }

    .subcategoria-titulo {
        min-height: 50px;
        padding: 1rem 1.1rem;
        font-size: 0.95rem;
    }

    /* Mismo truco de "borde a borde" que en desktop, pero con el padding
       lateral de .carta en este breakpoint (0.75rem, no 2.5rem). */
    .subcategoria[open] .subcategoria-titulo {
        margin-left: -0.75rem;
        margin-right: -0.75rem;
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    .plato,
    .plato-grupo {
        padding: 0.7rem 0.85rem;
    }

    .plato-titulo,
    .plato-grupo-titulo,
    .variante-nombre {
        font-size: 0.95rem;
    }

    .plato-descripcion {
        font-size: 0.85rem;
    }

    .leyenda-alergenos-grid {
        grid-template-columns: repeat(2, 1fr);
        max-height: calc(100vh - 8rem);
    }
}

/* Modo "live" del panel de administración (public/admin/live.php): la misma
   carta que ve el cliente, pero con los textos editables in situ. Estas
   reglas solo se activan bajo body.modo-edicion, así que no afectan en
   absoluto a la carta real que ven los clientes. */

body.modo-edicion [contenteditable] {
    border-radius: 4px;
    outline: 1px dashed transparent;
    outline-offset: 2px;
    transition: outline-color 140ms ease, background-color 140ms ease;
    cursor: text;
}

body.modo-edicion [contenteditable]:hover {
    outline-color: var(--color-secundario, #7a2e33);
}

body.modo-edicion [contenteditable]:focus {
    outline: 2px solid var(--color-secundario, #7a2e33);
    background: color-mix(in srgb, var(--color-secundario, #7a2e33) 8%, transparent);
}

body.modo-edicion [contenteditable].live-guardado {
    background: color-mix(in srgb, #2e7d4f 18%, transparent);
    outline-color: #2e7d4f;
}

body.modo-edicion [contenteditable].live-error {
    background: color-mix(in srgb, #b3261e 18%, transparent);
    outline-color: #b3261e;
}

body.modo-edicion .plato-descripcion:empty::before,
body.modo-edicion .variante-descripcion:empty::before {
    content: 'Descripción (opcional)';
    color: var(--color-secundario, #7a2e33);
    opacity: 0.55;
}

/* Lo oculto para los clientes no desaparece en el modo live (arbolCompleto()
   en vez de arbolVisible()): se ve muy tenue en vez de esfumarse, y su
   botón "ocultar" pasa a ser "mostrar" para poder reactivarlo sin salir. */
body.modo-edicion .live-oculto {
    opacity: 0.35;
}

/* Acciones rápidas (ocultar/duplicar/eliminar): fuera de la ficha del
   plato, en una columna a su derecha, no dentro ni encima del título. */
.plato-fila {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
}

.plato-fila > .plato,
.plato-fila > .plato-grupo {
    flex: 1 1 auto;
    min-width: 0;
}

.plato-acciones {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    flex: 0 0 auto;
    padding-top: 0.15rem;
}

.plato-accion {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--color-secundario, #7a2e33);
    opacity: 0.5;
    cursor: pointer;
    transition: opacity 140ms ease, background-color 140ms ease, color 140ms ease, transform 140ms ease;
}

.plato-accion .icono {
    width: 1rem;
    height: 1rem;
}

.plato-accion:hover {
    opacity: 1;
    background: color-mix(in srgb, var(--color-secundario, #7a2e33) 12%, transparent);
}

.plato-accion:active {
    transform: scale(0.92);
}

.plato-accion:disabled {
    opacity: 0.3;
    cursor: default;
}

.plato-accion-peligro:hover {
    color: #b3261e;
    background: color-mix(in srgb, #b3261e 12%, transparent);
}

.plato-accion-peligro.confirmando {
    color: #fff;
    background: #b3261e;
    opacity: 1;
}

/* Acciones de la subcategoría: inline dentro de la propia cabecera del
   acordeón (a diferencia de las del plato, que van fuera de la ficha),
   empujadas del todo a la derecha con margin-left:auto. */
.subcategoria-acciones {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    flex-shrink: 0;
    margin-left: auto;
}

/* .subcategoria-titulo tiene fondo oscuro (color_cerrado/color_activo) con
   texto blanco, así que aquí los iconos se aclaran en vez de usar el
   color_secundario oscuro de .plato-accion (quedaría invisible). */
.subcategoria-acciones .plato-accion {
    color: #fff;
    opacity: 0.7;
}

.subcategoria-acciones .plato-accion:hover {
    opacity: 1;
    background: rgba(255, 255, 255, 0.18);
}

.subcategoria-acciones .plato-accion-peligro:hover {
    color: #ffb4ab;
    background: rgba(255, 255, 255, 0.18);
}

/* .plato-accion-peligro.confirmando (0-2-0) de arriba es el aviso de
   "¿seguro? pulsa de nuevo" tras el primer clic en borrar — sin esta
   regla, aquí dentro pierde siempre contra
   .subcategoria-acciones .plato-accion-peligro:hover (0-3-0) mientras el
   ratón sigue sobre el botón (el caso normal justo después de pulsar), y
   el aviso visual desaparece en la acción más destructiva del acordeón.
   Misma especificidad compuesta que esa regla de hover, para que
   "confirmando" gane según orden de aparición en el archivo. */
.subcategoria-acciones .plato-accion-peligro.confirmando {
    color: #fff;
    background: #b3261e;
    opacity: 1;
}

/* En pantalla pequeña los iconos de ocultar/duplicar/eliminar se editan con
   el dedo, no con el ratón: sin :hover que los delate, necesitan una zona
   de toque más cómoda que el tamaño pensado para escritorio. */
@media (max-width: 480px) {
    .plato-accion {
        width: 2.1rem;
        height: 2.1rem;
        opacity: 0.75;
    }

    .plato-acciones {
        gap: 0.35rem;
    }

    .subcategoria-acciones {
        gap: 0.25rem;
    }
}

/* Página de login (public/login.php). No forma parte de la carta pública,
   pero comparte esta hoja de estilos porque no hay sesión todavía. */

.login-body {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 1.5rem;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background:
        radial-gradient(ellipse 900px 560px at 50% -8%, #eff6ff 0%, rgba(239, 246, 255, 0) 60%),
        #faf9f8;
}

.login-card {
    position: relative;
    background: #fff;
    width: 100%;
    max-width: 360px;
    padding: 2.75rem 2.25rem 2.25rem;
    border-radius: 16px;
    border: 1px solid #e5e1de;
    box-shadow: 0 24px 70px rgba(32, 28, 26, 0.12), 0 2px 8px rgba(32, 28, 26, 0.05);
    overflow: hidden;
}

.login-card::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: #1e3a8a;
}

.login-logo {
    display: block;
    height: 78px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
    margin: 0 auto 2rem;
}

.text-muted {
    color: #746c67;
    font-size: 0.9rem;
    margin: 0 0 1.25rem;
}

.alert {
    padding: 0.6rem 0.85rem;
    border-radius: 8px;
    margin-bottom: 1rem;
    font-size: 0.9rem;
}

.alert-danger {
    color: #b3261e;
    background: #fbeae8;
}

.form-group {
    margin-bottom: 1.2rem;
}

.form-group label {
    display: block;
    font-weight: 600;
    margin-bottom: 0.35rem;
    font-size: 0.85rem;
    color: #201c1a;
}

.form-group input {
    width: 100%;
    padding: 0.7rem 0.85rem;
    border: 1px solid #d6d0cc;
    border-radius: 10px;
    font: inherit;
    font-size: 0.95rem;
    color: #201c1a;
    background: #fff;
    transition: border-color 140ms ease, box-shadow 140ms ease;
}

.form-group input:focus {
    outline: none;
    border-color: #1e3a8a;
    box-shadow: 0 0 0 3px #eff6ff;
}

.btn {
    display: inline-block;
    padding: 0.55rem 1.05rem;
    border: 1px solid #d6d0cc;
    border-radius: 10px;
    background: #fff;
    color: #201c1a;
    cursor: pointer;
    font: inherit;
    text-decoration: none;
    transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1), background-color 140ms ease, border-color 140ms ease;
}

.btn:hover {
    background: #faf9f8;
}

.btn:active {
    transform: scale(0.97);
}

.btn-primary {
    background: #1e3a8a;
    border-color: #1e3a8a;
    color: #fff;
}

.btn-primary:hover {
    background: #172554;
    border-color: #172554;
}

.btn-primary:active {
    background: #0f1a3d;
    transform: scale(0.97);
}

.btn-block {
    display: block;
    width: 100%;
    text-align: center;
    padding: 0.75rem 1.05rem;
    margin-top: 0.4rem;
    font-weight: 600;
    letter-spacing: 0.01em;
}

@media (prefers-reduced-motion: reduce) {
    .btn,
    .platos-wrapper,
    .subcategoria-titulo,
    .modal-alergenos,
    .modal-alergenos::backdrop,
    .modal-foto,
    .modal-foto::backdrop,
    .carta-menu,
    .carta-menu::backdrop {
        transition-duration: 0.001ms !important;
    }

    .carta-slider-pista {
        scroll-behavior: auto;
    }
}
