/**
 * Main stylesheet for JamboQR Frontend
 */

/* ===== Base Styles ===== */

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

html {
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    /* Los costados, en horizontal (2026-10-06). Con la app de borde a borde, al
       girar el teléfono la barra de botones del sistema (◀ ● ■) se pone a un
       lado, y sin esto se dibujaba ENCIMA de la página tapando texto (Xiaomi
       14C, Android 16). Arriba y abajo ya se absorbían en la barra y en la de
       acciones; los costados no los miraba nadie. env() vale 0 en el
       navegador, en vertical y en Android antiguos: nada más cambia. */
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    line-height: var(--line-height-normal);
    color: var(--color-text-primary);
    background-color: var(--color-bg-primary);
    transition: background-color var(--transition-base), color var(--transition-base);
}

/* ===== Typography ===== */

h1, h2, h3, h4, h5, h6 {
    font-weight: var(--font-weight-semibold);
    line-height: var(--line-height-tight);
    margin-bottom: var(--space-md);
}

h1 { font-size: var(--font-size-4xl); }
h2 { font-size: var(--font-size-3xl); }
h3 { font-size: var(--font-size-2xl); }
h4 { font-size: var(--font-size-xl); }
h5 { font-size: var(--font-size-lg); }
h6 { font-size: var(--font-size-base); }

p {
    margin-bottom: var(--space-md);
}

a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--transition-fast);
}

a:hover {
    color: var(--color-primary-hover);
}

/* ===== Buttons ===== */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-lg);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-medium);
    line-height: 1.5;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
    user-select: none;
    /* El texto de un botón PUEDE partirse. Con `nowrap` la etiqueta traducida
       —«Escanear código de barras» ocupa el doble que «Scan Barcode»— empujaba
       su fila más ancha que la pantalla y la página entera se movía de lado
       (bugs del tester 2026-09-09: tienda, buscar productos), o se veía
       recortada dentro de una tarjeta de ancho fijo (pantalla de planes).
       Las barras que sí necesitan una línea lo piden aparte (.help-navbar-btn,
       .apk-navbar-btn, .tab-btn). */
    white-space: normal;
    max-width: 100%;
    /* Y una palabra larga sin espacios tampoco empuja: se parte. */
    overflow-wrap: anywhere;
    text-align: center;
}

/* …pero partirse porque NO CABE es una cosa y partirse porque lo aplastan es
   otra. En una fila flex un botón también encoge (`flex-shrink` vale 1), y al
   encoger por debajo de su texto el `overflow-wrap` de arriba parte la palabra:
   el «Buscar» de las listas salía como «Busc/ar» en tres líneas a 686px de
   ancho (Redmi Pad). Quien tiene que ceder ancho ahí es el campo, no el botón,
   así que el botón que sigue a un campo no encoge y el campo puede bajar de su
   ancho intrínseco (`min-width: 0`; por defecto es `auto`, y un <input> se
   niega a bajar de unas 20 letras). Medido: 92x65 en 3 líneas → 100x46 en una,
   y la etiqueta larga («Escanear código de barras») sigue partiendo sin empujar
   la página de lado. */
.form-control + .btn { flex-shrink: 0; }
.d-flex > .form-control { min-width: 0; }

.btn:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.btn:active {
    transform: translateY(0);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none;
}

.btn-primary {
    color: white;
    background-color: var(--color-primary);
    border-color: var(--color-primary);
}

.btn-primary:hover:not(:disabled) {
    background-color: var(--color-primary-hover);
}

.btn-secondary {
    color: var(--color-text-primary);
    background-color: var(--color-bg-secondary);
    border-color: var(--color-border-primary);
}

.btn-secondary:hover:not(:disabled) {
    background-color: var(--color-bg-hover);
}

.btn-danger {
    color: white;
    background-color: var(--color-danger);
    border-color: var(--color-danger);
}

.btn-danger:hover:not(:disabled) {
    background-color: var(--color-danger-hover);
}

.btn-sm {
    padding: var(--space-xs) var(--space-md);
    font-size: var(--font-size-sm);
}

.btn-lg {
    padding: var(--space-md) var(--space-xl);
    font-size: var(--font-size-lg);
}

/* ===== Form Controls ===== */

.form-group {
    margin-bottom: var(--space-lg);
}

.form-label {
    display: block;
    margin-bottom: var(--space-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-primary);
}

.form-control {
    width: 100%;
    padding: var(--space-sm) var(--space-md);
    font-size: var(--font-size-base);
    font-family: inherit;
    line-height: 1.5;
    color: var(--color-text-primary);
    background-color: var(--color-bg-primary);
    border: 1px solid var(--color-border-primary);
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
}

.form-control:focus {
    outline: none;
    border-color: var(--color-border-focus);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.form-control:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

textarea.form-control {
    resize: vertical;
    min-height: 100px;
}

select.form-control {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-md) center;
    padding-right: calc(var(--space-md) * 2 + 12px);
}

/* ===== Cards ===== */

.card {
    background-color: var(--color-bg-primary);
    border: 1px solid var(--color-border-primary);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
}

/* Tarjeta entera tocable: el ::after del enlace principal (.card-link) cubre
   la tarjeta; cualquier otro enlace o botón dentro queda por encima. */
.item-card,
.store-card,
.buy-card {
    position: relative;
}

.card-link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
}

.item-card a:not(.card-link),
.item-card button,
.store-card a:not(.card-link),
.store-card button,
.buy-card a:not(.card-link),
.buy-card button {
    position: relative;
    z-index: 2;
}

.card-header {
    padding: var(--space-lg);
    border-bottom: 1px solid var(--color-border-primary);
    background-color: var(--color-bg-secondary);
}

.card-body {
    padding: var(--space-lg);
}

.card-footer {
    padding: var(--space-lg);
    border-top: 1px solid var(--color-border-primary);
    background-color: var(--color-bg-secondary);
}

/* ===== Container & Layout ===== */

.container {
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

.container-fluid {
    width: 100%;
    padding: 0 var(--space-lg);
}

.row {
    display: flex;
    flex-wrap: wrap;
    margin: 0 calc(var(--space-md) * -1);
}

.col {
    flex: 1;
    padding: 0 var(--space-md);
}

/* Columnas con ancho. Se usaban en ~10 páginas (col-12, col-md-6…) pero no
   tenían CSS: el margen negativo de `.row` sacaba el texto al borde de la
   pantalla en el móvil. Móvil = una columna; desde 768px, las de `md`; desde
   1024px, las de `lg`. */
.col-12, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-9,
.col-md-12, .col-lg-4 {
    box-sizing: border-box;
    padding: 0 var(--space-md);
    flex: 0 0 100%;
    max-width: 100%;
    min-width: 0;
}
@media (min-width: 768px) {
    .col-md-3  { flex: 0 0 25%;        max-width: 25%; }
    .col-md-4  { flex: 0 0 33.3333%;   max-width: 33.3333%; }
    .col-md-5  { flex: 0 0 41.6667%;   max-width: 41.6667%; }
    .col-md-6  { flex: 0 0 50%;        max-width: 50%; }
    .col-md-7  { flex: 0 0 58.3333%;   max-width: 58.3333%; }
    .col-md-9  { flex: 0 0 75%;        max-width: 75%; }
    .col-md-12 { flex: 0 0 100%;       max-width: 100%; }
}
@media (min-width: 1024px) {
    .col-lg-4  { flex: 0 0 33.3333%;   max-width: 33.3333%; }
}

/* ===== Navigation ===== */


/* "Get the app" button in the top bar. Compact, and icon-only on narrow
   screens so it never pushes the brand or the hamburger out of the bar.
   Temporary: remove with js/components/apk-button.js once the app is on Play. */
.help-navbar-btn { margin-right: var(--space-sm); white-space: nowrap; }
/* La guía dentro de la app (#/help): el marco ocupa lo que queda entre la
   barra de arriba y la de acciones de abajo. */
.help-frame {
    width: 100%; height: calc(100vh - 240px); min-height: 360px;
    border: 1px solid var(--color-border-primary); border-radius: var(--radius-md);
    background: #fff;
}
/* El icono de ayuda: un SVG que hereda el color del texto del botón, en vez del
   emoji «❓», que lo pintaba la fuente del sistema —rojo, con su propio tamaño—
   y era lo único de la barra que no seguía el tema. `em` y no `px` para que
   crezca con la letra del botón. */
.help-navbar-icon {
    width: 1.05em; height: 1.05em; vertical-align: -0.16em;
    margin-right: 0.4em; flex: none;
    fill: none; stroke: currentColor; stroke-width: 2;
    stroke-linecap: round; stroke-linejoin: round;
}
@media (max-width: 480px) {
    .help-navbar-label { display: none; }
    /* Sin etiqueta, el icono queda solo: el margen lo descuadraría. */
    .help-navbar-icon { margin-right: 0; }
}
/* La campana de avisos, junto a «Ayuda» (js/components/notifications.js).
   El número va DENTRO del botón y no flotando encima: nada de capas. */
.notif-navbar-btn { margin-right: var(--space-sm); white-space: nowrap; }
.notif-navbar-btn .notif-count {
    margin-left: 0.3em; min-width: 1.3em; padding: 0 0.35em; border-radius: 999px;
    background: #e53e3e; color: #fff; font-size: 0.75em; font-weight: 700;
    line-height: 1.3em; text-align: center;
}
.notif-row.notif-unread { background: rgba(59, 130, 246, .10); }
/* En un teléfono caben marca, instalar, campana, ayuda y engrane en UNA fila
   solo si los botones van en icono: sin esto el engrane bajaba a otra línea. */
@media (max-width: 480px) {
    .install-navbar-label { display: none; }
    .notif-navbar-btn, .help-navbar-btn { margin-right: 4px; }
    .navbar .d-flex > .btn-sm { padding-left: 0.5rem; padding-right: 0.5rem; }
    /* Zona de toque de 44 px como el engrane: en el POCO la campana y la
       ayuda medían 36×32 y 33×26 dp (30-sep). Caben: la fila tiene sitio. */
    .notif-navbar-btn, .help-navbar-btn {
        min-width: 44px; min-height: 44px;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 1.15rem;
    }
}
.apk-navbar-btn { margin-left: auto; margin-right: var(--space-sm); white-space: nowrap; }
@media (max-width: 480px) {
    .apk-navbar-label { display: none; }
}

.navbar {
    background-color: var(--color-bg-primary);
    /* Fija arriba, como la barra de iconos lo está abajo. Se iba con el
       desplazamiento y en la pantalla de inicio de sesión desaparecía en
       cuanto uno bajaba al campo de contraseña. Por debajo del cajón lateral
       (950) y de su fondo oscurecido (940), que tienen que taparla. */
    position: sticky;
    top: 0;
    z-index: 930;
    border-bottom: 1px solid var(--color-border-primary);
    /* Top padding absorbs the status bar. From targetSdk 36 (Android 16) an app
       is drawn edge-to-edge and cannot opt out, so the WebView starts BEHIND the
       clock — without this the brand and the hamburger sit under it.
       env() resolves to 0 everywhere else (browsers, older Android), so the
       desktop and web layouts are untouched. Needs viewport-fit=cover on the
       viewport meta, or the inset is always reported as 0. */
    padding: calc(var(--space-md) + env(safe-area-inset-top, 0px)) 0 var(--space-md);
    box-shadow: var(--shadow-sm);
}

/* The navbar spans the full width (page content stays in the 1200px container):
   the brand to the left edge and the gear to the right one. */
.navbar > .container { max-width: none; }

.navbar-brand {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    color: var(--color-text-primary);
}

.navbar-nav {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    list-style: none;
}

.nav-link {
    color: var(--color-text-secondary);
    font-weight: var(--font-weight-medium);
    transition: color var(--transition-fast);
}

.nav-link:hover {
    color: var(--color-text-primary);
}

.nav-link.active {
    color: var(--color-primary);
}

/* Icon affordances before each nav entry (kept in CSS so i18n's textContent
   re-renders never wipe them). Shown on desktop too: text + icon. */
.nav-link[data-route="/"]::before          { content: "🏠 "; }
.nav-link[data-route="/items"]::before     { content: "📦 "; }
.nav-link[data-route="/stores"]::before    { content: "🏪 "; }
.nav-link[data-route="/propanel"]::before  { content: "📊 "; }
.nav-link[data-route="/my-stores"]::before { content: "🏬 "; }
.nav-link[data-route="/profile"]::before   { content: "👤 "; }
.nav-link[data-route="/profile/public"]::before { content: "🌐 "; }
.nav-link[data-route="/settings"]::before  { content: "⚙️ "; }
.nav-link[data-route="/admin"]::before     { content: "🛡️ "; }
.nav-link[data-route="/login"]::before     { content: "🔑 "; }
.navbar-nav button[data-i18n="nav.logout"]::before { content: "🚪 "; }

/* Notification dropdown default width (overridden inside the mobile drawer). */
.notif-panel { width: 320px; }

/* El botón del menú: oculto por omisión, lo muestra la regla de «Responsive» (todos los anchos). */
.navbar-toggle {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    padding: 0 9px;
    background: transparent;
    border: 1px solid var(--color-border-primary);
    border-radius: var(--radius-md);
    cursor: pointer;
}
.navbar-toggle span {
    display: block;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background-color: var(--color-text-primary);
    transition: transform var(--transition-fast), opacity var(--transition-fast);
}
/* Morph the three bars into an X while the drawer is open. */
.navbar-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.navbar-toggle.open span:nth-child(2) { opacity: 0; }
.navbar-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* …pero ya no despliega nada: LLEVA a `#/menu`, que es una página normal.
   El cajón deslizante se retiró tras tres fallos de apilado en tres aparatos
   (ver js/bootstrap.js). Las tres barras se cambian por un engrane DESDE AQUÍ
   —CSS, que sí viaja en el paquete OTA— porque el botón vive en el index.html
   del APK y ése no se puede sustituir en una app ya instalada. */
.navbar-toggle span { display: none; }
.navbar-toggle::before {
    content: "\2699";          /* ⚙ */
    font-size: 1.45rem;
    line-height: 1;
    color: var(--color-text-primary);
}

/* Dimmed backdrop behind the open drawer. */
.navbar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 940;
    background: rgba(0, 0, 0, 0.45);
}
.navbar-backdrop.open { display: block; }

/* …y la barra tiene que subir por encima de ese fondo mientras el cajón está
   abierto. El cajón (`#navbar-nav`) es HIJO de `.navbar`, así que el z-index de
   la barra crea un contexto de apilado y se lo lleva dentro: con la barra en
   930, el 950 del cajón y el 940 del fondo —que cuelga de `#app`, fuera de la
   barra— nunca llegaban a compararse, y decidía 930 < 940. El cajón se veía
   abierto pero quedaba DEBAJO del fondo: cada toque aterrizaba en el fondo,
   cuyo manejador cierra el cajón, de modo que el menú parecía muerto (medido en
   la Xiaomi Redmi Pad, 2026-09-15: `elementFromPoint` sobre el enlace devolvía
   `#navbar-backdrop`). Un `.click()` por guion sí navegaba, porque se salta el
   impacto — por eso el fallo sólo se veía con el dedo.

   Sólo mientras está abierto: el resto del tiempo la barra se queda en 930, por
   debajo de modales y avisos (≥999). Y va en CSS a propósito, que es lo único
   que el OTA puede cambiar en una app ya instalada; el HTML no viaja. */
body.drawer-open .navbar { z-index: 960; }

/* …y el BOTON tiene que quedar por encima del cajon, que es su hermano dentro
   de esa misma barra.

   El cajon ocupa 80vw pegado a la derecha — exactamente donde vive la
   hamburguesa. Abierto el cajon, el boton (estatico, z-index `auto`) quedaba
   DEBAJO de un panel opaco de 950: la X ni se veia, y tocarla no cerraba nada
   porque el toque aterrizaba en `#navbar-nav`, cuyo manejador solo cierra si
   caes sobre un enlace. Con el fondo reducido a la franja de 20% que queda a la
   izquierda, la unica salida era el boton fisico de atras: el menu parecia
   muerto (medido en la portada a 360px, 2026-09-21: `elementFromPoint` sobre el
   centro del boton devolvia `navbar-nav`).

   `position: relative` porque un z-index no pinta nada sobre un elemento
   estatico. Y solo mientras esta abierto: el resto del tiempo el boton no
   necesita apilarse sobre nada. */
body.drawer-open .navbar-toggle { position: relative; z-index: 960; }

/* ===== Alert ===== */

.alert {
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-lg);
    border: 1px solid transparent;
}

.alert-info {
    color: var(--color-info);
    background-color: var(--color-info-light);
    border-color: var(--color-info);
}

.alert-success {
    color: var(--color-secondary);
    background-color: var(--color-secondary-light);
    border-color: var(--color-secondary);
}

.alert-warning {
    color: var(--color-warning);
    background-color: var(--color-warning-light);
    border-color: var(--color-warning);
}

.alert-danger {
    color: var(--color-danger);
    background-color: var(--color-danger-light);
    border-color: var(--color-danger);
}

/* ===== Badge ===== */

.badge {
    display: inline-flex;
    align-items: center;
    padding: var(--space-xs) var(--space-sm);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    line-height: 1;
    border-radius: var(--radius-full);
}

.badge-primary {
    color: white;
    background-color: var(--color-primary);
}

.badge-secondary {
    color: var(--color-text-primary);
    background-color: var(--color-bg-tertiary);
}

.badge-success {
    color: white;
    background-color: var(--color-secondary);
}

.badge-danger {
    color: white;
    background-color: var(--color-danger);
}

.badge-warning {
    color: #1a1a1a;
    background-color: var(--color-warning, #f59e0b);
}

/* ===== Loading Spinner ===== */

.spinner {
    display: inline-block;
    width: 1.5rem;
    height: 1.5rem;
    border: 2px solid var(--color-border-primary);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

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

/* ===== Theme Toggle Button ===== */

.theme-toggle {
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-secondary);
    border: 1px solid var(--color-border-primary);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.theme-toggle:hover {
    background: var(--color-bg-hover);
    transform: translateY(-1px);
}

.theme-toggle .icon {
    font-size: var(--font-size-lg);
    margin-right: var(--space-xs);
}

/* ===== Utility Classes ===== */

.d-none { display: none; }
.d-block { display: block; }
.d-flex { display: flex; }
/* Título a un lado y acción al otro: si no caben, se pasa a dos líneas en vez
   de estirar la fila más ancha que la pantalla. `justify-between` sin esto es
   lo que hacía que la pantalla de la tienda se moviera de lado. */
.d-flex.justify-between { flex-wrap: wrap; gap: var(--space-sm); }
.d-inline-flex { display: inline-flex; }

.flex-column { flex-direction: column; }
.flex-row { flex-direction: row; }
.flex-wrap { flex-wrap: wrap; }
.align-center { align-items: center; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.gap-sm { gap: var(--space-sm); }
.gap-md { gap: var(--space-md); }
.gap-lg { gap: var(--space-lg); }

.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }

.mt-0 { margin-top: 0; }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }
.mt-xl { margin-top: var(--space-xl); }

.mb-0 { margin-bottom: 0; }
.mb-sm { margin-bottom: var(--space-sm); }
.mb-md { margin-bottom: var(--space-md); }
.mb-lg { margin-bottom: var(--space-lg); }
.mb-xl { margin-bottom: var(--space-xl); }

.w-full { width: 100%; }
.h-full { height: 100%; }

/* ===== Responsive ===== */

@media (max-width: 768px) {
    .container {
        padding: 0 var(--space-md);
    }

    .row {
        flex-direction: column;
    }

    h1 { font-size: var(--font-size-3xl); }
    h2 { font-size: var(--font-size-2xl); }
    h3 { font-size: var(--font-size-xl); }
}

/* ===== El menú en línea ya no se pinta: en todos los anchos, el engrane =====
   Hasta el 2026-10-06 los escritorios de más de 1320px pintaban las entradas
   en la barra. Con sesión son 15 más «Salir» y no caben ni a 1920px: las
   palabras se partían en dos renglones y «Salir» quedaba en vertical, letra
   por letra (reportado en Firefox ESR 140; en Chrome pasaba igual). Ahora el
   engrane lleva a `#/menu` en cualquier ancho, como en el teléfono. Las reglas
   de abajo eran las del cajón lateral, y el cajón ya no se abre (ver
   js/bootstrap.js): lo que queda de ellas es esconder la lista de la barra. */
@media all {
    .navbar-toggle { display: flex; }

    .navbar-nav {
        position: fixed;
        top: 0;
        right: 0;
        /* 100dvh y no 100vh: en Android de borde a borde, 100vh es la altura
           del hueco ENTERO, recortes incluidos, así que el cajón se extendía
           por debajo de las dos barras. dvh sigue al hueco visible —y también
           al teclado, que es la otra vez que esto se nota. */
        height: 100dvh;
        width: 80vw;
        min-width: 260px;
        max-width: 330px;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: var(--space-md);
        /* Los recortes de pantalla, arriba y abajo.

           A partir de targetSdk 36 la aplicación se dibuja de borde a borde y
           no puede renunciar a ello, así que este cajón empieza DETRÁS del
           reloj y termina DETRÁS de la barra de gestos. Antes se apoyaba en que
           --space-3xl fuera mayor que la barra de estado, lo cual funcionaba
           por casualidad y no por diseño; y el borde inferior no contemplaba
           nada, de modo que la última opción del menú quedaba bajo la barra de
           gestos, que es justo donde un dedo no puede pulsarla.

           env() vale 0 en el navegador y en Android antiguos, así que la web y
           el escritorio no cambian. */
        padding: calc(var(--space-3xl) + env(safe-area-inset-top, 0px))
                 var(--space-lg)
                 calc(var(--space-lg) + env(safe-area-inset-bottom, 0px));
        background-color: var(--color-bg-primary);
        border-left: 1px solid var(--color-border-primary);
        box-shadow: var(--shadow-lg);
        transform: translateX(100%);
        transition: transform var(--transition-base);
        z-index: 950;
        overflow-y: auto;
    }
    .navbar-nav.open { transform: translateX(0); }

    .navbar-nav > li { width: 100%; }

    .nav-link {
        display: block;
        padding: var(--space-sm) 0;
        font-size: var(--font-size-lg);
    }

    /* The auth area is a horizontal d-flex on desktop — stack it in the drawer. */
    .navbar-nav .d-flex {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-md);
        width: 100%;
    }
    /* Full-width Logout (direct child). */
    .navbar-nav .d-flex > .btn { width: 100%; justify-content: center; }

    /* The bell wrap spans the drawer so its dropdown can anchor to the full
       width, but the bell button itself stays a compact left-aligned icon. */
    .navbar-nav .notif-bell { align-self: stretch; width: 100%; text-align: left; }
    .navbar-nav .notif-bell > .btn { width: auto; }
    .navbar-nav .notif-panel {
        width: 100%;
        right: 0;
        left: auto;
        max-height: 60vh;
        overflow-y: auto;
    }
    /* Narrow panel: let the header wrap so "Mark all read" never clips. */
    .navbar-nav .notif-panel .notif-panel-head { flex-wrap: wrap; }

    /* Prevent body scroll-through while the drawer is open. */
    body.drawer-open { overflow: hidden; }
}

/* El mapa (Leaflet) pone sus controles de zoom en z-index 1000 y sus capas en
   400-700: al desplazar la página pasaban POR ENCIMA de la barra de arriba
   (930) y tapaban «JamboQR» (visto en la app, BlissOS, 2026-09-24).
   `isolation` encierra todo eso en el contexto del propio mapa: dentro sigue
   su orden, fuera cuenta como un elemento corriente de la página. */
.leaflet-container { isolation: isolate; }

/* Derecha a izquierda (ar, fa, he): js/core/i18n.js pone dir="rtl" en <html> y
   el texto, los flex y la alineación por defecto se invierten solos. Aquí solo
   lo que está escrito con left/right fijos. Con [dir] y no con propiedades
   lógicas (margin-inline-*) porque los WebView viejos no las conocen. */
[dir="rtl"] .home-menu-link,
[dir="rtl"] .accordion-header,
[dir="rtl"] .navbar-nav .notif-bell { text-align: right; }
[dir="rtl"] .plan-features li { padding-left: 0; padding-right: 1.5em; }
[dir="rtl"] .plan-features li::before { left: auto; right: 0; }
[dir="rtl"] .scanner-info ul { padding-left: 0; padding-right: var(--space-lg); }
[dir="rtl"] select.form-control {
    background-position: left var(--space-md) center;
    padding-right: var(--space-md);
    padding-left: calc(var(--space-md) * 2 + 12px);
}
[dir="rtl"] .help-navbar-btn,
[dir="rtl"] .notif-navbar-btn { margin-right: 0; margin-left: var(--space-sm); }
[dir="rtl"] .help-navbar-icon { margin-right: 0; margin-left: 0.4em; }
[dir="rtl"] .notif-navbar-btn .notif-count { margin-left: 0; margin-right: 0.3em; }
[dir="rtl"] .apk-navbar-btn { margin-left: var(--space-sm); margin-right: auto; }
@media (max-width: 480px) {
    [dir="rtl"] .help-navbar-icon { margin-left: 0; }
    [dir="rtl"] .notif-navbar-btn, [dir="rtl"] .help-navbar-btn { margin-left: 4px; }
}
[dir="rtl"] .toast { border-left: 0; border-right: 4px solid; }
[dir="rtl"] .input-icon { left: auto; right: 0.875rem; }
[dir="rtl"] .input-group .form-control { padding-left: 0.875rem; padding-right: 2.5rem; }
[dir="rtl"] .radio-label input[type="radio"] { margin-right: 0; margin-left: 0.5rem; }
/* Mapas, códigos y direcciones van siempre de izquierda a derecha. */
[dir="rtl"] .leaflet-container { direction: ltr; }

/* Panel de admin en un teléfono: las tablas tienen 6–8 columnas y empujaban la
   página entera hacia un lado (y los botones de acción se partían letra a
   letra). Cada tabla se desplaza dentro de su caja; vale para LTR y RTL. */
.admin-page .table { display: block; max-width: 100%; overflow-x: auto; }
.admin-page .table .btn { white-space: nowrap; }
/* Sin esto las celdas no tenían relleno: con la tabla vacía (Permisos sin
   permisos) los títulos se leían como una sola frase. */
.admin-page .table th,
.admin-page .table td {
    padding: 0.4rem 0.6rem;
    vertical-align: top;
    text-align: start;
    border-bottom: 1px solid var(--color-border-primary);
}
.admin-page .table th { white-space: nowrap; }
