/* ---------- MODERN ADMIN THEME: ALPINE GRANITE & PINE ---------- */
:root {
    --primary: #1b3022;      /* Deep Forest Pine */
    --primary-light: #2d4a3e;
    /* Texto en verde de marca. --primary es el relleno (botones, insignias) y es
       casi negro, asi que usarlo como color de letra sobre una superficie oscura
       lo hacia ilegible; este token es el que se lee, y el tema oscuro lo
       aclara para mantener el contraste. */
    --primary-ink: #1b3022;
    --secondary: #455a64;    /* Granite Stone */
    --accent: #a67c52;       /* Cedar Wood Wood */
    --dark: #121612;         /* Night Rock */
    --sidebar-bg: #0d120f;   /* Deepest Green-Black */
    --bg: #f4f7f6;
    --bg-soft: #f8fafc;
    --card-bg: #ffffff;
    --text: #2c332c;
    --text-muted: #607d8b;
    --white: #ffffff;
    --border: #e0e4e2;
    --radius: 0px;           /* Architectural sharp lines */
    --shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
    --sidebar-width: 220px;
    --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: 'Inter', -apple-system, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    overflow-x: hidden;
}

/* ---------- LAYOUT ---------- */
.admin-layout {
    display: flex;
    min-height: 100vh;
}

/* ---------- SIDEBAR ---------- */
.sidebar {
    display: flex;
    flex-direction: column;
    width: var(--sidebar-width);
    background: var(--sidebar-bg);
    color: var(--white);
    position: fixed;
    height: 100vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    transition: var(--transition);
    z-index: 1000;
}

.nav-links {
    list-style: none;
    padding: 20px 15px;
}

.nav-links li { margin-bottom: 5px; }

.nav-links a {
    display: flex;
    align-items: center;
    padding: 12px 18px;
    color: rgba(255,255,255,0.65);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 500;
    border-radius: var(--radius);
    transition: var(--transition);
    text-transform: uppercase;
    letter-spacing: 1px;
}

.nav-links a i { width: 20px; font-size: 1rem; margin-right: 12px; }

.nav-links a:hover, .nav-links a.active {
    background: rgba(255,255,255,0.03);
    color: var(--white);
}

.nav-links a.active {
    color: var(--accent);
    border-left: 3px solid var(--accent);
    padding-left: 15px;
}

/* El header movil se declara aqui, y no solo dentro de su media query, porque .admin-layout
   es un flex y este div es su primer hijo. Sin una regla base el navegador lo pintaba
   tambien en escritorio: se comia ~180px de ancho a la izquierda de todo el contenido
   —el logo "Gestion" con su h1 sinDimensionar—, que se sumaban a los 220px del
   margin-left de .main-wrapper y dejaban el panel empezando sobre los 400px. Ademas se
   veia el logo y el boton de menu duplicados sobre el escritorio.

   El !important que llevaba su regla de movil se puede quitar ahora: era la forma de
   pelear contra esto mismo desde el otro lado. */
.mobile-header { display: none; }

/* ---------- MAIN CONTENT ---------- */
.main-wrapper {
    /* min-width: 0. .admin-layout es flex, y un hijo flex no baja de su min-content
       sin esto: cualquier tabla o cabecera que no se deja encoger”—el header con los
       cuatro botones, un table—que era mas ancha que 360 y empujaba el documento a
       390. Medido: html y body a 360, main-wrapper a 390. */
    min-width: 0;
    flex: 1;
    /* offset, no decoracion: el sidebar es position:fixed y no ocupa sitio en el
       flujo, asi que esto es lo unico que aparta el contenido de la barra. Por eso
       no puede bajar del ancho de la barra sin que el texto se meta debajo. */
    margin-left: var(--sidebar-width);
    padding: 20px 24px;
    transition: var(--transition);
}

.top-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px; /* Reduced from 40px */
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px; /* Reduced from 20px */
}

.top-header h2 {
    font-family: 'Playfair Display', serif;
    font-size: 1.5rem; /* Reduced from 2rem */
    color: var(--primary-ink);
    font-weight: 700;
}

.user-nav {
    display: flex;
    align-items: center;
    gap: 20px;
}

.role-badge {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    padding: 4px 12px;
    background: var(--primary);
    color: white;
    font-weight: 700;
}

/* ---------- UI COMPONENTS ---------- */
.card {
    background: var(--card-bg);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    border: 1px solid var(--border);
    margin-bottom: 30px;
    padding: 30px;
}

.card-title {
    font-family: 'Inter', sans-serif;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--primary-ink);
    font-weight: 700;
    margin-bottom: 30px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* Tables */
.table-container {
    overflow-x: auto;
    /* A scroll container should also stop the page behind it from scrolling
       sideways when a gesture overshoots the end of the table. */
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
}

table {
    width: 100%;
    border-collapse: collapse;
}

th {
    text-align: left;
    padding: 15px;
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    border-bottom: 2px solid var(--bg);
    letter-spacing: 1px;
    font-weight: 700;
}

td {
    padding: 18px 15px;
    font-size: 0.9rem;
    border-bottom: 1px solid var(--bg);
}

tr:last-child td { border-bottom: none; }

/* El atributo hidden gana siempre. Varias reglas del panel fijan display (grid,
   flex) y en esas el atributo se ignoraba: un bloque marcado como oculto
   seguia occupying sitio. */
[hidden] { display: none !important; }

/* Status Badges */
.status-pill {
    padding: 4px 12px;
    border-radius: 0px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
}

.status-confirmed,
.status-verified { background: #e6f7ef; color: #0f7a55; }
.status-pending,
.status-pending_verification { background: #fff8eb; color: #8a5a00; }
.status-awaiting_payment { background: #eef2ff; color: #3730a3; }
.status-manual_block { background: #eef2f6; color: #455a64; }
.status-cancelled,
.status-suspended { background: #fef2f2; color: #b42318; }
.status-neutral { background: #eef2f6; color: #455a64; }
.status-info { background: #eff6ff; color: #1d4ed8; }
.status-warn,
.status-warning { background: #fff8eb; color: #8a5a00; }
.status-error { background: #fef2f2; color: #b42318; }
.status-debug { background: #eef2f6; color: #455a64; }
.status-airbnb { background: #fee2e2; color: #991b1b; }
.status-booking { background: #e0f2fe; color: #075985; }

/* Paginacion de tablas. Antes no tenia ninguna regla: los botones salian
   pegados, sin separacion ni estado actual. */
.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-top: 1rem;
}
.pagination .btn { min-width: 2.2rem; }
.pagination .btn[aria-current="page"] { font-weight: 800; }
.pagination .btn[disabled],
.pagination .btn[aria-disabled="true"] { opacity: .45; cursor: default; }
.pagination__ellipsis { color: var(--text-muted); padding: 0 .2rem; }

/* Stats Grid */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 25px;
    margin-bottom: 40px;
}

.stat-item {
    background: var(--card-bg);
    padding: 25px;
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    border-left: 4px solid var(--primary);
}

.stat-item .label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    display: block;
    letter-spacing: 1px;
    font-weight: 600;
}

.stat-item .value {
    font-size: 2rem;
    font-weight: 700;
    color: var(--primary-ink);
    margin-top: 8px;
}

/* ---------- BUTTONS ---------- */
.btn {
    padding: 12px 24px;
    border-radius: var(--radius);
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 2px;
    cursor: pointer;
    transition: var(--transition);
    border: none;
}

.btn-primary { background: var(--primary); color: white; border: 1px solid var(--primary); }
.btn-primary:hover { background: transparent; color: var(--primary-ink); }

.btn-sm { padding: 8px 16px; font-size: 0.65rem; }

.btn-danger { background: #fff5f5; color: #e74c3c; border: 1px solid #fed7d7; }
.btn-danger:hover { background: #e74c3c; color: white; }

.btn-outline { background: transparent; border: 1px solid var(--border); color: var(--primary-ink); }
.btn-outline:hover { background: var(--primary); color: white; border-color: var(--primary-ink); }

/* ---------- MODALS ---------- */
.modal {
    display: none;
    position: fixed;
    top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(13, 18, 15, 0.8);
    backdrop-filter: blur(8px);
    z-index: 2000;
    align-items: center;
    justify-content: center;
}

.modal.active { display: flex; }

.modal-content {
    background: var(--card-bg);
    padding: 50px;
    width: 95%;
    max-width: 700px;
    max-height: 90vh;
    overflow-y: auto;
    position: relative;
    box-shadow: 0 30px 60px rgba(0,0,0,0.2);
}

.form-stack { display: grid; gap: 1rem; }
.modal-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .6rem; margin-top: .5rem; }
.modal-header {
    margin-bottom: 40px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--border);
    padding-bottom: 20px;
}

.modal-header h3 { font-family: 'Playfair Display', serif; font-size: 1.8rem; color: var(--primary-ink); }

/* Modal Close Button */
.btn-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    color: var(--text-muted);
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition);
    border-radius: 50%;
}

.btn-close:hover {
    background: #f1f5f9;
    color: var(--dark);
    transform: rotate(90deg);
}

/* Tab Navigation inside Modals */
.tabs-header {
    display: flex;
    border-bottom: 1px solid var(--border);
    margin-bottom: 30px;
    gap: 30px;
}

.tab-link {
    background: none;
    border: none;
    padding: 12px 0;
    cursor: pointer;
    font-weight: 700;
    color: var(--text-muted);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    position: relative;
    transition: var(--transition);
}

.tab-link:hover { color: var(--primary-ink); }

.tab-link.active { color: var(--accent); }

.tab-link.active::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--accent);
}

/* Form Caps labels */
.label-caps {
    font-weight: 800;
    font-size: 0.65rem;
    text-transform: uppercase;
    color: var(--text-muted);
    display: block;
    margin-bottom: 10px;
    letter-spacing: 1px;
}

.label-mini {
    font-weight: 700;
    font-size: 0.6rem;
    text-transform: uppercase;
    color: #94a3b8;
    display: block;
    margin-bottom: 6px;
    letter-spacing: 0.5px;
}

/* Form Control */
.form-group { margin-bottom: 25px; }
.form-group label { display: block; font-size: 0.7rem; text-transform: uppercase; font-weight: 700; color: var(--primary-ink); margin-bottom: 10px; letter-spacing: 1px; }
.form-control {
    width: 100%;
    padding: 14px 18px;
    background: #f9fbf9;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 0.95rem;
    transition: var(--transition);
}
.form-control:focus { outline: none; border-color: var(--accent); background: white; }

/* ---------- SECTIONS ---------- */
.content-section { display: none; }
.content-section.active { display: block; animation: fadeIn 0.5s ease; }

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(15px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ---------- RESPONSIVE ---------- */






/* ---------- CALENDAR COMPONENT REWRITE ---------- */
.calendar-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .75rem; padding: 15px 30px; border-bottom: 1px solid var(--border); }
.calendar-toolbar__filter { flex: 1 1 14rem; max-width: 22rem; }
.calendar-toolbar__filter .form-control { width: 100%; }
.calendar-wrapper {
    width: 100%;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    overflow: hidden;
    box-shadow: var(--shadow);
}

.calendar-header-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 30px; /* Reduced from 30px */
    background: var(--card-bg);
    border-bottom: 1px solid var(--border);
}

.calendar-header {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    background: var(--bg-soft);
    border-bottom: 1px solid var(--border);
}

.day-label {
    padding: 10px 5px; /* Reduced from 15px */
    text-align: center;
    font-size: 0.65rem;
    text-transform: uppercase;
    font-weight: 800;
    color: var(--text-muted);
    letter-spacing: 1.5px;
}

.calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    grid-auto-rows: minmax(100px, auto); /* Reduced from 140px */
    background: var(--border);
    gap: 1px;
}

.calendar-day {
    background: var(--card-bg);
    padding: 10px; /* Reduced from 15px */
    display: flex;
    flex-direction: column;
    gap: 5px; /* Reduced from 8px */
    transition: var(--transition);
    min-height: 100px; /* Reduced from 140px */
}

.calendar-day:hover { background: var(--bg-soft); }
.calendar-day.other-month { background: var(--bg-soft); opacity: 0.65; }

.day-number {
    font-size: 0.9rem;
    font-weight: 800;
    color: var(--text);
    margin-bottom: 10px;
}

.calendar-day.today { background: #fffbeb; }
.calendar-day.today .day-number { color: var(--accent); position: relative; }
.calendar-day.today .day-number::after {
    content: 'HOY';
    font-size: 0.5rem;
    background: var(--accent);
    color: white;
    padding: 2px 4px;
    margin-left: 8px;
    vertical-align: middle;
}

.calendar-events { display: flex; flex-direction: column; gap: 6px; }

.cal-event {
    appearance: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
    font-size: 0.7rem;
    padding: 6px 10px;
    border-radius: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    font-weight: 600;
    transition: all 0.2s;
    border: 1px solid transparent;
}

.cal-event:hover { transform: translateY(-1px); box-shadow: 0 4px 6px rgba(0,0,0,0.05); }

/* Status Colors - Refined */
.cal-event.confirmed { background: #dcfce7; color: #166534; border-color: #bbf7d0; }
.cal-event.pending,
.cal-event.pending_verification,
.cal-event.awaiting_payment { background: #fef9c3; color: #854d0e; border-color: #fef08a; }
.cal-event.manual,
.cal-event.manual_block { background: #eef2f6; color: #455a64; border-color: #d5dde3; }
.cal-event.cancelled { background: #fef2f2; color: #b42318; border-color: #fecaca; }
.cal-event.airbnb { background: #fee2e2; color: #991b1b; border-color: #fecaca; }
.cal-event.booking { background: #e0f2fe; color: #075985; border-color: #bae6fd; }
.cal-event:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Resumen del mes, encima de la rejilla. Es lo primero que se mira al
   cambiar de mes: cuantas reservas, cuantas noches y cuantos alojamientos. */
.calendar-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    padding: 10px 30px;
    font-size: 0.78rem;
    color: var(--text-muted);
    background: var(--bg-soft);
    border-bottom: 1px solid var(--border);
}

.calendar-summary strong {
    color: var(--text);
    font-weight: 800;
}

.calendar-summary__sep { opacity: 0.5; }

/* Colores por alojamiento, para distinguirlos cuando se ven todos a la vez.
   La raya izquierda del evento y el cuadrado de la leyenda comparten el
   mismo color, que es el unico vinculo visual entre ambos. */
.cal-event.cal-apt-0 { border-left: 3px solid #2563eb; }
.cal-event.cal-apt-1 { border-left: 3px solid #16a34a; }
.cal-event.cal-apt-2 { border-left: 3px solid #dc2626; }
.cal-event.cal-apt-3 { border-left: 3px solid #9333ea; }
.cal-event.cal-apt-4 { border-left: 3px solid #ea580c; }
.cal-event.cal-apt-5 { border-left: 3px solid #0891b2; }
.cal-event.cal-apt-6 { border-left: 3px solid #ca8a04; }
.cal-event.cal-apt-7 { border-left: 3px solid #db2777; }

.legend-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    border: 1px solid transparent;
}

.legend-swatch.cal-apt-0 { background: #2563eb; }
.legend-swatch.cal-apt-1 { background: #16a34a; }
.legend-swatch.cal-apt-2 { background: #dc2626; }
.legend-swatch.cal-apt-3 { background: #9333ea; }
.legend-swatch.cal-apt-4 { background: #ea580c; }
.legend-swatch.cal-apt-5 { background: #0891b2; }
.legend-swatch.cal-apt-6 { background: #ca8a04; }
.legend-swatch.cal-apt-7 { background: #db2777; }

/* Un dia sin reservas se ve mas claro, para que el mes se lea de un vistazo. */
.calendar-day.is-free { background: var(--card-bg); }
.calendar-day.has-events { background: var(--card-bg); }

.calendar-legend__group {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    width: 100%;
    padding-top: 6px;
    border-top: 1px dashed var(--border);
    margin-top: 4px;
}


.calendar-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 25px;
    padding: 10px 30px; /* Reduced from 20px */
    background: #f8fafc;
    border-top: 1px solid var(--border);
}

.legend-item { display: flex; align-items: center; gap: 8px; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; color: var(--text-muted); }
.legend-dot { width: 8px; height: 8px; border-radius: 50%; border: 1px solid transparent; }
.legend-dot.confirmed { background: #dcfce7; border-color: #bbf7d0; }
.legend-dot.pending { background: #fef9c3; border-color: #fef08a; }
.legend-dot.airbnb { background: #fee2e2; border-color: #fecaca; }
.legend-dot.booking { background: #e0f2fe; border-color: #bae6fd; }

/* ---------- BOOKING DETAILS GRID ---------- */
.booking-details-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 30px;
}

.detail-group label {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--accent);
    margin-bottom: 8px;
    display: block;
    font-weight: 800;
}

.detail-value {
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--primary-ink);
}
/* ==================== Utility classes (migrated from inline styles) ==================== */

/* Notifications */
.notification-wrapper { position: relative; margin-right: 15px; }
.user-identity { display: flex; flex-direction: column; line-height: 1.2; margin-right: .25rem; }
.user-identity__name { font-weight: 700; font-size: .8rem; color: var(--primary-ink); }
.user-identity__org { font-size: .68rem; color: var(--text-muted); max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notif-bell-btn { padding: 10px; border: none; font-size: 1.2rem; color: var(--primary-ink); }
.notif-badge {
  display: none;
  position: absolute;
  top: 0;
  right: 0;
  min-width: 1.1rem;
  background: #c0392b;
  color: #fff;
  font-size: 0.65rem;
  line-height: 1;
  padding: 3px 5px;
  border-radius: 10px;
  font-weight: 800;
  text-align: center;
}
.notif-badge:not([hidden]) { display: inline-flex; align-items: center; justify-content: center; }
/* El overlay se abria y cerraba con dropdown.style.display, un estilo inline. Ahora
   el estado es una clase, que se puede animar, se puede comprobar en un test y no
   depende de que el script llegue a ejecutarse. */
.notif-dropdown.is-open { display: block; }

.notif-bell-btn { position: relative; }

.notif-bell-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.notif-badge[hidden] { display: none; }

.notif-dropdown { display: none; position: absolute; top: 100%; right: 0; width: 320px; background: var(--card-bg); border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0,0,0,0.1); z-index: 2000; margin-top: 10px; }
.notif-dropdown-header { padding: 15px; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; background: var(--bg-soft); }
.notif-dropdown-header .notif-title { font-weight: 700; font-size: 0.8rem; text-transform: uppercase; }
.notif-dropdown-header .btn { padding: 4px 8px; font-size: 0.6rem; }
.notif-list { max-height: 400px; overflow-y: auto; }

/* Layout helpers */
.mb-20 { margin-bottom: 20px; }
.mb-25 { margin-bottom: 25px; }
.mb-30 { margin-bottom: 30px; }
.table-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: .65rem;
    margin-bottom: 1rem;
}
.table-toolbar { margin-bottom: 18px; }
.table-toolbar__field { flex: 1 1 12rem; min-width: 0; }
.table-toolbar__field .form-control { width: 100%; }
.table-toolbar .btn { flex: none; }
.log-detail { display: grid; gap: 1rem; }
.log-detail__message { white-space: pre-wrap; overflow-wrap: anywhere; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .82rem; background: var(--bg-soft); border: 1px solid var(--border); padding: .8rem; border-radius: 6px; max-height: 45vh; overflow: auto; }
.charts-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 25px; }
.chart-box { height: 280px; padding: 20px; }
.chart-state { display: none; height: 100%; align-items: center; justify-content: center; }
.card-title__period { color: var(--text-muted); font-size: .72rem; font-weight: 500; letter-spacing: 0; text-transform: none; }
.chart-state.is-active { display: flex; }
.edit-apt-head { margin-bottom: 25px; display: flex; align-items: center; gap: 15px; }
.edit-apt-head h3 { margin: 0; font-family: 'Playfair Display', serif; }

/* Appearance section */
.appearance-shell { padding: 0; overflow: hidden; border-radius: 12px; }
.appearance-bare { padding: 0; border: none; background: none; box-shadow: none; }
.appearance-grid {
    display: grid;
    /* El formulario sube de 420px a 480px: sus filas de dos y tres campos se
       estaban quedando a ~110px por campo, y a ese ancho los <select> recortan
       su etiqueta. La vista previa se queda con el resto, que sigue siendo la
       parte mayor. */
    grid-template-columns: minmax(360px, 480px) 1fr;
    /* height: calc(100vh - 180px) + min-height: 600px se combinaban mal: en un
       portatil de 700px de alto la altura salia 520px pero el minimo la subia a
       600, y con la cabecera ya no cabia — la pagina aparecia con scroll en una
       seccion que deberia caber entera. Un minimo de 440px mantiene la vista
       previa usable sin imponer scroll en pantallas bajas. */
    min-height: 440px;
}

/* Los tres fondos iban en blanco fijo (#fff y #f1f5f9). En modo oscuro las
   tarjetas pasan a #1A2026 y estos tres se quedaban como una losa blanca
   incrustada en la pagina. Los tokens ya dan el valor correcto en ambos temas. */
.appearance-form-side {
    padding: 30px;
    border-right: 1px solid var(--border);
    overflow-y: auto;
    background: var(--card-bg);
}
.appearance-form-side .card-title { margin-bottom: 25px; }

/* Cabecera del formulario: titulo a la izquierda y el boton de
   cambiar la imagen principal a la derecha. */
.appearance-form-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 25px;
}
.appearance-form-header .card-title { margin-bottom: 0; }
.appearance-hero-picker-trigger { flex-shrink: 0; }
.appearance-loading { text-align: center; padding: 50px; }
/* --bg en vez de #f1f5f9 fijo: en claro es casi el mismo tono (#f4f7f6) y en
   oscuro pasa a #12161A, que es lo que evita la losa clara. */
.appearance-preview-side { background: var(--bg); position: relative; display: flex; flex-direction: column; }

/* La barra se queda pegada abajo dentro del formulario, que scrollea por dentro:
   asi el boton de guardar esta siempre a la vista sin tapar la vista previa. */
.appearance-savebar {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 30px;
    background: var(--card-bg);
    border-top: 1px solid var(--border);
}

.appearance-savebar__status {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 0.78rem;
    color: var(--text-muted);
}

.appearance-savebar__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #10b981;
    flex: none;
}

/* Sin guardar cambia el punto a ambar y el texto a la tinta principal: la
   diferencia no puede depender solo del color. */
.appearance-savebar.is-dirty .appearance-savebar__dot { background: #f59e0b; }
.appearance-savebar.is-dirty .appearance-savebar__status { color: var(--text); font-weight: 600; }
/* Site texts */
.texts-shell { padding: 0; overflow: hidden; border-radius: 12px; }
.texts-heading {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    padding: 28px 30px;
    border-bottom: 1px solid var(--border);
}
.texts-heading .card-title { margin: 0 0 6px; }
.texts-heading__help { margin: 0; max-width: 720px; color: var(--text-muted); font-size: 0.86rem; line-height: 1.55; }
.texts-heading .btn { flex: none; }
.texts-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 18px 30px;
    border-bottom: 1px solid var(--border);
    background: var(--card-bg);
}
.texts-lang-tabs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.texts-lang-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg);
    color: var(--text-muted);
    padding: 8px 12px;
    cursor: pointer;
    transition: var(--transition);
}
.texts-lang-tab:hover { border-color: var(--accent); color: var(--primary-ink); }
.texts-lang-tab.is-active { background: var(--primary-ink); border-color: var(--primary-ink); color: #fff; }
.texts-lang-tab__code { font-size: 0.68rem; font-weight: 800; letter-spacing: 0.08em; }
.texts-lang-tab__name { font-size: 0.76rem; }
.texts-lang-tab__count {
    min-width: 20px;
    height: 20px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 6px;
    background: rgba(148, 163, 184, 0.18);
    font-size: 0.66rem;
    font-weight: 800;
}
.texts-lang-tab.is-active .texts-lang-tab__count { background: rgba(255, 255, 255, 0.2); }
.texts-search { position: relative; display: flex; align-items: center; }
.texts-search i { position: absolute; left: 13px; color: var(--text-muted); pointer-events: none; }
.texts-search input {
    min-width: 280px;
    padding: 10px 14px 10px 36px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--bg);
    color: var(--text);
    font: inherit;
    font-size: 0.82rem;
}
.texts-search input:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: transparent; }
.texts-status-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 30px;
    color: var(--text-muted);
    font-size: 0.75rem;
}
.texts-status, .texts-status__count { margin: 0; }
.texts-status__count strong { color: var(--primary-ink); }
.texts-list { padding: 4px 30px 30px; }
.texts-group {
    margin-top: 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card-bg);
    overflow: hidden;
}
.texts-group__summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 16px 18px;
    cursor: pointer;
    list-style: none;
}
.texts-group__summary::-webkit-details-marker { display: none; }
.texts-group__summary:hover { background: var(--bg); }
.texts-group__title { display: inline-flex; align-items: center; gap: 9px; font-weight: 700; color: var(--primary-ink); }
.texts-group__title i { color: var(--accent); }
.texts-group__count { color: var(--text-muted); font-size: 0.7rem; white-space: nowrap; }
.texts-group__help { margin: 0; padding: 0 18px 14px; color: var(--text-muted); font-size: 0.78rem; line-height: 1.5; }
.texts-group[open] .texts-group__summary { border-bottom: 1px solid var(--border); }
.texts-fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 14px;
    padding: 16px 18px 18px;
}
.texts-field { border: 1px solid var(--border); border-radius: 9px; padding: 13px; background: var(--bg); min-width: 0; }
.texts-field__head { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-bottom: 8px; }
.texts-field__label { flex: 1 1 100%; color: var(--primary-ink); font-size: 0.75rem; font-weight: 700; line-height: 1.35; }
.texts-field__key {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.62rem;
    padding: 2px 6px;
    border-radius: 4px;
    background: rgba(148, 163, 184, 0.12);
}
.texts-field__custom {
    color: #0f766e;
    background: rgba(16, 185, 129, 0.14);
    border-radius: 999px;
    padding: 2px 7px;
    font-size: 0.6rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.texts-field__reset {
    margin-left: auto;
    border: 0;
    background: none;
    color: var(--accent);
    font: inherit;
    font-size: 0.68rem;
    font-weight: 700;
    cursor: pointer;
    padding: 2px 0;
}
.texts-field__reset:disabled { color: var(--text-muted); opacity: 0.45; cursor: default; }
.texts-field__input { font-size: 0.82rem; min-height: 38px; }
textarea.texts-field__input { resize: vertical; line-height: 1.45; }
.texts-field__help, .texts-field__default { margin: 7px 0 0; font-size: 0.68rem; line-height: 1.45; color: var(--text-muted); }
.texts-field__default span { font-weight: 700; color: var(--primary-ink); }
.texts-savebar {
    position: sticky;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 14px 30px;
    background: var(--card-bg);
    border-top: 1px solid var(--border);
}
.texts-savebar__status { display: flex; align-items: center; gap: 9px; color: var(--text-muted); font-size: 0.76rem; }
.texts-savebar__dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; flex: none; }
.texts-savebar.is-dirty .texts-savebar__dot { background: #f59e0b; }
.texts-savebar.is-dirty .texts-savebar__status { color: var(--text); font-weight: 600; }
.texts-loading, .texts-error { text-align: center; padding: 60px 30px; color: var(--text-muted); }
.texts-loading p, .texts-error p { margin: 14px 0; }
.texts-error i { font-size: 2rem; color: var(--accent); }
.texts-empty { text-align: center; padding: 30px; color: var(--text-muted); }
.appearance-preview-bar { background: #1e293b; color: white; padding: 12px 25px; font-size: 0.75rem; font-weight: 700; display: flex; justify-content: space-between; align-items: center; letter-spacing: 1px; }
.appearance-preview-bar .eye-icon { color: #818cf8; margin-right: 8px; }
.appearance-preview-actions { display: flex; gap: 12px; }
.appearance-preview-refresh { color: white; border-color: rgba(255,255,255,0.2); padding: 4px 10px; font-size: 0.7rem; }
.appearance-preview-stage {
    flex: 1;
    position: relative;
    padding: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow: auto;
}

/* El grupo (marco + linea de medidas) se centra solo en horizontal y se
   alinea arriba. La columna crece con el formulario, que es mucho mas alto
   que la vista previa: centrarlo tambien en vertical dejaba el iframe a
   media columna, por debajo del pliegue. Con overflow:auto y un contenido
   mas alto que el stage, el scroll arranca por arriba y no deja el marco
   desplazado hacia abajo. */
.appearance-device-group {
    margin: 0 auto;
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

/* El envoltorio mide lo ya escalado y el marco el ancho real del dispositivo.
   Es lo que mantiene el marco centrado: escalar solo el marco descentraria
   el centro y ademas dejaria hueco a un lado. El factor lo calcula el JS
   midiendo el hueco disponible, porque uno fijo desborda en pantallas
   pequenas y deja la vista previa ilegible en las grandes. */
.appearance-device-wrap {
    flex: none;
    position: relative;
}

.appearance-device {
    transform-origin: top left;
    background: var(--card-bg);
    overflow: hidden;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
    border: 1px solid var(--border);
}

/* Las medidas son las de verdad de cada dispositivo: es el ancho del iframe lo
   que hace que la web se maquete en ese breakpoint y no en el que le toque. */
.appearance-device[data-device="desktop"] { width: 1280px; height: 800px; border-radius: 6px; }
.appearance-device[data-device="tablet"] { width: 768px; height: 1024px; border-radius: 10px; }
.appearance-device[data-device="mobile"] { width: 390px; height: 844px; border-radius: 16px; }

/* Movil y tablet llevan marco: sin el, una pantalla de 390px dentro de un panel
   no se distingue de una ventana pequena. */
.appearance-device[data-device="mobile"],
.appearance-device[data-device="tablet"] { border: 6px solid var(--dark); }

.appearance-preview-frame { width: 100%; height: 100%; background: var(--card-bg); overflow: hidden; }
.appearance-preview-frame iframe { width: 100%; height: 100%; border: none; display: block; }

.appearance-devices { display: flex; gap: 4px; }

.appearance-device-btn {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.4px;
    padding: 5px 10px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 4px;
    background: transparent;
    color: rgba(255, 255, 255, 0.72);
    cursor: pointer;
    transition: background 0.2s, color 0.2s;
}

.appearance-device-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.1); }
.appearance-device-btn.is-on { background: #fff; border-color: #fff; color: #1e293b; }
.appearance-device-btn:focus-visible { outline: 2px solid #818cf8; outline-offset: 1px; }

.appearance-device-size {
    margin: 0;
    font-size: 0.68rem;
    letter-spacing: 0.6px;
    color: var(--text-muted);
}

/* --- Selector global de imagen hero (modal) -------------------------
   Reutiliza .modal / .modal-content / .modal-header / .modal-footer y
   el grid .tpl-grid con .tpl del selector de plantillas. Los colores
   usan las variables del tema, asi que el modal oscuro los hereda. */
.hero-image-picker-modal {
    max-width: 920px;
    width: 95%;
    max-height: 85vh;
    padding: 24px;
    display: flex;
    flex-direction: column;
}

.hero-image-picker-modal .modal-header {
    margin-bottom: 16px;
    padding-bottom: 14px;
}

.hero-image-picker-modal .modal-header h3 {
    font-size: 1.3rem;
}

.hero-image-picker-modal .modal-body {
    overflow-y: auto;
    flex: 1;
    min-height: 0;
}

.hero-image-picker-search input {
    width: 100%;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.875rem;
    background: var(--card-bg);
    color: var(--text);
}
.hero-image-picker-search input:focus {
    outline: none;
    border-color: var(--accent);
}

.hero-image-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 12px;
}

/* El grid vive dentro del modal: las .tpl del selector de plantillas
   pintan fondo blanco fijo, y aqui el fondo y el borde los pone el
   tema. */
.hero-image-picker-grid .tpl {
    background: var(--card-bg);
    border-color: var(--border);
    position: relative;
}
.hero-image-picker-grid .tpl:hover {
    border-color: var(--accent);
}
.hero-image-picker-grid .tpl.is-on {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
.hero-image-picker-grid .tpl:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.hero-image-picker-grid .tpl__img {
    aspect-ratio: 16 / 9;
}
.hero-image-picker-grid .tpl__label {
    font-size: .78rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hero-image-picker-group { margin-bottom: 20px; }
.hero-image-picker-group-title {
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    margin: 0 0 8px;
}

.hero-image-picker-empty {
    grid-column: 1 / -1;
    text-align: center;
    padding: 40px 20px;
    color: var(--text-muted);
    font-size: .875rem;
}

/* El aviso de carga y el de error ocupan toda la fila del grid. */
.hero-image-picker-loading { grid-column: 1 / -1; }

.hero-image-picker-modal .modal-footer {
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 16px;
}

/* Marca la foto principal actual de cada apartamento. */
.tpl__hero-badge {
    position: absolute;
    top: 6px;
    left: 6px;
    background: var(--accent);
    color: #fff;
    font-size: .55rem;
    font-weight: 700;
    padding: 2px 6px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    z-index: 1;
}


/* Modals (notification + confirm) */
.modal-box { max-width: 400px; text-align: center; padding: 40px; border-radius: 16px; position: relative; }
.modal-box .btn-close { position: absolute; top: 15px; right: 15px; width: 30px; height: 30px; }
.modal-box .btn-primary { width: 100%; margin-top: 20px; }
.confirm-icon { font-size: 3rem; color: #f59e0b; margin-bottom: 20px; }
.confirm-title { margin-bottom: 15px; font-family: 'Playfair Display', serif; color: #1e293b; }
.confirm-message { color: #64748b; margin-bottom: 25px; line-height: 1.6; }
.confirm-actions { display: flex; gap: 10px; justify-content: center; }
.confirm-actions .btn { flex: 1; padding: 12px; border-radius: 8px; }
.confirm-actions .btn-danger { background: #ef4444; color: white; border: none; font-weight: 600; }


/* Notification modal themes (set via data-notif-theme) */
.modal-content[data-notif-theme] { max-width: 400px; text-align: center; padding: 40px; border-radius: 16px; position: relative; }
.modal-content[data-notif-theme="error"] { background: #fef2f2; border: 1px solid #ef444433; }
.modal-content[data-notif-theme="success"] { background: #f0fdf4; border: 1px solid #10b98133; }
.modal-content[data-notif-theme="info"] { background: #eff6ff; border: 1px solid #6366f133; }
.modal-content[data-notif-theme] #notificationIcon i { font-size: 4rem; display: block; margin-bottom: 20px; }
.modal-content[data-notif-theme="error"] #notificationIcon i { color: #ef4444; }
.modal-content[data-notif-theme="success"] #notificationIcon i { color: #10b981; }
.modal-content[data-notif-theme="info"] #notificationIcon i { color: #6366f1; }
.modal-content[data-notif-theme] #notificationTitle { color: #1e293b; font-weight: 800; font-size: 1.25rem; }
.modal-content[data-notif-theme] #notificationMessage { color: #64748b; margin-top: 10px; line-height: 1.6; }

/* ---------- DASHBOARD INVENTORY ---------- */
.org-badge {
    font-size: 0.6rem;
    color: var(--accent);
    font-weight: 800;
    text-transform: uppercase;
    margin-top: 4px;
}

.btn-group {
    display: flex;
    gap: 5px;
}

.edit-tabs-container {
    padding: 0;
    overflow: hidden;
}

.edit-tabs-container .tab-link {
    background: none;
    border: none;
    padding: 20px 5px;
    cursor: pointer;
    font-weight: 700;
    color: #94a3b8;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    position: relative;
    transition: 0.2s;
}

.edit-tabs-container .tab-link:hover {
    color: var(--primary-ink);
}

.edit-tabs-container .tab-link.active {
    color: var(--accent);
}

.edit-tabs-container .tab-link.active::after {
    content: '';
    position: absolute;
    bottom: -1px;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--accent);
}

.lang-tabs-container {
    margin-bottom: 25px;
}

.lang-tabs-header {
    display: flex;
    border-bottom: 1px solid #e2e8f0;
    gap: 15px;
}

.lang-tab-link {
    background: none;
    border: none;
    padding: 10px 15px;
    cursor: pointer;
    font-weight: 600;
    color: #94a3b8;
    font-size: 0.8rem;
    display: flex;
    align-items: center;
    gap: 8px;
    border-radius: 6px;
    transition: 0.2s;
    border: 1px solid transparent;
}

.lang-tab-link img {
    width: 18px;
}

.lang-tab-link:hover {
    background: #f1f5f9;
}

.lang-tab-link.active {
    background: white;
    color: var(--primary-ink);
    border-color: #e2e8f0;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.edit-form {
    padding: 40px;
}

.edit-grid-2 {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 40px;
}

.edit-grid-4 {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 20px;
    margin-top: 25px;
}

.form-row-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-top: 25px;
}

.image-upload-card {
    background: #f8fafc;
    padding: 20px;
    border-radius: 12px;
    border: 1px solid #e2e8f0;
    text-align: center;
}

.image-upload-card img {
    width: 100%;
    aspect-ratio: 4/3;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid #cbd5e1;
    margin-bottom: 15px;
}

.upload-label {
    width: 100%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.upload-input {
    display: none;
}

.info-box {
    padding: 15px;
    border-radius: 8px;
    margin-bottom: 25px;
    font-size: 0.8rem;
    border: 1px solid;
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.info-box i {
    margin-top: 2px;
}

.info-box.info {
    background: #f1f5f9;
    color: #475569;
    border-color: #e2e8f0;
}

.info-box.features {
    background: #fdfcf0;
    color: #854d0e;
    border-color: #fef08a;
}

.info-box.prices {
    background: #f0fdf4;
    color: #166534;
    border-color: #bbf7d0;
}

.info-box.availability {
    background: #fff7ed;
    color: #9a3412;
    border-color: #ffedd5;
}

.info-box.sync {
    background: #eff6ff;
    color: #1e40af;
    border-color: #bfdbfe;
}

.features-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
}

.feature-card {
    display: flex;
    align-items: center;
    gap: 12px;
    background: #f8fafc;
    padding: 15px;
    border-radius: 8px;
    border: 1px solid #e2e8f0;
    cursor: pointer;
}

.feature-card .feature-icon {
    color: var(--accent);
    font-size: 1.1rem;
    width: 25px;
    text-align: center;
}

.feature-card .feature-label {
    font-size: 0.85rem;
    font-weight: 600;
}

.feature-card input[type="checkbox"] {
    width: auto;
}

.price-card {
    background: white;
    padding: 12px 15px;
    border-radius: 8px;
    border: 1px solid #e2e8f0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-shadow: 0 1px 3px rgba(0,0,0,0.02);
}

.price-card-actions {
    display: flex;
    align-items: center;
    gap: 15px;
}

.price-value {
    font-weight: 800;
    color: var(--accent);
    font-size: 1.1rem;
}

.block-card {
    background: white;
    padding: 12px 15px;
    border-radius: 8px;
    border: 1px solid #fee2e2;
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-shadow: 0 1px 3px rgba(0,0,0,0.02);
}

.block-title {
    font-size: 0.8rem;
    font-weight: 700;
    color: #991b1b;
}

.block-dates {
    font-size: 0.7rem;
    color: #64748b;
}

.gallery-manager-v2 {
    padding: 0;
}

.gallery-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 25px;
}

.gallery-description {
    color: #64748b;
    font-size: 0.9rem;
    margin: 0;
}

.gallery-description strong {
    color: var(--text);
}

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 15px;
    min-height: 200px;
}

.gallery-card {
    position: relative;
    background: white;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
    border: 1px solid #e2e8f0;
    transition: all 0.2s;
}

.gallery-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.gallery-card-image {
    position: relative;
    aspect-ratio: 4/3;
    overflow: hidden;
}

.gallery-card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.gallery-card-badge {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(16,185,129,0.9);
    color: white;
    font-size: 0.6rem;
    text-align: center;
    padding: 4px;
    font-weight: 800;
    letter-spacing: 1px;
}

.gallery-card-actions {
    display: flex;
    justify-content: center;
    gap: 8px;
    padding: 8px;
    background: #f8fafc;
}

.btn-icon {
    background: white;
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    /* 28px was well under the 44px a thumb needs, and the gallery buttons are
       the only way to reorder on a phone, where HTML5 drag never fires. */
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #64748b;
    cursor: pointer;
    transition: 0.2s;
}

.btn-icon:hover:not(:disabled) {
    color: var(--accent);
    border-color: var(--accent);
}

.btn-icon.delete:hover:not(:disabled) {
    color: #ef4444;
    border-color: #ef4444;
}

.btn-icon.star:hover:not(:disabled) {
    color: #f59e0b;
    border-color: #f59e0b;
}

.btn-icon:disabled {
    opacity: 0.2;
    cursor: not-allowed;
}

/* --- Gallery: drag to reorder, describe each photo, upload progress --- */

.gallery-card {
    cursor: grab;
}

.gallery-card.is-dragging {
    opacity: 0.4;
    cursor: grabbing;
}

.gallery-card.is-over {
    outline: 2px dashed var(--accent);
    outline-offset: 2px;
}

/* Held while the new order is in flight, so the grid cannot be re-dragged
   halfway through a save and end up showing an order that was never stored. */
.gallery-grid.is-saving {
    opacity: 0.7;
    pointer-events: none;
}

.gallery-grip {
    position: absolute;
    top: 6px;
    left: 6px;
    background: rgba(15, 23, 42, 0.55);
    color: #fff;
    border-radius: 4px;
    padding: 4px 6px;
    font-size: 0.8rem;
    opacity: 0;
    transition: opacity 0.2s;
    pointer-events: none;
}

.gallery-card:hover .gallery-grip,
.gallery-card:focus-within .gallery-grip {
    opacity: 1;
}

.gallery-card-fields {
    padding: 8px 8px 0;
    background: #f8fafc;
}

.gallery-alt-label {
    display: block;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #94a3b8;
    margin-bottom: 4px;
}

.gallery-alt {
    width: 100%;
    border: 1px solid #e2e8f0;
    border-radius: 4px;
    padding: 8px;
    font-size: 0.78rem;
    color: var(--text);
    background: #fff;
}

.gallery-alt:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.gallery-progress {
    margin: 0 0 16px;
}

.gallery-progress-bar {
    height: 6px;
    background: #e2e8f0;
    border-radius: 999px;
    overflow: hidden;
}

.gallery-progress-fill {
    height: 100%;
    width: 0%;
    background: var(--accent);
    border-radius: 999px;
    transition: width 0.15s linear;
}

.gallery-progress-text {
    margin: 6px 0 0;
    font-size: 0.75rem;
    color: #64748b;
    overflow-wrap: anywhere;
}

/* --- Gallery tab inside the property editor --- */

.gallery-open-manager {
    margin-top: 12px;
    width: 100%;
    justify-content: center;
}

.gallery-picker-foot {
    margin-top: 12px;
}

.gallery-strip-head {
    margin: 22px 0 10px;
}

.gallery-strip {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 12px;
}

.gallery-strip-item {
    position: relative;
    margin: 0;
    aspect-ratio: 4/3;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid #e2e8f0;
    background: #f8fafc;
}

.gallery-strip-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.gallery-strip-item.is-cover {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent);
}

.gallery-strip-badge {
    position: absolute;
    inset: auto 0 0 0;
    background: rgba(16, 185, 129, 0.92);
    color: #fff;
    font-size: 0.6rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: center;
    padding: 3px;
}

.gallery-strip-del {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 50%;
    background: rgba(15, 23, 42, 0.6);
    color: #fff;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.2s, background 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
}

.gallery-strip-item:hover .gallery-strip-del,
.gallery-strip-del:focus-visible {
    opacity: 1;
}

.gallery-strip-del:hover {
    background: #ef4444;
}

/* On touch there is no hover, so the control stays visible rather than being
   unreachable. */
@media (hover: none) {
    .gallery-strip-del {
        opacity: 1;
    }
}

.gallery-strip-item.is-missing img {
    opacity: 0.25;
    filter: grayscale(1);
}

.gallery-strip-gone {
    position: absolute;
    inset: auto 0 0 0;
    background: rgba(190, 18, 60, 0.92);
    color: #fff;
    font-size: 0.58rem;
    font-weight: 700;
    text-align: center;
    padding: 3px;
}

/* A cover that failed to load. The preview itself falls back to the neutral
   placeholder, so this only frames it and makes the way out obvious. */
.image-upload-card.is-broken {
    border-color: #f43f5e;
    box-shadow: 0 0 0 2px rgba(244, 63, 94, 0.25);
}

.cover-remove {
    margin-top: 8px;
}

.cover-warning {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 10px 0 0;
    padding: 10px 12px;
    border-radius: 8px;
    background: #fff1f2;
    border: 1px solid #fecdd3;
    color: #9f1239;
    font-size: 0.82rem;
    line-height: 1.45;
}

.cover-warning i {
    margin-top: 2px;
    flex-shrink: 0;
}

.upload-label.is-busy,
.gallery-manager-label.is-busy {
    opacity: 0.75;
    pointer-events: none;
    cursor: progress;
}

.cover-warning[hidden] {
    display: none;
}

/* --- Secciones: repeatable content blocks --- */

.section-tabs .tab-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.section-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: #e2e8f0;
    color: #64748b;
    font-size: 0.65rem;
    font-weight: 800;
}

.section-count:empty {
    display: none;
}

.section-block {
    display: none;
}

.section-block.active {
    display: block;
}

.section-block-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin: 18px 0 14px;
}

.section-block-title {
    margin: 0;
    font-size: 0.95rem;
}

.section-block-help {
    margin: 4px 0 0;
    font-size: 0.78rem;
    color: #94a3b8;
}

.section-rows {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.section-empty {
    padding: 22px;
    border: 1px dashed #cbd5e1;
    border-radius: 10px;
    color: #94a3b8;
    font-size: 0.85rem;
    text-align: center;
}

.section-row {
    border: 1px solid #e2e8f0;
    border-radius: 10px;
    overflow: hidden;
}

.section-row-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    background: #f8fafc;
    border-bottom: 1px solid #e2e8f0;
}

.section-row-title {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: #e2e8f0;
    color: #475569;
    font-size: 0.75rem;
    font-weight: 800;
}

.section-row-tools {
    display: flex;
    gap: 6px;
}

.section-row-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
    padding: 14px 12px;
}

.section-field--wide {
    grid-column: 1 / -1;
}

/* The three languages of one field sit side by side so a translator can see the
   whole item at once instead of flipping between language tabs per field. */
.section-i18n {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}

.section-i18n-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.section-i18n-label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.62rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    color: #94a3b8;
}

.section-i18n-label img {
    width: 14px;
    height: auto;
}

.section-hint {
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    color: #cbd5e1;
}

.section-input {
    font-size: 0.82rem;
}

/* Los textos legales. Cada documento es una ficha con sus tres idiomas al
   lado, porque un texto legal se traduce entero y no campo a campo: quien
   traduce necesita ver el documento completo, no un par de lineas sueltas. */
.legal-documents {
    display: flex;
    flex-direction: column;
    gap: 22px;
}

.legal-doc {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 22px;
    background: var(--card-bg);
}

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

.legal-doc__title {
    margin: 0;
    font-size: 0.95rem;
    color: var(--primary-ink);
}

/* El estado no se distingue solo por el color: el texto dice si hay cambios
   sin guardar, y el punto de color refuerza la diferencia. */
.legal-doc__state {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

.legal-doc__state::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #10b981;
    flex: none;
}

.legal-doc__state.is-new::before { background: #94a3b8; }
.legal-doc__state.is-dirty { color: #b45309; }
.legal-doc__state.is-dirty::before { background: #f59e0b; }

.legal-doc__help {
    margin: 0 0 16px;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.legal-doc__help code,
.legal-doc__note code {
    background: rgba(148, 163, 184, 0.16);
    padding: 1px 5px;
    border-radius: 4px;
    font-size: 0.9em;
}

.legal-textarea {
    font-size: 0.8rem;
    line-height: 1.55;
    min-height: 220px;
    resize: vertical;
}

.legal-doc__actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 16px;
}

.legal-doc__note {
    margin: 16px 0 0;
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* El bloque de los datos del responsable va primero: es lo que rellena los
   huecos de los textos, y un texto con los huecos sin rellenar se lee como
   un texto sin terminar. */
.legal-doc--responsible {
    border-color: var(--accent);
}

.legal-field__hint {
    margin: 4px 0 0;
    font-size: 0.68rem;
    color: var(--text-muted);
}

.form-group--wide {
    grid-column: 1 / -1;
}

.section-months {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(62px, 1fr));
    gap: 6px;
}

.section-month {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 7px 4px;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    font-size: 0.75rem;
    cursor: pointer;
    user-select: none;
}

.section-month:has(input:checked) {
    border-color: var(--accent);
    background: rgba(16, 185, 129, 0.08);
    color: var(--accent);
    font-weight: 700;
}

@media (max-width: 720px) {
    .section-i18n {
        grid-template-columns: 1fr;
    }
}

.sync-card {
    padding: 25px;
    border-radius: 12px;
    border: 1px solid;
}

.sync-card.import {
    background: #eff6ff;
    border-color: #bfdbfe;
}

.sync-card.export {
    background: #f8fafc;
    border-color: #e2e8f0;
}

.sync-card h4 {
    font-size: 0.8rem;
    text-transform: uppercase;
    margin-bottom: 20px;
    color: #1e40af;
    display: flex;
    align-items: center;
    gap: 8px;
}

.export-field {
    background: #fff;
    font-size: 0.7rem;
    font-family: monospace;
}

.save-bar {
    text-align: right;
    margin-top: 50px;
    padding-top: 30px;
    border-top: 1px solid #eee;
}

.save-btn {
    padding: 15px 50px;
    font-weight: 800;
    letter-spacing: 1px;
}

.empty-state {
    font-size: 0.8rem;
    color: #94a3b8;
    text-align: center;
    padding: 20px;
    border: 1px dashed #e2e8f0;
    border-radius: 8px;
}

.tab-content-item.hidden {
    display: none;
}

.mb-15 {
    margin-top: 15px;
}

.mb-20 {
    margin-top: 20px;
}

.btn-icon-sm {
    padding: 5px 8px;
    font-size: 0.6rem;
}

.spinner {
    color: var(--accent);
}

.gallery-empty {
    grid-column: 1/-1;
    text-align: center;
    padding: 40px;
    background: #f8fafc;
    border: 2px dashed #e2e8f0;
    border-radius: 12px;
    color: #94a3b8;
}

.gallery-empty-icon {
    display: block;
    margin-bottom: 15px;
    opacity: 0.5;
}

.gallery-manager-label {
    margin: 0;
    cursor: pointer;
}

.sync-description {
    font-size: 0.75rem;
    color: #64748b;
    margin-bottom: 15px;
}

.price-label {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--primary-ink);
}

.price-dates {
    font-size: 0.7rem;
    color: #64748b;
}

.gallery-spinner {
    grid-column: 1/-1;
    text-align: center;
    padding: 50px;
}

.gallery-picker {
    margin-top: 20px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}

.gallery-picker-title {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: var(--text-muted);
    font-weight: 700;
    margin-bottom: 12px;
}

.gallery-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
    gap: 10px;
}

.gallery-picker-item {
    aspect-ratio: 1;
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid var(--border);
    cursor: pointer;
    transition: var(--transition);
    position: relative;
}

.gallery-picker-item:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.gallery-picker-item.selected {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(166, 124, 82, 0.2);
}

.gallery-picker-item img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ==========================================================================
   RESPONSIVE AND ACCESSIBILITY PASS
   --------------------------------------------------------------------------
   Everything above predates the audit. The problems were not "it does not
   respond at all" but a handful of layouts that were declared once and never
   revisited, plus two accessibility gaps that the 1024px breakpoint introduced
   rather than fixed.
   ========================================================================== */

/* --- Overflow containment -------------------------------------------------
   A grid or flex child defaults to min-width:auto, so a single long string (an
   email, a slug, a URL in a table cell) refuses to shrink below its content
   and pushes the whole page wider than the viewport. Declaring min-width:0 on
   the children is what actually makes the tables scroll inside their container
   instead of dragging the layout sideways. */
.table-container > table,
.edit-grid-2 > *,
.edit-grid-4 > *,
.form-row-2 > *,
.stats-grid > *,
.appearance-grid > * {
    min-width: 0;
}

/* Long unbroken values inside cells: emails, custom domains, image paths. */
.table-container td,
.table-container th {
    overflow-wrap: anywhere;
}

/* --- Gestion de Propiedades: la fila se reconoce de un vistazo --- */

.col-photo { width: 1%; white-space: nowrap; }
.col-num { text-align: right; white-space: nowrap; }

.apt-photo-cell { padding-right: 0; }

.apt-thumb {
    display: block;
    width: 56px;
    height: 56px;
    object-fit: cover;
    background: var(--bg-soft, #f8fafc);
    border: 1px solid var(--border);
}

/* El tipo y la organizacion estaban cada uno en su propia linea bajo el nombre,
   asi que la fila medía tres lineas para decir dos cosas. */
.apt-sub {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 2px;
    font-size: 0.75rem;
    color: var(--text-muted);
}

td.num {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Keep the row label visible while the rest of a wide table scrolls. */


/* --- Grids that never collapsed -------------------------------------------
   .edit-grid-2, .edit-grid-4, .form-row-2 and .features-grid were declared
   with a fixed column count and had no breakpoint, so a phone got four
   columns of form fields 90px wide. */


/* ---------------------------------------------------------------------------
   Bandeja de mensajes.

   El mensaje entero ocupa media pantalla y empuja la tabla: se recorta a cuatro
   lineas y el texto sigue entero en el DOM, que es lo que se copia al
   seleccionar.
   --------------------------------------------------------------------------- */

.msg-text {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0 0 .35rem;
    max-width: 48ch;
}

.sub-block {
    display: block;
    margin-top: .15rem;
    font-size: .75rem;
    color: var(--text-muted);
}

.msg-reply {
    font-size: .78rem;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

.msg-reply:hover { color: var(--accent); }

/* ---------------------------------------------------------------------------
   Atajos de teclado.

   El boton esta en la barra de arriba al lado de las notificaciones: un atajo que
   solo existe si alguien lo lee no es un atajo, es un secreto. La lista la pinta
   el script leyendo los grupos del menu, asi que no puede describir atajos que no
   existan.
   --------------------------------------------------------------------------- */

.shortcuts-btn { flex: none; }

.shortcuts {
  position: fixed;
  inset: 0;
  z-index: 220;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(20, 24, 21, .5);
}

.shortcuts.is-open { display: flex; }

.shortcuts__panel {
  width: min(28rem, 100%);
  max-height: 80vh;
  overflow-y: auto;
  background: var(--card-bg, #fff);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .45);
}

.shortcuts__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
}

.shortcuts__title {
  margin: 0;
  font-size: 1.05rem;
}

.shortcuts__list { padding: .5rem .75rem; }

.shortcuts__row {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: .5rem .5rem;
}

/* El kbd tiene que tener tamano de tecla: un <span> con borde parece una etiqueta
   y no una tecla, y no dice pulsable. */
.shortcuts__row kbd {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.9rem;
  min-height: 1.9rem;
  padding: 0 .45rem;
  background: var(--bg, #f6f5f2);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 5px;
  font-family: inherit;
  font-size: .82rem;
  font-weight: 600;
  color: var(--ink, #2c332c);
}

.shortcuts__foot {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem .75rem;
  margin: 0;
  padding: .85rem 1.25rem;
  border-top: 1px solid var(--border);
  font-size: .78rem;
  color: var(--text-muted);
}

.shortcuts__count { font-weight: 600; }

/* --- Inline column definitions --------------------------------------------
   The appearance, coupon and booking forms set grid-template-columns through
   style attributes, which a media query cannot reach without !important. Those
   declarations moved to classes so the breakpoints below apply to them. */
.form-row {
    display: grid;
    gap: 15px;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

/* The address block: street takes the room, locality and region split the rest.
   auto-fit already collapses it, the explicit ratios just set the proportions. */
.form-row-address { grid-template-columns: 2fr 1fr 1fr; }
.form-row-triple { grid-template-columns: repeat(3, 1fr); }
.form-row-wide { gap: 20px; }

.stats-grid-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 900px) {
    .form-row-address,
    .form-row-triple,
    .stats-grid-3 { grid-template-columns: 1fr 1fr; }
    .texts-heading, .texts-toolbar, .texts-status-row, .texts-savebar { flex-direction: column; align-items: stretch; }
    .texts-heading, .texts-toolbar, .texts-status-row, .texts-list, .texts-savebar { padding-left: 18px; padding-right: 18px; }
    .texts-search input { min-width: 0; width: 100%; }
    .texts-fields { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
    .form-row-address,
    .form-row-triple,
    .form-row-wide,
    .stats-grid-3 { grid-template-columns: 1fr; }
}

/* --- Touch targets --------------------------------------------------------
   32px is below the 44px minimum. It only matters where a coarse pointer is
   actually used, so it is scoped to that instead of penalising desktop. */
@media (pointer: coarse) {
    .nav-links a,
    .btn,
    .btn-sm,
    .form-control,
    /* `.tab-btn` e `.icon-btn` no aparecen ni en la plantilla ni en los scripts:
       los nombres reales de estos controles son `.tab-link` y `.btn-icon`, asi
       que el area tactil minima se estaba dando a dos clases muertas mientras las
       que se pintan de verdad se quedan en 28px de alto. */
    .tab-link,
    .btn-icon,
    .help-topic__head {
        min-height: 44px;
    }

    .help-topic__head {
        display: flex;
        align-items: center;
    }

    .help-index__link {
        /* Los chips del indice tambien se pulsan con el dedo. */
        min-height: 44px;
        line-height: 30px;
    }

    .nav-links a {
        align-items: center;
    }

    .nav-links a i {
        /* Re-centre the glyph once the label is the thing that is hidden. */
        margin-right: 0;
    }

    .close,
    .modal-close {
        min-width: 44px;
        min-height: 44px;
    }
}

/* --- Focus visibility -----------------------------------------------------
   The dashboard does not load the public styles.css, so it had no focus style
   of its own: keyboard users tabbed through the whole panel invisibly. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* The icon-only sidebar must not paint a ring around the whole <a> when the
   label is present but hidden. */
.nav-links a:focus-visible {
    outline-offset: -3px;
}

/* --- Collapsed sidebar ----------------------------------------------------
   At 1024px the labels were hidden with display:none, which also removes them
   from the accessibility tree, and the links carried no title, so the icons
   were the only thing left: unlabelled controls for anyone not using a mouse.
   The label is now clipped rather than removed, so it still names the link, and
   it surfaces as a tooltip on hover. */
@media (max-width: 1024px) {
    /* En tablet la rejilla ya se queda en dos columnas por su propio minmax; solo
       hace falta quitar el tope de 1500px, que a este ancho no llega a aplicarse. */
    .help-topics { max-width: none; }

    .stats-grid { grid-template-columns: repeat(2, 1fr); }
    .sidebar { width: 80px; }
    .main-wrapper { margin-left: 80px; padding: 20px 16px; }
    .appearance-grid { grid-template-columns: 1fr; min-height: 0; }
    .charts-grid { grid-template-columns: 1fr; }
    /* Con una sola columna el formulario queda encima de la vista previa, asi que
       su borde derecho se convierte en una linea vertical suelta en el aire. Pasa
       a ser un borde inferior, que es lo que separa las dos mitades apiladas. */
    .appearance-form-side { border-right: 0; border-bottom: 1px solid var(--border); }
    .appearance-preview-side { min-height: 500px; }
    .top-header { flex-wrap: wrap; gap: 10px; }
    .top-header h2 { font-size: 1.2rem; }
    .user-nav { gap: 10px; }
    .card { padding: 20px; }
    th, td { padding: 10px 8px; }
    .btn-sm { padding: 6px 10px; font-size: 0.6rem; }
    /* Declared with a fixed column count and no breakpoint at all, so a tablet
       got four form fields about 150px wide. */
    .edit-grid-4 { grid-template-columns: repeat(2, 1fr); }
    .features-grid { grid-template-columns: repeat(2, 1fr); }
}

/* The icon-only rail applies from the tablet down to the point where the sidebar
   becomes an off-canvas drawer. Below that the drawer has room for the labels,
   and clipping them there would leave the open menu unlabelled. */
@media (max-width: 1024px) and (min-width: 769px) {
    /* The label used to be display:none, which also removed it from the
       accessibility tree, and no link had a title: twelve unlabelled icons.
       Clipping keeps the accessible name and adds a hover tooltip. */
    .nav-links span {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .nav-links a {
        position: relative;
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
    }

    .nav-links a[data-label]:hover::after,
    .nav-links a[data-label]:focus-visible::after {
        content: attr(data-label);
        position: absolute;
        left: calc(100% + 10px);
        top: 50%;
        transform: translateY(-50%);
        padding: 6px 10px;
        background: var(--dark);
        color: #fff;
        font-size: 0.75rem;
        white-space: nowrap;
        border-radius: 4px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
        z-index: 1200;
        pointer-events: none;
    }
}

/* El bloque de telefono va despues del de tablet. Con el orden al reves, el
   margin-left: 80px y el grid de dos columnas de tablet se le ganaban al
   margin-left: 0 y al grid de una columna de telefono (mismo peso
   especifico, gana el ultimo) y en 360 px el documento se iba 30 px mas
   ancho que la pantalla. Escritorio -> tablet -> telefono es el orden que
   espera cualquiera que lea la hoja. */
@media (max-width: 768px) {
    .user-identity__org { display: none; }
    .user-identity { max-width: 7rem; }
    .calendar-toolbar { padding: 12px 14px; }
    .calendar-toolbar__filter { max-width: none; }
    .table-toolbar { align-items: stretch; }
    .table-toolbar__field { flex-basis: 100%; }
    .table-toolbar .btn { width: 100%; }
    .org-suspended-banner { margin: 12px 14px 0; }
    .mobile-header {
        min-width: 0;
        /* Sin esto el header fijo se va de ancho: sus hijos no encogen y el documento
           acaba mas ancho que la pantalla. */ 
        display: flex; 
        position: fixed; 
        top: 0; 
        width: 100%; 
        z-index: 1100; 
        height: 52px; 
        background: var(--sidebar-bg);
        border-bottom: 1px solid rgba(255,255,255,0.08);
    }
    .sidebar { transform: translateX(-100%); top: 52px; height: calc(100vh - 52px); }
    
    /* El cajon cerrado no pinta nada. A 1024 la barra baja a 80px y las etiquetas se
       recortan con clip-path, pero el span de la etiqueta es mas ancho que el enlace
       que la contiene y no lleva overflow: hidden: al esconder el cajon con
       translateX(-100%) solo se ocultan 80px de los 74 del texto y lo que sobra se
       pinta encima del contenido por el borde izquierdo. Medido en 360: el span cae
       en -18..56 con su enlace en -65..-15. */
    .sidebar:not(.mobile-active) { visibility: hidden; }
.sidebar.mobile-active { transform: translateX(0); width: 260px; }
    .sidebar.mobile-active span { display: inline; }
    /* body delante para ganar en peso: el bloque de tablet (1024) va despues en la
       hoja y declaraba margin-left: 80px. Con el mismo peso ganaba el ultimo. */
    body .main-wrapper { margin-left: 0; padding: 72px 10px 20px; }
    .stats-grid { grid-template-columns: 1fr; }
    
    /* Mobile header logo */
    .mobile-header .logo h1 {
        color: var(--accent);
        font-size: 0.95rem;
        letter-spacing: 0.5px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 180px;
    }
    .mobile-header .logo h1 i {
        color: var(--accent);
        font-size: 1rem;
    }
    #mobile-toggle {
        /* Cuadrado y con el area de un pulgar. Con el padding de un .btn-sm mide
           lo que mide el icono y rozar el borde no es pulsar el boton. */
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        padding: 0;
        font-size: 1rem;
        flex-shrink: 0;
        border-color: rgba(255,255,255,0.15);
        color: rgba(255,255,255,0.8);
    }
    .sidebar.mobile-active {
        box-shadow: 18px 0 40px rgba(0,0,0,0.35);
    }
    
    /* Compact header */
    .top-header { 
        margin-bottom: 12px; 
        padding-bottom: 8px; 
        flex-wrap: wrap; 
        gap: 8px; 
    }
    .top-header h2 { 
        font-size: 1rem; 
        font-weight: 700; 
    }
    .user-nav { 
        gap: 6px; 
        flex-wrap: wrap; 
    }
    .role-badge { 
        font-size: 0.55rem; 
        padding: 3px 8px; 
        letter-spacing: 1px; 
    }
    #logoutBtn { 
        padding: 6px 10px; 
        font-size: 0.6rem; 
    }
    .notif-bell-btn { 
        padding: 6px; 
        font-size: 1rem; 
    }
    
    /* Compact cards */
    .card { 
        padding: 14px; 
        margin-bottom: 16px; 
    }
    .card-title { 
        font-size: 0.7rem; 
        margin-bottom: 12px; 
        letter-spacing: 1px; 
    }
    
    /* Compact tables */
    th { 
        padding: 8px 6px; 
        font-size: 0.6rem; 
    }
    td { 
        padding: 10px 6px; 
        font-size: 0.8rem; 
    }
    .btn-sm { 
        padding: 5px 8px; 
        font-size: 0.55rem; 
    }
    
    /* Nada se oculta ya en pantallas estrechas. Se ocultaban la primera, la tercera
       y la cuarta columna de los apartamentos, y ocultar una columna es borrarla.
       La tabla se apila con la etiqueta de su columna al lado, asi que se sigue
       viendo todo. Ver .table--stackable. */
    
    /* Compact org badge */
    .org-badge { 
        font-size: 0.55rem; 
        margin-top: 2px; 
    }
    
    /* Compact btn group */
    .btn-group { 
        gap: 4px; 
    }
    
    /* Section titles */
    .edit-apt-head h3 { 
        font-size: 1rem; 
    }
    
    /* Stats compact */
    .stat-item { 
        padding: 14px; 
    }
    .stat-item .value { 
        font-size: 1.4rem; 
    }
    
    /* Modal compact */
    .modal-content { 
        padding: 20px; 
        width: 98%; 
    }
    .modal-header h3 { 
        font-size: 1.2rem; 
    }
    
    /* Tabs compact */
    .tabs-header { 
        gap: 10px; 
        padding: 0 10px; 
        overflow-x: auto;
    }
    .tab-link { 
        font-size: 0.65rem; 
        padding: 10px 2px; 
        white-space: nowrap;
    }
    
    /* Language tabs compact - horizontal scroll */
    .lang-tabs-container {
        margin-bottom: 15px;
    }
    .lang-tabs-header {
        gap: 8px;
        overflow-x: auto;
        flex-wrap: nowrap;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .lang-tabs-header::-webkit-scrollbar {
        display: none;
    }
    .lang-tab-link {
        font-size: 0.7rem;
        padding: 8px 12px;
        white-space: nowrap;
        flex-shrink: 0;
    }
    .lang-tab-link img {
        width: 14px;
    }
    
    /* Calendar compact */
    .calendar-day { 
        min-height: 70px; 
        padding: 6px; 
    }
    .day-number { 
        font-size: 0.75rem; 
    }
    .cal-event { 
        font-size: 0.6rem; 
        padding: 3px 6px; 
    }
    .table-container thead th {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--card-bg);
    }

    .table-container td:first-child,
    .table-container th:first-child {
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--card-bg);
        box-shadow: 1px 0 0 var(--border);
    }

    .table-container thead th:first-child {
        z-index: 3;
    }
    .edit-grid-2,
    .edit-grid-4,
    .form-row-2,
    .features-grid { grid-template-columns: 1fr; }
    .table-container thead th {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--card-bg);
    }

    .table-container td:first-child,
    .table-container th:first-child {
        position: sticky;
        left: 0;
        z-index: 1;
        background: var(--card-bg);
        box-shadow: 1px 0 0 var(--border);
    }

    .table-container thead th:first-child {
        z-index: 3;
    }

    .edit-grid-2,
    .edit-grid-4,
    .form-row-2,
    .features-grid { grid-template-columns: 1fr; }

  /* En movil el cajon ocupa la pantalla y los grupos se leen de un vistazo. */
  .nav-group__label { padding-left: 15px; }
  /* Por encima del cajon (1000) y del velo (990). A 60 la cabecera quedaba
     debajo de los dos: el boton que cierra el menu se abria con el y ahi se
     quedaba, inalcanzable, y solo se podia salir por el velo o con Escape. */
  .mobile-header { z-index: 1010; }
  body.mobile-menu-open { overflow: hidden; }

  /* Apilada, la columna de foto se esconde en vez de etiquetarse: un cuadrado de
     56px con la palabra "Foto" encima cuesta una linea y no dice nada. */
  .table--stackable td.apt-photo-cell { display: none; }

/* El velo detras del cajon. Tocar fuera ya cerraba el menu, pero no se veia nada
   que dijera que lo que hay detras no se puede usar mientras esta abierto. */
.mobile-scrim {
    position: fixed;
    inset: 0;
    /* 990: por debajo del cajon (1000) y por encima del contenido. A 1005 el velo
       tapaba el menu entero, y como captura los toques no habia forma de pulsar un
       enlace: tocar el menu cerraba el menu. La cabecera movil va aparte, mas
       arriba, para que su boton siga disponible con el cajon abierto. */
    z-index: 990;
    background: rgba(9, 15, 24, 0.55);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, visibility 0.2s;
}

.mobile-scrim.is-active {
    opacity: 1;
    visibility: visible;
}

@media (prefers-reduced-motion: reduce) {
    .mobile-scrim {
        transition: none;
    }
}

  .table--stackable thead { display: none; }

  .table--stackable tbody tr {
    display: block;
    padding: 12px 14px;
    margin-bottom: 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card-bg);
  }

  .table--stackable tbody td {
    display: flex;
    /* wrap, no sin mas: varias celdas tienen mas de un hijo —el nombre y el correo,
       la entrada y la salida— y en fila los dos se partian a la mitad
       ("2026-11-" / "02"). Con wrap, el segundo hijo baja a su linea y ocupa el
       ancho entero. */
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 4px 10px;
    padding: 3px 0;
    border: 0;
  }

  /* Cada hijo del valor ocupa el ancho que queda tras la etiqueta. */
  .table--stackable tbody td > * {
    /* 0 1 auto, no 1 1. Con crecer, la pastilla de estado y el boton se
       estiraban al 66% del ancho y a 768 la tarjeta quedaba con medio
       metro de vacio a la derecha. Con basis al 66% tampoco vale: flex-shrink
       solo encoge cuando hay overflow, asi que con espacio de sobra el elemento
       se queda en 66%. Con auto ocupa lo que necesita y el tope impide que un
       texto largo se coma la tarjeta. */
    flex: 0 1 auto;
    max-width: calc(66% - 10px);
    min-width: 0;
  }

  /* La etiqueta es el nombre de la columna, que es lo que faltaba por completo. */
  .table--stackable tbody td::before {
    content: attr(data-label);
    /* 38% se comia media pantalla a 360 y las fechas se partian por la mitad
       ("2026-11-" / "02"). */
    flex: 0 0 34%;
    max-width: 34%;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: #8b958f;
  }

  /* La celda que no tiene etiqueta —el boton de acciones— ocupa la fila entera. */
  .table--stackable tbody td:not([data-label]) { justify-content: flex-end; }
  .table--stackable tbody td[data-label=""]::before { content: none; }

  .table--stackable tbody td[data-label=""] { padding-top: 10px; }

  /* En movil el pulgar llega abajo: los avisos, tambien. */
  .toast-host { left: 1rem; right: 1rem; max-width: none; }

  /* La ayuda en movil: menos aire y chips mas juntos, porque el ancho es el
     recurso escaso. El interlineado se mantiene holgado a proposito — es la
     diferencia entre leerse bien y leerse con prisa. */
  /* Por debajo de dos columnas, una sola. auto-fit ya lo hace solo por el minmax,
     pero se deja explicito porque es la decision que mas se nota en un movil y
     la primera que se rompe si alguien cambia el minmax. */
  .help-topics { grid-template-columns: 1fr; }

  .help-index__list { gap: 6px; }

  .help-index__link {
    padding: 8px 12px;
    font-size: 0.8rem;
  }

  .help-topic__head { padding: 12px 14px; }
  .help-topic__body { padding: 0 14px 16px; }
  .help-defs dt { margin-top: 12px; }

  /* La accion de la cabecera pasa debajo del titulo y a ancho completo: pegada
     al lado se pisa en la mayoria de los moviles, y a ancho completo es un
     objetivo de puntero comodo. */
  .card-head { flex-direction: column; align-items: stretch; }
  .card-head .btn { width: 100%; justify-content: center; }

  /* Las acciones del formulario de nueva propiedad se apilan, y la principal
     arriba —column-reverse— porque es la que se usa siempre y tiene que caer
     bajo el pulgar. */
  .new-apt__actions { flex-direction: column-reverse; }
  .new-apt__actions .btn { width: 100%; }
  .new-apt__foot { gap: 12px; }
}


/* --- Phones --------------------------------------------------------------- */
@media (max-width: 480px) {
    .main-wrapper { padding: 72px 8px 16px; }

    .card { padding: 14px; }

    .stats-grid { gap: 10px; }

    .top-header h2 { font-size: 1.05rem; }

    /* Full-width primary actions read better than a row of small ones. */
    .top-header .user-nav .btn,
    .form-actions .btn {
        flex: 1 1 auto;
    }

    .appearance-grid { grid-template-columns: 1fr; }

    /* The live preview iframe is useless below ~300px of height. */
    .appearance-preview-side { min-height: 320px; }
}

/* Very narrow phones: the calendar cannot show seven readable columns. */
@media (max-width: 380px) {
    .calendar-header,
    .calendar-grid {
        font-size: 0.6rem;
    }

    .calendar-header > *,
    .calendar-grid > * {
        padding: 4px 2px;
    }
}

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

/* --- Dark mode ------------------------------------------------------------
   The admin panel is the surface an operator stares at for a whole shift, and
   the palette is already tokenised. Two ways in: the toggle writes data-theme on
   <html>, and this block catches the OS preference for anyone who never touches
   it. The tokens sit behind :not([data-theme="light"]) so an explicit choice
   always wins; the component rules below are repeated for [data-theme="dark"].
   Brand --primary is left alone: it is a fill for buttons and badges, and it is
   near-black, which is why text uses --primary-ink instead. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg: #12161A;
        --bg-soft: #141A1F;
        --card-bg: #1A2026;
        --text: #E6E9EA;
        --text-muted: #9AA5AD;
        --primary-ink: #7FC4A0;
        --border: #2A323A;
        --dark: #0A0D10;
        --sidebar-bg: #0A0D10;
        --shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
    }
}

:root[data-theme="dark"] {
    --bg: #12161A;
    --bg-soft: #141A1F;
    --card-bg: #1A2026;
    --text: #E6E9EA;
    --text-muted: #9AA5AD;
    --primary-ink: #7FC4A0;
    --border: #2A323A;
    --dark: #0A0D10;
    --sidebar-bg: #0A0D10;
    --shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}

/* Las superficies que el tema oscuro tiene que repintar. Se declaran una sola
   vez y se aplican desde los dos caminos. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) body { background: var(--bg); color: var(--text); }
    :root:not([data-theme="light"]) .card,
    :root:not([data-theme="light"]) .stat-item,
    :root:not([data-theme="light"]) .modal-content,
    :root:not([data-theme="light"]) .table-container thead th,
    :root:not([data-theme="light"]) .table-container td:first-child,
    :root:not([data-theme="light"]) .table-container th:first-child,
    :root:not([data-theme="light"]) .form-control,
    :root:not([data-theme="light"]) .tab-content {
        background-color: var(--card-bg);
        color: var(--text);
    }
    :root:not([data-theme="light"]) .card,
    :root:not([data-theme="light"]) .stat-item,
    :root:not([data-theme="light"]) .modal-content { border-color: var(--border); }
    :root:not([data-theme="light"]) input,
    :root:not([data-theme="light"]) select,
    :root:not([data-theme="light"]) textarea {
        background-color: #141A1F;
        color: var(--text);
        border-color: var(--border);
    }
    :root:not([data-theme="light"]) .table-container thead th { color: var(--text-muted); }
    :root:not([data-theme="light"]) .nav-links a:hover,
    :root:not([data-theme="light"]) .tab-btn:hover { background: rgba(255, 255, 255, 0.05); }
    :root:not([data-theme="light"]) .calendar-day.today { background: #2b2617; }
    :root:not([data-theme="light"]) .calendar-day.today .day-number { color: #E7B36A; }
    :root:not([data-theme="light"]) .appearance-device-btn.is-on {
        background: var(--card-bg); border-color: var(--border); color: var(--text);
    }
}

:root[data-theme="dark"] body { background: var(--bg); color: var(--text); }
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .stat-item,
:root[data-theme="dark"] .modal-content,
:root[data-theme="dark"] .table-container thead th,
:root[data-theme="dark"] .table-container td:first-child,
:root[data-theme="dark"] .table-container th:first-child,
:root[data-theme="dark"] .form-control,
:root[data-theme="dark"] .tab-content {
    background-color: var(--card-bg);
    color: var(--text);
}
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .stat-item,
:root[data-theme="dark"] .modal-content { border-color: var(--border); }
:root[data-theme="dark"] input,
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea {
    background-color: #141A1F;
    color: var(--text);
    border-color: var(--border);
}
:root[data-theme="dark"] .table-container thead th { color: var(--text-muted); }
:root[data-theme="dark"] .nav-links a:hover,
:root[data-theme="dark"] .tab-btn:hover { background: rgba(255, 255, 255, 0.05); }
:root[data-theme="dark"] .calendar-day.today { background: #2b2617; }
:root[data-theme="dark"] .calendar-day.today .day-number { color: #E7B36A; }
:root[data-theme="dark"] .appearance-device-btn.is-on {
    background: var(--card-bg); border-color: var(--border); color: var(--text);
}

/* El tema de superadmin fijaba --bg claro; en oscuro dejaba texto claro sobre
   blanco. Solo se repintan las superficies, el acento indigo se conserva. */
:root[data-theme="dark"] body.super-admin-mode {
    --bg: #12161A;
    --card-bg: #1A2026;
    --border: #2A323A;
    --text: #E6E9EA;
    --text-muted: #9AA5AD;
    --primary-ink: #C7D2FE;
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) body.super-admin-mode {
        --bg: #12161A;
        --card-bg: #1A2026;
        --border: #2A323A;
        --text: #E6E9EA;
        --text-muted: #9AA5AD;
        --primary-ink: #C7D2FE;
    }
}


/* --- Modales ----------------------------------------------------------------
   Los modales viven siempre en el DOM y se abren anadiendo .active. Sin una regla
   que los saque del flujo, un modal inerte se coloca al final de la pagina ocupando su
   ancho: medido en 360, .modal-content ocupaba 377px y el documento se iba 25px mas
   ancho que la pantalla, con el panel desplazandose de lado. */
.modal { display: none; }
.modal.active { display: flex; }

/* --- Print ----------------------------------------------------------------
   Operators do print reservation lists and invoices from this panel. */
@media print {
    .sidebar,
    .mobile-header,
    .top-header .user-nav,
    .notification-wrapper,
    .btn,
    .tab-nav {
        display: none !important;
    }

    .main-wrapper {
        margin-left: 0 !important;
        padding: 0 !important;
    }

    .card {
        box-shadow: none;
        border: 1px solid #ccc;
        break-inside: avoid;
    }

    .table-container { overflow: visible; }
}

/* Was a <style nonce> block inside the dashboard template. It is theme, not
   markup, and it re-rendered on every navigation of the admin panel. */
/* --- SUPER ADMIN OVERRIDE THEME (INFRASTRUCTURE LOOK) --- */
    body.super-admin-mode {
    --primary: #0f172a;      /* Deep Slate */
    --primary-light: #1e293b;
    --accent: #6366f1;       /* Indigo */
    --sidebar-bg: #020617;   /* Black Slate */
    --bg: #f8fafc;
    }
    body.super-admin-mode .stat-item {
    border-left-width: 0;
    border-top: 4px solid var(--accent);
    }
    body.super-admin-mode .role-badge {
    background: var(--accent);
    border-radius: 4px;
    }
    body.super-admin-mode .nav-links a.active {
    border-left-color: var(--accent);
    color: #818cf8;
    }

/* ---------------------------------------------------------------------------
   Notificaciones del panel.

   Estas reglas estaban como atributos style="" dentro de
   admin-dashboard.js. La CSP del proyecto no admite 'unsafe-inline' en
   style-src-attr, asi que cada una estaba siendo descartada por el navegador y el
   panel salia sin formato: sin separadores, sin tamano de texto y con el color
   de fondo descartado tambien. La diferencia entre leida y no leida, que antes
   venia de un ternario en el estilo, es ahora una clase.
   --------------------------------------------------------------------------- */

.notif-empty {
  padding: 20px;
  text-align: center;
  color: #999;
}

/* Es un <button>: un div con cursor:pointer no dice nada a un teclado ni a un
   lector de pantalla, y por eso hay que neutralizar el estilo de boton. */
.notif-item {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  padding: 15px;
  border: 0;
  border-bottom: 1px solid #eee;
  background: #fff;
  cursor: pointer;
  transition: background-color .15s;
}

.notif-item:hover { background: #f6f8f7; }

.notif-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.notif-item.is-unread { background: #f0fdf4; }

.notif-title {
  font-weight: 700;
  font-size: .8rem;
  color: var(--primary, #1b3022);
}

.notif-body { font-size: .75rem; color: #666; }

.notif-when { font-size: .6rem; color: #999; margin-top: 5px; }

/* ---------------------------------------------------------------------------
   Panel de autenticacion en dos pasos.

   Mismo origen que las notificaciones: eran atributos style="" dentro de
   admin-dashboard.js y la CSP los descartaba uno a uno. La diferencia entre
   activado y desactivado, que era un ternario con dos colores distintos
   escritos a mano, son ahora dos clases.
   --------------------------------------------------------------------------- */

.tfa { max-width: 600px; }

.tfa-card {
  background: #fff;
  border: 1px solid #e9ecef;
  border-radius: 10px;
  padding: 24px;
  margin-bottom: 20px;
}

.tfa-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.tfa-title { margin: 0 0 6px; font-size: 1.1rem; color: #1a1a2e; }
.tfa-title i { color: #1b3022; margin-right: .4rem; }
.tfa-sub { margin: 0; color: #666; font-size: .85rem; }

.tfa-pill {
  padding: 6px 14px;
  border-radius: 20px;
  font-size: .8rem;
  font-weight: 700;
  white-space: nowrap;
}
.tfa-pill.is-on { background: #d4edda; color: #155724; }
.tfa-pill.is-off { background: #f8d7da; color: #721c24; }

.tfa-actions { margin-top: 16px; }
.tfa-btn { display: inline-block; padding: 10px 20px; }
.tfa-btn.is-danger { border: 2px solid #ef4444; color: #ef4444; }
.tfa-btn.is-danger:hover { background: #ef4444; color: #fff; }

/* ---------------------------------------------------------------------------
   Calendario (calendar-widget.js) y formulario de huespedes (client-dashboard.js).

   Estaban como atributos style="" y la CSP los descartaba, asi que el boton de
   guardar no ocupaba el ancho de la caja, las notas de reserva no salian en
   cursiva y los tres desplegables de la fecha de nacimiento no se repartian la
   fila. En calendario.ejs.
   --------------------------------------------------------------------------- */

.cal-wide { width: 100%; }
.cal-gap { margin-top: 1rem; }
.cal-note { margin-top: .5rem; font-style: italic; }

/* ---------------------------------------------------------------------------
   Selector de plantilla del panel de apariencia.

   Era un <select> con cinco <option> escritos a mano en dashboard-admin.js,
   mientras la lista blanca del servidor tenia siete. verano y primavera estaban
   instalados y no se podian elegir. Ahora las tarjetas se pintan con la lista que
   devuelve /gestionar/api/settings/org, con su miniatura y su descripcion, para
   que elegir una plantilla no sea elegir a ciegas.

   Los estilos de este bloque tambien estaban en el atributo style, que la CSP
   descarta, asi que el selector salia sin separaciones ni rejilla.
   --------------------------------------------------------------------------- */

.ap-col {
  display: flex;
  flex-direction: column;
  gap: 30px;
}

.ap-h4 {
  margin: 0 0 15px;
  color: var(--primary-ink);
  border-bottom: 1px solid #eee;
  padding-bottom: 8px;
}

/* fieldset solo por el legend: el navegador mete un borde y un padding que
   estorban, asi que se quitan y el legend se alinea con los otros titulos. */
.tpl-fieldset { border: 0; padding: 0; margin: 0 0 8px; }
.tpl-fieldset legend { padding: 0; width: 100%; }

.tpl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}

.tpl {
  display: grid;
  gap: 4px;
  padding: 8px;
  border: 1px solid #e2e6ea;
  border-radius: 10px;
  cursor: pointer;
  background: #fff;
  transition: border-color .2s, box-shadow .2s;
}

.tpl:hover { border-color: var(--primary-ink); }

.tpl.is-on {
  border-color: var(--primary-ink);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 18%, transparent);
}

.tpl input { position: absolute; opacity: 0; pointer-events: none; }

.tpl__img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}

.tpl__label { font-weight: 600; font-size: .9rem; }

.tpl__blurb { font-size: .78rem; color: #667; line-height: 1.35; }

/* ---------------------------------------------------------------------------
   Reservas (dashboard-bookings.js).

   Los quince estilos de este fichero estaban en atributos style="" y la CSP los
   descartaba uno a uno: la celda de huesped sin negrita, las fechas sin tamano, el
   aviso de proteccion de datos sin caja y el icono del aviso sin nada. La franja
   de color de las tres tarjetas de estadisticas era un color escrito dentro del
   atributo, y ahora son tres clases, porque un color que vive en el script no se
   puede cambiar sin tocar JavaScript.

   En gestionar-dashboard-es.ejs.
   --------------------------------------------------------------------------- */

.bk-empty { text-align: center; padding: 40px; }

.bk-guest { font-weight: 700; }
.bk-guest-mail { font-size: .75rem; color: #666; }
.bk-date { font-size: .85rem; }
.bk-date-end { font-size: .7rem; color: #888; }

.bk-privacy {
  margin-top: 40px;
  padding: 30px;
  background: #f8fafc;
  border: 1px dashed #cbd5e1;
  border-radius: 12px;
  text-align: center;
  color: #64748b;
  font-size: .9rem;
}

.bk-privacy__icon {
  display: block;
  margin-bottom: 15px;
  font-size: 2rem;
  color: #94a3b8;
}

.bk-month {
  margin: 0;
  font-family: 'Playfair Display', serif;
  font-weight: 800;
  font-size: 1.8rem;
  color: var(--primary-ink);
}

/* Las tres tarjetas de estadisticas globales. */
.stats-grid--spaced { margin-top: 20px; }

.stat-note { font-size: .72rem; color: var(--text-muted); }

.stat-item--is-accent { border-top: 4px solid var(--accent); }
.stat-item--is-ok { border-top: 4px solid #34d399; }
.stat-item--is-warn { border-top: 4px solid #f59e0b; }

/* ---------------------------------------------------------------------------
   Cupones (dashboard-coupons.js), el aviso de precio de miramar y el mensaje de
   exito del registro.

   Otros siete estilos inline, los tres ficheros completos. El codigo del cupon
   llevaba el fondo, el padding y el color de la letra en el atributo, asi que se
   veía como texto normal; y el campo de escribir el cupon llevaba un
   text-transform que no se aplicaba, de modo que el codigo se escribia en
   minusculas donde se esperaba en mayusculas.
   --------------------------------------------------------------------------- */

.cp-code {
  background: var(--bg-soft);
  padding: 4px 8px;
  border-radius: 4px;
  font-weight: 800;
  color: var(--primary-ink);
}

.cp-code-input { text-transform: uppercase; }

.cp-note { font-size: .75rem; color: #666; }

.cp-empty { text-align: center; padding: 40px; color: #999; }

.cp-actions { text-align: right; margin-top: 20px; }

/* El precio del apartamento no aparece hasta que hay fechas, y entonces no
   necesita margen: solo ocupa su propia linea. */
.price-note--flush { margin: 0; }

/* ==========================================================================
   Panel de administracion: vocabulario de los estilos que estaban inline.

   Los 47 estilos de dashboard-admin.js estaban en atributos style="", que la CSP
   descarta uno a uno. Se reconocen por lo que se veia: las casillas de opcion sin
   caja, el titulo de cada seccion sin su linea, la fila del boton pegada al
   borde de abajo, el codigo del cupon como texto normal, y la insignia del rol
   sin color, de modo que los tres roles se veian iguales.

   El nombre de cada clase es corto a proposito. Son objetos de un modulo que
   se lee entero de una vez, y nombres largos aqui solo anaden ruido sin ganar
   nada: lo que describe el bloque es el proposito, no cada propiedad.
   ========================================================================== */

/* --- tipografia y color --------------------------------------------------- */

.fw7-primary { font-weight: 700; color: var(--primary-ink); }
.fw8-11-primary { font-weight: 800; font-size: 1.1rem; color: var(--primary-ink); }
.xs-accent-ls { font-size: .7rem; color: var(--accent); letter-spacing: 1px; }
.xs-dim { font-size: .7rem; color: var(--text-muted); }
.xs-dim2 { font-size: .75rem; color: var(--text-muted); }
.xs-mb4 { font-size: .75rem; margin-bottom: 4px; }
.cl-admin { color: var(--accent); }
.cl-dim { color: #888; }

/* --- espaciado ------------------------------------------------------------ */

.mt10 { margin-top: 10px; }
.mt20 { margin-top: 20px; }
.mt-n10 { margin-top: -10px; }
.mb15 { margin-bottom: 15px; }
.mb20 { margin-bottom: 20px; }
.mb15-muted { margin-bottom: 15px; color: var(--text-muted); }
.mb20-primary { margin-bottom: 20px; color: var(--primary-ink); }
.pad0 { padding: 0; }
.pad-x30 { padding: 12px 30px; }

/* --- alineacion y tamano -------------------------------------------------- */

.ta-c { text-align: center; }
.ta-r { text-align: right; }
.ta-r-mt20 { text-align: right; margin-top: 20px; }
.ta-r-mt30 { text-align: right; margin-top: 30px; }
.w-auto { width: auto; }
.scale12 { width: auto; transform: scale(1.2); }
.input-sm { height: 45px; padding: 5px; }
.scrollbox { max-height: 300px; overflow-y: auto; }
.hr-soft { margin: 30px 0; border: none; border-top: 1px solid var(--border); }

/* --- filas y grupos ------------------------------------------------------- */

.row5 { display: flex; gap: 5px; }
.row5--wrap { flex-wrap: wrap; }
.row5--end { justify-content: flex-end; }
.clients-login { display: block; margin-top: 6px; }
.mt6 { margin-top: 6px; }
.row10 { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.row-between-xs {
  display: flex;
  justify-content: space-between;
  font-size: .65rem;
  color: #666;
  margin-top: 5px;
}

/* Una opcion de las que antes eran un label con el estilo puesto. */
.choice,
.choice-sm {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  border: 1px solid var(--border);
}
.choice { padding: 8px 12px; border-radius: 8px; margin-bottom: 10px; }
.choice-sm { padding: 8px 12px; border-radius: 8px; margin-bottom: 8px; }

.toggle-row,
.toggle-row-bordered {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  background: var(--bg-soft);
  padding: 15px;
}
.toggle-row { border-radius: 8px; margin-bottom: 10px; }
.toggle-row-bordered { border-radius: 8px; border: 1px solid var(--border); }

/* --- titulos de seccion --------------------------------------------------- */

.sec-h,
.sec-h-sm {
  margin-bottom: 15px;
  color: var(--primary-ink);
  border-bottom: 1px solid #eee;
  padding-bottom: 10px;
}
.sec-h { font-size: 1.1rem; }
.sec-h-sm { font-size: .9rem; }

/* --- insignias de rol ----------------------------------------------------- */

/* El color estaba escrito dentro del atributo, a partir de un ternario sobre el
   rol. Con tres roles son tres clases, y cambiar el color de un rol deja de
   obligar a tocar JavaScript. */
.role-badge--superadmin { background: #6366f1; }
.role-badge--admin { background: var(--dark); }
.role-badge--other { background: #64748b; }

/* Stripe se muestra o no segun la configuracion. El display estaba resuelto a
   mano dentro del atributo; dos clases hacen lo mismo y se pueden usar en CSS. */
.st-on { display: block; }
.st-off { display: none; }

/* --- pie pegado y boton ancho --------------------------------------------- */

.sticky-foot {
  position: sticky;
  bottom: 0;
  /* --card-bg y --border, no white y #eee: en modo oscuro esta barra quedaba
     como una franja clara pegada al borde de la ventana. */
  background: var(--card-bg);
  padding: 20px 0;
  border-top: 1px solid var(--border);
  margin-top: 20px;
}

.btn-block-wide {
  width: 100%;
  padding: 15px;
  font-weight: 800;
  letter-spacing: 1px;
}

/* Las cuatro tarjetas del mando central (dashboard-sections.js). El color de la
   franja estaba en el atributo de cada una, escrito a mano cuatro veces. */
.stat-item--is-danger { border-top: 4px solid #f87171; }

/* La organizacion a la que pertenece cada reserva, en la tabla de actividad. */
.org-tag { color: var(--accent); font-weight: 800; }

/* ---------------------------------------------------------------------------
   Estados de una vista: cargando, vacio y error.

   Los cuatro cargadores tenian `if (data.success)` y nada mas. apiFetch nunca
   lanza, devuelve { success: false, error }, asi que un fallo de red o de servidor
   no dejaba huella: la tabla se quedaba con lo que tuviera encima, y no habia
   manera de distinguir "no hay reservas" de "no se ha podido cargar".

   Y no habia estado de carga, de modo que una tabla vacia y una tabla que aun no
   ha llegado se veian igual, que es el peor sitio para confundirlas.

   El esqueleto tiene la forma del contenido real, no un spinner: el hueco que se ve
   es el que ocupa la tabla cuando llegue.
   --------------------------------------------------------------------------- */

@keyframes skel-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.skel {
  display: block;
  border-radius: 4px;
  background: linear-gradient(90deg, #eef1ef 25%, #e2e7e4 37%, #eef1ef 63%);
  background-size: 400% 100%;
  animation: skel-pulse 1.4s ease-in-out infinite;
}

.skel--cell { height: 1rem; }

.skel--title { height: 1.35rem; width: 55%; min-width: 7rem; margin-bottom: .75rem; }
.skel--stat { height: 7rem; border-radius: var(--radius); }

@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; background: #eef1ef; }
}

/* Vacio y error comparten forma: centro, icono, texto y una accion. Que un estado
   de error se vea distinto de uno de vacio es lo que evita que alguien piense que
   la lista esta vacia cuando en realidad no se pudo cargar. */
.state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .75rem;
  padding: 2.5rem 1rem;
  text-align: center;
  color: #667;
}

.state i { font-size: 1.75rem; opacity: .35; }
.state p { margin: 0; font-size: .95rem; }

.state--error { color: #8a3b32; }
.state--error i { opacity: .55; }
.state--empty .btn { margin-top: .25rem; }

/* ---------------------------------------------------------------------------
   El menu.

   Doce secciones en una columna no caben en 390 px. En escritorio se colapsa a
   iconos y se recuerda, porque decidir como quieres trabajar no es un estado de la
   aplicacion. En movil son las mismas doce, pero en cuatro grupos, y se cierra al
   navegar ademas de al pulsar fuera.
   --------------------------------------------------------------------------- */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.sidebar-version {
    margin-top: auto;
    padding: 14px 20px;
    font-size: .65rem;
    color: var(--text-muted);
    letter-spacing: .08em;
    text-transform: uppercase;
}
.sidebar-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  /* El boton es el primer hijo de la barra desde que se quito el encabezado con
     el nombre del tenant, asi que necesita aire arriba: conmargin 0 quedaba
     pegado al borde superior. */
  margin: 16px 15px 8px auto;
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  /* Sobre la barra oscura: --text-muted en tema claro es #607d8b y se apagaba
     contra el fondo del sidebar. Mismo blanco atenuado que los enlaces del menu. */
  color: rgba(255,255,255,0.65);
  cursor: pointer;
  transition: border-color .2s, color .2s;
}

.sidebar-toggle:hover { border-color: var(--accent); color: var(--accent); }
.sidebar-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Colapsado: se ven los iconos y el titulo sale por el title nativo.
   La anchura se declara sobre body, no sobre .sidebar: main-wrapper es hermano
   del sidebar y lee var(--sidebar-width) desde :root, asi que redefinirla en el
   propio sidebar no llegaba al contenido y la columna seguia ocupando lo mismo
   con la barra plegada. El JS marca body.sidebar-collapsed en los dos caminos. */
body.sidebar-collapsed { --sidebar-width: 68px; }
.sidebar.is-collapsed .sidebar-version { display: none; }
.sidebar.is-collapsed .nav-group__label { display: none; }
.sidebar.is-collapsed .nav-links a span,
.sidebar.is-collapsed .nav-links a small { display: none; }
.sidebar.is-collapsed .nav-links a { justify-content: center; padding-left: 0; padding-right: 0; }
.sidebar.is-collapsed .sidebar-toggle i { transform: rotate(180deg); }
.sidebar.is-collapsed .sidebar-toggle { margin-inline: auto; }

.sidebar-toggle i { transition: transform .2s; }

.nav-group + .nav-group { margin-top: 14px; }

.nav-group__label {
  display: block;
  padding: 0 15px 4px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #9aa5a0;
}

.nav-group__items { list-style: none; padding: 0; margin: 0; }

/* ---------------------------------------------------------------------------
   Tablas apiladas en pantallas estrechas.

   Antes se ocultaban columnas con display:none. Ocultar una columna es borrarla: en
   la tabla de reservas se iba justo la que identifica la reserva, y en la de
   apartamentos la del nombre. Con la etiqueta de la columna en cada celda, la
   misma tabla se apila y se sigue viendo todo.
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   Avisos.

   Eran un modal con un boton de Aceptar al final de cada accion, con un alert()
   detras por si el modal no estaba. El aviso de un guardado bien hecho no pide
   confirmacion: informa y se va, y no roba el foco, que es lo que hacia el modal.
   --------------------------------------------------------------------------- */

.toast-host {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 3000;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-width: min(24rem, calc(100vw - 2rem));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .8rem .9rem;
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: 8px;
  background: var(--card-bg);
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, .3);
  font-size: .9rem;
  color: var(--ink, #2c332c);
  pointer-events: auto;
  animation: toast-in .22s ease-out;
}

@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } }

.toast--success { border-left-color: #34d399; }
.toast--error { border-left-color: #e05a4a; }
.toast--info { border-left-color: var(--accent); }

.toast i { flex: none; margin-top: .1rem; }
.toast--success i { color: #1f9d6b; }
.toast--error i { color: #e05a4a; }
.toast--info i { color: var(--accent); }

.toast span { flex: 1; }

.toast__close {
  flex: none;
  background: none;
  border: 0;
  padding: 0 2px;
  color: #9aa5a0;
  cursor: pointer;
  line-height: 1;
}
.toast__close:hover { color: var(--ink, #2c332c); }
.toast__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* --- Ayuda ----------------------------------------------------------------
   Contenido estatico y largo. El reto no es que quepa, sino que se lea bien en
   un movil sin convertirse en una columna interminable: por eso cada tema es un
   <details> nativo, la pagina arranca mostrando solo el indice, y el texto se
   limita a una medida de ~70 caracteres, que es donde el ojo no se cansa.

   No lleva Javascript a proposito. Las secciones se muestran con una clase CSS,
   de modo que esta se lee igual aunque el script no cargue, y los <details>
   abren y cierran sin scripting y son navegables con teclado y lector de
   pantalla sin trabajo extra. */
.help-card { padding-bottom: 22px; }

.help-lead {
    /* Tope generoso: es un par de frases, no prosa. El limite de medida se aplica
       a los temas, que es donde hay mucho texto. */
    max-width: 90ch;
    color: var(--text-muted);
    line-height: 1.7;
    margin: 0 0 22px;
}

.help-index { margin: 0 0 26px; }

.help-index__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.help-index__link {
    display: inline-block;
    padding: 7px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg);
    /* --text y no --primary: el modo oscuro no redefine --primary, y sobre
       --card-bg #1A2026 ese verde da 1.17:1, es decir ilegible. --text llega a
       13.46:1 en claro y en oscuro con el mismo valor. */
    color: var(--text);
    font-size: 0.82rem;
    text-decoration: none;
    transition: border-color 0.2s, background 0.2s;
}

.help-index__link:hover { border-color: var(--accent); background: var(--card-bg); }

.help-topics {
    display: grid;
    /* Los temas se reparten en columnas en vez de apilarse. Apilados, el ancho
       libre se desperdiciaba: a 1920px el contenedor da 1600px, y con una columna
       de texto de 612px se dejaban 988px en blanco a la derecha (el 62%).
       Repartidos en tres, cada acordeon cae en unos 490px, que es la medida en la
       que una linea se lee bien, y el ancho se aprovecha entero.

       Es la unica forma de quadrangular el enzanque: alargar el texto hasta llenar
       la pantalla produciria lineas de 120 caracteres, que se leen peor que una
       columna estrecha, no mejor. */
    grid-template-columns: repeat(auto-fit, minmax(460px, 1fr));
    /* Tope de ancho: en una pantalla de 2560 la rejilla libre se partiria en cinco
       columnas diminutas, que se leen peor que tres anchas. */
    max-width: 1500px;
    gap: 10px;
    /* Abrir un tema agranda su fila, pero no estira a los de al lado: asi el hueco
       que queda se lee como separacion entre tarjetas y no como un fallo. */
    align-items: start;
}

.help-topic {
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--card-bg);
    /* Al saltar desde el indice, el titulo del tema queda por debajo del header
       fijo. Este margen lo aparta sin tener que calcular el alto en JS. */
    scroll-margin-top: 90px;
}

.help-topic[open] { border-color: var(--accent); }

.help-topic__head {
    cursor: pointer;
    padding: 14px 16px;
    list-style: none;
}

/* Safari pinta su propio marcador y el nuestro se sumaría. */
.help-topic__head::-webkit-details-marker { display: none; }

.help-topic__head::before {
    content: '›';
    display: inline-block;
    margin-right: 10px;
    color: var(--accent);
    font-size: 1.1rem;
    line-height: 1;
    vertical-align: -1px;
    transition: transform 0.2s ease;
}

/* Un solo indicador de "abierto/cerrado". El rotar el mismo glifo evita tener dos
   iconos que mantener sincronizados con el estado real del <details>. */
.help-topic[open] > .help-topic__head::before { transform: rotate(90deg); }

.help-topic__title {
    font-size: 0.95rem;
    font-weight: 700;
    /* Ver .help-index__link: --primary no sobrevive al modo oscuro. */
    color: var(--text);
    /* Es un <h3> real para que la navegacion por encabezados lo encuentre; el
       navegador le pondria sus propios margenes y descolgaria el titulo del
       glifo de plegado. */
    margin: 0;
    display: inline;
}

.help-topic__head:focus-visible { outline-offset: -3px; }

.help-topic__body {
    padding: 0 16px 18px;
    line-height: 1.75;
}

.help-topic__body > *:first-child { margin-top: 0; }
.help-topic__body > *:last-child { margin-bottom: 0; }
.help-topic__body p { margin: 0 0 12px; }

.help-steps,
.help-list {
    margin: 0;
    padding-left: 20px;
}

.help-steps li,
.help-list li { margin-bottom: 8px; }

.help-list { list-style: disc; }

/* <dl> en vez de <ul>: cada estado de reserva y cada termino de permiso lleva
   nombre y definicion, y un listado suelto no dice cual es cual. */
.help-defs { margin: 0; }

.help-defs dt {
    font-weight: 700;
    color: var(--text);
    margin-top: 14px;
}

.help-defs dt:first-child { margin-top: 0; }

.help-defs dd {
    margin: 2px 0 0;
}

/* Aviso destacado para lo que conviene no pasar por alto: la regla de la
   estancia minima, lo que si queda legible sin cifrar, lo que hay que hacer al
   dar de baja a alguien. */
.help-note {
    border-left: 3px solid var(--accent);
    background: var(--bg);
    padding: 12px 14px;
    margin: 14px 0;
}

.help-note > *:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   Visibilidad por rol

   Las clases admin-only y superadmin-only llevaban tiempo en el HTML y nada
   las ocultaba: no habia ni una regla en toda la hoja que las mencionase, ni
   ninguna que mirase el atributo data-user-role que initApp escribe en
   <body>. Eran pura decoracion: un admin de organizacion podia pulsar
   «Clientes» y caer en una seccion que su API devuelve 403, con una tabla
   vacia como unica explicacion.

   El body no lleva el atributo hasta que initApp resuelve /api/auth/me, asi
   que mientras la pagina carga las secciones quedan ocultas: para un
   superadmin es un instante, y para el resto es la respuesta correcta.

   Con display:none y no con visibility: una entrada de menu que no ocupa
   sitio es mejor que una entrada desactivada que si lo hace.

   El servidor sigue siendo la frontera. Esto solo evita que el panel ofrezca
   una accion que va a rebotar con 403.
   --------------------------------------------------------------------------- */
body[data-user-role="manager"] .admin-only,
body:not([data-user-role="superadmin"]) .superadmin-only {
  display: none;
}

/* A tenant-only control belongs to an organisation: a superadmin has no tenant
   to operate on, and the sections behind these links read that tenant's data.
   platform-only is the mirror: clients, logs and deletion backups are the
   platform's, not a tenant's. */
body[data-user-role="superadmin"]:not(.acting-as-org) .tenant-only,
body:not([data-user-role="superadmin"]) .platform-only,
body.acting-as-org .platform-only {
  display: none;
}

/* La seccion entera, no solo su entrada de menu. logsSection no lleva la
   clase —su enlace si— asi que se nombra por id para dejar las dos alineadas;
   mantener seccion y enlace en la misma clase es lo que evita que se
   desincronicen. */
body:not([data-user-role="superadmin"]) #clientsSection,
body:not([data-user-role="superadmin"]) #logsSection,
body:not([data-user-role="superadmin"]) #backupsSection {
  display: none;
}

/* ---------------------------------------------------------------------------
   Cabecera de tarjeta con accion

   La seccion de propiedades necesita un boton junto a su titulo. Antes no habia
   patron: el de usuarios y el de organizaciones se insertaban desde JS con
   margenes sueltos, asi que cada uno caia en un sitio distinto. Aqui el titulo y
   la accion viven en la misma fila y la accion se alinea a la derecha.
   --------------------------------------------------------------------------- */
.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 25px;
}
.card-head .card-title { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   Formulario de nueva propiedad

   El modal reutiliza .modal-content, que esta limitado a 700px. Este es mas
   ancho a proposito: lleva tres pestanas con campos numericos en cuatro
   columnas, y a 700px se aprieta hasta el punto de que las etiquetas se parten.
   --------------------------------------------------------------------------- */
.new-apt { max-width: 860px; width: 95%; }

.new-apt__lede {
  margin: 0 0 25px;
  color: var(--text-muted);
  font-size: .92rem;
  line-height: 1.6;
}

/* La direccion que tendra la propiedad. Se muestra mientras se escribe el
   nombre porque es lo unico que quien crea no puede deducir y lo primero
   que quiere saber. */
.new-apt__url {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 12px 0 25px;
  padding: 10px 14px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: .85rem;
  color: var(--text-muted);
}
.new-apt__url i { color: var(--accent); }
.new-apt__slug {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--primary);
  font-weight: 600;
  word-break: break-all;
}

/* Pie del formulario: lo que falta y las acciones. */
.new-apt__foot {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.new-apt__hint {
  margin: 0;
  font-size: .85rem;
  color: var(--text-muted);
}
.new-apt__hint--warn { color: #b45309; font-weight: 500; }
.new-apt__actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
.new-apt__actions .btn { min-width: 140px; }

/* Las pestañas del modal. .tabs-header ya hace scroll horizontal por si solo,
   que es lo que permite tener tres pestañas en una línea estrecha sin que
   ninguna quede cortada. */
.tabs-header--apt { margin-bottom: 25px; }


/* ---------------------------------------------------------------------------
   Aviso de organización suspendida

   La web publica responde 503, pero el panel sigue sirviendo para que el
   cliente pueda arreglar lo que haga falta. Sin un aviso, la suspension era
   invisible desde dentro: todo parecia normal.
   --------------------------------------------------------------------------- */
.org-act-as-banner {
    background: #eef2ff;
    border-color: #c7d2fe;
    color: #3730a3;
}

.org-act-as-exit {
    margin-left: 10px;
}

.org-suspended-banner {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin: 18px 24px 0;
  padding: 14px 18px;
  border-left: 4px solid #f59e0b;
  background: #fff8eb;
  color: #7a4b00;
  font-size: .9rem;
  line-height: 1.5;
}
.org-suspended-banner i { font-size: 1.25rem; margin-top: 1px; }
.org-suspended-banner strong { display: block; color: #5c3900; }
