/* ============================================================
   custom.css — Estilos del Panel de Administración OKmystay
   Bootstrap 4 como base, colores neutros, sidebar izquierdo.
   Variables de color inyectadas dinámicamente desde base.html.
   ============================================================ */

/* ---- Enlace discreto: navega pero SIN estética de link ----
   Sin subrayado, hereda el color del contexto (no azul), solo el cursor
   "dedo" al pasar por encima delata que es clicable. Para accesos directos
   embebidos en cabeceras/etiquetas donde el azul subrayado distrae. */
a.link-plain,
a.link-plain:hover,
a.link-plain:focus {
    color: inherit;
    text-decoration: none;
}
a.link-plain { cursor: pointer; }

/* ---- Variables de color (valores por defecto, se sobreescriben en JS) ---- */
:root {
    --sidebar-width: 220px;
    --sidebar-bg: #2c3e50;
    --sidebar-text: #ecf0f1;
    --sidebar-active-bg: #1a252f;
    --sidebar-hover-bg: #34495e;
    --brand-ok-color: #2980b9;
    --accent-blue: #3498db;
    --accent-color: #2ecc71;
    --border-color: #dee2e6;
    --body-bg: #f8f9fa;
    --text-color: #343a40;
    --card-bg: #ffffff;
}

/* ============================================================
   LAYOUT GENERAL
   ============================================================ */

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 0.9rem;
    background-color: var(--body-bg);
    color: var(--text-color);
}

/* Wrapper principal: sidebar + contenido en fila */
#wrapper {
    min-height: 100vh;
}

/* ============================================================
   SIDEBAR
   ============================================================ */

#sidebar-wrapper {
    width: var(--sidebar-width);
    min-height: 100vh;
    background-color: var(--sidebar-bg);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    left: 0;
    height: 100%;
    overflow-y: auto;
    z-index: 100;
    transition: transform 0.2s ease;
}

/* ===== TOGGLE DEL SIDEBAR EN ESCRITORIO ===== */

.sidebar-collapse-btn {
    position: absolute;
    top: 8px;
    right: 8px;
    background: transparent;
    border: 1px solid rgba(255,255,255,0.15);
    color: rgba(255,255,255,0.55);
    border-radius: 4px;
    padding: 1px 6px;
    cursor: pointer;
    font-size: 0.75rem;
    line-height: 1.2;
    transition: color 0.15s, border-color 0.15s;
    z-index: 5;
}

.sidebar-collapse-btn:hover {
    color: #fff;
    border-color: rgba(255,255,255,0.4);
}

.sidebar-show-btn {
    display: none;
    position: fixed;
    top: 12px;
    left: 12px;
    z-index: 200;
    background: var(--sidebar-bg);
    color: rgba(255,255,255,0.85);
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 4px;
    padding: 4px 9px;
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1.3;
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
    transition: color 0.15s, background-color 0.15s;
}

.sidebar-show-btn:hover {
    background: var(--sidebar-hover-bg);
    color: #fff;
}

/* Cuando body.sidebar-collapsed: ocultar sidebar y ampliar contenido */
@media (min-width: 769px) {
    body.sidebar-collapsed #sidebar-wrapper {
        transform: translateX(-100%);
    }
    body.sidebar-collapsed #page-content-wrapper {
        margin-left: 0;
    }
    /* Padding-left para que el contenido no quede tapado por el botón flotante */
    body.sidebar-collapsed .content-area {
        padding-left: 50px;
    }
    body.sidebar-collapsed .sidebar-show-btn {
        display: block;
    }
    #page-content-wrapper {
        transition: margin-left 0.2s ease;
    }
}

/* Cabecera del sidebar */
.sidebar-heading {
    padding: 1.2rem 1rem 0.8rem;
    font-size: 1.1rem;
    font-weight: 700;
    color: #ecf0f1;
    border-bottom: 1px solid rgba(255,255,255,0.1);
    letter-spacing: 0.02em;
    text-align: center;
}

/* Logo de empresa en la cabecera */
.sidebar-logo {
    max-width: 140px;
    max-height: 45px;
    object-fit: contain;
    display: block;
    margin: 0 auto 4px;
    filter: brightness(0) invert(1);
}

/* "OK" en color de marca */
.brand-ok { color: var(--brand-ok-color); }

.sidebar-clock {
    font-size: 0.7rem;
    font-weight: 400;
    color: rgba(255,255,255,0.45);
    margin-top: 0.2rem;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.04em;
}

/* Nombre del usuario */
.sidebar-user {
    padding: 0.7rem 1rem;
    color: rgba(255,255,255,0.7);
    font-size: 0.8rem;
}

/* Elementos del menú */
#sidebar-wrapper .list-group-item {
    background-color: transparent;
    border: none;
    border-radius: 0;
    color: rgba(255,255,255,0.8);
    padding: 0.5rem 1rem;
    font-size: 0.875rem;
    transition: background-color 0.15s;
}

/* Root ve más items en el sidebar (Mantenimientos, Admin…), así que
   apretamos un poco más la separación para que quepan sin scroll. */
body.is-super-admin #sidebar-wrapper .list-group-item {
    padding: 0.35rem 1rem;
}

#sidebar-wrapper .list-group-item:hover {
    background-color: var(--sidebar-hover-bg);
    color: #fff;
    text-decoration: none;
}

#sidebar-wrapper .list-group-item.active {
    background-color: var(--sidebar-active-bg);
    color: #fff;
    font-weight: 600;
    border-left: 3px solid var(--brand-ok-color);
}

/* Separador antes del logout */
.sidebar-separator {
    height: 1px;
    background-color: rgba(255,255,255,0.1);
    margin: 0.5rem 0;
}

/* Logout en rojo suave */
.sidebar-logout { color: rgba(255,150,150,0.85) !important; }
.sidebar-logout:hover { color: #fff !important; background-color: #c0392b !important; }

/* "Powered by OKmystay" pegado al fondo del sidebar, centrado y pequeño */
.sidebar-powered-by {
    margin-top: auto;
    text-align: center;
    padding: 0.75rem 0.5rem;
    font-size: 0.65rem;
    line-height: 1;
}
.sidebar-powered-by a {
    color: rgba(255,255,255,0.35);
    text-decoration: none;
}
.sidebar-powered-by a:hover {
    color: rgba(255,255,255,0.75);
    text-decoration: none;
}

/* ============================================================
   SELECTOR DE TEMA Y EMPRESA EN SIDEBAR
   ============================================================ */

.theme-selector {
    padding: 0.6rem 1rem;
    border-top: 1px solid rgba(255,255,255,0.1);
}

/* El selector de empresa va pegado al nick; su borde superior duplicaría
   la raya que ya hay encima del nick. Lo quitamos solo en ese caso. */
.sidebar-user + .theme-selector {
    border-top: none;
    padding-top: 0;
}

/* El .sidebar-separator (antes del logout/tema) ya pinta una raya y deja
   margen; el border-top del .theme-selector justo debajo duplicaría la
   línea. Quitamos el borde redundante solo en ese caso. */
.sidebar-separator + .theme-selector {
    border-top: none;
}

.theme-selector select {
    width: 100%;
    background-color: rgba(255,255,255,0.1);
    border: 1px solid rgba(255,255,255,0.2);
    color: rgba(255,255,255,0.85);
    border-radius: 4px;
    padding: 4px 6px;
    font-size: 0.78rem;
    cursor: pointer;
}

.theme-selector select:focus {
    outline: none;
    border-color: var(--brand-ok-color);
}

.theme-selector select option {
    background-color: #2c3e50;
    color: #fff;
}

.theme-selector-label {
    font-size: 0.68rem;
    color: rgba(255,255,255,0.45);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 4px;
    display: block;
}

/* ============================================================
   CONTENIDO PRINCIPAL
   ============================================================ */

#page-content-wrapper {
    margin-left: var(--sidebar-width);
    flex: 1;
    min-width: 0;
}

/* Barra superior */
.top-navbar {
    padding: 0.5rem 1.5rem;
    background: #fff;
    border-bottom: 1px solid var(--border-color) !important;
    min-height: 50px;
}

.page-title {
    font-size: 1rem;
    font-weight: 600;
    color: #495057;
}

/* Zona de contenido */
.content-area {
    padding: 1rem 1.5rem 2rem;
}

/* Top navbar oculta en escritorio: el sidebar ya identifica la página */
@media (min-width: 769px) {
    .top-navbar { display: none; }
}

/* Cabecera de página más compacta */
.page-header h2 {
    font-size: 1.4rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

/* ============================================================
   TARJETAS DE ESTADÍSTICAS (dashboard)
   ============================================================ */

.stat-card {
    border-radius: 6px;
    border: 1px solid var(--border-color);
}

.border-left-primary   { border-left: 4px solid #007bff !important; }
.border-left-success   { border-left: 4px solid #28a745 !important; }
.border-left-info      { border-left: 4px solid #17a2b8 !important; }
.border-left-warning   { border-left: 4px solid #ffc107 !important; }
.border-left-secondary { border-left: 4px solid #6c757d !important; }
.border-left-danger    { border-left: 4px solid #dc3545 !important; }

.stat-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 0.3rem;
}

.stat-value {
    font-size: 1.8rem;
    font-weight: 700;
    color: #343a40;
    line-height: 1;
}

.stat-link {
    display: block;
    margin-top: 0.4rem;
    color: var(--accent-blue);
}

/* Tarjeta compacta de resumen del dashboard: 3 líneas con label a la
   izquierda y número en grande a la derecha (clicable). */
.dashboard-summary-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.25rem 0;
}
.dashboard-summary-line + .dashboard-summary-line {
    border-top: 1px solid var(--border-color);
}
.dashboard-summary-label {
    flex: 1 1 auto;
    letter-spacing: 0.06em;
}
.dashboard-summary-num {
    flex: 0 0 auto;
    font-size: 1.6rem;
    font-weight: 700;
    color: #343a40;
    line-height: 1;
    text-decoration: none;
}
.dashboard-summary-num:hover,
.dashboard-summary-num:focus {
    color: var(--accent-blue);
    text-decoration: none;
}

/* ============================================================
   TARJETAS DE PROPIEDAD
   ============================================================ */

.property-card {
    border-radius: 6px;
    border: 1px solid var(--border-color);
    box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}

.property-card .card-header {
    background-color: #f8f9fa;
    font-size: 0.9rem;
}

/* ============================================================
   BOTONES EXTRA PEQUEÑOS
   ============================================================ */

.btn-xs {
    padding: 0.15rem 0.45rem;
    font-size: 0.75rem;
    line-height: 1.3;
    border-radius: 3px;
}

/* Feedback del botón abrir */
.open-feedback {
    font-size: 0.8rem;
    vertical-align: middle;
}

/* ============================================================
   CALENDARIO AGRUPADO (admin)
   ============================================================ */

.calendar-wrap { overflow-x: auto; }

.calendar-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

.calendar-table th {
    text-align: center;
    padding: 6px 4px;
    font-size: 0.75rem;
    font-weight: 600;
    color: #6c757d;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 2px solid var(--border-color);
}

.calendar-table td {
    vertical-align: top;
    border: 1px solid #e9ecef;
    padding: 4px;
    min-height: 60px;
    height: 60px;
}

/* Número del día */
.cal-day-num {
    font-size: 0.75rem;
    font-weight: 600;
    color: #495057;
    display: block;
    text-align: right;
    margin-bottom: 2px;
}

/* Día de hoy resaltado — borde izquierdo grueso + fondo levemente azul +
   número del día en negrita y con badge circular. El borde es lo que
   realmente "salta" sin teñir toda la caja, que dificultaba leer los
   badges E/A/S. */
.cal-today {
    background-color: #e3f0ff;
    box-shadow: inset 4px 0 0 0 var(--accent-blue);
}
.cal-today .cal-day-num {
    color: #fff;
    background-color: var(--accent-blue);
    font-weight: 700;
    border-radius: 999px;
    padding: 0 7px;
    line-height: 1.35;
    width: fit-content;
    margin-left: auto;
}

/* Días fuera del mes */
.cal-outside { background-color: #fafafa; opacity: 0.5; }

/* Contador de reservas por día — badge central en la celda */
.cal-count {
    display: block;
    text-align: center;
    font-size: 1.1rem;
    font-weight: 700;
    border-radius: 4px;
    padding: 2px 4px;
    margin-top: 2px;
    cursor: default;
}

/* Colores según volumen: verde < 5, amarillo 5-9, rojo >= 10 */
.cal-count-low    { color: #155724; background-color: #d4edda; }
.cal-count-medium { color: #856404; background-color: #fff3cd; }
.cal-count-high   { color: #721c24; background-color: #f8d7da; }

/* Calendario de Amapola (/amapola/reservas): variante COMPACTA. Solo muestra
   UN contador por día (no los 3 badges E/A/S del calendario de /reservas), así
   que las celdas de 60px sobran -> a ~mitad de alto. Scopeado al contenedor
   para NO afectar al calendario compartido de /reservas. */
/* Solo hay un número por día -> el calendario no necesita ocupar todo el
   ancho del contenido. Acotamos el CARD ENTERO (cabecera con flechas +
   rejilla) y lo centramos, así las flechas se ciñen al ancho real del
   calendario en lugar de flotar en los bordes de un card a 100%. */
#amapola-calendar-card {
    max-width: 560px;
    /* Alineado a la izquierda (sin margin auto) para que cuadre con el
       listado de abajo, que arranca pegado a la izquierda. */
}
#amapola-calendar-container .calendar-table td {
    height: 34px;
    min-height: 34px;
    padding: 2px 5px;
}
#amapola-calendar-container .calendar-table th { padding: 3px 4px; }
#amapola-calendar-container .cal-day-num {
    font-size: 0.7rem;
    margin-bottom: 0;
    line-height: 1.1;
}
#amapola-calendar-container .cal-count {
    font-size: 0.85rem;
    padding: 0 5px;
    margin-top: 1px;
}
#amapola-calendar-container .cal-today .cal-day-num { line-height: 1.15; }

/* Tres badges por celda: entradas / activas / salidas */
.cal-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    margin-top: 2px;
}

.cal-badge {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 1px 4px;
    border-radius: 3px;
    line-height: 1.1;
    cursor: default;
}

.cal-badge i { font-size: 0.7rem; }

.cal-badge-clickable { cursor: pointer; transition: filter 0.1s, transform 0.1s; }
.cal-badge-clickable:hover { filter: brightness(0.92); transform: translateY(-1px); }
.cal-badge-clickable:active { transform: translateY(0); }

/* Entradas: verde (mismo color que place-today-checkin del cleaners… aquí
   uso el verde estándar de checkin) */
.cal-badge-in  { background: #eafaf1; color: #1e8449; }

/* Salidas: naranja (mismo tono que place-today-checkout invertido) */
.cal-badge-out { background: #fef5ec; color: #b7570e; }

/* Activas: gradiente según volumen */
.cal-badge-active-low    { background: #eaf4fb; color: #1a6fa0; }
.cal-badge-active-medium { background: #fff3cd; color: #856404; }
.cal-badge-active-high   { background: #f8d7da; color: #721c24; }

/* Amapola: la celda ENTERA del día es clicable (no solo el badge) para
   filtrar el listado por ese día. `cal-sel` marca el día seleccionado con
   un contorno verde de marca; convive con `cal-today` (borde azul). */
.cal-clickable { cursor: pointer; }
.cal-clickable:hover { background-color: #eef4fb; }
.cal-sel { box-shadow: inset 0 0 0 2px var(--accent-color); }
.cal-today.cal-sel {
    box-shadow: inset 4px 0 0 0 var(--accent-blue), inset 0 0 0 2px var(--accent-color);
}

/* ============================================================
   AMAPOLA — AGENDA (timeline día por recurso, Fase 2)
   Posiciones (top/height en px) las calcula el backend; aquí solo el
   chrome. Escala vertical: _AGENDA_PX_PER_HOUR (routes/amapola.py).
   ============================================================ */
/* Layout de la página de agenda: columna flex que llena el viewport (en
   escritorio el top-navbar está oculto, así que content-area arranca arriba).
   El timeline (.amap-agenda-scroll) toma el hueco restante con flex y scrollea
   DENTRO de sí mismo solo si el día no cabe -> la PÁGINA nunca scrollea y un
   día que cabe no muestra ninguna barra. Sin medición JS ni offsets frágiles. */
@media (min-width: 769px) {
    .amap-agenda-page {
        display: flex;
        flex-direction: column;
        height: calc(100vh - 3rem);   /* = padding vertical de .content-area (1rem+2rem) */
    }
    .amap-agenda-page > .page-header { flex: 0 0 auto; }
    .amap-agenda-page > #amap-ajax-body {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }
    /* El timeline llena el resto; los controles de arriba y la nota de abajo
       conservan su alto natural. */
    #amap-ajax-body > .amap-agenda-scroll { flex: 1 1 auto; min-height: 0; }
}
.amap-agenda-scroll {
    /* Scroll interno en ambos ejes. La cabecera sticky y las horas quedan
       fijas dentro de este scroll. */
    overflow: auto;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: #fff;
}
.amap-agenda-head {
    display: flex;
    border-bottom: 2px solid var(--border-color);
    background: #f8f9fa;
    position: sticky;
    top: 0;
    z-index: 3;
}
.amap-agenda-head-spacer { flex: 0 0 54px; width: 54px; }
.amap-agenda-col-head {
    flex: 1 1 0;
    min-width: 130px;
    padding: 6px 8px;
    text-align: center;
    border-left: 1px solid #eee;
    font-size: 0.8rem;
}
.amap-col-name {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Columna "hoy" en la vista semana */
.amap-agenda-col-head.amap-col-today {
    background: #e3f0ff;
    box-shadow: inset 0 -3px 0 0 var(--accent-blue);
}
.amap-agenda-body { display: flex; position: relative; }
.amap-agenda-hours { flex: 0 0 54px; width: 54px; position: relative; }
.amap-hour-label {
    position: absolute;
    right: 5px;
    transform: translateY(-50%);
    font-size: 0.65rem;
    color: #999;
}
/* Horas comprimidas (madrugada / fuera de jornada): etiqueta y línea atenuadas */
.amap-hour-label.amap-hour-compressed { opacity: 0.4; font-size: 0.58rem; }
.amap-hour-line-compressed { border-top-color: #fafafa; }
.amap-agenda-lanes { display: flex; flex: 1 1 auto; position: relative; }
.amap-lane {
    flex: 1 1 0;
    min-width: 130px;
    position: relative;
    border-left: 1px solid #eee;
}
.amap-hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid #f2f2f2; }
.amap-lane-window { position: absolute; left: 0; right: 0; background: #eef6ff; }
.amap-item {
    position: absolute;
    left: 3px;
    right: 3px;
    border-radius: 4px;
    padding: 2px 5px;
    overflow: hidden;
    font-size: 0.68rem;
    line-height: 1.15;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    cursor: default;
}
.amap-item-time { font-weight: 700; font-size: 0.62rem; opacity: 0.85; }
.amap-item-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.amap-item-sub { color: #555; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.amap-item-active { background: #d4edda; border-left: 3px solid #28a745; }
.amap-item-hold { background: #fff3cd; border-left: 3px solid #ffc107; }
.amap-item-busy {
    background: repeating-linear-gradient(45deg, #f1f1f1, #f1f1f1 6px, #e6e6e6 6px, #e6e6e6 12px);
    border-left: 3px solid #adb5bd;
    color: #555;
}
/* Cuadraditos de la leyenda */
.amap-legend {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    vertical-align: middle;
    margin-right: 2px;
}
.amap-legend-window { background: #eef6ff; border: 1px solid #cfe2ff; }

/* ============================================================
   PÁGINA DE LOGIN
   ============================================================ */

.login-page {
    background-color: #f0f2f5;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}

.login-wrapper {
    width: 100%;
    max-width: 380px;
    padding: 1rem;
}

.login-card {
    border: none;
    border-radius: 8px;
}

.login-brand {
    font-size: 1.8rem;
    font-weight: 700;
    color: #2c3e50;
}

/* ============================================================
   TEMAS — variables aplicadas dinámicamente desde base.html
   ============================================================ */

#sidebar-wrapper              { background-color: var(--sidebar-bg); }
#sidebar-wrapper .list-group-item:hover  { background-color: var(--sidebar-hover-bg); }
#sidebar-wrapper .list-group-item.active {
    background-color: var(--sidebar-active-bg);
    border-left-color: var(--brand-ok-color);
}
.card, .modal-content { background-color: var(--card-bg); }

/* ============================================================
   RESPONSIVE: hamburguesa en móvil
   ============================================================ */

@media (max-width: 768px) {
    #sidebar-wrapper {
        display: none;
        position: fixed;
        top: 0;
        left: 0;
        height: 100%;
        z-index: 999;
        width: 220px;
    }

    #sidebar-wrapper.sidebar-open {
        display: flex;
    }

    #page-content-wrapper {
        margin-left: 0;
    }
}

/* ============================================================
   PÁGINA DE PROPIEDADES — copiado de cleaners (mismo estilo)
   ============================================================ */

/* ===== BUSCADOR ===== */

.search-box {
    position: relative;
}

.search-icon {
    position: absolute;
    left: 11px;
    top: 50%;
    transform: translateY(-50%);
    color: #adb5bd;
    pointer-events: none;
    font-size: 14px;
    z-index: 1;
}

.search-box .form-control {
    padding-left: 32px;
    border-radius: 8px;
    font-size: 14px;
}

/* ===== FILTRO DE ACTIVIDAD ===== */

.activity-filter {
    display: flex;
    gap: 8px;
}

.btn-activity {
    flex: 1;
    padding: 8px 10px;
    font-size: 13px;
    font-weight: 600;
    border-radius: 8px;
    border: 1.5px solid var(--border-color);
    background: #fff;
    color: #6c757d;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s, color 0.15s;
    text-align: center;
}

.btn-activity.active {
    background-color: #2c3e50;
    border-color: #2c3e50;
    color: #fff;
}

.btn-activity:not(.active):hover {
    border-color: #2c3e50;
    color: #2c3e50;
}

/* ===== FILTRO DE LOCALIDAD ===== */

.locality-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.btn-locality {
    background-color: #fff;
    border: 1.5px solid var(--border-color);
    border-radius: 20px;
    padding: 5px 14px;
    font-size: 13px;
    color: #495057;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s, color 0.15s;
    white-space: nowrap;
}

.btn-locality:hover {
    border-color: var(--accent-color);
    color: #2c3e50;
}

.btn-locality.active {
    background-color: var(--accent-color);
    border-color: var(--accent-color);
    color: #fff;
    font-weight: 600;
}

.locality-count {
    display: inline-block;
    background-color: rgba(0,0,0,0.12);
    border-radius: 10px;
    padding: 0 6px;
    font-size: 11px;
    margin-left: 4px;
    font-weight: 700;
    vertical-align: middle;
}

.btn-locality.active .locality-count,
.btn-activity.active .locality-count {
    background-color: rgba(255,255,255,0.3);
}

/* ===== TARJETAS DE PROPIEDADES ===== */

.place-card {
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
    background: #fff;
    height: 100%;
    position: relative; /* ancla del pin de Google Maps (.place-maps-link) */
}

/* Pin de Google Maps — hermano del <a> de cabecera (no puede anidarse
   dentro porque la cabecera entera ya es un enlace a la ficha). */
.place-maps-link {
    position: absolute;
    top: 6px;
    right: 6px;
    padding: 2px 4px;
    line-height: 1;
    z-index: 2;
    border-radius: 4px;
}
.place-maps-link:hover {
    background: rgba(0, 0, 0, 0.06);
}
.place-maps-link svg {
    display: block;
    width: 12px;
    height: 17px;
}
/* Reserva hueco en la cabecera para que el nombre no quede bajo el pin */
.place-card-header.has-maps {
    padding-right: 28px;
}

/* Propiedad desactivada (state=0) — solo la ve root; va al final del
   listado, atenuada y con borde ámbar discontinuo + badge INACTIVA. */
.place-card-inactive {
    opacity: 0.6;
    border: 1px dashed #e0a800;
}
.place-card-inactive:hover { opacity: 0.9; }
.place-inactive-badge {
    font-size: 0.62rem;
    vertical-align: middle;
}

.place-card-header {
    padding: 8px 10px;
    background: #f1f3f5;
    border-bottom: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.place-name {
    display: block;
    font-size: 12px;
    font-weight: 700;
    color: #2c3e50;
    line-height: 1.3;
    word-break: break-word;
}

.place-name .place-id,
.place-name .place-locality {
    font-weight: 400;
    color: #6c757d;
}

/* Etiqueta con el tipo de propiedad (Apartamento, Parking, Taquillas…).
   El color de fondo viene por tipo desde domopaco_place_types.color
   (paleta pastel; inline style en la plantilla). Solo se pinta cuando el
   listado tiene MÁS de un tipo (si no, sería ruido idéntico). El estilo de
   aquí es el fallback cuando el tipo no tiene color asignado en BD. */
.place-type-badge {
    display: inline-block;
    font-size: 9px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: #6c757d;
    background: #e9ecef;
    border: 1px solid #dee2e6;
    border-radius: 3px;
    padding: 0 4px;
    line-height: 1.4;
    vertical-align: middle;
    white-space: nowrap;
}

/* Nombre que ve el huésped en su panel (panel_name > channel_name > name),
   solo cuando difiere del nombre interno mostrado en grande. */
.place-guest-name {
    display: block;
    font-size: 11px;
    color: #6c757d;
    line-height: 1.3;
    word-break: break-word;
}
.place-guest-name .bi { opacity: 0.7; }

a.place-card-header {
    text-decoration: none;
    color: inherit;
    transition: background-color 0.15s;
}

a.place-card-header:hover {
    background: #e9ecef;
    text-decoration: none;
    color: inherit;
}

.place-address {
    display: block;
    font-size: 11px;
    color: #6c757d;
    line-height: 1.3;
    word-break: break-word;
}

.place-card-body {
    padding: 3px;
}

/* ===== CERRADURAS ===== */

/* Las cerraduras de una propiedad fluyen inline y envuelven, en lugar
   de apilarse una por línea (cards parejas aunque haya 11 cerraduras).
   Cada .lock-item sigue siendo una mini-columna chip + .lock-result,
   así el feedback de apertura queda pegado a su propio chip al envolver. */
.locks-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 3px 5px;
    align-items: flex-start;
}

.lock-item {
    margin-bottom: 0;
}

/* Fila con el botón de abrir + el atajo "ver detalle" alineados.
   El botón de abrir crece para ocupar el espacio disponible; el
   atajo de detalle queda a la derecha con anchura fija. */
.lock-row {
    gap: 4px;
}
.lock-row .btn-abrir {
    flex: 1 1 auto;
    width: auto;
}

.btn-abrir {
    display: block;
    width: 100%;
    padding: 5px 6px;
    font-size: 13px;
    font-weight: 600;
    background: #fff;
    border: 1.5px solid var(--accent-color);
    color: var(--accent-color);
    border-radius: 6px;
    text-align: center;
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s;
    white-space: normal;
    word-break: break-word;
    line-height: 1.3;
}

.btn-abrir:hover,
.btn-abrir:active {
    background: var(--accent-color);
    color: #fff;
}

.btn-abrir:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Atajo "→" al detalle de la cerradura, junto al botón de abrir.
   En gris para no competir visualmente con el botón principal. */
.btn-lock-detail {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 32px;
    padding: 0 6px;
    font-size: 14px;
    background: #fff;
    border: 1.5px solid #ced4da;
    color: #6c757d;
    border-radius: 4px;
    text-decoration: none;
}
.btn-lock-detail:hover,
.btn-lock-detail:focus {
    background: #f8f9fa;
    color: #495057;
    border-color: #adb5bd;
    text-decoration: none;
}

.lock-result {
    font-size: 11px;
    text-align: center;
}

.lock-result:not(:empty) {
    min-height: 16px;
    margin-top: 3px;
}

.no-locks {
    font-size: 11px;
    color: #adb5bd;
    margin: 0;
}

/* ===== RESERVAS DE HOY ===== */

.place-today {
    margin-top: 4px;
    padding-top: 4px;
    border-top: 1px solid var(--border-color);
}

.place-today-item {
    display: block;
    font-size: 11px;
    font-weight: 600;
    padding: 2px 5px;
    border-radius: 4px;
    margin-bottom: 2px;
    text-decoration: none;
}

.place-today-item:hover { opacity: 0.8; text-decoration: none; }

.place-today-checkout { background: #eafaf1; color: #1e8449; }
.place-today-checkin  { background: #fef5ec; color: #b7570e; }
.place-today-active   { background: #eaf4fb; color: #1a6fa0; }

.place-today-guests {
    font-weight: 400;
    opacity: 0.8;
}

.booking-extra-guest {
    display: inline-block;
    font-size: 11px;
    font-weight: 500;
    color: #6c757d;
    margin-left: 4px;
}

.booking-extra-purchase {
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    color: #d68910;
    margin-left: 4px;
}

/* ===== FICHA DETALLE DE PROPIEDAD ===== */

.detail-card {
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: #fff;
    overflow: hidden;
    height: 100%;
}

/* Columna que APILA varios .detail-card en vertical (p.ej. Aforo + Camas en
   la ficha de propiedad). El height:100% de arriba está pensado para 1 card
   por columna (equipara la altura de la pareja L-R del grid); con dos cards
   hermanos en una misma columna cada uno intentaría el 100% y se solaparían.
   Aquí cada card toma su altura natural y se apilan. */
.detail-card-stack .detail-card { height: auto; }

.detail-card-header {
    padding: 8px 12px;
    background: #f1f3f5;
    border-bottom: 1px solid var(--border-color);
    font-size: 13px;
    font-weight: 600;
    color: #2c3e50;
}

.detail-card-body {
    padding: 8px 12px;
}

/* Typeahead embebido en un .detail-card: el desplegable de resultados
   (.live-results, position:absolute, cuelga bajo el input) debe poder
   DESBORDAR el card hacia abajo. Sin esto, el overflow:hidden de .detail-card
   (que existe para redondear las esquinas del header) recorta el desplegable a
   la altura del propio card — que en fichas con poco contenido es minúscula,
   dejando la lista de resultados aplastada en un scroll de 2-3 filas
   ("escondida"). Se compensa el radio de las esquinas superiores del header,
   que antes clipaba el propio overflow:hidden.

   Regla por id: garantiza el caso reportado (card de permisos) en TODOS los
   navegadores. Va PRIMERO y en su propia regla — si se agrupara con el
   selector :has() de abajo, un navegador sin soporte de :has() descartaría la
   regla entera y perdería también este fallback. */
#user-perms-card { overflow: visible; }
#user-perms-card > .detail-card-header {
    border-top-left-radius: 7px;
    border-top-right-radius: 7px;
}

/* Regla GENERAL preventiva: cualquier .detail-card con un typeahead dentro.
   :has() es dinámico (cubre cuerpos inyectados por AJAX) y degrada con gracia
   en navegadores sin soporte (peor caso = el clip de siempre). En su propia
   regla para no arrastrar el fallback de arriba si :has() no está soportado. */
.detail-card:has(.live-results) { overflow: visible; }
.detail-card:has(.live-results) > .detail-card-header {
    border-top-left-radius: 7px;
    border-top-right-radius: 7px;
}

.detail-row {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 5px 0;
    border-bottom: 1px solid #f0f0f0;
    font-size: 13px;
    gap: 2px;
}

.detail-row:last-child { border-bottom: none; }

/* Dos .detail-row en la misma línea (p.ej. CP + Localidad, Coordenadas +
   Google en la ficha de propiedad). El borde/padding de fila lo lleva el
   pair; las filas interiores quedan sin borde y a mitad de ancho cada una. */
.detail-row-pair {
    display: flex;
    gap: 12px;
    padding: 5px 0;
    border-bottom: 1px solid #f0f0f0;
}
.detail-row-pair:last-child { border-bottom: none; }
.detail-row-pair > .detail-row {
    flex: 1 1 0;
    min-width: 0;
    padding: 0;
    border-bottom: none;
}

.detail-label {
    color: #6c757d;
    font-size: 12px;
}

.detail-value {
    color: #2c3e50;
    word-break: break-word;
}

.detail-value code {
    background: #f1f3f5;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 12px;
    color: #2c3e50;
}

.upcoming-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.upcoming-row {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 8px;
    border-radius: 4px;
    font-size: 12px;
    color: #495057;
    text-decoration: none;
    background: #f8f9fa;
    white-space: nowrap;
}

.upcoming-row:hover {
    background: #e9ecef;
    text-decoration: none;
    color: #2c3e50;
}

.upcoming-dates {
    font-weight: 600;
}

.upcoming-dates .bi-arrow-right {
    margin: 0 2px;
}

.upcoming-guests {
    color: #6c757d;
}

.upcoming-guests .bi-person {
    margin-left: 2px;
}

/* ===== PROPIETARIOS (card de la ficha de propiedad) ===== */
.owner-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.owner-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px;
    border: 1px solid #eef0f2;
    border-radius: 8px;
    background: #fbfcfd;
    transition: background .12s ease, border-color .12s ease;
}

.owner-item:hover {
    background: #f4f8f6;
    border-color: #d8e6df;
}

.owner-avatar {
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.5px;
    color: #fff;
    background: linear-gradient(135deg, #2ecc71, #27ae60);
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.04);
    user-select: none;
}

.owner-body {
    flex: 1 1 auto;
    min-width: 0;
}

.owner-name {
    font-size: 14px;
    font-weight: 600;
    color: #2c3e50;
    line-height: 1.2;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.owner-name a {
    color: #2c3e50;
    text-decoration: none;
}

.owner-name a:hover {
    color: #27ae60;
    text-decoration: underline;
}

.owner-contacts {
    margin-top: 4px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 14px;
    font-size: 12.5px;
}

.owner-contact {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: #5a6b7b;
    text-decoration: none;
    max-width: 100%;
}

.owner-contact span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.owner-contact:hover {
    color: #27ae60;
    text-decoration: none;
}

.owner-contact .bi {
    color: #adb5bd;
    flex: 0 0 auto;
}

.owner-contact:hover .bi { color: #27ae60; }

.owner-contact-phone {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.owner-contact-wa {
    color: #25d366;
    font-size: 14px;
    line-height: 1;
    text-decoration: none;
}

.owner-contact-wa:hover { color: #1da851; }

/* ===== AUTOCOMPLETE DE PROPIEDAD (financiero) ===== */

.property-autocomplete-wrap {
    position: relative;
}

.autocomplete-results {
    list-style: none;
    margin: 0;
    padding: 0;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1000;
    background: #fff;
    border: 1px solid var(--border-color);
    border-top: none;
    max-height: 280px;
    overflow-y: auto;
    box-shadow: 0 4px 8px rgba(0,0,0,0.08);
    border-radius: 0 0 4px 4px;
}

.autocomplete-results li {
    padding: 6px 10px;
    font-size: 0.85rem;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    border-top: 1px solid #f1f3f5;
}

.autocomplete-results li:first-child {
    border-top: none;
}

.autocomplete-results li:hover {
    background: #f1f3f5;
}

.autocomplete-results .ac-name {
    color: #2c3e50;
    font-weight: 500;
}

.autocomplete-results .ac-locality {
    color: #6c757d;
    font-size: 0.75rem;
}

/* ===== FILAS DE RESERVA CANCELADA (en listados) ===== */

.booking-canceled td {
    opacity: 0.6;
}

.booking-canceled td:hover {
    opacity: 0.85;
}

/* ===== ENLACE A FICHA DE PROPIEDAD (sutil, en cualquier listado) =====
   DEPRECATED — sustituir por el chip canónico .entity-chip-place
   (macro place_link en _macros.html). Mantener mientras queden call
   sites sin migrar. */

.property-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted rgba(0,0,0,0.25);
}

.property-link:hover,
.property-link:focus {
    color: var(--accent-blue);
    text-decoration: none;
    border-bottom-color: var(--accent-blue);
}


/* ===== ENTITY CHIPS — accesos canónicos a propiedad / reserva =====
   Patrón canónico para enlazar a la ficha de una entidad desde
   cualquier listado o ficha. Usar siempre los macros place_link /
   booking_link de _macros.html — no construir el HTML a mano.
   Documentado en CLAUDE.md. */
.entity-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.1rem 0.5rem 0.1rem 0.4rem;
    border: 1px solid rgba(0,0,0,0.1);
    border-radius: 4px;
    background-color: transparent;
    color: #212529;
    font-size: 0.85em;
    line-height: 1.4;
    text-decoration: none !important;
    white-space: nowrap;
    vertical-align: baseline;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.entity-chip:hover {
    background-color: rgba(0,0,0,0.04);
    border-color: rgba(0,0,0,0.22);
    color: #212529;
}
.entity-chip > i {
    font-size: 0.95em;
    flex-shrink: 0;
    line-height: 1;
}
.entity-chip > span {
    font-weight: 500;
}
.entity-chip-suffix {
    color: #6c757d;
    font-weight: 400;
}
.entity-chip-place > i    { color: var(--brand-ok-color, #2980b9); }
.entity-chip-booking > i  { color: #28a745; }
.entity-chip-lock-nav > i { color: var(--accent-color, #2ecc71); }
.entity-chip-lock-split { /* sin icono propio: lo lleva el botón interior */ }

/* Cerradura deshabilitada en su ficha (lock_state=0) pero todavía
   asociada a la plaza: se muestra atenuada con strikethrough sobre
   el nombre, sin botón abrir (chip 100% navegacional). El badge del
   fabricante mantiene su color para que se reconozca de un vistazo. */
.entity-chip-lock-disabled-device {
    opacity: 0.55;
}
.entity-chip-lock-disabled-device > span {
    text-decoration: line-through;
}
.entity-chip-lock-disabled-device:hover {
    opacity: 0.85;
}

/* Estados de conexión del chip (Cerraduras.md §9). Se aplican ENCIMA
   de las variantes existentes (-nav, -split) — son ortogonales:
   un chip puede ser split + offline, o nav + unknown.

   - `offline`  → borde rojo, icono wifi-off rojo a la izquierda.
   - `unknown`  → borde gris atenuado, icono question-circle gris.

   El icono se inserta entre el lock_type_badge y el <span> del
   nombre con `.entity-chip-lock-off-icon`. */
.entity-chip-lock-offline {
    border-color: #e74c3c;
}
.entity-chip-lock-offline.entity-chip-lock-split {
    border-color: #e74c3c;
}
.entity-chip-lock-offline.entity-chip-lock-split:hover {
    border-color: #e74c3c;
}
.entity-chip-lock-offline .entity-chip-lock-off-icon {
    color: #e74c3c;
    margin: 0 0.15rem 0 0.05rem;
    font-size: 0.95em;
}

.entity-chip-lock-unknown {
    border-color: #adb5bd;
    opacity: 0.78;
}
.entity-chip-lock-unknown.entity-chip-lock-split {
    border-color: #adb5bd;
}
.entity-chip-lock-unknown.entity-chip-lock-split:hover {
    border-color: #adb5bd;
}
.entity-chip-lock-unknown .entity-chip-lock-off-icon {
    color: #6c757d;
    margin: 0 0.15rem 0 0.05rem;
    font-size: 0.95em;
}
.entity-chip-lock-unknown:hover {
    opacity: 1;
}

/* ===== LOCK TYPE BADGE — mini-badge circular con letra del fabricante.
   Sustituye los antiguos badges textuales "Yacan/Omnitec/..." en
   listados y dentro del lock_link. Una sola letra + color por
   fabricante para identificar de un vistazo sin ocupar espacio. */
.lock-type-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-weight: 700;
    color: #fff;
    line-height: 1;
    flex-shrink: 0;
    font-family: ui-sans-serif, system-ui, sans-serif;
}
.lock-type-badge-sm { width: 18px; height: 18px; font-size: 10.5px; }
.lock-type-badge-md { width: 22px; height: 22px; font-size: 12.5px; }
.lock-type-badge-yacan     { background-color: #17a2b8; }  /* info / cyan */
.lock-type-badge-omnitec   { background-color: #007bff; }  /* primary / azul */
.lock-type-badge-ttlock    { background-color: #6f42c1; }  /* violeta */
.lock-type-badge-argonline { background-color: #343a40; }  /* dark / negro */
.lock-type-badge-mando     { background-color: #ffc107; color: #000; }  /* warning / ambar */
.lock-type-badge-relais    { background-color: #6c757d; }  /* secondary / gris */
.lock-type-badge-unknown   { background-color: #adb5bd; }  /* fallback */

/* ===== PROMO CODE CHIP — split: código (→ ficha) + copiar =====
   Cabecera de cada card de /modulos/codigos-promocionales. Mismo
   lenguaje visual que los entity chips / lock split chip: una sola
   pastilla con borde fino y dos zonas con hover independiente.
   Zona izquierda = el código en monospace (link a la ficha);
   zona derecha = botón de copiar al portapapeles, con animación
   "pop" del icono al copiar (clase .copied desde JS). */
.promo-code-chip {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid rgba(0,0,0,0.15);
    border-radius: 4px;
    overflow: hidden;
    background-color: #fff;
    line-height: 1.4;
    vertical-align: middle;
}
.promo-code-chip-code {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.6rem;
    font-family: SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    font-weight: 600;
    font-size: 0.92rem;
    letter-spacing: 0.5px;
    color: #212529;
    text-decoration: none !important;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.promo-code-chip-code:hover,
.promo-code-chip-code:focus {
    background-color: rgba(0,0,0,0.05);
    color: var(--brand-ok-color, #2980b9);
    outline: none;
}
.promo-code-chip-copy {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 0.5rem;
    background: transparent;
    border: 0;
    border-left: 1px solid rgba(0,0,0,0.12);
    color: #6c757d;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.promo-code-chip-copy:hover,
.promo-code-chip-copy:focus {
    background-color: rgba(0,0,0,0.05);
    color: #212529;
    outline: none;
}
.promo-code-chip-copy.copied {
    color: #28a745;
}
.promo-code-chip-copy.copied > i {
    animation: promo-copy-pop 0.35s ease;
}
@keyframes promo-copy-pop {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.4); }
    100% { transform: scale(1); }
}

/* ===== REGIME BADGE — régimen contratado SA/AD (macro regime_badge).
   Colores PROPIOS e intencionales: NO se reusan los de estado de
   Bootstrap (verde=cobrado, ámbar=pendiente, rojo=error) para no
   confundir un atributo de la reserva con un estado. Cada régimen su
   color. Ver REGIME.md. */
.regime-badge { font-weight: 600; }
.regime-badge-sa    { background-color: #607089; color: #fff; }  /* azul pizarra — solo alojamiento */
.regime-badge-ad    { background-color: #a9690d; color: #fff; }  /* ámbar café — con desayuno */
.regime-badge-mp    { background-color: #2a9d8f; color: #fff; }  /* teal — media pensión */
.regime-badge-pc    { background-color: #6f42c1; color: #fff; }  /* púrpura — pensión completa */
.regime-badge-ti    { background-color: #3b7a57; color: #fff; }  /* verde bosque — todo incluido */
.regime-badge-other { background-color: #6c757d; color: #fff; }  /* fallback */

/* ===== USER TYPE BADGE — tipo 6 "Profesional" (rol del panel del
   profesional, Amapola §15). Color propio violeta, distinto de los 5
   tipos Bootstrap (primary/secondary/success/warning/info). Mapeado en
   el macro user_type_badge() de _macros.html y en el TYPE_BADGE del JS
   de cerraduras_aperturas.html. */
.badge-profesional { background-color: #6f42c1; color: #fff; }
.badge-facturacion { background-color: #0f766e; color: #fff; }  /* type 7 Facturación (VeriFactu) */

/* ===== FLASH / BLINK genérico — feedback "esto se ha refrescado" aunque el
   contenido no cambie (botones ↻ de refresco). Reiniciable: en JS hacer
   el.classList.remove('okms-flash'); void el.offsetWidth; el.classList.add('okms-flash'); */
@keyframes okms-flash-bg {
    0%   { background-color: rgba(46, 204, 113, 0.35); }
    100% { background-color: transparent; }
}
.okms-flash { animation: okms-flash-bg 0.9s ease-out; border-radius: 3px; }

/* ===== INDICADOR "EN VIVO" — etiqueta discreta que avisa de que el
   contenido se auto-refresca (punto verde que late). Pensado para la
   esquina derecha de una cabecera de card. */
.okms-live-tag {
    display: inline-flex; align-items: center; gap: 0.3em;
    font-size: 0.72em; font-weight: 500; color: #6c757d;
    white-space: nowrap; vertical-align: middle;
}
.okms-live-tag .okms-live-dot {
    width: 7px; height: 7px; border-radius: 50%;
    background-color: #2ecc71; display: inline-block;
    animation: okms-live-pulse 2s ease-in-out infinite;
}
@keyframes okms-live-pulse {
    0%, 100% { opacity: 1;   box-shadow: 0 0 0 0   rgba(46, 204, 113, 0.55); }
    50%      { opacity: 0.5; box-shadow: 0 0 0 4px rgba(46, 204, 113, 0); }
}

/* ===== OKMS REFRESH CHIP — chip "actualizado HH:MM:SSh / pausado" del
   helper canónico de polling okms-poller.js (opción chipEl). Markup:
   <span class="okms-refresh-chip"><span class="dot"></span><span class="text">activo</span></span>
   Estados: (ninguno) = verde pulsante · .paused = gris sin animación ·
   .error = rojo ("sin conexión — reintentando"). Generaliza el chip que
   estrenó /tulipan (.tulipan-autorefresh-chip, migrable cuando se toque). */
.okms-refresh-chip {
    font-size: 0.72rem;
    color: #6c757d;
    margin-left: 0.5rem;
    white-space: nowrap;
    vertical-align: middle;
}
.okms-refresh-chip .dot {
    display: inline-block;
    width: 7px; height: 7px;
    border-radius: 50%;
    background-color: #28a745;
    margin-right: 0.25rem;
    vertical-align: middle;
    animation: okms-chip-pulse 1.6s ease-in-out infinite;
}
.okms-refresh-chip.paused .dot { background-color: #adb5bd; animation: none; }
.okms-refresh-chip.error  .dot { background-color: #e74c3c; animation: none; }
.okms-refresh-chip.error       { color: #c0392b; }
@keyframes okms-chip-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.35; }
}

/* ===== TPV PROVIDER BADGE — etiqueta de la pasarela de pago.
   Color fijo por proveedor, canónico (macro tpv_provider_badge). Colores
   de marca aproximados: CECA azul-banca, RedSys naranja, Stripe morado. */
.tpv-prov-badge {
    display: inline-block; padding: 0.15em 0.55em; border-radius: 4px;
    font-size: 0.78em; font-weight: 600; line-height: 1.4;
    color: #fff; white-space: nowrap; vertical-align: middle;
}
.tpv-prov-badge-ceca    { background-color: #0d6efd; }  /* azul banca */
.tpv-prov-badge-redsys  { background-color: #e8710a; }  /* naranja RedSys */
.tpv-prov-badge-stripe  { background-color: #635bff; }  /* morado Stripe */
.tpv-prov-badge-unknown { background-color: #adb5bd; }  /* fallback */

/* Color del icono según estado de la reserva (domopaco_bookings.state).
   Sigue la convención de colores del proyecto (CLAUDE.md): amarillo
   para pendiente, rojo para error/cancelado, verde para hecho/activo. */
.entity-chip-booking-state-1 > i { color: #f39c12; }  /* Pendiente */
.entity-chip-booking-state-2 > i { color: #e74c3c; }  /* Cancelada */
.entity-chip-booking-state-3 > i { color: #28a745; }  /* Activa     */
.entity-chip-booking-state-4 > i { color: #6c757d; }  /* Finalizada */
.entity-chip-disabled {
    border-style: dashed;
    color: #6c757d;
    cursor: default;
}
.entity-chip-meta {
    color: #6c757d;
    font-size: 0.85em;
    margin-left: 0.25rem;
}

/* ===== LOCK CHIP — split: zona "abrir" + flecha "detalle" =====
   El chip se comporta como un split-button. La caja exterior
   (.entity-chip-lock-split) lleva el border común y se anula su
   propio padding para que cada zona interior tenga el suyo. */
.entity-chip-lock-split {
    padding: 0;
    gap: 0;            /* anula el gap heredado de .entity-chip — las
                          dos zonas pegan a tope sin franja blanca */
    overflow: hidden;
    border-color: var(--accent-color, #2ecc71);
}
/* Hovers independientes por zona — anula el .entity-chip:hover
   genérico para que el wrapper no cambie de bg/border al pasar por
   encima; cada hijo gestiona su propio feedback. */
.entity-chip-lock-split:hover {
    background-color: transparent;
    border-color: var(--accent-color, #2ecc71);
    color: inherit;
}
/* Zona izquierda: botón de abrir (acción primaria). Bg transparente
   en reposo, verde + texto blanco al hover. */
.entity-chip-lock-action {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.15rem 0.55rem;
    background: transparent;
    border: 0;
    color: var(--accent-color, #2ecc71);
    font: inherit;
    font-weight: 500;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.entity-chip-lock-action > i { font-size: 0.95em; }
.entity-chip-lock-action:hover,
.entity-chip-lock-action:focus {
    background-color: var(--accent-color, #2ecc71);
    color: #fff;
    outline: none;
}
/* Zona derecha: flecha al detalle. Estrecha, color muted en reposo,
   gris claro al hover (independiente del hover de la apertura). */
.entity-chip-lock-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.15rem 0.4rem;
    border-left: 1px solid rgba(0,0,0,0.1);
    color: #6c757d;
    text-decoration: none !important;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.entity-chip-lock-arrow:hover,
.entity-chip-lock-arrow:focus {
    background-color: rgba(0,0,0,0.06);
    color: #212529;
    outline: none;
}

/* ===== TABLA DE AUDITORÍA ===== */

.audit-table tbody tr:hover {
    background: #f8f9fa;
}

/* Todas las celdas de la auditoría alinean a la izquierda (defensivo
   frente a cualquier text-align heredado de un contenedor padre). */
.audit-table td, .audit-table th { text-align: left; }

/* Columna izquierda: fecha/hora arriba, usuario debajo */
.audit-table .audit-meta {
    width: 1%;
    white-space: nowrap;
    vertical-align: top;
    padding-right: 12px;
}

.audit-table .audit-when {
    font-size: 0.75rem;
    color: #6c757d;
    line-height: 1.2;
}

.audit-table .audit-who {
    font-size: 0.78rem;
    color: #495057;
    font-weight: 600;
    margin-top: 2px;
}

/* Columna derecha: comment_key (badge coloreado) arriba, detalle debajo */
.audit-table .audit-detail {
    font-size: 0.78rem;
    color: #495057;
    margin-top: 3px;
    word-break: break-word;
    white-space: pre-wrap;
}

/* Badge del comment_key (color depende de categoría — ver audit_styles.py) */
.audit-key {
    font-size: 0.72rem;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 3px;
    white-space: nowrap;
    display: inline-block;
    letter-spacing: 0.02em;
}

.audit-default          { background: #f1f3f5; color: #495057; }
.audit-lifecycle        { background: #2c3e50; color: #fff;    }
.audit-lifecycle-cancel { background: #6c757d; color: #fff;    }
.audit-error            { background: #f8d7da; color: #721c24; }
.audit-modification     { background: #fff3cd; color: #856404; }
.audit-payment          { background: #d4edda; color: #155724; }
.audit-lock             { background: #e2d4f0; color: #4a148c; }
.audit-notification     { background: #d1ecf1; color: #0c5460; }
.audit-access           { background: #e9ecef; color: #495057; }
/* Notas manuales escritas por un admin desde el panel (MANUAL_NOTE). */
.audit-manual-note      { background: #fcefb6; color: #7a5a00; }

/* Filas de auditoría que son notas manuales — tinte amarillo claro
   y separador izquierdo, para distinguirlas de los eventos automáticos. */
.audit-table tr.audit-row-note > td      { background: #fffbe6; }
.audit-table tr.audit-row-note > td:first-child {
    border-left: 3px solid #f0c419;
}

/* Caja de acciones encima de la tabla de auditoría — contiene el
   botón "Añadir nota". */
.audit-actions {
    padding: 0.4rem 0.6rem;
    text-align: right;
    border-bottom: 1px solid var(--border-color, #dee2e6);
    background: #fafbfc;
}
.audit-actions .btn-add-note i { margin-right: 0.25em; }

/* ===== CABECERA COLLAPSABLE (audit) ===== */

.collapse-header {
    cursor: pointer;
    user-select: none;
}

.collapse-header:hover {
    background: #f8f9fa;
}

.collapse-header .collapse-chevron {
    transition: transform 0.2s;
}

.collapse-header[aria-expanded="true"] .collapse-chevron {
    transform: rotate(180deg);
}

/* ===== LÍNEA DEL HUÉSPED / TARJETA DE GARANTÍA EN LA TARJETA PRINCIPAL ===== */
/* Check-in online se extrajo del dl principal a su propio card en la
   sección CHECK-IN ONLINE (ver booking_detail.html). El antiguo
   .checkin-online-line ya no se usa. */

.guest-line, .creditcard-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
}

/* Bloque del número de tarjeta (ocupa la línea completa, debajo del badge) */
.creditcard-line .cc-block {
    flex-basis: 100%;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
}

.creditcard-line .cc-number {
    background: #f1f3f5;
    padding: 2px 8px;
    border-radius: 4px;
    letter-spacing: 0.5px;
    font-family: 'SFMono-Regular', Menlo, Consolas, monospace;
    font-size: 0.95em;
    color: #212529;
}

.guest-line .guest-name { font-weight: 600; }
.guest-line .guest-phone, .guest-line .guest-email { color: #495057; }

/* Bandera junto al teléfono */
.phone-flag {
    font-size: 1.05em;
    margin-right: 2px;
}

/* Botones-icono compactos: solo el icono visible */
.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 4px;
    border: 1px solid var(--border-color);
    color: #495057;
    background: #fff;
    text-decoration: none;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
    font-size: 0.85rem;
}

.btn-icon:hover {
    background: #2c3e50;
    border-color: #2c3e50;
    color: #fff;
    text-decoration: none;
}

.btn-icon.btn-icon-wa:hover {
    background: #25d366;
    border-color: #25d366;
}

/* Botón extra-pequeño consistente con el icono */
.btn-xs {
    padding: 2px 8px;
    font-size: 0.75rem;
    line-height: 1.4;
    border-radius: 4px;
}

/* ===== MODAL DE EDICIÓN DE PAGO ===== */

/* Etiquetas (Tipo / Desc / Importe / TPV) con ancho fijo para que alineen */
.pay-edit-body .input-group-prepend .input-group-text {
    min-width: 70px;
    justify-content: flex-end;
    font-size: 0.78rem;
    background: #f1f3f5;
    color: #495057;
}

/* Que el contenido del modal de edición scrollee si no cabe en pantalla */
.pay-edit-body { max-height: calc(100vh - 80px); overflow-y: auto; }

/* En móvil apaisado, permitir más altura todavía */
@media (max-height: 500px) {
    .modal-dialog-scrollable .modal-content { max-height: calc(100vh - 1rem); }
    .pay-edit-body { max-height: calc(100vh - 70px); }
}

/* ===== ICONO DE AYUDA (i) + POPOVER ===== */

.help-icon {
    color: #adb5bd;
    margin-left: 4px;
    cursor: pointer;
    text-decoration: none;
    font-size: 0.85em;
    vertical-align: middle;
    line-height: 1;
}

.help-icon:hover,
.help-icon:focus {
    color: var(--accent-blue);
    text-decoration: none;
    outline: none;
}

/* El popover de Bootstrap por defecto es muy estrecho — lo ensancho */
.popover { max-width: 320px; font-size: 0.85rem; }

/* ===== PÁGINA DE AYUDA ===== */

.help-toc {
    background: #f1f3f5;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 10px 14px;
    font-size: 0.9rem;
    line-height: 1.8;
}

.help-toc a {
    color: var(--accent-blue);
    margin-right: 6px;
}

.help-section {
    border-top: 2px solid var(--border-color);
    padding-top: 1.2rem;
    margin-top: 1.5rem;
}

.help-section h3 {
    font-size: 1.3rem;
    font-weight: 700;
    color: #2c3e50;
    margin-bottom: 0.8rem;
}

.help-section h4 {
    font-size: 1rem;
    font-weight: 700;
    color: #2c3e50;
    margin-top: 1rem;
    margin-bottom: 0.3rem;
    scroll-margin-top: 60px;
}

.help-section h4:target {
    background: #fff3cd;
    padding: 4px 8px;
    border-radius: 4px;
}

.help-section p {
    color: #495057;
    font-size: 0.9rem;
    margin-bottom: 0.8rem;
}

/* Botón "Abrir pantalla / Ir a la pestaña" inyectado por JS en la cabecera de
   cada sección de ayuda con pantalla destino (ver help.html + routes/help.py).
   `display: flow-root` hace que la cabecera contenga su float y no se solape
   con el párrafo siguiente. */
.help-section h2,
.help-section h3 {
    display: flow-root;
}
.help-open-screen {
    float: right;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.1rem 0.55rem;
    margin-left: 0.75rem;
    line-height: 1.6;
    white-space: nowrap;
}
.help-open-screen i {
    font-size: 0.85em;
}

/* ============================================================
   AYUDA IAed — caja de preguntas en lenguaje natural (/ayuda)
   ============================================================ */
.help-ai-box {
    background: #f8f9fb;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 0.9rem 1rem;
    margin-bottom: 1.5rem;
}
.help-ai-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.help-ai-icon {
    color: #6f42c1;
    font-size: 1.15rem;
    flex: 0 0 auto;
}
.help-ai-box .form-control {
    flex: 1 1 auto;
}
.help-ai-box #help-ai-send {
    flex: 0 0 auto;
    white-space: nowrap;
}
.help-ai-cap-note {
    margin-top: 0.6rem;
    color: #856404;
    background: #fff3cd;
    border: 1px solid #ffeeba;
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    font-size: 0.85rem;
}
.help-ai-answer {
    margin-top: 0.8rem;
    background: #fff;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0.8rem 1rem;
    font-size: 0.9rem;
    color: #333;
}
.help-ai-answer.help-ai-warn {
    background: #fff3cd;
    border-color: #ffeeba;
    color: #856404;
}
.help-ai-text {
    white-space: pre-wrap;
    line-height: 1.5;
}
.help-ai-link {
    margin-top: 0.7rem;
}
.help-ai-disclaimer {
    margin: 0.6rem 0 0;
    font-size: 0.75rem;
    color: #8a929b;
}

/* ============================================================
   LISTADO DE RESERVAS — barra de orden y responsive móvil
   ============================================================ */

/* Barra de pills de orden */
.bookings-sort-bar .btn-xs { font-size: 0.72rem; }
.bookings-sort-bar .sort-arrow { font-size: 0.7em; }

/* Cabeceras <th> con data-sort-pill: clicables, mismo comportamiento
   visual que las pills (flecha al campo activo, hover sutil). El JS de
   bookings_sort.js procesa cualquier elemento con data-sort-pill, así
   que no hace falta cambiar nada del JS — solo estilos. */
th[data-sort-pill],
th [data-sort-pill] {
    cursor: pointer;
    user-select: none;
}
th[data-sort-pill]:hover,
th [data-sort-pill]:hover {
    background-color: rgba(0,0,0,0.05);
}
th[data-sort-pill].active,
th [data-sort-pill].active {
    background-color: rgba(0,0,0,0.08);
}
th[data-sort-pill] .sort-arrow,
th [data-sort-pill] .sort-arrow {
    font-size: 0.7em;
    color: #6c757d;
}

/* Centrar verticalmente todas las celdas del listado de reservas en
   desktop. Algunas columnas (Propiedad/Localidad, Check-in+Check-out,
   Importe+€/noche) tienen 2 líneas y otras solo 1; sin esto, las de 1
   línea quedan pegadas arriba y la fila se ve descuadrada. */
#bookings-list-table tbody td,
#bookings-recent-table tbody td,
.bookings-search-table tbody td {
    vertical-align: middle;
}

/* En móvil vertical (xs, < 576px), la tabla de reservas se condensa
   a 3 columnas:
     col 1 → Propiedad / Localidad / Huésped
     col 2 → Check-in / Check-out / Nº noches
     col 3 → Importe / Check-in online / [Ver]
   Cada celda visible inyecta los datos extra mediante .booking-mobile-extra
   (oculto en desktop). Las columnas Huésped, Check-out, Noches, Check-in
   online y Ver llevan .booking-col-merge para ocultarse en móvil. */

.booking-mobile-extra { display: none; }
.booking-mobile-only  { display: none; }

@media (max-width: 575.98px) {
    /* Ocultar columnas que se fusionan dentro de las visibles */
    .booking-col-merge { display: none !important; }

    /* Mostrar inline-spans pensados solo para móvil */
    .booking-mobile-only { display: inline; }

    /* Mostrar bloques extra solo en móvil */
    .booking-mobile-extra {
        display: block;
        margin-top: 0.25rem;
        font-size: 0.8rem;
        line-height: 1.25;
    }

    /* Tabla más compacta */
    #bookings-list-table td,
    #bookings-recent-table td,
    .bookings-search-table td { padding: 0.4rem 0.3rem; vertical-align: top; }

    /* Cabecera de la tabla pierde sentido con cols fusionadas → ocultar */
    #bookings-list-table thead,
    #bookings-recent-table thead,
    .bookings-search-table thead { display: none; }

    /* El botón Ver dentro del extra ocupa todo el ancho para tap fácil */
    .booking-mobile-extra .btn { display: inline-block; }
}

/* ============================================================
   DISPOSITIVOS — píldoras con estado de conexión

   Cada item se muestra como una pastilla clicable. El color
   indica si el equipo está en contacto con el sistema:
     verde  → ha dado señal en los últimos 150 segundos
     rojo   → más de 150 s sin contestar (pero menos de 15 días)
     negro  → más de 15 días sin señal (RIP)
   ============================================================ */
.items-list {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.item-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    border-radius: 0.4rem;
    font-size: 0.85rem;
    line-height: 1.1;
    text-decoration: none !important;
    color: #fff !important;
    transition: filter 0.15s ease, transform 0.15s ease;
}
.item-pill:hover { filter: brightness(1.08); transform: translateY(-1px); }

.item-pill .item-pill-name { font-weight: 600; }
.item-pill .item-pill-age  { opacity: 0.75; font-size: 0.75rem; }

.item-pill-alive   { background-color: #28a745; }   /* verde — bootstrap success */
.item-pill-offline { background-color: #dc3545; }   /* rojo  — bootstrap danger  */
.item-pill-rip     { background-color: #212529; }   /* negro — bootstrap dark    */

/* Filas de la tabla de componentes son clicables (van a la gráfica) */
.component-row { cursor: pointer; }
.component-row .component-link { color: inherit; text-decoration: none; }
.component-row:hover .component-link { text-decoration: underline; }

/* Tarjetas de estadísticas en la pantalla de gráfica */
.stat-card {
    padding: 0.5rem 0.75rem;
    text-align: center;
    height: 100%;
}
.stat-card .stat-label { font-size: 0.75rem; text-transform: uppercase; opacity: 0.7; }
.stat-card .stat-value { font-size: 1.25rem; font-weight: 700; line-height: 1.2; }
.stat-card.stat-min   .stat-value { color: #28a745; }
.stat-card.stat-avg   .stat-value { color: #6c757d; }
.stat-card.stat-max   .stat-value { color: #dc3545; }
.stat-card.stat-count .stat-value { color: #0d6efd; }

/* Chips de fuente del historial: el check ✓ aparece sólo cuando
   el chip está activo, además del cambio btn-secondary / outline */
#history-card [data-source] .src-on-icon { display: none; }
#history-card [data-source].active .src-on-icon { display: inline-block; }

/* ============================================================
   HISTORIAL DEL DISPOSITIVO

   Cada fila lleva una banda fina de color a la izquierda según
   la fuente del registro: gets (azul), orders (morado), comments
   (gris). Las celdas de "Resultado" se truncan a una línea y se
   expanden al hacer click en la fila.
   ============================================================ */
#history-table tbody tr {
    cursor: pointer;
    border-left: 3px solid transparent;
}
#history-table tbody tr.history-src-gets     { border-left-color: #0d6efd; }
#history-table tbody tr.history-src-orders   { border-left-color: #6f42c1; }
#history-table tbody tr.history-src-comments { border-left-color: #6c757d; }

#history-table .history-source {
    display: inline-flex;
    width: 1.5rem;
    height: 1.5rem;
    align-items: center;
    justify-content: center;
    border-radius: 0.25rem;
    color: #fff;
    font-size: 0.85rem;
    margin-right: 0.25rem;
    vertical-align: middle;
}
#history-table tbody tr.history-src-gets     .history-source { background-color: #0d6efd; }
#history-table tbody tr.history-src-orders   .history-source { background-color: #6f42c1; }
#history-table tbody tr.history-src-comments .history-source { background-color: #6c757d; }

/* Resultado: una línea con elipsis hasta que se hace click en la fila */
#history-table .history-result .history-text {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}
#history-table tbody tr.expanded .history-result .history-text {
    white-space: pre-wrap;
    word-break: break-word;
}

/* ============================================================
   AÑADIR RESERVA — desplegables de live search
   ============================================================ */

.live-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1050;
    max-height: 280px;
    overflow-y: auto;
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-top: none;
    border-radius: 0 0 4px 4px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
}

.live-item {
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    border-bottom: 1px solid #f1f3f5;
}

.live-item:last-child { border-bottom: none; }

.live-item:hover { background-color: #f8f9fa; }

.live-empty {
    padding: 0.5rem 0.75rem;
    color: #6c757d;
    font-size: 0.85rem;
    font-style: italic;
}

.live-item.active { background-color: #eef2ff; }

/* Typeahead de filtro (filter-typeahead.js): <select data-typeahead> -> input
   con (x). El wrapper es relativo para anclar resultados y el botón limpiar. */
.ta-wrap {
    position: relative;
    display: inline-block;
    min-width: 9rem;
}
.ta-wrap > input { padding-right: 1.7rem; }
.ta-wrap .ta-clear {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    border: none;
    background: transparent;
    color: #adb5bd;
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
    display: none;
}
.ta-wrap .ta-clear:hover { color: #6c757d; }

/* Línea "Alta: <usuario> · fecha" debajo de la descripción de un pago */
.pay-creator-line {
    font-size: 0.75rem;
    opacity: 0.85;
}

/* Pago deshabilitado (state=0): fila entera atenuada con tachado en el
   importe para que el admin distinga de un vistazo los pagos activos. */
.pay-row-disabled td {
    background-color: #f8f9fa;
    color: #6c757d;
}
.pay-row-disabled td:nth-child(2) {
    text-decoration: line-through;
}

/* ===== PANEL DEL HUÉSPED ===== */

.panel-url-row .panel-url-input {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.78rem;
    background-color: #f8f9fa;
}

.panel-notif-table td { vertical-align: middle; }
.panel-notif-table ul li + li { margin-top: 2px; }

.panel-passcode-card {
    border: 1px solid var(--border-color, #dee2e6);
    background-color: #f8f9fa;
}

/* PIN code en grande para que se lea de un vistazo */
.panel-passcode-value {
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    color: #212529;
    user-select: all;
}

/* ============================================================
   Calendario heatmap de logins (ficha de usuario)
   La intensidad del color se inyecta inline desde la plantilla
   con `style="background-color: rgba(46,204,113, X);"`. Aquí solo
   layout, tipografía y los estados especiales.
   ============================================================ */
.logins-calendar {
    table-layout: fixed;
    width: 100%;
    max-width: 720px;
    margin: 0 auto;
}
.logins-calendar th {
    background-color: var(--card-bg, #f8f9fa);
    font-weight: 600;
    padding: 0.25rem 0;
}
.logins-cal-cell {
    height: 56px;
    vertical-align: top;
    padding: 2px 4px;
    position: relative;
    transition: filter 0.12s ease;
}
.logins-cal-cell.logins-cal-other {
    background-color: rgba(0, 0, 0, 0.03);
}
.logins-cal-day-num {
    font-size: 0.7rem;
    color: #666;
    text-align: right;
    line-height: 1;
}
.logins-cal-count {
    font-size: 1.05rem;
    font-weight: 700;
    color: #212529;
    text-align: center;
    margin-top: 4px;
}
.logins-cal-cell.logins-cal-active:hover {
    filter: brightness(0.92);
}
/* Enlace de celda: ocupa toda el área y hereda los colores de
   texto. El cursor pointer da feedback de que es clicable. */
.logins-cal-link {
    display: block;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
    height: 100%;
}
.logins-cal-link:hover,
.logins-cal-link:focus {
    text-decoration: none;
    color: inherit;
}

/* ============================================================
   CERRADURAS — listado y detalle
   ============================================================ */

/* Badge de plaza asignada en el listado de cerraduras: separación
   reducida (~30% menos que mr-1/mb-1) para que un cerradura con muchas
   plazas (caso del portal de Espazo) ocupe menos vertical. */
.lock-place-badge {
    margin: 0 0.175rem 0.175rem 0;
}


/* ============================================================
   Mini log de envío de orden a un dispositivo (item_detail)
   ============================================================ */

.send-order-log {
    font-family: ui-monospace, "Menlo", "Consolas", monospace;
    font-size: 11.5px;
    line-height: 1.4;
    max-height: 160px;
    overflow-y: auto;
    background: #1e1e1e;
    color: #d4d4d4;
    border-radius: 4px;
    padding: 6px 10px;
    display: none;
}
.send-order-log.has-lines { display: block; }

.send-order-line {
    white-space: pre-wrap;
    word-break: break-word;
}
.send-order-line .ts {
    color: #6a9955;
    margin-right: 6px;
}
.send-order-line.is-info    { color: #d4d4d4; }
.send-order-line.is-step    { color: #569cd6; }
.send-order-line.is-success { color: #4ec9b0; }
.send-order-line.is-error   { color: #f48771; }
.send-order-line.is-warn    { color: #dcdcaa; }

/* ============================================================
 * Listados de mantenimiento — sort + filtro client-side
 * (ver static/js/maintenance_list.js y CLAUDE.md sección
 * "Mantenimientos: listado client-side"). Se aplica también a
 * la tabla de productos dentro de la ficha de un proveedor.
 * ============================================================ */
table th.sortable,
table th .sortable[data-sort-key] {
    cursor: pointer;
    user-select: none;
}
table th.sortable:hover,
table th .sortable[data-sort-key]:hover {
    background-color: #e9ecef;
}
table th.sortable .sort-arrow,
table th .sortable[data-sort-key] .sort-arrow {
    display: inline-block;
    width: 0.9em;
    color: #6c757d;
    font-size: 0.85em;
    margin-left: 0.15em;
}
table th.sortable.sort-active .sort-arrow,
table th .sortable.sort-active .sort-arrow {
    color: var(--accent-color, #2ecc71);
    font-weight: bold;
}

/* Botón "✕" dentro del input de filtro client-side. */
.maint-search-clear-btn {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    padding: 0 4px;
    color: #adb5bd;
    cursor: pointer;
    line-height: 1;
    font-size: 0.95rem;
}
.maint-search-clear-btn:hover { color: #495057; }
.maint-search-clear-input { padding-right: 28px !important; }

/* Botón "✕" canónico de typeaheads (window.attachSearchClear).
   Variante genérica de la anterior: el helper envuelve solo el input
   en .search-clear-wrap para anclar la ✕ a la caja del input aunque
   haya label encima o dropdown hermano. Ver PATRON_TYPEAHEAD.md §4.bis.a. */
.search-clear-wrap { position: relative; display: block; }
.search-clear-btn {
    position: absolute;
    top: 50%;
    right: 6px;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    padding: 0 4px;
    color: #adb5bd;
    cursor: pointer;
    line-height: 1;
    font-size: 0.95rem;
    z-index: 3;
}
.search-clear-btn:hover { color: #495057; }
.search-clear-input { padding-right: 28px !important; }

/* ============================================================
   INDICADOR GLOBAL DE NAVEGACIÓN
   Barra fina (3px) en la parte superior + cursor `progress` en todo
   el body mientras el navegador está cargando una nueva página o
   procesando un submit. La barra solo se hace visible si la espera
   pasa de ~150ms (delay controlado en JS), de modo que las páginas
   rápidas no parpadean. La animación es indeterminada (no sabemos
   cuánto va a tardar el servidor).
   ============================================================ */
#global-progress-bar {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 3px;
    z-index: 2000;          /* por encima de modales (1050+) */
    background: transparent;
    pointer-events: none;
    overflow: hidden;
    opacity: 0;
    transition: opacity 0.15s ease-out;
}
#global-progress-bar.is-active { opacity: 1; }
#global-progress-bar.is-active::before {
    content: "";
    position: absolute;
    top: 0; bottom: 0;
    width: 30%;
    background: var(--accent-color, #2ecc71);
    box-shadow: 0 0 8px var(--accent-color, #2ecc71);
    border-radius: 0 2px 2px 0;
    animation: gpb-slide 1.1s linear infinite;
}
@keyframes gpb-slide {
    0%   { left: -30%; }
    100% { left: 100%; }
}

/* Cursor wait global mientras hay navegación en curso. */
body.is-navigating,
body.is-navigating * { cursor: progress !important; }

/* Spinner reusable: <i class="bi bi-arrow-repeat spin"></i>. */
.bi.spin {
    display: inline-block;
    animation: gpb-spin 0.9s linear infinite;
}
@keyframes gpb-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* Links interceptados por el handler global: semi-transparentes y
   sin pointer-events para que un segundo click no haga nada. */
a.nav-busy {
    pointer-events: none;
    opacity: 0.6;
}

/* Filas de tabla clicables (CLAUDE.md "Listados sin botón [Ver]").
   <tr data-row-href="..."> + handler global en base.html. El cursor
   pointer da la afordancia visual; el outline en focus es para Tab+
   Enter (los <tr> con tabindex="0" en el HTML del template). */
tr[data-row-href] {
    cursor: pointer;
}
tr[data-row-href]:focus {
    outline: 2px solid var(--accent-blue, #007bff);
    outline-offset: -2px;
}


/* ============================================================
   RECENT VIEWS — botón flotante fijo en esquina superior derecha
   Visible en escritorio y móvil. En móvil, la top-navbar reaparece
   (display:flex) ocupando los primeros 50px del viewport — bajamos
   un poco el FAB para no solaparlo con la barra de página.
   Ver routes/recent_views.py + RECENT_VIEWS.md
   ============================================================ */
#recent-views-fab {
    position: fixed;
    top: 0.6rem;
    right: 0.75rem;
    z-index: 1040;   /* por encima de page-content; por debajo de
                        modales (1050) y del global-progress-bar (2000) */
}
@media (max-width: 768px) {
    /* En móvil la top-navbar es visible (~50px). Bajamos el FAB
       para que quede dentro de esa barra, alineado con el título. */
    #recent-views-fab {
        top: 0.55rem;
    }
}
#recent-views-toggle {
    line-height: 1;
    padding: 0.3rem 0.55rem;
    border: 1px solid rgba(0, 0, 0, 0.1);
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
#recent-views-toggle:hover {
    background: #f8f9fa;
    border-color: rgba(0, 0, 0, 0.18);
}
#recent-views-toggle .bi-clock-history {
    font-size: 1.1rem;
    vertical-align: -1px;
    color: #495057;
}
/* Quitar la flecha por defecto que Bootstrap añade a dropdown-toggle
   — el icono del reloj ya señala que es un menú. */
#recent-views-toggle::after {
    display: none;
}
.recent-views-menu {
    min-width: 280px;
    max-width: 340px;
    padding: 0.25rem 0;
}
.recent-views-header {
    color: #6c757d;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.4rem 1rem 0.2rem;
    margin: 0;
}
.recent-views-header .bi {
    margin-right: 0.25rem;
    opacity: 0.85;
}
.recent-views-item {
    padding: 0.45rem 1rem;
    white-space: normal;
    line-height: 1.25;
}
.recent-views-item:active {
    background-color: var(--accent-color, #2ecc71);
    color: #fff;
}
.recent-views-line1 {
    display: block;
    font-size: 0.9rem;
    color: #212529;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.recent-views-id {
    font-weight: 600;
}
.recent-views-title {
    margin-left: 0.2rem;
    color: #495057;
}
.recent-views-line2 {
    display: block;
    font-size: 0.78rem;
    color: #6c757d;
    margin-top: 0.05rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.recent-views-item:active .recent-views-line1,
.recent-views-item:active .recent-views-line2,
.recent-views-item:active .recent-views-title {
    color: #fff;
}
.recent-views-empty {
    line-height: 1.35;
}


/* ============================================================
 * STATUS PILLS — resumen de estado en la cabecera del detalle de
 * reserva. Pill verde = hecho, ámbar = pendiente. Ver
 * BOOKING_STATUS_PILLS.md y CLAUDE.md sección "Pills de estado en
 * la cabecera del detalle de reserva".
 * ============================================================ */
.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.3rem 0.7rem;
    border-radius: 999px;
    font-size: 0.82rem;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
}
.status-pill > i {
    font-size: 0.95em;
}
.status-pill-done {
    background-color: #d4edda;
    color: #155724;
    border: 1px solid #c3e6cb;
}
.status-pill-pending {
    background-color: #fff3cd;
    color: #856404;
    border: 1px solid #ffeeba;
}
.status-pill-done .status-pill-check {
    color: #28a745;
}


/* ============================================================
 * BK-PEOPLE — iconos de huéspedes en la cabecera del detalle de
 * reserva. Un person-fill por adulto + un person-fill más pequeño
 * por niño. Ver _fmt_guests_html en routes/bookings.py.
 * ============================================================ */
.bk-people-adults .bi-person-fill {
    font-size: 1.05rem;
    margin-right: 1px;
    color: #495057;
    vertical-align: -2px;
}
.bk-people-children .bi-person-fill {
    font-size: 0.72rem;
    margin-right: 1px;
    color: #6c757d;
    vertical-align: 1px;
}
.bk-people-children {
    margin-left: 0.25rem;
}
.bk-people-count {
    font-size: 0.82rem;
    font-weight: 500;
    color: #495057;
    margin-left: 0.2rem;
    vertical-align: 1px;
}
.bk-people-sep {
    color: #adb5bd;
    margin: 0 0.4rem;
}


/* ============================================================
 * BOOKING-DL — `<dl class="row booking-dl">` del card cabecera del
 * detalle de reserva.
 *
 * Bootstrap col-sm-3/col-sm-9 reserva el 25% del ancho del card al
 * <dt>, dejando un huecazo entre etiquetas cortas ("Alta") y sus
 * valores. Aquí estrechamos el <dt> a un ancho fijo que fita la
 * etiqueta más larga del card ("Tarjeta de garantía" ≈ 150px) y
 * dejamos que el <dd> ocupe el resto via flex:1.
 *
 * El text-align: right pega la etiqueta al divisor con el valor
 * justo al lado, y como el <dt> ya no es ancho 25%, no queda
 * tampoco espacio vacío a la izquierda.
 *
 * En xs (móvil) se mantiene el layout Bootstrap por defecto
 * (col-4 + text-left) porque ahí no sobra ancho.
 * ============================================================ */
@media (min-width: 576px) {
    .booking-dl > dt {
        flex: 0 0 160px;
        max-width: 160px;
        text-align: right;
        padding-right: 0.75rem;
    }
    .booking-dl > dd {
        /* basis calc(100% - 160px) garantiza que el par dt+dd llene
           toda la fila y el siguiente dt wrappee a la siguiente línea.
           `flex: 1 1 0` sin esa basis permitía squeeze de varios pares
           en la misma fila — caso real visto en el último deploy. */
        flex: 0 0 calc(100% - 160px);
        max-width: calc(100% - 160px);
    }
}

/* ============================================================
   WIDGET REORDER — drag&drop para reordenar cards de un hub.
   Compartido por /admin, /mantenimientos, /modulos. Detalle en
   WIDGETS_REORDER.md. JS: static/js/widget-order.js.
   ============================================================ */

/* Anti-FOUC del reorden: con orden guardado, las cards se pintarían
   primero en el orden del template y el JS las reordenaría tras cargar
   (los <script> son render-blocking al final del body) -> salto
   visible. El template marca la row con `widget-order-pending` SOLO si
   hay orden guardado; la ocultamos hasta que widget-order.js reordena
   el DOM y revela en el mismo tick sincrono, antes del primer paint del
   orden correcto. Sin orden guardado la clase no se anade y la row
   pinta al instante (sin fase oculta). */
.widget-order-row {
    transition: opacity 0.15s ease-out;
}
.widget-order-row.widget-order-pending {
    opacity: 0;
    /* Failsafe: si el JS no revela en 1.5s (error de carga del script,
       etc.) forzamos la visibilidad para no dejar el hub en blanco. */
    animation: widget-order-failsafe-reveal 0s linear 1.5s forwards;
}
@keyframes widget-order-failsafe-reveal { to { opacity: 1; } }

.widget-drag-handle {
    position: absolute;
    top: 0.4rem;
    left: 0.4rem;
    z-index: 10;
    width: 26px;
    height: 26px;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: rgba(255,255,255,0.85);
    border: 1px solid #dee2e6;
    border-radius: 4px;
    color: #adb5bd;
    cursor: grab;
    font-size: 0.95rem;
    line-height: 1;
    transition: background-color 0.1s, color 0.1s, opacity 0.1s;
    opacity: 0;
}
/* Solo aparece al hacer hover sobre la card — no satura visualmente. */
[data-widget-id]:hover .widget-drag-handle,
.widget-drag-handle:focus {
    opacity: 1;
}
.widget-drag-handle:hover {
    background-color: #fff;
    color: #495057;
}
.widget-drag-handle:active,
.widget-drag-handle.sortable-grabbing {
    cursor: grabbing;
}

/* SortableJS classes durante el drag. */
.sortable-ghost  { opacity: 0.35; }
.sortable-chosen { box-shadow: 0 0.6rem 1.2rem rgba(0,0,0,0.18); }
.sortable-chosen .admin-card,
.sortable-chosen .maintenance-card,
.sortable-chosen .modulos-card { transform: none; }

/* Mini toast "Orden guardado" tras drop. */
#widget-order-toast {
    position: fixed;
    right: 1rem;
    top: 1rem;
    z-index: 1080;
    background: #28a745;
    color: #fff;
    padding: 0.35rem 0.75rem;
    border-radius: 4px;
    font-size: 0.85rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0,0,0,0.15);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.2s, transform 0.2s;
    pointer-events: none;
}
#widget-order-toast.show {
    opacity: 1;
    transform: translateY(0);
}

/* ============================================================
   ACCESOS DIRECTOS (⭐) — estrella de fijar en las cards de los hubs
   + bloque del sidebar. JS: static/js/shortcuts.js. Backend:
   routes/shortcuts.py. Detalle en ACCESOS_DIRECTOS.md.
   ============================================================ */

/* Estrella de fijar en la card del hub. Agrupada arriba a la izquierda
   junto al grip de reordenar (así NO tapa el badge de contador de la
   esquina superior derecha). Aparece en hover; si está fijada o en
   pantalla táctil, siempre visible. */
.widget-fav-star {
    position: absolute;
    top: 0.4rem;
    left: 2.35rem;               /* justo a la derecha del .widget-drag-handle */
    z-index: 10;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: rgba(255,255,255,0.85);
    border: 1px solid #dee2e6;
    border-radius: 4px;
    color: #adb5bd;
    cursor: pointer;
    font-size: 0.95rem;
    line-height: 1;
    transition: background-color 0.1s, color 0.1s, opacity 0.1s;
    opacity: 0;
}
[data-widget-id]:hover .widget-fav-star,
.widget-fav-star:focus,
.widget-fav-star.is-pinned {
    opacity: 1;
}
.widget-fav-star:hover { background-color: #fff; color: #f0ad4e; }
.widget-fav-star.is-pinned { color: #f0ad4e; border-color: #f0ad4e; }
/* En móvil el grip está oculto (d-md-flex): la estrella ocupa su sitio. */
@media (max-width: 767.98px) {
    .widget-fav-star { left: 0.4rem; }
}
/* Táctil (sin hover): la estrella siempre visible para poder fijar. */
@media (hover: none) {
    .widget-fav-star { opacity: 1; }
}

/* ---- Bloque "Accesos directos" del sidebar ---- */
.sidebar-shortcuts-label {
    padding: 0.5rem 1rem 0.2rem;
    font-size: 0.62rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: rgba(255,255,255,0.4);
}
.sidebar-shortcuts-label .bi-star-fill { color: #f0ad4e; }
body.is-super-admin .sidebar-shortcuts-label { padding-top: 0.35rem; }

/* Cada atajo reutiliza .list-group-item del sidebar (color/hover/active
   ya heredados). Aquí solo la disposición interna grip · icono · texto · ✕. */
#sidebar-wrapper .sidebar-shortcut-item {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding-right: 0.4rem;
}
.sidebar-shortcut-grip {
    color: rgba(255,255,255,0.28);
    cursor: grab;
    font-size: 0.8rem;
    align-items: center;
    flex: 0 0 auto;
}
.sidebar-shortcut-grip:hover { color: rgba(255,255,255,0.6); }
.sidebar-shortcut-grip:active { cursor: grabbing; }
.sidebar-shortcut-icon { flex: 0 0 auto; }
.sidebar-shortcut-text {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sidebar-shortcut-remove {
    flex: 0 0 auto;
    background: transparent;
    border: none;
    color: rgba(255,255,255,0.35);
    padding: 0 0.15rem;
    line-height: 1;
    font-size: 0.95rem;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.1s, color 0.1s;
}
.sidebar-shortcut-item:hover .sidebar-shortcut-remove { opacity: 1; }
.sidebar-shortcut-remove:hover { color: #ff8a8a; }
@media (hover: none) {
    .sidebar-shortcut-remove { opacity: 1; }   /* táctil: siempre visible */
}
.sidebar-shortcuts .sidebar-separator { margin-bottom: 0.25rem; }

/* Estrella de fijar en la cabecera de una ficha (Fase 2). Flotada a la
   IZQUIERDA del page-header (metáfora de bookmark; la derecha la ocupa el
   FAB fijo de vistas recientes 🕐, con el que chocaba a la derecha). Gris
   → dorada al fijar. Siempre visible (la ficha no tiene el "hover sobre
   card" de los hubs). */
.ficha-fav-star {
    float: left;
    margin-right: 0.55rem;
    margin-top: 0.1rem;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    color: #adb5bd;
    cursor: pointer;
    font-size: 0.9rem;
    line-height: 1;
    transition: color 0.1s, background-color 0.1s, border-color 0.1s;
}
.ficha-fav-star:hover { color: #f0ad4e; border-color: #f0ad4e; }
.ficha-fav-star.is-pinned { color: #f0ad4e; border-color: #f0ad4e; }

/* Estrella de fijar en una sección top-level del sidebar (Fase 3). Vive
   DENTRO del <a> del menú (fondo oscuro), a la derecha (zona vacía, no
   pisa el badge de contador que va inline junto al texto). Aparece en
   hover; dorada si está fijada. */
#sidebar-wrapper .list-group-item.has-sec-star { position: relative; }
.sidebar-sec-star {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: none;
    color: rgba(255,255,255,0.5);
    padding: 0 0.2rem;
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.1s, color 0.1s;
}
#sidebar-wrapper .list-group-item:hover .sidebar-sec-star,
.sidebar-sec-star:focus,
.sidebar-sec-star.is-pinned { opacity: 1; }
.sidebar-sec-star:hover,
.sidebar-sec-star.is-pinned { color: #f0ad4e; }
@media (hover: none) { .sidebar-sec-star { opacity: 1; } }

/* Toast propio (oscuro, distinto del verde de "Orden guardado"). */
#okms-shortcut-toast {
    position: fixed;
    right: 1rem;
    top: 1rem;
    z-index: 1080;
    background: #343a40;
    color: #fff;
    padding: 0.35rem 0.75rem;
    border-radius: 4px;
    font-size: 0.85rem;
    box-shadow: 0 0.25rem 0.75rem rgba(0,0,0,0.15);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.2s, transform 0.2s;
    pointer-events: none;
}
#okms-shortcut-toast.show { opacity: 1; transform: translateY(0); }

/* ============================================================
   COLLAPSIBLE CARD — cards desplegables que sobreviven al refresh AJAX
   (Desayunos, Fidelización en booking_detail). JS en collapsible_card.js.
   ============================================================ */
[data-collapse-toggle] {
    cursor: pointer;
    user-select: none;
}
.collapse-card-chevron {
    transition: transform 0.15s ease;
    margin-right: 0.35rem;
    color: #6c757d;
}

/* ============================================================
   MANDOS DE GARAJE — card del dashboard (garage-mando.js)
   ============================================================ */
.garage-mando-tile {
    border: 1px solid rgba(40, 167, 69, 0.25);
    border-radius: 6px;
    padding: 0.75rem;
    background: rgba(40, 167, 69, 0.03);
    display: flex;
    flex-direction: column;
}
.garage-mando-tile .btn-open-mando {
    width: 100%;
}
.garage-mando-history li + li {
    margin-top: 2px;
}

/* ============================================================
   PLANNING — timeline de ocupación (/reservas/planning)
   Filas = propiedades, columnas = días, barras = reservas.
   Ver PLANNING.md.
   ============================================================ */
.plan-scroll {
    overflow-x: auto;
    overflow-y: auto;
    /* Alto acotado → la rejilla scrollea DENTRO de la caja y así la
       cabecera de dias (.plan-head, sticky top), la columna de nombres
       (.plan-row-label, sticky left) y el pie 'Libres' (.plan-foot,
       sticky bottom) quedan clavados al hacer scroll. Sin esta altura el
       sticky NO engancha: .plan-scroll seria el contexto de scroll pero
       no tiene scroll vertical propio (scrollearia la pagina entera). El
       calc deja hueco para el navbar/tabs/barra de navegacion de arriba;
       con pocas filas la caja se queda a la altura del contenido (el
       max-height no fuerza alto). */
    max-height: calc(100vh - 185px);
    -webkit-overflow-scrolling: touch;
    border: 1px solid #e3e6ea;
    border-radius: 6px;
    background: #fff;
}
.plan-grid {
    display: flex;
    flex-direction: column;
}
.plan-grid-row {
    display: flex;
    align-items: stretch;
    border-top: 1px solid #eef0f2;
    min-height: 30px;
}
.plan-grid-row:first-child { border-top: none; }

/* Columna izquierda fija (nombre de propiedad) — sticky al hacer
   scroll horizontal. */
.plan-row-label {
    flex: 0 0 var(--plan-label-w, 140px);
    width: var(--plan-label-w, 140px);
    position: sticky;
    left: 0;
    z-index: 3;
    background: #fff;
    border-right: 2px solid #dfe3e7;
    padding: 3px 8px;
    font-size: 0.78rem;
    line-height: 1.15;
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
}
/* Etiqueta del rango de fechas en la esquina (cabecera de la
   columna Propiedad): compacta, puede partir a 2 líneas. */
.plan-corner-range {
    font-weight: 700;
    font-size: 0.72rem;
    color: #34404b;
    white-space: normal;
    line-height: 1.05;
}
.plan-place-link {
    font-weight: 600;
    color: #2c3e50;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.plan-place-link:hover { color: #1a6ee0; }
.plan-loc {
    font-size: 0.68rem;
    color: #8a939b;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Pista de días (área donde se posicionan celdas y barras). */
.plan-track {
    position: relative;
    flex: 1 1 auto;
    min-height: 30px;
}
.plan-head .plan-track { min-height: 42px; }

/* Celdas de fondo (una por día) — solo gridlines + resaltados. */
.plan-cell {
    position: absolute;
    top: 0;
    bottom: 0;
    border-right: 1px solid #eef0f2;
    pointer-events: none;
}
.plan-cell.plan-weekend { background: #f6f8fa; }
.plan-cell.plan-today   { background: rgba(26, 110, 224, 0.07); }

/* Cabecera de días — clavada arriba (sticky top) dentro de .plan-scroll.
   z-index por ENCIMA del hover de las barras (.plan-bar:hover = 6) para que
   una barra resaltada cerca del borde superior no pinte sobre la cabecera. */
.plan-head {
    background: #f8f9fb;
    position: sticky;
    top: 0;
    z-index: 7;
}
/* Esquina (interseccion cabecera×columna-nombres): pinada arriba-izquierda,
   por encima de todo. */
.plan-corner {
    background: #f8f9fb;
    z-index: 8;
    font-weight: 600;
    color: #55606b;
    font-size: 0.75rem;
}
.plan-daycol {
    position: absolute;
    top: 0;
    bottom: 0;
    border-right: 1px solid #e6e9ec;
    text-align: center;
    padding-top: 3px;
    font-size: 0.68rem;
    color: #6b7680;
}
.plan-daycol.plan-weekend { background: #eef1f4; }
.plan-daycol.plan-today   { background: rgba(26, 110, 224, 0.12); }
.plan-dc-mon {
    font-size: 0.6rem;
    font-weight: 700;
    text-transform: uppercase;
    color: #1a6ee0;
    line-height: 1;
}
.plan-dc-wd  { line-height: 1; }
.plan-dc-day { font-weight: 700; font-size: 0.8rem; color: #34404b; line-height: 1.1; }
.plan-daycol.plan-today .plan-dc-day { color: #1a6ee0; }

/* Barras de reserva. */
.plan-bar {
    position: absolute;
    top: 3px;
    bottom: 3px;
    border-radius: 4px;
    padding: 0 5px;
    display: flex;
    align-items: center;
    overflow: hidden;
    color: #fff;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1;
    box-shadow: 0 1px 1px rgba(0,0,0,0.15);
    z-index: 2;
    text-decoration: none;
    transition: filter 0.12s ease;
    /* Inset horizontal (calc en el style inline) separa barras adyacentes;
       este min-width evita que una barra muy corta desaparezca. */
    min-width: 8px;
}
.plan-bar:hover { filter: brightness(1.08); color: #fff; text-decoration: none; z-index: 6; }
.plan-bar-txt {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Barra que continúa fuera de la ventana: canto recto + flechita. */
.plan-cont-l { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.plan-cont-r { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.plan-cont-l::before {
    content: "‹"; position: absolute; left: 1px; opacity: 0.85; font-weight: 700;
}
.plan-cont-r::after {
    content: "›"; position: absolute; right: 1px; opacity: 0.85; font-weight: 700;
}

/* Colores por estado de reserva (convención del proyecto). */
.plan-bar-s1 { background: #f39c12; }  /* pendiente */
.plan-bar-s3 { background: #28a745; }  /* activa    */
.plan-bar-s4 { background: #6c757d; }  /* finalizada */
.plan-bar-s2 { background: #e74c3c; }  /* cancelada (no debería aparecer) */
/* Bloqueo del PMS / estancia del propietario (domopaco_place_blocks) —
   barra negra NO clicable (es un div, no un <a>). Ver PLACE_BLOCKS.md. */
.plan-bar-block { background: #1f2429; cursor: default; }

/* Pie de libres — clavado abajo (sticky bottom) dentro de .plan-scroll,
   mismo tier de z-index que la cabecera. Su celda 'Libres' es un
   .plan-corner (z-index 8) → queda pinada abajo-izquierda. */
.plan-foot {
    background: #f8f9fb;
    border-top: 2px solid #dfe3e7;
    font-weight: 700;
    position: sticky;
    bottom: 0;
    z-index: 7;
}
.plan-freecell {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    color: #2e7d32;
    border-right: 1px solid #eef0f2;
}
.plan-freecell.plan-today { background: rgba(26, 110, 224, 0.07); }
.plan-freecell.plan-free-none { color: #c0392b; background: rgba(231, 76, 60, 0.08); }

/* Leyenda. */
.plan-legend-item { margin-right: 0.85rem; white-space: nowrap; }
.plan-swatch {
    display: inline-block;
    width: 12px; height: 12px;
    border-radius: 3px;
    vertical-align: -1px;
    margin-right: 3px;
}

/* ============================================================
   USO · Tab "Clientes" — salud de uso de OKmystay por empresa
   (routes/uso.py::_clientes_data, templates/uso/_tab_clientes.html
   y cliente_detail.html). Detalle en REQUEST_TIMINGS.md.
   ============================================================ */
.cli-table td, .cli-table th { vertical-align: middle; }
.cli-table tbody tr { border-left: 4px solid transparent; }
.cli-table tbody tr.cli-h-green   { border-left-color: #2ecc71; }
.cli-table tbody tr.cli-h-amber   { border-left-color: #f1c40f; }
.cli-table tbody tr.cli-h-red     { border-left-color: #e74c3c; }
.cli-table tbody tr.cli-h-inactive{ border-left-color: #ced4da; }

/* Badge de salud (dot + etiqueta) */
.cli-health { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.72rem;
              font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }
.cli-health .dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.cli-h-green   .cli-health, .cli-health.green   { color: #1f7a3d; }
.cli-h-amber   .cli-health, .cli-health.amber   { color: #b7791f; }
.cli-h-red     .cli-health, .cli-health.red     { color: #c0392b; }
.cli-h-inactive .cli-health, .cli-health.inactive { color: #868e96; }
.cli-health.green   .dot { background: #2ecc71; }
.cli-health.amber   .dot { background: #f1c40f; }
.cli-health.red     .dot { background: #e74c3c; }
.cli-health.inactive .dot { background: #ced4da; }

/* Celda de palanca: adopción % grande + flecha + volumen */
.cli-feat { display: flex; flex-direction: column; align-items: center;
            justify-content: center; line-height: 1.15; min-width: 78px; }
.cli-feat-adop { font-size: 1.15rem; font-weight: 700; color: #2c3e50;
                 font-variant-numeric: tabular-nums; }
.cli-feat-vol { font-size: 0.66rem; margin-top: 0.1rem; }
.cli-feat-unused { color: #adb5bd; font-style: italic; }

/* Flecha de tendencia */
.cli-trend { display: inline-flex; align-items: center; gap: 1px; font-size: 0.72rem;
             font-weight: 600; font-variant-numeric: tabular-nums; }
.cli-trend.up   { color: #1f7a3d; }
.cli-trend.down { color: #c0392b; }
.cli-trend.flat { color: #adb5bd; }
.cli-trend.new  { color: #2b6cb0; }
.cli-trend i { font-size: 0.95rem; line-height: 1; }

/* Curva mensual del drill-down (4 mini-barras de adopción) */
.cli-curve-svg { width: 100%; height: 90px; display: block; }
.cli-curve-svg .bar { transition: opacity .1s; }
.cli-curve-svg .bar:hover { opacity: 0.75; }
.cli-curve-title { font-size: 0.78rem; font-weight: 600; color: #495057; margin-bottom: 0.2rem; }

/* Tabla por reserva (réplica v1): rojo si 0 en una palanca que la empresa usa */
.cli-cell-zero { background-color: rgba(231,76,60,0.14); font-weight: 700; color: #c0392b; }

/* Estado "low" (pocos datos) — visualmente gris como inactive */
.cli-table tbody tr.cli-h-low { border-left-color: #ced4da; }
.cli-h-low .cli-health, .cli-health.low { color: #868e96; }
.cli-health.low .dot { background: #ced4da; }

/* Barras HTML con número encima — tab "Panel del huésped" de /admin/uso
   (uso/_huesped_body.html). Reemplazan a los SVG para poder rotular cada
   barra sin que preserveAspectRatio="none" deforme el texto. */
.uso-barchart { display: flex; align-items: flex-end; gap: 2px;
                border-bottom: 1px solid #e9ecef; padding-top: 4px; }
.uso-bar-col { flex: 1 1 0; min-width: 0; height: 100%; display: flex;
               flex-direction: column; justify-content: flex-end; align-items: center; }
.uso-bar-num { font-size: 0.58rem; color: #868e96; font-variant-numeric: tabular-nums;
               line-height: 1; margin-bottom: 2px; white-space: nowrap; }
.uso-bar-fill { width: 80%; min-height: 1px; border-radius: 2px 2px 0 0;
                background: #4a90e2; transition: opacity .1s; }
.uso-bar-fill:hover { opacity: 0.78; }
.uso-bar-fill.cur { background: #a9c9f0; }
.uso-barchart-green .uso-bar-fill { background: #2ecc71; }
.uso-barchart-green .uso-bar-fill.cur { background: #8fdcae; }

/* Overlay "Calculando…" al cambiar de empresa en el tab Panel del huésped */
.huesped-spin { position: absolute; top: 60px; left: 50%; transform: translateX(-50%);
                z-index: 6; background: #fff; border: 1px solid #e9ecef;
                border-radius: 20px; padding: 6px 16px; font-size: 0.9rem;
                color: #495057; box-shadow: 0 2px 10px rgba(0,0,0,0.12); }
.huesped-spin .spin { margin-right: 4px; }

/* Etiquetas mes/año bajo cada barra (tab Panel del huésped) */
.uso-barlabels { display: flex; gap: 2px; margin-top: 3px; }
.uso-bar-lbl { flex: 1 1 0; min-width: 0; text-align: center; font-size: 0.54rem;
               color: #adb5bd; font-variant-numeric: tabular-nums; white-space: nowrap;
               overflow: hidden; }
.uso-bar-lbl.cur { color: #6c757d; font-weight: 600; }

/* Tono por año (agrupa visualmente las barras del mismo año) */
.uso-bar-fill.yr0 { background: #4a90e2; }
.uso-bar-fill.yr1 { background: #6ba3ea; }
.uso-barchart-green .uso-bar-fill.yr0 { background: #2ecc71; }
.uso-barchart-green .uso-bar-fill.yr1 { background: #5bd68f; }

/* Marca del máximo / mínimo del período */
.uso-bar-tag { font-size: 0.5rem; font-weight: 700; line-height: 1; padding: 1px 3px;
               border-radius: 3px; margin-bottom: 2px; text-transform: uppercase;
               letter-spacing: 0.02em; white-space: nowrap; }
.uso-bar-tag.max { background: #d4f4e0; color: #1f7a3d; }
.uso-bar-tag.min { background: #fdecc8; color: #b7791f; }
.uso-bar-num.is-max { color: #1f7a3d; font-weight: 700; }
.uso-bar-num.is-min { color: #b7791f; font-weight: 700; }
.uso-bar-fill.bar-max { box-shadow: inset 0 0 0 2px #1f7a3d; }
.uso-bar-fill.bar-min { box-shadow: inset 0 0 0 2px #b7791f; }

/* ============================================================
   TAQUILLAS — /modulos/taquillas (En vivo + Reservas).
   Compartido por modulos/taquillas.html y taquillas_reservas.html.
   Ver TAQUILLAS.md §19.
   ============================================================ */
.taq-kpi-card {
    text-align: center;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    padding: 0.6rem 0.5rem;
}
.taq-kpi-label { font-size: 0.78rem; color: #6c757d; }
.taq-kpi-value { font-size: 1.5rem; font-weight: 600; line-height: 1.1; }

/* Grid de cajas (pared física del local) */
.taq-grid-row {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.55rem;
    margin-bottom: 0.55rem;
}
@media (max-width: 991px) {
    .taq-grid-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 575px) {
    .taq-grid-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.taq-cell {
    border: 1px solid rgba(0,0,0,0.12);
    border-radius: 6px;
    background: #fff;
    padding: 0.45rem 0.5rem;
    position: relative;
    min-height: 118px;
    display: flex; flex-direction: column;
}
.taq-cell-head {
    display: flex; align-items: baseline; gap: 0.35rem;
    margin-bottom: 0.15rem;
}
.taq-cell-num  { font-size: 1.05rem; font-weight: 700; }
.taq-cell-name { font-size: 0.82rem; color: #495057;
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.taq-cell-type { font-size: 0.68rem; }
/* Estado efectivo — borde izquierdo grueso + tinte suave. */
.taq-cell.taq-free   { border-left: 4px solid #0d8ddb; }
/* Ocupada AHORA: se destaca claramente (borde verde completo + tinte
   más marcado + sombra) para que salte a la vista en la pared. */
.taq-cell.taq-busy   {
    border: 1px solid #28a745;
    border-left: 5px solid #28a745;
    background: rgba(40,167,69,0.13);
    box-shadow: 0 1px 5px rgba(40,167,69,0.28);
}
.taq-cell.taq-gw,
.taq-cell.taq-nolink { border-left: 4px solid #dc3545; background: rgba(220,53,69,0.05); }
/* Deshabilitada: rayado diagonal "fuera de uso" para que no pase
   desapercibida (antes solo bajaba opacidad y apenas se notaba). */
.taq-cell.taq-off    {
    border-left: 4px solid #6c757d;
    color: #6c757d;
    background:
        repeating-linear-gradient(45deg,
            #eceef0, #eceef0 7px,
            #dee2e6 7px, #dee2e6 14px);
}
.taq-cell.taq-off .taq-cell-name { color: #6c757d; }
.taq-off-badge { font-size: 0.66rem; }

/* Batería crítica (<10%): la caja dejará de abrir pronto. Debe saltar a
   la vista al mirar la pared "por encima", incluso si la caja está off
   (el resalte es ortogonal al estado). Motion = mejor pista para la
   visión periférica; el badge sólido rojo la remata al fijar la mirada. */
.taq-batt-crit { font-size: 0.66rem; font-weight: 700; }
.taq-cell.taq-cell-batt-crit {
    border: 1.5px solid #dc3545;
    animation: taq-batt-crit-glow 1.4s ease-in-out infinite;
}
@keyframes taq-batt-crit-glow {
    0%, 100% { box-shadow: 0 0 3px 1px rgba(220,53,69,0.45); }
    50%      { box-shadow: 0 0 12px 4px rgba(220,53,69,0.85); }
}
@media (prefers-reduced-motion: reduce) {
    .taq-cell.taq-cell-batt-crit {
        animation: none;
        box-shadow: 0 0 8px 2px rgba(220,53,69,0.75);
    }
}

/* Reserva de la celda ocupada → abre la pestaña Reservas filtrada. */
.taq-goto-book {
    cursor: pointer; border: 0; background: none; padding: 0;
    color: #1e7e34; font-weight: 600; font-size: 0.78rem;
    line-height: 1;
}
.taq-goto-book:hover { text-decoration: underline; }
.taq-cell-meta { font-size: 0.74rem; color: #6c757d; }
.taq-cell-actions {
    margin-top: auto;
    display: flex; align-items: center; gap: 0.3rem; flex-wrap: wrap;
}
.taq-cell-actions .btn { padding: 0.05rem 0.35rem; font-size: 0.75rem; }
.taq-guest {
    font-size: 0.78rem; margin-top: 0.15rem;
    border-top: 1px dashed rgba(0,0,0,0.1); padding-top: 0.2rem;
}
.taq-pin-slot { font-family: monospace; letter-spacing: 1px; }

/* Listados de reservas */
.taq-books-table td { vertical-align: middle; }
.taq-hist-row > td { background: #fbfbfd; }
.taq-hist-key { font-size: 0.72rem; font-weight: 600; }

/* Pills de estado con contador (pestaña Reservas) */
.taq-estado-pill { cursor: pointer; }
.taq-estado-pill .badge { font-size: 0.7rem; }

/* Toast flotante propio (no empuja el layout) */
#taq-flash {
    position: fixed; top: 1rem; right: 1rem;
    z-index: 1080; max-width: 360px; pointer-events: none;
}
#taq-flash > .alert { pointer-events: auto;
    box-shadow: 0 0.25rem 0.75rem rgba(0,0,0,0.15); }

/* Chip "actualizado / pausado" */
.taq-live-chip {
    font-size: 0.72rem; color: #6c757d;
    border: 1px solid rgba(0,0,0,0.1); border-radius: 10px;
    padding: 0.1rem 0.5rem; white-space: nowrap;
}

/* ============================================================
   DISPOSITIVOS — listado (/dispositivos) y conexiones DD
   (compartido por las pestañas Equipos y Conexiones DD)
   ============================================================ */
.dev-kpis { display:flex; flex-wrap:wrap; gap:0.6rem; margin-bottom:1rem; }
.dev-kpi {
    flex:1 1 140px; min-width:140px;
    background:#fff; border:1px solid rgba(0,0,0,0.08); border-radius:8px;
    padding:0.6rem 0.75rem;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    text-align:center;
}
.dev-kpi .dev-kpi-label { font-size:0.7rem; text-transform:uppercase; letter-spacing:0.02em; opacity:0.65; }
.dev-kpi .dev-kpi-value { font-size:1.5rem; font-weight:700; line-height:1.15; }
.dev-kpi-alive    .dev-kpi-value { color:#28a745; }
.dev-kpi-offline  .dev-kpi-value { color:#dc3545; }
.dev-kpi-outdated .dev-kpi-value { color:#e67e22; }
.dev-kpi-flap     .dev-kpi-value { color:#e67e22; }
.dev-kpi-dd       .dev-kpi-value { color:#17a2b8; }
.dev-kpi.is-zero  .dev-kpi-value { color:#adb5bd; }

.dev-status {
    display:inline-flex; align-items:center; gap:0.35rem;
    padding:0.1rem 0.5rem; border-radius:999px;
    color:#fff; font-size:0.75rem; font-weight:600; white-space:nowrap;
}
.dev-status .dot { width:7px; height:7px; border-radius:50%; background:rgba(255,255,255,0.9); }
.dev-status-alive   { background:#28a745; }
.dev-status-offline { background:#dc3545; }
.dev-status-rip     { background:#212529; }
.dev-status-alive .dot { animation:dev-pulse 2s ease-in-out infinite; }
@keyframes dev-pulse { 0%,100%{opacity:1;} 50%{opacity:0.35;} }

.dev-age { font-size:0.72rem; color:#6c757d; white-space:nowrap; }

.dev-badge {
    display:inline-block; padding:0.05rem 0.4rem; border-radius:4px;
    font-size:0.68rem; font-weight:600; line-height:1.4; text-decoration:none;
}
a.dev-badge:hover { text-decoration:none; filter:brightness(0.97); }
.dev-badge-hub   { background:#e7f1ff; color:#0d6efd; border:1px solid #b6d4fe; }
.dev-badge-deleg { background:#f1f3f5; color:#6c757d; border:1px solid #dee2e6; }
.dev-badge-dd    { background:#d1f5fa; color:#0b7285; border:1px solid #9be3ef; }
.dev-badge-dd .dot { display:inline-block; width:6px; height:6px; border-radius:50%; background:#17a2b8; margin-right:3px; vertical-align:middle; }

.dev-fw     { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:0.8rem; }
.dev-fw-ok  { color:#198754; }
.dev-fw-old { color:#e67e22; font-weight:700; }
.dev-fw-old::after { content:" ⚠"; }

.dev-net { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:0.74rem; color:#495057; white-space:nowrap; }
.dev-net .lbl { color:#adb5bd; }

.dev-filters { display:flex; flex-wrap:wrap; gap:0.4rem; align-items:center; margin-bottom:0.6rem; }
.dev-filters .form-control-sm, .dev-filters .custom-select-sm { height:calc(1.5em + 0.5rem + 2px); }
#dev-empty { display:none; }
table.dev-table td { vertical-align:middle; }
table.dev-table .mac { font-family:ui-monospace,monospace; font-size:0.68rem; color:#adb5bd; }

/* ============================================================
   VERIFACTU — selector de emisor del sub-nav (_tabs.html)
   ============================================================
   filter-typeahead.js oculta el <select> y lo sustituye por un
   `.ta-wrap` que nace SOLO con esa clase: las utilidades de margen
   del select (mr-1) quedan en el nodo oculto y no separan nada. La
   separación con lo que va detrás (badge de PRUEBAS, aviso de
   "mezclando", o el (i) cuando el emisor es de producción y no hay
   badge) se pone aquí, sobre el wrapper visible. */
#vf-scope-form .ta-wrap { margin-right: 0.65rem; }

/* ============================================================
   ENTITY REFS — chip-enlace a entidades dentro de texto libre
   ============================================================
   Render de entity_refs.py (filtro Jinja `notif_msg`): tokens tipo
   [booking_id=112225] / [item_id:207] / smss.id[268] se convierten en
   este chip. Lo comparten Admin·Notificaciones, el widget de notas
   manuales y las filas MANUAL_NOTE de las cards de auditoría. */
.notif-ref {
    display: inline-flex; align-items: center; gap: 0.25rem;
    padding: 0.05rem 0.4rem; margin: 0 0.1rem;
    border: 1px solid rgba(0,123,255,0.35); border-radius: 4px;
    background: rgba(0,123,255,0.06);
    font-family: var(--bs-font-sans-serif, system-ui);
    font-size: 0.74rem; font-weight: 600; line-height: 1.4;
    color: #0a58ca; text-decoration: none; white-space: nowrap;
}
.notif-ref:hover { background: rgba(0,123,255,0.14); color: #084298; text-decoration: none; }

/* ── Widget "Notas" de una ficha (manual_notes_card.html) ──
   Filas con el mismo lenguaje visual que las MANUAL_NOTE de la
   auditoría (tinte amarillo + borde izquierdo + lápiz). */
.manual-notes-card .card-header { cursor: pointer; }
.manual-note-item {
    background: rgba(255, 193, 7, 0.07);
    border-left: 3px solid #ffc107;
    border-radius: 3px;
    padding: 0.35rem 0.6rem;
    margin: 0.35rem 0;
}
.manual-note-item .manual-note-text {
    font-size: 0.86rem;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ── Picker de emojis (helper emoji-picker.js) ──
   .okms-emoji-panel = clase genérica para nuevos consumidores;
   .manual-note-emoji-panel se conserva por el modal de notas. */
.manual-note-emoji-panel,
.okms-emoji-panel {
    margin-top: 0.4rem;
    padding: 0.4rem 0.5rem;
    border: 1px solid #dee2e6;
    border-radius: 4px;
    background: #fdfdfd;
    max-height: 180px;
    overflow-y: auto;
}
.manual-note-emoji-panel .emoji-panel-label,
.okms-emoji-panel .emoji-panel-label {
    font-size: 0.68rem; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.03em; color: #adb5bd; margin: 0.2rem 0 0.1rem;
}
.manual-note-emoji-panel .emoji-panel-row,
.okms-emoji-panel .emoji-panel-row {
    display: flex; flex-wrap: wrap; gap: 0.1rem;
}
.manual-note-emoji-panel .emoji-pick,
.okms-emoji-panel .emoji-pick {
    border: 0; background: transparent; cursor: pointer;
    font-size: 1.15rem; line-height: 1.5; padding: 0.1rem 0.25rem;
    border-radius: 4px;
}
.manual-note-emoji-panel .emoji-pick:hover,
.okms-emoji-panel .emoji-pick:hover { background: rgba(0,123,255,0.12); }

/* ============================================================
   PLACE PHOTOS — grid de fotos de la ficha de propiedad
   (PLACE_CONTENT.md F3). La PORTADA es SIEMPRE el primer tile:
   el badge se pinta solo ahí vía :first-child.
   ============================================================ */
.place-photos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 0.75rem;
}
.pp-tile {
    position: relative;
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 6px;
    overflow: hidden;
    background: #fff;
    cursor: grab;
}
.pp-tile:active { cursor: grabbing; }
.pp-ghost { opacity: 0.4; }
.pp-img-link { display: block; }
.pp-tile img {
    width: 100%;
    height: 120px;
    object-fit: cover;
    display: block;
    background: #f2f2f2;
}
.pp-cover-badge {
    display: none;
    position: absolute;
    top: 6px; left: 6px;
    font-size: 0.65rem;
    pointer-events: none;
}
.pp-tile:first-child .pp-cover-badge { display: inline-block; }
.pp-meta {
    padding: 0.3rem 0.45rem 0;
    font-size: 0.75rem;
    min-height: 1.6rem;
}
.pp-room-badge { font-size: 0.65rem; }
.pp-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.25rem;
    padding: 0.25rem 0.45rem 0.4rem;
}
/* Feedback visual del drag&drop de subida sobre el card */
#place-photos-card.pp-dragover {
    outline: 2px dashed #2ecc71;
    outline-offset: -6px;
}
.pp-img-link { cursor: zoom-in; }

/* Fila del caption + iconito de traducción */
.pp-caption-row {
    display: flex;
    align-items: flex-start;
    gap: 0.25rem;
}
.pp-caption-row .pp-caption { flex: 1 1 auto; min-width: 0; }
.pp-i18n-btn {
    flex: 0 0 auto;
    background: none;
    border: none;
    padding: 0;
    line-height: 1;
    color: #2dccd3;
    cursor: pointer;
    font-size: 0.85rem;
}
.pp-i18n-btn:hover { color: #17a2b8; }

/* Contenido del popover de traducciones (inyectado en body por Bootstrap) */
.pp-i18n-row { margin-bottom: 0.25rem; }
.pp-i18n-row:last-child { margin-bottom: 0; }
.pp-i18n-loc {
    display: inline-block;
    min-width: 4.5rem;
    font-weight: 600;
    color: #6c757d;
    font-size: 0.72rem;
    text-transform: uppercase;
}
.pp-i18n-txt { font-size: 0.85rem; }

/* ============================================================
   PLACE PHOTOS — LIGHTBOX (visor a pantalla completa)
   Overlay propio (no un modal Bootstrap) con flechas, contador,
   descripción superpuesta y zoom con arrastre.
   ============================================================ */
body.pp-lb-open { overflow: hidden; }
.pp-lb {
    position: fixed;
    inset: 0;
    z-index: 3000;
    background: rgba(0, 0, 0, 0.92);
    display: none;
    align-items: center;
    justify-content: center;
}
.pp-lb.open { display: flex; }
.pp-lb-stage {
    width: 96vw;
    height: 92vh;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.pp-lb-img {
    max-width: 96vw;
    max-height: 92vh;
    object-fit: contain;
    cursor: zoom-in;
    user-select: none;
    -webkit-user-drag: none;
}
.pp-lb.zoomed .pp-lb-stage { overflow: auto; cursor: grab; }
.pp-lb.zoomed .pp-lb-stage.panning { cursor: grabbing; }
.pp-lb.zoomed .pp-lb-img {
    max-width: none;
    max-height: none;
    cursor: inherit;
}
.pp-lb-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    border: none;
    width: 3rem;
    height: 4.5rem;
    font-size: 1.8rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s;
}
.pp-lb-nav:hover { background: rgba(0, 0, 0, 0.6); }
.pp-lb-prev { left: 0.5rem; border-radius: 0 6px 6px 0; }
.pp-lb-next { right: 0.5rem; border-radius: 6px 0 0 6px; }
.pp-lb-close {
    position: absolute;
    top: 0.6rem;
    right: 0.9rem;
    background: none;
    border: none;
    color: #fff;
    font-size: 1.5rem;
    cursor: pointer;
    opacity: 0.85;
    z-index: 2;
}
.pp-lb-close:hover { opacity: 1; }
.pp-lb-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 2.5rem 1.2rem 1rem;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
    color: #fff;
    display: flex;
    align-items: center;
    gap: 0.9rem;
    pointer-events: none;
}
.pp-lb-bar > * { pointer-events: auto; }
.pp-lb-counter {
    font-size: 0.85rem;
    opacity: 0.85;
    white-space: nowrap;
}
.pp-lb-caption {
    flex: 1 1 auto;
    font-size: 0.95rem;
    line-height: 1.3;
}
.pp-lb-caption.pp-lb-nocap { opacity: 0.6; font-style: italic; }
.pp-lb-zoombtn {
    flex: 0 0 auto;
    background: rgba(255, 255, 255, 0.18);
    border: none;
    color: #fff;
    border-radius: 4px;
    padding: 0.25rem 0.55rem;
    cursor: pointer;
}
.pp-lb-zoombtn:hover { background: rgba(255, 255, 255, 0.3); }

/* ============================================================
   BADGE REPETIDOR — huésped con >=2 visitas, antes del nombre en
   la columna Huésped de los listados de reservas (calendario,
   últimas, buscar) vía _partials/guest_block.html. Copa dorada + nº
   de veces que ha venido. Ver ESTADISTICAS_RESERVAS.md §2.5.
   ============================================================ */
.guest-repeat-badge {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
    padding: 2px 6px;
    margin-right: 5px;
    border-radius: 9px;
    background-color: #fff3cd;
    color: #8a6d1a;
    border: 1px solid #f0d98a;
    vertical-align: 1px;
    white-space: nowrap;
    cursor: default;
}
.guest-repeat-badge .bi { font-size: 0.72rem; }
