:root {
  /* --- Paleta Huespix by DMG (06/10) -----------------------------------
     La interfaz es clara y neutra: Lino de fondo, Blanco en las tarjetas,
     Tinta en el texto. Un solo color fuerte por pantalla para la accion
     principal (turquesa oscuro), el violeta SOLO para lo que hace la IA, y
     verde/amarillo/rojo SOLO para estados -- nunca como decoracion.
     Medido (WCAG): Tinta sobre Blanco 17.9, Gris texto sobre Blanco 6.8 y
     sobre Lino 6.1, texto blanco sobre el turquesa oscuro 5.0.
     El Lino separa menos de las tarjetas que el gris azulado de antes (1.11
     contra 1.15): lo compensa el Borde, que es mas marcado (1.45 contra
     1.27 sobre blanco). */
  --bg: #f5f3ee;              /* Lino */
  --surface: #ffffff;         /* Blanco */
  /* Un paso mas oscuro que el Lino y en el mismo tono calido: zonas
     apagadas DENTRO de una tarjeta blanca (fondo del chat, campos de solo
     lectura, cabeceras de tabla). */
  --surface-muted: #f0ede6;
  --ink: #16142e;             /* Tinta */
  --muted: #5b5873;           /* Gris texto */
  --line: #dad6cc;            /* Borde */
  /* Turquesa oscuro: el RELLENO de lo turquesa solido (boton principal, dia
     de hoy, interruptor prendido) y los bordes e indicadores de acento
     (seleccionado, linea de hoy, casillero tildado). El texto que va encima
     de un relleno es --on-accent (blanco, 5.0). Como TEXTO no: eso es
     --accent-strong. */
  --accent: #0b7a91;
  --on-accent: #ffffff;
  /* Texto de acento (enlaces, pestaña activa, etiquetas): 7.3 sobre Blanco. */
  --accent-strong: #075f71;
  /* Hover de lo turquesa solido: un paso mas oscuro, 7.3 con texto blanco. */
  --accent-hover: #075f71;
  /* Anillo y borde de FOCO de teclado/campo, cursor de texto y tildes
     nativos. */
  --focus-outline: var(--accent);
  /* Turquesa de marca: iconos, indicadores, detalles graficos. NUNCA como
     texto sobre claro (2.4 sobre Blanco). */
  --accent-bright: #22b8d6;
  /* Agua: fondo suave de lo SELECCIONADO, de los avisos informativos y de
     las etiquetas de acento. El texto encima va en --accent-strong (6.2) o
     --ink. */
  --accent-soft: #d5f3f8;
  /* Violeta: todo lo que hace la IA (mensajes del asistente, estado del
     bot). Reservado: si aparece en otra cosa, el violeta deja de decir
     "esto lo hizo el bot". --ai es para iconos, bordes y rellenos sin
     texto; el texto va en --ai-strong (6.2 sobre Blanco, 5.1 sobre
     Lavanda) y el fondo suave en --ai-soft (Lavanda). */
  --ai: #6b4ef6;
  --ai-strong: #5b3ef0;
  --ai-soft: #eae5ff;
  /* Colores de ESTADO. No son de marca y no se mezclan con los acentos:
     estan medidos contra sus tintas (--tint-*-ink) y se mantienen. */
  --green: #2f9e44;
  --blue: #277da1;
  --yellow: #f9c74f;
  --orange: #f9844a;
  --red: #d9480f;
  /* Gris de estado (cancelada, sin dato): corrido hacia el violeta del Gris
     texto para que no quede un gris frio suelto en una paleta calida. */
  --gray: #b0acbd;
  /* Paleta EXCLUSIVA de los graficos de Estadisticas. Separada de --accent/
     --green/etc de arriba porque esas son semanticas y se usan en botones,
     badges y alertas en toda la app.
     Son TRES colores de serie y el numero salio de medir: con el validador
     de paletas categoricas (separacion bajo daltonismo, piso de vision
     normal, banda de luminosidad y contraste contra la superficie) NO
     existe un juego de seis tonos que pase en los dos temas. Alcanza con
     tres porque ningun grafico del PMS tiene mas de dos series; lo que
     antes pedia ocho colores (la torta de extras) es una lista de barras de
     un solo color.
     Paleta Huespix (06/10): antes la serie principal era violeta, y el
     violeta ahora es SOLO de la IA. Cada slot sale de la marca:
       --chart-1  turquesa MEDIO, el mismo tono de marca entre el Turquesa
                  (#22b8d6) y el Turquesa oscuro (#0b7a91). Ninguno de los
                  dos sirve tal cual: el claro da 2.4:1 sobre Blanco, y el
                  oscuro es el color del boton principal (con barras del
                  mismo tono la accion deja de ser el unico color fuerte de
                  la pantalla) y queda bajo el piso de croma (0.094: se lee
                  gris). Habitacion, Ocupacion, Confirmado y todas las barras.
       --chart-2  azul tinta, de la familia de la Tinta: Extras. Frio como
                  el turquesa, asi el unico color calido del panel es el que
                  pide atencion. Lejos del violeta de la IA (ΔE 17.6).
       --chart-3  naranja de PENDIENTE. Es un estado: el mismo naranja de
                  "pendiente de seña" del planning y de la lista, oscurecido
                  lo justo para pasar 3:1 (--orange puro da 2.5). Confirmado
                  NO va en verde aunque tambien sea un estado: verde contra
                  naranja se confunde con daltonismo (ΔE 5.8, falla).
     Medido sobre #ffffff, todos los pares: peor ΔE 17.9 con daltonismo y
     18.3 con vision normal; contraste 3.8 / 7.9 / 3.2. */
  --chart-1: #028fab;
  --chart-2: #0e509d;
  --chart-3: #e16f1e;
  /* Escala unica de radios (antes habia 6px/8px/10px/12px sueltos repartidos
     por el archivo, cada uno elegido a ojo en su momento). --radius-pill es
     para badges/chips, donde el radio tiene que ser mayor al alto. */
  /* Paleta Huespix: 12 a 16px en tarjetas y botones, 999px en etiquetas.
     --radius-sm queda para lo chico (bloques del planning, anillos de foco,
     celdas), donde 12px dejaria un circulo. */
  --radius-sm: 6px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  /* Texto de los badges de estado. Cada uno va sobre un fondo que es ese
     mismo color al ~12% sobre --surface (ver .pill), no sobre el color puro:
     por eso son versiones MAS OSCURAS que --red/--orange/etc, que estan
     pensadas para usarse como fondo con texto blanco encima. Se definen como
     tokens (y se pisan enteros en el bloque de modo oscuro) en vez de
     calcularse con color-mix para poder medir el contraste real de cada uno
     en los dos temas, en vez de confiar en que la mezcla de un tema sirva
     para el otro. */
  --tint-red-ink: #a33a0b;
  /* Rojo de SALIDA: la cruz que cierra un panel, la flecha de volver, cerrar
     sesion. Son controles que sacan de donde estas, no que borran algo, asi
     que van en un rojo apagado y no en --red: tienen que encontrarse rapido
     sin leerse como una alarma. Medido sobre --surface: 5.55 (el
     Gris texto da 6.80): se lee como color, no como texto secundario, y
     sigue sobre el minimo. Lo que BORRA usa --tint-red-ink, mas saturado:
     que los dos niveles no se confundan es justamente el punto. */
  --salida-ink: #9e5347;
  --tint-orange-ink: #9a4f10;
  --tint-green-ink: #1f7a33;
  --tint-blue-ink: #1c6180;
  --tint-yellow-ink: #7d611a;
  --tint-gray-ink: #4b4864;

  /* Anillo de foco de teclado. Existe un solo lugar que lo define para que
     todos los controles del PMS se vean igual al tabular (antes no habia
     NINGUNO: el navegador dibujaba su outline nativo o nada). */
  --focus-ring: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent);

  /* --- Movimiento -----------------------------------------------------
     Las curvas propias del sistema. Las de CSS (`ease`, `ease-out`) son
     demasiado suaves: el movimiento arranca despacio justo en el momento
     que el ojo mas mira, y la interfaz se siente lenta aunque dure lo
     mismo. Estas tres son las unicas curvas que se usan en todo el PMS.
       --ease-out    entrar/salir. Arranca rapido: da sensacion de respuesta.
       --ease-in-out algo que ya esta en pantalla y se mueve/transforma.
       --ease-drawer paneles que entran desde un borde (curva de iOS).
     NUNCA ease-in en UI: retrasa el arranque y se siente pesado. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  /* Duraciones por rol, no por gusto. Un PMS se usa TODO el dia: lo que en
     una landing es "elegante", aca despues de la decima vez es una espera.
     Por eso ninguna pasa de 260ms, y el feedback de apretar es casi
     instantaneo. */
  --dur-press: 130ms;   /* apretar un boton: tiene que sentirse inmediato */
  --dur-fast: 160ms;    /* hover, cambios de color, foco */
  --dur-panel: 200ms;   /* dropdowns, popovers, paneles que se despliegan */
  --dur-modal: 240ms;   /* modales y velos: lo unico que se puede tomar su tiempo */

  /* --- Elevacion ------------------------------------------------------
     Las superficies EN FLUJO (paneles, tarjetas, toolbars) siguen planas:
     la separacion la da el borde de 1px, y en una pantalla con 40 tarjetas
     de datos una sombra por tarjeta es ruido, no jerarquia. --shadow queda
     en none a proposito y las ~12 reglas que la usan siguen ahi para poder
     volver atras con una sola linea.
     Lo que SI flota gana una sombra de verdad, y esta TEÑIDA con la Tinta
     en vez de negro puro: una sombra negra sobre el Lino se ve sucia, gris,
     como si el elemento estuviera despegado del resto de la paleta. Tres
     niveles segun cuanto flota. */
  --shadow: none;
  --shadow-raised: 0 1px 2px rgba(22, 20, 46, 0.06), 0 2px 6px rgba(22, 20, 46, 0.05);
  --shadow-overlay: 0 4px 12px rgba(22, 20, 46, 0.09), 0 1px 3px rgba(22, 20, 46, 0.06);
  --shadow-float: 0 12px 32px rgba(22, 20, 46, 0.15), 0 2px 6px rgba(22, 20, 46, 0.07);
  /* Velo translucido de la pantalla de carga -- mismo tono que --bg de cada
     tema, no un color de marca fijo, para que aparecer/desaparecer sea un
     cambio sutil y no un salto de color. */
  --boot-veil-bg: rgba(245, 243, 238, 0.72);
}

/* Modo oscuro: preferencia PERSONAL de cada usuario (guardada en su perfil,
   ver users.theme_preference), no del hotel -- por eso se activa con un
   atributo en <html> puesto por JS al cargar sesion, no por
   prefers-color-scheme. Mismos nombres de variable que :root a proposito:
   todo lo que ya usa var(--x) se adapta solo, sin tocar cada regla. */
html[data-theme="dark"] {
  /* Paleta Huespix sobre fondo oscuro: Tinta de fondo, tarjetas #2a2650,
     bordes #3a3566, texto blanco y secundario #c9c4e8 (8.4 sobre la
     tarjeta). Acentos: turquesa #3fd0e6 y lila #b7a6ff. */
  --bg: #16142e;
  --surface: #2a2650;
  /* Como en el tema claro, un paso hacia el fondo... pero aca "apagado" es
     un poco MAS CLARO que la tarjeta, que es como se lee un hueco en oscuro. */
  --surface-muted: #312d5c;
  --ink: #ffffff;
  --muted: #c9c4e8;
  --line: #3a3566;
  --gray: #6a6596;
  /* --accent-strong se usa como COLOR DE TEXTO directo sobre --surface (ej.
     .ghost-button): en oscuro va el turquesa claro de marca, 7.6 sobre la
     tarjeta. --accent en cambio se usa sobre todo como FONDO de boton con
     texto blanco encima, eso ya funciona igual en los dos temas y no
     necesita cambiar. */
  /* En oscuro el acento es el turquesa CLARO de marca, tambien como relleno:
     el turquesa oscuro daba 2.8 contra la tarjeta #2a2650, y los bordes de
     lo seleccionado, la linea de hoy del planning y los casilleros tildados
     quedaban debajo del 3:1 de un indicador (2.0 contra el Agua). Con este,
     7.6 contra la tarjeta y 5.5 contra el Agua. Encima de un relleno el
     texto pasa a Tinta (--on-accent): el blanco sobre #3fd0e6 da 1.85. */
  --accent: #3fd0e6;
  --on-accent: #16142e;
  /* Hover de lo turquesa solido: un paso mas claro (11.3 con Tinta). */
  --accent-hover: #7adcec;
  --accent-strong: #3fd0e6;
  --accent-bright: #3fd0e6;
  --focus-outline: #3fd0e6;
  --focus-ring: 0 0 0 3px color-mix(in srgb, #3fd0e6 30%, transparent);
  /* Agua en oscuro: el turquesa al 16% sobre la tarjeta. --accent-strong
     encima da 5.5 y el texto blanco 10.2. */
  --accent-soft: #2d4168;
  /* Lila: en oscuro el violeta de marca no se lee (2.7 sobre la tarjeta).
     Sobre la Lavanda oscura da 5.4. */
  --ai: #b7a6ff;
  --ai-strong: #b7a6ff;
  --ai-soft: #382f75;
  /* Contraparte oscura de los --tint-*-ink de :root. Aca la logica se da
     vuelta: el fondo del badge es el color al ~18% sobre una superficie
     oscura, asi que el texto tiene que ser una version CLARA del mismo tono,
     no una oscura. Medidos sobre el tinte real, no sobre --surface pelado. */
  /* Graficos en oscuro: la banda de luminosidad es mas angosta (0.48-0.67)
     y la tarjeta pide 3:1. El turquesa medio sube un paso (para separarse
     mejor del azul) y el azul tinta pasa a un azul vivo: el marino del tema
     claro da 1.8 sobre la tarjeta. El naranja de pendiente aguanta los dos
     temas sin cambiar. Medido sobre #2a2650, todos los pares: peor ΔE 15.4
     con daltonismo y 17.0 con vision normal; contraste 4.7 / 3.3 / 4.4. */
  --chart-1: #0ca3be;
  --chart-2: #4571f2;
  --tint-red-ink: #ffa183;
  /* Contraparte oscura del rojo de salida: en oscuro la tinta tiene que ser
     una version CLARA del tono, igual que los --tint-*-ink de arriba. Medido
     sobre la tarjeta oscura (#2a2650): 5.84.
     Esta mas desaturado que el salmon obvio (#e19a8f, que daba 7.15 y quedaba
     mejor de contraste): contra el --tint-red-ink de oscuro, ese salmon daba
     una separacion de solo 15.9 de deltaE contra los 29.0 del tema claro, o
     sea que los dos niveles casi se confundian justo en el tema donde menos
     margen hay. Con este la separacion sube a 24.5 y sigue a 31 del gris que
     reemplaza -- se lee rojo, y se lee distinto del rojo de borrar. */
  --salida-ink: #cf9a95;
  --tint-orange-ink: #ffb083;
  --tint-green-ink: #74d98a;
  --tint-blue-ink: #7cc7e8;
  --tint-yellow-ink: #f2ce6b;
  --tint-gray-ink: #c9c4e8;
  /* En oscuro la sombra sola casi no se ve (negro sobre casi-negro): lo que
     separa una superficie flotante del fondo es el HALO CLARO de su borde
     superior, no la sombra de abajo. Por eso cada nivel suma un inset de
     1px con blanco muy tenue -- es el mismo truco de las interfaces de
     macOS/iOS en oscuro, y sin el las tarjetas oscuras se ven pegadas. */
  --shadow: none;
  --shadow-raised: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 2px 6px rgba(0, 0, 0, 0.32);
  --shadow-overlay: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 6px 16px rgba(0, 0, 0, 0.42);
  --shadow-float: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 16px 40px rgba(0, 0, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4);
  --boot-veil-bg: rgba(22, 20, 46, 0.72);
}

* {
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: Geist, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* Sin esto la fuente se ve mas gruesa de la cuenta en pantallas no-Retina,
     que es lo que hay en la recepcion de un hotel. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 1.5;
  /* Geist trae versalitas y ligaduras contextuales que en una interfaz densa
     solo generan formas raras a 11px. Se apagan y quedan solo las cifras. */
  font-feature-settings: "liga" 0, "clig" 0;
  text-rendering: optimizeLegibility;
}

/* Numeros de ancho fijo en TODO lo que sea un dato tabular: montos, fechas,
   codigos de reserva, contadores. Sin esto cada digito tiene su propio ancho
   y una columna de precios queda visualmente desalineada, ademas de "saltar"
   cuando un valor se actualiza en vivo (ej. el saldo al cargar un pago).
   Solo alcanza a los contenedores de datos -- el texto normal sigue con las
   cifras proporcionales, que leen mejor dentro de una frase. */
.metric strong,
.stats-kpi-grid .metric small,
.listing-table td,
.payment-row,
.season-price-table td,
.detail-summary,
.inhouse-row-tags,
.reservation-row,
.pill,
.cell,
.stats-axis-label,
.stats-channel-table {
  font-variant-numeric: tabular-nums;
}

/* Se probo poner los importes en Geist Mono y se descarto por una razon
   concreta del producto: money() formatea a la argentina, `$1.234.-`, y en
   una monoespaciada el punto y el guion ocupan una celda entera cada uno,
   asi que `$0.-` se dibuja `$0 . -` con huecos. Verificado en pantalla, se
   ve peor que antes. Geist ya trae cifras tabulares propias (activadas
   arriba con font-variant-numeric), que es lo que resuelve de verdad el
   problema de alineacion de columnas. No hace falta una segunda familia.

   Lo que si necesitan los importes GRANDES es tracking negativo: a 30px las
   cifras tabulares quedan sueltas entre si porque el ancho de celda esta
   calculado para texto chico. */
.metric strong,
.balance-banner-amount {
  letter-spacing: -0.025em;
}

/* Foco de teclado visible en todo control interactivo. El PMS no tenia
   NINGUNA regla de foco (salvo dos casos sueltos), asi que quien navega con
   Tab dependia del outline nativo del navegador, que varias reglas propias
   tapaban sin querer. Es :focus-visible y no :focus a proposito: no aparece
   al hacer click con el mouse, solo al llegar con el teclado. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

button,
input,
select {
  font: inherit;
}

/* Los <button> NO heredan color por defecto en ningun navegador (a
   diferencia del resto de los elementos, que si heredan de body) -- sin esto
   cualquier boton sin un color explicito propio (ej. .reservation-row, que es
   un <button> entero) cae al color de texto nativo del boton del sistema,
   que en la mayoria de los navegadores es negro fijo sin importar el fondo.
   En modo claro pasaba desapercibido (negro sobre blanco es casi el mismo
   --ink); en modo oscuro se volvia texto negro sobre fondo oscuro,
   ilegible. Una clase mas especifica (.primary-button, etc.) sigue pudiendo
   pisar esto sin problema. */
button {
  cursor: pointer;
  color: inherit;
}

/* Base para CUALQUIER input/select/textarea que no tenga una regla mas
   especifica (varios quedaban con el fondo blanco nativo del navegador en
   modo oscuro porque nunca tuvieron una regla de color propia -- en claro
   pasaba desapercibido porque el blanco nativo coincidia con el tema). Una
   clase mas especifica sigue pudiendo pisar esto sin problema. */
input,
select,
textarea {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

/* Los campos se leen como un HUECO en la superficie, no como un rectangulo
   dibujado encima: fondo apenas mas oscuro que el panel que los contiene y
   una sombra interna de 1px arriba, como si la luz entrara desde arriba y
   el borde superior proyectara dentro. Es sutil a proposito -- en un
   formulario de 12 campos cualquier cosa mas marcada seria ruido -- pero es
   la diferencia entre "formulario HTML" y "control de un producto".
   Va en un selector aparte del de arriba para que cualquier regla mas
   especifica que ya define su propio `background` (hay varias) siga
   ganando sin que quede un hueco sin fondo. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
select,
textarea {
  background-color: color-mix(in srgb, var(--ink) 2.5%, var(--surface));
  box-shadow: inset 0 1px 2px color-mix(in srgb, var(--ink) 5%, transparent);
}

/* Flecha propia en TODOS los desplegables. Antes solo la tenia
   .compact-field select y el resto mostraba la del sistema operativo, que
   cambia de dibujo entre Windows, macOS y Android: el mismo formulario se
   veia distinto en cada maquina de recepcion. Son dos triangulos hechos con
   degradados, sin imagen ni icono que cargar. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 15px) calc(50% + 1px),
    calc(100% - 10px) calc(50% + 1px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 30px;
  color: var(--ink);
}

/* La flecha hereda currentColor, asi que sin esto tomaria el color pleno
   del texto y competiria con el valor elegido. */
select:not(:disabled) {
  color: var(--ink);
}

/* El campo enfocado se marca con el color de marca + un halo suave, en vez
   del outline cuadrado del navegador (que ademas quedaba pegado al borde
   redondeado). Va en :focus y no :focus-visible porque en un campo de texto
   si tiene sentido verlo tambien al entrar con el mouse: marca donde va a
   escribir. */
input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--focus-outline);
  /* Al enfocar, el campo se "levanta": pierde el hundido y pasa a fondo
     pleno. El halo reemplaza a la sombra interna en vez de sumarse, para
     que el campo activo se lea claramente distinto de los demas. */
  background-color: var(--surface);
  box-shadow: var(--focus-ring);
}

input::placeholder,
textarea::placeholder {
  color: var(--muted);
  opacity: 0.75;
}

/* --- Detalles que nadie mira de a uno ----------------------------------
   Ninguno de estos se nota por separado; todos juntos son la diferencia
   entre una app y un producto. Son los lugares donde, si no se dice nada,
   el navegador pone SU criterio -- y el criterio del navegador no combina
   con ninguna marca. */

/* Los controles nativos (checkbox, radio, barra de progreso) se dibujan en
   el AZUL del sistema operativo si no se les dice otra cosa. En una app de
   marca teal, cada tilde azul es una pieza que quedo sin diseñar. */
:root {
  accent-color: var(--accent);
}

/* El cursor de texto tambien es azul por defecto en varios navegadores. */
input,
textarea,
[contenteditable] {
  caret-color: var(--accent);
}

/* Texto seleccionado: el celeste por defecto de Windows/Chrome sobre una
   interfaz teal se ve como un error. */
::selection {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  color: var(--ink);
}

/* Barras de desplazamiento en TODA la app. Antes solo las tenia la grilla
   de planning; el resto (chat, listas, modales, dropdowns) mostraba la
   barra gruesa del sistema, que en modo oscuro aparece como una franja
   clara sobre fondo oscuro y es lo primero que delata que la app no cuido
   ese detalle. Se declara para Firefox (scrollbar-*) y para los basados en
   WebKit/Blink por separado, porque no comparten sintaxis. */
* {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--muted) 42%, transparent) transparent;
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--muted) 34%, transparent);
  /* El borde transparente + background-clip deja la barra "flotando" con
     aire alrededor en vez de pegada al borde del contenedor. */
  border: 2px solid transparent;
  background-clip: content-box;
  border-radius: var(--radius-pill);
}

@media (hover: hover) and (pointer: fine) {
  ::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--muted) 62%, transparent);
    background-clip: content-box;
  }
}

::-webkit-scrollbar-corner {
  background: transparent;
}

/* Campo bloqueado (ej. la entrada del mostrador, siempre hoy) -- distinto de
   var(--surface) para que se note de un vistazo que no se puede tocar, sin
   llegar al tratamiento mas apagado de un :disabled real. */
input:read-only {
  background: var(--surface-muted);
  cursor: not-allowed;
}

.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Navbar superior (reemplaza a la vieja barra lateral) — compacto a
   proposito para no restarle alto util a las vistas debajo. */
.topnav {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: 6px 16px;
  min-height: 50px;
  position: sticky;
  top: 0;
  z-index: 40;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 0 0 auto;
}

/* --- Cambiar de alojamiento desde el navbar -------------------------------
   El nombre del alojamiento es el disparador. Arranca deshabilitado y sin
   flechita: solo se convierte en boton cuando la cuenta tiene acceso a 2 o
   mas (renderHotelSwitcher en app.js). Asi, para recepcion y para un dueño de
   un solo hotel se sigue viendo exactamente como antes: texto y nada mas. */
.brand { position: relative; }
.brand-texto { display: grid; min-width: 0; }

.hotel-switch {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  margin: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  min-width: 0;
  border-radius: var(--radius-sm);
}

.hotel-switch:disabled {
  cursor: default;
  /* Deshabilitado es el estado NORMAL aca (una sola cuenta), no un error:
     no se atenua ni se marca de ninguna forma. */
  opacity: 1;
}

.hotel-switch:not(:disabled) { cursor: pointer; }
.hotel-switch:not(:disabled):hover #sidebar-hotel-name { color: var(--accent-strong); }
.hotel-switch:focus-visible { outline: 2px solid var(--focus-outline); outline-offset: 2px; }

.hotel-switch-chevron {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  opacity: 0.55;
  transition: transform 140ms ease;
}
.hotel-switch:disabled .hotel-switch-chevron { display: none; }
.hotel-switch.open .hotel-switch-chevron { transform: rotate(180deg); }

.hotel-switch-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 60;
  min-width: 240px;
  max-width: 320px;
  padding: 6px;
  display: grid;
  gap: 2px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
}

.hotel-switch-option {
  display: grid;
  gap: 1px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.hotel-switch-option:hover { background: var(--surface-muted); }
.hotel-switch-option small { font-size: 11px; color: var(--muted); }

.hotel-switch-option[aria-current="true"] {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 600;
}
.hotel-switch-option[aria-current="true"] small { color: inherit; }

/* La misma lista, dentro del dropdown de Ajustes. Es el unico camino en
   telefono: ahi la marca del header no muestra texto y el boton de arriba no
   existe. */
.hotel-switch-nav {
  display: grid;
  gap: 2px;
  padding: 2px 0;
}

/* La lista plegada detras de su fila. El caret gira como el de los grupos del
   navbar, para que se lea como el mismo gesto y no como un boton distinto. */
.hotel-switch-nav-lista {
  display: grid;
  gap: 2px;
  padding: 2px 0 2px 10px;
}

/* Su etiqueta es la mas larga del menu y a 190px se partia en dos renglones,
   dejando la fila mas alta que el resto justo en el menu que se quiso acortar.
   El desplegable flota, asi que crecer a lo ancho no le cuesta nada a nadie. */
.hotel-switch-nav-toggle span:not(.nav-icon):not(.nav-caret) {
  white-space: nowrap;
}

.hotel-switch-nav-toggle .nav-caret {
  margin-left: auto;
  transition: transform var(--dur-fast) var(--ease-out);
}

.hotel-switch-nav-toggle.open .nav-caret {
  transform: rotate(180deg);
}

.brand-logo-wrap {
  position: relative;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
}

.brand-logo-fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.brand-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* --- La marca: "Huespix" y al lado, chico, "by DMG" (07/10) -------------
   Como el lockup de la marca: el nombre en Plus Jakarta Sans ExtraBold con
   tracking negativo, y la firma en regular gris con "DMG" en ExtraBold. Es
   la UNICA letra de la marca en la interfaz (todo lo demas sigue en Geist),
   y index.html la pide recortada a las letras de "Huespix byDMG": otra
   palabra con esta clase saldria con letras de respaldo.
   En baseline y no centradas: con tamaños distintos, centrar deja la firma
   flotando por encima del renglon del nombre. La misma pieza va en el
   header, el login y la pantalla de error; el tamaño lo pone cada lugar. */
.marca-huespix {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  font-family: "Plus Jakarta Sans", Geist, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.15;
  white-space: nowrap;
  color: var(--ink);
}

.marca-nombre {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.04em;
}

.marca-firma {
  font-size: 10.5px;
  font-weight: 400;
  color: var(--muted);
}

.marca-firma b {
  font-weight: 800;
  color: var(--ink);
}

/* En el header hay que pisar a ".brand span", que es para el nombre del
   alojamiento (bloque, 10px, gris y recortado con "...") y le gana a una
   clase sola. */
.brand .marca-huespix {
  display: inline-flex;
  max-width: none;
  overflow: visible;
  color: var(--ink);
}

.brand .marca-firma {
  max-width: none;
  overflow: visible;
  font-size: 10.5px;
}

.brand span {
  display: block;
  color: var(--muted);
  font-size: 10px;
  max-width: 150px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.topnav-list {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}

.topnav-group {
  position: relative;
}

.topnav-item {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--muted);
  font-weight: 500;
  font-size: 13px;
  text-align: left;
  white-space: nowrap;
  transition: background-color 140ms ease, color 140ms ease;
}

.topnav-item:hover {
  background: var(--surface-muted);
  color: var(--ink);
}

/* La seccion donde estas parado se distingue del simple hover: fondo teñido
   del color de marca y peso 600. Antes hover y activo se veian identicos,
   asi que al pasar el mouse por el navbar parecia que habias cambiado de
   seccion. */
.topnav-item.active {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 600;
}

/* Circulo de notificacion con la cantidad de chats de WhatsApp sin
   responder (ver updateChatUnreadBadge en app.js) — mismo criterio de
   "sin responder" que whatsappLeadStatusInfo: ultimo mensaje entrante sin
   ninguna respuesta (bot o humana) despues. */
.nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--red);
  color: white;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}

.nav-icon {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: inherit;
}

.nav-icon svg {
  width: 100%;
  height: 100%;
}

/* clamp() en vez de un padding fijo: 16px en pantallas chicas (lo de antes,
   para no perder ancho util donde escasea) y hasta 28px en un monitor de
   recepcion, donde el contenido pegado a los bordes se veia apretado. El
   bloque de mobile (max-width: 900px) sigue pisando esto con su propio
   valor, asi que el minimo real de esta linea es para tablets. */
.main {
  min-width: 0;
  padding: clamp(16px, 1.9vw, 28px);
}

.topbar {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: center;
  margin-bottom: 24px;
}

/* Pesos bajados de 800 a 700 en todo el rediseño: con Inter cargada de
   verdad (antes caia a la fuente del sistema) el 800 se ve macizo y grita.
   El 700 con letter-spacing negativo lee igual de jerarquico y mucho mas
   prolijo -- es la diferencia entre un titulo y un titular. */
.topbar h1,
.panel h2 {
  margin: 0;
  line-height: 1.2;
  font-weight: 700;
}

.panel h2 {
  font-size: 18px;
  letter-spacing: -0.011em;
}

.topbar h1 {
  font-size: 30px;
  letter-spacing: -0.025em;
}

.eyebrow {
  margin: 0 0 5px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  /* El tracking de 0.07em suma ~7px en una palabra de 9 letras: en las
     tarjetas angostas de 320px eso alcanzaba para cortar "Recepcion" contra
     el borde. Que envuelva antes de cortarse -- una etiqueta en dos lineas
     se lee, una cortada al medio no. */
  overflow-wrap: anywhere;
  min-width: 0;
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.primary-button,
.ghost-button,
.icon-button,
.segment {
  min-height: 38px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  /* Solo las propiedades que realmente cambian: un `transition: 150ms ease`
     sin lista anima TODO (incluido width/height si algo los toca), que es
     justo lo que la guia de animacion desaconseja por costo de layout.
     transform va aparte y mas rapido que el color: el hundido tiene que
     leerse como respuesta inmediata al dedo, el color puede tomarse su
     tiempo. */
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
  font-weight: 600;
}

/* Hundir al apretar. Es EL detalle que separa una interfaz que responde de
   una que parece una foto: sin esto el unico feedback de que el click se
   registro llega cuando el servidor contesta. scale() arrastra el texto y
   los iconos de adentro, por eso se lee como que el boton entero se aprieta.
   Va en todo lo presionable del PMS, no solo en los botones "importantes".
   :active funciona igual con dedo que con mouse, no necesita gatearse
   detras de (hover: hover) como si el hover. */
.primary-button:active:not(:disabled),
.ghost-button:active:not(:disabled),
.icon-button:active:not(:disabled),
.segment:active {
  transform: scale(0.97);
}

/* --- Respuesta al tacto en TODO lo que se toca --------------------------
   El PMS tenia 42 reglas :hover y solo 3 :active: casi nada respondia al
   click hasta que contestaba el servidor. En una herramienta que se usa a
   las apuradas en el mostrador, ese vacio se siente como que la app se
   colgo, y termina en el doble click que crea la reserva por duplicado.

   El hundido se calibra por TAMAÑO, no uniforme: un chip de 40px con
   scale(0.96) se lee perfecto, pero una fila de reserva a lo ancho de la
   pantalla con ese mismo valor se encoge varios pixeles por lado y parece
   que se rompe. Por eso las filas anchas usan un valor casi imperceptible
   -- alcanza para que el ojo registre que algo paso. */

/* Controles chicos y discretos: chips, dias del calendario, iconos. */
.gastro-chip:active,
.gastro-medio:active,
.date-badge:active,
.calendar-day:active,
.pms-datepicker-day:active,
.help-icon-btn:active,
.chat-audio-btn:active,
.topnav-item:active,
.topnav-dropdown-item:active,
.segment:active,
.link-button:active,
.view-proof:active,
.edit-payment:active,
.settings-nav-item:active {
  transform: scale(0.96);
}

/* Filas y tarjetas anchas: el mismo gesto, mucho mas contenido. */
.reservation-row:active,
.guest-row:active,
.guest-stay:active,
.inhouse-row-summary:active,
.room-card-summary:active,
.payment-search-result:active,
.planning-search-result:active,
.settings-search-result:active,
.gastro-historial-fila:active,
.reservation-block:active {
  transform: scale(0.995);
}

/* La transicion del hundido va aparte de la del color: el gesto tiene que
   verse instantaneo aunque el cambio de fondo sea mas lento. */
.gastro-chip,
.gastro-medio,
.date-badge,
.calendar-day,
.pms-datepicker-day,
.help-icon-btn,
.chat-audio-btn,
.topnav-item,
.topnav-dropdown-item,
.link-button,
.view-proof,
.edit-payment,
.settings-nav-item,
.reservation-row,
.guest-row,
.guest-stay,
.inhouse-row-summary,
.room-card-summary,
.payment-search-result,
.planning-search-result,
.settings-search-result,
.gastro-historial-fila,
.reservation-block {
  transition:
    transform var(--dur-press) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .gastro-chip:active,
  .gastro-medio:active,
  .date-badge:active,
  .calendar-day:active,
  .pms-datepicker-day:active,
  .help-icon-btn:active,
  .chat-audio-btn:active,
  .topnav-item:active,
  .topnav-dropdown-item:active,
  .link-button:active,
  .view-proof:active,
  .edit-payment:active,
  .settings-nav-item:active {
    transform: scale(0.99);
  }

  .reservation-row:active,
  .guest-row:active,
  .guest-stay:active,
  .inhouse-row-summary:active,
  .room-card-summary:active,
  .payment-search-result:active,
  .planning-search-result:active,
  .settings-search-result:active,
  .gastro-historial-fila:active,
  .reservation-block:active {
    transform: none;
  }
}

.primary-button {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
  padding: 0 16px;
  letter-spacing: -0.005em;
  /* El boton principal es lo unico "en flujo" que flota un poco: es la
     accion que la pantalla quiere que hagas, y una sombra propia lo separa
     del resto de los controles sin necesidad de agrandarlo ni gritarlo. */
  box-shadow: var(--shadow-raised);
}

.primary-button:hover:not(:disabled) {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  box-shadow: var(--shadow-overlay);
}

.ghost-button {
  background: var(--surface);
  color: var(--accent-strong);
  border-color: var(--line);
  padding: 0 13px;
}

.ghost-button.danger-text {
  color: var(--tint-red-ink);
}

/* --- Candado del precio ---------------------------------------------------
   Recepcion carga al precio que corresponde a las fechas; cambiarlo necesita
   el codigo de un admin. El campo bloqueado se ve distinto a uno normal a
   proposito: si se viera igual, se intentaria escribir en el y el silencio
   pareceria un error de la aplicacion. */
.precio-candado {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: -4px;
}

.precio-candado-texto {
  color: var(--muted);
  font-size: 12px;
}

.precio-candado .ghost-button {
  min-height: 32px;
  padding: 0 10px;
  font-size: 12px;
}

input.bloqueado {
  background: var(--surface-muted);
  color: var(--muted);
  cursor: not-allowed;
}

/* Un boton de icono es una caja fija con un dibujo en el medio, asi que el
   centrado va aca y no lo decide cada regla que le toque el `display` mas
   abajo. Sin esto quedaban descentrados de dos formas distintas:

   - Los dos "volver" de mobile (.conversation-back y .settings-detail-back)
     pasan a inline-flex para aparecer, y un contenedor flex sin
     align-items/justify-content deja su contenido arriba a la izquierda: la
     flecha del chat estaba 5,6px a la izquierda y 12px arriba del centro de
     su cuadrado de 44px.
   - Los que llevan un <svg> adentro (el lapiz de renombrar, el ojo del
     comprobante, el lapiz de editar un pago) lo apoyaban en la linea de
     base, que reserva lugar abajo para las colas de las letras: el dibujo
     quedaba 3px alto. Como flex, el svg deja de ser una caja en linea y el
     problema desaparece de raiz.

   padding 0 a proposito: el ancho ya es fijo y el centrado es simetrico, un
   padding lateral solo achica la caja donde entra el icono. */
.icon-button {
  width: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--surface);
  border-color: var(--line);
  color: var(--muted);
  font-weight: 600;
}

/* Que no se achique si el ancho del boton queda justo, y que tenga un tamaño:
   un svg con viewBox y sin width/height rendea al ancho del contenedor
   (medido: 36,4px en un boton de 38), o sea pegado a los bordes. */
.icon-button > svg {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}

/* Los hover de los controles base van detras de (hover: hover): en una
   pantalla tactil el navegador dispara :hover al tocar y lo deja PEGADO
   hasta que tocas otra cosa, asi que sin esto un boton recien apretado
   queda resaltado como si siguiera activo. El PMS se usa tanto en la PC de
   recepcion como en el telefono, y ahi el estado pegado se lee como un bug.
   El feedback tactil no se pierde: lo da :active, que arriba hunde el boton
   y funciona igual con dedo que con mouse. */
@media (hover: hover) and (pointer: fine) {
  /* Antes el hover solo cambiaba el color del borde, un cambio de 1px que
     practicamente no se percibia. Un fondo apenas teñido del color de marca
     se nota sin gritar, y ademas da la sensacion de superficie tocable. */
  .ghost-button:hover:not(:disabled) {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 7%, var(--surface));
    box-shadow: var(--shadow-raised);
  }

  .ghost-button.danger-text:hover:not(:disabled) {
    border-color: var(--red);
    background: color-mix(in srgb, var(--red) 7%, var(--surface));
  }

  .icon-button:hover:not(:disabled) {
    color: var(--ink);
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  }

  /* Los dos niveles de rojo se quedan en rojo al pasar por encima. Sin esto
     ganaria la regla de arriba y una cruz roja se volveria teal justo cuando
     el usuario apunta a ella, que es cuando mas tiene que confirmar lo que
     va a hacer. Especificidad 0,4,0 contra 0,3,0: gana sin depender del
     orden en el archivo. */
  .icon-button.salida:hover:not(:disabled),
  .ghost-button.salida:hover:not(:disabled) {
    color: var(--salida-ink);
    border-color: color-mix(in srgb, var(--salida-ink) 42%, var(--line));
    background: color-mix(in srgb, var(--salida-ink) 8%, var(--surface));
  }

  .icon-button.destructivo:hover:not(:disabled),
  .ghost-button.destructivo:hover:not(:disabled) {
    color: var(--tint-red-ink);
    border-color: color-mix(in srgb, var(--red) 45%, var(--line));
    background: color-mix(in srgb, var(--red) 10%, var(--surface));
  }
}

/* ---------------------------------------------------------------------------
   Rojo en los controles de salir y de borrar
   ---------------------------------------------------------------------------
   Dos niveles, a proposito:

   .salida       cierra, vuelve, cierra sesion. NO borra nada. Rojo apagado
                 (--salida-ink): se encuentra de un vistazo y no grita.
   .destructivo  quita/elimina de verdad. Rojo saturado (--tint-red-ink).

   Que sean dos y no uno es lo que hace que el color siga significando algo.
   Si la cruz que cierra un modal y la que borra una temporada se vieran
   iguales, el rojo dejaria de avisar nada -- y peor: pintar de rojo lo
   inofensivo y dejar en gris lo que borra es exactamente al reves de lo que
   tiene que pasar.

   Dos lugares donde a proposito NO se pone rojo:
   - El "Cancelar" de los carteles de confirmacion. En un "¿eliminar esta
     reserva?" el rojo va en Eliminar; pintar tambien la salida segura empuja
     al error que el cartel existe para evitar.
   - El par atras/adelante del historial de navegacion. Son una pareja de
     navegacion, no una salida: uno rojo y el otro gris se veria roto.

   Se usa --tint-red-ink y no --red pelado como tinta: --red (#d9480f) esta
   pensado como FONDO con texto blanco encima, y medido como texto sobre la
   superficie oscura (#2a2650) da 3.27, abajo del minimo. --tint-red-ink esta medido
   para leerse en los dos temas (6.63 claro / 7.16 oscuro).
   --------------------------------------------------------------------------- */

/* La clase va repetida a proposito. Con una sola (0,1,0) pierde contra
   cualquier regla del tipo ".extra-chip button" (0,1,1), que hay varias en
   este archivo porque muchos controles chicos se estilan por elemento adentro
   de su contenedor -- la cruz de los chips de extras se quedaba gris. Repetida
   sube a 0,2,0 y les gana a todas sin necesidad de ir enumerandolas una por
   una cada vez que aparece otra. Sigue por debajo de cualquier id, asi que un
   caso puntual se puede seguir sobrescribiendo. */
.salida.salida {
  color: var(--salida-ink);
}

.destructivo.destructivo {
  color: var(--tint-red-ink);
}

.view {
  display: none;
}

/* Cambiar de vista es la accion mas repetida del PMS: recepcion salta entre
   Planning, Reservas y Chat decenas de veces por turno. Por eso esto es un
   fundido de 120ms y NADA mas -- ni desplazamiento, ni escala.
   La regla es la frecuencia: algo que se ve 50 veces por dia no puede tener
   una animacion "linda", porque a la decima vez deja de ser linda y pasa a
   ser una espera. Lo unico que aporta es tapar el corte seco entre dos
   pantallas con contenido muy distinto, que sin esto parpadea.
   Es animation y no transition porque el elemento pasa de display:none: no
   hay estado anterior desde el cual transicionar. */
.view.active {
  display: block;
  animation: viewIn 120ms var(--ease-out);
}

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

#planning,
#listados {
  position: relative;
}

.metric-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(160px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}

.metric {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  box-shadow: var(--shadow);
}

/* Solo Inicio (renderDashboard) rellena .metric-icon -- las tarjetas de
   Estadisticas (statsKpiCard) reusan .metric sin este span, asi que esto
   nunca les cambia el layout: un position:absolute ausente no ocupa lugar. */
.metric-icon {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 18px;
  height: 18px;
  color: var(--muted);
}

.metric-icon svg {
  width: 100%;
  height: 100%;
}

/* --- Tarjeta de conteo (sin barra) --------------------------------------
   "Señas sin cubrir" es un conteo de pendientes, no un avance: el ideal es
   CERO, no llenar nada. Una barra ahi mentiria -- necesitaria un total
   contra el cual completarse que no existe.
   En vez de barra lleva una linea fija, colocada en LA MISMA RANURA que
   ocupa la barra de las otras tarjetas. Asi la fila conserva una base
   visual continua y la diferencia se lee como una decision, no como una
   tarjeta a la que le falta algo. (Al principio use el borde inferior de la
   tarjeta y la linea caia mas abajo que las barras vecinas, porque el
   borde queda despues del texto de ayuda.) */
/* `.metric.metric-conteo` y no `.metric-conteo` a secas: la regla que pone
   el borde inferior de 2px (`#inicio .metric`) vive MAS ABAJO en el archivo
   y con la misma especificidad le ganaba por orden, asi que la tarjeta
   quedaba con la linea naranja alineada Y ademas el borde gris viejo abajo,
   dos rayas. Detectado midiendo borderBottomWidth computado, no mirando la
   captura. */
#inicio .metric.metric-conteo {
  border-bottom: none;
}

.metric-regla {
  margin-top: 12px;
  height: 6px;
  display: flex;
  align-items: center;
}

/* --- Las tarjetas del panel son botones ---------------------------------
   Son <button> y no <article> porque se pueden tocar para ver el detalle:
   asi llegan por Tab, responden a Enter/Espacio y los lectores de pantalla
   las anuncian como accionables. Un <article> con un onclick no hace nada
   de eso.
   Como contrapartida hay que devolverles lo que el navegador le saca a un
   boton: alineacion a la izquierda, tipografia heredada y ancho completo. */
#metric-grid .metric {
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}

#metric-grid .metric:active {
  transform: scale(0.99);
}

/* El hover se marca con un fondo apenas teñido, no con sombra ni borde: la
   tarjeta de Inicio es plana a proposito (estilo suizo) y darle relieve al
   pasar por encima rompeeria ese lenguaje. */
@media (hover: hover) and (pointer: fine) {
  #metric-grid .metric:hover {
    background-color: color-mix(in srgb, var(--accent) 5%, transparent);
  }
}

/* --- Detalle de la metrica --- */

/* Dos clases y no una: .pms-confirm-modal (380px) esta declarada MAS ABAJO
   en el archivo con la misma especificidad, asi que un .metric-detail-modal
   suelto perdia sin aviso y el detalle salia a 380px. Ahi adentro "Check-outs
   de hoy" ponia el boton al lado de cada fila y quedaban dos columnas
   iguales, con el nombre partido letra por letra (captura del dueño, 04/10).
   En telefono la hoja va a lo ancho: lo repite el bloque de .pms-confirm-modal
   de telefono, con estas mismas dos clases para ganarle a esta. */
.pms-confirm-modal.metric-detail-modal {
  width: min(560px, 100%);
}

/* Lo mismo con el subtitulo: .pms-confirm-modal p (clase + elemento) le
   ganaba a .metric-detail-sub y le sacaba el margen, y su overflow:auto con
   min-height:0 (pensados para el mensaje largo de una confirmacion) dejaba
   que la lista lo aplastara: con varias filas "1 de 5 ya salieron" salia
   cortado por la mitad y pegado a la primera. Lo que scrollea aca es la lista. */
.metric-detail-modal .metric-detail-sub {
  margin: 0 0 12px;
  flex-shrink: 0;
  overflow: visible;
  color: var(--muted);
  font-size: 13px;
}

.metric-detail-body {
  overflow-y: auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Las filas con boton deciden si lo llevan al lado o abajo segun el ancho
     de LA LISTA y no de la pantalla: la misma ventana es una caja de 560px en
     escritorio y una hoja a lo ancho en un telefono o una tablet. */
  container-type: inline-size;
  container-name: detalle-metrica;
}

.metric-detail-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}

.metric-detail-row:active:not(:disabled) {
  transform: scale(0.995);
}

@media (hover: hover) and (pointer: fine) {
  .metric-detail-row:hover:not(:disabled) {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  }
}

/* Sin reserva asociada la fila no lleva a ningun lado: se muestra igual
   (el dato importa) pero no finge ser cliqueable. */
.metric-detail-row:disabled {
  cursor: default;
  opacity: 0.75;
}

/* --- Fila con su accion ("Check-outs de hoy") ----------------------------
   [Hacer check-out] / [Cobrar $X] en cada salida. La fila sigue abriendo la
   reserva y el boton hace la accion: dos botones HERMANOS, no uno adentro del
   otro (un <button> dentro de otro no es HTML valido).

   El boton se dibuja ADENTRO de la tarjeta de su fila: la fila ocupa la caja
   entera y, con subgrid, deja libre a su derecha la columna que mide el
   boton. Antes iban lado a lado y el boton se estiraba al alto de la fila
   (270px en una combinada): un bloque teal que parecia otra tarjeta y se
   quedaba con la mitad del ancho. Asi la tarjeta es UNA, el texto se queda
   con lo que el boton no usa y el boton tiene alto de boton.
   Tocar la tarjeta en cualquier lugar que no sea el boton abre la reserva (la
   fila esta DEBAJO del boton, no al costado), y al pasar por encima del boton
   la tarjeta no se resalta: lo que se va a tocar es el boton. */
.metric-detail-row-con-accion {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
}

.metric-detail-row-con-accion > .metric-detail-row {
  grid-row: 1;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
}

.metric-detail-row-con-accion > .metric-detail-row > .metric-detail-row-main {
  grid-column: 1;
}

.metric-detail-accion {
  grid-row: 1;
  grid-column: 2;
  align-self: center;
  /* El borde (1px) mas el padding (12px) de la fila: el boton queda a la
     misma distancia del borde derecho que el texto del izquierdo. */
  margin-right: 13px;
  /* Encima de la fila, que esta debajo: al apretarla, su scale() la pinta
     por arriba de todo lo que no este posicionado y el boton desapareceria
     un instante. */
  position: relative;
  z-index: 1;
  /* Alto y letra de boton de fila, no de pie de ventana: va al lado de un
     texto de 13,5px. En pantallas tactiles el bloque de 44px de mas abajo lo
     vuelve a subir (misma especificidad, declarado despues). */
  min-height: 36px;
  padding: 0 14px;
  font-size: 13px;
  white-space: nowrap;
}

/* En una lista angosta (telefono) el boton no entra al lado sin dejar el
   nombre en tres renglones: baja, a lo ancho, pero ADENTRO de la tarjeta.
   Antes iba debajo como un pie pegado con la union recta; adentro no hay
   duda de que reserva es. 440px: al lado de un boton de ~150px el texto
   necesita ~250 para que una combinada ("DBL 106 + TPL 109 · Estrella
   Duarte") entre en un renglon. */
@container detalle-metrica (max-width: 439px) {
  .metric-detail-row-con-accion {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
  }

  .metric-detail-row-con-accion > .metric-detail-row {
    grid-row: 1 / -1;
    grid-template-rows: subgrid;
  }

  .metric-detail-row-con-accion > .metric-detail-row > .metric-detail-row-main {
    grid-row: 1;
  }

  .metric-detail-accion {
    grid-row: 2;
    grid-column: 1;
    margin: 0 13px 13px;
  }
}

/* Sin subgrid (navegadores anteriores a 2023) la fila no sabe cuanto mide el
   boton y el texto le pasaria por debajo: ahi el boton vuelve a quedar afuera
   de la tarjeta (al lado, o abajo en una lista angosta), sin pisar nada. */
@supports not (grid-template-columns: subgrid) {
  .metric-detail-row-con-accion > .metric-detail-row {
    grid-row: 1;
    grid-column: 1;
  }

  .metric-detail-accion {
    margin: 0;
  }
}

.metric-detail-row-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* break-word y no anywhere: anywhere deja que el navegador corte CUALQUIER
   palabra por cualquier letra en cuanto la columna se angosta ("Marian / a
   Falco"); break-word solo parte una palabra que no entra sola en un renglon. */
.metric-detail-row-main strong {
  font-size: 13.5px;
  overflow-wrap: break-word;
}

/* Solo los hijos directos: con cualquier descendiente, los pedazos del titulo
   y la pastilla del renglon del codigo heredaban este gris de 12px. */
.metric-detail-row-main > span {
  font-size: 12px;
  color: var(--muted);
}

/* Un pedazo que se muda ENTERO de renglon ("TPL 107", "ST-72GF5Y", "debe
   $1.250.000.-"): el renglon se parte entre pedazos, nunca adentro. Es
   inline-block y no nowrap a proposito: uno que no entre ni solo en un
   renglon se parte igual, en vez de salirse de la tarjeta. */
.metric-detail-junto {
  display: inline-block;
  max-width: 100%;
}

/* Renglon del codigo en una lista con acciones: la pastilla de estado va
   primera, donde no le saca ancho al nombre y todas quedan encolumnadas. Mas
   baja que la de la derecha (1px y no 3px de alto extra) para que el renglon
   no pase de los 20px. */
.metric-detail-row-meta {
  margin-top: 2px;
}

.metric-detail-row-meta .metric-detail-tag {
  display: inline-block;
  margin-right: 4px;
  padding: 1px 8px;
}

.metric-detail-tag {
  flex: 0 0 auto;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--tint-orange-ink);
  background: color-mix(in srgb, var(--orange) 13%, transparent);
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Lo ya resuelto (ya ingreso / ya salio) se apaga: la lista muestra TODO el
   dia para que coincida con la barra, pero lo que queda por hacer tiene que
   destacarse sobre lo que ya esta hecho. */
.metric-detail-row.hecho {
  background: color-mix(in srgb, var(--ink) 2%, var(--surface));
}

.metric-detail-row.hecho .metric-detail-tag {
  color: var(--tint-green-ink);
  background: color-mix(in srgb, var(--green) 13%, transparent);
}

.metric-detail-row.hecho .metric-detail-row-main strong {
  color: var(--muted);
  font-weight: 500;
}

.metric-regla::before {
  content: "";
  display: block;
  width: 100%;
  height: 2px;
  border-radius: var(--radius-pill);
  background: var(--line);
}

/* Con al menos una reserva corta de seña, la linea y el numero toman el
   naranja de atencion. Es informacion accionable -- alguien tiene que ir a
   pedir esa seña -- y a cero tiene que verse tranquila, no verde: cero no
   es un logro, es el estado normal. */
#inicio .metric-conteo.metric-alerta .metric-regla::before {
  background: var(--orange);
}

/* --tint-orange-ink y no --orange pelado: el naranja pleno (#f9844a) esta
   pensado para usarse como FONDO con texto blanco encima; como texto sobre
   el fondo claro de la pagina da 2.35:1, por debajo del 3:1 que pide un
   texto grande. El token de tinte es la version oscurecida del mismo
   naranja, medida para leerse sobre fondo claro (y se da vuelta sola en
   modo oscuro). El borde inferior si se queda con el naranja pleno: es un
   refuerzo visual, no el unico portador del dato. */
#inicio .metric-conteo.metric-alerta strong {
  color: var(--tint-orange-ink);
}

#inicio .metric-conteo.metric-alerta .metric-icon {
  color: var(--tint-orange-ink);
}

/* Inicio: "Minimalism & Swiss Style" (ui-ux-pro-max, --domain style) aplicado
   SOLO a esta vista -- .metric/.panel/.alert-item se comparten con
   Estadisticas/Limpieza/Chat/Configuracion, asi que todo esto son overrides
   encima de la base compartida (nunca ediciones a esa regla), gateados por
   #inicio para no arrastrar el cambio a las otras vistas. Plano en vez de
   tarjetas con sombra: sin --shadow, bordes finos como unico separador,
   jerarquia por tipografia (numero grande, label chica en mayusculas) en vez
   de por chrome. El acento sigue siendo el teal/naranja de siempre -- la
   skill sugirio paletas navy+dorado (hospitalidad "de lujo") que no son la
   identidad de este hotel, asi que se descartaron a proposito. */
#inicio .metric {
  background: transparent;
  border: none;
  border-bottom: 2px solid var(--line);
  /* El radio NO se ve en reposo -- la tarjeta es transparente y sin borde,
     asi que lo plano del estilo suizo queda igual. Se ve cuando la tarjeta se
     MARCA: el fondo tenido del hover y el anillo de foco del teclado, que
     hasta el 07/10 salian con las esquinas a 90 grados en el medio de una
     pantalla toda redondeada (pedido de Juan: "que siga las curvas de toda la
     pagina"). Va aca y no adentro del :hover por el foco: la regla global
     (`button:focus-visible`) pone --radius-sm, pero `#inicio .metric` le gana
     por especificidad (1,1,0 contra 0,1,1), asi que el valor de ESTA linea es
     el que termina usando el anillo -- con el 0 de antes, el outline del
     teclado tambien era un cuadrado. --radius y no --radius-sm porque esto es
     una tarjeta, como las de Estadisticas (`.metric` base), no un control
     chico.
     Las 4 tarjetas de Inicio anulan el borde inferior de aca (.metric-bar y
     .metric-conteo, mas abajo), asi que el radio no curva las puntas de
     ninguna linea: lo unico que recorta es el fondo de la marca. */
  border-radius: var(--radius);
  box-shadow: none;
  padding: 18px 4px 16px;
}

#inicio .metric span:not(.metric-icon) {
  text-transform: uppercase;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
}

#inicio .metric strong {
  font-size: 32px;
  margin-top: 10px;
}

/* --- Barras de progreso del panel --------------------------------------
   Las 4 metricas de Inicio dejan de ser numeros sueltos y pasan a mostrar
   cuanto de lo de HOY ya esta resuelto. Un "3" no dice si es mucho o poco;
   "1 de 3" con la barra a un tercio se entiende sin leer.

   La barra OCUPA EL LUGAR del borde inferior de 2px que ya tenia la
   tarjeta: el dato pasa a ser la linea, en vez de sumar un elemento que
   compite con ella. Por eso aca se saca el borde -- si quedaran los dos, la
   tarjeta tendria dos rayas horizontales pegadas diciendo cosas distintas. */
#inicio .metric-bar {
  border-bottom: none;
  padding-bottom: 14px;
}

.metric-progress {
  margin-top: 12px;
  height: 6px;
  border-radius: var(--radius-pill);
  /* El canal es el estado "sin hacer": tiene que verse, pero apenas -- es el
     fondo contra el que se lee el avance, no un dato en si mismo. */
  background: color-mix(in srgb, var(--ink) 9%, transparent);
  overflow: hidden;
}

.metric-progress-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--gray);
  /* Se anima el ANCHO y no un transform:scaleX porque la barra tiene bordes
     redondeados: escalar deformaria el radio de las puntas. Son 4 barras que
     cambian pocas veces por turno, asi que el costo de layout es
     irrelevante frente a que se vea bien. */
  transition: width 420ms var(--ease-out), background-color 260ms var(--ease-out);
}

/* Rojo / amarillo / verde segun cuanto falta.
   La BARRA usa los colores plenos y el NUMERO los tokens de tinte, y no es
   un descuido: son dos problemas distintos. La barra es una forma sobre un
   canal gris -- solo necesita distinguirse; el numero es texto y necesita
   contraste real contra el fondo. Al principio puse el tinte en los dos y
   el amarillo (#7d611a, pensado para leerse como texto) salia marron: no
   comunicaba "atencion", que es justo lo que tiene que decir.
   El color NUNCA es la unica señal: arriba esta el numero ("1 de 3") y
   abajo el texto ("faltan 2 por ingresar"), asi que quien no distingue
   rojo de verde lee exactamente lo mismo. */
.metric-bar.nivel-rojo .metric-progress-fill { background: var(--red); }
.metric-bar.nivel-amarillo .metric-progress-fill { background: var(--yellow); }
.metric-bar.nivel-verde .metric-progress-fill { background: var(--green); }

/* Sin nada programado hoy la barra queda VACIA, no llena. Llenarla de gris
   parecia razonable ("no queda nada pendiente") pero en pantalla la tarjeta
   sin trabajo terminaba con la barra mas larga de la fila, robandole la
   atencion justo a las que si tienen algo que hacer. Vacia + el texto "No
   hay salidas programadas" se entiende sin competir. */
.metric-bar.nivel-neutro .metric-progress-fill {
  background: transparent;
}

/* El numero grande toma el color del estado, igual que la barra: es el
   mismo dato dicho dos veces, no dos datos. Los tokens de tinte estan
   medidos para leerse sobre fondo claro y se dan vuelta solos en oscuro. */
#inicio .metric-bar.nivel-rojo strong { color: var(--tint-red-ink); }
#inicio .metric-bar.nivel-amarillo strong { color: var(--tint-yellow-ink); }
#inicio .metric-bar.nivel-verde strong { color: var(--tint-green-ink); }

/* --- Ocupacion: la gente al lado del % ----------------------------------
   Cuantos huespedes hay en el hotel iba en la letra chica de abajo y no se
   veia de un vistazo (pedido de Juan, 05/10). Va al MISMO tamaño que el %,
   separado por una raya y en el color del texto: el rojo/amarillo/verde es
   del avance de la barra, y "12 huespedes" no esta bien ni mal. Sigue en la
   misma tarjeta y no en una propia (pedido anterior: no sobrecargar Inicio).
   La regla de color tiene que ganarle a `#inicio .metric-bar.nivel-x strong`
   (misma especificidad, por eso va despues). */
.metric-cifras {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 14px;
}

/* La unidad ("HUESPEDES") no lleva regla propia: la toma de
   `#inicio .metric span:not(.metric-icon)`, el mismo estilo que el rotulo de
   la tarjeta. Es lo que dice que es el numero, no el dato. */
#inicio .metric-cifras strong.metric-segunda-cifra {
  padding-left: 14px;
  border-left: 1px solid var(--line);
  color: var(--ink);
  white-space: nowrap;
}

/* Sin esto la unidad hereda el alto de renglon de la cifra y, por ser de
   otro tamaño, lo estira (apiladas: 28px en vez de 24). Las tarjetas son
   <button> y un boton CENTRA su contenido: esos 4px corrian 2px hacia abajo
   todo lo de las tarjetas vecinas, barra incluida. */
#inicio .metric-segunda-cifra span {
  line-height: 1;
}

/* Tarjeta angosta (telefono, y escritorio de menos de ~1170px): "100% |
   204 HUESPEDES" no entra en un renglon. Las dos cifras van una abajo de la
   otra, a la mitad del alto de renglon de la cifra de las tarjetas vecinas
   (32px con renglon de 48): 10 de margen + 24 + 24 = lo mismo que ocupa
   "1 de 3" al lado. Si la tarjeta creciera, su barra quedaria mas abajo que
   las de la fila. El corte sale de medir: "100% | 999 HUESPEDES" en un
   renglon pide 253px de contenido. */
@container (max-width: 260px) {
  #inicio .metric-cifras {
    flex-direction: column;
    align-items: stretch;
  }

  #inicio .metric-cifras strong {
    font-size: 24px;
    line-height: 24px;
  }

  #inicio .metric-cifras strong.metric-segunda-cifra {
    margin-top: 0;
    padding-left: 0;
    border-left: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .metric-progress-fill {
    transition: background-color 260ms var(--ease-out);
  }
}

#inicio .metric-icon {
  opacity: 0.7;
}

#inicio .metric-grid {
  gap: 24px 18px;
  margin-bottom: 28px;
}

/* Mobile: contenido centrado en cada tarjeta de metrica.
   Mismo breakpoint (980px) en el que .metric-grid pasa a 2 columnas -- en esa
   grilla angosta el texto alineado a la izquierda dejaba las dos columnas
   visualmente desbalanceadas, con el numero pegado al borde y un hueco a la
   derecha distinto en cada tarjeta segun el largo del rotulo.
   El icono deja de estar posicionado en la esquina (position:absolute) y pasa
   a ser un bloque centrado arriba del rotulo: una esquina fija sobre un
   contenido centrado se ve descolgada, y ademas en 179px de ancho se
   superponia con los rotulos largos ("Habitaciones ocupadas"). */
@media screen and (max-width: 980px) {
  #inicio .metric {
    text-align: center;
    padding-top: 16px;
  }

  #inicio .metric-icon {
    position: static;
    display: block;
    margin: 0 auto 8px;
  }

  #inicio .metric-cifras {
    justify-content: center;
  }
}

#inicio .panel {
  box-shadow: none;
}

/* Se deja pasar el fondo teñido de .alert-item (no se pisa con transparent):
   ahora que toda la app es plana, la alerta de Inicio no tiene motivo para
   ser el unico aviso sin color de fondo. Lo que si se saca es la caja: sigue
   siendo una fila con su franja lateral, no una tarjeta. */
#inicio .alert-item {
  border-top: none;
  border-right: none;
  border-bottom: none;
  border-radius: var(--radius-sm);
  padding: 13px 14px;
}

.metric span {
  color: var(--muted);
  font-size: 13px;
}

.metric strong {
  display: block;
  margin-top: 8px;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.metric small {
  color: var(--muted);
}

.two-column,
/* minmax(0, 1fr) en vez de 1fr: `1fr` es minmax(AUTO, 1fr), y ese `auto`
   significa "nunca mas angosto que el min-content del hijo". Estas dos
   grillas contienen tablas, graficos y formularios cuyo min-content ronda
   los 330px, asi que en una pantalla de 320 la columna se plantaba en 330 y
   empujaba la PAGINA ENTERA a scroll horizontal -- se veia como que la app
   "no entra" en el telefono. Con minmax(0, ...) la columna puede achicarse
   y lo que no entra scrollea dentro de su propio contenedor. */
.reservations-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
}

#inicio .panel + .panel {
  margin-top: 18px;
}

/* Dentro de .two-column la separacion la da el `gap` de la grilla. Sin esta
   excepcion, la regla de arriba le suma 18px de margen superior al segundo
   panel y las dos columnas quedan desalineadas por altura -- un panel
   arrancando 18px mas abajo que el de al lado. */
#inicio .two-column .panel + .panel {
  margin-top: 0;
}

/* "Tareas pendientes" y "Prioridad de hoy" van UNA AL LADO DE LA OTRA.
   El contenedor se llamaba .two-column desde siempre pero nunca tuvo dos
   columnas: estaba definido con una sola y ninguna media query lo abria,
   asi que los dos paneles se apilaban a lo ancho completo. Son dos listas
   angostas (una tarea por linea, una alerta por linea): a 1400px de ancho
   cada linea usaba menos de un tercio del espacio y el resto era aire, lo
   que empujaba "En estadia" fuera de la primera pantalla.
   981px es el mismo corte que ya usa el resto de la app; por debajo siguen
   apilados, que en un telefono es lo correcto. */
@media (min-width: 981px) {
  #inicio .two-column {
    /* Las tareas se llevan mas ancho (06/10): son las que tienen nombre,
       habitacion, detalle y un boton por fila. Las prioridades son una fila
       corta cada una y con 300px les alcanza. */
    grid-template-columns: minmax(0, 1.65fr) minmax(300px, 1fr);
    align-items: start;
  }
}

.inhouse-summary {
  color: var(--muted);
  font-size: 13px;
}

.inhouse-list {
  display: grid;
  gap: 8px;
  margin-top: 4px;
}

.inhouse-row {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

/* Header SIEMPRE visible, compacto -- lo unico que hace falta para priorizar
   de un vistazo con muchas habitaciones en estadia a la vez: donde, quien, y
   los 3 estados que importan (combinada/sale hoy/saldo). Es un <button>
   entero (no un div con onclick) para que expandir/colapsar sea accesible
   por teclado gratis. El resto de la info (contacto, extras, notas,
   acciones) vive en .inhouse-card-body, un hermano NO un hijo -- adentro hay
   inputs/botones propios, y un <button> no puede anidar otro botón valido. */
.inhouse-row-summary {
  display: grid;
  grid-template-columns: minmax(90px, 160px) minmax(180px, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.inhouse-row-summary:hover {
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}

.inhouse-row-room {
  font-weight: 700;
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inhouse-row-guest {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.inhouse-row-guest strong {
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inhouse-row-guest span {
  color: var(--muted);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.inhouse-row-tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 4px;
}

.inhouse-row-chevron {
  width: 18px;
  height: 18px;
  color: var(--muted);
  flex-shrink: 0;
  transition: transform 150ms ease;
}

.inhouse-row.expanded .inhouse-row-chevron {
  transform: rotate(180deg);
}

.inhouse-card-body {
  display: none;
  gap: 10px;
  padding: 12px 14px 14px;
  border-top: 1px solid var(--line);
}

.inhouse-row.expanded .inhouse-card-body {
  display: grid;
}

@media (max-width: 640px) {
  .inhouse-row-summary {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "room chevron"
      "guest guest"
      "tags tags";
    row-gap: 6px;
  }

  /* grid-area solo ACA adentro, nunca en la regla de escritorio de arriba --
     un grid-area con un nombre que no matchea ningun grid-template-areas del
     contenedor (el layout de escritorio no tiene, usa las 4 columnas
     explicitas en orden de DOM) igual le genera pistas implicitas fantasma
     al grid, rompiendo el ancho de las columnas reales (bug real
     encontrado: las 3 primeras columnas del header quedaban todas con el
     mismo ancho, con 3 pistas de mas en 0px). */
  .inhouse-row-room {
    grid-area: room;
  }

  .inhouse-row-guest {
    grid-area: guest;
  }

  .inhouse-row-tags {
    grid-area: tags;
    justify-content: flex-start;
  }

  .inhouse-row-chevron {
    grid-area: chevron;
  }
}

.inhouse-extras {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.inhouse-notes-label {
  display: block;
  font-size: 12px;
  color: var(--muted);
  font-weight: 700;
}

.inhouse-notes {
  display: block;
  width: 100%;
  margin-top: 4px;
  min-height: 52px;
  resize: vertical;
  font-family: inherit;
  font-size: 13px;
  font-weight: 400;
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px;
}

.inhouse-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.inhouse-actions .inhouse-checkout {
  margin-left: auto;
}

.inhouse-actions .inhouse-checkout:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Con una reserva abierta, la lista es una columna ANGOSTA y el detalle se
   lleva el resto (pedido de Juan, 05/10: "achicar la parte izquierda ... y
   darle mas espacio a los datos de la reserva"). Antes iban casi mitad y
   mitad (0.95fr / 1.05fr): a 1366 la lista se quedaba con ~620px para
   mostrar dos renglones por fila y el detalle no llegaba a tres columnas de
   campos. La lista compacta (ver .detail-open .reservation-row) solo
   necesita nombre, fechas y estado: con 264-340px le alcanza.
   clamp y no fr: el ancho de la lista no tiene por que crecer con la
   pantalla, lo que sobra es del detalle. Por debajo de 981px esta regla no
   corre: ahi el detalle es la pantalla entera (bloque max-width: 980px). */
.reservations-layout.detail-open {
  grid-template-columns: clamp(264px, 24vw, 340px) minmax(0, 1fr);
}

.reservations-layout > .panel {
  min-width: 0;
}

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: var(--shadow);
}

.panel-header,
.conversation-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 16px;
}

.panel-header > div,
.conversation-header > div {
  min-width: 0;
}

.panel-header h2 {
  overflow-wrap: anywhere;
}

.task-list,
.alert-list,
.cleaning-board,
.knowledge-list {
  display: grid;
  gap: 10px;
}

.alert-item,
.cleaning-card,
.conversation-item,
.knowledge-list div {
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--radius);
}

.alert-item strong,
.conversation-item strong,
.cleaning-card strong {
  display: block;
}

.alert-item span,
.conversation-item span,
.cleaning-card span {
  color: var(--muted);
  font-size: 13px;
}

/* Badges de estado: fondo teñido + texto del mismo tono, en vez del color
   pleno con texto blanco de antes.
   El motivo no es solo estetico: una pantalla del PMS llega a tener 20+
   badges a la vez (Planning, Reservas, Clientes), y con el color pleno todos
   competian por la atencion con la misma intensidad que una alerta real, asi
   que ninguno terminaba destacando. Teñidos, el color sigue distinguiendo el
   estado de un vistazo pero deja de gritar; lo que de verdad urge (una
   alerta, una metrica en rojo) vuelve a poder destacarse por encima.
   Cada tono usa su --tint-*-ink, medido para contraste sobre el tinte real
   en los dos temas (ver los tokens en :root). */
.pill {
  display: inline-flex;
  align-items: center;
  min-height: 22px;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.005em;
  white-space: nowrap;
  border: 1px solid transparent;
}

.pill.red,
.pill.vencida {
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--red) 26%, transparent);
  color: var(--tint-red-ink);
}

.pill.orange {
  background: color-mix(in srgb, var(--orange) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--orange) 32%, transparent);
  color: var(--tint-orange-ink);
}

.pill.blue,
.pill.en-curso {
  background: color-mix(in srgb, var(--blue) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--blue) 26%, transparent);
  color: var(--tint-blue-ink);
}

.pill.green,
.pill.confirmada {
  background: color-mix(in srgb, var(--green) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--green) 26%, transparent);
  color: var(--tint-green-ink);
}

/* Un color por cada estado real de reserva (statusClass), no solo 4 colores
   genericos compartidos entre varios estados distintos — asi "Confirmada",
   "Check-in realizado", "En estadia" y "Check-out realizado" (antes todos
   verdes) se distinguen de un vistazo. */
.pill.pre-reserva {
  background: color-mix(in srgb, var(--yellow) 24%, var(--surface));
  border-color: color-mix(in srgb, var(--yellow) 46%, transparent);
  color: var(--tint-yellow-ink);
}

.pill.pendiente {
  background: color-mix(in srgb, #c1440e 12%, var(--surface));
  border-color: color-mix(in srgb, #c1440e 26%, transparent);
  color: var(--tint-red-ink);
}

.pill.finalizada,
.pill.cancelada,
.pill.lead-new {
  background: var(--surface-muted);
  border-color: var(--line);
  color: var(--tint-gray-ink);
}

/* La franja lateral baja de 4px a 3px y el fondo se tiñe apenas del mismo
   color: con los badges ya calmados (ver .pill arriba), la alerta es lo que
   tiene que ganar la atencion en la pantalla, y un fondo teñido pesa mas que
   una linea gruesa sin dejar de ser sobrio. */
.alert-item {
  padding: 13px 14px;
  border-left: 3px solid var(--orange);
  background: color-mix(in srgb, var(--orange) 6%, var(--surface));
}

/* Las alertas accionables son <button>: hay que devolverles lo que el
   navegador le saca a un boton (ancho, alineacion, tipografia heredada).
   La de "todo al dia" queda como <article> y no entra por este selector,
   asi que no finge ser tocable. */
button.alert-item {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}

button.alert-item:active {
  transform: scale(0.995);
}

/* El hover refuerza el tinte que la alerta ya tiene por nivel, en vez de
   pisarlo con un color propio: una alerta roja tiene que seguir leyendose
   roja mientras el mouse esta encima. */
@media (hover: hover) and (pointer: fine) {
  button.alert-item.alert-orange:hover {
    background: color-mix(in srgb, var(--orange) 13%, var(--surface));
  }
  button.alert-item.alert-red:hover {
    background: color-mix(in srgb, var(--red) 13%, var(--surface));
  }
  button.alert-item.alert-blue:hover {
    background: color-mix(in srgb, var(--blue) 13%, var(--surface));
  }
}

.alert-item.alert-orange {
  border-left-color: var(--orange);
  background: color-mix(in srgb, var(--orange) 6%, var(--surface));
}

.alert-item.alert-red {
  border-left-color: var(--red);
  background: color-mix(in srgb, var(--red) 6%, var(--surface));
}

.alert-item.alert-blue {
  border-left-color: var(--blue);
  background: color-mix(in srgb, var(--blue) 6%, var(--surface));
}

.alert-item.good {
  border-left-color: var(--green);
  background: color-mix(in srgb, var(--green) 6%, var(--surface));
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.toolbar-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.search-field {
  position: relative;
  min-width: 280px;
}

/* Dropdown de resultados del buscador de Planning -- mismo patron visual que
   .payment-search-results (Pagos). */
/* Ancho propio (no "left:0; right:0" copiando el ancho del input) a
   proposito: el campo de busqueda vive en un toolbar apretado junto a otros
   controles y en pantallas de laptop comunes (1024px) queda de apenas
   ~190px -- calcado a eso, el nombre del huesped y el pill de estado no
   entraban ni recortados. min() contra 100vw evita que se salga de pantalla
   en mobile, donde el toolbar apila los controles angosto. */
.planning-search-results {
  display: none;
  position: absolute;
  z-index: 6;
  left: 0;
  width: min(340px, calc(100vw - 32px));
  top: calc(100% + 4px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
  padding: 6px;
  max-height: 320px;
  overflow-y: auto;
  flex-direction: column;
  gap: 4px;
}

.planning-search-results.visible {
  display: flex;
}

.planning-search-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  border: none;
  background: transparent;
  border-radius: var(--radius);
  padding: 8px 10px;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
}

.planning-search-result:hover {
  background: var(--accent-soft);
}

/* Sin min-width:0 un item de flex nunca se achica mas alla del ancho que
   pide su contenido -- el nombre peleaba por espacio contra el pill de
   estado en vez de recortarse prolijo, y terminaba viendose grande/apretado
   en la columna angosta que le quedaba. flex:1 1 auto para que ocupe todo
   el lugar que el pill (flex-shrink:0, abajo) le deja libre. */
.planning-search-result-info {
  flex: 1 1 auto;
  min-width: 0;
}

.planning-search-result strong {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 12.5px;
}

.planning-search-result span {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 2px;
}

.planning-search-result .pill {
  flex-shrink: 0;
}

.hidden {
  display: none !important;
}

.compact-panel {
  margin-bottom: 14px;
}

.reservation-form {
  display: grid;
  grid-template-columns: repeat(4, minmax(140px, 1fr));
  gap: 12px;
}

.reservation-form label,
.detail-form label {
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
}

.reservation-form input,
.reservation-form select,
.detail-form input,
.detail-form select,
.detail-form textarea {
  min-height: 40px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
  margin-top: 6px;
}

.detail-form textarea {
  min-height: 74px;
  padding: 10px;
  resize: vertical;
}

.wide {
  grid-column: span 2;
}

.segment {
  background: var(--surface);
  border-color: var(--line);
  padding: 0 12px;
  color: var(--muted);
  font-weight: 700;
}

.segment.active {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  color: var(--accent-strong);
}

.planning-wrap {
  overflow-x: scroll;
  overflow-y: auto;
  background: var(--surface);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  position: relative;
  scrollbar-gutter: stable;
}

.planning-wrap::-webkit-scrollbar {
  width: 14px;
  height: 14px;
}

.planning-wrap::-webkit-scrollbar-track {
  background: var(--surface-muted);
}

.planning-wrap::-webkit-scrollbar-thumb {
  background: var(--gray);
  border: 3px solid var(--surface-muted);
  border-radius: 999px;
}

.planning-wrap::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
}


.planning-grid {
  min-width: 1234px;
}

.mini-calendar {
  position: absolute;
  right: 16px;
  top: 74px;
  z-index: 8;
  width: min(340px, calc(100vw - 48px));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-float);
  padding: 12px;
}

.mini-calendar-header {
  display: grid;
  grid-template-columns: 92px 1fr 92px;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.mini-calendar-header strong {
  text-align: center;
  color: var(--ink);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
}

.mini-calendar-header .ghost-button {
  min-height: 34px;
  padding: 0 9px;
  font-size: 12px;
}

.mini-calendar-weekdays,
.mini-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
}

.mini-calendar-weekdays span {
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  text-align: center;
}

.calendar-day {
  min-height: 34px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--surface-muted);
  color: var(--ink);
  font-weight: 700;
}

.calendar-day:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.calendar-day.muted {
  color: var(--gray);
  background: var(--surface-muted);
}

.calendar-day.today {
  background: var(--accent);
  color: var(--on-accent);
}

.planning-header,
.planning-row {
  display: grid;
  grid-template-columns: 142px repeat(14, 78px);
}

.planning-header {
  position: sticky;
  top: 0;
  z-index: 5;
}

.planning-row {
  position: relative;
  /* --alto-fila-rack lo escribe app.js en #planning-grid: cuando el rack tiene
     pocas filas (un complejo de 3 cabañas) se reparte el alto disponible para
     que no queden 3 franjas finitas flotando en un panel vacio. El 34px es el
     minimo de siempre, y el fallback si la variable no esta. */
  min-height: var(--alto-fila-rack, 34px);
}

/* grid-row:1 explicito en TODAS las celdas del rack.
   Las celdas de dia se reciclan al scrollear (ver pintarColumnasVisibles en
   app.js), asi que su orden en el DOM deja de coincidir con el de sus columnas.
   Con la fila en "auto", el algoritmo de auto-colocacion de CSS Grid no puede
   retroceder el cursor: cada celda cuya columna es menor que la anterior abre
   una fila NUEVA. El efecto medido fue una fila de 1.844 px de alto en vez de
   34, con la grilla practicamente en blanco y el layout carisimo. Fijando la
   fila, ninguna celda queda en auto-colocacion y el orden del DOM deja de
   importar. */
.planning-row > .cell,
.planning-header > .cell {
  grid-row: 1;
}

/* El alto variable es solo para las filas de datos: la de fechas se queda en
   su alto propio. Sin este recorte, el encabezado crecia igual que las filas
   y quedaba una banda de fechas del mismo grosor que una habitacion. */
.planning-row > .cell {
  min-height: var(--alto-fila-rack, 34px);
}

.cell {
  min-height: 34px;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 4px;
  background: var(--surface);
  font-size: 11px;
  /* Los dias sueltos (sin .header ni .room) se pueden arrastrar para crear
     una reserva -- ver bindPlanningDragSelect en app.js. user-select:none
     evita que arrastrar dispare una seleccion de texto nativa del navegador
     por encima (el room-label vecino si tiene texto). */
  user-select: none;
}

.cell:not(.header):not(.room) {
  /* "cell" es justo el cursor pensado para "esto se puede seleccionar como
     una celda de planilla" -- afordancia que a Avirato (la referencia de
     este gesto) le falta por completo. */
  cursor: cell;
}

/* SIN position:sticky por celda. La fila contenedora (.planning-header) ya es
   sticky, asi que cada celda tambien serlo no aportaba nada -- pero obligaba
   al navegador a reposicionar 800 elementos pegajosos en cada frame de
   scroll. Medido: sacarlo baja los frames lentos de 15 a 11 sobre 39.
   Las de la PRIMERA columna si son sticky por su cuenta (cada habitacion,
   .cell.room, y la esquina del encabezado, .rack-esquina), porque se pegan
   en horizontal, no en vertical, y son una por fila -- esas reglas viven
   aparte. */
.cell.header {
  z-index: 2;
  background: var(--surface-muted);
  color: var(--muted);
  font-weight: 700;
}

.cell.header.date-header {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 1px;
  padding: 3px 2px;
  text-align: center;
}

/* --- Ritmo de la grilla ------------------------------------------------
   Un rack de 45 columnas iguales no se puede leer: no hay donde apoyar la
   vista. Estas tres marcas son informacion, no decoracion.

   HOY: era la ausencia mas grave. Se marcaba solo el ENCABEZADO, asi que al
   scrollear un poco la referencia desaparecia y quedaban 45 columnas
   idénticas. Ahora la columna entera se tiñe y lleva una linea de acento a
   la izquierda que baja por todo el rack. */
.cell.today {
  background: color-mix(in srgb, var(--accent) 7%, var(--surface));
  box-shadow: inset 1px 0 0 var(--accent);
}

.cell.header.today {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: none;
}

.cell.header.today .rack-month,
.cell.header.today .rack-day,
.cell.header.today .rack-dow {
  color: var(--on-accent);
}

/* FIN DE SEMANA: un hotel factura distinto un sabado que un martes, asi que
   la ocupacion del finde tiene que poder leerse sin contar columnas. */
.cell.weekend:not(.today) {
  background: color-mix(in srgb, var(--ink) 3.5%, var(--surface));
}

.cell.header.weekend:not(.today) {
  background: color-mix(in srgb, var(--ink) 8%, var(--surface-muted));
}

.cell.header.weekend:not(.today) .rack-day {
  color: var(--accent-strong);
}

/* INICIO DE SEMANA: una linea mas marcada cada lunes. Sin esto, saltar "a
   la semana que viene" obliga a contar columnas de a una. */
.cell.week-start {
  border-left: 1px solid color-mix(in srgb, var(--muted) 45%, transparent);
}

/* La inicial del dia (L M X J V S D) debajo del numero. */
.rack-dow {
  display: block;
  font-size: 8px;
  font-weight: 600;
  line-height: 1;
  color: var(--muted);
  letter-spacing: 0.04em;
}

.rack-month {
  display: block;
  color: var(--muted);
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
}

.rack-day {
  display: block;
  color: var(--ink);
  font-size: 13px;
  line-height: 1;
}

.cell.room {
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--surface-muted);
  font-weight: 600;
  text-align: center;
  /* Acompaña al alto de fila, igual que el texto del bloque. */
  font-size: var(--fuente-unidad, 11px);
  display: grid;
  align-content: center;
  gap: 2px;
  line-height: 1.25;
}

/* La esquina del encabezado ("Habitación", o "Plaza" en el estacionamiento)
   se pega a la izquierda igual que las celdas de habitacion. Sin esto, al
   correr el rack quedaba arriba de la columna de habitaciones la fecha de una
   columna escondida ("OCT 07" encima de "101").
   z-index 3 y no el 2 de .cell.header: el encabezado es sticky con z-index 5,
   asi que forma su propio apilamiento, y adentro las fechas (2, y van despues
   en el DOM) tienen que pasar POR DEBAJO de la esquina. El fondo de
   .cell.header ya es opaco, en los dos temas. */
.cell.header.rack-esquina {
  position: sticky;
  left: 0;
  z-index: 3;
}

/* La segunda linea (la capacidad, o el tipo y las camas en un hotel) siempre un
   escalon por debajo del nombre.
   
   El tope de 9px y el nowrap van juntos y no son cosmeticos: la columna mide
   64px fijos y "CPL · MAT" a 0.82em del escalon mas grande (12,3px) mide 75px,
   asi que se partia en dos lineas y se salia 21px por debajo de la celda. Un
   hotel de pocas habitaciones es justo el que usa ese escalon. A 9px entra
   siempre, y es la segunda linea: no es donde se lee el numero de habitacion. */
.cell.room span {
  font-size: min(0.82em, 9px);
  font-weight: 500;
  opacity: 0.75;
  white-space: nowrap;
}

.reservation-block {
  position: absolute;
  top: 4px;
  z-index: 2;
  /* Columna centrada en vertical: en una fila alta (un complejo de 3 cabañas
     reparte ~163px por fila) el texto quedaba pegado al borde de arriba con
     todo el color vacio debajo. Centrado no cambia nada en una fila al
     minimo, donde el contenido ocupa el bloque entero. */
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Ocupa la fila menos el margen de arriba y abajo: sin esto, en una fila
     alta quedaba una pastilla finita pegada al borde superior.
     min-height y NO height: con height fijo, en una fila al minimo (34px) el
     bloque quedaba en 26px y el contenido necesita ~30 (el nombre mas la
     linea de "Confirmada · 3 noches"), asi que el estado se cortaba a la
     mitad. Con min-height el contenido puede empujarlo cuando la fila es
     corta, y en una fila alta manda igual la fila. */
  min-height: calc(var(--alto-fila-rack, 34px) - 8px);
  border: 0;
  border-radius: var(--radius-sm);
  color: #16142e;
  text-align: left;
  /* Padding izquierdo mayor: deja lugar a la barra de estado de ::before,
     que es lo que permite identificar el estado de una reserva aunque el
     bloque sea tan angosto que no entre el texto. */
  /* Padding y cuerpo salen de app.js (medirRack): con filas de 160px el 10px
     fijo quedaba diminuto en el medio de un bloque enorme. Los fallback son
     los valores historicos, para un rack apretado. */
  padding: var(--padding-bloque, 3px) 8px var(--padding-bloque, 3px) 11px;
  font-size: var(--fuente-bloque, 10px);
  font-weight: 600;
  overflow: hidden;
  /* Canto superior iluminado + sombra propia: hace que el bloque se lea
     como una pieza APOYADA sobre la grilla y no como una celda pintada.
     Es lo que separa un planning de una planilla de calculo con colores. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 1px 2px rgba(22, 20, 46, 0.16);
}

/* Barra de estado a la izquierda, en el mismo color pero saturado. Cumple
   dos funciones: le da un borde definido al bloque (antes se fundia con el
   fondo pastel de al lado cuando dos reservas quedaban pegadas) y, en
   estadias de 1 noche donde no entra ni el nombre, sigue comunicando el
   estado. El color no es la unica señal -- el texto lo dice igual. */
.reservation-block::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: currentColor;
  opacity: 0.45;
}

.reservation-block small {
  display: block;
  margin-top: 2px;
  font-size: var(--fuente-bloque-chica, 9px);
  color: rgba(22, 20, 46, 0.68);
  white-space: nowrap;
  font-weight: 500;
  /* En una estadia corta el bloque es mas angosto que "Confirmada · 3
     noches" y el texto quedaba cortado a cuchillo contra el borde, sin
     ninguna señal de que seguia. Los puntos suspensivos avisan que hay mas
     -- y el dato completo esta en el popover al tocar el bloque. */
  overflow: hidden;
  text-overflow: ellipsis;
}


/* Los pasteles de los bloques se derivan ahora de los mismos --green/--blue/
   --red/--yellow que usa el resto del PMS, en vez de ser 4 hex sueltos
   (#8ce99a, #90e0ef, #ff8787) elegidos aparte: asi el verde de "confirmada"
   en Planning es reconociblemente el mismo verde que el badge "Confirmada"
   en Reservas, solo que mas claro.
   Se mezclan contra `white` literal y no contra --surface a proposito: estos
   bloques llevan texto oscuro fijo (la Tinta, #16142e) en los dos temas, asi
   que su fondo tambien tiene que quedarse claro en modo oscuro -- es la misma
   decision que ya estaba tomada antes, solo que ahora explicita. */
.reservation-block.pendiente {
  background: color-mix(in srgb, var(--orange) 58%, white);
  color: #16142e;
}

.reservation-block.confirmada {
  background: color-mix(in srgb, var(--green) 34%, white);
}

/* Pendiente de seña, pero con una transferencia ya cargada esperando que
   alguien mire el banco. Ver claseDeBloque en app.js.
   Amarillo y no rojo: el huesped ya pago, lo que falta es que el hotel mire el
   banco. Contra el naranja de "no mando nada" (#fcb98f mezclado) queda
   #fcdf99, otro tono y no otra intensidad del mismo. */
.reservation-block.en-revision {
  background: color-mix(in srgb, var(--yellow) 58%, white);
}

.reservation-block.en-curso {
  background: color-mix(in srgb, var(--blue) 32%, white);
}

.reservation-block.vencida {
  background: color-mix(in srgb, var(--red) 26%, white);
}

.reservation-block.cancelada {
  /* --gray es la unica variable de este set de estados que cambia bastante
     entre temas (gris medio-claro en claro, medio-oscuro en oscuro) -- el
     resto de los estados usa colores pasteles fijos (no ligados al tema) por
     lo que el texto oscuro heredado de .reservation-block les queda bien
     siempre. Este es el unico que necesita un color de texto que se adapte
     al tema, igual que finalizada de abajo. */
  background: var(--gray);
  color: var(--ink);
}

.reservation-block.finalizada {
  background: var(--surface-muted);
  color: var(--muted);
}

/* El <small> de "Check out · N noches" tiene su propio color hardcodeado
   (ver regla .reservation-block small mas abajo, pensada para los estados de
   fondo pastel fijo) que en estos dos estados pisaba el color ya correcto
   del bloque padre -- se veia como texto casi negro sobre un fondo que en
   modo oscuro tambien es oscuro. */
.reservation-block.cancelada small,
.reservation-block.finalizada small {
  color: inherit;
}

/* El nombre usa las lineas que entren en la fila, no siempre una.
   Antes estaba fijo en una sola linea porque el bloque no tenia alto propio y
   envolver lo hacia crecer por encima de su fila, pisando la habitacion de
   abajo. Ahora el bloque mide exactamente la fila (height: calc(...) mas
   arriba), asi que no puede desbordar, y --lineas-nombre lo escribe app.js
   segun cuanto alto haya (ver medirRack): en un rack apretado sigue siendo
   una linea con puntos suspensivos, y en uno holgado un nombre largo entra
   entero en vez de quedar en "Maria Fern...".
   El corte es SOLO entre palabras (overflow-wrap normal): con "anywhere", un
   bloque de una noche (33px de ancho) partia el nombre letra por letra y se
   leia "An / a / L... / P...", peor que truncarlo. Asi, "Ana Lopez" baja
   "Lopez" a la linea de abajo y lo que no entra se corta con puntos. */
.reservation-block-name {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lineas-nombre, 1);
  line-clamp: var(--lineas-nombre, 1);
  overflow: hidden;
  overflow-wrap: normal;
}

/* "!" rojo: reserva confirmada sin ningun pago de seña registrado todavia. */
.deposit-warning {
  display: inline-block;
  color: var(--red);
  font-weight: 700;
  margin-right: 3px;
}

/* El candadito de "no mover de esta habitacion" en el bloque del planning.
   Chico y sin color propio: no es una alerta, es una propiedad de la reserva
   -- el rojo de al lado (deposit-warning) si avisa de algo que hay que
   resolver, y dos marcas gritando en el mismo bloque compiten entre si. */
.room-lock-mark {
  display: inline-block;
  margin-right: 3px;
  font-size: 0.85em;
  opacity: 0.75;
}

/* La habitacion es mas grande que lo que se cobra. El triangulo es monocromo y
   el candado un emoji a color, asi que conviven sin competir aunque midan casi
   lo mismo; a 0.7em (6px dentro del bloque, que tipografia a 10px) no se veia. */
.upgrade-mark {
  display: inline-block;
  margin-right: 3px;
  font-size: 0.8em;
  opacity: 0.75;
  vertical-align: 1px;
}

/* En cuotas: el pago lo cobra recepcion. "6c" en el bloque del planning y
   "6 cuotas" en el renglon de la lista. */
.cuotas-en-lista {
  font-weight: 700;
}

.cuotas-mark {
  display: inline-block;
  margin-right: 3px;
  font-size: 0.8em;
  font-weight: 700;
  opacity: 0.8;
  vertical-align: 1px;
}

/* Un selector de habitacion deshabilitado por el candado: que se lea como "no
   se puede tocar ahora", no como un campo roto. */
select.bloqueado {
  opacity: 0.7;
  cursor: not-allowed;
}

.reservation-row-status {
  display: flex;
  align-items: center;
  gap: 4px;
}

.reservation-list {
  display: grid;
  gap: 10px;
}

.reservation-row {
  display: grid;
  grid-template-columns: minmax(160px, 1.2fr) minmax(140px, 0.8fr) minmax(120px, 0.8fr) auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 12px 14px;
  text-align: left;
  min-height: 72px;
  transition: background-color 140ms ease, border-color 140ms ease;
}

/* Es un <button> entero: sin feedback al pasar el mouse no se leia como algo
   clickeable (la guia de interaccion lo marca como Medium: "no hover
   feedback on clickable elements"). */
.reservation-row:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: var(--surface-muted);
}

.reservation-row.active,
.reservation-row.active:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.reservation-row strong,
.detail-summary strong {
  display: block;
}

/* Los :not() excluyen a los spans que traen COLOR PROPIO y que por lo tanto
   no son "texto secundario". Estaban excluidos los .pill pero no los chips de
   plata: por especificidad (0,2,1 contra 0,1,0) esta regla les ganaba y el
   saldo pendiente se veia gris en vez de rojo en la lista de Reservas. Bug
   viejo, encontrado midiendo el contraste al agregar .balance-over. */
.reservation-row span:not(.pill):not(.balance-due):not(.balance-over):not(.balance-clear),
.detail-summary span:not(.pill):not(.balance-due):not(.balance-over):not(.balance-clear),
.listing-table span:not(.pill):not(.balance-due):not(.balance-over):not(.balance-clear) {
  color: var(--muted);
  font-size: 13px;
}

.reservation-detail {
  align-self: start;
  position: sticky;
  top: 18px;
  min-width: 0;
  max-height: calc(100vh - 110px);
  overflow: auto;
}

/* El padding superior lo pone el propio header (ver .panel-header mas abajo)
   para que su fondo blanco lo cubra al quedar pegado arriba — position:sticky
   ignora el margen negativo de un hijo al calcular donde "pegarlo", asi que
   compensar el padding del contenedor con margen negativo no funciona.
   Selector con dos clases a proposito: hay una regla ".panel { padding:14px }"
   mas abajo en el archivo (seccion "UI polish pass") que gana por orden de
   cascada a cualquier ".reservation-detail" suelto sin importar donde se
   ubique — subir la especificidad evita depender de la posicion. */
.panel.reservation-detail {
  padding-top: 0;
}

.detail-summary {
  display: grid;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
  margin-bottom: 14px;
}

.detail-form {
  display: grid;
  gap: 12px;
}

.detail-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

/* El "Guardar cambios" de la ficha cierra el formulario entero (estadia +
   huesped + extras), no la ultima seccion. Antes quedaba a media caja debajo
   de Extras y se leia como si fuera de ahi. Ancho completo y con un separador
   arriba: se ve que cierra todo el bloque editable. */
.reservation-detail .detail-actions {
  /* Guardar a lo ancho y las acciones secundarias (imprimir, mensaje,
     WhatsApp) de a varias por renglon cuando hay lugar. Con el detalle
     ancho (05/10), cuatro botones de 1500px apilados ocupaban media
     pantalla para cuatro palabras. En un telefono no entran dos de 200px y
     quedan apilados como antes. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.reservation-detail .detail-actions > .primary-button {
  grid-column: 1 / -1;
}

/* Ritmo vertical unico entre form/extras/pagos/actividad/zona de peligro --
   antes cada bloque tenia su propio margin-top suelto (4px, 12px, ninguno)
   sin relacion entre si, lo que se sentia desprolijo. Un solo gap ademas
   hace que reordenar secciones (ver renderReservationDetail) no dependa de
   arrastrar el margen correcto con cada bloque. */
.detail-sections {
  display: grid;
  /* 20 y no 14: con cinco bloques del mismo tamaño apilados, 14px los dejaba
     casi tocandose y se leian como una sola masa. El aire entre secciones es
     lo que hace que se vean COMO secciones. */
  gap: 20px;
}

/* Franja de datos que NO se editan (noches, huespedes, habitaciones, canal),
   entre el banner de saldo y el formulario. Antes esto vivia adentro de
   "Estadia y estado", debajo de los campos editables: no se distinguia lo que
   era informativo de lo que se podia tocar. Sin borde ni tarjeta a proposito
   -- es un dato al paso, no una seccion mas que compita con las cinco de
   abajo. */
.detail-hechos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: 4px 16px;
  margin: 0 0 18px;
  padding: 10px 14px;
  background: var(--surface-muted);
  border-radius: var(--radius);
}

.detail-hechos > div {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.detail-hechos dt {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.detail-hechos dd {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* El upgrade ocupa la fila entera: es una frase ("206: Triple al precio de
   Doble"), no un numero, y en una columna de 90px se partia en cuatro lineas. */
.detail-hechos > .detail-hecho-upgrade {
  grid-column: 1 / -1;
}

/* Chat/CRM de WhatsApp: layout de altura FIJA (no min-height) a proposito —
   solo con una altura definida los hijos flex (.conversation-list y
   .messages) pueden tener scroll propio via flex:1+overflow:auto; con
   min-height el panel crecia con el contenido y terminaba scrolleando la
   pagina entera en vez de cada columna por separado. */
.chat-layout {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 14px;
  height: calc(100vh - 88px);
  min-height: 460px;
}

.conversation-list-col,
.conversation-panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.conversation-search-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  padding: 8px;
  border-bottom: 1px solid var(--line);
}

.conversation-search-bar input {
  flex: 1;
  min-height: 32px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  font-size: 12px;
  color: var(--ink);
  background: var(--surface-muted);
}

.conversation-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 6px;
  display: grid;
  /* minmax(0, 1fr), no solo 1fr: sin el 0 explicito, la columna implicita de
     grid crece para acomodar el contenido mas ancho de sus items (un pill de
     estado largo, un telefono) en vez de quedarse en el ancho del
     contenedor — eso es lo que generaba scroll horizontal feo en la lista. */
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: 4px;
}

.conversation-item {
  width: 100%;
  text-align: left;
  padding: 8px 9px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
}

.conversation-item.active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* Chat sin responder (ultimo mensaje del huesped, ver whatsappLeadStatusInfo
   y updateChatUnreadBadge): mismo criterio que el circulo del boton "Chat"
   del navbar, pero visible directamente en la lista para no tener que abrir
   cada chat para saber cuales necesitan respuesta. */
.conversation-item.unread {
  border-left: 3px solid var(--red);
  background: color-mix(in srgb, var(--red) 8%, var(--surface));
}

.conversation-item.unread.active {
  background: var(--accent-soft);
}

.conversation-item.unread .conversation-preview {
  color: var(--ink);
  font-weight: 700;
}

.conversation-unread-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--red);
}

.conversation-item-top {
  display: flex;
  align-items: center;
  gap: 6px;
}

.conversation-item-top strong {
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
}

.conversation-preview {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.conversation-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.conversation-panel {
  min-width: 0;
}

/* Header compacto: nombre + estado + accion de "tomar control" entran todos
   en la misma fila (pedido explicito), y al quedar fuera de .messages (el
   unico hijo con overflow:auto) se mantiene fijo arriba sin necesitar
   position:sticky. */
.conversation-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 6px;
  gap: 10px;
  padding: 10px 14px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--line);
}

.conversation-identity {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}

/* Solo tiene sentido en mobile (donde lista y conversacion son pantallas
   separadas) -- en desktop ambos paneles conviven siempre, se oculta por
   defecto y el @media(max-width:980px) lo muestra. */
.conversation-back {
  display: none;
  flex-shrink: 0;
}

.conversation-name {
  font-size: 15px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
}

.conversation-name-input {
  min-height: 30px;
  max-width: 220px;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 0 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
}

.conversation-name-edit {
  min-height: 26px;
  width: 26px;
  flex: 0 0 auto;
  padding: 0;
}

.conversation-name-edit svg {
  width: 14px;
  height: 14px;
}

.conversation-lead-status {
  flex: 0 0 auto;
  white-space: nowrap;
}

.conversation-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.conversation-actions .ghost-button {
  min-height: 30px;
  padding: 0 10px;
  font-size: 12px;
}

/* Estado del bot en el encabezado del chat: el violeta de la IA, con un
   punto que se lee de un vistazo, mientras el bot atiende. Con el humano al
   mando pasa a neutro (ver .off), asi el violeta solo esta prendido cuando
   habla el bot. */
.bot-badge {
  min-height: 26px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 9px;
  border: 1px solid color-mix(in srgb, var(--ai) 30%, transparent);
  border-radius: var(--radius-pill);
  background: var(--ai-soft);
  color: var(--ai-strong);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.bot-badge::before {
  content: "";
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ai);
}

/* Sin conversacion abierta app.js le vacia el texto: sin esto quedaba un
   ovalo de color vacio en el encabezado. */
.bot-badge:empty {
  display: none;
}

/* "Humano al mando": neutro, como .pill.lead-new. Antes iba en naranja con
   el texto en --orange pelado, que sobre su propio tinte daba ~2.3:1. */
.bot-badge.off {
  background: var(--surface-muted);
  border-color: var(--line);
  color: var(--tint-gray-ink);
}

.bot-badge.off::before {
  background: var(--muted);
}

.conversation-subheader {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-bottom: 1px solid var(--line);
}

/* Aviso de "informar esta respuesta al equipo". Ocupa toda la fila del
   subheader (el chip del telefono queda arriba). Habla del bot -- que no
   supo responder y como aprende --, asi que va en el violeta de la IA y no
   en el acento: es algo del asistente, no una accion del hotel. El "Si,
   informar" sigue en el turquesa del boton principal. Medido: --muted
   sobre la Lavanda da ~5.6 en claro y ~6.9 en oscuro. */
.gap-prompt {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 14px;
  margin: 4px 0 2px;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--ai) 35%, var(--line));
  border-radius: var(--radius);
  background: var(--ai-soft);
}

.gap-prompt-text {
  margin: 0;
  flex: 1 1 240px;
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.45;
  /* La pregunta la escribio un huesped: puede ser larga o venir sin espacios. */
  overflow-wrap: anywhere;
}

/* Muestra textual lo que se va a mandar -- ocupa el ancho completo (no
   comparte fila con los botones) porque puede ser varios mensajes seguidos. */
.gap-prompt-preview {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.gap-prompt-preview span {
  font-weight: 600;
  color: var(--ink);
}

.gap-prompt-extra-label {
  flex: 1 1 100%;
  margin: 2px 0 -4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
}

.gap-prompt-extra {
  flex: 1 1 100%;
  min-height: 46px;
  resize: vertical;
  font-size: 12.5px;
}

.gap-prompt-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.gap-prompt-actions .primary-button,
.gap-prompt-actions .ghost-button {
  min-height: 32px;
  font-size: 12.5px;
  padding: 0 12px;
}

/* Selector de "vincular a reserva": vive en la misma linea que el nombre y
   "Tomar control" (pedido explicito, para no sumar una fila mas al header) —
   angosto y sin label visible a proposito; el resumen de la reserva
   vinculada (codigo/estado/fechas/saldo, ver renderConversationLinkSummary)
   ahora es el "title" del propio select en vez de una linea aparte, para no
   volver a sumarle alto al header. */
.conversation-link-select {
  flex: 0 0 auto;
  min-height: 30px;
  max-width: 138px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 6px;
  font-size: 11.5px;
  color: var(--ink);
  background: var(--surface);
}

/* Solo geometria: NO fijar `color` aca. Esta regla es un selector descendiente
   (.conversation-item .pill.x) y por lo tanto le gana en especificidad a la
   clase de color del propio badge (.pill.confirmada, .pill.blue, etc.), asi
   que un color puesto aca pisa el de TODOS los estados. Tenia `color: white`,
   correcto mientras los badges eran de color pleno, pero desde que pasaron a
   fondo teñido dejaba texto blanco sobre un fondo claro: contraste 1.13, o
   sea ilegible. El color lo pone cada .pill.<estado> y se hereda solo. */
.conversation-item .pill.conversation-tag,
.conversation-item .pill.conversation-lead-status {
  margin-top: 0;
  font-size: 10px;
  min-height: 18px;
  padding: 0 6px;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Quien atiende cada conversacion de WhatsApp (app.js: .ia / .humano). Antes
   eran .blue y .orange, colores de estado puestos de adorno. "Bot activo" va
   en el violeta de la IA y "Humano" neutro -- lo que pide atencion ya lo
   marca .unread en rojo. El "Sin responder" del Mail sigue siendo
   .conversation-tag.orange: ese si es un estado. */
.pill.conversation-tag.ia {
  background: var(--ai-soft);
  border-color: color-mix(in srgb, var(--ai) 30%, transparent);
  color: var(--ai-strong);
}

.pill.conversation-tag.humano {
  background: var(--surface-muted);
  border-color: var(--line);
  color: var(--tint-gray-ink);
}

.detected-data {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.data-chip {
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 4px 9px;
  font-size: 11px;
  color: var(--muted);
}

.messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 14px;
  background: var(--surface-muted);
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.message {
  max-width: 72%;
  border-radius: var(--radius);
  padding: 7px 10px;
  font-size: 13px;
  line-height: 1.35;
  white-space: pre-wrap;
}

.message.user {
  align-self: flex-start;
  background: var(--surface);
  border: 1px solid var(--line);
}

/* Lo que escribio el bot va en la Lavanda de la IA: tres voces que se
   distinguen de un vistazo (huesped blanco, recepcion Agua, bot Lavanda).
   El texto sigue en --ink: parrafos largos en violeta cansan, y la
   identidad ya la dan el fondo y el borde. */
.message.bot {
  align-self: flex-end;
  background: var(--ai-soft);
  border: 1px solid color-mix(in srgb, var(--ai) 30%, var(--line));
}

/* En oscuro la Lavanda (#382f75) casi no se separa del fondo del chat
   (--surface-muted, #312d5c): el borde tiene que hacer mas trabajo. Solo el
   color, para no pisar el border: none de un sticker. */
html[data-theme="dark"] .message.bot {
  border-color: color-mix(in srgb, var(--ai) 45%, var(--line));
}

/* Lo que escribio recepcion: una persona, asi que no va en violeta. Antes
   usaba --blue, un color de estado puesto de adorno. */
.message.human {
  align-self: flex-end;
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
}

/* Reproductor de notas de voz. Reemplaza al <audio controls> nativo, que
   pedia 300x54px y estaba forzado a 32px de alto: a ese tamaño el navegador
   recorta sus propios controles, y ademas se veia como un widget del sistema
   pegado dentro de la burbuja. Este mide lo mismo que una burbuja de texto. */
.message-audio {
  padding: 6px 8px;
  min-width: 210px;
  /* .message usa white-space: pre-wrap para respetar los saltos de linea que
     escribio el huesped. En una burbuja de audio no hay texto del huesped,
     pero SI estan los saltos de linea y la indentacion del template HTML, que
     con pre-wrap se pintan como lineas en blanco de verdad: la burbuja media
     116px de alto para un reproductor de 32px. */
  white-space: normal;
}

.chat-audio {
  display: flex;
  align-items: center;
  gap: 9px;
}

.chat-audio-btn {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  /* 32px de caja visible, pero el area tocable llega a 40px con el padding
     negativo del margin -- por debajo de eso un dedo no acierta comodo. */
  width: 32px;
  height: 32px;
  margin: -4px;
  padding: 4px;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  box-sizing: content-box;
  transition: background-color 140ms ease;
}

.chat-audio-btn:hover {
  background: var(--accent-hover);
}

.chat-audio-icon {
  width: 15px;
  height: 15px;
  grid-area: 1 / 1;
}

.chat-audio-spinner {
  grid-area: 1 / 1;
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #ffffff;
  border-radius: var(--radius-pill);
  animation: chat-audio-spin 700ms linear infinite;
}

@keyframes chat-audio-spin {
  to {
    transform: rotate(360deg);
  }
}

.chat-audio-track {
  flex: 1 1 auto;
  height: 4px;
  min-width: 60px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ink) 16%, transparent);
  cursor: pointer;
  position: relative;
}

/* El area clickeable para adelantar el audio se extiende arriba y abajo de
   la barra visible de 4px, que sola seria imposible de acertar. */
.chat-audio-track::after {
  content: "";
  position: absolute;
  inset: -10px 0;
}

.chat-audio-fill {
  height: 100%;
  width: 0%;
  border-radius: inherit;
  background: var(--accent);
  transition: width 120ms linear;
}

.chat-audio-time {
  flex: 0 0 auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  min-width: 30px;
  text-align: right;
}

.chat-audio.error .chat-audio-btn {
  background: var(--red);
}

.chat-audio.error .chat-audio-time {
  color: var(--tint-red-ink);
}

@media (prefers-reduced-motion: reduce) {
  .chat-audio-spinner {
    animation-duration: 2s;
  }

  .chat-audio-fill {
    transition: none;
  }
}

/* --- Fotos que manda el huesped -----------------------------------------
   La burbuja de una foto no es una burbuja de texto con una imagen adentro:
   se le saca el pre-wrap (que agregaria saltos de linea invisibles entre los
   bloques) y se aprieta el padding, para que la foto llene el globo y no
   quede flotando con un marco de aire alrededor. */
.message-imagen {
  padding: 5px;
  white-space: normal;
  max-width: min(78%, 268px);
}

.chat-imagen {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Es un <button> y no un <div>: ademas de abrir la foto grande, es lo que se
   toca para reintentar una que no bajo. Un div con role="button" habria que
   atarlo a mano al teclado. */
.chat-imagen-marco {
  width: 100%;
  padding: 0;
  border: none;
  border-radius: calc(var(--radius) - 3px);
  background: var(--surface-muted);
  cursor: pointer;
  overflow: hidden;
  /* Mientras baja ocupa el lugar que va a ocupar la foto: sin esto la lista
     de mensajes pega un salto cada vez que entra una, justo cuando alguien
     esta leyendo. */
  min-height: 132px;
  display: grid;
  place-items: center;
}

.chat-imagen-marco img {
  display: block;
  width: 100%;
  height: auto;
  /* Una captura de pantalla de un celular es mucho mas alta que ancha: sin
     tope, una sola foto ocupa el chat entero y tapa los mensajes de arriba.
     Se recorta, y el visor grande muestra la foto completa.
     object-position: top y no el centro por defecto: de un comprobante lo que
     importa es el encabezado (banco, monto), que es justo lo que un recorte
     centrado tira. */
  max-height: 260px;
  object-fit: cover;
  object-position: top;
}

.chat-imagen-marco.cargando {
  /* Barrido suave en vez de un spinner: es un bloque grande, y un spinner
     centrado en un rectangulo vacio se lee como un error. */
  background: linear-gradient(100deg,
    var(--surface-muted) 30%,
    color-mix(in srgb, var(--ink) 7%, var(--surface-muted)) 50%,
    var(--surface-muted) 70%);
  background-size: 220% 100%;
  animation: chat-imagen-barrido 1.4s ease-in-out infinite;
}

.chat-imagen-marco.fallada {
  background: color-mix(in srgb, var(--red) 8%, var(--surface));
}

.chat-imagen-marco.fallada .chat-imagen-estado {
  color: var(--tint-red-ink);
}

@keyframes chat-imagen-barrido {
  from { background-position: 180% 0; }
  to { background-position: -80% 0; }
}

.chat-imagen-estado {
  padding: 0 12px;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
}

.chat-imagen-pie {
  margin: 0;
  padding: 0 3px;
  font-size: 13px;
  line-height: 1.35;
  white-space: pre-wrap;
}

/* El atajo que evita bajar el comprobante y volver a subirlo. Va en verde y
   no en el acento del PMS: es la accion que cierra la plata, y tiene que
   distinguirse de un boton mas del chat. */
.chat-imagen-pago {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  /* 36px de alto: el minimo para acertarle con el pulgar en el telefono, que
     es donde recepcion mira el chat. */
  min-height: 36px;
  padding: 0 10px;
  border: 1px solid color-mix(in srgb, var(--green) 38%, var(--line));
  border-radius: calc(var(--radius) - 3px);
  background: color-mix(in srgb, var(--green) 12%, var(--surface));
  color: var(--tint-green-ink);
  font-size: 12.5px;
  font-weight: 650;
  cursor: pointer;
}

.chat-imagen-pago svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.chat-imagen-pago:hover:not(:disabled) {
  background: color-mix(in srgb, var(--green) 20%, var(--surface));
}

/* Apagado y no escondido mientras la foto baja: esconderlo haria saltar la
   burbuja de alto justo cuando entra la imagen. */
.chat-imagen-pago:disabled {
  opacity: 0.45;
  cursor: default;
}

/* --- Documentos (el PDF de una transferencia) -------------------------------
   Una ficha y no una miniatura: el documento se baja recien al tocarlo, y
   hasta entonces no se sabe ni el nombre. Mismo globo que una foto
   (.message-imagen) para que "Registrar pago" quede igual en los dos. */
.chat-documento-marco {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 56px;
  padding: 8px 10px;
  border: none;
  border-radius: calc(var(--radius) - 3px);
  background: var(--surface-muted);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.chat-documento-marco:hover {
  background: color-mix(in srgb, var(--ink) 6%, var(--surface-muted));
}

.chat-documento-marco.cargando {
  background: linear-gradient(100deg,
    var(--surface-muted) 30%,
    color-mix(in srgb, var(--ink) 7%, var(--surface-muted)) 50%,
    var(--surface-muted) 70%);
  background-size: 220% 100%;
  animation: chat-imagen-barrido 1.4s ease-in-out infinite;
}

.chat-documento-icono {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  color: var(--tint-red-ink);
}

.chat-documento-icono svg {
  width: 20px;
  height: 20px;
}

.chat-documento-datos {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.chat-documento-datos strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.chat-documento-datos small {
  color: var(--muted);
  font-size: 11.5px;
}

/* --- Stickers ------------------------------------------------------------
   Sin globo y sin fondo: un sticker de WhatsApp es un .webp con transparencia
   y adentro de una burbuja blanca se ve como una foto recortada. Chico, porque
   es una reaccion y no un contenido -- ocupar media pantalla con un pulgar
   arriba empuja la conversacion de verdad fuera de cuadro. */
/* .message.message-sticker y no .message-sticker a secas: el fondo y el borde
   los pone .message.user / .message.human, que con dos clases pesan mas. Ya
   pasado dos veces en este archivo: una regla de una clase no le gana a una de
   dos por estar mas abajo. */
.message.message-sticker {
  padding: 0;
  max-width: 140px;
  background: transparent;
  border: none;
  /* .message hereda white-space: pre-wrap, asi que los saltos de linea y la
     sangria del template literal se dibujan como espacio de verdad: eran 72px
     de aire debajo del sticker. Mismo motivo por el que .message-imagen lo
     apaga. */
  white-space: normal;
}

.chat-sticker .chat-imagen-marco {
  min-height: 0;
  background: transparent;
  border-radius: 0;
}

.chat-sticker .chat-imagen-marco img {
  /* contain y no cover: un sticker recortado deja de ser el dibujo que era. */
  max-height: 140px;
  object-fit: contain;
  object-position: center;
}

/* Mientras baja si necesita ocupar lugar, para que la lista no pegue un salto
   cuando entra. El barrido se hereda de .chat-imagen-marco.cargando. */
.chat-sticker .chat-imagen-marco.cargando,
.chat-sticker .chat-imagen-marco.fallada {
  min-height: 96px;
  border-radius: calc(var(--radius) - 3px);
}

@media (prefers-reduced-motion: reduce) {
  .chat-imagen-marco.cargando,
  .chat-documento-marco.cargando { animation: none; }
}

.reply-box {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
}

.reply-box input,
.form-grid input,
.form-grid select {
  min-height: 40px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
}

.cleaning-board {
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  align-items: start;
}

.cleaning-column {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  box-shadow: var(--shadow);
  display: grid;
  gap: 8px;
  align-content: start;
  /* Habilita las @container de .cleaning-card: cada tarjeta decide si pone
     los botones al lado del texto o debajo segun el ancho de SU columna. */
  container-type: inline-size;
}

.cleaning-column h2 {
  margin: 0 0 4px;
  font-size: 17px;
}

/* El estado vacio de TODO el PMS: se usa en 39 lugares (renderizado tanto
   como <p> de bloque como <span> en linea, por eso son dos tratamientos).
   Se le saca la italica: texto muted en italica se lee como "placeholder
   sin terminar", no como un estado que alguien diseño. Un estado vacio bien
   resuelto es la diferencia entre "no hay datos" y "la app esta rota". */
.cleaning-empty {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  font-style: normal;
}

/* En contexto de bloque gana una superficie propia: un fondo apenas teñido
   y texto centrado, para que el hueco se lea como una zona en reposo y no
   como contenido que falto cargar. Sin borde punteado a proposito -- el
   punteado se asocia a "zona para soltar archivos" y ademas se ve barato.
   Los pocos casos que traen un style="padding" inline siguen ganando. */
/* "Cargando..." NO es un estado vacio: uno dice "no hay nada", el otro dice
   "esperá". Antes se veian identicos, asi que una lista que tardaba se leia
   como una lista vacia y el usuario se iba de la pantalla.
   El pulso es lento (1.6s) y solo de opacidad -- lo justo para comunicar
   "esto sigue trabajando" sin convertirse en algo que parpadea al lado de
   quien esta laburando. */
.cleaning-empty.is-loading,
.is-loading > .cleaning-empty {
  animation: cargandoPulso 1.6s var(--ease-in-out) infinite;
}

@keyframes cargandoPulso {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .cleaning-empty.is-loading,
  .is-loading > .cleaning-empty {
    animation: none;
    opacity: 0.7;
  }
}

p.cleaning-empty {
  padding: 20px 16px;
  text-align: center;
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  text-wrap: pretty;
  /* Varios contenedores que lo alojan son grillas (habitaciones, clientes,
     tarifas): sin esto el mensaje ocupa UNA celda y, ahora que tiene fondo
     propio, se ve como una cajita rota en un rincon en vez de como el
     estado de la lista entera. En un contenedor que no sea grilla estas
     dos lineas no hacen nada. */
  grid-column: 1 / -1;
  width: 100%;
}

.cleaning-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.cleaning-actions .ghost-button {
  min-height: 30px;
  padding: 0 9px;
  font-size: 12px;
}

/* --- Tarjeta de habitacion: de bloque apilado a fila compacta ----------
   Antes cada habitacion eran 3 bloques uno debajo del otro (nombre, estado,
   y dos botones a ancho completo): ~100px de alto para una habitacion. Con
   20 habitaciones eso son 2000px de scroll para un tablero que se mira de
   un vistazo, y los botones quedaban ridiculamente anchos -- "Marcar
   limpia" no necesita 140px.
   Ahora el texto va a la izquierda en dos renglones y los botones a la
   derecha, dimensionados por su texto: la misma tarjeta pasa de ~100px a
   ~52px sin perder nada. */
.cleaning-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "nombre"
    "estado"
    "acciones";
  row-gap: 4px;
  column-gap: 12px;
  align-items: center;
  padding: 8px 10px;
  margin-bottom: 6px;
}

/* La fila de una sola linea se activa segun el ancho de la COLUMNA, no del
   viewport: el tablero tiene 4 columnas, asi que en una pantalla de 1440px
   cada una mide ~330px y una media query de viewport decidiria mal. Con
   @container la tarjeta se adapta a lo que realmente tiene disponible.
   Ver .cleaning-column, que declara el contenedor. */
@container (min-width: 300px) {
  .cleaning-card {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "nombre acciones"
      "estado acciones";
    row-gap: 0;
  }

  /* Sin nota (el caso normal en "Para limpiar" y "Listas") la tarjeta es
     una sola fila: habitacion a la izquierda, acciones a la derecha. */
  .cleaning-card.sin-nota {
    grid-template-areas: "nombre acciones";
  }
}

.cleaning-card strong {
  grid-area: nombre;
  font-size: 13.5px;
}

.cleaning-card span {
  grid-area: estado;
  font-size: 12px;
}

.cleaning-actions {
  grid-area: acciones;
  display: flex;
  gap: 6px;
  margin-top: 0;
}

/* Botones al ancho de su texto, no al de la tarjeta. Se conserva el minimo
   tactil de 30px de alto que ya tenian. */
.cleaning-actions button {
  width: auto;
  white-space: nowrap;
}


.tariff-hint {
  margin: -6px 0 16px;
  color: var(--muted);
  font-size: 13px;
  max-width: 760px;
}

/* Tarifas: una tarjeta por temporada en vez de una tabla de 9 columnas con
   scroll horizontal — pedido explicito del usuario ("poco intuitivo y poco
   practico"). Cada tarjeta agrupa fechas + precio normal/promo por tipo de
   habitacion, en vez de obligar a leer una fila entera de izquierda a
   derecha para entender una sola temporada. */
.season-cards {
  display: grid;
  /* min(420px, 100%) y no 420px pelado: con el valor fijo, en una pantalla
     de 320px la columna igual reclamaba el minimo y empujaba la pagina entera
     a scroll horizontal. El min() deja que la columna se achique cuando no
     entra, que es exactamente lo que uno espera de un minimo.
     420 y no 380 (12/10): es lo que pide la tabla de precios en su minimo
     (384, con un precio de 7 cifras entero) mas el relleno de la tarjeta. Con
     380, entre 1210 y 1330px de ventana la tabla scrolleaba y escondia el "%"
     y el descuento. */
  grid-template-columns: repeat(auto-fill, minmax(min(420px, 100%), 1fr));
  gap: 16px;
  margin-bottom: 24px;
  align-items: start;
}

/* El orden de la pantalla (12/10): tarjetas, extras, promociones y, al final,
   la temporada operativa. Mismo aire entre los cuatro bloques. */
.tarifas-extras {
  margin-bottom: 24px;
}

/* "Todavia no hay temporadas" / "todas terminaron": a lo ancho, no metido en
   la primera columna de la grilla. */
.season-cards-aviso {
  grid-column: 1 / -1;
}

/* Las temporadas que ya terminaron van plegadas al final de la grilla, a lo
   ancho. Adentro llevan la misma grilla, asi las columnas coinciden con las
   de arriba. */
.season-terminadas {
  grid-column: 1 / -1;
}

.season-terminadas > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 0 14px 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.season-terminadas > summary::-webkit-details-marker {
  display: none;
}

/* Flechita dibujada con bordes (no un caracter: depende de la fuente). */
.season-terminadas > summary::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-fast) var(--ease-out);
}

.season-terminadas[open] > summary::before {
  transform: rotate(45deg);
}

.season-terminadas > summary:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
}

@media (hover: hover) and (pointer: fine) {
  .season-terminadas > summary:hover {
    background: var(--surface-muted);
    color: var(--ink);
  }
}

.season-terminadas > .season-cards {
  margin: 14px 0 0;
}

.season-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
  display: grid;
  /* minmax(0, 1fr): sin esto la unica columna del grid toma el min-content
     de su hijo mas ancho (la tabla de precios) y la tarjeta crece mas alla
     de la pantalla. Mismo patron que .reservations-layout. */
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

.season-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Un hijo de flex tiene min-width: auto por defecto, o sea "nunca mas
   angosto que mi contenido". El input del nombre de la temporada se negaba
   a achicarse y empujaba la tarjeta entera mas alla del ancho de la
   pantalla: en 320px la vista quedaba con scroll horizontal y el boton de
   borrar caia fuera (medido: la tarjeta terminaba en x=360).
   Es el mismo problema que el minmax(auto) de las grillas, con otra cara. */
.season-card-header .season-name {
  flex: 1 1 60px;
  min-width: 0;
}

/* La temporada de hoy: una etiqueta en Agua y el borde un poco mas marcado.
   Con diez tarjetas de meses, es la que se busca primero. */
.season-card.en-curso {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}

.season-estado {
  flex: none;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}

.season-name {
  flex: 1 1 auto;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  font-weight: 700;
  font-size: 15px;
  color: var(--ink);
  background: var(--surface);
}

.season-card-dates {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.season-card-dates label {
  display: grid;
  gap: 5px;
  flex: 1 1 120px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
}

.season-card-dates input {
  min-height: 38px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
  font-weight: 400;
}

/* Copiar/Pegar precios van en el pie, a la izquierda; "Guardar cambios" a la
   derecha cuando aparece. Antes eran un renglon propio entre las fechas y la
   tabla, y el pie quedaba vacio casi siempre. */
.season-price-actions {
  display: flex;
  gap: 8px;
}

.season-price-actions .ghost-button {
  min-height: 30px;
  padding: 0 10px;
  font-size: 12px;
}

/* La tabla de precios tiene 3 columnas con inputs adentro: en 320px su
   ancho minimo real es mayor que la pantalla y empujaba la PAGINA entera a
   scroll horizontal. El que scrollea es el contenedor de la tabla, que es
   donde corresponde: la pagina queda quieta y la tabla se explora sola.

   Hasta el 12/10 la tabla misma era el bloque que scrolleaba, con el thead y
   el tbody como DOS tablas sueltas de ancho max-content: los titulos no
   quedaban arriba de sus columnas ("Promo 7+ noches" empezaba 50px antes que
   sus campos) y en una tarjeta de 430px la tabla pedia 434 y cortaba el "%"
   y el descuento. Ahora es UNA tabla al 100% de la tarjeta y los campos de
   precio se achican hasta un minimo (abajo): solo si ni asi entra, scrollea
   el contenedor. */
.season-price-scroll {
  max-width: 100%;
  overflow-x: auto;
}

.season-price-table {
  width: 100%;
  border-collapse: collapse;
}

/* La columna del tipo, del ancho de su texto; el resto se reparte entre los
   precios. */
.season-price-table th:first-child {
  width: 1%;
}

.season-price-table th + th,
.season-price-table td + td {
  padding-left: 8px;
}

.season-price-table th {
  text-align: left;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 0 0 6px;
  border-bottom: 1px solid var(--line);
}

.season-price-table td {
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.season-price-table tr:last-child td {
  border-bottom: none;
}

.season-room-type {
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  padding-right: 2px;
}

.season-price {
  min-height: 36px;
  width: 100%;
  /* En caracteres y no en px: con 16px de letra (pantallas tactiles) un
     precio de 7 cifras no entraba en 108px (FE-104). El minimo es lo que
     ocupa "$1.234.567.-": por debajo de eso la tabla scrollea en vez de
     esconder cifras. */
  min-width: 12ch;
  max-width: 15ch;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 9px;
  color: var(--ink);
  background: var(--surface);
  font-size: 13.5px;
}

.season-promo-price {
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
}

.season-promo-price::placeholder {
  color: var(--muted);
  font-size: 12px;
}

/* La celda sigue siendo una celda (con display:flex dejaba de serlo y su
   titulo no quedaba arriba): la fila de precio + % + descuento es la capa de
   adentro. Ver "Las dos promos se turnan" mas abajo. */
.season-promo-tier {
  display: flex;
  align-items: center;
  gap: 6px;
}

.season-promo-tier .season-price {
  flex: 1 1 auto;
}

/* El descuento ("−10%") tiene su lugar aunque esa fila no tenga promo: sin
   eso el campo promo de esa fila se estiraba y los "%" no quedaban en
   columna. El hueco lo ocupa un ::after del mismo ancho, porque .hidden es
   display:none con !important. */
.season-promo-tier .promo-discount-hint {
  min-width: 30px;
}

.season-promo-tier:has(> .promo-discount-hint.hidden)::after {
  content: "";
  flex: 0 0 30px;
}

.season-promo-percent {
  flex: none;
  min-height: 36px;
  width: 46px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 6px;
  color: var(--muted);
  background: var(--surface);
  font-size: 12px;
}

.season-promo-percent::placeholder {
  color: var(--muted);
}

.season-card-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.season-card-footer .save-season {
  margin-left: auto;
}

.promo-discount-hint {
  font-size: 11px;
  font-weight: 700;
  color: var(--tint-green-ink);
  white-space: nowrap;
}

.promo-discount-hint.warn {
  color: var(--tint-red-ink);
}

.promo-discount-hint.hidden {
  display: none;
}

.extras-list {
  display: grid;
  gap: 10px;
}

.extra-row {
  display: grid;
  /* Siete columnas: nombre, precio, forma de cobro, obligatorio, fechas sin
     cargo, guardar y eliminar. Con seis, el boton de eliminar se caia a un
     renglon propio al sumar el de fechas. */
  grid-template-columns: 1fr 140px 180px auto auto auto auto;
  gap: 8px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
}

.extra-mandatory-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap;
}

.extra-mandatory-toggle input {
  width: auto;
  min-height: auto;
}

.extra-row input,
.extra-row select {
  min-height: 38px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
}

.users-list {
  display: grid;
  gap: 10px;
  margin-bottom: 14px;
}

.user-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 10px;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
}

.user-row-identity {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.user-row-name {
  font-weight: 700;
  font-size: 13.5px;
}

.user-row-role {
  color: var(--muted);
  font-size: 12px;
  text-transform: capitalize;
}

.users-add-form {
  display: grid;
  grid-template-columns: 1fr 140px 140px auto;
  gap: 8px;
}

.users-add-form input,
.users-add-form select {
  min-height: 38px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
}

.form-grid textarea {
  margin-top: 6px;
  width: 100%;
  min-height: 90px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px;
  color: var(--ink);
  background: var(--surface);
  font: inherit;
  resize: vertical;
}

.funnel,
.channel-bars {
  display: grid;
  gap: 12px;
}

.funnel-row,
.channel-row {
  display: grid;
  gap: 6px;
}

/* La pista de una barra horizontal. --accent es el color semantico de los
   botones de la app; el de un grafico es --chart-1, un turquesa mas claro
   que el del boton: la barra se lee como dato y no como un control, y la
   accion principal sigue siendo el unico turquesa fuerte de la pantalla. */
.bar-track {
  height: 10px;
  background: var(--surface-muted);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.bar-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--chart-1);
}

/* ===== Panel de Estadisticas ===== */
.stats-kpi-grid {
  /* Mismo motivo que .season-cards: el minimo fijo desbordaba en 320px. */
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  margin-bottom: 0;
}

.metric {
  position: relative;
}

.stat-trend {
  display: block;
  margin-top: 8px;
  font-size: 12px;
  font-weight: 700;
}

.stat-trend.up {
  color: var(--tint-green-ink);
}

.stat-trend.down {
  color: var(--tint-red-ink);
}

.stat-trend.neutral {
  color: var(--accent-strong);
}

.stat-trend.flat {
  color: var(--muted);
}

.stats-chart {
  width: 100%;
}

.stats-chart-svg {
  width: 100%;
  height: auto;
  display: block;
}

.stats-grid-line {
  stroke: var(--line);
  stroke-width: 1;
}

.stats-axis-label {
  fill: var(--muted);
  font-size: 11px;
}

.stats-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 10px;
}

.stats-legend-vertical {
  flex-direction: column;
  gap: 8px;
  margin-bottom: 0;
}

.stats-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted);
}

.stats-legend-item i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  display: inline-block;
}


.stats-channel-table {
  display: grid;
  gap: 4px;
}

.stats-channel-row {
  display: grid;
  grid-template-columns: 1.4fr 0.8fr 1fr 1fr;
  gap: 8px;
  align-items: center;
  padding: 10px 6px;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
}

.stats-channel-row.stats-channel-head {
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line);
}

.stats-muted {
  color: var(--muted);
}

.stats-empty {
  color: var(--muted);
  font-size: 14px;
  padding: 18px 0;
  text-align: center;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 14px;
}

/* El rotulo baja de 700 a 500 y de 13px a 12.5px: con Inter real, un label
   en 700 pesaba casi lo mismo que el valor escrito adentro del campo, y la
   fila entera leia como si todo fuera igual de importante. */
.form-grid label {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
}

.form-grid input {
  margin-top: 6px;
}

.knowledge-list div {
  padding: 12px;
}

.knowledge-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

/* Las reglas del asistente son lo que el bot sabe: franja violeta de la IA
   y el rotulo del panel en violeta. Acotado al id porque .knowledge-item
   dibuja tambien el personal de limpieza, los destinatarios del informe,
   las copias de factura y las mesas, que no son del bot. La tarjeta sigue
   blanca: alcanza con la franja. */
#knowledge-list .knowledge-item {
  border-left: 3px solid var(--ai);
}

.panel:has(> #knowledge-list) .eyebrow {
  color: var(--ai-strong);
}

.knowledge-item .icon-button {
  min-height: 28px;
  width: 28px;
  flex: 0 0 auto;
}

.knowledge-add-form {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

.knowledge-add-form input {
  flex: 1 1 auto;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
}

.settings-hint {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

/* Rotulo de una lista dentro de un panel de Configuracion ("Enviar a", arriba
   de los destinatarios del informe). No es .settings-hint: eso es texto de
   aclaracion, va en gris claro y sin margen arriba, y usado como rotulo queda
   pegado al campo de mas arriba y no se lee como el titulo de lo que sigue. */
.settings-list-label {
  margin: 16px 0 8px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
}

.settings-search {
  position: relative;
  margin-bottom: 4px;
}

.settings-search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.settings-search-icon {
  position: absolute;
  left: 12px;
  width: 16px;
  height: 16px;
  color: var(--muted);
  pointer-events: none;
}

#settings-search-input {
  width: 100%;
  padding: 10px 14px 10px 36px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  box-shadow: var(--shadow);
}

.settings-search-results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 5;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
  max-height: 320px;
  overflow-y: auto;
}

.settings-search-results.hidden {
  display: none;
}

.settings-search-result {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 14px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  font: inherit;
  color: var(--ink);
}

.settings-search-result:last-child {
  border-bottom: none;
}

.settings-search-result:hover,
.settings-search-result:focus-visible {
  background: color-mix(in srgb, var(--ink) 6%, transparent);
}

.settings-search-result-label {
  display: block;
  font-weight: 600;
  font-size: 13.5px;
}

.settings-search-result-group {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}

.settings-search-empty {
  padding: 14px;
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

/* Configuracion en maestro-detalle: categorias a la izquierda, detalle de
   la elegida a la derecha (como Ajustes de Instagram, pedido explicito del
   usuario). Reemplaza al viejo acordeon de 7 tarjetas apiladas en una sola
   columna. */
.settings-shell {
  display: grid;
  grid-template-columns: minmax(200px, 240px) minmax(0, 1fr);
  align-items: start;
  gap: 22px;
}

.settings-sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.settings-sidebar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.settings-nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px;
}

.settings-nav-item {
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  /* La transition (transform + colores) la pone la lista compartida de
     "respuesta al tacto" mas arriba en el archivo -- no redeclarar aca. */
}

.settings-nav-item:hover {
  background: color-mix(in srgb, var(--ink) 5%, transparent);
}

.settings-nav-item.active {
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-weight: 700;
}

.settings-detail {
  min-width: 0;
}

/* Solo aparece en mobile (ver @media screen and (max-width: 980px) mas
   abajo en el archivo) -- en escritorio las dos columnas se ven siempre
   juntas y no hace falta "volver" a ningun lado. */
.settings-detail-back {
  display: none;
  margin-bottom: 14px;
}

.settings-panel-group {
  display: none;
  flex-direction: column;
  gap: 18px;
}

.settings-panel-group.active {
  display: flex;
}

.settings-detail-title {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Modulos del PMS: una fila por modulo opcional, switch a la derecha. */
.feature-toggle-list {
  display: flex;
  flex-direction: column;
}

.feature-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 13px 2px;
  border-bottom: 1px solid var(--line);
}

.feature-toggle-row:last-child {
  border-bottom: none;
}

.feature-toggle-identity {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.feature-toggle-name {
  font-size: 13.5px;
  font-weight: 600;
}

.feature-toggle-hint {
  font-size: 12px;
  color: var(--muted);
}

/* Switch tipo interruptor: un checkbox nativo (teclado/lector de pantalla
   gratis, mismo criterio que .panel-plegable en otro lado del archivo) mas
   dos spans estilizados. El input real queda invisible pero cubre TODA el
   area del control (position:absolute inset:0) para que el click funcione
   en cualquier punto del rectangulo, no solo en un pixel del medio. */
.feature-switch {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  width: 40px;
  height: 24px;
  cursor: pointer;
}

.feature-switch-input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}

.feature-switch-track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ink) 18%, transparent);
  transition: background-color var(--dur-fast) var(--ease-out);
}

.feature-switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: white;
  box-shadow: var(--shadow);
  transition: transform var(--dur-fast) var(--ease-out);
}

.feature-switch-input:checked ~ .feature-switch-track {
  background: var(--accent);
}

.feature-switch-input:checked ~ .feature-switch-track .feature-switch-thumb {
  transform: translateX(16px);
}

.feature-switch-input:focus-visible ~ .feature-switch-track {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
}

.feature-switch-input:disabled {
  cursor: not-allowed;
}

.feature-switch-input:disabled ~ .feature-switch-track {
  opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
  .feature-switch-track,
  .feature-switch-thumb {
    transition: none;
  }
}

@keyframes settings-search-pulse {
  0% {
    background-color: color-mix(in srgb, var(--accent) 22%, transparent);
  }
  100% {
    background-color: transparent;
  }
}

.settings-search-target-flash {
  border-radius: 8px;
  animation: settings-search-pulse 1.6s ease-out;
}

.status-warning-text {
  color: var(--tint-red-ink);
  font-weight: 700;
}

.settings-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.operating-season-panel {
  margin-bottom: 24px;
}

/* readonly a proposito (el picker de abajo escribe el valor, no se tipea a
   mano) -- pero sigue siendo clickeable, asi que no hereda el cursor
   "not-allowed" del input:read-only generico. */
.pms-date-input {
  cursor: pointer;
  background: var(--surface);
}

/* Panel flotante que reemplaza <input type="date"> en toda la pantalla de
   Tarifas (temporada operativa + from/to de cada tarjeta) -- mismo patron de
   posicionamiento que .topnav-dropdown. Un solo elemento singleton en el
   DOM (ver #pms-datepicker-popover en index.html), reposicionado y
   rellenado en JS segun que input lo abrio. */
.pms-datepicker-popover {
  position: absolute;
  z-index: 60;
  width: 260px;
  padding: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
}

.pms-datepicker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 8px;
}

.pms-datepicker-nav {
  min-height: 30px;
  width: 30px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font-size: 15px;
  cursor: pointer;
}

.pms-datepicker-month-toggle {
  flex: 1 1 auto;
  min-height: 30px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-weight: 700;
  font-size: 13.5px;
  text-transform: capitalize;
  cursor: pointer;
}

.pms-datepicker-shortcut {
  display: block;
  width: 100%;
  min-height: 28px;
  margin-bottom: 8px;
  border: 1px dashed var(--accent);
  border-radius: 8px;
  background: transparent;
  color: var(--accent-strong);
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
}

.pms-datepicker-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.pms-datepicker-dow {
  text-align: center;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  padding-bottom: 4px;
}

.pms-datepicker-day {
  min-height: 30px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
  font-size: 12.5px;
  cursor: pointer;
}

.pms-datepicker-day:hover:not(:disabled) {
  border-color: var(--accent);
}

.pms-datepicker-day.selected {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 700;
}

.pms-datepicker-day.today:not(.selected) {
  border-color: var(--line);
  font-weight: 700;
}

.pms-datepicker-day:disabled {
  color: var(--muted);
  opacity: 0.4;
  cursor: not-allowed;
}

/* Meses del selector rapido "‹ Mes Año ›" -> grilla de 12 meses en vez de
   dias, mismo popover reusado (togglea .pms-datepicker-grid entre modo dia
   y modo mes via una clase en el contenedor). */
.pms-datepicker-grid.months-mode {
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}

.pms-datepicker-grid.months-mode .pms-datepicker-day {
  min-height: 34px;
  text-transform: capitalize;
}

.whatsapp-qr-box {
  margin-bottom: 14px;
}

.whatsapp-qr-box img {
  width: 220px;
  max-width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px;
  background: var(--surface);
}

/* ---------------------------------------------------------------------------
   Habitaciones: tablero en grilla (reemplaza a la tabla de 8 columnas).
   Pedido explicito: ver de un vistazo que habitaciones estan libres, cuales
   ocupadas y cuales tienen a alguien entrando mañana, en vez de leer una
   lista fila por fila.

   El color NUNCA es el unico indicador — cada tarjeta dice su estado con
   todas las letras ("Libre", "Ocupada", "Entra mañana"), que es lo que hace
   que el tablero siga siendo legible para alguien con daltonismo o en una
   pantalla lavada por el sol de la recepcion.
   --------------------------------------------------------------------------- */
.rooms-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-bottom: 16px;
  font-size: 12px;
  color: var(--muted);
}

.rooms-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.rooms-legend-item i {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
}

.rooms-legend-item.libre i {
  background: color-mix(in srgb, var(--green) 30%, var(--surface));
  border-color: var(--green);
}

.rooms-legend-item.entra-manana i {
  background: color-mix(in srgb, var(--yellow) 45%, var(--surface));
  border-color: color-mix(in srgb, var(--yellow) 80%, var(--ink));
}

.rooms-legend-item.ocupada i {
  background: color-mix(in srgb, var(--red) 26%, var(--surface));
  border-color: var(--red);
}

.rooms-legend-item.inactiva i {
  background: var(--surface-muted);
  border-color: var(--line);
}

.rooms-legend-hint {
  margin-left: auto;
  font-style: italic;
}

/* auto-fill + minmax: la cantidad de columnas la decide el ancho disponible,
   asi que el mismo tablero entra 2 por fila en un telefono y 7-8 en el
   monitor de recepcion, sin breakpoints a mano.
   align-items: start es lo que permite que una tarjeta abierta crezca sin
   estirar a todas las de su fila. */
.rooms-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 12px;
  align-items: start;
}

.room-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}

.room-card-summary {
  display: grid;
  gap: 3px;
  width: 100%;
  padding: 12px;
  border: none;
  background: none;
  text-align: left;
  color: inherit;
  min-height: 104px;
  align-content: start;
}

.room-card-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.room-card-name {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.room-card-type {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.room-card-state {
  font-size: 12.5px;
  font-weight: 600;
}

/* El nombre del huesped se corta a una linea: sin esto, un nombre largo hace
   mas alta la tarjeta que las demas de su fila y la grilla queda despareja. */
.room-card-guest {
  font-size: 12px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.room-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-size: 11px;
  color: var(--muted);
}

.room-card-housekeeping {
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--orange) 16%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--orange) 32%, transparent);
  color: var(--tint-orange-ink);
  font-weight: 600;
}

/* Los 4 estados. El tinte es fuerte a proposito (bastante mas que el de un
   badge): la tarjeta ENTERA es la señal, tiene que leerse cruzando la vista
   por la grilla sin detenerse en ninguna. */
.room-card.room-libre {
  background: color-mix(in srgb, var(--green) 11%, var(--surface));
  border-color: color-mix(in srgb, var(--green) 34%, var(--line));
}

.room-card.room-libre .room-card-state {
  color: var(--tint-green-ink);
}

.room-card.room-entra-manana {
  background: color-mix(in srgb, var(--yellow) 22%, var(--surface));
  border-color: color-mix(in srgb, var(--yellow) 62%, var(--line));
}

/* El amarillo es el unico de los cuatro que es claro POR SI MISMO, asi que
   sobre una superficie oscura el mismo 22% que funciona en modo claro levanta
   el fondo a un tono medio, y el texto secundario (--muted) se cae a 3.6:1
   (medido). Con menos tinte la tarjeta se sigue leyendo amarilla contra sus
   vecinas y el contraste vuelve a pasar. El borde queda fuerte para que no
   pierda presencia en la grilla. */
html[data-theme="dark"] .room-card.room-entra-manana {
  background: color-mix(in srgb, var(--yellow) 9%, var(--surface));
  border-color: color-mix(in srgb, var(--yellow) 55%, var(--line));
}

.room-card.room-entra-manana .room-card-state {
  color: var(--tint-yellow-ink);
}

.room-card.room-ocupada {
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  border-color: color-mix(in srgb, var(--red) 32%, var(--line));
}

.room-card.room-ocupada .room-card-state {
  color: var(--tint-red-ink);
}

.room-card.room-inactiva {
  background: var(--surface-muted);
  border-style: dashed;
}

.room-card.room-inactiva .room-card-name {
  color: var(--muted);
}

.room-card.room-inactiva .room-card-state {
  color: var(--tint-gray-ink);
}

.room-card-summary:hover {
  background: color-mix(in srgb, var(--ink) 5%, transparent);
}

.room-card.expanded {
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}

.room-card-body {
  display: none;
  gap: 10px;
  padding: 0 12px 12px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.room-card.expanded .room-card-body {
  display: grid;
}

.room-card-body label {
  display: grid;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.room-card-body .wide {
  grid-column: 1 / -1;
}

.room-card-body input,
.room-card-body select {
  min-height: 34px;
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  padding: 0 8px;
  font-size: 13px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
}

.room-card-body .room-active-toggle {
  grid-column: 1 / -1;
  width: 100%;
}

.payment-list {
  display: grid;
  gap: 8px;
  align-content: start;
}

/* Fila de titulos de columna sobre el registro -- mismas columnas que
   #payment-list .payment-row de abajo, tienen que coincidir si se cambia
   una de las dos. */
.payment-list-header {
  display: grid;
  grid-template-columns: 90px minmax(160px, 1fr) 130px 136px 100px 64px;
  gap: 12px;
  padding: 0 12px 6px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}

.payment-list-header span:last-child {
  text-align: right;
}

.payment-row {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 11px;
  background: var(--surface);
}

.payment-row strong,
.payment-row span,
.payment-row small {
  display: block;
}

.payment-row span,
.payment-row small {
  color: var(--muted);
  font-size: 13px;
  margin-top: 3px;
}

/* Fila del REGISTRO principal (#payment-list, la vista Pagos) -- grid de
   columnas fecha/reserva/metodo/monto/comprobante/anular. El detalle de una
   reserva puntual (.detail-payments-list) sigue usando la misma clase base
   .payment-row pero con el layout flex de .payment-row-main de abajo, mas
   chico -- no ligar estas reglas a esa otra lista sin querer. */
#payment-list .payment-row {
  display: grid;
  grid-template-columns: 90px minmax(160px, 1fr) 130px 136px 100px 64px;
  align-items: center;
  gap: 12px;
  transition: 150ms ease;
  cursor: pointer;
  text-align: left;
  width: 100%;
  font: inherit;
}

#payment-list .payment-row:hover {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}

.payment-row-actions {
  display: flex;
  justify-content: flex-end;
  gap: 4px;
}

.view-proof {
  color: var(--muted);
}

.view-proof:hover {
  color: var(--accent-strong);
}

.edit-payment {
  color: var(--muted);
}

.edit-payment:hover {
  color: var(--accent-strong);
}

.view-proof svg,
.edit-payment svg {
  width: 16px;
  height: 16px;
}

.payment-row-date {
  font-size: 13px;
  color: var(--muted);
}

.payment-row-guest {
  min-width: 0;
}

.payment-row-guest strong {
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.payment-row-guest span,
.payment-row-guest small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.payment-method-badge {
  justify-self: start;
}

.payment-row .payment-method-badge {
  background: var(--accent-soft);
  color: var(--accent-strong);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* Cada medio de pago con su color. Antes eran todos del mismo turquesa, o
   sea que la columna "metodo" habia que LEERLA fila por fila. Al cerrar
   caja la pregunta es siempre "cuanto entro por efectivo y cuanto por
   tarjeta", y con colores distintos eso se responde barriendo la columna.
   El color no es la unica señal: el nombre del medio sigue escrito. */
.payment-row .payment-method-badge.medio-efectivo {
  background: color-mix(in srgb, var(--green) 14%, var(--surface));
  color: var(--tint-green-ink);
}

.payment-row .payment-method-badge.medio-tarjeta {
  background: color-mix(in srgb, var(--blue) 14%, var(--surface));
  color: var(--tint-blue-ink);
}

.payment-row .payment-method-badge.medio-transferencia {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

/* Mercado Pago era violeta, y el violeta ahora es SOLO de la IA. Va en
   Tinta: el mismo tinte neutro de "otro" pero mas marcado y con el texto
   en --ink (14.0 en claro y 9.7 en oscuro, contra 5.9 y 6.8 de "otro"),
   asi se separa de los demas medios sin gastar un color. --ink se da
   vuelta sola en oscuro: no hace falta regla aparte. */
.payment-row .payment-method-badge.medio-mercado_pago {
  background: color-mix(in srgb, var(--ink) 12%, var(--surface));
  color: var(--ink);
}

.payment-row .payment-method-badge.medio-otro {
  background: color-mix(in srgb, var(--ink) 7%, var(--surface));
  color: var(--muted);
}

/* 136px y nowrap: un monto de 9 cifras con centavos ("$123.456.789,50") no
   entraba en 110 y se salia de la columna (FE-104). */
.payment-row-amount {
  font-size: 14px;
  text-align: right;
  white-space: nowrap;
}

.payment-row-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.payment-row-main > div {
  min-width: 0;
}

.delete-payment {
  flex: 0 0 auto;
  min-height: 32px;
  width: 32px;
  /* El color lo pone .destructivo. Antes era --red pelado, que como tinta
     sobre la tarjeta oscura (#2a2650) da 3.27 -- abajo del minimo legible. */
}

/* "Sin comprobante" era un recuadro punteado ROJO en cada fila que no
   tuviera imagen adjunta. En una tabla donde la mayoria de los pagos
   historicos no tiene comprobante cargado, eso pinta la pantalla entera de
   alarma -- y una alarma que suena siempre deja de comunicar: se aprende a
   ignorarla, incluida la fila donde el comprobante SI hacia falta.
   Ahora es una nota gris al margen. Sigue estando, sigue siendo legible, y
   el rojo queda libre para lo que de verdad es un problema (saldos
   impagos, diferencias de caja). */
.payment-proof-missing {
  /* flex: 0 0 auto obligaba a la pastilla a mantener su ancho ideal aunque
     la columna fuera mas angosta, asi que el texto se cortaba contra el
     boton de al lado (verificado: pedia 109px en una columna de 98).
     Con `min-width: 0` mas ellipsis se achica de forma ordenada. */
  flex: 0 1 auto;
  min-width: 0;
  font-size: 11px;
  color: var(--muted);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  border-radius: var(--radius);
  padding: 4px 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-style: italic;
}

.payment-reservation-picker {
  position: relative;
  margin-bottom: 14px;
}

.payment-search-results {
  display: none;
  position: absolute;
  z-index: 5;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
  padding: 6px;
  max-height: 280px;
  overflow-y: auto;
  flex-direction: column;
  gap: 4px;
}

.payment-search-results.visible {
  display: flex;
}

.payment-search-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  border: none;
  background: transparent;
  border-radius: var(--radius);
  padding: 8px 10px;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: var(--ink);
}

.payment-search-result:hover {
  background: color-mix(in srgb, var(--accent-soft) 55%, var(--surface));
}

.payment-search-result strong {
  display: block;
  font-size: 13px;
}

.payment-search-result span {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}

.payment-search-result .balance-clear {
  color: var(--tint-green-ink);
  font-weight: 700;
  font-size: 12px;
  white-space: nowrap;
}

.payment-search-result .balance-due {
  font-size: 12px;
  white-space: nowrap;
}

.payment-selected-reservation {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 10px;
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 10px 12px;
}

.payment-selected-reservation strong {
  display: block;
  font-size: 13px;
}

.payment-selected-reservation span {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
}

.payment-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-top: 16px;
}

.payment-form label {
  display: grid;
  /* start y no el stretch por defecto: la celda del monto es mas alta que las
     otras (abajo del campo lleva los atajos de seña y el aviso de saldo), y sin
     esto la grilla repartia ese alto de mas ENTRE el rotulo y el campo de al
     lado -- el desplegable de metodo de pago quedaba flotando, con un hueco
     arriba, en vez de arrancar a la misma altura que el monto. */
  align-content: start;
  gap: 5px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
  min-width: 0;
}

.payment-form input,
.payment-form select {
  min-height: 40px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 10px;
  color: var(--ink);
  background: var(--surface);
  font: inherit;
}

.payment-form textarea {
  width: 100%;
  min-height: 40px;
  /* Sin resize manual: el alto lo maneja el propio texto (data-crece), y una
     esquina para arrastrar al lado de un campo que ya crece solo confunde. */
  resize: none;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 9px 10px;
  color: var(--ink);
  background: var(--surface);
  font: inherit;
  line-height: 1.4;
}

.payment-form input[type="file"] {
  padding: 8px 10px;
  min-height: 40px;
}

.payment-form .wide,
.payment-form-actions {
  grid-column: 1 / -1;
}

.payment-proof-hint {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
}

.payment-proof-hint.ok {
  color: var(--tint-green-ink);
  font-weight: 700;
}

/* El archivo no sirve (no es PDF ni foto, un PDF de mas de 3 MB, una HEIC que
   el navegador no abre): el motivo en rojo, en el mismo lugar del aviso. */
.payment-proof-hint.error {
  color: var(--tint-red-ink);
  font-weight: 700;
}

/* Atajos de monto (seña / saldo restante). Van pegados debajo del campo, como
   sugerencias del propio campo y no como acciones del formulario -- por eso son
   chips chicos y no botones con el peso de "Registrar pago". */
.payment-quick-amounts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
}

.quick-amount {
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink);
  padding: 3px 11px;
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 120ms ease, background 120ms ease;
}

.quick-amount:hover {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  color: var(--accent-strong);
}

.quick-amount:active { transform: translateY(1px); }

/* Aviso de saldo debajo del monto. En estado normal dice cuanto falta cobrar;
   con .alerta avisa que el monto tipeado se pasa (o que la reserva ya esta
   saldada). Usa --tint-*-ink y no --orange/--red pelados: esos estan pensados
   como FONDO con texto blanco encima y como texto no llegan al contraste
   minimo. */
.payment-balance-hint {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--muted);
}

.payment-balance-hint.alerta {
  color: var(--tint-orange-ink);
  font-weight: 700;
}

.payment-proof-preview {
  margin-top: 4px;
}

.payment-proof-preview img {
  max-width: 160px;
  max-height: 160px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  display: block;
}

.payment-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 4px;
}

.primary-button:disabled {
  background: var(--gray);
  border-color: var(--gray);
  color: #f1f3f5;
  cursor: not-allowed;
  box-shadow: none;
}

.primary-button:disabled:hover {
  background: var(--gray);
}

.ghost-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.ghost-button:disabled:hover {
  border-color: var(--line);
}

@media (max-width: 900px) {
  .payment-form {
    grid-template-columns: 1fr;
  }

  .payment-form-actions {
    flex-direction: column-reverse;
  }

  .payment-form-actions button {
    width: 100%;
  }

  .payment-list-header {
    display: none;
  }

  #payment-list .payment-row {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "guest amount"
      "date method"
      "proof actions";
    row-gap: 6px;
  }

  .payment-row-guest {
    grid-area: guest;
  }

  .payment-row-amount {
    grid-area: amount;
  }

  .payment-row-date {
    grid-area: date;
  }

  .payment-row .payment-method-badge {
    grid-area: method;
    justify-self: end;
  }

  .view-proof,
  .payment-proof-missing {
    grid-area: proof;
    justify-self: start;
  }

  .payment-row-actions {
    grid-area: actions;
  }
}

.print-area {
  overflow-x: auto;
}

.listing-heading {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 14px;
}

.listing-table {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
}

/* Al hacer scroll horizontal (tablas mas anchas que la pantalla, sobre todo
   en mobile) se perdia de vista a que fila correspondia cada celda -- la
   primera columna queda fija, mismo criterio que .cell.room en el grid de
   Planning. */
.listing-table th:first-child,
.listing-table td:first-child,
.housekeeping-table th:first-child,
.housekeeping-table td:first-child {
  position: sticky;
  left: 0;
  background: var(--surface);
  z-index: 1;
}

.listing-table th,
.listing-table td {
  border-bottom: 1px solid var(--line);
  padding: 11px 12px;
  text-align: left;
  vertical-align: top;
}

/* Encabezado de tabla con el mismo tratamiento que .eyebrow (chico, en
   mayusculas, con separacion entre letras y peso medio): sin esto el th
   pesaba lo mismo que el dato de la celda y la tabla leia como un bloque
   uniforme, sin saber donde terminaba el rotulo y empezaba el contenido. */
.listing-table th {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-bottom-color: var(--line);
  padding-top: 8px;
  padding-bottom: 8px;
}

.listing-table tbody tr:last-child td {
  border-bottom: none;
}

/* El toast entra y sale POR EL MISMO LADO (desde abajo, su borde mas
   cercano), y se mide en % de su propia altura en vez de en px fijos: asi
   un toast de dos lineas recorre lo que mide el, no 12px sueltos elegidos
   para un toast de una linea.
   La transicion nombra sus propiedades: el `transition: 170ms ease` de
   antes animaba TODO -- incluido el box-shadow y los colores -- en cada
   aparicion. */
.toast {
  position: fixed;
  right: 18px;
  bottom: 18px;
  transform: translateY(calc(100% + 18px));
  opacity: 0;
  pointer-events: none;
  /* Tinta fija en los dos temas. El borde es el del set "sobre fondo oscuro"
     de la marca: en el tema oscuro el fondo de la pagina es la misma Tinta y
     sin el el aviso no se despegaba. */
  background: #16142e;
  border: 1px solid #3a3566;
  color: white;
  border-radius: var(--radius);
  padding: 12px 14px;
  box-shadow: var(--shadow-float);
  font-weight: 500;
  transition:
    transform var(--dur-modal) var(--ease-out),
    opacity var(--dur-modal) var(--ease-out);
  z-index: 20;
}

.toast.visible {
  transform: translateY(0);
  opacity: 1;
}

/* El velo se funde junto con el modal. Antes el modal entraba animado pero
   el fondo oscuro aparecia de golpe en el frame 0, asi que se leian como dos
   cosas distintas apareciendo a destiempo en vez de como una sola capa.
   El blur es apenas 2px: lo suficiente para que el contenido de atras deje
   de competir por la atencion, no tanto como para costar GPU en la PC de
   recepcion (el velo es fixed, que es donde el blur si es barato). */
.pms-confirm-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(22, 20, 46, 0.45);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 50;
  animation: backdropIn var(--dur-modal) var(--ease-out);
}

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

.pms-confirm-modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 22px;
  width: min(380px, 100%);
  max-height: min(640px, 80vh);
  display: flex;
  flex-direction: column;
  /* Un modal SI flota sobre el contenido: --shadow-float, no --shadow (que
     desde el rediseño plano vale none). Antes usaba la sombra de 1px de las
     tarjetas en flujo, que para un dialogo encima de un velo era demasiado
     poco de todas formas. */
  box-shadow: var(--shadow-float);
  animation: popoverIn 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.pms-confirm-modal h3 {
  margin: 0 0 8px;
  font-size: 16px;
  flex-shrink: 0;
}

.pms-confirm-modal p {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-line;
  overflow-y: auto;
  min-height: 0;
}

/* Body del modal de ayuda contextual (#pms-help-backdrop) -- mismo
   .pms-confirm-modal como contenedor (hereda el max-height:80vh + layout en
   columna), pero HTML real (<p>/<ul>/<strong>) en vez del texto con saltos
   de linea de pmsConfirm, asi que no puede reusar la regla de arriba
   (white-space:pre-line rompe listas/parrafos). */
.pms-help-body {
  overflow-y: auto;
  min-height: 0;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.6;
}

.pms-help-body p {
  margin: 0 0 10px;
}

.pms-help-body p:last-child {
  margin-bottom: 0;
}

.pms-help-body ul {
  margin: 0 0 10px;
  padding-left: 18px;
}

.pms-help-body li {
  margin-bottom: 4px;
}

.pms-help-body strong {
  color: var(--ink);
}

/* Vista #ayuda -- consolida las 15 entradas de helpTopics (reusando
   .pms-help-body de arriba dentro de cada tarjeta) en un solo lugar
   navegable con buscador. */
.help-search-bar input {
  width: 100%;
  min-height: 38px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 12px;
  font-size: 14px;
  color: var(--ink);
  background: var(--surface-muted);
}

.help-topics-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 18px;
}

.help-topic-card h3 {
  margin: 0 0 10px;
}

/* Icono "?" de ayuda contextual por vista -- chico a proposito para ir
   inline al lado de un titulo (h1/h2 de 16-19px) sin romper el ritmo
   vertical; .icon-button (38px) es demasiado grande para este uso. */
.help-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  margin-left: 8px;
  /* 24px es el minimo tactil de WCAG 2.2 AA. Con 20x20 quedaba por debajo, y
     este boton aparece en las 16 vistas del PMS. */
  width: 24px;
  height: 24px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.help-icon-btn:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
}

/* 24px es el minimo tactil de WCAG 2.2 AA y la regla base ya lo respeta;
   este override lo bajaba a 22 y dejaba el boton por debajo del minimo
   justo en las dos vistas que muestran el titulo grande (Inicio y
   Limpieza). Detectado midiendo el boton renderizado en 6 configuraciones
   de pantalla, no leyendo el CSS. Se mantiene la tipografia mas grande que
   pedia ese override, que era el motivo real del cambio. */
.topbar h1 .help-icon-btn {
  width: 24px;
  height: 24px;
  font-size: 13px;
}

/* Ancla del icono de ayuda para vistas sin ningun titulo propio
   (Configuracion) -- una fila minima antes del contenido real de la vista. */
.view-help-anchor {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 4px;
}

/* Mismo backdrop que pmsConfirm (.pms-confirm-backdrop), contenido propio:
   una imagen grande centrada en vez de un dialogo chico de texto. */
.proof-viewer-modal {
  position: relative;
  max-width: min(90vw, 640px);
  /* dvh y no vh: en un telefono vh es el viewport MAS GRANDE posible (el que
     habria sin la barra del navegador), asi que 90vh no entra en lo que de
     verdad se ve y el comprobante queda cortado abajo. La linea de vh queda
     como respaldo para un navegador que no entienda dvh. */
  max-height: 90vh;
  max-height: 90dvh;
  animation: popoverIn 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.proof-viewer-modal img {
  display: block;
  max-width: 100%;
  max-height: 90vh;
  max-height: 90dvh;
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
}

/* Mientras el comprobante baja, el velo no puede quedar vacio: un <img> con
   src="" mide 0x0, asi que el modal desaparecia y solo flotaba la cruz de
   cerrar. Se reserva un rectangulo con el mismo barrido que usan las fotos del
   chat (un spinner centrado en un rectangulo vacio se lee como un error). */
.proof-viewer-modal.cargando {
  width: min(78vw, 360px);
  height: min(62dvh, 420px);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
  background: linear-gradient(100deg,
    var(--surface-muted) 30%,
    color-mix(in srgb, var(--ink) 7%, var(--surface-muted)) 50%,
    var(--surface-muted) 70%);
  background-size: 220% 100%;
  animation: chat-imagen-barrido 1.4s ease-in-out infinite;
}

.proof-viewer-close {
  position: absolute;
  top: -14px;
  right: -14px;
  background: var(--surface);
  border: 1px solid var(--line);
  /* Flota sobre la imagen del comprobante y su velo oscuro -- necesita
     despegarse de verdad, --shadow ya no dibuja nada. */
  box-shadow: var(--shadow-float);
}

/* --- Comprobantes en PDF ---------------------------------------------------
   Un PDF no entra en un <img>. En la vista previa del formulario es una ficha
   (icono, nombre, peso y "Ver"); en el visor, la misma ficha con "Abrir en
   otra pestaña" y "Descargar", y abajo el PDF en un iframe cuando el
   navegador sabe mostrarlo (ver mostrarComprobanteEnElVisor). */
.comprobante-pdf {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 360px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.comprobante-pdf-icono {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 36px;
  height: 44px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  color: var(--tint-red-ink);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.04em;
}

.comprobante-pdf-datos {
  display: grid;
  gap: 2px;
  flex: 1;
  /* El nombre de un PDF de homebanking es largo y sin espacios: sin esto
     estira la ficha fuera del formulario. */
  min-width: 0;
}

.comprobante-pdf-datos strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
}

.comprobante-pdf-datos small {
  color: var(--muted);
  font-size: 11.5px;
}

.comprobante-pdf-ver {
  flex-shrink: 0;
}

/* Con un PDF el visor deja de ser una foto flotando sobre el velo y pasa a
   ser un panel con superficie: la ficha arriba y el PDF ocupando el resto. */
.proof-viewer-modal.es-pdf {
  /* El max-width de la foto (640) le queda chico a una hoja A4 entera. */
  width: min(92vw, 880px);
  max-width: min(92vw, 880px);
  height: 88vh;
  height: 88dvh;
  display: flex;
  flex-direction: column;
  padding: 16px;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-float);
}

/* Sin visor adentro de la pagina (Chrome de Android) queda la ficha sola: un
   panel de 88% de alto vacio se leeria como que no cargo. */
.proof-viewer-modal.es-pdf:not(:has(iframe)) {
  height: auto;
}

.proof-viewer-pdf {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  min-height: 0;
}

.proof-viewer-pdf-cabecera {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  /* Lugar para la cruz de cerrar, que sobresale de la esquina. */
  padding-right: 18px;
}

/* En la cabecera el nombre arranca en 160px: sin esa base, en un telefono no
   bajaban los botones y el nombre quedaba aplastado a 19px (medido a 375). */
.proof-viewer-pdf-cabecera .comprobante-pdf-datos {
  flex: 1 1 160px;
}

.proof-viewer-pdf-acciones {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Son <a> (un blob: se abre y se descarga navegando) con la cara de boton:
   las clases de boton no traen el reset de un link. */
.proof-viewer-pdf a {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.proof-viewer-pdf-marco {
  flex: 1;
  width: 100%;
  min-height: 0;
  border: 1px solid var(--line);
  border-radius: calc(var(--radius) - 3px);
  background: var(--surface-muted);
}

.proof-viewer-pdf-nota {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

#pms-prompt-input {
  min-height: 42px;
  padding: 0 12px;
  margin-top: 4px;
  font-size: 15px;
}
#pms-prompt-input:focus-visible {
  outline: none;
  border-color: var(--focus-outline);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
#pms-prompt-message.hidden { display: none; }

.pms-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
  flex-shrink: 0;
}

.pms-confirm-actions .danger-button {
  background: var(--red);
  border-color: var(--red);
  color: white;
}

.delete-reservation-payments {
  margin-top: 14px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: rgba(217, 72, 15, 0.06);
  flex-shrink: 0;
}

.delete-reservation-payments.hidden {
  display: none;
}

.checkbox-field {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 4px 8px;
  font-size: 13px;
  cursor: pointer;
}

/* La linea de ayuda baja a su propio renglon y queda alineada con el texto
   del tilde, no con el cuadradito. Como hermana en la misma fila del flex,
   compartia el ancho con el titulo y los dos quedaban en dos columnas
   apretadas -- el titulo partido en tres renglones y la ayuda en letra
   diminuta al lado. */
.checkbox-field > small {
  flex: 1 0 100%;
  /* 13px del tilde + 8px del gap: cae bajo el texto, no bajo el cuadradito. */
  padding-left: 21px;
  color: var(--muted);
  line-height: 1.4;
}

.checkbox-field input[type="checkbox"] {
  margin-top: 2px;
  /* Bug real preexistente: ".form-grid input" (y ".reply-box input") le
     pone width:100% y min-height:40px a CUALQUIER input adentro, sin excluir
     checkboxes -- un checkbox dentro de un .form-grid quedaba estirado a lo
     ancho del contenedor (un rectangulo gigante en vez de un tilde chico).
     Esta regla ya tiene mas especificidad que esa (2 clases/atributos contra
     1), asi que alcanza con volver a declarar estas dos propiedades. */
  width: auto;
  min-height: 0;
  flex: 0 0 auto;
}

.delete-reservation-payments small {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.4;
}

/* UI polish pass */

textarea {
  font: inherit;
}

.main {
  padding: 24px;
}

.topbar {
  margin-bottom: 20px;
}

.topbar h1 {
  font-size: 30px;
}

/* Sombra teñida con el propio color del boton, no negra: una sombra gris
   debajo de un boton teal lo ensucia. Se define aca (y no como token) porque
   es la unica sombra del sistema que toma el color del elemento y no el del
   fondo. Reemplaza al var(--shadow-raised) de la regla base a proposito. */
.primary-button {
  box-shadow:
    0 1px 2px color-mix(in srgb, var(--accent) 16%, transparent),
    0 2px 8px color-mix(in srgb, var(--accent) 18%, transparent);
}

.primary-button:hover:not(:disabled) {
  box-shadow:
    0 2px 4px color-mix(in srgb, var(--accent) 20%, transparent),
    0 6px 16px color-mix(in srgb, var(--accent) 24%, transparent);
}

/* Al apretar, la sombra se achica junto con el boton. Si quedara igual, el
   boton se veria hundido pero seguiria "flotando" a la misma altura: dos
   señales contradictorias en el mismo gesto. */
.primary-button:active:not(:disabled) {
  box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 20%, transparent);
}

/* En oscuro el acento es el turquesa claro: teñida con el, la sombra se lee
   como un brillo de neon alrededor del boton. Ahi vuelve a la sombra de
   siempre, que en oscuro es negra. */
html[data-theme="dark"] .primary-button {
  box-shadow: var(--shadow-raised);
}

html[data-theme="dark"] .primary-button:hover:not(:disabled) {
  box-shadow: var(--shadow-overlay);
}

html[data-theme="dark"] .primary-button:active:not(:disabled) {
  box-shadow: var(--shadow-raised);
}

.metric-grid {
  grid-template-columns: repeat(4, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.metric,
.panel {
  padding: 18px;
}

/* --- Refinamiento de superficies ---------------------------------------
   Las tarjetas de KPI son la banda que se lee "de un vistazo" al entrar:
   son lo primero que ve recepcion cada mañana y merecen mas cuidado que un
   panel cualquiera. Se les da una elevacion minima que las despega del
   fondo sin convertirlas en botones. El fondo es blanco plano: la marca
   reserva los degradados para el logo.
   El resto de los paneles queda PLANO a proposito: en una pantalla con 15
   paneles de datos, una sombra por panel es ruido, no jerarquia. */
.metric {
  box-shadow: var(--shadow-raised);
  background: var(--surface);
  transition:
    box-shadow var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .metric:hover {
    box-shadow: var(--shadow-overlay);
    border-color: color-mix(in srgb, var(--accent) 22%, var(--line));
  }
}

.metric strong {
  margin-top: 7px;
  /* clamp y no 25px fijo: un hotel con facturacion de 7 cifras muestra
     "$1.585.500.-", que a 25px pide 150px de ancho y no entra en una
     tarjeta de KPI angosta -- se cortaba contra el borde (medido: pedia
     150px en 102 disponibles). Con clamp el numero se achica solo cuando la
     tarjeta es chica y mantiene su presencia cuando hay lugar.
     El limite inferior (17px) sigue siendo claramente el dato dominante de
     la tarjeta frente a la etiqueta de 10px. */
  font-size: clamp(17px, 4.6cqw + 8px, 25px);
  /* 700 en un numero grande de Geist se empasta; 600 mantiene el peso
     visual con mejor dibujo de las cifras. */
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* container-type habilita las unidades cqw de arriba: el numero se mide
   contra el ancho de SU tarjeta, no del viewport, que es lo correcto --
   en Estadisticas hay 4 tarjetas por fila en escritorio y 1 en telefono. */
.metric {
  container-type: inline-size;
}

/* El label de la tarjeta (OCUPACION HOY, CHECK-INS HOY...) es informacion
   secundaria: mas chico, mas espaciado y mas apagado que el numero. Antes
   competia con el dato por atencion. */
.metric .eyebrow {
  font-size: 10px;
  letter-spacing: 0.09em;
  color: color-mix(in srgb, var(--muted) 88%, transparent);
}

.panel-header {
  align-items: center;
  margin-bottom: 14px;
}

.reservation-row,
.cleaning-card {
  padding: 11px;
}

.toolbar {
  margin-bottom: 12px;
  background: color-mix(in srgb, var(--surface) 76%, transparent);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
  box-shadow: var(--shadow);
}

.toolbar-actions {
  flex-wrap: wrap;
  justify-content: flex-end;
}

.toolbar-title h2 {
  margin: 0;
  font-size: 18px;
}

.compact-field {
  display: grid;
  min-width: 160px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  gap: 5px;
}

/* .compact-field es un <label> que ENVUELVE a su input/select, y
   text-transform/letter-spacing se heredan adentro de los controles: sin
   este reset, lo que el usuario escribe en el buscador de Planning o de
   Reservas se mostraria en mayusculas y con las letras separadas. El rotulo
   en mayusculas es solo para el texto del label. */
.compact-field input,
.compact-field select,
.compact-field textarea {
  text-transform: none;
  letter-spacing: normal;
  font-size: 13px;
  font-weight: 400;
}

.compact-field select {
  min-height: 38px;
  width: 100%;
  min-width: 160px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  appearance: none;
  background:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%) calc(100% - 16px) 17px / 6px 6px no-repeat,
    linear-gradient(135deg, var(--muted) 50%, transparent 50%) calc(100% - 10px) 17px / 6px 6px no-repeat,
    var(--surface);
  padding: 0 30px 0 10px;
}

.compact-field input {
  min-height: 38px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  background: var(--surface);
  padding: 0 10px;
}

.reservation-search-summary:not(:empty) {
  margin: 0 0 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent-strong);
  padding: 10px 12px;
  font-size: 13px;
}

/* Destaca el bloque al que salto una seleccion del buscador de Planning.
   outline y no box-shadow: .reservation-block tiene overflow:hidden (para
   recortar el nombre si es largo), y un box-shadow puesto en el MISMO
   elemento que tiene overflow:hidden se recorta con el -- outline es el
   unico de los dos que un elemento nunca clippea sobre si mismo. */
/* El aviso del resumen de la reserva cuando hay una transferencia esperando.
   Mismo amarillo que el bloque del planning y que el chip de la fila del pago:
   los tres son la misma cosa vista en tres lugares. */
/* Plata cargada que todavia no cuenta como cobrada. Subio al bloque de avisos
   de arriba, asi que toma la forma de los otros banners -- pero conserva el
   AMARILLO, que es el mismo de las otras dos vistas de lo mismo (el bloque del
   planning y el chip al lado del importe). Amarillo y no rojo a pedido
   explicito: el huesped ya pago, lo que falta es que el hotel mire el banco. */
.balance-banner.en-revision {
  background: color-mix(in srgb, var(--yellow) 16%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--yellow) 52%, var(--line));
  color: var(--tint-yellow-ink);
}

.balance-banner.en-revision span {
  color: var(--tint-yellow-ink);
}

/* El cartelito al lado del importe de un pago que no es plata confirmada.
   Solo aparece en los que esperan revision o no entraron: en un pago normal
   no se dibuja nada. */
.pago-estado {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  vertical-align: 1px;
}
.pago-estado.en_revision {
  background: color-mix(in srgb, var(--yellow) 24%, var(--surface));
  color: var(--tint-yellow-ink);
}
.pago-estado.rechazado {
  background: color-mix(in srgb, var(--red) 13%, var(--surface));
  color: var(--tint-red-ink);
}

/* --- La bandeja de transferencias del panel de Inicio -------------------
   Una fila por transferencia esperando: de cuanto, de quien, y los dos
   botones. El importe va primero y grande porque es el dato con el que se
   busca en el homebanking. */
.transferencia {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.transferencia:last-child { border-bottom: none; }

.transferencia-datos { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.transferencia-datos strong { font-size: 15.5px; font-variant-numeric: tabular-nums; }
.transferencia-datos span { font-size: 13px; color: var(--ink); }
.transferencia-datos small { font-size: 11.5px; color: var(--muted); }

.transferencia-acciones {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
/* En el telefono los dos botones pasan a ocupar el ancho: son la accion de la
   pantalla y tienen que poder tocarse con el pulgar sin apuntar. */
@media (max-width: 620px) {
  .transferencia-acciones { width: 100%; }
  .transferencia-acciones .ghost-button,
  .transferencia-acciones .primary-button { flex: 1 1 0; }
}

.reservation-block.search-target {
  outline-offset: 2px;
  animation: planning-search-pulse 1.8s ease-in-out;
}

@keyframes planning-search-pulse {
  0%,
  100% {
    outline: 3px solid transparent;
  }
  20%,
  55%,
  85% {
    outline: 3px solid var(--focus-outline);
  }
}

.reservation-form {
  grid-template-columns: repeat(5, minmax(130px, 1fr));
}

/* Cebra por fila, MUY tenue. Con --surface-muted pleno (lo que habia antes)
   las bandas grises horizontales dominaban la grilla y le daban aspecto de
   planilla de calculo; ademas le ganaban por especificidad a las marcas de
   columna (hoy / fin de semana), que en un planning de hotel son mas
   importantes: se lee "que pasa el 15" mucho mas seguido que "que hace la
   habitacion 210" -- y para seguir una fila ya esta la columna fija de la
   izquierda. Ahora la cebra apenas insinua la fila y deja pasar el color de
   la columna. */
/* La cebra CEDE ante las columnas marcadas (:not(.today):not(.weekend)) en
   vez de competirle por especificidad. Es la unica forma limpia: la regla
   de cebra tiene especificidad (0,4,0) y le ganaba en silencio a las marcas
   de columna -- se veian en el CSS pero no en pantalla. Verificado midiendo
   el backgroundColor computado, que daba el MISMO valor para hoy, finde y
   un dia normal.
   Y la banda en si baja de --surface-muted pleno a un 1.6%: con el valor
   anterior las franjas horizontales dominaban la grilla y le daban aspecto
   de planilla de calculo. En un planning de hotel la columna importa mas
   que la fila (se lee "que pasa el 15" mucho mas seguido que "que hace la
   210"), y para seguir una fila ya esta la columna fija de la izquierda. */
.planning-row:nth-child(even) .cell:not(.room):not(.today):not(.weekend) {
  background: color-mix(in srgb, var(--ink) 1.6%, var(--surface));
}

.planning-row:nth-child(even) .cell.weekend:not(.today) {
  background: color-mix(in srgb, var(--ink) 5.5%, var(--surface));
}

.cell.header {
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
}

.cell.room {
  background: var(--surface-muted);
}

/* Canto superior iluminado + sombra: el bloque se lee como una pieza
   APOYADA sobre la grilla, no como una celda pintada. Es la diferencia
   entre un planning y una planilla con colores de fondo. */
.reservation-block {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 1px 3px rgba(22, 20, 46, 0.18);
}

.reservation-list {
  gap: 8px;
}

.reservation-row {
  grid-template-columns: minmax(180px, 1.25fr) minmax(150px, 0.8fr) minmax(140px, 0.8fr) auto;
  /* `transition: 150ms ease` sin lista anima TODO, incluido el layout de la
     grilla. Se nombran las propiedades que de verdad cambian. */
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
  position: relative;
  overflow: hidden;
}

/* --- Barra de estado a la izquierda de cada fila -----------------------
   El estado vivia SOLO en el badge del extremo derecho: para saber como
   estaba una reserva habia que recorrer la fila entera con la vista, y para
   comparar 30 reservas habia que leer 30 badges. La barra de color permite
   escanear la columna de estados de un vistazo, sin leer.
   No es la unica señal: el badge sigue diciendo el estado con palabras, asi
   que no depende de distinguir colores. */
.reservation-row::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--gray);
}

.reservation-row.estado-en-curso::before { background: var(--blue); }
.reservation-row.estado-confirmada::before { background: var(--green); }
.reservation-row.estado-pendiente::before { background: var(--orange); }
.reservation-row.estado-vencida::before { background: var(--red); }
.reservation-row.estado-finalizada::before { background: var(--gray); }
.reservation-row.estado-cancelada::before { background: var(--gray); }

@media (hover: hover) and (pointer: fine) {
  .reservation-row:hover {
    border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
    transform: translateY(-1px);
    box-shadow: var(--shadow-overlay);
  }
}

/* Con el detalle abierto, la lista comparte ancho con el panel -- antes cada
   fila igual mostraba las 6 lineas de la vista completa (nombre+habitacion,
   fechas+noches, total+saldo) apiladas en una sola columna angosta, dando
   filas mucho mas altas que las original 64px de min-height (el numero solo
   marca un piso, no un techo). Se reduce a las 2 lineas que importan para
   ubicar una reserva de un vistazo (nombre+fecha, estado) -- el resto
   (habitacion, noches, canal, total, saldo) ya se ve de entrada al abrir el
   detalle con un click, no hace falta duplicarlo en la lista comprimida. */
.reservations-layout.detail-open .reservation-row {
  /* Mismo motivo que la version mobile (mas abajo en el archivo): "auto" sin
     techo dejaba que un status largo empujara la fila -- este es el layout
     compacto de escritorio cuando hay una reserva seleccionada, no solo
     mobile, asi que necesita la misma proteccion. */
  grid-template-columns: 1fr minmax(0, 92px);
  align-items: center;
  gap: 2px 8px;
  min-height: 0;
  padding: 8px 10px;
}

.reservations-layout.detail-open .reservation-row > div {
  min-width: 0;
}

.reservations-layout.detail-open .reservation-row strong {
  font-size: 13px;
  line-height: 1.2;
}

.reservations-layout.detail-open .reservation-row span {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.reservations-layout.detail-open .reservation-row > div:first-child span,
.reservations-layout.detail-open .reservation-row > div:nth-child(2) span {
  display: none;
}

.reservations-layout.detail-open .reservation-row > div:nth-child(2) {
  grid-column: 1;
  grid-row: 2;
}

.reservations-layout.detail-open .reservation-row > div:nth-child(3) {
  display: none;
}

.reservations-layout.detail-open .reservation-row .reservation-row-status {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  max-width: 100%;
  min-width: 0;
}

.reservations-layout.detail-open .reservation-row .pill {
  display: inline-block;
  max-width: 100%;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-height: 22px;
  font-size: 11px;
  padding: 0 7px;
}

/* La cabecera de la lista en la columna angosta: titulo arriba y los
   filtros debajo, a lo ancho -- el buscador en su propio renglon y los dos
   selectores compartiendo el de abajo. Al lado del titulo (como en la vista
   sin detalle) no entran: .search-field y .compact-field piden 280 y 160px
   de minimo y la columna mide 264-340. */
.reservations-layout.detail-open > .panel:not(.reservation-detail) > .panel-header {
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  margin-bottom: 10px;
}

.reservations-layout.detail-open > .panel:not(.reservation-detail) .toolbar-group {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.reservations-layout.detail-open > .panel:not(.reservation-detail) .toolbar-group .compact-field,
.reservations-layout.detail-open > .panel:not(.reservation-detail) .toolbar-group .compact-field select {
  min-width: 0;
}

.reservations-layout.detail-open > .panel:not(.reservation-detail) .toolbar-group .search-field {
  grid-column: 1 / -1;
}

/* En la columna mas angosta (264px, pantallas de ~1000-1100) cada selector
   quedaba en 113px y "Cualquier fecha" se cortaba: ahi van uno debajo del
   otro. Container query sobre la lista y no media query: lo que decide es el
   ancho de la columna. */
.reservations-layout.detail-open > .panel:not(.reservation-detail) {
  container-type: inline-size;
  container-name: lista-reservas;
}

@container lista-reservas (max-width: 290px) {
  .reservations-layout.detail-open > .panel:not(.reservation-detail) .toolbar-group {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Codigo y nombre en dos renglones como mucho: un nombre largo
   ("Maria Fernanda Gonzalez Etcheverry") ocupaba cuatro y cada fila media el
   doble que las vecinas. El nombre entero esta en el detalle de al lado. */
.reservations-layout.detail-open .reservation-row > div:first-child strong {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.reservation-detail .panel-header {
  align-items: flex-start;
  gap: 10px;
  /* Tiene que coincidir con el padding real de .panel (18px, ver seccion
     "UI polish pass" mas arriba en el archivo). */
  padding: 18px 18px 10px;
  border-bottom: 1px solid var(--line);
  border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0;
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--surface);
}

.panel-header-title {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
}

.panel-header-title .icon-button {
  flex-shrink: 0;
  font-size: 16px;
  line-height: 1;
}

/* Sin margin-top: la separacion la pone el gap de .detail-sections, igual que
   para el resto de las secciones. Con los dos, esta quedaba a 24px y las otras
   a 20px -- una diferencia chica pero de las que hacen sentir "torcida" una
   pantalla sin saber por que. */
.reservation-detail .detail-danger-zone {
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  display: flex;
  justify-content: flex-end;
}

.reservation-detail .panel-header h2 {
  font-size: 20px;
  line-height: 1.15;
}

.reservation-detail .detail-summary {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  padding: 10px;
}

.reservation-detail .detail-summary div {
  min-width: 0;
}

.reservation-detail .detail-summary strong {
  font-size: 12px;
}

.reservation-detail .detail-summary span {
  display: block;
  font-size: 12px;
  line-height: 1.3;
}

/* UNA sola columna. Esta regla daba dos, de cuando el <form> ERA la grilla de
   campos; desde que adentro va el maestro-detalle (.detalle-shell) su unico
   hijo caia en la primera columna y la segunda quedaba VACIA -- el formulario
   entero ocupaba la mitad del panel y al lado no habia nada. Los campos
   siguen yendo de a dos, pero eso lo resuelve .detail-block-fields, que es
   quien los contiene. */
.reservation-detail .detail-form {
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

.reservation-detail .detail-form label {
  min-width: 0;
  font-size: 12px;
}

.reservation-detail .detail-form input,
.reservation-detail .detail-form select {
  min-height: 36px;
}

/* `grid-column: 1 / -1` sirve dentro de .detail-block-fields, que es la grilla
   de dos columnas que quedo. Sobre el <form> ya no hace nada (tiene una sola
   columna) pero tampoco molesta, y .detail-actions si lo sigue necesitando. */
.reservation-detail .detail-block-fields > textarea,
.reservation-detail .detail-block-fields > .wide,
.reservation-detail .detail-actions,
.reservation-detail .detail-form .detail-block {
  grid-column: 1 / -1;
}

/* `auto-fit` y no dos columnas fijas: el detalle cambia mucho de ancho (la
   lista de reservas abierta o cerrada, y una pantalla de 1920 contra una de
   1280). Con dos fijas, en un panel ancho cada campo se estiraba hasta
   quedar un "Huespedes" de 400px al lado de un numero de dos digitos. Asi el
   espacio de mas se gasta en MAS columnas, que es lo que un formulario de
   carga necesita. */
.detail-block-fields {
  display: grid;
  /* Tope de CUATRO columnas: el minimo de cada una es el mayor entre 210px y
     un cuarto del ancho (menos los tres gaps), asi nunca entra una quinta.
     `auto-fit` sin tope seguia sumando columnas mientras hubiera lugar: en
     una pantalla ancha el formulario llegaba a siete y los campos de una
     misma reserva quedaban desparramados en una tira horizontal.
     Antes el tope era un max-width de 820px (tres columnas), de cuando la
     lista se llevaba la mitad de la pantalla. Desde que la lista es una
     columna angosta (05/10) ese tope dejaba un tercio del detalle VACIO a la
     derecha de los campos: a 1366, 820px de campos en un panel de 1090. */
  grid-template-columns: repeat(auto-fit, minmax(max(210px, calc((100% - 36px) / 4)), 1fr));
  gap: 10px 12px;
  align-items: start;
}

/* .detail-block-readonly quedo sin uso: los datos que no se editan (noches,
   canal, huespedes, habitaciones) salieron de adentro de "Estadia y estado" y
   ahora viven en su propia franja arriba de todo (.detail-hechos). Se borra la
   regla para que no quede una clase muerta invitando a reusarla. */

.detail-dl-cols {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.detail-group-rooms {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}

.detail-group-room-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.detail-group-room-tag {
  flex: 0 0 auto;
  min-width: 36px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
}

.detail-group-room-select {
  flex: 1 1 auto;
}

/* El precio de cada habitacion de una reserva combinada comparte la fila con
   la etiqueta, igual que el selector de arriba. `min-width: 0` para que pueda
   achicarse por debajo de su contenido: sin eso un importe largo estira la
   fila y se sale del panel. */
.detail-group-room-row .detail-precio {
  flex: 1 1 auto;
  min-width: 0;
}

/* Cuantas personas duermen en esa habitacion (combinada), al lado de su
   selector. Ancho fijo y chico: es un numero de una cifra, y el selector es el
   que tiene que llevarse el espacio. */
.detail-group-personas {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 400;
}

.reservation-detail .detail-form .detail-group-personas input {
  width: 3.6em;
  padding: 0 6px;
  text-align: center;
}

/* El reparto al lado del total, en los hechos del detalle y en el popover:
   es un dato secundario del mismo numero. */
.detail-hecho-reparto,
.popover-reparto {
  color: var(--muted);
  font-weight: 400;
}

.detail-hint {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-weight: 400;
}

.reservation-detail .detail-form textarea {
  min-height: 68px;
}

.detail-summary {
  gap: 7px;
}

.balance-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 4px;
}

.balance-banner strong {
  display: block;
  font-size: 14px;
}

.balance-banner span {
  display: block;
  font-size: 12px;
  margin-top: 2px;
}

/* --tint-orange-ink y no --orange: medido, el naranja pleno sobre este fondo
   (12% de naranja) da 2,24:1, menos de la mitad del 4,5 que pide AA. Es la
   misma regla que el resto del archivo ya documenta -- --orange esta pensado
   como FONDO con texto blanco encima, no como color de texto. */
.balance-banner.due {
  background: color-mix(in srgb, var(--orange) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--orange) 40%, var(--line));
  color: var(--tint-orange-ink);
}

.balance-banner.due span {
  color: var(--tint-orange-ink);
}

/* Mismo caso que .balance-banner.due: --tint-green-ink como texto, no --green. */
.balance-banner.paid {
  background: color-mix(in srgb, var(--green) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--green) 40%, var(--line));
  color: var(--tint-green-ink);
}

.balance-banner.paid span {
  color: var(--tint-green-ink);
}

/* Pagada de mas. Rojo y no naranja: el naranja ya es "falta cobrar", que es lo
   normal en una reserva; esto es casi siempre un pago cargado dos veces y pide
   mas atencion, no menos.
   --tint-red-ink como color de TEXTO (no --red pelado, que esta pensado para
   usarse de fondo con texto blanco encima y sobre este fondo tenue no llega al
   contraste minimo). */
.balance-banner.over {
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--red) 40%, var(--line));
  color: var(--tint-red-ink);
}

.balance-banner.over span {
  color: var(--tint-red-ink);
}

.balance-banner-amount {
  font-size: 20px;
  font-weight: 700;
  white-space: nowrap;
}

.balance-banner-amount.ok {
  font-size: 22px;
}

/* El huesped tiene en la bandeja un total que ya no es el de su reserva (ver
   avisoDeTotalViejoHtml). Agua y no naranja ni rojo: es un aviso INFORMATIVO
   (regla de colores), no un estado de la plata -- el naranja de arriba ya dice
   lo que falta cobrar. Titulo en --accent-strong (6.3 sobre el Agua en claro,
   5.5 en oscuro) y la explicacion en --ink, como los otros avisos. */
.balance-banner.total-viejo {
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent-strong) 30%, var(--line));
  color: var(--accent-strong);
}

.balance-banner.total-viejo span {
  color: var(--ink);
}

/* Los botones de un aviso (vencida, promo sin el pago, total viejo) NO son el
   pie del formulario: sin el separador ni la grilla de 200px que les pone
   `.reservation-detail .detail-actions`. Con esa regla, en un telefono el texto
   del aviso quedaba en una columna de tres palabras por renglon al lado de un
   boton de media caja. Ahora, si no entran juntos, el boton baja debajo del
   texto y el texto usa el ancho entero. */
.reservation-detail .balance-banner .detail-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  flex: 0 1 auto;
  padding-top: 0;
  border-top: 0;
}

.balance-banner:has(> .detail-actions) {
  flex-wrap: wrap;
}

.balance-banner:has(> .detail-actions) > div:first-child {
  flex: 1 1 260px;
  min-width: 0;
}

/* "Total de la reserva" en Estadia y estado, debajo del precio del
   alojamiento (refrescarTotalDelDetalle). Caja tenue y no un aviso: es un dato,
   no algo que haya que hacer. */
.detail-total-reserva {
  grid-column: 1 / -1;
  display: grid;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}

.detail-total-cabecera {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  color: var(--muted);
}

.detail-total-cabecera strong {
  font-size: 17px;
  color: var(--ink);
  white-space: nowrap;
}

/* Con cambios sin guardar el total se marca con el borde punteado: lo que
   esta arriba (y en los mails) sigue siendo lo guardado hasta que se guarde. */
.detail-total-reserva.sin-guardar {
  border-style: dashed;
  border-color: var(--accent-strong);
}

.desglose-del-total {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 4px;
  font-size: 12.5px;
}

.desglose-del-total li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: var(--ink);
}

.desglose-del-total li > span:last-child {
  white-space: nowrap;
}

.desglose-del-total small {
  color: var(--muted);
  font-size: 11.5px;
}

.detail-total-reserva .link-button {
  justify-self: start;
  font-size: 12px;
}

/* La composicion debajo del Total en Pagos y facturas. */
.detail-dl-nota {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 11.5px;
  overflow-wrap: anywhere;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

/* UN solo estilo de bloque para toda la ficha. Antes habia tres definiciones
   casi iguales (.detail-block, .detail-extras, .detail-payments), cada una con
   su propio h3 -- y ya habian divergido: 11px contra 12px, letter-spacing
   0.03em contra 0.02em. Se veian "parecidas pero no iguales", que es
   exactamente lo que hace sentir desprolija una pantalla. */
.detail-block {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  background: var(--surface);
  min-width: 0;
  /* Grid con gap y NO margenes por hijo: el espaciado interno de todos los
     bloques sale de un solo numero. Con margenes, cada bloque terminaba con su
     propio ritmo (era el caso: 8px en unos, 10px en otros). */
  display: grid;
  gap: 12px;
  align-content: start;
}

/* Titulo de seccion REAL, no un rotulo. Antes era 11px gris en mayusculas: se
   leia como una etiqueta de campo, no como el encabezado del bloque, asi que
   cinco bloques apilados parecian una sola masa. Ahora: tamaño de titulo, peso
   700, color de texto normal y una linea que lo separa del contenido. */
.detail-block > h3 {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--ink);
  /* Sin margin-bottom: el espacio lo pone el gap del bloque (ver .detail-block).
     Con los dos, el titulo quedaba al doble de distancia que el resto. */
  margin: 0;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

/* --accent-strong y no --accent: --accent (#0b7a91) es el turquesa oscuro
   pensado para FONDOS, y como trazo sobre la superficie oscura del modo oscuro
   queda en 2,82 (medido). --accent-strong es justamente el token que el modo oscuro
   redefine para usar el acento en primer plano, como ya documenta el bloque
   de tokens mas arriba. */
.detail-block-icon {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--accent-strong);
}

.detail-dl {
  display: grid;
  gap: 8px;
}

.detail-dl > div {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.detail-dl dt {
  color: var(--muted);
  font-size: 11px;
}

.detail-dl dd {
  margin: 0;
  font-size: 13px;
  text-align: left;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* El saldo pendiente es EL dato accionable de la lista de reservas: es
   plata que el hotel todavia no cobro. Antes era texto rojo del mismo
   tamaño que "pagado $X", perdido en una linea gris. Ahora es una pastilla
   con fondo propio, asi que la pregunta "a quien le falta pagar" se
   responde barriendo la columna con la vista en vez de leyendo importe por
   importe. */
.balance-due {
  display: inline-block;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--red) 13%, transparent);
  color: var(--tint-red-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.reservation-row .balance-due {
  font-weight: 700;
}

/* Plata cargada de MAS. Comparte forma con .balance-due (es el mismo tipo de
   dato: un importe que pide atencion) pero no color: deber plata es normal,
   tener de mas casi siempre es un pago cargado dos veces. */
.balance-over {
  display: inline-block;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--red) 16%, transparent);
  color: var(--tint-red-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.detail-form-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--muted);
  margin: 6px 0 -2px;
}

@media (max-width: 900px) {
  .detail-grid {
    grid-template-columns: 1fr;
  }
}

/* .detail-extras ya no existe como estilo propio: Extras pasó a ser una
   <section class="detail-block"> como el resto (antes era un <div> con su
   propio borde y su propio h3, que es de donde salia parte de la sensacion de
   desprolijo). Solo queda la lista, que si tiene layout propio. */
.detail-extras-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.walkin-extras-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.walkin-extra-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.walkin-extra-item:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.walkin-extra-item input {
  width: auto;
  min-height: auto;
  margin: 0;
}

/* La lista de pagos de la categoria "Pagos y facturas" del detalle. */
.detail-payments-list {
  display: grid;
  gap: 8px;
}

/* Colgado de la LISTA, que dibuja el propio template junto a las filas. Era
   `.detail-payments .payment-row`, colgado de la seccion que envolvia los
   pagos cuando el detalle era una pila: al pasar a maestro-detalle esa
   seccion desaparecio y la regla quedo muerta sin que nada lo avisara (las
   filas volvieron a los 11px de la regla general de .payment-row). */
.detail-payments-list .payment-row {
  padding: 8px;
}

.extra-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--accent-soft);
  border-radius: var(--radius-pill);
  padding: 4px 8px;
  font-size: 12px;
  color: var(--ink);
  border: 1px solid transparent;
}

/* --- Consumos de la cafeteria cargados a la habitacion -------------------
   Van en la seccion de Extras porque para el huesped son eso: un cargo mas
   sobre la reserva. Pero NO son un extra de tarifas -- se cargan desde la
   Cafeteria y desde aca no se editan ni se quitan (para eso esta anular el
   pedido, que ademas deshace la plata en la caja). Por eso su chip no tiene
   la cruz de quitar y usa el verde de la plata en vez del acento del PMS. */
.detail-consumos {
  width: 100%;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

.extra-chip.consumos-chip {
  background: color-mix(in srgb, var(--green) 13%, var(--surface));
  color: var(--tint-green-ink);
  font-weight: 650;
  cursor: default;
}

.detail-consumos-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.detail-consumo {
  padding: 7px 9px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

.detail-consumo-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 12px;
  color: var(--muted);
}

.detail-consumo-head strong {
  color: var(--ink);
  font-size: 12.5px;
}

/* El importe se va a la derecha y con cifras de ancho fijo: varios pedidos
   uno debajo del otro se comparan de un vistazo solo si los numeros alinean. */
.detail-consumo-monto {
  margin-left: auto;
  color: var(--ink);
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.detail-consumo-items {
  list-style: none;
  margin: 5px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}

.detail-consumo-items li {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.detail-consumo-items li span:last-child {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.detail-consumo-items small {
  color: var(--muted);
}

.detail-consumo-parcial {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--muted);
}

/* Extra recien tildado en el detalle de reserva, todavia sin presionar
   "Guardar cambios" -- borde punteado para que se note que es un borrador,
   mismo color de fondo que el resto para no verse "roto". */
.extra-chip.pending {
  border: 1px dashed var(--accent);
}

.extra-chip button {
  border: none;
  background: transparent;
  color: var(--muted);
  width: 16px;
  height: 16px;
  min-height: 16px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  font-size: 12px;
  padding: 0;
}

.extra-chip button:hover {
  background: rgba(217, 72, 15, 0.12);
  color: var(--tint-red-ink);
}

.extra-chip.add-extra,
.extra-chip.inhouse-add-extra {
  border: 1px dashed var(--line);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-weight: 700;
}

.extra-chip.add-extra:hover,
.extra-chip.inhouse-add-extra:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
}

.detail-form-title {
  grid-column: 1 / -1;
}

.toolbar-group {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.toolbar-divider {
  width: 1px;
  align-self: stretch;
  background: var(--line);
}

/* Sesion real (reemplaza al viejo selector de rol simulado) — chip oscuro y
   compacto a la derecha del navbar, mismo contraste de antes pero mas chico
   para no restarle alto al navbar. */
.session-box {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 5px 6px 5px 10px;
  border-radius: 8px;
  background: #16142e;
  border: 1px solid #3a3566;
  flex: 0 0 auto;
  margin-left: auto;
}

/* Dentro del dropdown de Ajustes el session-box ya no es un item mas de una
   fila horizontal (el navbar) sino el pie de una columna vertical — ocupa
   todo el ancho disponible en vez de flotar pegado a la derecha. */
.topnav-dropdown .session-box {
  width: 100%;
  margin-left: 0;
  margin-top: 2px;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 8px;
}

.topnav-dropdown .personalization-box {
  flex: 1 1 100%;
  justify-content: space-between;
}

/* Bloque de notificaciones push dentro del chip de sesion (desplegable de
   Ajustes). Ocupa el ancho completo para que la aclaracion de abajo no quede
   apretada contra el boton. */
.push-box {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.push-box .ghost-button {
  width: 100%;
}

/* Caja del codigo de autorizacion, adentro del chip de sesion. Como el chip
   tiene fondo oscuro propio en los dos temas, los colores de aca son literales
   claro-sobre-oscuro y no var(--ink)/var(--surface), igual que sus vecinos. */
.codigo-box {
  flex: 1 1 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border-radius: 8px;
  background: #2a2650;
  border: 1px solid #3a3566;
}

.codigo-encabezado {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  color: #c9c4e8;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* El reloj cuenta hacia atras y cambia de ancho en cada tick: con cifras de
   ancho variable, el numero de al lado se movia solo. */
.codigo-reloj {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  text-transform: none;
}

/* Se dicta por telefono, asi que se lee en voz alta de un vistazo: cuerpo
   grande, cifras de ancho fijo y separadas para no confundir un 6 con un 8 a
   la primera. Es seleccionable a proposito, para poder copiarlo y mandarlo por
   mensaje en vez de dictarlo. */
.codigo-numero {
  color: #ffffff;
  font-size: 25px;
  font-weight: 700;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
  user-select: all;
}


/* El chip de sesion es un cuadro oscuro fijo en los DOS temas, asi que este
   texto usa el mismo color claro que sus vecinos (.session-box-info span) en
   vez de var(--muted), que en tema claro es gris oscuro sobre casi negro
   (~2.6:1, por debajo del minimo legible). */
.push-hint {
  margin: 0;
  font-size: 12px;
  line-height: 1.35;
  color: #c9c4e8;
}

/* Vacio casi siempre (ver renderPushToggle). Sin esto seguiria contando como
   hijo flex de .push-box y sumaria el gap de 4px por nada. */
.push-hint:empty {
  display: none;
}

/* Panel de Configuracion (fondo claro normal, a diferencia del chip de
   sesion de arriba) -- estado siempre visible, sin depender de que el
   usuario tenga el desplegable de Ajustes abierto. */
.push-status {
  margin: 0 0 12px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

/* Se muestra SOLO cuando Notification.permission === "denied": el navegador
   no vuelve a mostrar su propio cartel de permiso en ese estado (resuelve
   solo, en silencio), asi que sin esto tocar "Activar" no tiene ningun
   efecto visible. Colores de advertencia (mismos --orange/--red que ya usa
   el resto del PMS) para que se note que hace falta una accion manual. */
.push-blocked-help {
  margin-top: 12px;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--orange);
  background: color-mix(in srgb, var(--orange) 12%, var(--surface));
}

.push-blocked-help p {
  margin: 0 0 8px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
}

.push-blocked-help ol {
  margin: 0;
  padding-left: 20px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink);
}

.topnav-dropdown-divider {
  height: 1px;
  background: var(--line);
  margin: 4px 4px 6px;
}

/* Boton "+ Ingreso por mostrador" reubicado donde antes vivia el chip de
   sesion — mismo empuje a la derecha del navbar. */
.topnav-cta {
  margin-left: auto;
  flex: 0 0 auto;
}

.session-box-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.session-box-info strong {
  font-size: 12px;
  color: #ffffff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.session-box-info span {
  font-size: 10px;
  color: #c9c4e8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.session-box .ghost-button {
  flex: 0 0 auto;
  padding: 4px 8px;
  font-size: 11px;
  min-height: 26px;
  border-color: rgba(255, 255, 255, 0.18);
  color: #c9c4e8;
  background: transparent;
}

.session-box .ghost-button:hover {
  border-color: #3fd0e6;
  color: white;
}

/* "Cerrar sesion" vive adentro del chip oscuro, que tiene fondo propio y no
   sigue el tema de la pagina (ver el comentario de abajo). Por eso no le
   sirve --salida-ink, que es tinta oscura sobre fondo claro: medido sobre la
   Tinta (#16142e) del chip da 3.22. Necesita su propio rojo claro-sobre-oscuro,
   que ademas es el mismo en los dos temas porque el chip tampoco cambia.
   Medido sobre el fondo real del chip: 8.61 (el gris de los otros botones del
   chip da 10.69, sigue muy por encima del minimo). */
.session-box .ghost-button.salida {
  color: #e8a396;
  border-color: rgba(232, 163, 150, 0.34);
}

.session-box .ghost-button.salida:hover {
  color: #f6c4ba;
  border-color: rgba(232, 163, 150, 0.6);
  background: rgba(232, 163, 150, 0.12);
}

/* El chip de sesion es un cuadro oscuro fijo (background propio arriba, no
   sigue el tema de la pagina) -- por eso estos controles usan su propia
   paleta clara-sobre-oscuro en vez de var(--ink)/var(--surface), que
   asumirian un fondo claro. */
.personalization-box {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.theme-toggle {
  display: flex;
  gap: 2px;
  background: #2a2650;
  border-radius: 7px;
  padding: 2px;
}

.theme-toggle-option {
  border: none;
  background: transparent;
  color: #c9c4e8;
  font-size: 10px;
  font-weight: 700;
  padding: 4px 7px;
  border-radius: 5px;
  cursor: pointer;
}

.theme-toggle-option.active {
  background: var(--accent);
  color: var(--on-accent);
}

/* Tarifas/Usuarios no tenian NINGUN ajuste para pantallas angostas -- las
   filas de grid fijo (extra-row, users-add-form, user-row) se aprietan mal
   con varias columnas de ancho fijo, y la fila de precio+promo+% de Tarifas
   queda muy justa. Se resuelve apilando en columna y dejando scroll
   horizontal como ultimo recurso en la tabla de precios, nunca contenido
   cortado o inutilizable. */
@media (max-width: 640px) {
  /* El "%" y el descuento bajan debajo del precio promo antes de que la
     tabla tenga que scrollear (el scroll lo da .season-price-scroll). */
  .season-promo-tier {
    flex-wrap: wrap;
    row-gap: 6px;
  }

  .extra-row,
  .users-add-form {
    grid-template-columns: 1fr;
  }

  .user-row {
    grid-template-columns: 1fr;
    justify-items: start;
  }

  .user-row-identity {
    flex-wrap: wrap;
  }
}

/* Pantalla de carga: visible por defecto en el HTML (antes de que corra JS),
   y reutilizada por bootIntoApp() mientras se hidrata el cache del backend --
   cualquier momento en que el PMS este "cargando" pasa por esto en vez de
   quedar en blanco. z-index por encima de .login-screen (100) porque tambien
   se muestra ENCIMA del formulario de PIN mientras se hidrata tras loguearse.
   Velo translucido + blur (no un color solido/de marca): asi aparecer y
   desaparecer es un cambio suave de opacidad, nunca un salto brusco de color
   contra lo que haya debajo (el propio PMS, o el login). */
.boot-loading-screen {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  background: var(--boot-veil-bg);
  backdrop-filter: blur(6px) saturate(1.1);
  -webkit-backdrop-filter: blur(6px) saturate(1.1);
  opacity: 1;
  visibility: visible;
  transition: opacity 0.28s ease, visibility 0s linear 0s;
}

.boot-loading-screen.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.22s ease, visibility 0s linear 0.22s;
}

.boot-loading-content {
  position: relative;
  display: grid;
  place-items: center;
}

/* Logo y anillo ocupan la MISMA celda de grid (se superponen centrados) sin
   necesitar posicionamiento absoluto a mano. */
.boot-loading-ring,
.boot-loading-logo-wrap {
  grid-area: 1 / 1;
}

/* El logo NUNCA rota -- es lo unico que tiene que respetar su forma real en
   todo momento. Lo que transmite "cargando" es el anillo de alrededor. */
.boot-loading-logo-wrap {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  filter: drop-shadow(0 2px 6px rgba(22, 20, 46, 0.2));
}

.boot-loading-logo-wrap .brand-logo-fallback,
.boot-loading-logo-wrap .brand-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Anillo con los dos turquesas de la marca (--accent-bright y --accent): un
   "track" tenue de fondo y dos lados con color, que girando da la sensacion
   clasica de spinner sin tocar el logo. Violeta no: la marca lo reserva para
   lo que hace la IA. */
.boot-loading-ring {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  border: 3px solid var(--line);
  border-top-color: var(--accent-bright);
  border-right-color: var(--accent);
  animation: boot-loading-spin 0.85s linear infinite;
}

@keyframes boot-loading-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .boot-loading-ring {
    animation-duration: 2s;
  }

  .topnav-collapsible {
    transition: none;
  }

  /* Movimiento reducido NO es cero movimiento: lo que molesta a quien tiene
     sensibilidad vestibular es el DESPLAZAMIENTO, no el cambio de opacidad.
     Asi que se sacan los translate/scale y se dejan los fundidos, que son
     los que explican que algo aparecio o desaparecio. Sin esa distincion,
     un panel que aparece de golpe se lee como un salto y se pierde
     informacion, que es peor que el movimiento. */
  /* .topnav-group como prefijo NO es decorativo: la regla base de
     .topnav-dropdown vive mas abajo en el archivo, asi que con la misma
     especificidad ganaba ella por orden y el panel seguia desplazandose con
     movimiento reducido activado. Verificado midiendo el transform real en
     el navegador, no leyendo el CSS. */
  .topnav-group .topnav-dropdown,
  .topnav-group .topnav-dropdown.open {
    transform: none;
  }

  .toast {
    transform: none;
  }

  .login-card,
  .pms-confirm-modal,
  .view.active {
    animation-name: reducedFadeIn;
  }

  /* El hundido al apretar se conserva: es feedback directo del gesto del
     usuario, no movimiento autonomo de la interfaz, y sacarlo dejaria los
     botones sin respuesta al tacto. Se hace mas sutil, nada mas. */
  .primary-button:active:not(:disabled),
  .ghost-button:active:not(:disabled),
  .icon-button:active:not(:disabled),
  .login-user-btn:active,
  .segment:active {
    transform: scale(0.99);
  }
}

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

/* Login de dos pasos: hotel -> usuario -> contraseña */
/* La pantalla de login es la PRIMERA impresion del producto -- lo que ve un
   hotel antes de haber usado nada. Fondo Tinta plano, el oscuro de la marca
   e igual en los dos temas: la marca reserva los degradados para el logo, asi
   que las luces radiales de teal que llevaba antes se sacaron. Lo que le saca
   el aspecto de vector plano es una trama de puntos de 1px al 4%.
   Todo es CSS: no suma una sola peticion de red al arranque. */
.login-screen {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: #16142e;
  padding: 20px;
  z-index: 100;
}

/* Trama de puntos. pointer-events:none para no comerse los clicks del
   formulario que esta encima. */
.login-screen::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.055) 1px, transparent 1px);
  background-size: 22px 22px;
  pointer-events: none;
}

.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 30px 28px;
  /* Unica tarjeta del PMS que sigue con sombra: flota sobre el fondo oscuro
     de la pantalla de login, no sobre el fondo de la app.
     El inset blanco del borde superior simula el canto iluminado de una
     placa fisica: es lo que hace que la tarjeta se lea apoyada SOBRE el
     fondo y no recortada y pegada encima. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 24px 60px rgba(0, 0, 0, 0.4),
    0 4px 12px rgba(0, 0, 0, 0.22);
  display: grid;
  gap: 14px;
  position: relative;
  /* Entra con un fundido corto y un desplazamiento minimo. Se ve UNA vez por
     turno, asi que puede darse el gusto -- pero sigue por debajo de 300ms:
     quien abre la recepcion a las 7 de la mañana no quiere esperar una
     animacion para escribir su PIN. */
  animation: loginCardIn 280ms var(--ease-out);
}

@keyframes loginCardIn {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.login-brand .marca-nombre { font-size: 20px; }
.login-brand .marca-firma { font-size: 12px; }

/* El titulo es lo unico que tiene que leerse de lejos en esta pantalla.
   Sube de tamaño y toma tracking negativo, que es lo que hace que un titulo
   se vea "compuesto" y no simplemente agrandado. */
.login-card h1 {
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: balance;
}

.login-hint {
  margin: -6px 0 4px;
  color: var(--muted);
  font-size: 13px;
}

.login-step {
  display: grid;
  gap: 10px;
}

.login-step label {
  display: grid;
  gap: 4px;
  font-size: 12px;
  font-weight: 700;
  color: var(--muted);
}

/* Los campos van HUNDIDOS en la tarjeta, no dibujados encima: un fondo
   apenas mas oscuro que la tarjeta mas una sombra interna de 1px arriba
   simulan un hueco donde se escribe. Es la contraparte del boton, que
   sobresale. Sin esto los inputs eran rectangulos con borde, iguales a los
   de cualquier formulario. */
.login-step input {
  min-height: 42px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--ink) 3%, var(--surface));
  box-shadow: inset 0 1px 2px rgba(22, 20, 46, 0.05);
  padding: 0 12px;
  font-size: 14px;
  color: var(--ink);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

/* Al enfocar, el campo se "enciende": pasa a fondo pleno (como si se
   levantara) y gana el halo del color de marca. */
.login-step input:focus {
  outline: none;
  border-color: var(--focus-outline);
  background: var(--surface);
  box-shadow:
    inset 0 1px 2px rgba(22, 20, 46, 0.03),
    0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

/* El ojo va DENTRO del campo, a la derecha. El campo le deja lugar con su
   padding para que el texto nunca pase por debajo del icono. */
.campo-contrasena {
  position: relative;
  display: block;
  min-width: 0;
}

.campo-contrasena input {
  padding-right: 46px;
}

.ver-contrasena {
  position: absolute;
  top: 50%;
  right: 3px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.ver-contrasena svg {
  width: 19px;
  height: 19px;
}

.ver-contrasena .ojo-tachado,
.ver-contrasena[aria-pressed="true"] .ojo-abierto {
  display: none;
}

.ver-contrasena[aria-pressed="true"] .ojo-tachado {
  display: block;
}

.ver-contrasena:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: -2px;
}

@media (hover: hover) and (pointer: fine) {
  .ver-contrasena:hover { color: var(--ink); }
}

/* Sin esto el campo del PIN se salia de la pantalla en un telefono: un input
   dentro de una grilla toma de minimo su ancho natural, y con 22px de letra y
   medio em de espaciado ese ancho superaba al de la tarjeta, que se estiraba
   con el. minmax(0, 1fr) deja que la columna se achique y el input se adapte. */
.login-card,
.login-step,
.login-step label {
  grid-template-columns: minmax(0, 1fr);
  min-width: 0;
}

.login-step input {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

.mp-estado {
  margin: 0 0 10px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 13px;
}

.mp-estado.alerta {
  color: var(--ink);
  background: color-mix(in srgb, var(--yellow) 22%, var(--surface));
}

.mp-estado.conectado {
  color: var(--ink);
  background: color-mix(in srgb, var(--green) 12%, var(--surface));
}

.pin-input {
  font-size: 22px !important;
  letter-spacing: 0.5em;
  /* El espaciado tambien se agrega DESPUES del ultimo punto, y eso corria los
     puntos a la izquierda del centro. La sangria compensa ese medio em. */
  text-indent: 0.5em;
  text-align: center;
  font-weight: 700;
  /* type="text" (no type="password") a proposito, para que el gestor de
     contraseñas del navegador no ofrezca autocompletar/sugerir una
     contraseña guardada en un campo que en realidad espera un PIN numerico
     — esto enmascara visualmente igual, sin depender de type="password". */
  -webkit-text-security: disc;
}

.login-back {
  justify-self: start;
  padding: 4px 8px;
  min-height: 28px;
  font-size: 12px;
}

/* Camino secundario ("sos dueño" / "tenes un codigo de activacion") -- se ve
   como un link de texto, no como un boton mas, para no competir visualmente
   con el submit primario (Continuar/Ingresar) que es la accion esperada por
   la inmensa mayoria de quien entra (personal de mostrador). */
/* Accion secundaria: la usa una minoria (los propietarios), asi que no puede
   competir con el boton principal. El subrayado permanente la hacia gritar
   como un link de 1995; ahora aparece solo al pasar por encima, y el peso
   baja de 700 a 500. Sigue siendo un boton de verdad y sigue siendo
   alcanzable por teclado. */
.login-switch-owner {
  justify-self: center;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  min-height: auto;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .login-switch-owner:hover {
    color: var(--accent-strong);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}

.login-error {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  color: var(--tint-red-ink);
}

.login-user-list {
  display: grid;
  gap: 8px;
}

.login-user-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 10px 12px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  text-align: left;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-press) var(--ease-out);
}

/* Elegir tu nombre para entrar al turno es la accion mas repetida de la
   pantalla de login: tiene que responder al toque como cualquier boton. */
.login-user-btn:active {
  transform: scale(0.98);
}

.login-user-btn strong {
  font-size: 13px;
  color: var(--ink);
}

.login-user-btn span {
  font-size: 11px;
  color: var(--muted);
}

.login-user-btn:hover {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
}

/* Actividad reciente (auditoria) en el detalle de reserva */
/* Actividad usa el .detail-block comun. Antes redefinia borde, radio, padding
   (10px contra 16px) y gap (8px contra 12px) por su cuenta, y como esta mas
   abajo en el archivo le ganaba por orden de cascada: quedaba mas apretada que
   las otras cuatro secciones sin que se viera por que. Ademas tenia un
   margin-top: 12px suelto que se sumaba al gap de .detail-sections y la dejaba
   a 32px de la anterior cuando el resto estaba a 20px. */

.audit-log-list {
  display: grid;
  gap: 6px;
}

.audit-log-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--surface-muted);
  font-size: 12px;
}

.audit-log-row strong {
  color: var(--accent-strong);
}

.audit-log-row span {
  color: var(--ink);
  flex: 1 1 auto;
}

.audit-log-row small {
  color: var(--muted);
  white-space: nowrap;
}

/* Movimiento hecho con el codigo de autorizacion: borde naranja y, debajo, PARA
   QUE se uso (audit_log.codigo_para). Naranja y no rojo: no es un error, es una
   autoridad del dueño que se ejercio y que tiene que poder ubicar de un vistazo. */
.audit-log-row.con-codigo {
  border-left: 3px solid var(--orange);
  background: color-mix(in srgb, var(--orange) 7%, var(--surface));
}

/* Movimiento que hizo el asistente ("Asistente IA" o "Asistente web", clase
   .por-el-asistente): borde violeta, el color que la marca reserva para la
   IA. Sin fondo: en una lista de 500 filas alcanza con el borde. En la
   actividad de la reserva el <strong> es el usuario y toma el violeta; en
   #actividad es la entidad y queda como esta. Nunca lleva .con-codigo. */
.audit-log-row.por-el-asistente {
  border-left: 3px solid var(--ai);
}
.audit-log-list:not(.activity-list) .audit-log-row.por-el-asistente strong {
  color: var(--ai-strong);
}
.audit-codigo {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin: 2px 0 0;
}
.audit-codigo-sello {
  flex: 0 0 auto;
  padding: 1px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--orange) 22%, var(--surface));
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}
.audit-log-row .audit-codigo-para {
  flex: 1 1 200px;
  color: var(--ink);
  font-weight: 600;
}

/* El movimiento al que llevo la notificacion "se uso tu codigo". */
.audit-log-row.enfocada {
  outline: 2px solid var(--focus-outline);
  outline-offset: 1px;
  animation: auditEnfocada 1.6s ease-out 1;
}
@keyframes auditEnfocada {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--accent) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .audit-log-row.enfocada { animation: none; }
}

.activity-list {
  max-height: 70vh;
  overflow-y: auto;
  padding-right: 4px;
}

@media (hover: hover) and (pointer: fine) {
  .reservation-block:hover {
    transform: translateY(-1px);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.5),
      0 4px 10px rgba(22, 20, 46, 0.2);
  }
}

/* Arrastrando, el bloque se LEVANTA: sube, crece apenas y proyecta sombra.
   Antes bajaba a opacity 0.55 y desaturaba, que se lee como "esto se
   deshabilito" -- exactamente lo contrario de "esto lo estas moviendo".
   La opacidad alta se conserva apenas para poder ver la celda de destino
   por debajo mientras se arrastra. */
.reservation-block.dragging {
  opacity: 0.92;
  transform: translateY(-2px) scale(1.02);
  box-shadow: 0 10px 22px rgba(22, 20, 46, 0.3);
  z-index: 5;
  cursor: grabbing;
}

.planning-row.drop-target .cell:not(.room) {
  background: var(--accent-soft);
}

.planning-row.drop-target .cell.room {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.planning-row.hover-row .cell {
  background: var(--accent-soft);
}

.planning-row.hover-row .cell.room {
  background: var(--accent-soft);
}

.cell.hover-col {
  background: var(--accent-soft);
}

.cell.header.hover-col {
  background: var(--accent-soft);
}

.cell.drag-select {
  /* Solo un lavado de fondo (misma intensidad que .hover-col) -- la
     seleccion en si la comunica .planning-drag-ghost, que flota ENCIMA de
     estas celdas. Sin outline por celda: bordear cada casillero por
     separado es lo que hacia que un arrastre de 3 noches se viera como 3
     casilleros sueltos en vez de UNA sola seleccion. */
  background: var(--accent-soft);
}

/* El "fantasma" de la reserva que se esta por crear -- aparece mientras se
   arrastra sobre el Planning (ver paintSelection en app.js) con la MISMA
   forma y formula de posicion que un .reservation-block real (los pixeles
   de left/width son deliberadamente identicos), para que se lea como una
   vista previa de la reserva y no como una seleccion de planilla.
   El borde punteado es lo que la distingue de una reserva real: "esto
   todavia no existe, es lo que vas a crear si soltas aca". */
.planning-drag-ghost {
  position: absolute;
  top: 4px;
  z-index: 3;
  min-height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--accent);
  /* Agua un paso mas hondo: el fantasma flota sobre la fila resaltada en
     Agua (.hover-row) y tiene que despegarse de ella sin salir de la
     familia. Texto --accent-strong encima: 5.0 en claro. En oscuro el
     turquesa claro sobre ese Agua da 3.9, asi que ahi el texto va en --ink
     (blanco, 7.2): ver la regla de abajo. */
  background: color-mix(in srgb, var(--accent) 18%, var(--accent-soft));
  color: var(--accent-strong);
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 6px;
  /* El fantasma no puede recibir eventos de mouse: bindPlanningDragSelect
     usa elementFromPoint para saber sobre que celda esta el cursor, y si el
     fantasma lo tapara, ese chequeo lo encontraria A EL en vez de la celda
     de abajo -- el arrastre se trabaria apenas el cursor pasara por encima
     de su propio fantasma. */
  pointer-events: none;
}

html[data-theme="dark"] .planning-drag-ghost {
  color: var(--ink);
}

.cell.header.today {
  background: var(--accent);
  color: var(--on-accent);
}

/* .rack-month/.rack-day tienen su propio color (--muted/--ink, pensado para
   el fondo normal de .cell.header) que le ganaba por especificidad al
   color de encima del relleno heredado de aca arriba -- la columna de HOY
   quedaba con el mes en gris apagado y el numero en el color de texto normal
   encima del turquesa solido. */
.cell.header.today .rack-month,
.cell.header.today .rack-day {
  color: var(--on-accent);
}

.reservation-popover {
  position: absolute;
  z-index: 20;
  width: min(348px, calc(100vw - 48px));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-float);
  padding: 12px;
  animation: popoverIn 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

.popover-header {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: flex-start;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

.popover-header h3 {
  margin: 0;
  font-size: 17px;
  line-height: 1.15;
}

.popover-header .icon-button {
  min-height: 30px;
  width: 30px;
}

.popover-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-top: 10px;
}

.popover-grid div,
.popover-contact {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
  padding: 8px;
}

.popover-grid span,
.popover-contact span {
  display: block;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
}

.popover-grid strong,
.popover-contact strong {
  display: block;
  margin-top: 3px;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.2;
}

.popover-contact {
  margin-top: 8px;
}

.popover-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  gap: 8px;
  margin-top: 10px;
}

@keyframes popoverIn {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

@media print {
  body {
    background: var(--surface);
  }

  .topnav,
  .topbar,
  .toolbar,
  .view:not(#listados),
  .mini-calendar,
  .toast {
    display: none !important;
  }

  .app-shell,
  .main {
    display: block;
    padding: 0;
  }

  #listados,
  #listados.view {
    display: block !important;
  }

  .panel {
    border: 0;
    box-shadow: none;
    padding: 0;
  }

  /* El papel va siempre en tinta negra sobre blanco: con el tema oscuro las
     tablas salian con letra blanca, o sea en blanco (FE-079). */
  html,
  html[data-theme="dark"] {
    --ink: #000;
    --muted: #333;
    --line: #999;
    --surface: #fff;
    --bg: #fff;
    --accent-strong: #000;
    --accent-soft: #fff;
  }

  body {
    background: #fff;
  }

  /* Las tablas anchas entran en la hoja: con su min-width y el overflow del
     panel, en A4 se imprimia una barra de scroll y se perdian las columnas
     de notas (FE-078). */
  #listing-output.print-area {
    overflow: visible;
  }

  .listing-table,
  .housekeeping-table {
    min-width: 0;
    width: 100%;
  }

  /* En el papel el servicio elegido se marca con el borde, no con el color,
     y los demas no se imprimen. */
  .service-tag:not(.active) {
    display: none;
  }

  .service-tag.active {
    border: 1.5px solid #000;
    background: none;
    color: #000;
  }
}

/* Aparte del bloque de mobile de abajo (que es por ANCHO) -- esta es por
   CAPACIDAD DE TOQUE (pointer:coarse), asi que tambien cubre una tablet en
   horizontal (~1024px, mas ancha que el corte de 980px de abajo) donde
   Safari/Chrome igual hacen zoom automatico al tocar un input chico. Pedido
   explicito: que nunca se haga zoom automatico al tocar un campo (buscador,
   PIN, lo que sea). Safari/Chrome mobile hacen ese zoom solo cuando el
   font-size efectivo del input es menor a 16px -- varios campos puntuales de
   la app (ej. .conversation-search-bar input a 12px) quedaban por debajo.
   !important a proposito: es una regla de accesibilidad/UX dura, no deberia
   poder pisarse sin querer agregando un font-size mas especifico en algun
   componente nuevo. El viewport meta (index.html) con
   maximum-scale=1/user-scalable=no cubre el resto (pellizcar para hacer zoom
   manual) en los navegadores que lo respetan -- Chrome/Firefox Android
   moderno lo ignoran por accesibilidad (limitacion de plataforma conocida,
   sin solucion puramente declarativa), pero el zoom-on-focus que motivo este
   pedido si depende 100% del font-size y ese caso queda cubierto siempre. */
@media (max-width: 980px), (pointer: coarse) {
  input,
  select,
  textarea {
    font-size: 16px !important;
  }
}

@media screen and (max-width: 980px) {
  /* "screen and" agregado el 16/08 (antes solo "max-width:980px", sin
     calificador): Chrome evalua max-width tambien contra el ancho de la
     HOJA IMPRESA, y una hoja portrait mide menos de 980px -- sin "screen",
     este bloque entero (incluida .main mas abajo, que reserva espacio para
     la barra de navegacion fija via --mobile-bottom-nav-space) competia con
     el "@media print { .main{padding:0} }" que ya existe mas arriba en el
     archivo, y por aparecer despues en el archivo le ganaba a igual
     especificidad -- dejaba ~72px de espacio en blanco al pie de cada
     hoja impresa (Listados). Mismo patron ya usado en otro bloque de este
     archivo (buscar "screen and (max-width: 900px)") -- faltaba aplicarlo
     aca y en los otros dos bloques "@media (max-width:980px)" del archivo,
     corregidos los 3 igual. */
  /* Pedido explicito (16/08): en mobile el contenido tiene que ocupar toda
     la pantalla, sin el margen gris + tarjeta redondeada/con sombra que lo
     hacia ver "encajonado" (bug real reportado con captura: un panel entero,
     ej. el detalle de una reserva, quedaba flotando con aire visible en los
     4 lados en vez de llegar a los bordes fisicos del telefono). Sin padding
     horizontal en .main, cada .panel pasa a ocupar el ancho completo -- ver
     mas abajo en este mismo bloque donde se le saca el border-radius/sombra
     a .panel/.metric (mantener esas esquinas redondeadas pegadas al borde
     recto de la pantalla, con cero margen alrededor, se veria roto/a medio
     cortar). El padding vertical interno de .panel (18px, sin tocar) sigue
     dando aire al contenido -- lo que desaparece es el marco gris ALREDEDOR
     de todo, no el respiro de lectura de adentro. */
  .main {
    padding-left: 0;
    padding-right: 0;
    /* Espacio para que el contenido no quede tapado atras de la barra fija
       de abajo (ver .topnav mas abajo en este mismo archivo) -- sin cambios,
       esto es espacio FUNCIONAL (evita que la barra tape contenido), no el
       marco cosmetico que se saca arriba. */
    padding-bottom: calc(14px + var(--mobile-bottom-nav-space));
    /* Mismo criterio que arriba: se saca el aire cosmetico fijo (14px) y
       queda solo el area segura real de un notch/isla dinamica (0 en la
       mayoria de los dispositivos) -- viewport-fit=cover (index.html) hace
       que env(safe-area-inset-top) resuelva a un valor real ahi. */
    padding-top: env(safe-area-inset-top);
  }

  /* .metric, .toolbar (redefinido mas abajo en el archivo con su propio
     fondo/borde), .planning-wrap (la grilla de Planning), .season-card
     (Tarifas), .conversation-list-col/.conversation-panel (Chat) y
     .cleaning-column (Limpieza) comparten el MISMO look de "tarjeta" que
     .panel (fondo blanco, borde, radio 10px, sombra) pero son clases
     propias, no heredan de .panel -- sin esto quedaban con el mismo "cuadro"
     que se pidio sacar, solo que en Planning/Tarifas/Chat/Limpieza en vez de
     donde se detecto originalmente (el detalle de una reserva). Se aplanan
     todas parejo y por el mismo motivo. El borde de 1px (var(--line)) se
     deja en todas: entre
     paneles apilados sigue funcionando como separador sutil (estilo "lista
     agrupada" nativa), y en los bordes izquierdo/derecho, pegado
     literalmente al borde fisico de la pantalla, es practicamente
     imperceptible -- no vuelve a verse como el "cuadro" que se pidio sacar. */
  .panel,
  .metric,
  .toolbar,
  .planning-wrap,
  .season-card,
  .conversation-list-col,
  .conversation-panel,
  .cleaning-column {
    border-radius: 0;
    box-shadow: none;
  }

  /* .topbar (titulo de pagina, solo visible en Inicio/Limpieza) queda
     directo adentro de .main sin pasar por .panel/.toolbar (que ya traen su
     propio padding) -- al sacarle el padding a .main (16/08, para que el
     contenido llegue a los bordes) el titulo quedaba literalmente pegado al
     borde fisico de la pantalla (0px, medido con captura real). Mismo valor
     que el padding interno de .panel (18px) a proposito, para que el titulo
     quede alineado con el contenido de la primera tarjeta debajo. */
  .topbar {
    flex-wrap: wrap;
    row-gap: 10px;
    padding: 16px 18px 0;
  }

  /* Mismo motivo que .topbar: .view-help-anchor (el "?" suelto de
     Configuracion, la unica vista sin .topbar ni .toolbar propio) tambien
     queda directo adentro de .main -- sin esto el boton quedaba literalmente
     cortado por el borde derecho/superior de la pantalla (mitad del circulo
     invisible, confirmado con captura real), no solo "pegado". */
  .view-help-anchor {
    padding: 14px 14px 0 0;
  }

  .topbar-title-group {
    flex: 1 1 100%;
  }

  .topbar h1 {
    font-size: 22px;
  }

  .metric-grid {
    grid-template-columns: repeat(2, minmax(140px, 1fr));
  }

  /* Botones/inputs se quedaban en el mismo tamaño de desktop (min-height 38-40px)
     sin importar el ancho de pantalla -- se achican un poco en mobile, sin bajar
     de 34-36px para no perder precision tactil. */
  .primary-button,
  .ghost-button,
  .icon-button,
  .segment {
    min-height: 34px;
    padding: 0 10px;
    font-size: 13px;
  }

  input,
  select,
  textarea {
    min-height: 36px;
  }

  /* .toolbar-actions ya tenia flex-wrap:wrap, pero .toolbar (el que empareja
     titulo+acciones lado a lado) no lo tenia -- con varios controles angostos
     (buscador, selects, botones) esto forzaba overflow horizontal en vez de
     apilar en 2+ filas. Afecta a ~10 vistas que comparten esta clase. */
  .toolbar {
    flex-wrap: wrap;
  }

  /* Mismo problema que .reservation-form/.payment-form (que si se resetean
     abajo): .form-grid nunca colapsaba a 1 columna -- afecta Configuracion
     ("Politica de seña"), el modal de Fechas especiales, y Tarifas/Temporada
     operativa. */
  .form-grid {
    grid-template-columns: 1fr;
  }

  /* min-width:280px fijo forzaba que un solo campo de busqueda ocupara casi
     toda la pantalla en mobile. */
  .search-field {
    min-width: 0;
    width: 100%;
  }

  /* Los graficos SVG de Estadisticas usan un viewBox fijo de 640 unidades que
     escala ~0.5x en un panel mobile -- el texto de los ejes quedaba ilegible.
     Las etiquetas del eje X ahora estan rotadas (ver svgTimeSeriesChart/
     svgStackedBarChart), asi que no hace falta un salto tan agresivo como
     antes para que sigan siendo legibles sin solaparse. */
  .stats-axis-label {
    font-size: 13px;
  }

  .reservations-layout.detail-open {
    grid-template-columns: 1fr;
  }

  .reservations-layout.detail-open > .panel:not(.reservation-detail) {
    display: none;
  }

  /* La fila compacta de .detail-open (mas abajo en el archivo) no alcanza a
     mobile porque detail-open oculta la lista entera aca arriba -- se repite
     el mismo layout de 2 lineas para el caso "lista visible, sin seleccion",
     que es justo el que faltaba. */
  .reservations-layout .reservation-row {
    /* minmax(0, 92px), no "auto": un status largo ("Pendiente de seña") sin
       tope hacia el ancho maximo del contenido, empujando la fila entera
       fuera de la pantalla (bug real reportado: "las etiquetas sobresalen
       hacia la derecha"). Con un tope fijo, la columna nunca crece mas alla
       de eso -- el texto que no entra se trunca (ver .reservation-row-status
       y .pill mas abajo), nunca desborda. */
    grid-template-columns: 1fr minmax(0, 92px);
    align-items: center;
    gap: 2px 8px;
    min-height: 0;
    padding: 8px 10px;
  }

  .reservations-layout .reservation-row > div {
    min-width: 0;
  }

  .reservations-layout .reservation-row strong {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 13px;
    line-height: 1.2;
  }

  .reservations-layout .reservation-row span {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* La regla generica de arriba matchea CUALQUIER span de la fila, incluido
     .deposit-warning (el "!" de seña no registrada, tambien un span) -- le
     pisaba el display:inline-block de su regla base por especificidad,
     corriendolo ~2px de mas hacia abajo. Restaurado puntualmente aca. */
  .reservations-layout .reservation-row .deposit-warning {
    display: inline-block;
    margin-top: 0;
  }

  .reservations-layout .reservation-row > div:first-child span,
  .reservations-layout .reservation-row > div:nth-child(2) span {
    display: none;
  }

  .reservations-layout .reservation-row > div:nth-child(2) {
    grid-column: 1;
    grid-row: 2;
  }

  .reservations-layout .reservation-row > div:nth-child(3) {
    display: none;
  }

  .reservations-layout .reservation-row .reservation-row-status {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    max-width: 100%;
    min-width: 0;
  }

  .reservations-layout .reservation-row .pill {
    display: inline-block;
    max-width: 100%;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-height: 22px;
    font-size: 11px;
    padding: 0 7px;
  }

  /* grid-template-columns de esta vista vive junto a la regla base
     (mas abajo en el archivo) para no perder contra ella en la cascada --
     ver el comentario ahi. */
  .guests-layout.detail-open > .guests-list-panel {
    display: none;
  }

  .guests-layout:not(.detail-open) > .guest-detail-panel {
    display: none;
  }

  /* Configuracion, mismo patron lista/detalle que Reservas/Clientes/Chat:
     una pantalla por vez. Sin .settings-detail-open se ve el nav de
     categorias solo (el detalle no aparece hasta elegir una); con la clase
     (ver openSettingsAccordionGroup en app.js) se invierte. */
  .settings-shell {
    grid-template-columns: 1fr;
  }

  .settings-sidebar {
    position: static;
  }

  .settings-detail {
    display: none;
  }

  .settings-shell.settings-detail-open .settings-sidebar {
    display: none;
  }

  .settings-shell.settings-detail-open .settings-detail {
    display: block;
  }

  .settings-detail-back {
    display: inline-flex;
  }

  .reservation-form,
  .payment-form {
    grid-template-columns: 1fr;
  }

  .wide {
    grid-column: auto;
  }

  .chat-layout {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
    /* La base (100vh - 88px) asume el navbar arriba -- en mobile ahora esta
       ABAJO (ver .topnav mas abajo en este archivo), asi que lo que hay que
       descontar es lo que .main REALMENTE reserva arriba y abajo (su propio
       padding), no un header fijo de 88px que ya no ocupa lugar arriba.
       Tiene que calzar EXACTO con .main -- si esta altura queda mas grande
       que el hueco real que .main deja libre, .main (y con el body entero)
       termina mas alto que el viewport, y el navegador deja scrollear la
       PAGINA, no solo el ".messages" de adentro (que sigue teniendo su
       propio scroll interno bien armado, ver el flex de mas arriba). Bug
       real reportado: en mobile, el header de la conversacion abierta no se
       sentia fijo al scrollear -- la causa NO era el flex interno (correcto
       desde siempre, confirmado con scrollTop manual) sino este sobrante:
       quedaban 14px de mas, la pagina entera podia scrollear esos 14px, y
       ese scroll de pagina se llevaba el header con el resto del layout.
       padding-top de .main = env(safe-area-inset-top); padding-bottom =
       14px + var(--mobile-bottom-nav-space) -- los 2 tienen que restarse
       completos y exactos, el "14px" del bottom NO es opcional. */
    height: calc(100vh - env(safe-area-inset-top) - 14px - var(--mobile-bottom-nav-space));
    /* Ese ajuste de 14px no alcanzo solo -- el usuario probo en un telefono
       real y seguia viendo el header (y el cuadro de escribir de abajo, el
       ultimo hijo flex de .conversation-panel) moverse. Causa de fondo:
       "100vh" en un navegador mobile real NO es el viewport visible en cada
       momento -- es el mas grande posible, con la barra de direcciones
       oculta. Mientras esa barra esta visible (el estado inicial normal),
       "100vh" da un numero MAS GRANDE que el espacio realmente visible, asi
       que .chat-layout terminaba mas alto de lo que entraba en pantalla —
       mismo sintoma que el bug de arriba (pagina con scroll de mas), pero
       esta vez el numero en si estaba mal, no la resta. La unidad
       "100dvh" (dynamic viewport height, soporte amplio en navegadores
       2023+) SI se recalcula en vivo contra el viewport visible real. Se
       declara DESPUES de la version con vh a proposito -- fallback seguro:
       un navegador que no entiende dvh directamente descarta esta linea por
       invalida (no la interpreta como "0" ni rompe nada) y se queda con la
       de vh de arriba; uno que si la entiende la usa, ganando por ser la
       ULTIMA declaracion de "height" en esta misma regla (misma
       especificidad, no depende del orden del archivo, solo del orden
       DENTRO de esta regla). */
    height: calc(100dvh - env(safe-area-inset-top) - 14px - var(--mobile-bottom-nav-space));
  }

  /* Mismo motivo que .chat-layout: el tope de alto se calculaba contra
     100vh asumiendo el navbar arriba -- ahora esta abajo. A diferencia de
     .chat-layout (que se pudo medir exacto con un test real: el navbar
     arriba libera espacio, pero NO es 1 a 1 con lo que ocupaba, porque .main
     ya tenia su propio padding-top independiente del navbar) -- aca lo mas
     seguro es NO asumir cuanto se libero arriba y solo restar lo nuevo que
     hay que reservar abajo. Es un max-height (con scroll propio si no
     alcanza), asi que el peor caso de quedarse corto es una vista un poco
     mas chica, nunca contenido inaccesible -- mas seguro que arriesgarse a
     que la caja quede mas alta de lo que realmente entra sin taparse con la
     barra de abajo. */
  .planning-wrap {
    max-height: calc(100vh - 240px - var(--mobile-bottom-nav-space));
    /* Mismo fallback dvh que .chat-layout mas arriba -- "100vh" en mobile es
       el viewport MAS GRANDE posible (barra de direcciones oculta), no el
       visible en cada momento, asi que esta cuenta ya venia optimista. Con
       max-height (nunca genera overflow de pagina como .chat-layout con
       height fijo) el riesgo era menor, pero igual vale corregirlo: con dvh
       el limite queda mas ajustado a lo que realmente se ve. Se declara
       despues por el mismo motivo (fallback seguro, gana en navegadores que
       entienden dvh, se ignora en los que no). */
    max-height: calc(100dvh - 240px - var(--mobile-bottom-nav-space));
  }

  /* En el telefono el detalle es la pantalla entera: la lista de al lado se
     oculta (ver .detail-open mas arriba en este bloque) y arriba no queda
     nada, porque el navbar esta abajo y switchView esconde el .topbar en
     esta vista. Asi que el alto disponible es el hueco que deja .main y
     nada mas: viewport, menos su padding-top (el notch) y menos su
     padding-bottom (14px + la barra de abajo). Es la misma cuenta que
     .chat-layout mas arriba, que ya se midio contra un telefono real.

     Antes se restaban 110px fijos: era la reserva de espacio del ESCRITORIO
     (el navbar arriba mas el "top" del sticky), heredada de cuando la barra
     estaba arriba. Cuando la barra se mudo abajo se le sumo el espacio nuevo
     pero no se saco el viejo, a proposito -- quedarse corto con un
     max-height solo achica la caja, no esconde contenido, y era lo prudente
     sin poder medir. Medido ahora: esos 110px eran exactamente la franja
     gris que quedaba entre el final del detalle y la barra (panel hasta 644,
     barra desde 754, en una pantalla de 812). */
  .reservation-detail {
    max-height: calc(100vh - env(safe-area-inset-top) - 14px - var(--mobile-bottom-nav-space));
    /* Mismo fallback dvh que .chat-layout: "100vh" en un telefono es el
       viewport mas grande posible, no el visible. */
    max-height: calc(100dvh - env(safe-area-inset-top) - 14px - var(--mobile-bottom-nav-space));
  }

  /* Sin esto el toast (esquina inferior derecha) quedaba tapado atras de la
     barra nueva -- solo se le mueve el "bottom" base, translateY (la
     animacion de aparecer/desaparecer) sigue igual, ver .toast/.toast.visible
     mas arriba en el archivo. */
  .toast {
    bottom: calc(18px + var(--mobile-bottom-nav-space));
  }

  .chat-layout:not(.conversation-open) .conversation-panel {
    display: none;
  }

  .chat-layout.conversation-open .conversation-list-col {
    display: none;
  }

  .conversation-back {
    display: inline-flex;
  }

  /* Position:absolute con top fijo (74px) contra #planning -- con el toolbar
     ya envolviendo a 2-3 filas en mobile (fix de arriba), ese offset fijo
     puede quedar superpuesto con los propios controles o con el formulario
     "Nueva reserva" expandido. Se centra como un modal en su lugar. */
  .mini-calendar {
    position: fixed;
    top: 50%;
    left: 50%;
    right: auto;
    transform: translate(-50%, -50%);
    width: min(340px, calc(100vw - 32px));
    /* Mismo motivo que .toast/.topnav-collapsible: sin restar el espacio de
       la barra nueva de abajo, en un mobile horizontal (bajo de alto) el
       calendario podia terminar pintando encima de la barra, sin ningun velo
       que lo justifique como modal. */
    max-height: calc(100vh - 32px - var(--mobile-bottom-nav-space));
    /* Mismo fallback dvh que .chat-layout/.planning-wrap mas arriba. */
    max-height: calc(100dvh - 32px - var(--mobile-bottom-nav-space));
    overflow-y: auto;
    z-index: 60;
  }
}

.nav-caret {
  color: var(--muted);
  transition: transform 150ms ease;
  font-size: 11px;
}

.topnav-parent.open .nav-caret {
  transform: rotate(180deg);
}

/* Dropdown flotante (reemplaza al viejo submenu inline de la barra lateral
   vertical) — anclado al boton padre via .topnav-group{position:relative}. */
/* El panel sale DESDE su boton, no aparece de la nada: transform-origin en
   el borde superior izquierdo (que es donde esta el boton padre) + un scale
   apenas por debajo de 1. Antes pasaba de display:none a display:flex, o sea
   un salto seco de invisible a visible.
   No se usa display para ocultarlo porque display no se puede transicionar;
   visibility si, y ademas saca los items del orden de tabulacion igual que
   display:none (opacity sola no lo haria: quedarian enfocables e invisibles).
   El panel es position:absolute, asi que dejarlo en el flujo no mueve nada. */
.topnav-dropdown {
  display: flex;
  flex-direction: column;
  gap: 1px;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 190px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-float);
  z-index: 45;

  visibility: hidden;
  opacity: 0;
  transform: scale(0.96) translateY(-4px);
  transform-origin: top left;
  pointer-events: none;
  transition:
    opacity var(--dur-panel) var(--ease-out),
    transform var(--dur-panel) var(--ease-out),
    visibility 0s linear var(--dur-panel);
}

.topnav-dropdown.open {
  visibility: visible;
  opacity: 1;
  transform: scale(1) translateY(0);
  pointer-events: auto;
  /* Al ABRIR, visibility tiene que cambiar en el instante 0 (si esperara al
     final de la transicion, el panel apareceria recien despues de la
     animacion). Al cerrar en cambio espera, para que el fundido se vea. */
  transition:
    opacity var(--dur-panel) var(--ease-out),
    transform var(--dur-panel) var(--ease-out),
    visibility 0s;
}

/* El dropdown de Ajustes esta pegado al extremo derecho del navbar: si
   creciera desde la izquierda se veria salir del lugar equivocado. */
.topnav-group:last-of-type .topnav-dropdown,
.topnav-dropdown[data-align="right"] {
  transform-origin: top right;
}

/* ---------------------------------------------------------------------------
   LA CAMPANITA
   El boton vive suelto en el navbar (fuera del menu que se pliega en
   telefono), asi que tiene que ocupar poco y leerse igual en las dos anchuras.
   --------------------------------------------------------------------------- */
.nav-bell-group {
  position: relative;
  flex: 0 0 auto;
}

.nav-bell {
  position: relative;
}

/* El badge se monta sobre la esquina del icono, no al lado: el boton es
   cuadrado y un numerito en linea lo deformaria. */
.nav-bell .nav-badge {
  position: absolute;
  top: 1px;
  right: 1px;
  transform: translate(35%, -35%);
}

/* Que haya algo sin leer se nota tambien en la campana, no solo en el numerito:
   en telefono el numero es chico y se pierde contra el navbar claro. */
.nav-bell.tiene-sin-leer {
  color: var(--red);
}

.nav-bell-dropdown {
  /* Mas ancho que los otros: estos items son dos lineas de texto real, no
     etiquetas de una palabra. */
  width: min(360px, calc(100vw - 24px));
  padding: 0;
  gap: 0;
  /* Anclado a la derecha: el boton esta en el extremo derecho del navbar, asi
     que creciendo desde la izquierda el panel se saldria de la pantalla. */
  left: auto;
  right: 0;
  transform-origin: top right;
}

.nav-bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}

.nav-bell-head strong {
  font-size: 13px;
}

/* Tope de alto con scroll propio: son hasta 50 avisos y el panel no puede
   crecer mas que la pantalla. */
.nav-bell-list {
  display: flex;
  flex-direction: column;
  max-height: min(420px, 60vh);
  overflow-y: auto;
  padding: 4px;
}

.nav-bell-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.nav-bell-item:hover,
.nav-bell-item:focus-visible {
  background: var(--surface-muted);
}

.nav-bell-item-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.nav-bell-item-top strong {
  font-size: 13px;
  font-weight: 600;
  /* Sin esto un titulo largo empuja la hora fuera del panel. */
  min-width: 0;
}

.nav-bell-cuando {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--muted);
}

.nav-bell-item-body {
  font-size: 12px;
  color: var(--muted);
  line-height: 1.35;
}

/* El punto a la izquierda marca lo que todavia no se abrio. Se queda mientras
   el panel esta abierto aunque ya se hayan marcado leidas (ver
   marcarNotificacionesLeidas): si se apagara al instante, lo nuevo perderia el
   resaltado justo cuando la persona lo esta mirando. */
.nav-bell-item.sin-leer {
  position: relative;
  padding-left: 20px;
}

.nav-bell-item.sin-leer::before {
  content: "";
  position: absolute;
  left: 8px;
  top: 14px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-strong);
}

.nav-bell-item.sin-leer.urgente::before {
  background: var(--red);
}

/* En oscuro, con la fila en hover (--surface-muted), el rojo pleno queda en
   2.9: el punto es lo unico que dice "urgente". La tinta clara da 6.4. */
html[data-theme="dark"] .nav-bell-item.sin-leer.urgente::before {
  background: var(--tint-red-ink);
}

.nav-bell-vacio {
  margin: 0;
  padding: 18px 12px;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
}

.topnav-dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 34px;
  padding: 6px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--ink);
  text-align: left;
  font-size: 13px;
  font-weight: 600;
}

.topnav-dropdown-item:hover {
  background: var(--surface-muted);
  color: var(--accent-strong);
}

/* La vista abierta, en Agua como el resto de lo seleccionado. El hover
   queda en el gris calido: mas sutil que lo elegido. */
.topnav-dropdown-item.active {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.date-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 38px;
  padding: 0 12px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
}

.date-badge:hover {
  border-color: var(--accent);
}

.calendar-day.selected {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.housekeeping-table {
  width: 100%;
  min-width: 980px;
  border-collapse: collapse;
}

.housekeeping-table th,
.housekeeping-table td {
  border-bottom: 1px solid var(--line);
  padding: 10px;
  text-align: left;
  vertical-align: top;
}

.housekeeping-table th {
  color: var(--muted);
  font-size: 12px;
  text-transform: uppercase;
}

.housekeeping-table td span {
  color: var(--muted);
  font-size: 12px;
}

/* Tiene que venir DESPUES de las reglas base de .listing-table/
   .housekeeping-table de arriba (min-width:720px/980px) -- antes este bloque
   vivia mas arriba en el archivo, ANTES de esas reglas base, y por eso nunca
   ganaba en la cascada (misma especificidad, gana quien viene despues en el
   CSS, sin importar que este adentro de un @media): en mobile las 4 tablas
   de Listados (limpieza/entradas/salidas/desayunos) seguian forzando su
   min-width de escritorio y quedaban con scroll horizontal (bug real
   reportado). screen (no "print") a proposito: hay un @media print dedicado
   a #listados mas abajo que tiene que seguir imprimiendo tabla real -- una
   hoja en portrait mide <900px y sin este calificador Chrome evaluaria
   max-width tambien contra el ancho de pagina impresa. */
@media screen and (max-width: 900px) {
  .listing-table,
  .housekeeping-table {
    min-width: 0;
  }

  .listing-table thead,
  .housekeeping-table thead {
    display: none;
  }

  .listing-table tr,
  .housekeeping-table tr {
    display: block;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    padding: 10px 12px;
    margin-bottom: 10px;
  }

  .listing-table td:first-child,
  .housekeeping-table td:first-child {
    position: static;
  }

  .listing-table td,
  .housekeeping-table td {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    border-bottom: 0;
    padding: 6px 0;
  }

  .listing-table td::before,
  .housekeeping-table td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    min-width: 100px;
    color: var(--muted);
    font-size: 12px;
    text-transform: uppercase;
    font-weight: 600;
  }

  /* Mismo motivo que .housekeeping-notes-input (mas abajo, ya tenia
     width:100%): sin esto el <select> de Staff se queda en su min-width de
     130px con espacio muerto a la derecha de la fila -- inconsistente con el
     resto de los campos de la misma tarjeta en mobile. */
  .housekeeping-staff-select {
    width: 100%;
  }
}

.housekeeping-staff-select {
  min-height: 34px;
  min-width: 130px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  padding: 0 8px;
}

.housekeeping-event {
  border-left: 3px solid var(--line);
  padding: 4px 0 4px 8px;
  margin-bottom: 6px;
  font-size: 13px;
}

.housekeeping-event:last-child {
  margin-bottom: 0;
}

.housekeeping-event strong {
  margin-right: 4px;
}

.housekeeping-event span {
  display: block;
}

.housekeeping-event.entrada {
  border-left-color: var(--green);
}

.housekeeping-event.salida {
  border-left-color: var(--orange);
}

.housekeeping-event.cliente {
  border-left-color: var(--blue);
}

.service-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  min-width: 160px;
}

.service-tag {
  min-height: 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--muted);
  padding: 0 10px;
  font-size: 11px;
  font-weight: 700;
}

.service-tag.active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.housekeeping-notes-input {
  min-height: 34px;
  width: 100%;
  min-width: 140px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  padding: 0 8px;
}

.topbar-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* En desktop, topnav-collapsible es simplemente otra fila flex adentro de
   .topnav (.topnav-list + los 2 botones de accion empujados a la derecha via
   .topnav-cta). En mobile YA NO es un drawer que se despliega: sus hijos
   quedan a la vista siempre, como una fila mas de la barra fija de abajo —
   ver el comentario grande junto a .topnav-list mas abajo para el porque de
   este cambio completo (antes: hamburguesa + panel deslizante). */
.topnav-collapsible {
  display: flex;
  align-items: center;
  gap: 18px;
  flex: 1 1 auto;
  min-width: 0;
}

/* Los 2 botones de accion (+Reserva, +Ingreso por mostrador) duplicados
   dentro de "Mas" (#nav-ajustes-dropdown) -- ocultos en escritorio, donde
   los originales siguen sueltos en el navbar (.topnav-cta mas abajo). Ver el
   comentario grande junto a .topnav-list para el porque de la duplicacion en
   vez de mover el mismo boton entre contenedores. */
.topnav-dropdown-actions {
  display: none;
}

/* Atras/adelante del historial de navegacion interno -- solo en desktop
   (junto al logo, como un navegador); en mobile se ocultan aca y viven
   duplicados dentro de "Mas" (.nav-history-actions mas abajo), igual que ya
   pasaba con +Reserva/+Ingreso por mostrador -- la barra fija de abajo no
   tiene lugar para 2 iconos mas. */
.nav-history {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}

/* .ghost-button:disabled ya cubre el par duplicado de mobile (mas abajo en
   el archivo) -- esto es solo para el par de escritorio, que usa
   .icon-button sin variante disabled propia. */
.nav-history .icon-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Sin barra abajo (computadora, tablet apaisada) no hay nada que reservar:
   sin esto, las reglas tactiles caian al respaldo de 58px y dejaban una franja
   muerta debajo del planning en una tablet de mas de 980px (FE-070). El bloque
   del telefono la redefine. */
:root {
  --mobile-bottom-nav-space: 0px;
}

@media screen and (max-width: 980px) {
  /* Pedido explicito (25/08): eliminar el hamburguesa y mostrar los 5
     accesos de primer nivel (Inicio, Recepcion, Listados, Chat, Mas)
     directo en la barra de abajo, sacando el texto de marca (Huespix by
     DMG + nombre del hotel) para hacerles lugar. El logo pasa a flex:0 0 auto (antes
     necesitaba flex:1+shrink para ceder espacio a un nombre de hotel largo
     -- ya no hay texto que ceder). */
  .brand {
    flex: 0 0 auto;
  }

  .brand > div {
    display: none;
  }

  /* Pedido explicito (15/08): el navbar pasa de arriba a ABAJO en mobile —
     mas facil de alcanzar con el pulgar. env(safe-area-inset-bottom) es el
     alto real del home indicator/gesture bar de iOS (0 en Android o si el
     navegador no lo soporta) -- sin viewport-fit=cover en el <meta viewport>
     de index.html, esta funcion siempre da 0, asi que los dos van juntos. El
     numero base (58px) es un poco mas generoso que el alto real de .topnav
     (~50px, min-height:50px con box-sizing:border-box) a proposito: mejor un
     pelo de aire de sobra que contenido tapado por la barra en algun
     dispositivo puntual que no se pudo probar en persona. Sigue en uso mas
     alla del navbar mismo (padding-bottom de .main, alturas de Chat/
     Planning/el datepicker), no es exclusivo de este bloque. */
  :root {
    --mobile-bottom-nav-space: calc(58px + env(safe-area-inset-bottom));
  }

  /* De sticky-arriba a fixed-abajo. El resto del layout (.app-shell es un
     flex column) no necesita tocarse: position:fixed saca a .topnav del
     flujo igual que sticky lo mantenia "flotando" en su lugar, asi que
     .main pasa a ocupar toda la altura libre desde arriba -- el hueco que
     hace falta dejar ahora es ABAJO, no arriba (ver .main mas abajo). */
  .topnav {
    position: fixed;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    border-bottom: 0;
    border-top: 1px solid var(--line);
    padding-bottom: calc(6px + env(safe-area-inset-bottom));
  }

  /* Los 5 accesos de primer nivel (Inicio, Recepcion, Listados, Chat, Mas)
     repartidos por todo el ancho de la barra -- antes .topnav-list vivia
     apilado en columna DENTRO del drawer deslizante; ahora es la barra
     misma. space-between deja el primero y el ultimo pegados a los bordes
     de .topnav (que ya tiene 16px de padding horizontal propio, asi que no
     quedan pegados de verdad a la pantalla). */
  .topnav-list {
    flex: 1 1 auto;
    justify-content: space-between;
    gap: 4px;
  }

  /* El pedido explicito fue "acceder mas facil" desde mobile -- 44px es el
     minimo recomendado (Apple HIG / Material Design); antes quedaban en
     36px/34px (los mismos que escritorio, pensados para mouse). Solo mobile,
     escritorio no cambia. */
  .topnav-item,
  .topnav-dropdown-item {
    min-height: 44px;
  }

  /* Solo icono en los 5 botones de primer nivel -- sin esto, "Habitaciones"/
     "Configuracion"/etc con su texto no entran los 5 juntos en un telefono
     angosto. min-width (no width fijo) para que Recepcion/Listados/Mas, que
     ademas del icono llevan la flechita de "esto despliega algo", puedan ser
     un poco mas anchos que Inicio/Chat sin verse recortados. Los items
     DENTRO de un dropdown (.topnav-dropdown-item) no se tocan: esos abren en
     un panel flotante con lugar de sobra, mantienen su texto siempre. */
  .topnav-item {
    min-width: 44px;
    padding: 0 8px;
    gap: 4px;
    justify-content: center;
  }

  .topnav-item > span:not(.nav-icon):not(.nav-caret):not(.nav-badge) {
    display: none;
  }

  /* El dropdown de Recepcion/Listados/Mas abria hacia ABAJO (top: calc(100% +
     6px) heredado de la regla de escritorio) porque el navbar estaba arriba
     de la pantalla. Ahora que esta abajo, abrir hacia abajo lo mandaria fuera
     de la pantalla -- se ancla al revez (bottom en vez de top). El resto de
     las propiedades (fondo, borde, sombra, radio) NO se pisan -- se
     mantienen las de escritorio, ahora que esto vuelve a ser un panel
     flotante de verdad y no un acordeon aplanado dentro de un drawer (que es
     como funcionaba antes en este mismo breakpoint).
     max-height + scroll propio: el de Ajustes es el mas largo de los tres
     (6 vistas + los 2 accesos + el chip de sesion) y en un telefono bajo
     podria no entrar completo entre la barra de abajo y el techo de la
     pantalla. */
  .topnav-dropdown {
    top: auto;
    bottom: calc(100% + 8px);
    left: auto;
    right: 0;
    max-height: calc(100vh - var(--mobile-bottom-nav-space) - 24px);
    max-height: calc(100dvh - var(--mobile-bottom-nav-space) - 24px);
    overflow-y: auto;
  }

  /* El anclaje horizontal de arriba (right:0) NO alcanza para los 3: con
     190px de ancho minimo y los 5 accesos repartidos por TODO el ancho de la
     barra (justify-content:space-between en .topnav-list), ni "siempre
     left" ni "siempre right" entran los 3 sin salirse de la pantalla.
     Medido en 375px: Recepcion (2do de 5, hacia la izquierda) con right:0
     se salia 18px por la izquierda; Listados y Mas (3ro y 5to/ultimo) SI
     entran con right:0. Recepcion es el unico que necesita el anclaje
     contrario (el de escritorio, left:0). */
  #nav-recepcion-dropdown {
    left: 0;
    right: auto;
  }

  /* Los originales (sueltos en el navbar, empujados a la derecha) se ocultan
     -- mobile ya no tiene lugar para un boton CON TEXTO en la barra de
     iconos. Sus duplicados dentro de "Mas" (mismo id + "-mobile", ver
     index.html #nav-ajustes-dropdown) toman su lugar. */
  #open-reservation-shortcut,
  #open-walkin-form {
    display: none;
  }

  /* Mismo criterio: el par de escritorio (junto al logo) se oculta, el
     duplicado dentro de "Mas" (.nav-history-actions) lo reemplaza. */
  .nav-history {
    display: none;
  }

  .topnav-dropdown-actions {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 2px;
  }

  .topnav-dropdown-actions .topnav-cta {
    width: 100%;
    margin-left: 0;
    justify-content: center;
  }

  /* "Atras"/"Adelante" son textos cortos -- a diferencia de +Reserva/+
     Ingreso (que necesitan la fila entera), van lado a lado en vez de
     apilados, sino desperdician la mitad del ancho de cada boton. */
  .nav-history-actions {
    flex-direction: row;
  }

  .nav-history-actions .topnav-cta {
    flex: 1 1 0;
  }
}

/* ---------------------------------------------------------------------------
   Vista Clientes (base de clientes)

   Todo el color sale de las variables de tema, asi que claro/oscuro sale solo.
   Dos reglas que se respetan a proposito en cada grid de aca (ver
   feedback_visual_layout_verification): las columnas usan minmax(0, ...) para
   que una celda pueda ENCOGERSE por debajo de su contenido, y toda celda de
   texto trunca con ellipsis. Sin las dos, un nombre o un mail largo desborda
   su pista y pinta encima de la celda vecina — exactamente el bug que tuvo el
   header "Comprobante" de Pagos.
--------------------------------------------------------------------------- */
/* Aviso de "este cliente ya existe" al cargar una reserva nueva (Planning y
   Mostrador) — ver findMatchingGuest() en app.js. Usa las mismas variables de
   tema que el resto (nunca colores fijos), y trunca su texto con ellipsis en
   vez de dejarlo desbordar cuando el nombre es largo. */
.guest-match-hint {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--line));
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 8px 12px;
  font-size: 13px;
  color: var(--ink);
}

.guest-match-hint span {
  min-width: 0;
  flex: 1 1 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guest-match-hint .ghost-button {
  padding: 4px 10px;
  font-size: 12px;
  flex: 0 0 auto;
}

/* Enlace en linea dentro de un titulo (ej. "Ver ficha del cliente" en el
   detalle de reserva). Hereda el tamaño del contexto para no romper el alto
   del <h3> que lo contiene. */
.link-button {
  background: none;
  border: 0;
  padding: 0;
  margin-left: 8px;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--accent-strong);
  text-decoration: underline;
  cursor: pointer;
}

/* El hover engrosa el subrayado en vez de cambiar el color: --accent como
   texto da 2.8 sobre la tarjeta oscura. */
.link-button:hover {
  text-decoration-thickness: 2px;
}

/* Una sola columna mientras no haya ningun cliente elegido: la lista ocupa la
   pantalla entera y el panel de la ficha ni siquiera reserva lugar. Antes la
   grilla era SIEMPRE de dos columnas, asi que al entrar a Clientes media
   pantalla se iba en un panel vacio que solo decia "elegi un cliente".
   Mismo criterio que ya usaba Reservas (.reservations-layout). */
.guests-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

/* Con una ficha abierta, la lista es una columna angosta y la ficha se lleva
   el resto: mismo criterio y mismo ancho que Reservas (pedido de Juan, 06/10).
   Por debajo de 981px no corre (ver el bloque de abajo): ahi la ficha es la
   pantalla entera. */
.guests-layout.detail-open {
  grid-template-columns: clamp(264px, 24vw, 340px) minmax(0, 1fr);
}

/* El panel de ficha se saca del flujo cuando esta vacio -- si solo se le
   quitara la columna, igual quedaria dibujado debajo de la lista como una
   tarjeta vacia. En mobile ya habia una regla equivalente dentro del bloque
   de @media(max-width:980px); esta la cubre en todos los anchos. */
.guests-layout:not(.detail-open) > .guest-detail-panel {
  display: none;
}

/* Tiene que declararse DESPUES de la regla base de arriba -- misma
   especificidad, en CSS gana la que aparece mas tarde en el archivo sin
   importar que este envuelta en @media. El resto de las reglas mobile de
   esta vista (detail-open, ocultar paneles) viven en el bloque grande de
   @media(max-width:980px) mas arriba en el archivo -- pero ESTA declaracion
   puntual necesita quedar aca para ganarle a la de linea 4640.
   Se incluye .detail-open explicitamente: en mobile la ficha se ve a pantalla
   completa (la lista se oculta), asi que NUNCA hay dos columnas. Sin
   nombrarla, `.guests-layout.detail-open` (2 clases) le ganaria por
   especificidad a esta regla y partiria la pantalla en dos en un telefono. */
@media screen and (max-width: 980px) {
  .guests-layout,
  .guests-layout.detail-open {
    grid-template-columns: minmax(0, 1fr);
  }
}

.guests-list-panel,
.guest-detail-panel {
  min-width: 0;
}

.guests-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
}

.guest-row {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  grid-auto-rows: min-content;
  gap: 4px 12px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: inherit;
  padding: 10px 12px;
  text-align: left;
  cursor: pointer;
  transition: 150ms ease;
}

.guest-row:hover {
  border-color: var(--accent);
}

.guest-row.active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.guest-row-name,
.guest-row-meta,
.guest-row-stats {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guest-row-name {
  font-weight: 600;
  color: var(--ink);
}

.guest-row-meta,
.guest-row-stats {
  font-size: 0.82rem;
  color: var(--muted);
}

.guest-row-meta {
  text-align: right;
}

.guest-row-pills {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.guest-row-pills:empty {
  display: none;
}

/* Con la lista a pantalla completa (sin ficha abierta) la fila pasa de un
   2x2 a una sola linea de 4 columnas, tipo tabla.
   El 2x2 esta pensado para la columna angosta de ~550px que queda cuando hay
   una ficha al lado; estirado a 1300px dejaba el nombre solo en una celda de
   700px y la fila entera medía 96px de alto para tres datos cortos. En una
   linea entran mas clientes en pantalla y las columnas quedan alineadas
   entre filas, que es lo que hace que una lista larga se pueda barrer con la
   vista.
   Solo desde 981px: abajo de eso manda el bloque mobile, donde la lista
   siempre ocupa el ancho completo y el 2x2 es el layout correcto. */
@media screen and (min-width: 981px) {
  .guests-layout:not(.detail-open) .guest-row {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1.4fr) minmax(0, 1.1fr) auto;
    align-items: center;
    gap: 12px 16px;
  }

  .guests-layout:not(.detail-open) .guest-row-meta {
    text-align: left;
  }

  /* Deja de ocupar su propia fila y se alinea a la derecha del todo. */
  .guests-layout:not(.detail-open) .guest-row-pills {
    grid-column: auto;
    justify-content: flex-end;
    flex-wrap: nowrap;
  }
}

.pill.guest-tag {
  background: var(--accent-soft);
  color: var(--accent-strong);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
}

/* Sobre la fila elegida (que ya es Agua) la etiqueta pasa a blanco: Agua
   sobre Agua se perderia. */
.guest-row.active .pill.guest-tag {
  background: var(--surface);
}

.guest-detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.guest-detail-head h3 {
  margin: 2px 0 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.guest-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 10px;
  margin: 14px 0;
}

.guest-metric {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
  min-width: 0;
}

.guest-metric strong {
  font-size: 1.05rem;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guest-metric span {
  font-size: 0.76rem;
  color: var(--muted);
}

.guest-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.guest-field-wide {
  grid-column: 1 / -1;
}

.guest-form textarea {
  resize: vertical;
  font: inherit;
}

.guest-form-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
}

.guest-history {
  margin-top: 18px;
  border-top: 1px solid var(--line);
  padding-top: 14px;
}

.guest-history h4 {
  margin: 0 0 10px;
  font-size: 0.95rem;
}

.guest-history h4 small {
  font-weight: 400;
  color: var(--muted);
}

.guest-stays {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.guest-stay {
  display: grid;
  /* auto -> minmax(0, 92px): mismo bug/fix que .reservation-row en Reservas
     (ver comentario ahi) -- un status largo ("Pendiente de seña") sin techo
     empujaba la fila entera fuera de la pantalla entre ~641px y 980px (el
     @media de mas abajo recien colapsa a 1 columna a partir de 640px). */
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 92px) minmax(0, 0.9fr);
  align-items: center;
  gap: 10px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: inherit;
  padding: 10px 12px;
  text-align: left;
  cursor: pointer;
  transition: 150ms ease;
}

.guest-stay:hover {
  border-color: var(--accent);
}

.guest-stay span:not(.pill) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.85rem;
}

/* El pill queda afuera de la regla de arriba (:not(.pill)) porque no
   necesita su font-size -- pero si necesita la misma proteccion de ancho,
   mismo motivo que .reservation-row .pill en Reservas. */
.guest-stay .pill {
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guest-stay-dates {
  font-weight: 600;
  color: var(--ink);
}

.guest-stay-room,
.guest-stay-total {
  color: var(--muted);
}

.guest-stay-total {
  text-align: right;
}

@media (max-width: 640px) {
  .guest-row,
  .guest-stay {
    grid-template-columns: minmax(0, 1fr);
  }

  .guest-row-meta,
  .guest-stay-total {
    text-align: left;
  }

  .guest-form {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ---------------------------------------------------------------------------
   CAJA POR TURNO

   Todo se apoya en los tokens de :root, asi que el modo oscuro
   (html[data-theme="dark"], que redefine los mismos nombres) se adapta solo
   sin una sola regla extra.

   Dos decisiones de diseño que codifican reglas del modulo, no adorno:
   - El bloque de efectivo es el unico "destacado" (borde de acento): es el
     unico que alguien tiene que contar.
   - El bloque de cobros online va apagado (--muted) a proposito: es plata
     real pero nadie la recibio, y tiene que leerse como informacion, no como
     algo pendiente de hacer.
--------------------------------------------------------------------------- */

.caja-turno-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-size: 13px;
  color: var(--muted);
}

.caja-turno-duracion {
  font-weight: 600;
  color: var(--ink);
}

.caja-cuentas,
.caja-relevo-cuentas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 12px;
  /* align-items: start es el arreglo que mas espacio recupera de toda la
     vista: por defecto la grilla estira las 4 tarjetas a la altura de la
     mas alta, y como "Efectivo" tiene 5 renglones y "Tarjeta" tiene 1, esa
     ultima quedaba con ~200px de blanco adentro. Cada una toma ahora el
     alto de su contenido. */
  align-items: start;
}

.caja-relevo-cuentas {
  margin-bottom: 18px;
}

.caja-bloque {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  background: var(--surface);
}

.caja-bloque-destacado {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--surface));
}

.caja-bloque-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}

.caja-bloque-header h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.caja-bloque-pista {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

.caja-fila {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 14px;
  padding: 4px 0;
  font-size: 13.5px;
}

.caja-fila-etiqueta {
  color: var(--muted);
}

.caja-fila-nota {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  font-size: 11px;
  text-align: center;
}

/* Los montos se leen en columna: tabular-nums evita que los digitos bailen
   de fila en fila y hace comparable el alineado a la derecha. */
.caja-fila-monto {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

.caja-fila-total {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.caja-fila-total .caja-fila-etiqueta {
  color: var(--ink);
  font-weight: 600;
}

.caja-fila-total .caja-fila-monto {
  font-size: 17px;
  color: var(--accent-strong);
}

.caja-fila-negativo .caja-fila-monto {
  color: var(--tint-red-ink);
}

.caja-fila-apagado .caja-fila-monto {
  color: var(--muted);
  font-weight: 500;
}

/* --- Lineas de caja (04/10) ----------------------------------------------
   Una linea por movimiento, la misma en la lista del turno, en el detalle de
   cada total y en el historial. Dos renglones y no uno: el pedido de Juan fue
   ver DE DONDE vino cada peso ("efectivo $94.000, de donde ingresaron"), y en
   un solo renglon el concepto se cortaba con puntos suspensivos justo donde
   estaba la respuesta. Arriba lo que fue (la reserva con su link, el pedido,
   el concepto del gasto); abajo, chico, tipo y medio, nota, hora y quien. */
.caja-lineas {
  display: flex;
  flex-direction: column;
}

.caja-linea {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 10px;
  align-items: start;
  padding: 8px 2px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
}

.caja-linea:last-child {
  border-bottom: none;
}

.caja-linea-icono {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  color: var(--muted);
  font-weight: 700;
  font-size: 13px;
}

.caja-linea-cobro .caja-linea-icono {
  background: color-mix(in srgb, var(--green) 15%, var(--surface));
  color: var(--tint-green-ink);
}

.caja-linea-ingreso .caja-linea-icono,
.caja-linea-fondo .caja-linea-icono {
  background: color-mix(in srgb, var(--blue) 15%, var(--surface));
  color: var(--tint-blue-ink);
}

.caja-linea-retiro .caja-linea-icono,
.caja-linea-gasto .caja-linea-icono {
  background: color-mix(in srgb, var(--red) 13%, var(--surface));
  color: var(--tint-red-ink);
}

.caja-linea-cuerpo {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* El nombre del huesped puede ser largo: baja de renglon entero, nunca letra
   por letra (overflow-wrap solo corta una palabra que no entra sola). */
.caja-linea-principal {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

/* El separador "·" va ANTES de cada dato y la fila arranca 12px a la
   izquierda con esos 14px recortados: el punto del primer dato de cada
   renglon queda en la parte recortada. Sin esto, un renglon que baja empieza
   con "· cargó Recepcion". */
.caja-linea-detalle {
  display: flex;
  flex-wrap: wrap;
  row-gap: 1px;
  margin-left: -14px;
  clip-path: inset(0 0 0 14px);
  font-size: 12px;
  color: var(--muted);
  line-height: 1.4;
}

/* Cada dato es un item de la fila flexible: si no entra en lo que queda del
   renglon, baja ENTERO al siguiente ("Cobro en efectivo" no se parte). Solo
   uno que no entra ni en un renglon solo (un usuario como
   "carla_de_martino_64d3a3" en la columna angosta del arqueo) se corta por
   dentro, en vez de salirse de la tarjeta. */
.caja-linea-dato {
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.caja-linea-dato {
  position: relative;
  padding-left: 14px;
}

.caja-linea-dato::before {
  content: "·";
  position: absolute;
  left: 5px;
}

.caja-linea-aviso {
  font-size: 12px;
  color: var(--tint-yellow-ink);
  line-height: 1.35;
}

.caja-linea-monto {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 14px;
  white-space: nowrap;
  text-align: right;
  min-width: 88px;
  padding-top: 1px;
}

.caja-linea-monto.negativo {
  color: var(--tint-red-ink);
}

.caja-linea-apagada .caja-linea-monto {
  color: var(--muted);
  font-weight: 600;
}

/* El link a la reserva: texto, no boton. Subrayado para que se sepa que se
   toca; el area tocable crece con padding sin mover el texto. */
.caja-link {
  appearance: none;
  border: 0;
  background: none;
  padding: 2px 0;
  margin: -2px 0;
  font: inherit;
  font-weight: 600;
  color: var(--accent-strong);
  text-align: left;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent-strong) 40%, transparent);
  text-underline-offset: 3px;
  cursor: pointer;
  overflow-wrap: anywhere;
}

@media (hover: hover) and (pointer: fine) {
  .caja-link:hover {
    text-decoration-color: currentColor;
  }
}

.caja-link:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (max-width: 720px) {
  .caja-linea-monto {
    min-width: 0;
  }
}

/* --- Detalle de cada total del arqueo ------------------------------------ */

.caja-desglose-toggle {
  appearance: none;
  border: 0;
  background: none;
  margin-top: 8px;
  padding: 6px 0;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent-strong);
  cursor: pointer;
}

.caja-desglose-toggle::after {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 7px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-fast) var(--ease-out);
}

.caja-desglose-toggle[aria-expanded="true"]::after {
  transform: translateY(1px) rotate(-135deg);
}

.caja-desglose-toggle:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
  border-radius: 3px;
}

.caja-desglose {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px dashed var(--line);
}

/* Un total abierto ocupa la fila entera del arqueo, con el resumen a la
   izquierda y sus lineas a la derecha: en su columna de ~300px cada linea
   bajaba a cuatro renglones. En pantallas angostas, una debajo de la otra. */
.caja-bloque-abierto {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  column-gap: 28px;
}

.caja-bloque-abierto > .caja-bloque-resumen {
  grid-column: 1;
  grid-row: 1;
}

.caja-bloque-abierto > .caja-desglose-toggle {
  grid-column: 1;
  grid-row: 2;
  align-self: start;
  justify-self: start;
}

.caja-bloque-abierto > .caja-desglose {
  grid-column: 2;
  grid-row: 1 / span 2;
  margin-top: 0;
  padding-top: 0;
  padding-left: 24px;
  border-top: 0;
  border-left: 1px dashed var(--line);
}

@media (max-width: 980px) {
  .caja-bloque-abierto {
    display: block;
  }

  .caja-bloque-abierto > .caja-desglose {
    margin-top: 4px;
    padding: 4px 0 0;
    border-left: 0;
    border-top: 1px dashed var(--line);
  }
}

.caja-desglose-grupo {
  margin: 10px 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.caja-desglose-pie {
  margin-top: 4px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--green) 9%, var(--surface));
  color: var(--tint-green-ink);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.caja-desglose-pie.no-coincide {
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  color: var(--tint-red-ink);
}

/* --- Historial de movimientos -------------------------------------------- */

.caja-movs {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.caja-movs-filtros {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: 10px;
  align-items: end;
}

/* Las dos fechas van juntas: son un rango, y separadas por la grilla una
   podia caer en otro renglon que la otra. */
.caja-movs-fechas {
  grid-column: span 2;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.caja-movs-fechas.hidden {
  display: none;
}

.caja-movs-buscar {
  grid-column: span 2;
}

.caja-movs-filtros label {
  min-width: 0;
}

.caja-movs-filtros input,
.caja-movs-filtros select {
  width: 100%;
  min-width: 0;
}

.caja-movs-resumen {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 14px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

.caja-movs-total {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
}

.caja-movs-total strong {
  font-size: 17px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.caja-movs-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.caja-movs-chip {
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 12px;
  white-space: nowrap;
}

.caja-movs-chip span {
  color: var(--muted);
}

.caja-movs-chip strong {
  font-variant-numeric: tabular-nums;
}

.caja-movs-turno {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.caja-movs-turno-cabeza {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px 12px;
}

.caja-movs-turno-quien {
  flex: 1 1 200px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.caja-movs-turno-quien strong {
  font-size: 14px;
  overflow-wrap: anywhere;
}

.caja-movs-turno-quien > span {
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.caja-junto {
  white-space: nowrap;
}

.caja-movs-quitar-turno {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--surface-muted);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  font: inherit;
  font-size: 12px;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}

.caja-movs-turno-numeros {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
  gap: 8px;
  margin: 0;
}

.caja-movs-turno-numeros div {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.caja-movs-turno-numeros dt {
  font-size: 12px;
  color: var(--muted);
}

.caja-movs-turno-numeros dd {
  margin: 0;
  font-weight: 700;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.caja-movs-turno-cuenta {
  margin: 0;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--green) 9%, var(--surface));
  color: var(--tint-green-ink);
  font-size: 12.5px;
}

.caja-movs-turno-cuenta.no-coincide {
  background: color-mix(in srgb, var(--yellow) 16%, var(--surface));
  color: var(--tint-yellow-ink);
}

.caja-movs-mas {
  align-self: center;
}

.caja-historial-ver {
  flex: 0 0 auto;
  min-height: 32px;
  font-size: 12.5px;
}

/* --- Cuadrar la caja (06/10, solo admin) ---------------------------------
   Las acciones de un cierre van juntas a la derecha ("Corregir lo contado"
   solo la ve un admin). Las correcciones de un cierre se leen como aviso, en
   la tinta amarilla de .caja-linea-aviso: un arqueo corregido nunca se ve
   igual que uno que siempre dijo eso. */
.caja-historial-acciones {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px;
}

.caja-correcciones {
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--tint-yellow-ink);
  overflow-wrap: anywhere;
}

/* Texto y no boton lleno: es la accion rara de una linea, no la de la vista.
   El area tocable crece con padding sin mover el texto. */
.caja-linea-anular {
  align-self: flex-start;
  appearance: none;
  border: 0;
  background: none;
  padding: 4px 0;
  margin: -2px 0 -4px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--tint-red-ink);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--tint-red-ink) 40%, transparent);
  text-underline-offset: 3px;
}

@media (hover: hover) and (pointer: fine) {
  .caja-linea-anular:hover {
    text-decoration-color: currentColor;
  }
}

.gastro-cierre-corregir {
  align-self: flex-start;
  min-height: 32px;
  font-size: 12.5px;
}

.pms-confirm-modal.caja-correccion-modal {
  width: min(440px, 100%);
  overflow-y: auto;
}

.caja-correccion-modal #caja-correccion-ayuda {
  overflow: visible;
}

.caja-correccion-cifras {
  display: grid;
  gap: 4px;
  margin: 12px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  font-size: 13px;
}

.caja-correccion-cifras div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.caja-correccion-cifras dt {
  color: var(--muted);
}

.caja-correccion-cifras dd {
  margin: 0;
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.caja-correccion-campo {
  display: grid;
  gap: 6px;
  margin-top: 14px;
  font-size: 13px;
  font-weight: 600;
}

.caja-correccion-campo input {
  min-height: 42px;
  padding: 0 12px;
  font-size: 15px;
  font-weight: 400;
}

.caja-correccion-campo input:focus-visible {
  outline: none;
  border-color: var(--focus-outline);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

#caja-correccion-vista:not(:empty) {
  margin-top: 10px;
}

.caja-correccion-modal .caja-correccion-pie {
  margin-top: 12px;
  font-size: 12px;
}

/* "Ver mas turnos": al pie de la lista de turnos cerrados, centrado. */
.caja-historial-mas {
  align-self: center;
  margin-top: 12px;
  min-height: 36px;
}

@media (max-width: 720px) {
  .caja-movs-fechas,
  .caja-movs-buscar {
    grid-column: 1 / -1;
  }
}

/* --- Panel plegable ------------------------------------------------------
   Para lo que se consulta de vez en cuando y no hace falta tener siempre a
   la vista (turnos cerrados, historial). Es <details>/<summary> nativo: el
   navegador ya resuelve teclado, foco y el anuncio de plegado/desplegado.
   Reusable en cualquier vista, no solo en Caja. */
.panel-plegable {
  padding: 0;
}

.panel-plegable-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  cursor: pointer;
  /* Saca el triangulito nativo del navegador, que ademas se ve distinto en
     cada uno; el chevron propio de al lado hace ese trabajo. */
  list-style: none;
  border-radius: var(--radius-lg);
  transition: background-color var(--dur-fast) var(--ease-out);
}

.panel-plegable-header::-webkit-details-marker {
  display: none;
}

.panel-plegable-header .eyebrow {
  display: block;
  margin-bottom: 2px;
}

.panel-plegable-header strong {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

@media (hover: hover) and (pointer: fine) {
  .panel-plegable-header:hover {
    background: color-mix(in srgb, var(--ink) 2.5%, transparent);
  }
}

.panel-plegable-chevron {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  color: var(--muted);
  transition: transform var(--dur-panel) var(--ease-out);
}

.panel-plegable[open] .panel-plegable-chevron {
  transform: rotate(180deg);
}

/* El contenido lleva el padding, no el <details>: asi el encabezado plegado
   ocupa exactamente su propia altura y no arrastra un hueco debajo. */
.panel-plegable > :not(summary) {
  padding: 0 18px 18px;
}

@media (prefers-reduced-motion: reduce) {
  .panel-plegable-chevron {
    transition: none;
  }
}

/* --- Avisos en vivo (retiro y relevo) --- */

.caja-queda-hint {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  font-size: 13px;
  color: var(--muted);
}

/* --- Formularios de caja: anchos razonables -----------------------------
   Un campo de monto no necesita 1300px. Los formularios heredaban el ancho
   completo del panel, asi que "Monto" era un campo de pantalla entera para
   escribir 5 digitos, y el boton de registrar iba igual de largo: ademas de
   verse mal, obliga a recorrer media pantalla con la vista entre el campo y
   el boton.
   Se limitan a un ancho de lectura comodo y los campos cortos se agrupan de
   a tres, que es lo que entra sin apretarse. */
#caja-movimiento-form,
#caja-arranque-form {
  max-width: 640px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

#caja-relevo-form {
  max-width: 760px;
}

/* El submit deja de ocupar todo el ancho: un boton de accion se dimensiona
   por su texto. Sigue siendo el elemento mas visible del formulario por
   color, no por tamaño. */
#caja-movimiento-form .primary-button,
#caja-arranque-form .primary-button,
#caja-relevo-form .primary-button {
  justify-self: start;
  width: auto;
  min-width: 200px;
}

/* .wide sigue existiendo para los campos que si necesitan la fila entera
   (nota, observaciones), pero ahora "entera" son 3 columnas y no la
   pantalla. */
#caja-movimiento-form .wide,
#caja-arranque-form .wide,
#caja-relevo-form .wide {
  grid-column: 1 / -1;
}

@media (max-width: 720px) {
  #caja-movimiento-form,
  #caja-arranque-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.caja-queda-hint strong {
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.caja-queda-hint.caja-queda-error {
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  color: var(--tint-red-ink);
}

.caja-queda-hint.caja-queda-error strong {
  color: var(--tint-red-ink);
}

.caja-diferencias {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.caja-dif-linea {
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  font-size: 13px;
}

.caja-dif-linea.caja-dif-cuadra {
  background: color-mix(in srgb, var(--green) 11%, var(--surface));
  color: var(--tint-green-ink);
}

.caja-dif-linea.caja-dif-sobra {
  background: color-mix(in srgb, var(--yellow) 18%, var(--surface));
  color: var(--tint-yellow-ink);
}

.caja-dif-linea.caja-dif-falta {
  background: color-mix(in srgb, var(--red) 11%, var(--surface));
  color: var(--tint-red-ink);
}

/* --- Historial de turnos cerrados --- */

.caja-historial {
  display: flex;
  flex-direction: column;
}

.caja-historial-fila {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--line);
}

.caja-historial-fila:last-child {
  border-bottom: none;
}

.caja-historial-quien {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.caja-historial-quien strong {
  font-size: 13.5px;
  font-weight: 600;
}

.caja-historial-quien span {
  font-size: 12px;
  color: var(--muted);
}

.caja-historial-numeros {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 13.5px;
  white-space: nowrap;
}

.caja-historial-secundario {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--muted);
}

/* El estado del arqueo se codifica en forma y color a la vez (texto explicito
   "Cuadro"/"Faltaba X"), no solo en color: un daltonico tiene que poder leer
   igual si el turno cerro bien. */
.caja-dif {
  flex: 0 0 auto;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}

.caja-dif-cuadra {
  background: color-mix(in srgb, var(--green) 13%, var(--surface));
  color: var(--tint-green-ink);
}

.caja-dif-sobra {
  background: color-mix(in srgb, var(--yellow) 20%, var(--surface));
  color: var(--tint-yellow-ink);
}

.caja-dif-falta {
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  color: var(--tint-red-ink);
}

@media (max-width: 720px) {
  .caja-cuentas,
  .caja-relevo-cuentas {
    grid-template-columns: minmax(0, 1fr);
  }

  .caja-turno-meta {
    align-items: flex-start;
  }

  .caja-historial-fila {
    flex-wrap: wrap;
  }

  .caja-historial-quien {
    flex: 1 1 100%;
  }
}

/* ---------------------------------------------------------------------------
   GASTRONOMIA (bar / cafeteria)

   Es un punto de venta: los productos son botones grandes, el ticket esta
   siempre a la vista, y tocar algo tiene efecto inmediato. Todo sobre los
   tokens de :root, asi que el modo oscuro se adapta solo.
--------------------------------------------------------------------------- */

.gastro-turno-barra {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 20px;
  flex-wrap: wrap;
  padding: 12px 16px;
  margin-bottom: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.gastro-turno-info { display: flex; flex-direction: column; gap: 2px; }
.gastro-turno-quien { font-weight: 700; font-size: 15px; }
.gastro-turno-desde { font-size: 12px; color: var(--muted); }

/* Resumen del turno como TIRA horizontal de datos, no como tabla.
   Antes era una grilla de 3 columnas que se partia en 3 filas con
   separadores: ~150px de alto arriba del punto de venta, empujando la
   grilla de productos (que es lo que se toca todo el tiempo) fuera de la
   primera pantalla. Cada dato pasa a ser un par etiqueta/valor apilado, y
   los 8 entran en una sola linea de ~46px.
   Es informacion de consulta, no de trabajo: se mira al cerrar la caja. */
.gastro-resumen-turno {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 6px 22px;
  flex: 1 1 340px;
  min-width: 0;
  font-size: 12.5px;
}
.gastro-resumen-fila {
  display: flex;
  flex-direction: column;
  gap: 1px;
  color: var(--muted);
}
.gastro-resumen-fila span:first-child {
  font-size: 10.5px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.gastro-resumen-fila span:last-child {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}
.gastro-resumen-fila.total span:last-child { color: var(--accent-strong); }
.gastro-resumen-fila.negativo span:last-child { color: var(--tint-red-ink); }
/* Los separadores partian la grilla en 3 bloques; en una tira horizontal
   pasan a ser una linea vertical fina entre grupos. */
.gastro-resumen-sep {
  width: 1px;
  align-self: stretch;
  min-height: 28px;
  background: var(--line);
  margin: 0;
}

/* --- Pedidos abiertos (las "mesas") --- */

.gastro-mesas-wrap { margin-bottom: 14px; }
.gastro-mesas-titulo {
  display: block;
  margin-bottom: 6px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Scroll propio: con muchas mesas abiertas no entran, y el body nunca tiene
   que scrollear de costado. */


.gastro-mesa {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 108px;
  min-height: 52px;
  padding: 9px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  transition: border-color 100ms ease, transform 80ms ease;
}
.gastro-mesa:hover { border-color: var(--accent); }
.gastro-mesa:active { transform: scale(0.97); }
.gastro-mesa.activa { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
.gastro-mesa-num { font-size: 11px; font-weight: 700; color: var(--muted); }
.gastro-mesa-label { font-size: 13px; font-weight: 600; }
.gastro-mesa-total { font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--accent-strong); }

/* --- Layout del punto de venta --- */

.gastro-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: 16px;
  align-items: start;
}

.gastro-menu { min-width: 0; }
/* El buscador no necesita el ancho completo del menu (eran ~1030px para
   escribir "cafe"). Se limita, y los chips de categoria suben a la MISMA
   fila: dos elementos que sirven para lo mismo -- filtrar la grilla -- que
   antes ocupaban dos renglones separados. */
.gastro-filtros {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-bottom: 12px;
}
.gastro-menu-barra {
  margin-bottom: 0;
  flex: 0 1 280px;
  min-width: 180px;
}
.gastro-menu-barra input {
  width: 100%;
}

.gastro-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 0; flex: 1 1 auto; }
.gastro-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 40px;
  padding: 6px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 100ms ease, background 100ms ease;
}
.gastro-chip:hover { border-color: var(--accent); }
/* Elegido = Agua, como todo lo seleccionado: con turquesa pleno competia con
   "Cobrar", que es el unico color fuerte de la pantalla del pedido. */
.gastro-chip.activo { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-strong); font-weight: 600; }
/* Punto de color por categoria: mismo color en el chip, en las tarjetas de
   producto de esa categoria y en la carta de Configuracion -- ayuda a ubicar
   productos de un vistazo, no solo por el nombre (no depende SOLO del color,
   el nombre de la categoria siempre esta al lado). */
.gastro-chip-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  flex: 0 0 auto;
}

/* Botones grandes: en un bar se toca con el dedo y a las apuradas. */
.gastro-productos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}
.gastro-producto {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  min-height: 80px;
  padding: 12px 12px 12px 15px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  transition: border-color 100ms ease, transform 80ms ease, box-shadow 100ms ease;
}
/* Borde de color a la izquierda: el mismo hash de color que el chip de la
   categoria, asi la grilla entera se puede escanear por color sin leer cada
   nombre. Ver gastroCategoryColor() en app.js. */
.gastro-producto::before {
  content: "";
  position: absolute;
  left: 0; top: 10px; bottom: 10px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--gastro-cat-color, transparent);
}
.gastro-producto:hover:not(:disabled) { border-color: var(--accent); box-shadow: var(--shadow-raised); }
.gastro-producto:active:not(:disabled) { transform: scale(0.97); }
.gastro-producto:disabled { opacity: 0.5; cursor: not-allowed; }
.gastro-producto-nombre { font-size: 13.5px; font-weight: 600; line-height: 1.25; overflow-wrap: anywhere; }
.gastro-producto-precio { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--accent-strong); }

/* --- El ticket --- */

.gastro-ticket {
  position: sticky;
  top: 12px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 14px 16px;
}

.gastro-ticket-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.gastro-ticket-head strong { display: block; font-size: 15px; }
.gastro-ticket-mesa { font-size: 12px; color: var(--muted); }

.gastro-lineas { list-style: none; margin: 0; padding: 8px 0; max-height: 44vh; overflow-y: auto; }
.gastro-linea {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
}
.gastro-linea:last-child { border-bottom: none; }
.gastro-linea-cuerpo { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.gastro-linea-nombre { font-size: 13.5px; overflow-wrap: anywhere; }
.gastro-linea-unit { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.gastro-linea-total { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.gastro-linea-vacia { padding: 14px 0; color: var(--muted); font-size: 13px; font-style: italic; list-style: none; }

.gastro-cantidad { display: flex; align-items: center; gap: 4px; }
.gastro-qty {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 17px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: border-color 100ms ease, transform 80ms ease;
}
.gastro-qty:hover { border-color: var(--accent); color: var(--accent-strong); }
.gastro-qty:active { transform: scale(0.93); }
.gastro-qty-valor { min-width: 26px; text-align: center; font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums; }

.gastro-totales { padding: 10px 0; border-top: 1px solid var(--line); }
.gastro-total-fila { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; color: var(--muted); padding: 2px 0; }
.gastro-total-fila span:last-child { font-variant-numeric: tabular-nums; }
.gastro-total-fila.descuento span:last-child { color: var(--tint-red-ink); }
.gastro-total-fila.grande { font-size: 19px; font-weight: 700; color: var(--ink); padding-top: 6px; }
.gastro-total-fila.grande span:last-child { color: var(--accent-strong); }

.gastro-ticket-acciones { display: flex; flex-wrap: wrap; gap: 6px; }
.gastro-ticket-acciones .primary-button { flex: 1 1 100%; }
.gastro-ticket-acciones .ghost-button { flex: 1 1 auto; }
.danger-text { color: var(--tint-red-ink); }

/* --- Cobro --- */

.gastro-cobro-falta { margin: 0 0 12px; font-size: 14px; font-weight: 600; }
.gastro-cobro-falta.pendiente { color: var(--muted); }
.gastro-cobro-falta.ok { color: var(--tint-green-ink); }
.gastro-cobro-falta.error { color: var(--tint-red-ink); }

/* Sin margen propio: el cuerpo del cobro es una columna con gap. Tres por
   fila (seis medios, dos filas parejas); en telefono "Transferencia" no entra
   en un tercio y van de a dos. */
.gastro-medios { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
@media (max-width: 520px) {
  .gastro-medios { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.gastro-medio {
  min-height: 46px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.gastro-medio:hover:not(:disabled) { border-color: var(--accent); color: var(--accent-strong); }
.gastro-medio:disabled { opacity: 0.4; cursor: not-allowed; }

/* Elegido: el medio que ya tiene su parte abajo. Los botones son de prender y
   apagar (tocarlo de nuevo lo saca), y NUNCA se apagan por estar cubierto el
   total: tocar otro medio es como se divide el pago. */
.gastro-medio.elegido {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}

/* "¿Cómo paga?" y, con un medio elegido, "Para dividir el pago, tocá otro
   medio". Es lo unico que dice en pantalla que se puede dividir. */
.gastro-cobro-medios-titulo { margin: 0 0 -4px; font-size: 13px; font-weight: 600; color: var(--muted); }

/* Una parte del pago por medio: nombre, monto y la x para sacarla, y debajo
   (solo el efectivo) cuanto entrego para calcular el vuelto. */
.gastro-cobro-lineas { list-style: none; margin: 0; padding: 0; }
.gastro-cobro-lineas:empty { display: none; }
.gastro-cobro-parte { padding: 10px 0; border-bottom: 1px solid var(--line); }
.gastro-cobro-parte:first-child { padding-top: 0; }
.gastro-cobro-parte:last-child { padding-bottom: 0; border-bottom: none; }
.gastro-cobro-linea {
  display: flex;
  align-items: center;
  /* En 320px el nombre del medio ("Transferencia") + el campo de monto + el
     boton de quitar no entran en una linea, y el boton terminaba fuera de la
     pantalla. Envuelve, y el monto puede achicarse en vez de ser fijo. */
  flex-wrap: wrap;
  gap: 6px 10px;
}
.gastro-cobro-medio { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.gastro-cobro-medio-nombre { font-size: 13.5px; font-weight: 600; color: var(--ink); }
/* "el resto": la parte que se completa sola mientras se tipea en las otras. */
.gastro-cobro-medio-nota { font-size: 11.5px; font-weight: 600; color: var(--accent-strong); }
.gastro-cobro-medio-nota:empty { display: none; }
.gastro-cobro-monto { flex: 1 1 110px; min-width: 0; max-width: 150px; text-align: right; font-variant-numeric: tabular-nums; }
/* La parte que es "el resto" (solo con el pago dividido): su monto lo pone
   el sistema, y se lee del mismo color que la nota que lo dice. */
.gastro-cobro-parte.es-resto .gastro-cobro-monto {
  color: var(--accent-strong);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}

/* Fila del vuelto: colgada de la parte en efectivo, no un pago aparte. */
.gastro-cobro-vuelto-fila {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 10px;
  padding-top: 8px;
}
.gastro-cobro-vuelto-fila label { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); }
.gastro-cobro-recibido { width: 110px; min-height: 40px; text-align: right; font-variant-numeric: tabular-nums; }
.gastro-cobro-vuelto { font-size: 13px; font-weight: 700; color: var(--muted); }
.gastro-cobro-vuelto:empty { display: none; }
.gastro-cobro-vuelto.con-vuelto {
  color: var(--tint-green-ink);
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--tint-green-ink) 12%, transparent);
}

/* El cartel ("Falta $X", "Te pasaste $X", "Listo para cobrar") cierra la
   cuenta debajo de las partes: con partes, va separado como un total. */
.gastro-cobro-lineas:not(:empty) ~ .gastro-cobro-falta {
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

/* --- Carta --- */

.gastro-alta-cat { display: flex; gap: 8px; margin-bottom: 16px; }
.gastro-alta-cat input { flex: 1 1 auto; min-width: 0; }
.gastro-alta-cat button { white-space: nowrap; }

.gastro-carta-lista { display: flex; flex-direction: column; gap: 14px; margin-top: 16px; }
.gastro-cat-bloque { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; }
.gastro-cat-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 8px; }
.gastro-cat-head-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.gastro-cat-head h3 { margin: 0; font-size: 14px; }
.gastro-carta-productos { list-style: none; margin: 0; padding: 0; }
.gastro-carta-productos li {
  display: flex;
  align-items: center;
  /* Envuelve: en 320px el nombre + precio + los tres botones no entran en
     una linea y el de borrar terminaba fuera de la pantalla. */
  flex-wrap: wrap;
  gap: 6px 10px;
  padding: 6px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
}
.gastro-carta-productos li:last-child { border-bottom: none; }
.gastro-carta-nombre { flex: 1 1 auto; font-size: 13.5px; overflow-wrap: anywhere; }
.gastro-carta-precio { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.gastro-carta-productos .ghost-button { padding: 2px 10px; font-size: 11.5px; }
/* Agotado: nunca se borra, solo se atenua -- reactivar es un click, no hay
   que volver a cargar el producto de cero. */
.gastro-carta-productos li.gastro-carta-agotado { opacity: 0.62; }
.gastro-agotado-tag {
  display: inline-block;
  padding: 1px 8px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--tint-red-ink) 14%, transparent);
  color: var(--tint-red-ink);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

/* --- Historial --- */

.gastro-historial-filtros { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.gastro-historial-filtros input[type="search"] { flex: 1 1 200px; min-width: 0; }
.gastro-historial-filtros select { flex: 0 0 auto; }

.gastro-historial-lista { display: flex; flex-direction: column; gap: 6px; }
.gastro-historial-fila {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  transition: border-color 100ms ease;
}
.gastro-historial-fila:hover { border-color: var(--accent); }
.gastro-historial-codigo { font-weight: 700; font-size: 13px; flex: 0 0 auto; }
.gastro-historial-mesa { flex: 1 1 auto; min-width: 0; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gastro-historial-fecha { flex: 0 0 auto; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.gastro-historial-total { flex: 0 0 auto; font-weight: 700; font-variant-numeric: tabular-nums; min-width: 70px; text-align: right; }

/* --- Cierres de la caja del bar (04/10) ---
   Una tarjeta por cierre: quien y cuando arriba con el estado del arqueo (la
   misma pastilla .caja-dif del historial de la Caja, texto y color), el
   efectivo en tres cifras y lo cobrado por medio en una grilla de celdas
   iguales (dos por fila en un telefono, todas en una fila en escritorio).
   Todo en tokens de :root, asi que el oscuro sale solo. */
.gastro-cierres-lista { display: flex; flex-direction: column; gap: 10px; }
.gastro-cierre {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.gastro-cierre-cabeza { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.gastro-cierre-quien { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.gastro-cierre-quien strong { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.gastro-cierre-quien > span { font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Apertura y cierre: uno al lado del otro si entran, uno abajo del otro si no.
   Cada uno entero ("Abrio 04/10 09:05" no se parte por dentro). */
.gastro-cierre-horas { display: flex; flex-wrap: wrap; column-gap: 14px; row-gap: 2px; }
.gastro-cierre-junto { white-space: nowrap; }
.gastro-cierre-titulo {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.gastro-cierre-efectivo {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}
/* Tope de ancho: en escritorio las tres cifras quedaban a 400px una de otra. */
.gastro-cierre-efectivo dl { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0; max-width: 560px; }
.gastro-cierre-efectivo dl div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.gastro-cierre-efectivo dt { font-size: 12px; color: var(--muted); }
.gastro-cierre-efectivo dd { margin: 0; font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.gastro-cierre-dif-sobra { color: var(--tint-yellow-ink); }
.gastro-cierre-dif-falta { color: var(--tint-red-ink); }
.gastro-cierre-medios {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 6px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.gastro-cierre-medios li {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.gastro-cierre-medios li span { font-size: 12px; color: var(--muted); }
.gastro-cierre-medios li strong { font-size: 13.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.gastro-cierre-vacio,
.gastro-cierre-pie { margin: 0; font-size: 12.5px; color: var(--muted); }
.gastro-cierre-nota { margin: 0; font-size: 12.5px; color: var(--muted); font-style: italic; overflow-wrap: anywhere; }
/* Los movimientos de un cierre: la misma linea que la Caja de recepcion. */
.gastro-cierre-movs .caja-desglose-toggle { margin-top: 0; }
.gastro-cierre-movs .caja-desglose { display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 480px) {
  .gastro-cierre { padding: 12px; }
  .gastro-cierre-efectivo { padding: 8px 10px; }
  .gastro-cierre-efectivo dl { gap: 6px; }
  .gastro-cierre-efectivo dd { font-size: 13px; }
  .gastro-cierre-medios { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.gastro-historial-detalle-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; color: var(--muted); font-size: 13px; }
.gastro-historial-motivo { font-size: 13px; color: var(--muted); font-style: italic; margin: 0 0 10px; }
.gastro-historial-pagos-titulo { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); margin: 14px 0 4px; }
.gastro-historial-pagos { list-style: none; margin: 0 0 16px; padding: 0; }
.gastro-historial-pagos li { display: flex; justify-content: space-between; padding: 4px 0; font-size: 13.5px; }
.gastro-historial-pagos li span:last-child { font-variant-numeric: tabular-nums; font-weight: 600; }
#gastro-historial-anular { margin-top: 6px; }

@media (max-width: 900px) {
  /* En el telefono lo primero tienen que ser los PRODUCTOS: es un punto de
     venta, no un tablero. El resumen del turno (fondo, cobrado por medio,
     facturado) se manda al final -- se consulta al cerrar la caja, no
     mientras se toman pedidos, y arriba se comia media pantalla antes de
     llegar a la carta. */
  #gastro-pos { display: flex; flex-direction: column; }
  .gastro-mesas-wrap { order: 0; }
  .gastro-layout { order: 1; }
  .gastro-turno-barra { order: 2; margin: 14px 0 0; }

  /* El ticket pasa abajo del menu y deja de ser pegajoso: en una pantalla
     angosta, un panel sticky se come la mitad del alto util. */
  .gastro-layout { grid-template-columns: minmax(0, 1fr); }
  .gastro-ticket { position: static; }
  .gastro-lineas { max-height: none; }
  .gastro-productos { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
  .gastro-turno-barra { flex-direction: column; }
  .gastro-resumen-turno { flex: 1 1 auto; width: 100%; }
}

/* ===========================================================================
   ZONAS TACTILES EN TELEFONO
   ===========================================================================
   Auditoria del 05/09 sobre las 16 vistas con datos reales, a 375x812:
   216 de 268 elementos interactivos (81%) median menos de 44px de alto, que
   es el minimo que recomiendan tanto Apple como Google. El promedio del
   sistema estaba en 34px.
   No eran 216 problemas distintos: estaban concentrados en 8 clases
   compartidas, asi que se corrigen desde la base y no vista por vista.

   Este bloque va al FINAL del archivo a proposito. En CSS, con la misma
   especificidad, gana la regla que aparece MAS TARDE — sin importar si esta
   envuelta en @media. Las reglas base de estos selectores viven entre las
   lineas 715 y 5369, y hay bloques mobile hasta la ~9440: puesto aca, nada
   lo pisa en silencio. Ver el gotcha documentado en
   project_mobile_optimization (mover una regla mobile ANTES de su base la
   vuelve inerte sin dar ningun error).

   Se usa min-height y NO height: el objetivo es agrandar el area tocable sin
   recortar contenido que ya entraba.
   =========================================================================== */
@media (max-width: 980px), (pointer: coarse) {
  .primary-button,
  .ghost-button,
  .icon-button,
  .segment {
    min-height: 44px;
  }

  .icon-button {
    width: 44px;
    /* El bloque mobile de mas arriba le pone `padding: 0 10px` a todos los
       botones, pero este mide 44px fijos: esos 10px por lado le dejaban al
       icono una caja de 22px en el medio de un cuadrado de 44. Como el
       contenido va centrado (ver la base), el padding no aporta nada y solo
       aprieta. */
    padding: 0;
    /* Ese mismo bloque los baja a 13px, que para un boton con texto ahorra
       lugar pero para uno con un solo glifo solo achica el dibujo: la flecha
       de volver medida a 13px son 11x5 pixeles de tinta en un cuadrado de
       44, mas chica que la MISMA flecha en escritorio. 17px es el tamaño de
       los iconos SVG de la navegacion, asi que todos los dibujos del
       telefono quedan en la misma escala. */
    font-size: 17px;
  }

  /* Los campos: 44px de alto y 16px de cuerpo. El 16 no es estetico — abajo
     de 16px, Safari en iPhone hace zoom automatico al enfocar un campo, y
     despues el usuario queda con la pagina ampliada y tiene que volver a
     alejarla a mano. Es el motivo por el que todos los formularios de las
     apps seria usan 16px en mobile. */
  input:not([type="checkbox"]):not([type="radio"]),
  select,
  textarea {
    min-height: 44px;
    font-size: 16px;
  }

  textarea {
    min-height: 88px;
  }

  /* --- Iconos que tienen que SEGUIR viendose chicos ---------------------
     El "?" de ayuda se veria mal a 44px: es una marca discreta al lado de un
     titulo. Lo que crece es el AREA TOCABLE, no el dibujo — un ::after
     invisible centrado que extiende el blanco hasta 44x44. El icono queda
     igual y el dedo tiene donde caer.
     pointer-events se mantiene: el pseudo-elemento hereda los del boton. */
  .help-icon-btn {
    position: relative;
  }

  .help-icon-btn::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
    /* Sin fondo: no se ve, solo recibe el toque. */
  }

  /* Los inputs de precio de Tarifas eran la peor vista de todas (65 de 67
     elementos por debajo del minimo): una tabla de tipo x precio normal x
     promo, con tres campos por fila. */
  .season-price,
  .season-promo-percent,
  .season-field,
  .extra-name,
  .extra-price,
  .extra-charge-type {
    min-height: 44px;
    font-size: 16px;
  }

  /* Las filas de la barra lateral de Configuracion y los items de menu:
     son listas largas que se recorren con el pulgar. */
  .settings-nav-item,
  .topnav-dropdown-item,
  .hotel-switch-option,
  .date-badge {
    min-height: 44px;
  }

  /* Separacion minima entre acciones contiguas. La auditoria encontro pares
     como "Cancelar / Eliminar" pegados: con 44px de alto pero sin aire, el
     riesgo de tocar la equivocada sigue estando. */
  .pms-confirm-actions,
  .toolbar-actions,
  .season-price-actions {
    gap: 12px;
  }

  /* El encabezado de cada panel, en dos filas cuando no entra en una.
     Es flex con nowrap y sus hijos se encogen por defecto: al agrandar los
     campos a 44px, las acciones pasaron a pedir mas ancho y el titulo quedo
     comprimido hasta PARTIRSE por la mitad ("Reserv / as").
     min-width:min-content en el titulo impide que se encoja por debajo de su
     palabra mas larga; con el wrap habilitado, lo que baja de linea es la
     accion, que es lo correcto. No se fuerza width:100% a proposito: un
     header corto (titulo + un chip) sigue entrando en una sola fila. */
  .panel-header {
    flex-wrap: wrap;
  }

  .panel-header > div:first-child {
    min-width: min-content;
  }

  /* El detalle de reserva tiene su propio header (flecha de volver + titulo)
     y no debe partirse en dos filas. */
  .reservation-detail .panel-header {
    flex-wrap: nowrap;
  }

  .toolbar-actions {
    justify-content: flex-start;
  }

  /* --- Los que le ganaban a la regla de arriba por especificidad ---------
     Estos selectores tienen DOS clases (o un id), asi que una regla de una
     sola clase no los alcanza por mas que este mas abajo en el archivo: en
     CSS la especificidad manda antes que el orden. Se listan uno por uno
     porque cada uno se achico a mano en su momento para ahorrar espacio en
     escritorio, y en un telefono ese ahorro no compensa. */
  .cleaning-actions .ghost-button,
  .season-price-actions .ghost-button,
  .conversation-actions .ghost-button,
  .gap-prompt-actions .ghost-button,
  .mini-calendar-header .ghost-button,
  .session-box .ghost-button,
  .knowledge-item .icon-button,
  .popover-header .icon-button {
    min-height: 44px;
    height: auto;
  }

  /* El ancho va SOLO para estos dos, no para los .ghost-button de la lista
     de arriba: esos llevan texto ("Tomar control", "Marcar como leida") y
     fijarles 44px les parte la etiqueta en tres renglones. Son botones de
     icono que alguien achico a mano en su momento (28px y 30px) y que la
     regla generica .icon-button no alcanza por tener una clase menos, asi
     que quedaban altos y flacos: 28 de ancho por 44 de alto, desproporcionado
     y por debajo del minimo tactil justo en el eje horizontal. */
  .knowledge-item .icon-button,
  .popover-header .icon-button {
    width: 44px;
  }

  /* Campos con selector "clase + elemento" (especificidad 0,1,1), que le gana
     a la regla generica de arriba. Se listan porque cada formulario del PMS
     achico sus campos por su cuenta en algun momento. */
  .reservation-detail .detail-form select,
  .detail-form textarea,
  .conversation-search-bar input,
  .compact-field input,
  .compact-field select,
  .knowledge-add-form input,
  .extra-row input,
  .extra-row select,
  .users-add-form select,
  .help-search-bar input,
  .form-grid select,
  .room-card-body select,
  .payment-form select,
  .payment-form input[type="file"],
  .season-card-dates input,
  .login-step input {
    min-height: 44px;
    height: auto;
    font-size: 16px;
  }

  /* La casilla de los formularios: 40px y con el area de toque justa. */
  .checkbox-field input[type="checkbox"] {
    min-height: 24px;
    min-width: 24px;
  }

  /* La "x" de quitar un extra de una reserva medía 16px: es la mas chica de
     todo el PMS y ademas es destructiva. */
  .extra-chip button {
    min-height: 32px;
    min-width: 32px;
  }

  #pms-prompt-input {
    min-height: 44px;
    height: auto;
    font-size: 16px;
  }
}

/* ===========================================================================
   FORMULARIOS LARGOS EN TELEFONO
   ===========================================================================
   Medido en 375x812: el formulario de "Crear reserva" mide 1.268px (una
   pantalla y media) con sus 13 campos en una sola columna, y el boton de
   crear quedaba en y=1556 — fuera de la vista. Habia que recorrer todo el
   formulario hacia abajo para poder guardar, y con el teclado abierto peor.
   =========================================================================== */

/* Los formularios de carga (mostrador y Nueva reserva) ya no usan titulos de
   seccion sueltos (.form-seccion): desde el 11/10 tienen secciones de verdad
   en los dos tamaños (ver FORMULARIOS DE CARGA al final del archivo). */
@media (max-width: 980px), (pointer: coarse) {
  /* La accion principal viaja con el scroll y queda siempre alcanzable.
     position:sticky y no fixed: sigue siendo parte del formulario (no tapa
     nada de otras vistas, no necesita z-index alto ni limpieza al cerrar) y
     se despega solo cuando el formulario es mas largo que la pantalla.
     El bottom NO es 0: la barra de navegacion vive fija abajo, asi que el
     boton se apoya justo encima de ella. --mobile-bottom-nav-space ya incluye
     el safe-area del telefono. */
  .form-accion {
    position: sticky;
    bottom: calc(var(--mobile-bottom-nav-space, 58px) + 10px);
    z-index: 5;
    width: 100%;
    box-shadow: var(--shadow-float);
  }

  /* Aire al final del formulario para que el ultimo campo no quede tapado por
     el boton pegado. */
  .reservation-form,
  .payment-form {
    padding-bottom: 8px;
  }
}

/* ===========================================================================
   MODALES Y MENUS COMO HOJA INFERIOR (TELEFONO)
   ===========================================================================
   Medido: el cartel de confirmacion queda centrado en la pantalla, con
   "Cancelar" y "Eliminar" uno al lado del otro, de 33px de alto y ~75 de
   ancho. Para una accion que no se puede deshacer es poco margen con el
   pulgar, y ademas el centro de la pantalla es la zona MAS lejos del dedo.

   En telefono pasa a ser una hoja que sube desde abajo: ocupa el ancho
   completo, nace donde esta la mano, y las acciones van apiladas — la
   destructiva arriba y "Cancelar" abajo del todo, que es la que se toca por
   reflejo al querer salir.
   =========================================================================== */
@media (max-width: 980px), (pointer: coarse) {
  .pms-confirm-backdrop {
    align-items: flex-end;
    padding: 0;
  }

  /* El visor de comprobantes comparte este backdrop pero NO es una hoja que
     sube desde abajo: es una foto para mirar. Con el flex-end de arriba el
     comprobante quedaba pegado al borde inferior, con todo el velo vacio
     arriba y el ultimo renglon 1px afuera de la pantalla (medido en 375x812:
     imagen de 716px con el borde de abajo en y=813).
     Va por id a proposito: le gana a la clase sin depender del orden. */
  #proof-viewer-backdrop {
    align-items: center;
    padding: 16px;
  }

  /* Los 16px de padding de cada punta mas los 14 que la cruz de cerrar
     sobresale por arriba: sin descontarlos, el 90dvh del modal no deja lugar
     para el boton y queda fuera de pantalla. */
  .proof-viewer-modal,
  .proof-viewer-modal img {
    max-height: calc(100dvh - 56px);
  }

  .pms-confirm-modal {
    width: 100%;
    max-width: none;
    max-height: 85vh;
    max-height: 85dvh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    /* El safe-area del telefono: sin esto, en un iPhone la ultima accion
       queda debajo de la barra gestual de abajo. */
    padding-bottom: calc(22px + env(safe-area-inset-bottom));
    animation: hojaSube 220ms cubic-bezier(0.16, 1, 0.3, 1);
  }

  /* El detalle de las metricas pide 560px con dos clases (ver
     .pms-confirm-modal.metric-detail-modal): sin repetirlas aca le ganaria a
     la regla de arriba y en una tablet la hoja quedaria flotando angosta en
     vez de llegar a los bordes. */
  .pms-confirm-modal.metric-detail-modal {
    width: 100%;
  }

  .pms-confirm-actions {
    flex-direction: column-reverse;
    gap: 10px;
    margin-top: 20px;
  }

  /* column-reverse: en el HTML "Cancelar" viene primero y la accion viene
     despues; invirtiendo, la accion queda ARRIBA y Cancelar abajo, al alcance
     del pulgar. Es el orden de iOS y el que evita confirmar sin querer. */
  .pms-confirm-actions > button {
    width: 100%;
  }
}

@keyframes hojaSube {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

/* El menu del navbar en telefono: hoy es una columna de 201px de ancho por
   661 de alto en una pantalla de 375x812 — usa el 80% del alto pero solo la
   mitad del ancho, con 16 items apretados. Pasa a ocupar el ancho completo. */
/* Solo cuando la barra esta ABAJO (telefono, <=980px). Con (pointer: coarse)
   una tablet apaisada de mas de 980px, con la barra ARRIBA, abria los menus
   como hoja pegada abajo (FE-070). */
@media screen and (max-width: 980px) {
  /* position:fixed y no absolute: el dropdown cuelga de .topnav-group, que en
     la barra de abajo mide apenas el ancho de su icono — con left/right
     relativos a ESE grupo, el menu quedaba de 31px. Fijo, se resuelve contra
     la pantalla y ocupa el ancho completo, que es lo que corresponde en un
     telefono. El bottom lo apoya sobre la barra de navegacion. */
  .topnav-dropdown,
  .hotel-switch-menu {
    position: fixed;
    left: 8px;
    right: 8px;
    top: auto;
    bottom: calc(var(--mobile-bottom-nav-space, 58px) + 6px);
    width: auto;
    min-width: 0;
    max-width: none;
    max-height: 66vh;
    max-height: 66dvh;
    overflow-y: auto;
    /* overscroll-contain: al llegar al final de la lista, el scroll NO se
       propaga a la pagina de atras (el efecto de "arrastrar el fondo" que
       delata a una web mal adaptada). */
    overscroll-behavior: contain;
  }
}

/* ===========================================================================
   HUECOS VENDIBLES
   ===========================================================================
   Los tramos libres que quedan ENTRE dos reservas. Es la razon de ser del
   planning resuelta por el sistema: en vez de recorrer la grilla buscando
   espacios, el PMS los lista y deja crear la reserva de un toque.
   =========================================================================== */
.huecos {
  margin-bottom: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.huecos-header {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 14px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.huecos-titulo {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 13.5px;
  flex: 0 0 auto;
}

/* El punto usa el mismo color con el que se tiñen las celdas del hueco en la
   grilla: sirve de leyenda sin necesidad de escribir una. */
.huecos-punto {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  background: var(--hueco-color, #d98324);
  flex: 0 0 auto;
}

.huecos-resumen {
  flex: 1 1 auto;
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.huecos-flecha {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  color: var(--muted);
  transition: transform var(--dur-fast, 150ms) ease;
}

.huecos.abierto .huecos-flecha {
  transform: rotate(180deg);
}

.huecos-lista {
  display: grid;
  /* En columnas y no una fila por hueco: en un monitor, cinco huecos apilados
     a todo el ancho empujan el rack media pantalla hacia abajo y dejan el
     importe a 1.200px del nombre de la unidad. En un telefono el minimo de
     250px da una sola columna, que es lo que corresponde ahi. */
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 6px;
  padding: 0 10px 10px;
  max-height: 200px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.hueco {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "unidad importe"
    "fechas importe"
    "noches importe";
  gap: 0 12px;
  align-items: center;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--hueco-color, #d98324);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.hueco-unidad { grid-area: unidad; font-weight: 600; font-size: 13.5px; }
.hueco-fechas { grid-area: fechas; font-size: 12.5px; color: var(--ink); }
.hueco-noches { grid-area: noches; font-size: 11.5px; color: var(--muted); }
.hueco-importe {
  grid-area: importe;
  font-weight: 700;
  font-size: 14px;
  color: var(--hueco-color, #d98324);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (hover: hover) and (pointer: fine) {
  .huecos-header:hover { background: var(--surface-muted); }
  .hueco:hover { border-color: var(--hueco-color, #d98324); }
}

/* Las celdas del hueco, en la grilla. Un rayado sutil y no un color pleno:
   el hueco tiene que resaltar contra el blanco de "libre" sin competir con
   los bloques de reserva, que son lo que ya se lee.

   Va como CAPA ENCIMA y no como `background` de la celda a proposito. El
   fondo de una celda ya se lo pelean cinco reglas (fin de semana, hoy, fila
   par, hover de fila, hover de columna) y la mas fuerte es de especificidad
   0,7,0 -- `.cell.en-hueco` es 0,2,0 y perdia en la mitad de las celdas, con
   el resultado peor de todos: el rayado aparecia salteado. Como capa aparte
   no compite con ninguna, y ademas se ve el color que la celda ya tenia
   debajo, que es lo correcto: el rayado dice "esto esta libre y encajonado",
   no reemplaza a "esto es sabado". */
.cell.en-hueco {
  position: relative;
}

.cell.en-hueco::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Los bloques de reserva son hermanos posteriores dentro de la fila, asi
     que pintan por encima igual; esto solo asegura que el rayado no atrape
     el click derecho que crea una reserva sobre la celda. */
  pointer-events: none;
  background: repeating-linear-gradient(
    135deg,
    color-mix(in srgb, var(--hueco-color, #d98324) 20%, transparent) 0 3px,
    transparent 3px 7px
  );
}

:root { --hueco-color: #c2691a; }
:root[data-theme="dark"] { --hueco-color: #e0a355; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --hueco-color: #e0a355; }
}

/* En telefono la lista puede ser el contenido principal de la vista, asi que
   se le da mas aire y los items respetan el minimo tactil. */
@media (max-width: 980px), (pointer: coarse) {
  .hueco { min-height: 56px; padding: 12px; }
  .huecos-header { min-height: 48px; }
  .huecos-lista { max-height: 45vh; max-height: 45dvh; }
}

/* ===========================================================================
   DESLIZAR DESDE EL BORDE PARA IR ATRAS / ADELANTE
   ===========================================================================
   El gesto esta en iniciarGestoNav() (app.js). Aca van las dos hojas que usa y
   el recorte que impide que la pantalla, al correrse, agrande la pagina a lo
   ancho.
   =========================================================================== */
.swipe-nav {
  position: fixed;
  inset: 0;
  /* Debajo de la barra de navegacion (40) y de los menus flotantes, encima del
     fondo de la pagina. .main sube por encima de las dos hojas solo mientras
     dura el gesto (ver .swipe-nav-activo mas abajo). */
  z-index: 20;
  pointer-events: none;
}

.swipe-nav-atras,
.swipe-nav-hoja {
  position: absolute;
  inset: 0;
  background: var(--bg);
  will-change: transform;
}

/* El papel de la pantalla actual: va debajo de .main y se mueve con el.
   La sombra del canto es lo que hace que se lea como una hoja que se levanta y
   no como un fondo que se despinta. */
.swipe-nav-hoja {
  z-index: 2;
  box-shadow: 0 0 22px rgba(0, 0, 0, 0.28);
}

.swipe-nav-atras {
  z-index: 1;
}

/* El velo: la pantalla que asoma por atras se ve levemente apagada mientras
   esta "lejos", y se aclara a medida que llega. app.js escribe --swipe-velo. */
.swipe-nav-atras::after {
  content: "";
  position: absolute;
  inset: 0;
  background: #000;
  opacity: var(--swipe-velo, 0);
}

.swipe-nav-activo .main {
  position: relative;
  /* Por encima de .swipe-nav (20) y de sus dos hojas, que son internas. */
  z-index: 21;
  will-change: transform;
}

/* Mientras la pantalla esta corrida sobresale del ancho de la ventana. Sin
   esto la pagina se puede arrastrar a lo ancho y queda una franja vacia al
   costado. `clip` y no `hidden` a proposito: `hidden` convierte al elemento en
   un contenedor de scroll y eso rompe el scroll vertical de la pagina. */
.swipe-nav-activo,
.swipe-nav-activo body {
  /* `hidden` primero como respaldo para navegadores viejos (clip llego en
     Safari 16). Se declara antes para que el que entiende clip lo pise. */
  overflow-x: hidden;
  overflow-x: clip;
}

/* Quien pidio menos movimiento igual necesita poder volver atras: el gesto
   sigue funcionando, lo que se saca es el viaje. La pantalla no vuelve ni sale
   deslizandose; al soltar, cambia y listo. */
@media (prefers-reduced-motion: reduce) {
  .swipe-nav-activo .main,
  .swipe-nav-atras,
  .swipe-nav-hoja,
  .swipe-nav {
    transition: none !important;
  }
}

/* ---------------------------------------------------------------------------
   BARRA DEL PLANNING EN TELEFONO
   ---------------------------------------------------------------------------
   Medida: 340px de los 812 de pantalla, o sea que la grilla -- que es la vista
   -- arrancaba abajo del pliegue y encima le quedaba tan poco alto que 8
   habitaciones no entraban sin scroll. El grueso se iba en el buscador y el
   filtro de estado, uno debajo del otro, en el boton de crear ocupando un
   renglon entero para el solo, y en dos separadores verticales que forzaban
   salto de linea sin aportar nada cuando los controles ya vienen apilados.
   Queda en 204px.
   ------------------------------------------------------------------------- */
@media (max-width: 980px), (pointer: coarse) {
  /* "CALENDARIO" arriba de "Habitaciones": en un telefono el titulo ya es el
     unico rotulo de la vista y el eyebrow solo suma altura. */
  .planning-toolbar .eyebrow { display: none; }

  .planning-toolbar .toolbar-title h2 {
    font-size: 17px;
    margin: 0;
  }

  /* Los separadores son reglas verticales pensadas para una fila unica. */
  .planning-toolbar .toolbar-divider { display: none; }

  /* Buscador y estado en la MISMA fila: son los dos controles que mas alto
     ocupaban y ninguno necesita el ancho entero. */
  .planning-toolbar .toolbar-group {
    flex: 1 1 100%;
  }

  .planning-toolbar .search-field,
  .planning-toolbar .compact-field {
    flex: 1 1 0;
    min-width: 0;
  }

  /* "+ Nueva reserva" ocupaba una fila entera para el solo (~80px) teniendo al
     lado del titulo todo el ancho libre. Se sube ahi. Va con position y no
     reordenando el flex porque el boton esta anidado dentro de
     .toolbar-actions, que es hermano del titulo: no hay forma de que compartan
     fila sin tocar el HTML, y ese HTML lo comparten diez vistas mas. */
  .planning-toolbar {
    position: relative;
  }

  /* 12px y no 0: `right:0` se resuelve contra la caja de PADDING de la
     toolbar, no contra su contenido, asi que el boton quedaba pegado al borde
     de la pantalla mientras el titulo respetaba el padding de 12px. */
  .planning-toolbar #open-reservation-form {
    position: absolute;
    top: 12px;
    right: 12px;
  }

  /* El grupo que lo contenia dejaria su gap con el boton fuera de flujo.
     `contents` y NO `none`: con `none` el boton, aunque sea absolute, no se
     renderiza -- un descendiente de un ancestro display:none no existe para
     el layout. Con `contents` desaparece la caja del grupo y el boton queda
     colgando directamente de .planning-toolbar, que es quien tiene el
     position:relative. */
  .planning-toolbar .toolbar-group:has(> #open-reservation-form) {
    display: contents;
  }

  /* padding-right: que el titulo no se meta abajo del boton si la vista tiene
     un nombre largo ("Estacionamiento").
     min-height: el boton esta fuera de flujo, asi que no empuja nada -- sin
     reservarle el alto, la fila de abajo ("Hoy / Ir a fecha") arrancaba a 51px
     y el boton llega a 57, y se pisaban por una esquina. */
  .planning-toolbar .toolbar-title {
    padding-right: 150px;
    min-height: 44px;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* El rack no encadena su desplazamiento con el de la pagina: al llegar al
   ultimo dia, seguir empujando movia la pagina entera detras -- parte de la
   sensacion de "suelto" que tenia el rack en el telefono. El bloqueo de eje
   (iniciarArrastreDelRack en app.js) ya evita esto mientras dura un arrastre
   tomado por nosotros; esto cubre el resto: el rebote de los extremos y los
   28px del borde, donde manda el gesto de navegacion y el desplazamiento
   queda en manos del navegador. */
.planning-wrap {
  overscroll-behavior: contain;
}

/* ===========================================================================
   EL RACK LLENA SU CAJA, SIN SOBRAS NI FALTANTES
   ===========================================================================
   Antes el alto de cada fila lo calculaba app.js (medirRack: el espacio libre
   dividido la cantidad de filas) y el CSS lo aplicaba como min-height. Eso
   fallaba por los dos lados a la vez:

   - Por defecto, la division entera perdia hasta un pixel por fila y quedaba
     una franja muerta abajo de la ultima habitacion (medidos 20px en un
     monitor con 12 habitaciones).
   - Por exceso, min-height es un PISO, no una medida: el contenido de la
     celda de la unidad (dos lineas, nombre y tipo) empujaba la fila a 35,83px
     cuando el calculo decia 35, y esos 0,83 por fila daban ~10px de
     desplazamiento vertical que el rack no deberia tener -- se podia arrastrar
     el planning hacia abajo y aparecia una franja vacia arriba.

   Ahora reparte el navegador: la grilla es una columna flexible que ocupa como
   minimo todo el alto de su caja, y cada fila pide `--alto-fila-rack` como
   base pero puede CRECER para repartirse lo que sobre. El calculo de app.js
   pasa a ser la base, no la medida final, que es lo unico que puede ser exacto
   sin conocer el contenido. =========================================================================== */
.planning-grid {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

/* La fila de fechas se queda en su alto propio: no crece con las demas. */
.planning-header {
  flex: 0 0 auto;
}

.planning-row {
  /* crece 1, no se encoge, base = lo que calculo medirRack. Sin encogerse es
     lo que hace que con muchas habitaciones el rack scrollee en vez de
     aplastar las filas hasta lo ilegible. */
  flex: 1 0 var(--alto-fila-rack, 34px);
  /* Sin esto la fila sigue pudiendo crecer por su contenido (min-height:auto
     es el valor inicial de un elemento flexible), que es justo el desborde de
     0,83px por fila que se viene a arreglar. */
  min-height: 0;
}

/* Las celdas ya se estiran solas al alto de la fila (son items de grid, que
   por defecto van en stretch), asi que el min-height que las hacia crecer deja
   de hacer falta -- y era el que empujaba la fila de mas. overflow:hidden para
   que el rotulo de la unidad, si no entra, se recorte adentro de su fila en
   vez de invadir la de abajo. */
.planning-row > .cell {
  min-height: 0;
  overflow: hidden;
}

/* Contra el alto REAL de la fila y no contra la variable: ahora la fila puede
   crecer un pixel sobre la base al repartirse el sobrante, y el bloque tiene
   que acompañarla. */
.reservation-block {
  min-height: calc(100% - 8px);
}

/* Nada de rebote: arrastrar el rack pasado el primer dia o la ultima
   habitacion no tiene que mostrar una franja vacia detras. `none` y no
   `contain` -- contain corta el encadenado con la pagina pero deja el rebote
   del propio elemento, que es justo lo que se ve como espacio vacio. */
.planning-wrap {
  overscroll-behavior: none;
}

/* ===========================================================================
   EL PLANNING OCUPA LA PANTALLA
   ===========================================================================
   El alto del rack lo calculaba app.js restando geometria (ventana menos donde
   arranca el rack menos lo que reserva .main) y lo escribia como style inline.
   Esa cuenta da bien solo si se hace en el momento justo: con la pagina
   scrolleada, con el panel de huecos abierto, con la vista todavia oculta (el
   rect da cero) o a mitad de una transicion da otro numero, y ese numero
   quedaba CONGELADO en el style hasta la proxima medicion buena. De ahi salia
   el "a veces queda mas chico de lo que tiene que estar".

   Ahora es una columna flex de alto definido y lo reparte el navegador, que lo
   rehace en cada cuadro y no se equivoca nunca: shell (alto de la pantalla) ->
   main (crece) -> #planning (crece) -> .planning-wrap (crece). No queda
   ninguna constante calibrada a ojo ni ningun momento malo en el que medir.

   Y de paso deja de ser un cuadro: sin borde a los costados ni radio ni
   sombra, y sin el padding lateral de .main, el rack llega hasta los dos
   bordes de la pantalla. El aire horizontal se lo queda solo lo que va arriba
   (la barra de herramientas, el calendario, los huecos), que es texto y si lo
   necesita. =========================================================================== */
.app-shell:has(#planning.active) {
  /* dvh y no vh: en un telefono vh es el viewport MAS GRANDE posible, el que
     habria sin la barra del navegador, asi que el rack se pasaba de pantalla. */
  height: 100dvh;
  min-height: 0;
}

.app-shell:has(#planning.active) > .main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* auto y no hidden: si en una pantalla muy baja lo de arriba no entra, se
     puede llegar igual. Con hidden quedaria recortado y sin salida. */
  overflow-y: auto;
  padding-left: 0;
  padding-right: 0;
  /* En esta vista el aire de abajo no es aire: seria una franja muerta debajo
     del rack, y la pagina quedaria scrolleable por esa diferencia. */
  padding-bottom: 0;
}

/* .view.active es display:block; el planning necesita ser columna flex para
   que el rack pueda crecer. */
#planning.active {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* Lo que va ARRIBA del rack conserva el aire lateral que .main dejo de dar. */
#planning.active > .toolbar,
#planning.active > .mini-calendar,
#planning.active > .huecos,
#planning.active > .panel {
  margin-left: clamp(16px, 1.9vw, 28px);
  margin-right: clamp(16px, 1.9vw, 28px);
}

/* El que crece. min-height:0 es lo que le permite ACHICARSE por debajo de su
   contenido -- sin eso un rack de 50 habitaciones empuja la columna y vuelve
   a aparecer el scroll de pagina. */
.app-shell:has(#planning.active) .planning-wrap {
  flex: 1 1 auto;
  min-height: 0;
  /* El techo de mas abajo (calc(100dvh - 240px - barra)) es justamente la
     constante calibrada a ojo que este bloque viene a reemplazar: con el
     techo puesto, la columna flex no puede crecer mas alla de el y el rack
     se queda corto de nuevo. */
  max-height: none;
}

@media (max-width: 980px), (pointer: coarse) {
  /* En telefono lo de abajo no es aire: es la barra de navegacion fija. Se
     reserva exactamente eso y ni un pixel mas. */
  .app-shell:has(#planning.active) > .main {
    padding-bottom: var(--mobile-bottom-nav-space, 58px);
  }
  #planning.active > .toolbar,
  #planning.active > .mini-calendar,
  #planning.active > .huecos,
  #planning.active > .panel {
    margin-left: 12px;
    margin-right: 12px;
  }
}

/* El texto del bloque, con el interlineado justo.
   Heredaba el 1,5 del documento: a 10px eso son 15px de renglon para el nombre
   y 13,5 para el estado, o sea 34,5px de contenido dentro de un bloque que en
   una fila de 36 tiene 28,6 disponibles. El bloque se desbordaba ~4px y pisaba
   la fila de abajo -- por eso la grilla se veia corrida, y por eso el rack
   tenia unos pixeles de desplazamiento vertical que no le correspondian.
   1,15 es holgado para una linea de 10px y hace que el contenido entre. */
.reservation-block {
  line-height: 1.15;
}

/* ===========================================================================
   FILTROS DE LA LISTA DE CHATS
   ===========================================================================
   Todos / Sin leer / Sin responder, con la cuenta adentro del chip. Es el
   patron de WhatsApp y de cualquier bandeja: una fila de pastillas debajo del
   buscador, una sola activa por vez.

   Los dos filtros son cosas distintas y por eso son dos: "sin leer" lo
   controla la persona (abrir un chat lo marca leido, y se puede volver a
   marcar sin leer), "sin responder" lo dice la conversacion (el ultimo mensaje
   es del huesped). Un chat leido y sin responder es justo el que se pierde, y
   antes no habia forma de encontrarlo.
   =========================================================================== */
.chat-filtros {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  /* Menos padding lateral que la barra de busqueda: los tres chips tienen que
     entrar en el ancho de la columna (298px medidos) sin deslizarse -- con tan
     pocos, una fila que hay que arrastrar esconde opciones sin que se note. */
  padding: 8px 6px;
  border-bottom: 1px solid var(--line);
  /* Red de contencion, no el modo normal: si algun dia son mas de tres o el
     idioma los alarga, se deslizan en vez de apilarse y comerle alto a la
     lista, que vive en una caja de alto fijo. */
  overflow-x: auto;
  scrollbar-width: none;
}

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

.chat-filtro {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  min-height: 30px;
  padding: 0 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.chat-filtro.activo {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  color: var(--accent-strong);
}

/* La cuenta va como NUMERO, no como pastilla adentro de la pastilla (que es
   ademas lo que hace WhatsApp). No es solo estetica: con el fondo redondo los
   tres chips ocupaban exactamente el ancho de la columna, sin un pixel de
   sobra, y con una cuenta de tres cifras ya se desbordaban. Asi sobran ~25px
   incluso en el peor caso.
   Tabular para que el ancho no baile cuando el numero se actualiza solo con
   el polling. */
.chat-filtro-cuenta {
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}

.chat-filtro.activo .chat-filtro-cuenta {
  opacity: 1;
}

/* "Sin responder" con algo pendiente es el unico que pide accion, asi que su
   numero va en el color de aviso aunque el chip este sin elegir. Sin esto los
   tres se ven igual y la barra sirve de filtro pero no de aviso -- que es la
   mitad de para lo que esta. */
/* Un rojo propio y no --red (#d9480f). Medido con canvas contra los dos fondos
   reales del chip (blanco cuando esta sin elegir, Agua cuando esta
   elegido), --red daba 4,30 y 3,69 de contraste -- los dos por debajo del 4,5
   que pide un numero de 11,5px, que no llega a "texto grande" ni en negrita.
   #b23c0c es el primero de la escala que pasa en los dos: 5,92 y 5,08. */
.chat-filtro[data-filtro="sin-responder"] .chat-filtro-cuenta {
  color: #b23c0c;
  opacity: 1;
}

/* Y al reves en oscuro: ese mismo rojo sobre el chip oscuro no se lee. Aca
   pasa a un tono claro -- 6,30 sin elegir y 4,54 elegido (sobre el Agua
   oscura, apenas por encima del 4,5). */
html[data-theme="dark"] .chat-filtro[data-filtro="sin-responder"] .chat-filtro-cuenta {
  color: #ff8f6b;
}

@media (hover: hover) and (pointer: fine) {
  .chat-filtro:not(.activo):hover {
    background: var(--surface-muted);
    color: var(--ink);
  }
}

.chat-filtro:active {
  transform: scale(0.97);
}

@media (max-width: 980px), (pointer: coarse) {
  /* 40px y no los 30 de escritorio: es un control que se toca. No llega a los
     44 del resto de los botones a proposito -- la lista de chats vive en una
     caja de alto fijo (.chat-layout) y cada pixel de esta barra es un pixel
     menos de conversaciones a la vista; con 40 de alto y 8 de separacion el
     area de toque queda holgada igual. */
  .chat-filtro {
    min-height: 40px;
    padding: 0 14px;
    font-size: 13.5px;
  }

  .chat-filtros {
    gap: 8px;
    padding: 8px 10px;
  }
}

/* ===========================================================================
   PROMO POR PAGAR EL 100%
   ===========================================================================
   Panel con el interruptor, debajo de las tarjetas de temporada y los extras
   (desde el 12/10), al lado del de cuotas. Es una promocion con fecha de
   vencimiento: al apagarla desaparece su columna de las tarjetas, que si no
   queda ocupando ancho en una tabla ya angosta.
   =========================================================================== */
/* Las dos promociones, una al lado de la otra cuando entran (y de la misma
   altura); en una pantalla angosta, una debajo de la otra. */
.tarifas-promociones {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.promo-pago-total-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.promo-pago-total-head h2 {
  margin: 0;
}

.promo-pago-total-switch {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}

/* El estado en palabras al lado del interruptor: un switch solo, sin rotulo,
   obliga a acordarse de que lado es "prendido". */
.promo-pago-total-estado {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--muted);
  letter-spacing: 0.02em;
}

.promo-pago-total-estado.activa {
  color: var(--accent-strong);
}

.promo-pago-total-panel .settings-hint {
  margin-bottom: 0;
}

/* Pago en cuotas: el mismo panel, con los dos numeros del plan debajo del
   interruptor. Angostos: son numeros de dos cifras. */
.cuotas-panel .cuotas-campos {
  grid-template-columns: repeat(2, minmax(0, 220px));
  margin-top: 14px;
}

@media (max-width: 560px) {
  .cuotas-panel .cuotas-campos {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 980px), (pointer: coarse) {
  /* El interruptor baja a su propia linea: con el titulo al lado, en 375px
     quedaban los dos apretados contra los bordes. */
  .promo-pago-total-head {
    align-items: flex-start;
  }

  .promo-pago-total-switch {
    width: 100%;
    justify-content: space-between;
  }
}

/* ===========================================================================
   LAS DOS PROMOS SE TURNAN EN LA MISMA COLUMNA
   ===========================================================================
   Con las dos a la vista (promo por noches y promo por pago total) no se
   entendia en cual de los dos precios se estaba escribiendo. Ahora comparten
   columna y el titulo es el selector: se toca el que se quiere cargar.

   Las dos capas estan en el DOM y se esconde una -- no se re-renderiza al
   cambiar, asi lo tipeado en la otra no se pierde y se guarda igual.
   =========================================================================== */
/* Los dos titulos van en una caja de adentro: el <th> sigue siendo celda, asi
   queda arriba de su columna. */
.season-promo-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}

.season-promo-tab {
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: inherit;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

/* La activa se lee como el titulo de la columna que esta abajo; la otra, como
   lo que es: un boton para cambiar. Sin esta diferencia clara vuelve el
   problema que esto viene a resolver, que era no saber donde estabas
   escribiendo. */
.season-promo-tab.activo {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
  color: var(--accent-strong);
}

@media (hover: hover) and (pointer: fine) {
  .season-promo-tab:not(.activo):hover {
    background: var(--surface-muted);
    color: var(--ink);
  }
}

.season-promo-tab:active {
  transform: scale(0.97);
}

/* Una capa por promo dentro de la misma celda; se ve la de la pestaña activa.
   La capa visible es una fila flex (precio, %, descuento): ver .season-promo-tier
   mas arriba. */
.season-price-table[data-promo-tab="promo"] .season-promo-tier[data-tier="prepaid"],
.season-price-table[data-promo-tab="prepaid"] .season-promo-tier[data-tier="promo"] {
  display: none;
}

@media (max-width: 980px), (pointer: coarse) {
  .season-promo-tab {
    min-height: 34px;
    padding: 0 10px;
  }
}

/* ===========================================================================
   FICHA DE RESERVA IMPRIMIBLE
   ===========================================================================
   Se imprime al confirmar y se archiva en el cuaderno; cuando el huesped
   llega, ese papel es todo el contexto que tiene recepcion. Por eso esta
   pensada para PAPEL y no como una vista de pantalla mas: tinta negra sobre
   blanco, bordes visibles (una tabla sin lineas no se sigue con el dedo), y
   nada que dependa de color para entenderse.
   =========================================================================== */
#ficha-impresion {
  display: none;
}

@media print {
  /* Imprimiendo la ficha: se esconde la app entera y queda solo el papel. El
     bloque @media print de mas arriba (el de Listados) fuerza #listados con
     !important, asi que aca se lo gana por especificidad (clase + id). */
  .imprimiendo-ficha .app-shell,
  .imprimiendo-ficha #listados,
  .imprimiendo-ficha #listados.view {
    display: none !important;
  }

  .imprimiendo-ficha #ficha-impresion {
    display: block;
  }

  @page {
    size: A4;
    margin: 14mm 15mm;
  }
}

.ficha {
  color: #000;
  background: #fff;
  font-size: 11pt;
  line-height: 1.35;
}

.ficha-encabezado {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding-bottom: 8px;
  border-bottom: 2px solid #000;
}

.ficha-hotel {
  margin: 0;
  font-size: 10pt;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.ficha-encabezado h1 {
  margin: 2px 0 0;
  font-size: 17pt;
  font-weight: 700;
}

/* El codigo es lo que se busca al hojear el cuaderno: va grande y a la
   derecha, que es por donde se pasan las hojas. */
.ficha-codigo {
  text-align: right;
  white-space: nowrap;
}

.ficha-codigo strong {
  display: block;
  font-size: 16pt;
  letter-spacing: 0.02em;
}

.ficha-codigo span {
  font-size: 9.5pt;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.ficha-seccion {
  margin-top: 12px;
  /* Que una seccion no quede partida entre dos hojas: media tabla de pagos en
     la pagina siguiente es justo lo que hace dudar de si esta completa. */
  break-inside: avoid;
}

.ficha-seccion h2 {
  margin: 0 0 5px;
  padding-bottom: 2px;
  border-bottom: 1px solid #000;
  font-size: 10.5pt;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.ficha-datos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 20px;
  margin: 0;
}

.ficha-dato {
  display: flex;
  gap: 6px;
  align-items: baseline;
  padding: 1.5px 0;
}

.ficha-dato dt {
  min-width: 74px;
  font-size: 9.5pt;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ficha-dato dd {
  margin: 0;
  font-weight: 600;
}

/* La cuenta en una sola columna: son cinco renglones que se leen de arriba
   abajo como un total, no datos sueltos que se puedan repartir. */
.ficha-cuenta {
  grid-template-columns: minmax(0, 1fr);
  max-width: 60%;
}

.ficha-cuenta .ficha-dato {
  justify-content: space-between;
  border-bottom: 1px dotted #999;
}

.ficha-tabla {
  width: 100%;
  border-collapse: collapse;
  font-size: 10pt;
}

.ficha-tabla th,
.ficha-tabla td {
  border: 1px solid #000;
  padding: 3px 6px;
  text-align: left;
  vertical-align: top;
}

.ficha-tabla th {
  font-size: 9pt;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ficha-num {
  text-align: right;
  white-space: nowrap;
}

.ficha-tilde {
  font-size: 8.5pt;
}

.ficha-vacio,
.ficha-nota {
  margin: 0;
}

/* Renglones en blanco para escribir a mano al recibir al huesped: la ficha
   sigue viviendo despues de imprimirse.

   El alto va en mm y no en gap entre lineas de altura cero: lo que define un
   renglon es cuanto espacio queda para escribir arriba de la raya, y 8mm es
   la separacion de un cuaderno comun. Con la separacion que tenian antes
   (2,9mm) no entraba una letra. */
.ficha-lineas {
  display: grid;
  gap: 0;
  margin-top: 8px;
}

.ficha-lineas span {
  display: block;
  height: 8mm;
  border-bottom: 1px solid #666;
}

.ficha-firmas {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px;
  margin-top: 22px;
}

.ficha-firmas span {
  display: block;
  border-bottom: 1px solid #000;
}

.ficha-firmas small {
  display: block;
  margin-top: 2px;
  font-size: 8.5pt;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ficha-pie {
  margin-top: 14px;
  padding-top: 4px;
  border-top: 1px solid #999;
  font-size: 8.5pt;
}

/* Los dos escalones de compresion de la ficha (ver ajustarFichaAUnaHoja en
   app.js). Se aplican solo cuando la ficha no entra en una hoja, y en orden:
   primero "compacta"; si con eso todavia no entra, se le suma "apretada"
   encima. Una reserva chica se imprime siempre con el tamaño comodo.

   Se toca tipografia y aire, nunca los bordes de las tablas ni el contraste:
   lo que no puede perderse al comprimir es la legibilidad de los numeros. */
.ficha.compacta {
  font-size: 10pt;
  line-height: 1.28;
}

.ficha.compacta .ficha-encabezado h1 { font-size: 15pt; }
.ficha.compacta .ficha-codigo strong { font-size: 15pt; }

.ficha.compacta .ficha-seccion {
  margin-top: 9px;
}

.ficha.compacta .ficha-seccion h2 {
  margin-bottom: 4px;
  font-size: 10pt;
}

.ficha.compacta .ficha-dato {
  padding: 0.5px 0;
}

.ficha.compacta .ficha-dato dt {
  font-size: 9pt;
  min-width: 70px;
}

.ficha.compacta .ficha-tabla {
  font-size: 9.5pt;
}

.ficha.compacta .ficha-tabla th,
.ficha.compacta .ficha-tabla td {
  padding: 2px 5px;
}

.ficha.compacta .ficha-tabla th { font-size: 8.5pt; }

.ficha.compacta .ficha-lineas span { height: 7mm; }

.ficha.compacta .ficha-firmas {
  margin-top: 16px;
}

.ficha.compacta .ficha-pie {
  margin-top: 10px;
}

/* Segundo escalon. Va despues del primero a proposito: misma especificidad,
   gana el que esta mas abajo. */
.ficha.apretada {
  font-size: 9pt;
  line-height: 1.2;
}

.ficha.apretada .ficha-encabezado h1 { font-size: 13pt; }
.ficha.apretada .ficha-codigo strong { font-size: 13pt; }
.ficha.apretada .ficha-hotel { font-size: 9pt; }

.ficha.apretada .ficha-seccion {
  margin-top: 6px;
}

.ficha.apretada .ficha-seccion h2 {
  margin-bottom: 2px;
  font-size: 9pt;
}

.ficha.apretada .ficha-dato {
  padding: 0;
}

.ficha.apretada .ficha-dato dt {
  font-size: 8pt;
  min-width: 64px;
}

.ficha.apretada .ficha-tabla {
  font-size: 8.5pt;
}

.ficha.apretada .ficha-tabla th,
.ficha.apretada .ficha-tabla td {
  padding: 1px 4px;
}

.ficha.apretada .ficha-tabla th { font-size: 8pt; }

/* Dos renglones en vez de tres, y mas cortos: es lo primero que se puede
   achicar sin perder ningun dato. Se para ahi -- por debajo de 6mm el renglon
   deja de servir para escribir, y un renglon que no sirve es peor que no
   tenerlo. */
.ficha.apretada .ficha-lineas span { height: 6mm; }

.ficha.apretada .ficha-lineas span:last-child {
  display: none;
}

.ficha.apretada .ficha-firmas {
  margin-top: 10px;
}

.ficha.apretada .ficha-pie {
  margin-top: 6px;
  font-size: 8pt;
}

/* ===========================================================================
   ACOMPANANTES (huespedes secundarios de una reserva)
   ===========================================================================
   Tres apariciones, un solo editor:
   1. .companions-field  -- el disparador en los formularios de carga. Es UNA
      fila, y ese es el punto: los campos de los acompanantes viven en el
      modal, no en el formulario, que ya es largo y se completa con el huesped
      esperando enfrente.
   2. .acompanantes-modal -- el editor.
   3. .detail-companions -- la lista ya cargada, en el detalle de la reserva.
   =========================================================================== */

/* Alto FIJO. El texto de la bajada cambia de largo segun cuantos acompanantes
   haya y cuantos huespedes declare la reserva; con `flex-wrap: wrap` a veces
   entraba en la misma linea del boton y a veces bajaba, y el bloque media 44
   o 73px segun el caso -- o sea, el formulario se movia igual aunque el
   control ya no se oculte. Sin envolver y con la bajada recortada, la fila
   mide siempre lo mismo. Lo importante (cuantos hay cargados) esta en el
   rotulo del boton, no en la bajada. */
.companions-field {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: nowrap;
  min-height: 44px;
}

.companions-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* 44px: el minimo tactil del resto del PMS (ver la auditoria mobile). */
  min-height: 44px;
}

.companions-button svg {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
}

.companions-hint {
  color: var(--muted);
  font-size: 12.5px;
  /* Se recorta en vez de envolver: envolver cambia el alto de la fila. */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 620px) {
  /* En telefono no entran los dos al lado. La bajada pasa a su propia linea
     SIEMPRE (no solo cuando no entra) y la fila vuelve a tener un alto fijo,
     ahora el de las dos lineas. */
  .companions-field {
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 2px 12px;
    min-height: 66px;
  }
  .companions-hint { flex: 1 0 100%; }
}

/* Reserva para una sola persona: el control se atenua pero NO se saca del
   flujo. Sacarlo (display:none) movia el formulario entero al pasar de 1 a 2
   huespedes -- y como vive arriba del campo de personas, se corria justo el
   selector que se estaba tocando. El alto de esta fila es constante. */
.companions-field-apagado { opacity: 0.5; }
.companions-field-apagado .companions-button { cursor: default; }

/* Mas ancho que el modal de confirmacion: adentro hay cuatro campos por
   persona, y con el ancho de un dialogo de texto quedarian uno abajo del otro
   desde el primer acompanante. */
.acompanantes-modal {
  width: min(760px, 100%);
  max-height: min(720px, 88vh);
  max-height: min(720px, 88dvh);
  gap: 12px;
}

/* En el telefono, la misma hoja que las demas (85dvh): con 88vh le ganaba a
   la regla de la hoja y en Safari pasaba el alto visible (FE-099). Dos clases
   para ganarle a la de arriba sin depender del orden. */
@media (max-width: 980px), (pointer: coarse) {
  .pms-confirm-modal.acompanantes-modal {
    max-height: 85vh;
    max-height: 85dvh;
  }
}

/* La bajada explica para que sirve la seccion: se lee entera o no sirve. La
   regla generica de .pms-confirm-modal p le pone overflow:auto (pensada para
   el mensaje largo de una confirmacion, que ahi SI puede scrollear), y en
   telefono eso la cortaba a la mitad de una oracion. Lo que scrollea aca es
   la lista, que es lo que crece. */
.acompanantes-modal > p {
  flex-shrink: 0;
  overflow: visible;
}

.acompanantes-cuerpo {
  overflow-y: auto;
  min-height: 0;
  /* Que el foco no quede tapado por el borde al tabular entre campos. */
  padding: 2px;
  margin: -2px;
}

.acompanantes-lista {
  display: grid;
  gap: 10px;
}

.acompanante-fila {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}

/* El numero de huesped, no el indice de la lista: el titular es el 1, asi que
   el primer acompanante es el 2. Es como se numera la planilla de pasajeros. */
.acompanante-numero {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.acompanante-campos {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.acompanante-campos label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  min-width: 0;
}

.acompanante-campos input {
  min-height: 40px;
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 0 8px;
  color: var(--ink);
  background: var(--surface);
  font: inherit;
}

/* El color lo pone .destructivo: quitar a alguien de la lista borra su
   ficha cargada. */
.acompanante-quitar {
  font-size: 18px;
  line-height: 1;
}

.acompanantes-pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.acompanantes-pie small {
  color: var(--muted);
  font-size: 12.5px;
}

@media (max-width: 720px) {
  /* En telefono los cuatro campos no entran en fila. El numero y el boton de
     quitar se van a un renglon propio arriba (uno en cada punta) y los campos
     se quedan con todo el ancho. La ubicacion de cada uno va explicita: el
     orden del HTML es numero -> campos -> quitar, y dejandolo a la
     colocacion automatica el boton caia debajo del numero, en la esquina de
     abajo a la izquierda. */
  .acompanante-fila {
    grid-template-columns: auto 1fr;
    align-items: start;
  }

  .acompanante-numero {
    grid-column: 1;
    grid-row: 1;
  }

  .acompanante-quitar {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
  }

  .acompanante-campos {
    grid-column: 1 / -1;
    grid-row: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* --- La lista ya cargada, dentro del detalle de la reserva --------------- */

.detail-companions {
  display: grid;
  gap: 6px;
}

.detail-companions-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.detail-companions-head .detail-form-title {
  margin: 0;
}

.detail-companions-list {
  display: grid;
  gap: 6px;
}

.companion-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

.companion-name {
  font-weight: 600;
  font-size: 13px;
}

.companion-tag {
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

/* Un menor no es un dato mas de la fila: cambia como se lo recibe (quien
   autoriza, si hace falta cama extra), asi que se marca en vez de quedar
   como un numero mas en gris. */
.companion-tag.menor {
  color: var(--tint-orange-ink);
  font-weight: 600;
}

/* ===========================================================================
   MARKETING: FILTROS Y SEGMENTOS
   ===========================================================================
   El segmento (en que quedo la reserva de esa persona) es lo que decide a
   quien se le escribe, asi que va como badge y no como texto suelto: se tiene
   que poder barrer la columna con la vista. Los colores son los mismos que ya
   usan los estados de reserva en el resto del PMS -- naranja lo que espera
   algo, verde lo confirmado, gris lo que no llego a pasar.
   =========================================================================== */
.marketing-filtros {
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.marketing-resumen {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  align-self: end;
  padding-bottom: 10px;
}

.marketing-segmento {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
  color: var(--tint-gray-ink);
  background: color-mix(in oklab, var(--gray) 14%, var(--surface));
}

.marketing-segmento.seg-confirmada {
  color: var(--tint-green-ink);
  background: color-mix(in oklab, var(--green) 14%, var(--surface));
}

.marketing-segmento.seg-pendiente {
  color: var(--tint-orange-ink);
  background: color-mix(in oklab, var(--orange) 14%, var(--surface));
}

/* El segmento de la campaña que motivo todo esto: se distingue del resto
   porque es al que hay que salir a buscar. */
.marketing-segmento.seg-sin-concretar {
  color: var(--tint-red-ink);
  background: color-mix(in oklab, var(--red) 12%, var(--surface));
}

.marketing-segmento.seg-alojado {
  color: var(--tint-blue-ink);
  background: color-mix(in oklab, var(--blue) 14%, var(--surface));
}

/* ===========================================================================
   FECHAS SIN CARGO DE UN EXTRA
   ===========================================================================
   El boton vive en la fila del extra y dice de un vistazo si hay rangos
   configurados; el editor es un modal aparte porque la lista es de largo
   variable y no entra en una fila que ya tiene cinco controles.
   =========================================================================== */
.extra-fechas {
  white-space: nowrap;
  font-size: 12px;
  min-height: 40px;
}

/* Con rangos cargados el boton deja de ser neutro: que este extra no se cobre
   en ciertas fechas es informacion, no una configuracion mas. Va en Agua (el
   fondo de lo informativo) y no en verde: el verde es de los estados. */
.extra-fechas.tiene-rangos {
  color: var(--accent-strong);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
  background: var(--accent-soft);
}

.rangos-modal {
  width: min(560px, 100%);
  gap: 12px;
}

.rangos-cuerpo {
  overflow-y: auto;
  min-height: 0;
  padding: 2px;
  margin: -2px;
}

.rangos-lista {
  display: grid;
  gap: 10px;
}

.rango-fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: 10px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}

.rango-fila label {
  display: grid;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  min-width: 0;
}

/* El color lo pone .destructivo: quitar a alguien de la lista borra su
   ficha cargada. */
.rango-quitar {
  font-size: 18px;
  line-height: 1;
}

.rangos-pie {
  display: flex;
  justify-content: flex-start;
}

@media (max-width: 620px) {
  .rango-fila {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .rango-quitar {
    grid-column: 1 / -1;
    justify-self: end;
  }
}

/* ===========================================================================
   Encuesta de calidad y mails al huesped
   =========================================================================== */

/* Con el interruptor maestro apagado, los de abajo se deshabilitan en vez de
   esconderse: asi se ve como quedaria la configuracion al volver a prenderlo. */
.feature-toggle-list.apagada {
  opacity: 0.5;
}

/* Un mail que no salio. Es el unico caso del historial que pide mirarse, asi
   que se tiñe la fila entera y no solo la fecha. */
.audit-log-row.mail-con-problema {
  background: color-mix(in srgb, var(--red) 8%, var(--surface));
}
.audit-log-row small.mail-fallado {
  color: var(--tint-red-ink);
  font-weight: 600;
  white-space: normal;
}

.pill.atencion {
  background: color-mix(in srgb, var(--yellow) 24%, var(--surface));
  border-color: color-mix(in srgb, var(--yellow) 46%, transparent);
  color: var(--tint-yellow-ink);
}

.encuestas-resumen {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* El promedio grande: es el numero que se busca al abrir el panel. */
.encuestas-promedio {
  display: flex;
  align-items: baseline;
  gap: 7px;
}
.encuestas-promedio strong {
  font-size: 26px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.encuestas-promedio span {
  font-size: 12.5px;
  color: var(--muted);
}

.encuestas-lista {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.encuesta {
  padding: 11px 13px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
}

/* Las flojas se marcan: son las que hay que atender, y mezcladas entre las de
   cinco estrellas no se encuentran. Cuando alguien ya se ocupo, la marca se
   va -- el punto es que la lista muestre lo que queda por hacer. */
.encuesta.floja {
  border-left: 3px solid var(--red);
  background: color-mix(in srgb, var(--red) 5%, var(--surface));
}
.encuesta.floja.atendida {
  border-left-color: var(--line);
  background: var(--surface);
  opacity: 0.72;
}

.encuesta-cabeza {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.encuesta-cabeza small {
  color: var(--muted);
  font-size: 11.5px;
  white-space: nowrap;
}

.encuesta-estrellas {
  color: #d99b1f;
  font-size: 14px;
  letter-spacing: 1px;
  flex-shrink: 0;
}

.encuesta-quien {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  flex: 1 1 auto;
  min-width: 0;
}

.encuesta-comentario {
  margin: 7px 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
}
.encuesta-comentario.sin-texto {
  color: var(--muted);
  font-style: italic;
}

.encuesta-atender {
  margin-top: 9px;
}

/* ===========================================================================
   Comparar periodos (Estadisticas)
   =========================================================================== */

.comparador-acciones {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* El alta: una fila de controles que cambian segun el tipo elegido. Inline y
   no en un modal a proposito -- el punto del panel es cargar varios periodos
   seguidos, y abrir y cerrar un dialogo por cada uno lo haria tedioso. */
.comparador-alta {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  margin: 14px 0 0;
  padding: 13px;
  border-radius: var(--radius);
  background: var(--surface-muted);
}
.comparador-alta .compact-field { margin: 0; }
.comparador-alta .primary-button { flex: 0 0 auto; }

@media (max-width: 620px) {
  /* En telefono cada control ocupa el ancho: apretados en fila quedan por
     debajo del minimo tactil y se elige el mes equivocado. */
  .comparador-alta { flex-direction: column; align-items: stretch; }
  .comparador-alta .compact-field,
  .comparador-alta .primary-button { width: 100%; }
}

.comparador-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin: 14px 0 0;
}

.comparador-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 7px 5px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
/* La base se distingue porque TODA la tabla se mide contra ella: sin marcarla,
   los porcentajes de las otras columnas no se sabe contra que son. */
.comparador-chip.base {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: var(--accent-soft);
}
.comparador-chip small {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-strong);
}
.comparador-quitar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--salida-ink);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}
@media (hover: hover) {
  .comparador-quitar:hover { background: color-mix(in srgb, var(--red) 12%, transparent); }
}

/* El chip base va en Agua, y en oscuro el rojo de salida encima da 4.2. */
html[data-theme="dark"] .comparador-chip.base .comparador-quitar {
  color: var(--tint-red-ink);
}

/* Sin limite de periodos: la tabla crece a lo ancho y scrollea dentro de su
   propio contenedor, nunca empuja la pagina de costado. */
.comparador-tabla-scroll {
  overflow-x: auto;
  margin: 14px 0 0;
  -webkit-overflow-scrolling: touch;
}

.comparador-tabla {
  border-collapse: collapse;
  width: 100%;
  min-width: 320px;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}

.comparador-tabla th,
.comparador-tabla td {
  padding: 9px 12px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--line);
}

/* La columna de nombres queda fija al scrollear: con seis periodos, sin esto
   no se sabe que fila se esta mirando. */
.comparador-tabla th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  text-align: left;
  font-weight: 500;
  color: var(--muted);
  background: var(--surface);
}

.comparador-tabla thead th {
  padding-bottom: 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.comparador-tabla thead th.base { color: var(--accent-strong); }

.comparador-tabla td {
  min-width: 116px;
  font-weight: 600;
  color: var(--ink);
}
.comparador-tabla td.base { color: var(--accent-strong); }

.comparador-tabla tr.destacada td,
.comparador-tabla tr.destacada th[scope="row"] {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}
.comparador-tabla tr.sangria th[scope="row"] { padding-left: 26px; font-size: 12.5px; }
.comparador-tabla tr.tenue td,
.comparador-tabla tr.tenue th[scope="row"] { color: var(--muted); font-weight: 500; }
.comparador-tabla tbody tr:last-child th,
.comparador-tabla tbody tr:last-child td { border-bottom: none; }

/* La diferencia contra la base, debajo del numero. En su propia linea y no al
   lado: al lado obliga a ensanchar cada columna y con varios periodos la
   tabla deja de entrar. */
.comparador-dif {
  display: block;
  margin-top: 1px;
  font-size: 11.5px;
  font-weight: 700;
}
.comparador-dif.mejor { color: var(--tint-green-ink); }
.comparador-dif.peor { color: var(--tint-red-ink); }
.comparador-dif.neutra { color: var(--muted); }

.comparador-nota {
  margin: 12px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}

/* ===========================================================================
   Graficos de Estadisticas: las barras horizontales
   =========================================================================== */

/* Etiqueta a la izquierda y valor a la derecha, en la misma linea y arriba de
   la barra. El valor NO va adentro de la barra: una barra corta no tiene
   lugar para el numero y recortarlo es peor que no ponerlo. */
.funnel-row strong {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}
.funnel-row strong span {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-weight: 700;
}

/* La cola agrupada se lee como lo que es: un resto, no una categoria mas. */
.funnel-row.es-otros strong,
.funnel-row.es-otros strong span { color: var(--muted); font-weight: 600; }
.funnel-row.es-otros .bar-fill { background: var(--tint-gray-ink); opacity: 0.55; }

/* Meses y años como botones marcables. Es lo que convierte "comparar enero
   contra febrero" en un solo gesto: se marcan los dos y se agrega una vez. */
.comparador-multi {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.comparador-multi-titulo {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.comparador-opciones {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.comparador-opcion {
  min-width: 42px;
  min-height: 32px;
  padding: 0 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.03em;
  cursor: pointer;
}
.comparador-opcion.marcado {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}
@media (hover: hover) {
  .comparador-opcion:hover:not(.marcado) { border-color: var(--muted); color: var(--ink); }
}
@media (max-width: 620px) {
  /* En telefono los doce meses entran en tres filas de cuatro, con el alto
     tactil minimo. Repartidos a lo ancho en vez de apretados a la izquierda. */
  .comparador-opciones { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
  .comparador-opcion { min-height: 40px; width: 100%; }
}

/* ===========================================================================
   LISTADO DE DESAYUNOS
   ===========================================================================
   Dos hojas, las dos apaisadas: la del dia (que se lleva al comedor y se va
   tildando) y la de los proximos dias (que se mira para saber con cuanta
   gente contar).

   Apaisado por pagina NOMBRADA y no con un @page suelto: un @page global
   daria vuelta tambien Entradas, Salidas y Limpieza, que se leen mejor
   verticales. Con `page: desayunos` la orientacion aplica solo a estas dos
   hojas. =========================================================================== */
@page desayunos {
  size: A4 landscape;
  margin: 9mm 10mm;
}

.listado-desayunos {
  page: desayunos;
}

.desayunos-encabezado {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-bottom: 7px;
  border-bottom: 2px solid var(--ink);
}
.desayunos-encabezado .eyebrow { margin: 0; }
.desayunos-encabezado h2 { margin: 1px 0 0; font-size: 19px; font-weight: 700; }

.desayunos-totales {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 14px;
  font-size: 13px;
  color: var(--muted);
}
.desayunos-totales strong {
  font-size: 17px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.desayunos-fecha { font-weight: 600; color: var(--ink); }

.desayunos-aviso {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--muted);
}

/* La lista fluye en columnas. Es lo que hace que entren muchas habitaciones
   en una hoja: apaisada, una columna de 78mm entra tres veces, asi que 51
   habitaciones (ocupacion total de Santa Teresita) caben en UNA hoja en vez
   de tres. Una <table> no puede fluir en columnas; por eso es una lista. */
.desayunos-lista {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  columns: 78mm;
  column-gap: 10mm;
  column-rule: 1px solid var(--line);
}

.desayuno-item {
  display: grid;
  grid-template-columns: 16px 46px 26px minmax(0, 1fr);
  align-items: center;
  gap: 7px;
  padding: 3.5px 0;
  border-bottom: 1px solid var(--line);
  font-size: 12.5px;
  /* Una fila partida entre el pie de una columna y la cabeza de la siguiente
     es ilegible y ademas rompe el tildado. */
  break-inside: avoid;
}

/* El cuadradito para tildar cuando llegan. Se dibuja con borde y no con un
   caracter: un ☐ depende de la fuente y en la impresora sale de cualquier
   tamaño. */
.desayuno-tilde {
  width: 13px;
  height: 13px;
  border: 1.5px solid var(--ink);
  border-radius: 2px;
}

.desayuno-hab { font-weight: 700; font-variant-numeric: tabular-nums; }
.desayuno-pax {
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.desayuno-huesped {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
}

/* La cabecera se repite arriba de cada columna: con tres columnas, saber cual
   numero es "pax" no puede depender de mirar la primera. */
.desayuno-cabecera {
  border-bottom: 1.5px solid var(--ink);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.desayuno-cabecera .desayuno-hab,
.desayuno-cabecera .desayuno-pax,
.desayuno-cabecera .desayuno-huesped { font-weight: 700; color: var(--muted); }
.desayuno-cabecera .desayuno-tilde { border: 0; }

.desayuno-vacio {
  padding: 14px 0;
  color: var(--muted);
  font-size: 13px;
}

/* --- La segunda hoja --------------------------------------------------- */
.hoja-proximos {
  /* Siempre empieza en hoja nueva: son dos papeles distintos, uno va al
     comedor y el otro a la cocina. */
  break-before: page;
  margin-top: 26px;
}

.proximos-tabla {
  width: 100%;
  border-collapse: collapse;
  margin-top: 10px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.proximos-tabla th,
.proximos-tabla td {
  padding: 6px 10px;
  text-align: left;
  border-bottom: 1px solid var(--line);
}
.proximos-tabla th {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1.5px solid var(--ink);
}
.proximos-tabla .num { text-align: right; width: 84px; }
.proximos-tabla td strong { font-size: 15px; }
.proximos-tabla tr.dia-vacio td { color: var(--muted); }

/* Una barra por dia: el pico de la quincena se ve sin leer numero por numero,
   que es para lo que se mira esta hoja. */
.proximos-tabla .carga { width: 30%; padding-right: 0; }
.proximos-tabla .carga span {
  display: block;
  height: 9px;
  min-width: 1px;
  border-radius: var(--radius-pill);
  background: var(--chart-1);
}

@media print {
  /* En la hoja impresa el gris claro se pierde y el color gasta tinta: todo
     negro sobre blanco, que es como se lee un papel de cocina. Se listan los
     hijos uno por uno porque cada uno trae su propio color de token y
     `color: inherit` no alcanza contra una regla que lo fija. */
  .listado-desayunos,
  .listado-desayunos .eyebrow,
  .listado-desayunos .desayunos-totales,
  .listado-desayunos .desayunos-totales strong,
  .listado-desayunos .desayunos-aviso,
  .listado-desayunos .desayuno-huesped,
  .listado-desayunos .desayuno-cabecera,
  .listado-desayunos .desayuno-cabecera span,
  .listado-desayunos .proximos-tabla th,
  .listado-desayunos .proximos-tabla td,
  .listado-desayunos .proximos-tabla tr.dia-vacio td {
    color: #000;
  }
  /* Las lineas finas en gris claro desaparecen en papel. */
  .listado-desayunos .desayuno-item,
  .listado-desayunos .proximos-tabla td { border-bottom-color: #bbb; }
  .listado-desayunos .desayunos-lista { column-rule-color: #bbb; }
  .proximos-tabla .carga span { background: #000; }
  /* La cabecera de la tabla se repite en cada hoja si la quincena se parte. */
  .proximos-tabla thead { display: table-header-group; }
  .proximos-tabla tr { break-inside: avoid; }
  /* El cuadradito tiene que verse si o si: es para lo que se imprime. */
  .desayuno-tilde { border-color: #000; }
}

/* ===========================================================================
   CAFETERIA: TRES PANTALLAS, NO TRES SECCIONES APILADAS
   ===========================================================================
   Antes el punto de venta era una pila: la grilla de productos, mas abajo el
   ticket, mas abajo todavia el cobro. Atender una mesa era bajar dos veces y
   volver a subir, y el boton "Cobrar" (arriba, en el ticket) abria un panel
   que quedaba fuera de la pantalla -- tanto que hubo que agregarle un scroll
   automatico para que se notara que habia hecho algo.

   Ahora son tres pantallas que se turnan en el mismo lugar: el salon, el
   pedido de una mesa, y el cobro de ese pedido. Una sola visible a la vez, y
   se vuelve con la flecha. =========================================================================== */
.gastro-pos {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
}

.gastro-pantalla {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
}
.gastro-pantalla.hidden { display: none; }

.gastro-pantalla-cabeza {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.gastro-pantalla-titulo {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1 1 auto;
  min-width: 0;
}
.gastro-pantalla-titulo h3 {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  color: var(--ink);
}
.gastro-pantalla-titulo span {
  font-size: 12.5px;
  color: var(--muted);
}

/* --- El salon ----------------------------------------------------------- */
/* Cuadrados de verdad: mismo alto que ancho, para que el salon se lea como un
   plano y no como una lista. auto-fill y no auto-fit: con tres mesas
   cargadas, auto-fit las estira a lo ancho de la pantalla y cada una queda
   del tamaño de un cartel. */
.gastro-mesas-grilla {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(124px, 1fr));
  gap: 10px;
}

.gastro-mesa {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 4px;
  aspect-ratio: 1 / 1;
  min-height: 108px;
  padding: 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Ocupada se lee de lejos: el salon se mira de un vistazo para saber a cual
   hay que ir. El borde teñido y el fondo son la señal; el importe, el dato. */
.gastro-mesa.ocupada {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: var(--accent-soft);
}

.gastro-mesa-nombre {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.gastro-mesa-total {
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent-strong);
  line-height: 1.1;
}
.gastro-mesa-estado {
  font-size: 11.5px;
  color: var(--muted);
}
.gastro-mesa-estado.libre { color: var(--muted); }

@media (hover: hover) {
  .gastro-mesa:hover { border-color: var(--accent); }
}
.gastro-mesa:active:not(:disabled) { transform: scale(0.98); }
.gastro-mesa:disabled { opacity: 0.6; cursor: default; }

@media (max-width: 620px) {
  /* En telefono entran dos por fila con el dedo comodo. Se suelta el
     cuadrado perfecto: con dos columnas angostas quedarian demasiado altas. */
  .gastro-mesas-grilla { grid-template-columns: repeat(2, 1fr); }
  .gastro-mesa { aspect-ratio: auto; min-height: 96px; }
}

/* --- El cobro, ahora pantalla --------------------------------------------- */
.gastro-cobro-cuerpo {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
#gastro-pantalla-cobro .gastro-cobro-falta { margin: 0; }
/* A lo ancho de una pantalla de escritorio, el monto de cada parte quedaba a
   1.300px de su medio y el vuelto en la otra punta: no se leia que numero era
   de quien. El cobro es una columna angosta, como un ticket. */
#gastro-pantalla-cobro { width: 100%; max-width: 640px; }
#gastro-pantalla-cobro > .primary-button { margin-top: 2px; }

/* La cafeteria ocupa la pantalla, igual que el planning y por el mismo motivo:
   el punto de venta se usa de pie y lo que no entra tiene que scrollear
   ADENTRO de su caja, nunca mover la pagina. Sin esto, con una carta larga la
   grilla de productos empuja el ticket fuera de la pantalla y hay que bajar
   para ver lo que se lleva cargado. */
.app-shell:has(#gastronomia.active) {
  height: 100dvh;
  min-height: 0;
}
.app-shell:has(#gastronomia.active) > .main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* auto y no hidden: los paneles de historial, carta y cierre viven en esta
     misma vista y pueden ser mas altos que la pantalla. */
  overflow-y: auto;
}
#gastronomia.active {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
#gastronomia.active #gastro-pos { flex: 1 1 auto; min-height: 0; }
#gastronomia.active #gastro-pantalla-pedido,
#gastronomia.active #gastro-pantalla-mesas { flex: 1 1 auto; min-height: 0; }

/* El salon scrollea solo cuando hay muchas mesas. */
#gastronomia.active .gastro-mesas-grilla {
  overflow-y: auto;
  align-content: start;
  min-height: 0;
}

#gastronomia.active .gastro-layout {
  flex: 1 1 auto;
  min-height: 0;
  /* La regla base trae align-items:start, que deja a las dos columnas con el
     alto de su contenido -- y entonces la grilla de productos crece sin techo
     y el que scrollea termina siendo .main. Con stretch mas una fila de
     minmax(0,1fr), las columnas miden lo que mide la caja y la grilla puede
     achicarse por debajo de su contenido, que es lo que la hace scrollear a
     ella. */
  align-items: stretch;
  grid-template-rows: minmax(0, 1fr);
}
#gastronomia.active .gastro-menu {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* La grilla de productos es la unica que crece: el buscador y los chips
   quedan fijos arriba, que es lo que permite filtrar sin volver a subir. */
#gastronomia.active .gastro-productos {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
#gastronomia.active .gastro-ticket {
  max-height: 100%;
  overflow-y: auto;
}

/* En el TELEFONO la cadena de alto completo no alcanza: la barra del turno
   (que ahi va al final, ver el max-width: 900px de la cafeteria) comparte el
   alto de la pantalla con la del pedido o la del cobro, y como todas pueden
   achicarse (min-height: 0), la que se aplastaba era la pantalla. Medido a
   380x800: la grilla de productos media 0px (no se podia cargar nada) y la
   barra del turno tapaba las partes del cobro y el boton de confirmar. Ahi
   se vuelve al scroll de siempre: cada pantalla mide lo que su contenido y
   scrollea .main, con el resumen del turno al final. */
@media (max-width: 900px) {
  #gastronomia.active #gastro-pos > * { flex-shrink: 0; }
  #gastronomia.active .gastro-layout { grid-template-rows: none; }
  #gastronomia.active .gastro-productos { overflow-y: visible; }
  #gastronomia.active .gastro-ticket { max-height: none; overflow-y: visible; }
}

/* ===========================================================================
   Ubicacion sugerida (17/09): la mejor habitacion para una estadia, debajo del
   resultado de disponibilidad, y las reservas que conviene mover para cerrar
   huecos, dentro del panel de huecos del planning. Lo calcula el backend.
   =========================================================================== */
.ubicacion-sugerida {
  display: grid;
  gap: 6px;
}

.ubicacion-linea {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 12px;
  margin: 0;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: 13px;
}

.ubicacion-linea > span { flex: 1 1 240px; min-width: 0; }
.ubicacion-linea .ghost-button { flex: 0 0 auto; }
.ubicacion-linea.es-buena { border-left-color: var(--green); }

/* Amarillo apagado y no el acento: un upgrade regala categoria y tiene que
   leerse distinto de "esta es la mejor opcion". */
.ubicacion-linea.es-upgrade {
  border-left-color: var(--yellow);
  background: color-mix(in srgb, var(--yellow) 10%, var(--surface));
}

.huecos-subtitulo {
  grid-column: 1 / -1;
  margin: 6px 2px 0;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.movimiento {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "quien aplicar"
    "que aplicar"
    "por aplicar";
  gap: 0 12px;
  align-items: center;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
}

.movimiento.es-upgrade { border-left-color: var(--yellow); }
.movimiento-quien { grid-area: quien; font-weight: 600; font-size: 13.5px; overflow-wrap: anywhere; }
.movimiento-que { grid-area: que; font-size: 12.5px; }
.movimiento-por { grid-area: por; font-size: 11.5px; color: var(--muted); }
.movimiento-aplicar { grid-area: aplicar; }

.movimiento-etiqueta {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--yellow) 28%, var(--surface));
  color: var(--ink);
  font-size: 10.5px;
  font-weight: 600;
  white-space: nowrap;
}

/* ===========================================================================
   VOUCHER DE INGRESO
   Replica del papel que la hosteria ya usa. Se imprime al entrar el huesped y
   se completa a mano durante la estadia.

   Apaisado por pagina NOMBRADA (mismo criterio que el listado de desayunos):
   un @page suelto daria vuelta tambien la ficha de reserva, que es vertical.

   Las reglas viven FUERA de @media print a proposito, igual que .ficha: asi lo
   que se mide y se ve en pantalla predice la hoja impresa.
   =========================================================================== */
@page voucher {
  size: A4 landscape;
  margin: 8mm 9mm;
}

.voucher {
  page: voucher;
  font-family: Arial, Helvetica, sans-serif;
  color: #000;
  font-size: 8.5pt;
  line-height: 1.15;
}

.voucher * {
  box-sizing: border-box;
}

/* --- cabecera ------------------------------------------------------------ */
.v-cabecera {
  display: flex;
  align-items: flex-start;
  gap: 10mm;
  margin-bottom: 2mm;
}

.v-marca {
  flex: 0 0 auto;
  line-height: 1;
}

.v-marca span {
  display: block;
  font-style: italic;
  font-size: 11pt;
}

.v-marca strong {
  display: block;
  font-size: 19pt;
  letter-spacing: 0.5px;
}

.v-contacto {
  flex: 1 1 auto;
  font-size: 7.5pt;
  padding-top: 1mm;
}

.v-numero {
  flex: 0 0 auto;
  font-size: 12pt;
  white-space: nowrap;
}

/* El renglon para escribir el numero a mano queda igual: el codigo de reserva
   se imprime encima, pero el papel se sigue numerando aparte. */
.v-numero span {
  display: inline-block;
  min-width: 34mm;
  border-bottom: 1px solid #000;
  text-align: center;
  font-size: 10pt;
}

/* --- nombre + leyenda ---------------------------------------------------- */
.v-titular {
  display: flex;
  align-items: flex-end;
  gap: 4mm;
  margin-bottom: 1.5mm;
}

.v-linea {
  flex: 1 1 auto;
  display: flex;
  align-items: flex-end;
  gap: 2mm;
}

.v-linea em {
  flex: 0 0 auto;
  font-size: 11pt;
  font-style: italic;
  text-decoration: underline;
}

.v-linea > span {
  flex: 1 1 auto;
  border-bottom: 1px solid #000;
  font-size: 10pt;
  padding-bottom: 0.5mm;
}

.v-nofactura {
  flex: 0 0 auto;
  border: 1.5px solid #000;
  padding: 0.8mm 2mm;
  font-size: 10pt;
  font-weight: 700;
}

.v-nofactura b {
  border-right: 1.5px solid #000;
  padding-right: 2mm;
  margin-right: 2mm;
}

/* --- las 12 cajas numeradas ---------------------------------------------- */
/* Cuatro por fila, como el papel. Se reparten el ancho segun cuantas celdas
   tiene cada una para que ninguna quede apretada. */
.v-grilla {
  display: flex;
  flex-wrap: wrap;
  gap: 1mm;
  margin-bottom: 1.5mm;
}

.v-caja {
  display: flex;
  align-items: stretch;
  gap: 1mm;
  flex: 1 1 calc(25% - 1mm);
  min-width: 0;
}

.v-num {
  flex: 0 0 15mm;
  font-size: 6.5pt;
  font-weight: 700;
  font-style: italic;
  align-self: center;
  text-align: right;
}

.v-celdas {
  flex: 1 1 auto;
  display: flex;
  border: 1px solid #000;
  min-width: 0;
}

.v-celda {
  flex: 1 1 0;
  min-width: 0;
  border-right: 1px solid #000;
  display: flex;
  flex-direction: column;
}

.v-celda:last-child {
  border-right: 0;
}

.v-rotulo {
  display: block;
  border-bottom: 1px solid #000;
  padding: 0.4mm 1mm;
  font-size: 6.5pt;
  font-weight: 700;
  font-style: italic;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
}

/* La caja donde se escribe. El alto fijo es lo que hace que entre una lapicera
   y que todas las cajas de una fila queden parejas. */
.v-valor {
  display: block;
  min-height: 7mm;
  padding: 1mm;
  font-size: 8.5pt;
  text-align: center;
  overflow: hidden;
}

/* CHECK IN / CHECK OUT: el rotulo ocupa la celda entera, sin renglon debajo. */
.v-fija {
  flex: 0 0 auto;
  justify-content: center;
}

.v-fija .v-rotulo {
  border-bottom: 0;
  padding: 1mm 1.5mm;
}

/* Los dos totales: el numero grande, como en el papel. */
.v-plata .v-valor {
  font-size: 11pt;
  font-weight: 700;
  text-align: left;
  padding-left: 2mm;
  min-height: 9mm;
}

/* --- observaciones + datos del huesped ----------------------------------- */
.v-medio {
  display: flex;
  gap: 1.5mm;
  margin-bottom: 1.5mm;
}

.v-observaciones,
.v-datos {
  border: 1px solid #000;
  padding: 1mm 1.5mm;
}

.v-observaciones {
  flex: 1 1 50%;
}

.v-datos {
  flex: 1 1 50%;
}

.v-observaciones strong {
  font-size: 9pt;
  text-decoration: underline;
}

.v-renglon {
  display: block;
  border-bottom: 1px solid #000;
  height: 4.5mm;
}

.v-datos p {
  display: flex;
  align-items: flex-end;
  gap: 1.5mm;
  margin: 0 0 1mm;
}

.v-datos strong {
  flex: 0 0 auto;
  font-size: 8pt;
  text-decoration: underline;
}

.v-datos span {
  flex: 1 1 auto;
  border-bottom: 1px solid #000;
  min-height: 4mm;
  font-size: 8pt;
}

/* --- la cuenta corriente por dia ----------------------------------------- */
/* Queda toda vacia: se completa a mano, un renglon por dia de estadia. */
.v-cuenta {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.v-cuenta th,
.v-cuenta td {
  border: 1px solid #000;
  height: 5.2mm;
  font-size: 7.5pt;
}

.v-cuenta thead td {
  font-style: italic;
  font-weight: 700;
  text-align: left;
  padding-left: 1mm;
}

.v-cuenta th {
  width: 26mm;
  text-align: left;
  padding-left: 1.5mm;
  font-style: italic;
  font-weight: 700;
}

.v-cuenta thead th {
  text-align: center;
  padding-left: 0;
}

.v-suma th {
  font-weight: 700;
}

/* ===========================================================================
   FACTURACION ELECTRONICA — el asistente del certificado
   Un paso por vez: el que ya se hizo queda tenue, el que toca ahora resaltado.
   El sistema que usaba el hotel antes muestra los veinte pasos como una sola
   pared de texto, y ahi es donde la gente se pierde.
   =========================================================================== */
.afip-pasos {
  list-style: none;
  counter-reset: afip;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.afip-pasos > li {
  counter-increment: afip;
  position: relative;
  padding: 12px 14px 12px 44px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* El numerito del paso. Va como ::before y no como texto para que el orden
   salga solo si se agrega o saca un paso. */
.afip-pasos > li::before {
  content: counter(afip);
  position: absolute;
  left: 12px;
  top: 12px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.afip-pasos > li.actual {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: color-mix(in srgb, var(--accent) 5%, var(--surface));
}

.afip-pasos > li.actual::before {
  background: var(--accent);
  color: var(--on-accent);
}

/* Un paso ya hecho no se esconde: sigue visible para poder volver a el (por
   ejemplo a re-descargar el archivo), pero sin competir por la atencion. */
.afip-pasos > li.hecho {
  opacity: 0.72;
}

.afip-pasos > li.hecho::before {
  content: "✓";
  background: var(--green);
  color: #fff;
}

/* Solo el titulo del paso va en su propia linea. El selector va con ">" a
   proposito: sin eso, los <strong> que resaltan el nombre de una pantalla de
   ARCA dentro de los sub-pasos se partian en renglones sueltos. */
.afip-pasos > li > strong {
  display: block;
  font-size: 14px;
  margin-bottom: 2px;
}

.afip-pasos > li > p {
  margin: 0 0 8px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.45;
}

.afip-ok {
  color: var(--tint-green-ink);
}

.afip-subpasos {
  margin: 0;
  padding-left: 18px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.6;
}

.afip-subpasos code {
  background: var(--surface-muted);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 12px;
}

.afip-subir {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.afip-subir textarea {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  resize: vertical;
}

/* La factura de un pago, debajo del importe en el detalle de la reserva.
   Es una linea de dato, no un chip: el chip de al lado del importe ya dice el
   estado del PAGO, y dos chips pegados compiten entre si. */
.pago-factura {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  color: var(--muted);
}
.pago-factura.ok {
  color: var(--tint-green-ink);
  font-weight: 600;
}
.pago-factura.error {
  color: var(--tint-red-ink);
}
.pago-factura .link-button {
  font-size: 11.5px;
}

/* Una habitacion guardada sin reserva. Tiene que leerse como "esto no se
   vende" y a la vez NO confundirse con una reserva: por eso va en gris, con
   rayas y sin ninguno de los colores de estado. El rayado es lo que la
   distingue de un bloque comun a la distancia, cuando el texto no entra. */
.reservation-block.bloqueo-de-habitacion {
  background-image: repeating-linear-gradient(
    -45deg,
    var(--line) 0 7px,
    var(--surface-muted) 7px 14px
  );
  background-color: var(--surface-muted);
  color: var(--muted);
  /* Un paso hacia --muted desde la raya (mas oscuro en claro, mas claro en
     oscuro): con --line a secas el borde punteado se perdia sobre las rayas
     del mismo color. */
  border: 1px dashed color-mix(in srgb, var(--muted) 30%, var(--line));
  cursor: pointer;
}
.reservation-block.bloqueo-de-habitacion .reservation-block-name {
  font-weight: 600;
}
/* color: inherit por lo mismo que .cancelada/.finalizada: el bloqueo sigue al
   tema, y el gris oscuro fijo de .reservation-block small quedaba ilegible
   sobre las rayas del modo oscuro. */
.reservation-block.bloqueo-de-habitacion small {
  color: inherit;
}

/* La lista de habitaciones del modal de bloqueo: varias columnas, porque un
   hotel de 51 habitaciones en una sola columna es un modal con scroll infinito. */
.bloqueo-habitaciones {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 2px 14px;
  max-height: 260px;
  overflow-y: auto;
}
.bloqueo-habitacion small {
  color: var(--muted);
  font-weight: 400;
}

/* Tres botones: cancelar, liberar todas, liberar solo esta. En telefono se
   apilan; el primario queda abajo, que es donde cae el pulgar. */
.soltar-bloqueo-actions {
  flex-wrap: wrap;
  gap: 8px;
}
@media (max-width: 520px) {
  .soltar-bloqueo-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
}

/* ---------------------------------------------------------------------------
   Carta del restaurante (Configuracion)

   Los precios que se tocan aca son los que ve el publico en la pagina del
   restaurante. Con ~230 platos, la fila tiene que ser corta: nombre y precio,
   uno al lado del otro. El resto de los campos (descripcion, porciones, stock)
   se despliega con el boton de los puntos, porque casi nunca se cambian.
   --------------------------------------------------------------------------- */

.carta-acciones { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.carta-pendientes {
  font-size: 0.85rem; font-weight: 600; color: var(--tint-orange-ink);
}

.carta-toolbar { display: flex; gap: 10px; margin: 14px 0 6px; flex-wrap: wrap; }
.carta-toolbar input {
  flex: 1 1 240px; min-height: 40px; padding: 0 14px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--ink); font: inherit;
}

.carta-editor { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }

.carta-cat {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.carta-cat-head {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 10px 4px 4px;
}
.carta-cat-toggle {
  display: flex; align-items: center; gap: 10px; flex: 1;
  padding: 10px 8px; border: 0; background: transparent;
  font: inherit; font-weight: 600; color: var(--ink);
  text-align: left; cursor: pointer; min-height: 44px;
}
/* La flecha se dibuja con un borde girado: un caracter depende de la fuente y
   sale de cualquier tamaño segun el sistema. */
.carta-cat-flecha {
  width: 7px; height: 7px; flex: 0 0 auto; margin-left: 4px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg); transition: transform 0.16s ease;
}
.carta-cat.abierta .carta-cat-flecha { transform: rotate(45deg); }
.carta-cat-cuenta { font-size: 0.85rem; color: var(--muted); white-space: nowrap; }

.carta-grupo { padding: 0 14px 12px; }
.carta-grupo-nombre {
  margin: 10px 0 6px; font-size: 0.74rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); font-weight: 600;
}

.carta-platos { list-style: none; margin: 0; padding: 0; }

.carta-plato {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 130px auto auto;
  align-items: center; gap: 8px;
  padding: 5px 0; border-bottom: 1px solid var(--surface-muted);
}
.carta-plato:last-child { border-bottom: 0; }
.carta-plato.sin-stock .carta-plato-nombre { text-decoration: line-through; color: var(--muted); }

.carta-plato input[type="text"],
.carta-plato-precio,
.carta-plato-detalle input:not([type="checkbox"]) {
  min-height: 38px; padding: 0 10px;
  border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--ink); font: inherit; width: 100%;
}
.carta-plato input:hover { border-color: var(--line); }
.carta-plato input:focus { border-color: var(--focus-outline); background: var(--surface); outline: none; }

.carta-plato-precio {
  text-align: right; font-variant-numeric: tabular-nums; font-weight: 600;
  background: var(--surface-muted) !important; border-color: var(--line) !important;
}
.carta-plato-precio:focus { border-color: var(--focus-outline) !important; }

.carta-plato-mas { min-height: 34px; padding: 0 10px; font-size: 0.95rem; letter-spacing: 0.06em; }

/* Los campos secundarios ocupan toda la fila, debajo. */
.carta-plato-detalle {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; padding: 10px 2px 12px;
}
.carta-plato-detalle label { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; color: var(--muted); }
.carta-plato-detalle label.wide { grid-column: 1 / -1; }
.carta-plato-detalle input:not([type="checkbox"]) { border-color: var(--line); background: var(--surface); }
.carta-plato-stock { flex-direction: row !important; align-items: center; gap: 8px; align-self: end; min-height: 38px; }

.carta-agregar-plato { margin-top: 8px; }

@media (max-width: 640px) {
  .carta-plato { grid-template-columns: minmax(0, 1fr) 104px auto auto; gap: 4px; }
  .carta-acciones { width: 100%; }
}

/* ---------------------------------------------------------------------------
   Estadisticas de la web (pestaña "Web")

   Barras horizontales de un solo color, ordenadas, con el valor AL LADO de la
   etiqueta y nunca adentro de la barra: una barra corta no tiene lugar para
   el numero y recortarlo es peor que no ponerlo. Mismo criterio que la lista
   de extras de Estadisticas.
   --------------------------------------------------------------------------- */

.web-rango { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.web-atajos { display: inline-flex; gap: 2px; }

.stats-grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }

.web-subtitulo {
  margin: 22px 0 10px; font-size: 0.74rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted); font-weight: 600;
}

.web-barras { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.web-barra-fila {
  display: flex; align-items: baseline; gap: 12px; margin-bottom: 5px;
}
.web-barra-nombre { color: var(--ink); font-size: 0.93rem; }
.web-barra-fila b { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--ink); }
.web-barra-riel {
  height: 8px; border-radius: 999px; background: var(--surface-muted); overflow: hidden;
}
.web-barra-riel span {
  display: block; height: 100%; border-radius: 999px;
  background: var(--chart-1); min-width: 2px;
}

/* El embudo. Cada escalon se dibuja contra el ancho del primero, asi la
   caida se ve como una escalera y no hay que leer los numeros. */
.web-embudo { display: flex; flex-direction: column; gap: 18px; margin-top: 14px; }
.web-paso-cabeza { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; }
.web-paso-nombre { font-weight: 600; color: var(--ink); }
.web-paso-cabeza b { margin-left: auto; font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.web-paso-riel { height: 12px; border-radius: 999px; background: var(--surface-muted); overflow: hidden; }
.web-paso-riel span {
  display: block; height: 100%; border-radius: 999px;
  /* Un solo color, el de las demas barras de datos: el degradado va solo
     en el logo, y el turquesa oscuro es el del boton principal. */
  background: var(--chart-1);
}
.web-paso-nota { margin: 6px 0 0; font-size: 0.84rem; color: var(--muted); }
.web-caida { color: var(--tint-red-ink); }

.web-privacidad { margin-top: 18px; }

.tabla-simple { width: 100%; border-collapse: collapse; margin-top: 12px; }
.tabla-simple th, .tabla-simple td {
  padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--line);
}
.tabla-simple th {
  font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
.tabla-simple td { color: var(--ink); }
.tabla-simple .num { text-align: right; font-variant-numeric: tabular-nums; }
.tabla-simple tbody tr:last-child td { border-bottom: 0; }

@media (max-width: 640px) {
  .web-rango { width: 100%; }
  .web-rango .compact-field { flex: 1 1 140px; }
}

/* ---------------------------------------------------------------------------
   El detalle de una reserva, en maestro-detalle

   Mismo patron que Configuracion y Estadisticas, pero el detalle de una
   reserva vive en un panel LATERAL que cambia de ancho segun la pantalla y
   segun si la lista esta abierta. Por eso el menu se adapta al ancho del
   CONTENEDOR y no al de la ventana (container query): con lugar es una
   columna de categorias como en Configuracion, y cuando no lo hay pasa a una
   tira de chips arriba del contenido.

   La tira NO es el maestro-detalle de Configuracion escondido: ahi elegir una
   categoria "navega" y hay que volver, y el detalle de una reserva en
   telefono YA es una pantalla completa con su propio boton de volver. Dos
   "volver" anidados es justo lo que confunde.
   --------------------------------------------------------------------------- */

.reservation-detail { container-type: inline-size; container-name: detalle; }

.detalle-shell.settings-shell .settings-sidebar { display: flex; }
.detalle-shell.settings-shell .settings-detail { display: block; }

.detalle-shell { grid-template-columns: minmax(150px, 178px) minmax(0, 1fr); gap: 16px; }
.detalle-shell .settings-sidebar { gap: 0; }
.detalle-shell .settings-nav { padding: 4px; box-shadow: none; }
.detalle-shell .settings-nav-item {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px; font-size: 13px;
}
/* Los iconos vienen de detailSectionIcon(), el mismo que tenian los titulos
   de las secciones cuando estaban apiladas. */
.detalle-shell .settings-nav-item svg { width: 15px; height: 15px; flex: 0 0 auto; opacity: 0.75; }
.detalle-shell .settings-nav-item.active svg { opacity: 1; }
.detalle-shell .settings-detail-title { font-size: 16px; margin-bottom: 4px; }

/* Lo que el <h3> de la seccion traia al lado (el link a la ficha del
   cliente): pasa a ser una accion de la categoria, alineada a la derecha. */
.detalle-grupo-acciones { display: flex; justify-content: flex-end; margin: -2px 0 6px; }

/* Sin lugar para la columna: tira de chips arriba, con scroll horizontal
   propio y el panel siempre visible debajo. */
@container detalle (max-width: 620px) {
  .detalle-shell { display: block; }
  .detalle-shell .settings-sidebar { position: static; margin-bottom: 14px; }
  .detalle-shell .settings-nav {
    flex-direction: row; gap: 6px;
    overflow-x: auto; scrollbar-width: none;
    scroll-snap-type: x proximity;
    background: none; border: 0; padding: 0;
  }
  .detalle-shell .settings-nav::-webkit-scrollbar { display: none; }
  .detalle-shell .settings-nav-item {
    flex: 0 0 auto; width: auto;
    border: 1px solid var(--line); border-radius: 999px;
    padding: 8px 14px; background: var(--surface);
    white-space: nowrap;
    scroll-snap-align: start;
    /* Alto minimo de toque: la tira se usa con el pulgar. */
    min-height: 40px;
  }
  /* Agua de fondo: la regla de arriba pone --surface y le ganaba al tinte de
     .settings-nav-item.active (misma especificidad, mas abajo). */
  .detalle-shell .settings-nav-item.active { border-color: var(--accent); background: var(--accent-soft); }
  /* El detalle se ve siempre: sin esto quedaria oculto hasta elegir, que es
     un paso de mas sobre una pantalla que antes mostraba todo. */
  .detalle-shell .settings-detail { display: block; }
  .detalle-shell .settings-detail-back { display: none; }
}

/* Los navegadores sin container queries caen aca: columna siempre, que es el
   comportamiento correcto aunque quede mas angosta. */
@supports not (container-type: inline-size) {
  .detalle-shell { grid-template-columns: minmax(140px, 168px) minmax(0, 1fr); }
}

/* La descripcion de un extra: texto libre, a ancho completo debajo de la fila
   (que ya tiene siete columnas y no le entra otra). */
.extra-descripcion-campo {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 6px;
  font-size: 0.74rem; letter-spacing: 0.04em; color: var(--muted);
}
.extra-descripcion-campo input,
.extra-descripcion-campo textarea {
  min-height: 36px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 13px;
}
/* El detalle es de varias lineas (una por cosa que incluye), asi que
   necesita su propio alto y respetar los saltos que escribe el hotel. */
.extra-descripcion-campo textarea {
  padding: 8px 10px;
  line-height: 1.45;
  resize: vertical;
}

/* Los datos del auto. Mismo bloque en los dos formularios de carga y en el
   detalle: aparece solo cuando la reserva lleva estacionamiento. Se marca
   como un sub-bloque (fondo y borde suaves) porque depende de un extra, no
   es un dato suelto del huesped. */
.vehiculo-campos {
  margin-top: 4px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}
.vehiculo-campos .detail-form-title { margin: 0 0 8px; }
.vehiculo-grilla {
  display: grid;
  /* La patente es corta y el modelo largo, pero van iguales: dos columnas
     de distinto ancho en un bloque de dos campos se lee como un error. */
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px 12px;
}
/* La patente, en mayusculas ya desde que se escribe: es como se guarda (ver
   datosDelVehiculo), asi que mostrarla de otra forma mientras se tipea seria
   mentir sobre lo que se va a guardar. */
#walkin-vehiculo-patente,
#detail-vehiculo-patente {
  text-transform: uppercase;
}

/* Varias habitaciones en la misma reserva. La primera son los campos de
   arriba del formulario; estas se suman, y se marcan como un sub-bloque para
   que se lea que pertenecen a la misma reserva y no son un formulario nuevo. */
.multi-habitaciones {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  margin-top: 2px;
}
.multi-lista { display: grid; gap: 8px; width: 100%; }
.multi-lista:empty { display: none; }
.multi-fila {
  display: grid;
  /* Habitacion, personas, precio y la cruz de quitar. La de habitacion se
     lleva el espacio de mas porque es la que tiene el texto largo. */
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.7fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}
.multi-fila label { display: flex; flex-direction: column; gap: 3px; min-width: 0; font-size: 0.72rem; }
.multi-fila input, .multi-fila select {
  min-height: 36px; padding: 0 8px; width: 100%;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 13px;
}
/* Un precio que sale de la tarifa se ve como dato, no como campo: es lo
   mismo que hace el candado del formulario principal. */
.multi-fila input[readonly] { background: var(--surface-muted); color: var(--muted); }
.multi-quitar { align-self: end; margin-bottom: 2px; }
.multi-hint { color: var(--muted); font-size: 0.74rem; }
.multi-hint:empty { display: none; }

@media (max-width: 720px) {
  /* En telefono la fila se apila: cuatro columnas de ~70px no dejan leer ni
     el nombre de la habitacion. La cruz pasa a la primera linea, al lado del
     campo de habitacion. */
  .multi-fila { grid-template-columns: minmax(0, 1fr) auto; }
  .multi-fila .multi-campo-guests, .multi-fila .multi-campo-total { grid-column: 1 / -1; }
}

/* Cotejo de comprobantes: el paso donde recepcion compara el monto que
   declaro el huesped contra lo que dice la imagen. La fila reusa
   .transferencia (es la misma idea: un pago esperando que alguien lo mire) y
   agrega el campo del importe en el medio, porque corregirlo aca es lo que
   evita que el revisor tenga que hacerlo despues. */
.transferencia.cotejo {
  flex-wrap: wrap;
}

.cotejo-monto {
  flex-shrink: 0;
}

.cotejo-monto label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11.5px;
  color: var(--muted);
}

.cotejo-monto input {
  width: 130px;
  padding: 7px 9px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}

/* En telefono la fila se apila: con el campo de importe, tres botones y el
   nombre del huesped no entra nada en una sola linea. */
@media (max-width: 620px) {
  .transferencia.cotejo .transferencia-datos,
  .transferencia.cotejo .cotejo-monto {
    width: 100%;
  }
  .cotejo-monto input { width: 100%; }
  .transferencia.cotejo .transferencia-acciones { width: 100%; justify-content: flex-end; }
}

/* ---------------------------------------------------------------------------
   Panel de Inicio: "Tareas pendientes" y "Prioridad de hoy" (06/10)

   Con un dia cargado eran treinta tareas en fila: cinco pantallas de alto en
   la computadora, siete en el telefono, la misma reserva dos y tres veces y
   las prioridades fuera de vista. Ahora (ver tareasAgrupadasHtml y
   prioridadesDeInicio en app.js):
   - las tareas van en BLOQUES con su cuenta, y cada bloque muestra las
     primeras tres ("Ver N mas" para el resto; "Atender ya" va entero);
   - cada fila dice quien y donde, y lleva UN boton con lo que hace
     ("Hacer check-in", "Cobrar $X"); tocar la fila abre la reserva;
   - las prioridades quedan fijas al costado en escritorio y ARRIBA de las
     tareas en el telefono.
   --------------------------------------------------------------------------- */

/* El panel de prioridades se pega debajo de la barra de navegacion mientras
   se recorren las tareas (mismo --alto-barra-superior que el detalle de la
   reserva: lo mide medirBarraSuperior). Las columnas, en .two-column. */
@media (min-width: 981px) {
  #inicio .panel-prioridades {
    position: sticky;
    top: calc(var(--alto-barra-superior, 0px) + 16px);
    max-height: calc(100vh - var(--alto-barra-superior, 0px) - 32px);
    overflow-y: auto;
  }
}

/* En el telefono las prioridades van ANTES que las tareas: abajo quedaban
   despues de toda la lista, donde no llegaba nadie. Son una fila corta por
   prioridad, asi que no empujan mucho. */
@media (max-width: 980px) {
  #inicio .panel-prioridades {
    order: -1;
  }
}

/* --- Los bloques ---------------------------------------------------------- */
#inicio .task-list {
  /* Para que la fila se reacomode por el ancho de la LISTA (que cambia con la
     columna), no de la ventana. */
  container-type: inline-size;
  container-name: lista-de-tareas;
}

/* Entre bloque y bloque, 18px: los 10 del gap de la lista y estos 8. */
.tareas-grupo + .tareas-grupo {
  margin-top: 8px;
}

/* La ultima fila de un bloque no lleva raya: abajo viene el titulo del
   siguiente, que ya tiene la suya. */
.tareas-grupo > .tarea:last-child {
  border-bottom: none;
}

.tareas-grupo-titulo {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.tareas-grupo-cuenta {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  color: var(--ink);
  font-size: 11.5px;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

/* "Atender ya" en la tinta roja: es lo unico del panel que no puede esperar.
   El numero lleva el mismo tinte que las etiquetas rojas (.pill.red). */
.tareas-grupo-urgente .tareas-grupo-titulo {
  color: var(--tint-red-ink);
}

.tareas-grupo-urgente .tareas-grupo-cuenta {
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  color: var(--tint-red-ink);
}

.tareas-ver-mas {
  display: block;
  width: 100%;
  min-height: 36px;
  margin-top: 2px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--accent-strong);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .tareas-ver-mas:hover {
    background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  }
}

/* --- Una tarea ------------------------------------------------------------
   Texto a la izquierda (lo que se toca para abrir la reserva) y el boton a
   la derecha, centrado en el alto de la fila. */
.tarea {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px 14px;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}

.tarea-principal {
  display: grid;
  /* minmax(0, ...): sin esto la columna implicita es "auto", y el resumen de
     una consulta (un renglon que se recorta con "...") la estiraba hasta el
     largo del texto entero -- en el telefono la pagina media 560px de ancho. */
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  min-width: 0;
  padding: 0;
  border: none;
  border-radius: 2px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
}

button.tarea-principal {
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}

/* El resaltado se agranda con una sombra del mismo color y no con padding:
   una sombra no ocupa lugar, asi el texto queda alineado con el titulo del
   bloque y nada se sale de la fila (con margenes negativos, en el telefono
   la fila media 6px mas que la lista). */
@media (hover: hover) and (pointer: fine) {
  button.tarea-principal:hover {
    --resaltado-tarea: color-mix(in srgb, var(--accent) 6%, var(--surface));
    background: var(--resaltado-tarea);
    box-shadow: 0 0 0 6px var(--resaltado-tarea);
  }
}

.tarea-titulo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  min-width: 0;
}

.tarea-titulo strong {
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.tarea-detalle {
  color: var(--muted);
  font-size: 13px;
  overflow-wrap: anywhere;
}

/* Una marca es un dato que la fila tiene ADEMAS ("Vence en 5 h", "Sin
   revisar", "WhatsApp"): chica y teñida, para que no compita con el nombre.
   Sin color es un rotulo neutro; con color, un estado (en su tinta). */
.tarea-marca {
  display: inline-flex;
  align-items: center;
  min-height: 20px;
  padding: 0 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  color: var(--tint-gray-ink);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.tarea-marca.red {
  background: color-mix(in srgb, var(--red) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--red) 26%, transparent);
  color: var(--tint-red-ink);
}

.tarea-marca.orange {
  background: color-mix(in srgb, var(--orange) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--orange) 32%, transparent);
  color: var(--tint-orange-ink);
}

.tarea-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* El boton de la fila es "ghost": un turquesa lleno por fila serian veinte
   colores fuertes en la pantalla, y la paleta deja uno solo (el de la accion
   principal, arriba). Un <a> (el WhatsApp) se ve igual que un boton. */
.tarea-accion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  white-space: nowrap;
  text-decoration: none;
}

/* Lista angosta (telefono, o una columna chica): el boton baja abajo del
   texto. Al lado le comia el ancho al nombre, que es lo que se busca. */
@container lista-de-tareas (max-width: 480px) {
  .tarea {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }

  .tarea-acciones {
    justify-content: flex-start;
  }
}

/* ---------------------------------------------------------------------------
   Consultas de la web en Inicio (ver consultasWebSinAtender en app.js)

   Una tarea como las demas -- titulo, detalle y [Marcar atendida] a la
   derecha -- con dos cosas abajo: los links para devolver el contacto y lo
   que se hablo en el chat, plegado a un renglon.
   --------------------------------------------------------------------------- */
.tarea.tarea-consulta-web {
  align-items: start;
}

.consulta-web-contacto {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin-top: 4px;
}

.consulta-web-link {
  color: var(--accent-strong);
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  /* Un mail largo no puede empujar la tarjeta mas alla del borde. */
  overflow-wrap: anywhere;
}

.consulta-web-dato {
  color: var(--ink);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.consulta-web-nota {
  display: block;
  margin-top: 4px;
  color: var(--tint-orange-ink);
  font-size: 12px;
}

/* El resumen lo arma el chat en varias lineas (fechas, huespedes, lo ultimo
   que escribio el visitante). Plegado muestra UN renglon y "Ver todo" lo
   abre entero (pre-line respeta los saltos), con tope de alto y scroll
   propio: son hasta 1.500 caracteres. La linea violeta y el rotulo dicen que
   lo armo el asistente (el violeta es solo de la IA); la tarea en si es de
   una persona esperando que la llamen, y por eso no se tiñe nada mas. */
.consulta-web-resumen {
  display: flex;
  min-width: 0;
  align-items: flex-start;
  gap: 4px 10px;
  margin-top: 6px;
  padding: 5px 10px;
  border-left: 2px solid var(--ai);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
}

.consulta-web-resumen p {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  color: var(--ink);
  font-size: 13px;
  line-height: 1.45;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.consulta-web-resumen.abierto p {
  max-height: 9.5em;
  overflow-y: auto;
  white-space: pre-line;
  overflow-wrap: anywhere;
  text-overflow: clip;
}

.consulta-web-resumen-rotulo {
  color: var(--ai-strong);
  font-weight: 600;
}

.consulta-web-resumen-alternar {
  flex: 0 0 auto;
  padding: 0;
  border: none;
  background: none;
  color: var(--accent-strong);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.45;
  cursor: pointer;
}

/* Arriba de una bandeja (cotejo o revisor), que reemplaza a las tareas pero
   no a estas: ver pintarConsultasWebSobreLaBandeja. Una linea las separa de
   la bandeja de abajo. */
.consultas-web-sobre-bandeja {
  display: grid;
  padding-bottom: 6px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--line);
  /* Mismo reacomodo por ancho que la lista de tareas. */
  container-type: inline-size;
  container-name: lista-de-tareas;
}

.consultas-web-sobre-bandeja .tarea:last-child {
  border-bottom: none;
}

.consultas-web-sobre-bandeja-titulo {
  margin: 0;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* --- Prioridad de hoy -----------------------------------------------------
   Una fila por prioridad: el numero grande a la izquierda (lo que se lee de
   un vistazo), el titulo y UN renglon de detalle, y la flecha que dice que se
   puede tocar. Conserva el fondo teñido y la franja lateral de .alert-item. */
#inicio .alert-list {
  gap: 8px;
}

#inicio .alert-item.prioridad {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
}

/* Con #inicio y las dos clases: el numero es un <span>, y `.alert-item span`
   (gris y a 13px, para el detalle) le ganaria a una regla mas corta. */
#inicio .alert-item.prioridad .prioridad-numero {
  min-width: 26px;
  color: var(--tint-orange-ink);
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

#inicio .alert-item.prioridad.alert-red .prioridad-numero {
  color: var(--tint-red-ink);
}

#inicio .alert-item.prioridad.alert-blue .prioridad-numero {
  color: var(--tint-blue-ink);
}

.prioridad-texto {
  display: grid;
  gap: 1px;
  min-width: 0;
}

#inicio .prioridad-texto strong {
  color: var(--ink);
  font-size: 14px;
}

/* El detalle en UN renglon: la lista entera esta en lo que abre la fila. */
#inicio .prioridad-texto span {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.prioridad-flecha {
  width: 16px;
  height: 16px;
  color: var(--muted);
}

/* WhatsApp del hotel en Configuracion: el campo y "Probar" en la misma fila.
   El boton va fuera del <label> (un label con dos controles no sabe a cual
   nombra), asi que el rotulo se dibuja igual que el de los demas campos. */
.settings-whatsapp > label {
  display: block;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
}

.settings-whatsapp-fila {
  display: flex;
  gap: 8px;
  align-items: stretch;
  margin-top: 6px;
}

.settings-whatsapp-fila input {
  flex: 1;
  min-width: 0;
  margin-top: 0;
}

.settings-whatsapp .settings-hint {
  display: block;
  margin: 6px 0 0;
  font-size: 12px;
}

.settings-whatsapp .settings-hint-error {
  color: var(--tint-red-ink);
}

/* Los tres plazos de la seña (11/10): un rotulo y tres campos en fila; en el
   telefono, uno debajo del otro. */
.settings-plazos-titulo {
  display: block;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
}

.settings-plazos-fila {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px 14px;
  margin-top: 8px;
}

.settings-plazos-sena .settings-hint {
  display: block;
  margin: 8px 0 0;
  font-size: 12px;
}

@media (max-width: 760px) {
  .settings-plazos-fila {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ===========================================================================
   MAIL EN EL CHAT (04/10)
   ===========================================================================
   El canal Mail es otra .chat-layout (#mail-layout): hereda el alto fijo, el
   scroll independiente de la lista y del hilo, y en el telefono el "una
   pantalla a la vez" (.conversation-open). Lo de aca es solo lo propio.
   =========================================================================== */

/* El selector WhatsApp / Mail. Va arriba de la lista (adentro de la caja de
   alto fijo, no encima): no le suma alto a la vista. Dos mitades iguales, como
   un control segmentado: se ve de un vistazo en cual se esta. */
.canal-selector {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  margin: 8px 8px 0;
  padding: 3px;
  border-radius: var(--radius);
  background: var(--surface-muted);
  border: 1px solid var(--line);
}

.canal-opcion {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  min-height: 32px;
  padding: 0 8px;
  border: 0;
  border-radius: calc(var(--radius) - 3px);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.canal-opcion svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}

.canal-opcion.activo {
  background: var(--surface);
  color: var(--accent-strong);
  box-shadow: 0 1px 2px rgba(22, 20, 46, 0.12);
}

/* El rojo oscuro de las cuentas de los chips y no --red: blanco sobre --red da
   4,3:1 (medido en el banco), por debajo de lo que pide un numero chico. */
.canal-cuenta {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: #b23c0c;
  color: #fff;
  font-size: 10.5px;
  font-weight: 800;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

@media (hover: hover) and (pointer: fine) {
  .canal-opcion:not(.activo):hover {
    color: var(--ink);
  }
}

.canal-opcion:focus-visible {
  outline: 2px solid var(--focus-outline);
  outline-offset: 1px;
}

@media (max-width: 980px), (pointer: coarse) {
  .canal-opcion {
    min-height: 40px;
    font-size: 14px;
  }

  .canal-selector {
    margin: 8px 10px 0;
  }
}

/* Mismo rojo legible que el chip de WhatsApp (ver .chat-filtro arriba). */
.chat-filtro[data-filtro-mail="sin-responder"] .chat-filtro-cuenta {
  color: #b23c0c;
  opacity: 1;
}

html[data-theme="dark"] .chat-filtro[data-filtro-mail="sin-responder"] .chat-filtro-cuenta {
  color: #ff8f6b;
}

/* Tres cosas en la barra (buscar, actualizar, Nuevo) en una columna de 300px:
   sin min-width 0 el campo no se achica y la barra se sale 4px. */
#mail-layout .conversation-search-bar input {
  min-width: 0;
}

.mail-actualizar {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.mail-actualizar svg {
  width: 16px;
  height: 16px;
}

.mail-actualizar.girando svg {
  animation: girarMail 0.9s linear infinite;
}

@keyframes girarMail {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .mail-actualizar.girando svg { animation: none; opacity: 0.5; }
}

@media (max-width: 980px), (pointer: coarse) {
  .mail-actualizar {
    width: 40px;
    height: 40px;
  }

  .mail-nuevo-boton {
    min-height: 40px;
  }
}

.mail-nuevo-boton {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 0 12px;
  font-size: 12.5px;
}

.mail-estado-cuenta {
  flex: 0 0 auto;
  margin: 8px 8px 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 12px;
  line-height: 1.4;
}

.mail-estado-cuenta.alerta {
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  color: var(--tint-red-ink);
}

.mail-sin-cuenta {
  display: grid;
  gap: 10px;
  padding: 14px 10px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
}

/* La fila de la lista: remitente y fecha arriba, asunto, extracto. Con
   .mail-item delante: ".conversation-item span" (de WhatsApp) les gana a
   las clases solas y pinta todo de gris y a 13px. */
.mail-item .mail-item-fecha {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.mail-item .mail-item-asunto {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
  color: var(--ink);
}

.mail-item.unread .mail-item-asunto {
  font-weight: 700;
}

.mail-item-clip {
  display: inline-flex;
  flex: 0 0 auto;
}

.mail-item-clip svg {
  width: 13px;
  height: 13px;
  color: var(--muted);
}

.mail-item .mail-item-cantidad {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
}

/* Lo automatico (newsletters, avisos de sistemas) se ve, pero atenuado: no
   pide nada. */
.mail-item.automatico {
  opacity: 0.72;
}

.pill.mail-pill-auto {
  background: var(--surface-muted);
  color: var(--muted);
  border-color: var(--line);
}

.mail-header .conversation-identity {
  min-width: 0;
}

.mail-header-textos {
  display: grid;
  min-width: 0;
  gap: 1px;
}

.mail-header-textos .conversation-name {
  max-width: none;
}

.mail-contacto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 12px;
}

.mail-boton {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.mail-boton svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* En el telefono la cabecera ocupa DOS renglones y no cuatro: el asunto, y
   abajo el selector de reserva con los dos botones solo con su icono (el
   texto queda en el title y en aria-label). Cada renglon de mas era un mail
   menos a la vista en una caja de alto fijo. */
@media (max-width: 980px) {
  .mail-header .conversation-link-select {
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
  }

  .mail-header .conversation-actions {
    flex: 0 0 auto;
    gap: 6px;
  }

  .mail-header .mail-boton {
    width: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
  }

  .mail-header .mail-boton-texto {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

/* El hilo: el UNICO hijo con scroll del panel (como .messages en WhatsApp),
   asi la cabecera y la caja de responder quedan fijas sin sticky. */
.mail-hilo {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 14px;
  background: var(--surface-muted);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.mail-mensaje {
  max-width: min(100%, 760px);
  width: 100%;
  flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.45;
  min-width: 0;
}

.mail-mensaje.entrante {
  align-self: flex-start;
}

/* Lo que mando el hotel: Agua, igual que la burbuja de recepcion en
   WhatsApp (.message.human). Antes era el azul de estado puesto de adorno. */
.mail-mensaje.saliente {
  align-self: flex-end;
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
}

.mail-mensaje-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 8px;
  row-gap: 2px;
  margin-bottom: 6px;
}

.mail-mensaje-de {
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 12.5px;
}

.mail-mensaje-fecha {
  margin-left: auto;
  color: var(--muted);
  font-size: 11.5px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.mail-mensaje-para {
  flex-basis: 100%;
  color: var(--muted);
  font-size: 11.5px;
  overflow-wrap: anywhere;
}

/* El texto del mail, escapado: los saltos de linea se respetan y una URL
   larga no ensancha la caja. */
.mail-cuerpo {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.mail-cuerpo a {
  color: var(--accent-strong);
}

.mail-vacio {
  color: var(--muted);
}

.mail-cita {
  margin-top: 8px;
}

.mail-cita summary,
.mail-aviso summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

.mail-cita .mail-cuerpo {
  margin-top: 6px;
  padding-left: 10px;
  border-left: 3px solid var(--line);
  color: var(--muted);
}

/* Aviso automatico al huesped (mailsHuesped): una linea plegada, centrada,
   para que no se lea como una respuesta del hotel. */
.mail-aviso {
  align-self: center;
  max-width: min(100%, 560px);
  background: transparent;
  border-style: dashed;
  padding: 6px 10px;
}

.mail-aviso summary {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.mail-aviso .mail-cuerpo {
  margin-top: 6px;
  font-size: 12px;
}

.mail-adjuntos,
.mail-adjuntos-borrador {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.mail-adjunto {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-height: 32px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.mail-adjunto svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  color: var(--muted);
}

.mail-adjunto small {
  flex: 0 0 auto;
  color: var(--muted);
}

.mail-adjunto-nombre {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-adjunto:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.mail-adjunto-borrador {
  cursor: default;
  padding-right: 4px;
}

.mail-adjunto-quitar {
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 16px;
  line-height: 1;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  cursor: pointer;
}

.mail-mensaje-pie {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-size: 12px;
}

.mail-mensaje-pie .link-button {
  margin-left: auto;
}

.mail-nota-enviados {
  color: var(--tint-orange-ink);
}

/* Responder: fija abajo (ultimo hijo flex del panel, como .reply-box). */
.mail-redactar {
  flex: 0 0 auto;
  display: grid;
  gap: 6px;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.mail-redactar-nuevo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 6px 10px;
}

.mail-redactar-nuevo label {
  display: grid;
  gap: 3px;
  min-width: 0;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
}

.mail-redactar-nuevo label:first-child {
  grid-column: 1 / -1;
}

.mail-redactar-nuevo input,
.mail-redactar-nuevo select,
.mail-redactar textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  color: var(--ink);
  background: var(--surface);
  font: inherit;
  font-size: 13px;
}

.mail-redactar textarea {
  resize: vertical;
  min-height: 64px;
  /* Que la caja de escribir no se coma el hilo en una pantalla baja. */
  max-height: 32vh;
  line-height: 1.45;
}

.mail-redactar-destino {
  margin: 0;
  color: var(--muted);
  font-size: 11.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-redactar-destino:empty {
  display: none;
}

.mail-adjuntos-borrador {
  margin-top: 0;
}

.mail-redactar-acciones {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.mail-redactar-nota {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--tint-red-ink);
  font-size: 12px;
  line-height: 1.35;
}

.mail-adjuntar {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  cursor: pointer;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* El input de archivo real queda adentro del label, invisible: el label lo
   abre con el toque, y con el teclado se le llega igual. */
.mail-adjuntar-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.mail-adjuntar:focus-within {
  outline: 2px solid var(--focus-outline);
  outline-offset: 1px;
}

@media (max-width: 980px), (pointer: coarse) {
  .mail-adjuntar,
  .mail-redactar-acciones .primary-button,
  .mail-redactar-acciones .ghost-button {
    min-height: 44px;
  }

  .mail-adjunto {
    min-height: 40px;
  }

  .mail-redactar-nuevo {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 16px: con menos, Safari hace zoom al tocar el campo. */
  .mail-redactar textarea,
  .mail-redactar-nuevo input,
  .mail-redactar-nuevo select {
    font-size: 16px;
  }

  .mail-mensaje-fecha {
    margin-left: 0;
  }
}

/* El visor del mail con formato: un iframe aislado (ver documentoSeguroDelMail).
   Alto fijo con su propio scroll: desde adentro no se puede medir el contenido
   (no corre ningun script), asi que no se ajusta solo. */
.mail-visor-modal {
  display: flex;
  flex-direction: column;
  width: min(900px, 96vw);
  height: 86vh;
  height: 86dvh;
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-float);
  overflow: hidden;
  animation: popoverIn 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

.mail-visor-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px 6px 16px;
}

.mail-visor-cabecera strong {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mail-visor-barra {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 16px 8px;
  border-bottom: 1px solid var(--line);
}

.mail-visor-nota {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  color: var(--muted);
  font-size: 12px;
}

.mail-visor-barra .ghost-button {
  flex: 0 0 auto;
}

/* El adjunto con su "Registrar pago" al lado (el mismo boton que las fotos de
   WhatsApp), juntos para que se lea de que adjunto es. */
.mail-adjunto-con-pago {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  max-width: 100%;
}

.mail-adjunto-con-pago .mail-adjunto-pago {
  width: auto;
  margin: 0;
}

.mail-ver-mas {
  margin: 6px auto 4px;
}

/* Fondo blanco siempre: el HTML de un mail se diseña sobre blanco y en el
   tema oscuro quedaria texto negro sobre negro. */
.mail-visor-marco {
  flex: 1;
  width: 100%;
  border: 0;
  background: #fff;
}

/* Configuracion: la ayuda del proveedor y el resultado de las pruebas. */
.mail-ayuda {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--ink);
  font-size: 12.5px;
  line-height: 1.45;
}

.mail-ayuda ul {
  margin: 6px 0 0;
  padding-left: 18px;
}

.mail-avanzado summary {
  cursor: pointer;
  color: var(--accent-strong);
  font-size: 13px;
  font-weight: 600;
}

.mail-avanzado .form-grid {
  margin-top: 10px;
}

.mail-pruebas {
  display: grid;
  gap: 4px;
}

.mail-prueba {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.4;
}

.mail-prueba.ok {
  color: var(--tint-green-ink);
}

.mail-prueba.mal {
  color: var(--tint-red-ink);
}

/* ===========================================================================
   LIMPIEZA: HOJAS DEL DIA POR SECTOR (05/10)
   ===========================================================================
   La gobernanta le da un sector a cada mucama y por habitacion se marca si se
   retiraron toallas y sabanas, con observaciones. Se usa en la PC de la
   gobernanta y en el telefono de cada mucama: cada fila se reacomoda segun el
   ancho de SU sector (container query), no de la ventana.
   =========================================================================== */
.limpieza-pestanas {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
}

.limpieza-pestana {
  min-height: 32px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.limpieza-pestana.activa {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-raised);
}

.limpieza-hojas {
  display: grid;
  gap: 14px;
}

.limpieza-barra {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
}

.limpieza-barra .compact-field { min-width: 0; }
.limpieza-barra .compact-field input[type="date"] { min-width: 150px; }

/* Los dos papeles: la lista general (la gobernanta) y las hojas por mucama. */
.limpieza-imprimir {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.limpieza-imprimir-titulo {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.limpieza-resumen {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

.limpieza-resumen strong { color: var(--ink); }

.limpieza-aviso {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--surface-muted);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.45;
}

.limpieza-aviso.error {
  background: color-mix(in srgb, var(--red) 9%, var(--surface));
  color: var(--tint-red-ink);
}

.limpieza-aviso .ghost-button {
  min-height: 30px;
  margin-left: 6px;
  padding: 0 10px;
  font-size: 12px;
}

.limpieza-sector {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  container-type: inline-size;
  overflow: hidden;
}

.limpieza-sector-cabeza {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 12px 14px;
  background: var(--surface-muted);
  border-bottom: 1px solid var(--line);
}

.limpieza-sector-titulo h3 {
  margin: 0;
  font-size: 16px;
}

.limpieza-sector-titulo span,
.limpieza-sector-nota {
  color: var(--muted);
  font-size: 12.5px;
}

.limpieza-mucama-campo { min-width: 190px; }

.limpieza-filas { display: grid; }

/* Una fila: habitacion | que pasa | toallas y sabanas | observaciones. */
.limpieza-fila {
  display: grid;
  grid-template-columns: 96px minmax(140px, 1fr) auto minmax(180px, 1.6fr);
  grid-template-areas: "hab estado tildes obs";
  align-items: center;
  gap: 8px 12px;
  padding: 8px 14px;
  border-top: 1px solid var(--line);
}

.limpieza-fila:first-child { border-top: 0; }

.limpieza-hab {
  grid-area: hab;
  display: grid;
  line-height: 1.2;
}

.limpieza-hab strong { font-size: 14px; }
.limpieza-hab span { color: var(--muted); font-size: 11.5px; }

.limpieza-estado {
  grid-area: estado;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.limpieza-pastilla {
  display: inline-flex;
  align-items: center;
  min-height: 22px;
  padding: 0 9px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}

.limpieza-pastilla.salida {
  background: color-mix(in srgb, var(--orange) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--orange) 32%, transparent);
  color: var(--tint-orange-ink);
}

.limpieza-pastilla.ingreso {
  background: color-mix(in srgb, var(--green) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--green) 26%, transparent);
  color: var(--tint-green-ink);
}

.limpieza-pastilla.ocupada {
  background: color-mix(in srgb, var(--blue) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--blue) 26%, transparent);
  color: var(--tint-blue-ink);
}

.limpieza-pastilla.libre {
  background: var(--surface-muted);
  border-color: var(--line);
  color: var(--tint-gray-ink);
}

.limpieza-tildes {
  grid-area: tildes;
  display: flex;
  gap: 6px;
}

/* Un casillero con su nombre: se toca entero. Marcado = lleno, con el color
   del sistema; el texto dice que es, el casillero dice si esta. */
.limpieza-tilde {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 0 12px 0 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

.limpieza-tilde:active:not(:disabled) { transform: scale(0.97); }
.limpieza-tilde:disabled { opacity: 0.55; cursor: default; }

.limpieza-tilde-caja {
  position: relative;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
  border: 1.5px solid var(--muted);
  border-radius: 4px;
}

.limpieza-tilde.marcado {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.limpieza-tilde.marcado .limpieza-tilde-caja {
  border-color: var(--accent);
  background: var(--accent);
}

/* La tilde, dibujada: un rectangulo con dos bordes, rotado. */
.limpieza-tilde.marcado .limpieza-tilde-caja::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 5px;
  height: 9px;
  border: solid var(--on-accent);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.limpieza-obs {
  grid-area: obs;
  min-height: 36px;
  width: 100%;
  min-width: 0;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}

@media (hover: hover) {
  .limpieza-tilde:hover:not(:disabled):not(.marcado) { border-color: var(--muted); }
  .limpieza-pestana:hover:not(.activa) { color: var(--ink); }
}

@media (pointer: coarse) {
  .limpieza-tilde,
  .limpieza-obs { min-height: 44px; }
}

/* Sector angosto (telefono, o una PC con la ventana chica): la habitacion y
   lo que pasa en el primer renglon, los dos casilleros a lo ancho en el
   segundo, y la observacion abajo. */
@container (max-width: 640px) {
  .limpieza-fila {
    grid-template-columns: 80px minmax(0, 1fr);
    grid-template-areas:
      "hab estado"
      "tildes tildes"
      "obs obs";
    padding: 10px 12px;
  }

  .limpieza-tildes .limpieza-tilde {
    flex: 1 1 0;
    justify-content: center;
  }
}

@supports not (container-type: inline-size) {
  @media (max-width: 700px) {
    .limpieza-fila {
      grid-template-columns: 80px minmax(0, 1fr);
      grid-template-areas:
        "hab estado"
        "tildes tildes"
        "obs obs";
    }
    .limpieza-tildes .limpieza-tilde { flex: 1 1 0; justify-content: center; }
  }
}

@media (max-width: 620px) {
  .limpieza-barra .compact-field { flex: 1 1 140px; }
  .limpieza-imprimir { margin-left: 0; width: 100%; }
  .limpieza-imprimir-titulo { flex: 1 1 100%; }
  .limpieza-imprimir button { flex: 1 1 0; }
  .limpieza-mucama-campo { flex: 1 1 100%; }
}

/* --- La hoja impresa ------------------------------------------------------
   Va en #ficha-impresion (ver la ficha de reserva) y las reglas viven FUERA
   de @media print, igual que .ficha: asi medirla en pantalla predice el
   papel. Negro sobre blanco y en milimetros. Una hoja por mucama. */
@page limpieza {
  size: A4;
  margin: 10mm 11mm;
}

.hoja-limpieza {
  page: limpieza;
  break-after: page;
  color: #000;
  background: #fff;
  font: 10.5pt/1.25 system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}

.hoja-limpieza:last-child { break-after: auto; }

.hoja-limpieza-cabeza {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8mm;
  padding-bottom: 2.5mm;
  border-bottom: 0.6mm solid #000;
}

.hoja-limpieza-cabeza p { margin: 0; font-size: 9pt; }
.hoja-limpieza-cabeza h1 { margin: 0.5mm 0 0; font-size: 15pt; }

.hoja-limpieza-mucama {
  font-size: 12pt;
  white-space: nowrap;
}

.hoja-limpieza-mucama strong { font-size: 14pt; }

.hoja-linea {
  display: inline-block;
  width: 55mm;
  border-bottom: 0.3mm solid #000;
}

.hoja-limpieza-resumen {
  margin: 2mm 0 2.5mm;
  font-size: 9.5pt;
}

.hoja-limpieza-tabla {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.hoja-limpieza-tabla col.c-hab { width: 21mm; }
.hoja-limpieza-tabla col.c-marca { width: 16mm; }

.hoja-limpieza-tabla th,
.hoja-limpieza-tabla td {
  border: 0.25mm solid #000;
  padding: 0 1.5mm;
  vertical-align: middle;
}

.hoja-limpieza-tabla thead th {
  height: 7mm;
  font-size: 8.5pt;
  text-align: center;
}

.hoja-limpieza-tabla thead th:first-child,
.hoja-limpieza-tabla thead th:last-child { text-align: left; }

/* 10 mm: dos sectores (21 habitaciones, Chalet + Piso 1.A) entran en UNA
   hoja (medido en banco-limpieza-sectores: con 10,5 mm se pasaba por medio
   milimetro). Tres sectores ya van a dos hojas, y el encabezado se repite. */
.hoja-limpieza-tabla tbody tr {
  height: 10mm;
  break-inside: avoid;
}

.hoja-limpieza-sector th {
  height: 7mm;
  text-align: left;
  font-size: 10pt;
  background: #e6e6e6;
}

.hoja-limpieza-sector th span {
  margin-left: 2mm;
  font-weight: 400;
  font-size: 9pt;
}

.hoja-hab strong { display: block; font-size: 11.5pt; }
.hoja-hab small { font-size: 7.5pt; }

.hoja-marca {
  text-align: center;
  line-height: 1.1;
}

.hoja-marca small {
  display: block;
  font-size: 7.5pt;
}

.hoja-x {
  font-size: 13pt;
  font-weight: 800;
}

/* El casillero para tildar: dibujado con borde y no con un caracter (que
   depende de la fuente, ver desayunos). Lleno = ya se marco en el PMS. */
.hoja-caja {
  display: inline-block;
  width: 5mm;
  height: 5mm;
  border: 0.4mm solid #000;
  vertical-align: middle;
}

.hoja-caja.marcada { background: #000; }

.hoja-obs {
  font-size: 9.5pt;
  word-break: break-word;
}

.hoja-limpieza-pie {
  margin: 2.5mm 0 0;
  font-size: 8.5pt;
}

/* --- La lista general (la gobernanta) ---------------------------------------
   Todas las habitaciones en UNA hoja: dos columnas de tablas, cada sector
   entero en una (columnasDeLaListaGeneral las empareja). Filas de 7 mm: con
   las 50 de Santa Teresita, la columna mas larga son 32 filas (medido en
   banco-limpieza-sectores). Las mismas columnas que las hojas de las mucamas,
   en mas chico. */
.lista-general-reparto {
  display: flex;
  flex-wrap: wrap;
  gap: 1mm 5mm;
  margin: -1mm 0 2.5mm;
  font-size: 8.5pt;
}

.lista-general-columnas {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4mm;
  align-items: start;
}

.lista-general-tabla {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.lista-general-tabla col.c-hab { width: 15mm; }
.lista-general-tabla col.c-marca { width: 8.5mm; }

.lista-general-tabla th,
.lista-general-tabla td {
  border: 0.25mm solid #000;
  padding: 0 0.8mm;
  vertical-align: middle;
}

.lista-general-tabla thead th {
  height: 5.5mm;
  font-size: 7pt;
  text-align: center;
}

.lista-general-tabla thead th:first-child,
.lista-general-tabla thead th:last-child { text-align: left; }

.lista-general-tabla tbody tr {
  height: 7mm;
  break-inside: avoid;
}

/* El renglon lo pone la letra de la CELDA: con la de la hoja (10,5 pt y 1,25)
   el "TPL" de abajo armaba un renglon de 4,6 mm y cada fila crecia a 8,8 mm
   (la hoja media 310 mm). Celda chica y renglon justo. */
.lista-general-tabla td { font-size: 7pt; line-height: 1.1; }
.lista-general .hoja-limpieza-sector th { height: 5.5mm; font-size: 8pt; }
.lista-general .hoja-limpieza-sector th span { font-size: 7pt; }
.lista-general .hoja-hab strong { font-size: 9pt; line-height: 1.05; }
.lista-general .hoja-hab small { display: block; font-size: 6.5pt; line-height: 1.05; }
.lista-general .hoja-x { font-size: 10pt; line-height: 1; }
.lista-general .hoja-marca small { font-size: 6.5pt; line-height: 1; }
.lista-general .hoja-caja { width: 3.6mm; height: 3.6mm; border-width: 0.3mm; }
.lista-general .hoja-obs { font-size: 7pt; line-height: 1.15; }

/* Agregar otra habitacion a una reserva hecha (agregarHabitacionDesdeElDetalle). */
.agregar-habitacion-modal label {
  display: grid;
  gap: 4px;
  margin-top: 10px;
  font-size: 0.85rem;
  font-weight: 600;
}
.agregar-habitacion-modal input,
.agregar-habitacion-modal select {
  width: 100%;
  min-height: 38px;
}
.agregar-habitacion-modal #agregar-hab-precio {
  display: block;
  margin-top: 8px;
}
.detail-agregar-habitacion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
}

/* Detalle de la reserva FIJO (06/10, pedido de Juan, con captura):
   1. Lo que scrollea es la PAGINA (la lista de la izquierda). El detalle es
      sticky y se pega DEBAJO de la barra de navegacion (--alto-barra-superior,
      medirBarraSuperior); con top 18px la barra le tapaba la cabecera.
   2. La cabecera queda fuera de la zona que scrollea (.detalle-cuerpo), asi
      que el menu de categorias se pega en top 0 de esa caja sin medir nada.
      Antes la cabecera era sticky dentro del mismo scroll y tapaba el menu. */
@media (min-width: 981px) {
  .reservation-detail {
    top: calc(var(--alto-barra-superior, 0px) + 16px);
    max-height: calc(100vh - var(--alto-barra-superior, 0px) - 32px);
  }
}
.reservation-detail {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.reservation-detail.hidden { display: none; }
.reservation-detail > .panel-header { position: static; flex: 0 0 auto; }
.reservation-detail > .detalle-cuerpo {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-top: 12px;
  display: grid;
  gap: 14px;
  align-content: start;
}
.detalle-shell.settings-shell .settings-sidebar {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--surface);
}
@container detalle (max-width: 620px) {
  .detalle-shell.settings-shell .settings-sidebar {
    position: sticky;
    top: 0;
    margin: 0 -2px 14px;
    padding: 0 2px 8px;
  }
}

/* Ficha del cliente FIJA, como el detalle de la reserva (06/10, pedido de
   Juan): lo que scrollea es la PAGINA (la lista de la izquierda) y la ficha
   queda pegada debajo de la barra de navegacion (--alto-barra-superior). La
   cabecera queda fuera de la zona que scrollea (.guest-detail-cuerpo), asi
   que el nombre y el boton de cerrar siempre se ven. En telefono no corre: la
   ficha es la pantalla entera y scrollea la pagina, como antes. */
@media screen and (min-width: 981px) {
  .guests-layout.detail-open > .guest-detail-panel {
    align-self: start;
    position: sticky;
    top: calc(var(--alto-barra-superior, 0px) + 16px);
    max-height: calc(100vh - var(--alto-barra-superior, 0px) - 32px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .guests-layout.detail-open > .guest-detail-panel > .guest-detail-head {
    flex: 0 0 auto;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line);
  }

  .guests-layout.detail-open > .guest-detail-panel > .guest-detail-cuerpo {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    /* Aire para que el foco de los campos y las sombras no se recorten contra
       el borde de la caja que scrollea. */
    margin: 0 -6px;
    padding: 0 6px 4px;
  }

  /* La fila en la columna angosta: un dato por renglon. El 2x2 de 1.4fr/1fr
     dejaba el documento o el mail en ~110px, cortado a las pocas letras. */
  .guests-layout.detail-open .guest-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
    padding: 8px 10px;
  }

  .guests-layout.detail-open .guest-row-meta {
    text-align: left;
  }

  .guests-layout.detail-open .guest-row-pills {
    margin-top: 4px;
  }
}

/* Pastilla "Sin conexión · datos de las HH:MM" en la barra (auditoria 06/10,
   FE-042): aparece desde el segundo refresco fallido y se va sola. Amarillo de
   ESTADO (algo espera), con su tinta como texto. Flota centrada debajo de la
   barra (adentro le sacaba lugar a los botones), por debajo de los modales. */
.estado-conexion {
  position: fixed;
  top: calc(var(--alto-barra-superior, 56px) + 8px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 45;
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.12);
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  color: var(--tint-yellow-ink);
  background: color-mix(in srgb, var(--yellow) 22%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--yellow) 55%, var(--line));
}

/* En el telefono la barra de navegacion va abajo: la pastilla, arriba de todo. */
@media (max-width: 980px) {
  .estado-conexion {
    top: calc(env(safe-area-inset-top, 0px) + 8px);
  }
}

/* Avisos (auditoria 06/10, FE-037 y FE-045). Arriba de los modales (50) y del
   login (100): antes tenian z-index 20 y una validacion dentro de un modal, o
   el "Sesion cerrada por inactividad", quedaban detras. Visible se puede tocar
   para cerrarlo. El de error va en rojo de estado, con la misma tinta fija. */
.toast {
  z-index: 210;
}

.toast.visible {
  pointer-events: auto;
  cursor: pointer;
}

.toast.toast-error {
  background: #7a2410;
  border-color: #a33a0b;
  max-width: min(480px, calc(100vw - 36px));
}

/* En el telefono, con una hoja inferior abierta el aviso iria encima de sus
   botones: se muestra arriba. */
@media (max-width: 980px) {
  body:has(.pms-confirm-backdrop:not(.hidden)) .toast {
    top: calc(env(safe-area-inset-top, 0px) + 8px);
    bottom: auto;
    transform: translateY(calc(-100% - 18px));
  }

  body:has(.pms-confirm-backdrop:not(.hidden)) .toast.visible {
    transform: translateY(0);
  }
}

/* Por que se volvio al login (sesion vencida, inactividad): FE-018. */
.login-aviso {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 14px;
  line-height: 1.4;
  color: var(--tint-orange-ink);
  background: color-mix(in srgb, var(--orange) 14%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--orange) 45%, var(--line));
}

/* La confirmacion y el pedido de codigo se abren ENCIMA de otros modales (el
   detalle de "Check-outs de hoy", por ejemplo). Con el mismo z-index que el
   resto ganaba el que venia despues en el HTML y "Hacer check-out" parecia no
   hacer nada (auditoria 06/10, FE-011). Y encima del login (100): "Cambiar
   de hotel" pregunta desde ahi (FE-065). Los avisos (210) siguen arriba. */
#pms-confirm-backdrop,
#pms-prompt-backdrop {
  z-index: 120;
}

/* "Mantenimiento" saca la habitacion de la venta: va separado de
   limpia/sucia para no tocarlo de casualidad (FE-025). */
.cleaning-actions .cleaning-a-mantenimiento {
  margin-left: auto;
  color: var(--tint-orange-ink);
}

/* Barra de escritorio entre 981 y 1260 px (auditoria 06/10, FE-010): con
   los textos no entra y "+ Reserva" / "+ Ingreso por mostrador" tapaban
   "Chat" y "Mas" (y recibian sus toques). En ese rango los botones quedan
   solo con el icono (el nombre va en el title) y el de mostrador se acorta.
   Por las dudas, la lista recorta lo que no entre en vez de pasar por debajo. */
.cta-texto-corto {
  display: none;
}

@media screen and (min-width: 981px) and (max-width: 1260px) {
  .topnav {
    gap: 10px;
  }

  .topnav-list {
    overflow-x: clip;
  }

  .topnav-item > span:not(.nav-icon):not(.nav-caret):not(.nav-badge) {
    display: none;
  }

  .topnav-item {
    padding-inline: 10px;
  }

  .cta-texto-largo {
    display: none;
  }

  .cta-texto-corto {
    display: inline;
  }
}

/* Marketing: la tabla scrollea adentro de su caja y no la pagina entera
   (de 360 a 1280 px la pagina se corria de costado). En el telefono cada fila
   es una tarjeta con el rotulo de cada dato (data-label), sin el hueco vacio
   de 100px que dejaban las celdas sin rotulo (auditoria 06/10, FE-073). */
.room-table-wrap {
  overflow-x: auto;
  max-width: 100%;
}

@media screen and (max-width: 900px) {
  .room-table-wrap .listing-table td {
    overflow-wrap: anywhere;
  }
}

/* Un link largo en un mensaje de WhatsApp se salia de la burbuja y el chat
   scrolleaba de costado en el celular (FE-069). Mismo criterio que el Mail. */
.message {
  overflow-wrap: anywhere;
}

/* El login (y la pantalla de error de arranque) no scrolleaban: con el celular
   acostado o muchos usuarios la tarjeta se cortaba abajo (FE-071). "safe
   center" centra si entra y, si no, arranca arriba y deja scrollear. */
.login-screen {
  overflow-y: auto;
  overscroll-behavior: contain;
  place-items: safe center;
}

/* Planning: el rack tiene un piso de alto. Con el formulario de Nueva reserva
   abierto (notebook) o el celular acostado se aplastaba a 0-3 px y no habia
   forma de llegar a el; ahora scrollea la pagina (FE-081). */
.app-shell:has(#planning.active) .planning-wrap {
  min-height: min(260px, 50dvh);
}

/* Estadisticas y Configuracion en el telefono son "una pantalla por vez": el
   menu solo, y al tocar una categoria, la categoria. En el menu se veia
   "Resumen" (o "Identidad") pintado como elegido aunque no se mostrara nada,
   y en Estadisticas el selector de periodo arriba del menu, donde no hace
   nada (auditoria 06/10, FE-074). El detalle de la reserva no entra aca: su
   menu se ve siempre. */
@media screen and (max-width: 980px) {
  .settings-shell:not(.settings-detail-open):not(.detalle-shell) .settings-nav-item.active {
    background: transparent;
    color: inherit;
    font-weight: inherit;
    box-shadow: none;
  }

  #estadisticas:has(#stats-shell:not(.settings-detail-open)) #stats-period-field {
    display: none;
  }
}

/* "Pagos registrados" marca el estado de cada pago: antes uno rechazado ("No
   entró") o esperando el banco se veia igual que uno cobrado (FE-031). El
   rechazado ademas va tachado, siempre con el texto y no solo el color. */
#payment-list .payment-row.estado-rechazado .payment-row-amount {
  text-decoration: line-through;
  color: var(--muted);
}

/* Hay plata esperando al banco: el mismo amarillo de "en revision" que el
   bloque del planning y el chip del pago (FE-032). */
.payment-balance-hint.esperando {
  color: var(--tint-yellow-ink);
  background: color-mix(in srgb, var(--yellow) 18%, var(--surface));
  border-radius: var(--radius-sm);
  padding: 6px 8px;
}

/* Tocar un producto del bar: un pulso corto confirma el toque mientras el
   pedido viaja (los toques van en fila y el boton ya no se apaga, FE-060). */
@keyframes gastro-producto-tocado {
  from { transform: scale(0.96); box-shadow: 0 0 0 3px var(--accent-soft); }
  to { transform: none; box-shadow: none; }
}
.gastro-producto-tocado { animation: gastro-producto-tocado 260ms ease-out; }
@media (prefers-reduced-motion: reduce) {
  .gastro-producto-tocado { animation: none; }
}


/* --- Ventanas (07/10, FE-034/FE-036) -------------------------------------
   Con una ventana abierta la pagina de atras no scrollea (la clase la pone
   acomodarVentanas en app.js), y los scrolls de adentro no le pasan el
   envion a la pagina al llegar al final. En el chat, ademas, tirar para abajo
   al principio de la lista ya no recarga el PMS en el celular. */
html.con-ventana {
  overflow: hidden;
  padding-right: var(--ancho-barra-de-scroll, 0px);
}
.pms-confirm-modal,
.pms-confirm-modal p,
.metric-detail-body,
.pms-help-body,
.messages,
.conversation-list,
.nav-bell-list {
  overscroll-behavior: contain;
}

/* El teclado del telefono tapaba "Confirmar" de las hojas que suben desde
   abajo. En Android alcanza con interactive-widget en el viewport; en iPhone
   la hoja sube lo que mide el teclado (--alto-teclado, de visualViewport). */
@media (max-width: 980px), (pointer: coarse) {
  .pms-confirm-backdrop {
    padding-bottom: var(--alto-teclado, 0px);
  }
}

/* Habitacion desactivada que todavia tiene reservas: se ve en el planning
   para poder moverlas, pero marcada (FE-064). */
.planning-row .cell.room.fuera-de-servicio {
  color: var(--muted);
  font-style: italic;
}
.planning-row .cell.room.fuera-de-servicio span {
  color: var(--tint-orange-ink);
  font-style: normal;
  font-weight: 600;
}

/* Temporadas que se pisan: dice quien cobra en esos dias (FE-094). */
.season-superpuesta {
  margin: 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--tint-orange-ink);
  background: color-mix(in srgb, var(--orange) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--orange) 40%, var(--line));
}


/* --- Celular y tablet (07/10) --------------------------------------------- */

/* El menu "Mas" en una notebook baja: sin tope, "Cerrar sesion" quedaba fuera
   de la pantalla (FE-041). En el telefono ya tienen su propio tope. */
@media screen and (min-width: 981px) {
  .topnav-dropdown {
    max-height: calc(100dvh - var(--alto-barra-superior, 56px) - 16px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}

/* Chat: en la computadora, la misma columna flex que el planning en vez de
   "100vh - 88px" calculado a ojo (sobraban 11px de pagina a 768 de alto).
   En el telefono acostado (412px) el min-height de 460 le ganaba al alto y la
   caja de responder quedaba abajo de la pantalla (FE-072). */
@media screen and (min-width: 981px) {
  .app-shell:has(#chat.active) {
    height: 100dvh;
    min-height: 0;
  }
  .app-shell:has(#chat.active) > .main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
  }
  .app-shell:has(#chat.active) #chat.active {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .app-shell:has(#chat.active) #chat.active > .chat-layout {
    height: auto;
    flex: 1 1 auto;
    min-height: 320px;
  }
}
@media screen and (max-width: 980px) {
  .chat-layout {
    min-height: 0;
  }
}

/* Toques de 44px en lo que se habia quedado chico en el telefono: reglas mas
   especificas le ganaban al bloque tactil general (FE-083). Las cruces chicas
   y los chips no crecen: crece el area que se puede tocar. */
@media (max-width: 980px), (pointer: coarse) {
  .precio-candado .ghost-button,
  .limpieza-aviso .ghost-button,
  .limpieza-pestana,
  .housekeeping-staff-select,
  .tareas-ver-mas,
  .carta-plato-mas {
    min-height: 44px;
  }
  .comparador-quitar,
  .mail-adjunto-quitar,
  .service-tag {
    position: relative;
  }
  .comparador-quitar::after,
  .mail-adjunto-quitar::after,
  .service-tag::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }
  .pms-datepicker-popover button {
    min-height: 40px;
  }
}

/* Barra de abajo del telefono: cada icono con su nombre debajo. Solo iconos
   no se entendia que era cada boton (FE-076). La flechita de "despliega" se
   saca: con el nombre abajo no entra y el menu se abre igual. */
@media screen and (max-width: 980px) {
  .topnav-item {
    flex-direction: column;
    gap: 2px;
    padding: 4px 4px 2px;
  }
  .topnav-item > span:not(.nav-icon):not(.nav-caret):not(.nav-badge) {
    display: block;
    font-size: 11px;
    line-height: 1.1;
    font-weight: 600;
    white-space: nowrap;
  }
  .topnav-item > .nav-caret {
    display: none;
  }
  /* El circulo de sin leer va sobre el icono, no abajo del nombre. */
  .topnav-item {
    position: relative;
  }
  .topnav-item > .nav-badge {
    position: absolute;
    top: 0;
    left: 50%;
    margin-left: 4px;
    min-width: 16px;
    height: 16px;
    font-size: 10px;
  }
}

/* Lista de Reservas en el telefono: la columna de plata se esconde, asi que
   el saldo va en el renglon de las fechas, con texto y no solo color (FE-082). */
.saldo-en-telefono {
  display: none;
}
@media screen and (max-width: 980px) {
  /* Cuatro clases: la regla que esconde los textos del segundo renglon de la
     fila en el telefono tiene tres. */
  .reservations-layout .reservation-row > div:nth-child(2) .saldo-en-telefono {
    display: block;
    color: var(--tint-red-ink);
    font-weight: 600;
  }
}

/* Cafeteria en el telefono: el ticket queda debajo de toda la carta. Un boton
   pegado abajo dice cuanto lleva el pedido y lleva al ticket (FE-080). */
.gastro-ir-al-ticket {
  display: none;
}
@media (max-width: 900px) {
  /* fixed y no sticky: la pantalla del pedido es una caja de alto fijo y su
     contenido la desborda, asi que un sticky no baja de su borde. */
  #gastro-pantalla-pedido .gastro-ir-al-ticket {
    display: block;
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: calc(var(--mobile-bottom-nav-space, 0px) + 8px);
    z-index: 25;
    box-shadow: var(--shadow-float);
  }
  /* Lugar para que el final del ticket ("Cobrar") no quede debajo del boton. */
  #gastro-pantalla-pedido .gastro-ticket {
    margin-bottom: 72px;
  }
}

/* Barra del planning en el telefono: "Bloquear" ocupaba un renglon entero
   para el solo; va en el mismo renglon que "Hoy" e "Ir a fecha" (FE-075). */
@media (max-width: 980px), (pointer: coarse) {
  .planning-toolbar .toolbar-group:has(> #planning-today) {
    flex: 1 1 auto;
    order: 1;
  }
  .planning-toolbar #open-bloqueo-form {
    flex: 0 0 auto;
    order: 2;
  }
  .planning-toolbar .toolbar-group:has(#planning-search) {
    order: 3;
  }
  .planning-toolbar #planning-resource-group {
    order: 4;
  }
}

/* El valor de un punto del grafico, al tocarlo (FE-068). */
.dato-del-grafico {
  position: absolute;
  z-index: 30;
  max-width: min(320px, 80vw);
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: var(--surface);
  font-size: 13px;
  line-height: 1.3;
  pointer-events: none;
  box-shadow: var(--shadow-float);
}

/* "Hay una version nueva del PMS · Recargar" (FE-098). Abajo y al centro, por
   encima de la barra del telefono; no tapa nada importante. */
.aviso-version-nueva {
  position: fixed;
  left: 50%;
  bottom: calc(var(--mobile-bottom-nav-space, 0px) + 16px);
  transform: translateX(-50%);
  z-index: 46;
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: calc(100vw - 32px);
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent-strong);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-float);
  font-size: 13px;
  font-weight: 600;
}
.aviso-version-nueva .link-button {
  font-weight: 700;
}

/* Error de un formulario, junto al boton de guardar: queda hasta que se toca
   algo (FE-044). Ocupa la fila entera en los formularios en grilla. */
.form-error {
  grid-column: 1 / -1;
  margin: 0;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  color: var(--tint-red-ink);
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--red) 40%, var(--line));
  font-size: 13.5px;
  font-weight: 600;
}
.form-error[hidden] {
  display: none;
}
[aria-invalid="true"] {
  border-color: var(--red) !important;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--red) 25%, transparent);
}

/* Con un error a la vista, los avisos que llegan despues van en renglones
   aparte, debajo (FE-045). */
.toast {
  white-space: pre-line;
}

/* ===========================================================================
   FORMULARIOS DE CARGA: INGRESO POR MOSTRADOR Y NUEVA RESERVA (11/10)
   ===========================================================================
   Los dos eran una grilla de cinco columnas (.reservation-form) donde cada
   campo caia donde entraba: "Entrada" quedaba al lado de "Acompañantes", los
   titulos de seccion no se mostraban en la computadora, y el boton y el precio
   cambiaban de lugar segun lo que se tildara. Nueva reserva, ademas, era un
   panel arriba del planning que le dejaba al rack 260px de alto. Ahora los dos
   son una pantalla con el mismo esquema:

   - Tres secciones en el orden en que se atiende (.carga-seccion): 1 Estadia y
     habitacion (que hay libre y a que precio), 2 Huesped, 3 lo que cierra la
     carga (extras y notas en el mostrador; canal, estado y notas en Nueva
     reserva). Cada una con su grilla propia, que se acomoda por el ancho de la
     SECCION (container query), no de la ventana.
   - A la derecha, fijo debajo de la barra de navegacion, el resumen: la
     habitacion, las fechas, el precio, el desglose y el boton. Lo que se
     pregunta ("cuanto es") y lo que se toca al final no se mueven.
   - En el telefono va todo en una columna y el resumen al final; el boton
     sigue pegado abajo (.form-accion) porque .carga-lateral es
     display:contents y el boton queda como hijo directo del formulario.

   Lo que pelea con reglas genericas (.reservation-form, .panel,
   .walkin-extra-item tienen reglas en varios lugares de este archivo) cuelga
   de :is(#mostrador, #nueva-reserva): un id le gana a todas sin pelear el
   orden. */

#mostrador,
#nueva-reserva {
  max-width: 1280px;
  margin-inline: auto;
}

.carga-bajada {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 13px;
}

:is(#mostrador, #nueva-reserva) .carga-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

@media (min-width: 981px) {
  :is(#mostrador, #nueva-reserva) .carga-form {
    grid-template-columns: minmax(0, 1fr) clamp(300px, 27vw, 360px);
    gap: 16px;
  }
}

.carga-cuerpo {
  display: grid;
  gap: 14px;
  min-width: 0;
}

/* --- Secciones ----------------------------------------------------------- */
:is(#mostrador, #nueva-reserva) .carga-seccion {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: 18px 20px 20px;
  container-type: inline-size;
}

.carga-seccion-cabecera {
  display: flex;
  align-items: center;
  gap: 10px;
}

.carga-seccion-cabecera h3 {
  margin: 0;
  color: var(--ink);
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -0.01em;
}

/* El numero del paso: neutro, no turquesa. El unico color fuerte de la
   pantalla es el boton de abajo del resumen. */
.carga-paso {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface-muted);
  color: var(--muted);
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.carga-campos {
  display: grid;
  gap: 12px 14px;
  /* Los campos se alinean por ABAJO: con una habitacion agregada el rotulo de
     personas pasa a "Personas (1ª habitación)" y puede ocupar dos renglones;
     alineados arriba, ese campo quedaba mas abajo que sus vecinos. */
  align-items: end;
}

/* Las labels de estos campos ya traen su estilo de .reservation-form label
   (rotulo chico y gris, campo debajo); aca solo se reparte el ancho. */
.carga-campos > label {
  min-width: 0;
}

.carga-campos-estadia {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.8fr) minmax(0, 1.5fr);
  grid-template-areas: "entrada salida personas habitacion";
}

.carga-campo-entrada { grid-area: entrada; }
.carga-campo-salida { grid-area: salida; }
.carga-campo-personas { grid-area: personas; }
.carga-campo-habitacion { grid-area: habitacion; }

/* La entrada del mostrador es siempre la noche en curso: se ve como dato, no
   como campo. */
#walkin-check-in[readonly] {
  background: var(--surface-muted);
  color: var(--muted);
  cursor: default;
}

.carga-campos-huesped {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Canal y estado son dos selectores cortos; las notas, texto libre: se llevan
   el doble. */
.carga-campos-origen {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 2fr);
}

/* Cuatro en fila necesitan ~760px: con menos, "Personas (1ª habitación)" (el
   rotulo cuando hay otra habitacion agregada) se partia en dos renglones. */
@container (max-width: 760px) {
  .carga-campos-estadia {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "entrada salida"
      "personas habitacion";
  }
}

@container (max-width: 640px) {
  .carga-campos-huesped {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .carga-campo-email,
  .carga-campo-domicilio {
    grid-column: 1 / -1;
  }
  .carga-campos-origen {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .carga-campos-origen .carga-campo-notas {
    grid-column: 1 / -1;
  }
}

/* En el telefono el nombre de la habitacion ("102 · Doble · 2 pax") no entra
   en media columna: va a lo ancho, y las personas tambien (un campo solo en
   media fila parece que le falta el compañero). */
@container (max-width: 420px) {
  .carga-campos-estadia {
    grid-template-areas:
      "entrada salida"
      "personas personas"
      "habitacion habitacion";
  }
}

:is(#mostrador, #nueva-reserva) .multi-habitaciones {
  margin-top: 0;
}

:is(#mostrador, #nueva-reserva) .companions-field {
  padding-top: 2px;
}

/* Los botones secundarios de las secciones ("+ Agregar otra habitación",
   "Agregar acompañantes") a la medida del texto de los campos: a su tamaño de
   siempre competian con los titulos de seccion. El alto tactil no cambia. */
:is(#mostrador, #nueva-reserva) .carga-seccion .ghost-button {
  font-size: 14px;
}

/* --- Extras del mostrador: tarjetas para tildar ---------------------------
   Nombre arriba y como se cobra abajo, en vez de "Desayuno buffet ·
   $9.000.-/huesped/noche" en una pastilla. Lo que suma en ESTE ingreso lo
   dice el resumen. */
#walkin-extras-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 8px;
}

#walkin-extras-list .walkin-extra-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: 13px;
  font-weight: 400;
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  #walkin-extras-list .walkin-extra-item:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  }
}

#walkin-extras-list .walkin-extra-item:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

#walkin-extras-list .walkin-extra-item:has(input:focus-visible) {
  outline: 2px solid var(--focus-outline);
  outline-offset: 2px;
}

#walkin-extras-list .walkin-extra-item input {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  min-height: 0;
  margin: 1px 0 0;
  accent-color: var(--accent);
}

#walkin-extras-list .walkin-extra-item.es-obligatorio {
  cursor: default;
}

.walkin-extra-texto {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.walkin-extra-nombre {
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.walkin-extra-precio {
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

#walkin-extras-list .walkin-extra-item:has(input:checked) .walkin-extra-precio {
  color: var(--accent-strong);
}

#mostrador .vehiculo-campos {
  margin-top: 0;
}

/* --- El resumen ------------------------------------------------------------ */
.carga-lateral {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.carga-resumen {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.carga-resumen > .eyebrow {
  margin: 0;
}

.carga-resumen p {
  margin: 0;
}

.carga-resumen-estadia {
  display: grid;
  gap: 4px;
}

.carga-resumen-habitacion {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
}

.carga-resumen-habitacion strong {
  color: var(--ink);
  font-size: 24px;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.carga-resumen-habitacion span {
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
}

.carga-resumen-fechas {
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
}

.carga-resumen-cuenta,
.carga-resumen-vacio {
  color: var(--muted);
  font-size: 13px;
}

.carga-resumen-vacio {
  line-height: 1.45;
}

.carga-campo-total input {
  min-height: 44px;
  font-size: 18px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* La promo por pagar el 100%: pegada al precio, que es lo que cambia. */
/* nowrap: con el wrap de .checkbox-field, el texto (mas largo que lo que queda
   al lado del tilde) bajaba entero al renglon de abajo y el tilde quedaba solo
   arriba. */
:is(#mostrador, #nueva-reserva) .carga-promo {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 8px;
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
}

/* El tamaño del tilde lo pone .checkbox-field (24px en tactil). */
:is(#mostrador, #nueva-reserva) .carga-promo input {
  accent-color: var(--accent);
}

:is(#mostrador, #nueva-reserva) .carga-promo > span {
  flex: 1 1 auto;
  min-width: 0;
}

.carga-desglose {
  display: grid;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.carga-desglose:empty,
.carga-avisos:empty {
  display: none;
}

.carga-desglose .desglose-del-total {
  gap: 6px;
  font-size: 13px;
}

.carga-desglose .desglose-del-total li > span:last-child {
  font-variant-numeric: tabular-nums;
}

.carga-total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
}

.carga-total strong {
  color: var(--ink);
  font-size: 20px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Sin recuadro propio: cada aviso es su renglon. */
.carga-avisos {
  display: grid;
  gap: 6px;
}

/* Un aviso por renglon. "error" es lo que impide crear (la habitacion no esta
   libre): el mismo rojo que el error de un formulario (.form-error).
   "atencion" es estado (amarillo, como todo lo que hay que revisar antes de
   cobrar); "info" es Agua, como el resto de los avisos informativos. */
.carga-aviso {
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  line-height: 1.4;
}

.carga-aviso.es-info {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.carga-aviso.es-atencion {
  border-color: color-mix(in srgb, var(--yellow) 45%, var(--line));
  background: color-mix(in srgb, var(--yellow) 14%, var(--surface));
  color: var(--tint-yellow-ink);
}

.carga-aviso.es-error {
  border-color: color-mix(in srgb, var(--red) 40%, var(--line));
  background: color-mix(in srgb, var(--red) 10%, var(--surface));
  color: var(--tint-red-ink);
  font-weight: 600;
}

.carga-lateral .form-accion {
  width: 100%;
  min-height: 48px;
  font-size: 15px;
}

@media (min-width: 981px) {
  /* Una sola tarjeta con el resumen y el boton, pegada debajo de la barra de
     navegacion mientras se completa lo de la izquierda. */
  .carga-lateral {
    position: sticky;
    top: calc(var(--alto-barra-superior, 56px) + 16px);
    padding: 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-raised);
  }
}

/* Los selectores a la altura de los campos de al lado. La regla tactil
   general les da 44px, pero .reservation-form select y .multi-fila select (mas
   especificas) los dejaban en 40 y 36: el de la habitacion quedaba mas bajo que
   la entrada y las personas. Y 16px de letra, por el zoom de Safari. */
@media (max-width: 980px), (pointer: coarse) {
  :is(#walkin-form, #reservation-form) select {
    min-height: 44px;
    font-size: 16px;
  }
}

@media (max-width: 980px) {
  :is(#mostrador, #nueva-reserva) .carga-seccion {
    padding: 16px;
  }
  .carga-lateral {
    display: contents;
  }
  .carga-resumen {
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    background: var(--surface);
  }
}
