/* ─────────────────────────────────────────────────────────────
   Marketplace (nombre provisorio) — hoja de estilos
   Shell compartido (Fase 0.5): tokens, layout base, auth, botones,
   formularios, modal genérico, badges. Cada fase agrega sus propias
   secciones a partir de acá — sin sobre-diseñar por adelantado.
   ───────────────────────────────────────────────────────────── */

:root {
    /* ═══ SISTEMA DE DISEÑO TRIVENTA — primitivos de marca ═══════════════════
       Handoff design_handoff_triventa/. Dos paletas comparten un logo maestro:
       · Corporativa (navy/azul) → empresas + admin.
       · Viva (azul eléctrico/turquesa/naranjo/violeta) → vendedores + misiones.
       Los tokens --color-* de abajo (que consume TODA la app) se remapean a
       estos valores → re-skin de marca sin reescribir cada regla. Antes estaban
       alineados al azure de Tabler (#066fd1); hoy a Triventa. Ver SESSION_LOG. */

    /* Master (logo) — nunca se reordena ni se degrada en gradiente */
    --triventa-navy: #0b1d3b;      /* Azul Triventa — wordmark, titulares */
    --triventa-green: #10b981;     /* Verde Territorio — confirmación */
    --triventa-orange: #f97316;    /* Naranjo Impulso — acento comercial */

    /* Paleta A — Corporativa */
    --corp-navy: #0b1d3b;
    --corp-blue: #1d4ed8;          /* Azul Ejecutivo — primario interactivo */
    --corp-blue-dark: #1740b8;     /* hover del primario */
    --corp-teal: #0f766e;

    /* Paleta B — Viva */
    --vivid-navy: #071a3d;
    --vivid-blue: #2563eb;         /* Azul Eléctrico */
    --vivid-teal: #00b8a9;         /* Turquesa Territorio — disponibles */
    --vivid-orange: #ff6b00;       /* Naranjo Energía — misiones, urgencias */
    --ai-purple: #7c3aed;          /* Violeta IA — SOLO para IA */
    --opportunity-yellow: #facc15; /* Amarillo Oportunidad */

    /* Rampa neutra (slate) */
    --slate-900: #0f172a;
    --slate-800: #1e293b;
    --slate-700: #334155;
    --slate-600: #475569;
    --slate-500: #64748b;
    --slate-400: #94a3b8;
    --slate-300: #cbd5e1;
    --slate-200: #e2e8f0;
    --slate-100: #f1f5f9;
    --slate-50: #f8fafc;

    /* Tints (fondos suaves de estado) */
    --tint-info: #e8eefd;
    --tint-success: #e7f7f0;
    --tint-warning: #fef7dc;
    --tint-danger: #fce8ec;
    --tint-purple: #f0eafb;
    --tint-orange: #feeedd;

    /* Marcadores del mapa (semántica fija, guía §13) */
    --marker-prospect: #2563eb;  /* prospecto — azul */
    --marker-saved: #7c3aed;     /* guardado — violeta */
    --marker-client: #10b981;    /* cliente — verde */
    --marker-mission: #ff6b00;   /* misión — naranjo */

    /* ═══ Tokens de la app (nombres estables) → valores Triventa ═════════════ */
    --color-bg: #f8fafc;               /* slate-50 */
    --color-surface: #ffffff;
    --color-border: #e2e8f0;           /* slate-200 */
    --color-text: #1e293b;             /* slate-800 — texto primario */
    --color-text-muted: #64748b;       /* slate-500 — secundario/muted */
    --color-heading: #0b1d3b;          /* navy — titulares (Poppins) */
    --color-primary: #1d4ed8;          /* corp-blue — Azul Ejecutivo */
    --color-primary-dark: #1740b8;
    --color-primary-soft: rgba(29, 78, 216, 0.1);
    --color-success: #10b981;          /* Verde Territorio */
    --color-success-bg: #e7f7f0;       /* tint-success */
    --color-warning: #8a6d05;          /* fg de aviso Triventa (legible en claro) */
    --color-warning-bg: #fef7dc;       /* tint-warning */
    --color-danger: #e11d48;           /* status-danger (rose) */
    --color-danger-bg: #fce8ec;        /* tint-danger */
    --color-neutral-bg: #f1f5f9;       /* slate-100 */

    /* Radios: app 8px (--radius-md dominante), tarjetas 12px, badges pill */
    --radius: 8px;
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;
    --radius-2xl: 24px;
    --radius-pill: 999px;

    /* Sombras Triventa (slate suave, heredadas de Adminox) */
    --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.06);
    --shadow-sm: 0 1px 3px rgba(154, 161, 171, 0.20);
    --shadow-md: 0 6px 18px rgba(154, 161, 171, 0.20);
    --shadow-lg: 0 18px 40px rgba(11, 29, 59, 0.12);
    --shadow-navy: 0 24px 60px rgba(7, 26, 61, 0.28);

    /* Tipografía: Inter (texto/UI) + Poppins (titulares/cifras/botones) */
    --font: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-text: var(--font);
    --font-display: 'Poppins', var(--font);
    --font-mono: "SF Mono", "Fira Code", Consolas, monospace;

    /* ── Alias semánticos (semantic.css del handoff) — los consumen componentes
       y el topbar. Apuntan a los tokens de arriba: una sola fuente de verdad. ── */
    --text-heading: var(--color-heading);
    --text-primary: var(--color-text);
    --text-secondary: var(--slate-600);
    --text-muted: var(--color-text-muted);
    --text-on-dark: #ffffff;
    --surface-page: #ffffff;
    --surface-soft: var(--slate-50);
    --surface-card: var(--color-surface);
    --surface-navy: var(--triventa-navy);
    --border-subtle: var(--color-border);
    --border-strong: var(--slate-300);
    --border-focus: var(--corp-blue);
    --app-topbar-bg: #ffffff;
    --app-topbar-border: var(--color-border);
    --app-search-fill: var(--slate-50);
    --app-card-bg: #ffffff;
}

/* ── Reset suave ──────────────────────────────────────────── */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: var(--font);
    font-size: 15px;
    line-height: 1.5;
    color: var(--color-text);
    background-color: var(--color-bg);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

code {
    font-family: var(--font-mono);
    font-size: 0.9em;
    background: var(--color-neutral-bg);
    padding: 1px 5px;
    border-radius: 3px;
}

/* ── Pantalla de autenticación ────────────────────────────── */
.auth-screen {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    min-height: 100vh;
}

/* CRÍTICO: el atributo `hidden` debe SIEMPRE poder ocultar un elemento.
   Varios componentes fijan display:flex/inline-flex (.modal-overlay, .btn,
   .loading-banner, .app-header), que gana por especificidad al `display:none`
   del user-agent para `[hidden]`. Esta regla global lo restablece — sin ella,
   ocultar un botón con `el.hidden = true` no tiene efecto (ej. "+ Tomar
   pedido", que debe verse solo para vendedores). */
[hidden] {
    display: none !important;
}

.auth-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-md);
    padding: 2rem;
    width: 100%;
    max-width: 420px;
}

.auth-logo {
    font-size: 2.5rem;
    text-align: center;
    margin-bottom: 0.5rem;
}

.auth-card h2 {
    text-align: center;
    font-size: 1.4rem;
    color: var(--color-primary);
    margin-bottom: 0.25rem;
}

.auth-sub {
    text-align: center;
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-bottom: 1.25rem;
}

.auth-warning {
    background: var(--color-warning-bg);
    color: var(--color-warning);
    padding: 0.75rem 1rem;
    border-radius: var(--radius);
    font-size: 0.82rem;
    margin-bottom: 1rem;
    line-height: 1.4;
}

.auth-msg {
    margin-top: 0.75rem;
    font-size: 0.85rem;
    min-height: 1.2em;
}

.auth-msg.error { color: var(--color-danger); }
.auth-msg.ok { color: var(--color-success); }

/* ── Paso del código de verificación ───────────────────────── */
/* Grande, monoespaciado y separado: se teclea mirando el correo, y confundir
   0/O o 1/l es lo que hace fallar el intento. */
.auth-code-input {
    font-family: var(--font-mono);
    font-size: 1.5rem;
    letter-spacing: 0.4em;
    text-align: center;
    padding: 0.7rem !important;
}

.auth-code-hint {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin-top: 0.4rem;
    line-height: 1.4;
}

.auth-code-hint a {
    color: var(--color-primary);
    cursor: pointer;
    font-weight: 600;
}

.auth-code-hint a:hover { text-decoration: underline; }

/* Durante la espera NO es un enlace: es texto. Un enlace deshabilitado igual
   invita a hacerle clic, y el clic que no hace nada se lee como app rota. */
.auth-resend-wait {
    color: var(--color-text-muted);
    font-weight: 600;
    cursor: default;
}

/* "Recordar este equipo" — solo en el desafío de 2FA. */
.auth-remember {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.7rem;
    font-weight: 400;
    font-size: 0.85rem;
    color: var(--color-text);
    cursor: pointer;
}

/* ── Verificación en dos pasos (Mi cuenta) ─────────────────── */
.tf-state {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    font-size: 0.88rem;
    margin-bottom: 0.3rem;
}

.tf-badge {
    background: var(--color-success-bg);
    color: var(--color-success);
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
}

.tf-badge.is-off {
    background: var(--color-neutral-bg);
    color: var(--color-text-muted);
}

.tf-devices {
    margin-top: 0.4rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

.tf-device {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 0.7rem;
    font-size: 0.85rem;
}

.tf-device + .tf-device {
    border-top: 1px solid var(--color-border);
}

/* ── Los dos métodos: app autenticadora y correo ───────────── */
.tf-method {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.75rem 0.85rem;
    margin-top: 0.7rem;
}

.tf-method-head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.25rem;
}

/* "Recomendada" — distinta del badge de estado: eso dice si está activa, esto
   dice cuál conviene. Si compartieran estilo se leerían como lo mismo. */
.tf-tag {
    border: 1px solid var(--color-primary);
    color: var(--color-primary);
    padding: 0.1rem 0.45rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
}

/* Desactivar y regenerar van PLEGADOS: son la salida de emergencia, no lo que
   uno viene a hacer. Abiertos, cada método mostraría una caja de contraseña
   compitiendo con el botón que sí importa. */
.tf-details {
    margin-top: 0.6rem;
}

.tf-details > summary {
    cursor: pointer;
    font-size: 0.82rem;
    color: var(--color-text-muted);
}

.tf-warn {
    color: var(--color-warning, #b45309);
    font-size: 0.85rem;
    font-weight: 600;
}

.tf-backup-line {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    font-size: 0.85rem;
    margin-top: 0.5rem;
}

/* ── Enrolar la app: QR + clave a mano ─────────────────────── */
.tf-enroll {
    margin-top: 0.8rem;
    padding-top: 0.8rem;
    border-top: 1px solid var(--color-border);
}

.tf-steps {
    margin: 0 0 0.7rem 1rem;
    padding: 0;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.tf-steps li {
    margin-bottom: 0.2rem;
}

.tf-enroll-body {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;      /* en el teléfono el QR se va arriba y la clave abajo */
    align-items: flex-start;
}

.tf-qr {
    width: 160px;
    height: 160px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    /* El QR se lee por CONTRASTE. En tema oscuro un SVG con fondo transparente
       queda negro sobre negro y la cámara no ve nada: el fondo blanco es
       funcional, no decorativo. */
    background: #fff;
    padding: 6px;
}

.tf-secret-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}

.tf-secret {
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: 0.9rem;
    letter-spacing: 0.08em;
    background: var(--color-neutral-bg);
    padding: 0.3rem 0.5rem;
    border-radius: var(--radius);
    word-break: break-all;
}

/* ── Link de invitación (se muestra UNA vez) ───────────────── */
.invite-link-box {
    border: 1px solid var(--color-primary);
    border-radius: var(--radius);
    padding: 0.7rem 0.8rem;
    margin-top: 0.8rem;
}

.invite-link-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0.5rem 0;
}

.invite-link {
    flex: 1;
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: 0.78rem;
    background: var(--color-neutral-bg);
    padding: 0.4rem 0.5rem;
    border-radius: var(--radius);
    /* El link es largo y lleva un token: tiene que verse ENTERO para poder
       comprobar que se copió bien. Cortado con puntos suspensivos, nadie sabe si
       lo que tiene en el portapapeles está completo. */
    word-break: break-all;
}

/* ── Códigos de respaldo ───────────────────────────────────── */
.tf-codes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 0.4rem;
    margin-top: 0.8rem;
}

.tf-codes code {
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    background: var(--color-neutral-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.4rem 0.5rem;
    text-align: center;
    letter-spacing: 0.06em;
}

/* ── Respuesta al código: bien / mal ────────────────────────
   La señal va por TRES canales a la vez (sacudida + color + texto), nunca solo
   uno: quien no ve el color, lee el texto; quien tiene el movimiento reducido
   (mareos), igual ve el borde rojo y lee el mensaje. La animación REFUERZA, no
   informa sola. */
@keyframes auth-shake {
    10%, 90% { transform: translateX(-2px); }
    20%, 80% { transform: translateX(4px); }
    30%, 50%, 70% { transform: translateX(-7px); }
    40%, 60% { transform: translateX(7px); }
}

.auth-card.is-shake {
    animation: auth-shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

.auth-code-input.is-error {
    border-color: var(--color-danger);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.15);
}

.auth-code-input.is-ok {
    border-color: var(--color-success);
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
    color: var(--color-success);
}

/* Confirmación al acertar: el visto se ve antes de entrar, para que el salto a
   la app no parezca un parpadeo sin explicación. */
.auth-ok {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
    font-weight: 700;
    color: var(--color-success);
}

.auth-ok-check {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--color-success);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9rem;
    animation: auth-pop 0.35s ease-out;
}

@keyframes auth-pop {
    0% { transform: scale(0.3); opacity: 0; }
    70% { transform: scale(1.15); }
    100% { transform: scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .auth-card.is-shake { animation: none; }
    .auth-ok-check { animation: none; }
}

.auth-switch {
    text-align: center;
    font-size: 0.85rem;
    margin-top: 1rem;
    color: var(--color-text-muted);
}

.auth-switch a {
    color: var(--color-primary);
    cursor: pointer;
    font-weight: 600;
    text-decoration: none;
}

.auth-switch a:hover {
    text-decoration: underline;
}

/* ── Header con usuario ───────────────────────────────────── */
.app-header {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 1rem 1.5rem;
    box-shadow: var(--shadow-sm);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}

.app-header h1 {
    font-size: 1.35rem;
    font-weight: 700;
    color: var(--color-primary);
}

.subtitle {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    margin-top: 2px;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.user-badge {
    font-size: 0.82rem;
    color: var(--color-text-muted);
    background: var(--color-neutral-bg);
    padding: 0.3rem 0.7rem;
    border-radius: 20px;
    font-weight: 600;
}

/* ── Navegación ───────────────────────────────────────────── */
.tabs {
    display: flex;
    gap: 0;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 0 1.5rem;
    overflow-x: auto;
}

.tab {
    background: none;
    border: none;
    border-bottom: 3px solid transparent;
    padding: 0.85rem 1.2rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.15s, border-color 0.15s;
}

.tab:hover {
    color: var(--color-text);
}

.tab-active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

/* ── Layout principal ─────────────────────────────────────── */
.app-main {
    flex: 1;
    padding: 1.5rem;
    max-width: 1400px;
    width: 100%;
    margin: 0 auto;
}

.panel {
    display: none;
    animation: fadeIn 0.2s ease;
}

.panel-active {
    display: block;
}

/* El título de cada pantalla es redundante: la pestaña activa de arriba ya dice en
   qué sección estás ("Inicio es Inicio"). Se oculta el <h2> que es HIJO DIRECTO del
   panel (el título de página). Los <h2> de modales (.modal-header) y de tarjetas de
   contenido (misiones, detalle de pedido) van más adentro, así que NO se tocan. Los
   pocos títulos anidados en un header con botón (Empresas, Misiones) y el de
   Oportunidades se quitan en app.js, porque no son hijos directos del panel. */
.panel > h2 {
    display: none;
}

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

/* ── Formularios ──────────────────────────────────────────── */
form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-text);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
input[type="tel"],
select,
textarea {
    width: 100%;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-family: var(--font);
    background: var(--color-surface);
    color: var(--color-text);
    transition: border-color 0.15s, box-shadow 0.15s;
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-soft);
}

textarea {
    resize: vertical;
}

/* ── Contraseñas: ojito para ver + medidor de seguridad ─────
   El ojito se inyecta por JS en TODO input[type=password] (ver
   enhancePasswordFields). El medidor solo donde la persona ELIGE una
   contraseña nueva (opt-in con data-strength). */
.pw-wrap {
    width: 100%;
}

/* Envuelve SOLO al input: es la referencia del ojito. Si el ojito se
   posicionara contra .pw-wrap (que además lleva el medidor), su height:100%
   abarcaría input+medidor y quedaría empujado abajo, fuera del campo. */
.pw-field {
    position: relative;
}

/* Espacio a la derecha para que el texto no pase por debajo del ojito. */
.pw-field input {
    padding-right: 2.6rem;
}

.pw-eye {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    width: 2.6rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    opacity: 0.55;
    /* El input hermano ya tiene su propio foco; este botón no debe taparlo. */
    border-radius: 0 var(--radius) var(--radius) 0;
}

.pw-eye:hover { opacity: 1; }

.pw-eye:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
    opacity: 1;
}

.pw-meter {
    margin-top: 0.4rem;
}

.pw-meter-track {
    height: 4px;
    border-radius: 999px;
    background: var(--color-neutral-bg);
    overflow: hidden;
}

.pw-meter-fill {
    height: 100%;
    width: 0;
    border-radius: 999px;
    transition: width 0.2s ease, background-color 0.2s ease;
    background: var(--color-danger);
}

.pw-meter-text {
    margin-top: 0.25rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-text-muted);
}

/* Rojo → ámbar → verde. El color es la señal; el texto explica por qué. */
.pw-meter.is-s0 .pw-meter-fill { background: var(--color-danger); }
.pw-meter.is-s1 .pw-meter-fill { background: var(--color-danger); }
.pw-meter.is-s2 .pw-meter-fill { background: var(--color-warning); }
.pw-meter.is-s3 .pw-meter-fill { background: var(--color-success); }
.pw-meter.is-s4 .pw-meter-fill { background: var(--color-success); }

.pw-meter.is-s0 .pw-meter-text,
.pw-meter.is-s1 .pw-meter-text { color: var(--color-danger); }
.pw-meter.is-s2 .pw-meter-text { color: var(--color-warning); }
.pw-meter.is-s3 .pw-meter-text,
.pw-meter.is-s4 .pw-meter-text { color: var(--color-success); }

@media (prefers-reduced-motion: reduce) {
    .pw-meter-fill { transition: none; }
}

/* ── Checkboxes / radios: tamaño cómodo de clickear ────────── */
input[type="checkbox"],
input[type="radio"] {
    width: 16px;
    height: 16px;
    flex: none;
}

/* ── Botones ──────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.6rem 1.1rem;
    border: none;
    border-radius: var(--radius);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, opacity 0.15s;
}

.btn-primary {
    background: var(--color-primary);
    color: #fff;
}

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

.btn-secondary {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
}

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

.btn-danger {
    background: var(--color-danger);
    color: #fff;
}

.btn-danger:hover {
    background: #b91c1c;
}

/* Colores semánticos de acción (convención del usuario): VERDE = aceptar/
   confirmar/positivo · ROJO = cancelar/destructivo · AZUL (primary) = lo demás. */
/* Regla de marca Triventa: los botones VERDES (y naranjos) llevan texto NAVY,
   no blanco. No es solo estética: verde #10b981 con texto blanco no alcanza el
   contraste AA; con navy sí. */
.btn-success {
    background: var(--color-success);
    color: var(--triventa-navy);
}
.btn-success:hover { background: #0ea271; }

.btn-warning {
    background: var(--color-warning);
    color: #fff;
}
.btn-warning:hover { background: #b45309; }

/* "Cancelar"/descartar: rojo pero de contorno (no compite con el verde de la
   acción positiva ni con el rojo sólido de lo destructivo). */
.btn-danger-soft {
    background: var(--color-surface);
    color: var(--color-danger);
    border: 1px solid var(--color-danger);
}
.btn-danger-soft:hover { background: var(--color-danger-bg); }

.btn-sm {
    padding: 0.35rem 0.7rem;
    font-size: 0.8rem;
}

/* Un botón que en realidad es un <a> (los que SALEN de la app: Google Maps,
   descargar un documento). Sin esto hereda el subrayado de enlace y se lee como
   texto suelto en medio de una fila de botones. */
a.btn { text-decoration: none; }

.btn-xs {
    padding: 0.25rem 0.55rem;
    font-size: 0.75rem;
}

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

/* ── Cajas de estado ──────────────────────────────────────── */
.status-box {
    margin-top: 0.75rem;
    padding: 0.65rem 0.8rem;
    border-radius: var(--radius);
    font-size: 0.85rem;
}

.status-info {
    background: var(--color-neutral-bg);
    color: var(--color-text);
}

.status-success,
.status-ok {
    background: var(--color-success-bg);
    color: var(--color-success);
}

.status-warning {
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

.status-error {
    background: var(--color-danger-bg);
    color: var(--color-danger);
}

/* ── Badges ───────────────────────────────────────────────── */
.badge {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: 20px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.badge-yes {
    background: var(--color-success-bg);
    color: var(--color-success);
}

.badge-no {
    background: var(--color-neutral-bg);
    color: var(--color-text-muted);
}

.badge-unknown,
.badge-warn {
    background: var(--color-warning-bg);
    color: var(--color-warning);
}
.badge-info {
    background: var(--color-primary-soft);
    color: var(--color-primary);
}
.badge-danger {
    background: var(--color-danger-bg);
    color: var(--color-danger);
}

/* Badge que ESCONDE información y la despliega al tocarlo (hoy: el motivo de la
   cancelación). Evita llenar el pedido de texto: el detalle está a un clic.
   Sin chevron ni ningún otro adorno: el destello ES el indicador. Convención del
   producto (se enseña a los vendedores): **lo que destella esconde información**.
   Por eso destella mientras está plegado y se queda quieto al abrirlo. */
.badge-reveal {
    border: none;
    font-family: inherit;
    cursor: pointer;
    /* .badge fija el resto (padding, radio, tipografía) — acá solo lo que un
       <button> no hereda. */
}

.badge-reveal:hover {
    filter: brightness(0.94);
}

@keyframes badge-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.45); }
    50%      { box-shadow: 0 0 0 5px rgba(220, 38, 38, 0); }
}

.badge-reveal.is-pulsing {
    animation: badge-pulse 1.9s ease-out infinite;
}

/* ── Autoguardado: chip vivo junto a "Guardar" ─────────────────────────
   El formulario se guarda solo mientras la persona escribe; este chip dice
   en qué va (sin guardar / guardando / guardado / error). Discreto a
   propósito: es tranquilidad, no una alarma. */
.autosave-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 0.8rem;
}
.autosave-status {
    font-size: 0.82rem;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--color-text-muted);
}
.autosave-status::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}
.autosave-status.is-dirty  { color: var(--color-text-muted); }
.autosave-status.is-saving { color: var(--color-warning); }
.autosave-status.is-saving::before { animation: autosave-blink 1s ease-in-out infinite; }
.autosave-status.is-saved  { color: var(--color-success); }
.autosave-status.is-blocked,
.autosave-status.is-error  { color: var(--color-danger); }

@keyframes autosave-blink {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
    .autosave-status.is-saving::before { animation: none; }
}

/* Encabezado de sección que despliega su contenido (hoy: "Historial del
   pedido"). Misma convención que los badges: destella mientras esconde algo, y
   se queda quieto cuando hay algo abierto. Clic = abrir/cerrar TODO. */
.section-reveal {
    display: inline-block;
    background: none;
    border: none;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 700;
    color: var(--color-text);
    cursor: pointer;
    padding: 0.2rem 0.55rem;
    /* Aire arriba (lo separa de la caja de estado) y abajo: pegado al primer
       evento del historial se leía como si fuera parte de él. */
    margin: 1.4rem 0 0.85rem -0.55rem;
    border-radius: 10px;
}

.section-reveal:hover {
    background: var(--color-neutral-bg);
}

@keyframes section-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(29, 78, 216, 0.35); }
    50%      { box-shadow: 0 0 0 6px rgba(29, 78, 216, 0); }
}

.section-reveal.is-pulsing {
    animation: section-pulse 1.9s ease-out infinite;
}

/* Variante "inline" del encabezado colapsable: dentro de un toolbar-card (hoy los
   filtros de "Mis órdenes"), sin el margen del contexto del modal, con ícono +
   texto. Mismo destello que "Historial del pedido". */
.section-reveal.reveal-inline {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 0.4rem;
    margin: 0.3rem 0 0.1rem;
    font-size: 0.95rem;
}
.section-reveal.reveal-inline .mp-icon { color: var(--color-text-muted); }

/* Título de un evento del historial: clic → despliega cuándo, quién y el detalle
   de cantidades. No destella (siete títulos parpadeando sería una feria): el que
   avisa es el encabezado de la sección. */
.tl-event {
    background: none;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: inherit;
    font-weight: 700;
    color: var(--color-text);
    text-align: left;
    cursor: pointer;
}

.tl-event:hover {
    color: var(--color-primary);
}

/* La Ficha del establecimiento se abre SOBRE otros modales (ej. desde "Tomar
   pedido", para revisar o corregir los datos del cliente sin perder el pedido a
   medio armar). Vive en el contenedor `#modals`, que va antes en el DOM que los
   modales creados al vuelo: con el z-index por defecto quedaría DEBAJO de ellos. */
#ficha-overlay {
    z-index: 1100;
}

/* ── Progreso de lectura (toda la app) ─────────────────────── */
/* La barra de scroll nativa se ve tosca y le roba ancho al contenido. Se esconde
   —el scroll sigue funcionando igual: rueda, trackpad, teclado, barra espaciadora—
   y su información ("cuánto queda por leer") la da una barra fina que se llena al
   bajar: en la PÁGINA, fija arriba de todo; en cada MODAL, bajo su encabezado.
   Ojo: solo se esconde el scroll VERTICAL de la página y de los modales. Los
   contenedores con scroll horizontal (ej. la tabla de productos angosta)
   conservan su barra: ahí el desplazamiento lateral no se adivina. */
html,
.modal-body {
    scrollbar-width: none;              /* Firefox */
    -ms-overflow-style: none;           /* Edge viejo */
}

html::-webkit-scrollbar,
.modal-body::-webkit-scrollbar {
    width: 0;
    height: 0;
}

.scroll-progress {
    flex: 0 0 auto;
    height: 3px;
    background: var(--color-border);
}

.scroll-progress > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--color-primary);
    transition: width 0.08s linear;
}

/* La de la página va fija arriba de todo (sobre el encabezado), sin fondo: en un
   documento corto no debe verse ni una línea gris de más. */
#page-progress {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1200;
    background: transparent;
}

@media (prefers-reduced-motion: reduce) {
    .scroll-progress > span { transition: none; }
}

/* ── La BARRA DE SCROLL de vuelta, en ESCRITORIO ────────────────
   El público de escritorio pidió la barra de desplazamiento real al costado
   para subir/bajar, en vez de la barrita de progreso de arriba (en pantalla
   grande esa no se siente como "scroll"). SOLO ≥768px: en móvil el scrollbar
   nativo es overlay (no roba ancho) y se deja oculto como estaba.
   Estilizada acorde al tema: fina, pulgar gris redondeado que se oscurece al
   pasar por encima, riel transparente. Gana la cascada por ir DESPUÉS de la
   regla que lo escondía y por venir en una media query. */
@media (min-width: 768px) {
    html {
        scrollbar-width: thin;                   /* Firefox */
        scrollbar-color: #c2c9d2 transparent;
        -ms-overflow-style: auto;
    }
    html::-webkit-scrollbar { width: 12px; }     /* Chrome / Safari / Edge */
    html::-webkit-scrollbar-track { background: transparent; }
    html::-webkit-scrollbar-thumb {
        background: #c2c9d2;
        border-radius: 8px;
        border: 3px solid transparent;           /* aire alrededor → pulgar más fino */
        background-clip: padding-box;
    }
    html::-webkit-scrollbar-thumb:hover { background: #9aa3af; }

    /* Con la barra de vuelta, la barrita de progreso de arriba sobra (era su
       reemplazo). Se apaga en escritorio; en móvil sigue haciendo su trabajo. */
    #page-progress { display: none; }
}

/* ── Sub-pestañas dentro de un panel (Órdenes / Seguimientos) ─ */
.subtabs {
    display: flex;
    flex-wrap: wrap;   /* en móvil, 3 sub-pestañas con contadores no caben en una fila → 2ª fila (antes desbordaban) */
    gap: 0.25rem;
    border-bottom: 1px solid var(--color-border);
    margin-top: 0.75rem;
}

.subtab {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: 0.45rem 0.75rem;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--color-text-muted);
    cursor: pointer;
    white-space: nowrap;   /* la etiqueta no se parte en dos líneas al envolver */
}

.subtab:hover {
    color: var(--color-text);
}

.subtab.is-active {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

/* ── Fila de filtros ──────────────────────────────────────── */
/* Los controles conservan el contenedor de la app (borde, radio, padding y
   tipografía vienen del estilo base de input/select): acá solo se corrige el
   ancho —los campos de formulario son `width:100%` y apilaban un control por
   fila— y se les fija un ALTO común.
   El alto hace falta porque `<input>` y `<select>` NO miden lo mismo con el
   mismo padding: Chrome le reserva al select un alto de línea mayor (2px de
   diferencia), y ni `align-items:stretch` ni `line-height` lo emparejan. Con
   `box-sizing:border-box`, fijar la altura los deja idénticos. */
.filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0.75rem 0 0.5rem;
}

.filter-row .filter-select,
.filter-row .btn {
    height: 2.4rem;
}

/* Ojo con la especificidad: el estilo base apunta a `input[type="search"]`
   (0,1,1), que le gana a una clase suelta (0,1,0) — con `.filter-select` a secas,
   el `width:100%` del formulario seguía ganando y el campo se comía la fila
   entera. `.filter-row .filter-select` (0,2,0) sí manda. */
.filter-row .filter-select {
    margin: 0;
    width: auto;
    min-width: 190px;
    max-width: 100%;
    flex: 0 1 auto;
}

/* Buscador con sugerencias (cliente o RUT). El <datalist> nativo se ve feo y el
   navegador lo posiciona a su antojo: esta lista es de la casa, cae bajo el
   campo y usa el contenedor de la app.

   El componente es reutilizable (lo usan "Mis órdenes" y "Tomar pedido"): acá
   solo se posiciona. El ANCHO depende del contexto — en la fila de filtros crece
   y se queda con el espacio sobrante (es el control más usado y los nombres de
   cliente son largos); dentro de un modal ocupa el ancho completo, como cualquier
   campo de formulario. */
.combo {
    position: relative;
}

.filter-row .combo {
    flex: 1 1 260px;
    min-width: 240px;
    max-width: 460px;
}

/* Dentro del combo, el campo ocupa todo el ancho disponible (el min-width de
   190px es para los controles sueltos de la fila, no para este). */
.filter-row .combo .filter-select {
    width: 100%;
    min-width: 0;
}

.filter-row select.filter-select {
    flex: 0 0 auto;
}

/* `fixed`, no `absolute`: dentro de un modal el cuerpo tiene `overflow:auto` y
   RECORTA cualquier hijo posicionado — la lista salía cortada a una línea. Fija
   escapa del recorte; su posición la calcula el JS desde el campo
   (`positionComboList`) y se recalcula al hacer scroll o redimensionar. */
.combo-list {
    position: fixed;
    /* Más ancha que el campo si hace falta: con el ancho del input, el RUT
       quedaba cortado ("Almacén Don Pepe · …") y era justo lo que hay que ver
       para elegir. */
    width: max-content;
    max-width: min(380px, 90vw);
    z-index: 1150;
    margin: 0;
    padding: 0.25rem;
    list-style: none;
    max-height: 260px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
}

.combo-option {
    padding: 0.45rem 0.6rem;
    border-radius: 6px;
    font-size: 0.85rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.combo-option:hover,
.combo-option.is-active {
    background: var(--color-neutral-bg);
}

.combo-empty {
    padding: 0.45rem 0.6rem;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

/* En móvil ya se apilan igual (no caben en una fila): que ocupen el ancho
   completo en vez de quedar angostos con un hueco al lado. */
@media (max-width: 480px) {
    .filter-row .combo,
    .filter-row .filter-select,
    .filter-row .btn {
        width: 100%;
        min-width: 0;
    }
}

/* ⭐ Seguir una orden: marca personal, se fija en "Mis seguimientos". */
.follow-star {
    background: none;
    border: none;
    padding: 0 0.15rem;
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
    color: var(--color-text-muted);
}

.follow-star:hover {
    color: var(--color-warning);
}

.follow-star.is-on {
    color: var(--color-warning);
}

/* ── Etiquetas personalizadas del cliente ──────────────────── */
/* La ETAPA es un .badge (embudo, fijo); las ETIQUETAS son chips libres que el
   vendedor crea. Color por etiqueta, pintado inline desde TAG_COLORS. */
.tag-chip {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    border-radius: 20px;
    font-size: 0.72rem;
    font-weight: 600;
    white-space: nowrap;
}
.tag-add {
    border: none;
    background: none;
    cursor: pointer;
    line-height: 0;
    padding: 0 0.1rem;
    display: inline-flex;
    align-items: center;
    opacity: 0.75;
}
.tag-add:hover { opacity: 1; }

/* Modal de etiquetas: cada fila es una etiqueta (toggle) + eliminar. */
.tag-manage-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.4rem;
}
.tag-toggle {
    flex: 1;
    text-align: left;
    border: 1px solid;
    border-radius: 20px;
    padding: 0.25rem 0.65rem;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    background: transparent;
}
.tag-toggle:not(.is-on) { opacity: 0.7; }
.tag-toggle:hover { opacity: 1; }
.tag-del {
    border: none;
    background: none;
    cursor: pointer;
    opacity: 0.45;
    font-size: 0.9rem;
    line-height: 1;
}
.tag-del:hover { opacity: 1; }
.tag-swatch {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
}
.tag-swatch.is-sel { outline: 2px solid var(--color-text-muted); outline-offset: 1px; }

/* ── Buscar prospectos: hero de búsqueda + tarjetas de resultado ── */
.search-hero {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
    box-shadow: var(--shadow-sm);
}
.search-hero .search-row {
    display: flex;
    gap: 0.6rem;
    align-items: flex-end;
    flex-wrap: wrap;
}
.search-hero .search-grow { flex: 1; min-width: 220px; }
.search-hero .search-row > div:not(.search-grow) { flex: 1; min-width: 110px; }
.search-hero label {
    display: block;
    font-weight: 600;
    font-size: 0.85rem;
    margin-bottom: 0.3rem;
}
.search-hero input,
.search-hero select { margin: 0; }
.search-advanced summary {
    cursor: pointer;
    color: var(--color-text-muted);
    font-size: 0.85rem;
    list-style: none;
}
.search-advanced summary::-webkit-details-marker { display: none; }

.search-results-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1.25rem;
    min-height: 1.2rem;
}
.search-results-head p { margin: 0; }
.search-results {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    margin-top: 0.5rem;
}
.search-result { cursor: pointer; }
/* Las dos listas del mismo mapa: prospectos de la búsqueda y tu cartera.
   `.subtabs` y `.list-card-meta` ya traen su layout; acá solo el aire que el
   reset propio (*{margin:0}) se lleva. */
#search-list-tabs { margin-top: 1.25rem; }
#search-client-filter { margin-top: 0.6rem; }
.search-client-row .list-card-meta { align-items: center; }
.search-result-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.6rem;
    flex-wrap: wrap;
}
.search-result-badges {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.search-result-meta {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}
.search-reason { margin-top: 0.45rem; line-height: 1.4; }
/* Resumen "Mejor producto: X" — un punto más fuerte que la razón muted de abajo. */
.search-best { margin-top: 0.4rem; line-height: 1.4; color: var(--color-text); }
.result-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.12rem 0.55rem;
    border-radius: 20px;
    font-size: 0.72rem;
    font-weight: 600;
    background: var(--color-neutral-bg);
    color: var(--color-text-muted);
    white-space: nowrap;
}
/* Variante clicable "Ver en el mapa": chip con tinte primario, se lee como acción
   (en todas las tarjetas de Buscar, para saltar al mapa y ver dónde queda el punto). */
button.result-chip { border: 1px solid transparent; cursor: pointer; font-family: inherit; line-height: 1.35; }
.result-chip--map { background: var(--color-primary-soft, #e8f1fc); color: var(--color-primary, #066fd1); }
.result-chip--map:hover { filter: brightness(0.96); }
.search-empty {
    text-align: center;
    padding: 2.75rem 1rem;
    color: var(--color-text);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}
.search-empty-icon { font-size: 2.5rem; margin-bottom: 0.5rem; }
.search-empty p { margin: 0.25rem 0; }

/* ── Líneas de la orden (tabla de productos) ───────────────── */
.order-lines {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
}

.order-lines th {
    text-align: left;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-muted);
    font-weight: 700;
    padding: 0 0.4rem 0.35rem;
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
}

.order-lines td {
    padding: 0.5rem 0.4rem;
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}

.order-lines .num {
    text-align: right;
    white-space: nowrap;
}

/* La línea que no llegó: atenuada (ya no es plata) pero legible — es
   justamente la que el vendedor tiene que ver. */
.order-lines .line-lost td {
    opacity: 0.55;
}

/* Fila del catálogo: se toca para elegir el producto en el pedido. */
.order-lines .catalog-row {
    cursor: pointer;
}

.order-lines .catalog-row:hover td {
    background: var(--color-neutral-bg);
}

/* Aparición del panel desplegado: un fundido corto, sin rebote. */
@keyframes reveal-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.reveal-panel {
    animation: reveal-in 0.18s ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .badge-reveal.is-pulsing,
    .section-reveal.is-pulsing { animation: none; }
    .btn.is-loading { animation: none; }
    .reveal-panel { animation: none; }
}

/* Contenedor liviano para agrupar sub-secciones dentro de un panel
   (ej. "Generar con IA", "Semáforo" en los perfiles de prospección). */
.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 0.9rem 1rem;
}
.card h3 {
    margin: 0 0 0.4rem;
}

/* El dropdown de autocompletado de Google Places debe quedar por encima
   del modal de alta manual. */
.pac-container {
    z-index: 100000 !important;
}

/* Rueda de carga + banner prominente (para acciones con IA que tardan). */
@keyframes mp-spin {
    to { transform: rotate(360deg); }
}
.spinner {
    display: inline-block;
    width: 1.5rem;
    height: 1.5rem;
    border: 3px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: mp-spin 0.7s linear infinite;
    flex: none;
}

/* Botón en carga: parpadea para indicarle a cualquiera (no informático) que está
   trabajando. El texto cambia a "Cargando…" y queda deshabilitado mientras consulta. */
@keyframes mp-btn-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
.btn.is-loading {
    animation: mp-btn-pulse 1s ease-in-out infinite;
    cursor: wait;
}
.loading-banner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.75rem;
    padding: 1rem 1.25rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-primary);
    background: var(--color-primary-soft);
    border: 1px solid rgba(29, 78, 216, 0.25);
    border-radius: var(--radius);
}
/* `display:flex` de arriba le gana al atributo `hidden` del navegador; esta
   regla más específica restablece que `hidden` vuelva a ocultar el banner
   (si no, se quedaría "pegado" al terminar la acción). */
.loading-banner[hidden] {
    display: none;
}

/* Dos campos lado a lado (ej. latitud/longitud). */
.form-row {
    display: flex;
    gap: 0.5rem;
}
.form-row > div {
    flex: 1;
}

/* Mapa de Google en "Buscar prospectos". Grande y navegable: es el centro de la
   pantalla (arrastrar el pin, ver la cartera, soltar puntos). */
.map-canvas {
    width: 100%;
    height: 400px;               /* chico por defecto; el ⛶ lo agranda */
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
}

/* Barra de controles del mapa (toggle cartera, agregar punto, buscar en esta zona). */
.map-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
}
.map-toolbar .map-toolbar-spacer { flex: 1; }
.map-toolbar-label {
    font-size: 0.8rem; font-weight: 600; color: var(--color-text-muted);
    text-transform: uppercase; letter-spacing: 0.04em;
}

/* Interruptor de CAPA. No es `.subtab` a propósito: una pestaña elige UNA de N y
   una capa se prende y se apaga sola, así que necesita un apagado visible. Apagada
   se ve claramente apagada (gris, figura sin color, tachada) — con solo quitarle el
   subrayado no se distinguía de "no seleccionada". */
.map-layer {
    display: inline-flex; align-items: center; gap: 0.4rem;
    border: 1px solid var(--color-border); background: var(--color-surface);
    border-radius: 999px; padding: 0.35rem 0.75rem; min-height: 40px;
    font-family: inherit; font-size: 0.85rem; font-weight: 600;
    color: var(--color-text-muted); cursor: pointer; white-space: nowrap;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.map-layer:hover { border-color: var(--color-primary); }
.map-layer.is-on { background: var(--color-primary-soft, #e8f2fd); border-color: var(--color-primary); color: var(--color-primary); }
.map-layer:not(.is-on) { text-decoration: line-through; opacity: 0.7; }
.map-layer:not(.is-on) .layer-badge { filter: grayscale(1); opacity: 0.5; }

/* La figura de la capa: el MISMO dibujo del marcador, en chico. Va en el botón, en
   la sub-pestaña de la lista y en la leyenda, para que las tres se lean juntas. */
.layer-badge { width: 1.05em; height: 1.05em; flex: none; vertical-align: -0.18em; }

/* Leyenda del mapa: figuras + qué significa el color. */
.map-legend { margin-top: 0.4rem; line-height: 1.7; }
.legend-dot {
    display: inline-block; width: 0.7em; height: 0.7em; border-radius: 50%;
    vertical-align: -0.02em; border: 1px solid rgba(0, 0, 0, 0.12);
}
/* El estado "faltan datos": el marcador es una gota azul con "?"; en la leyenda va
   un badge chico con el mismo "?" (no un simple punto, porque lo que lo distingue
   es el glifo, no el color). */
.legend-q {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.05em; height: 1.05em; border-radius: 50%;
    background: #2563eb; color: #fff; font-size: 0.7em; font-weight: 700;
    line-height: 1; vertical-align: -0.05em;
}

/* Las sub-pestañas de la lista llevan la figura de su capa. */
#search-list-tabs .layer-badge { margin-right: 0.15rem; }

/* ── "Dónde estoy" ────────────────────────────────────────────
   Píldora como los interruptores de capa (para que la franja se lea como UN
   conjunto), pero se distingue de ellos porque es una ACCIÓN, no un estado: la
   mira va en el primario dentro de su propio disco, y al pulsarla el disco emite
   un pulso de radar mientras el dispositivo busca señal. */
.btn-locate {
    display: inline-flex; align-items: center; gap: 0.5rem;
    border: 1px solid var(--color-border); background: var(--color-surface);
    border-radius: 999px; padding: 0.25rem 0.95rem 0.25rem 0.35rem; min-height: 40px;
    box-sizing: border-box;   /* mismo alto EXACTO que los chips de capa de al lado */
    font-family: inherit; font-size: 0.85rem; font-weight: 600;
    color: var(--color-text); cursor: pointer; white-space: nowrap;
    transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
}
.locate-eye {
    position: relative; display: inline-flex; align-items: center; justify-content: center;
    width: 1.75rem; height: 1.75rem; flex: none; border-radius: 50%;
    background: var(--color-primary-soft, #e8f2fd); color: var(--color-primary);
}
.locate-eye .mp-icon { width: 1.05rem; height: 1.05rem; vertical-align: 0; }
.btn-locate:hover { border-color: var(--color-primary); color: var(--color-primary); box-shadow: 0 1px 3px rgba(29, 78, 216, 0.18); }
.btn-locate:hover .locate-eye { background: var(--color-primary); color: #fff; }
.btn-locate:active { transform: translateY(1px); }
.btn-locate:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.btn-locate[disabled] { cursor: default; color: var(--color-text-muted); }

/* Buscando señal: el disco late y suelta un anillo, como un radar. Es la espera
   más larga de la pantalla (hasta 10 s) y sin señal de vida el botón parece
   colgado. */
.btn-locate.is-locating .locate-eye { background: var(--color-primary); color: #fff; }
.btn-locate.is-locating .locate-eye::after {
    content: ""; position: absolute; inset: 0; border-radius: 50%;
    border: 2px solid var(--color-primary);
    animation: locate-ping 1.4s cubic-bezier(0, 0, 0.2, 1) infinite;
}
@keyframes locate-ping {
    0% { transform: scale(1); opacity: 0.7; }
    100% { transform: scale(1.9); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .btn-locate.is-locating .locate-eye::after { animation: none; opacity: 0.35; }
}

/* En el teléfono el mapa es lo que se viene a ver: la barra no puede empujarlo
   cuatro filas hacia abajo. Se aprieta para que las tres capas entren en una fila
   y las acciones en otra. El rótulo "VER:" se va — las figuras ya lo dicen. */
/* Botón "Crear cliente" del encabezado: etiqueta larga en escritorio, corta en el
   teléfono ("+ Nuevo"). El vendedor no entendía "+ PDV". El swap va por CSS (dos
   spans) y no por JS: así se ajusta solo al rotar/redimensionar, sin depender de que
   algo se vuelva a ejecutar. */
#header-add-pos .lbl-short { display: none; }

@media (max-width: 640px) {
    #header-add-pos .lbl-full  { display: none; }
    #header-add-pos .lbl-short { display: inline; }

    .map-toolbar { gap: 0.3rem; }
    .map-toolbar-label { display: none; }
    .map-layer { padding: 0.3rem 0.55rem; font-size: 0.78rem; gap: 0.3rem; }
    /* Sin el spacer, las acciones siguen a las capas en vez de saltar de fila. */
    .map-toolbar .map-toolbar-spacer { display: none; }
    #map-locate, #map-add-point, #map-search-here { font-size: 0.8rem; padding: 0.4rem 0.6rem; }
}
/* "Mis clientes" es una pestaña (.subtab); en la barra va sin el margen de la
   barra de sub-pestañas. */
.map-toolbar .subtab { margin: 0; }
/* El botón "Buscar en esta zona" aparece al mover el pin. */
#map-search-here { transition: opacity 0.15s; }

/* "Agregar punto de venta": misma pestaña que "Mis clientes" (.subtab) pero
   PARPADEA para avisar que es un botón/acción. Al activarlo (modo agregar) deja de
   parpadear y queda como pestaña activa. */
@keyframes map-cta-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}
.subtab.map-cta {
    color: var(--color-primary);
    animation: map-cta-pulse 1.4s ease-in-out infinite;
}
.subtab.map-cta.is-active {
    animation: none;
    border-bottom-color: var(--color-primary);
}
@media (prefers-reduced-motion: reduce) {
    .subtab.map-cta { animation: none; }
}

/* InfoWindow del mapa más compacto: Google reserva mucho aire arriba (header de
   ~48px + 17px de padding). Achicamos el header y el botón de cierre — el ícono ×
   (span 24×24) trae margin:12px pensado para 48px, así que lo recentramos con
   flex, si no queda descolgado. */
.gm-style-iw-ch { padding-top: 0 !important; }
.gm-style-iw button.gm-ui-hover-effect {
    width: 30px !important;
    height: 30px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
}
.gm-style-iw button.gm-ui-hover-effect > span { margin: 0 !important; }

/* Segundo tamaño del mapa (agrandado). El control ⛶ lo alterna. */
.map-canvas.map-big {
    height: 60vh;
    min-height: 460px;
}

/* Control propio en la esquina del mapa (estilo del ⛶ de Google) → agrandar/achicar. */
.map-size-ctrl {
    background: #fff;
    border-radius: 2px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
    cursor: pointer;
    margin: 10px;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.map-size-ctrl:hover { background: #f5f5f5; }

/* ── Modales (overlay/card/header/body/footer) ─────────────
   Genérico: cualquier modal usa este mismo esqueleto de clases,
   abierto/cerrado con openModal(id)/closeModal(id) (app.js) — no un
   par de funciones open/close por cada modal. ────────────────── */
.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 2rem 1rem;
    overflow-y: auto;
}

.modal-card {
    background: #fff;
    border-radius: 12px;
    max-width: 600px;
    width: 100%;
    display: flex;
    flex-direction: column;
    max-height: 90vh;
}

/* El <form> dentro de .modal-card debe heredar el flex chain para que
   modal-body y modal-footer se estructuren bien (scroll, footer fijo). */
.modal-card > form {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.modal-lg {
    max-width: 850px;
}

/* La ficha del cliente se veía angosta centrada en escritorio (era 850px como
   cualquier modal-lg). Se ensancha SOLO acá y SOLO en escritorio — en móvil ya es
   pantalla completa (FASE 3.5). Pedido del usuario: "las cards más anchas". */
@media (min-width: 768px) {
    #ficha-overlay .modal-card { max-width: min(1080px, 94vw); }
}

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

.modal-header h2 {
    margin: 0;
    font-size: 1.25rem;
}

.modal-close {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--color-text-muted);
    padding: 0;
    line-height: 1;
}

.modal-close:hover {
    color: var(--color-text);
}

.modal-body {
    padding: 1.5rem;
    overflow-y: auto;
    /* Al llegar al final del modal, la rueda deja de "contagiar" el scroll a la
       página de atrás (scroll chaining). Es la otra mitad del arreglo: `has-modal`
       congela el fondo cuando el puntero está AFUERA, y esto lo congela cuando
       está adentro y el contenido ya se acabó. */
    overscroll-behavior: contain;
}

/* Con un modal abierto la página de atrás NO se mueve. El `top` negativo lo pone
   el JS (setBodyScrollLock) con el desplazamiento que había, así que el fondo se ve
   igual que antes de abrir; al cerrar se devuelve el scroll.
   Con `overflow:hidden` a secas el documento pierde su posición y `scrollY` cae a
   0: se cerraba el modal y aparecías arriba de todo.
   No hace falta compensar el ancho de la barra de scroll — en esta app está oculta
   por CSS, así que el fondo tampoco salta a lo ancho. */
html.has-modal { overflow: hidden; }
html.has-modal body {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    /* ⚠️ VISIBLE, no `hidden`: acá el body NO puede recortar, y es lo contrario de
       lo que parece. El body mide UNA pantalla (`min-height:100vh` más el
       `flex-basis:0` de `#app-wrap`) y su contenido la desborda; con el fondo
       suelto eso no se nota porque su `overflow-x:hidden` —la red de seguridad de
       más abajo— se PROPAGA al viewport y el que recorta es la ventana. Al
       congelar, `html{overflow:hidden}` corta esa propagación y el overflow del
       body pasa a aplicar sobre el body: con `top:-500px` su caja termina en y=220
       y los 500 px de abajo del fondo quedaban EN BLANCO. Reportado como «se
       recorta la parte de atrás» al abrir cualquier modal.
       El recorte crece con el scroll: a `scrollY=0` no se ve nada, por eso hay que
       probarlo con la página abajo. Y no hace falta el guard del eje x mientras
       tanto: quien recorta durante el bloqueo es `html`, que sí mide el viewport
       y lo hace en los dos ejes. */
    overflow: visible;
}

.modal-body label {
    display: block;
    margin-top: 0.75rem;
}

.modal-body input:not([type="checkbox"]):not([type="radio"]),
.modal-body select,
.modal-body textarea {
    margin-top: 0.25rem;
}

.modal-footer {
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--color-border);
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
}

/* ── Panel general (superadmin) ───────────────────────────── */
.overview-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 1rem;
    margin: 1rem 0 1.5rem;
}

.stat-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    padding: 1rem 1.25rem;
    box-shadow: var(--shadow-md);
}

.stat-value {
    font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--color-text);
    line-height: 1.1;
}

.stat-label {
    margin-top: 0.25rem;
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.stat-sub {
    margin-top: 0.35rem;
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

.overview-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
}

.overview-cols h3 {
    margin-bottom: 0.75rem;
}

/* Selector de estado compacto (tabla de Empresas / global admin). */
.status-select {
    width: auto;
    padding: 0.2rem 0.4rem;
    font-size: 0.8rem;
    margin: 0;
}

/* Barra de filtros de las vistas globales (Clientes / Órdenes). */
.admin-filters {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.admin-filters select,
.admin-filters input {
    width: auto;
    max-width: 240px;
    padding: 0.35rem 0.5rem;
    font-size: 0.85rem;
    margin: 0;
}

/* ── Órdenes: tarjeta clicable + zona de peligro ──────────── */
.order-card { transition: box-shadow 0.12s, border-color 0.12s; }
.order-card:hover {
    border-color: var(--color-primary);
    box-shadow: 0 2px 10px rgba(29, 78, 216, 0.10);
}

/* ── Ficha del establecimiento (cliente): hero + relaciones ── */
/* La ficha habla el mismo idioma que "Mis clientes"/"Mis órdenes": lo que
   importa (identidad, relación, compra) arriba; los datos editables, plegados. */
.ficha-hero {
    background: var(--color-neutral-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.85rem 1rem;
    margin-bottom: 1.2rem;
}
.ficha-hero-clickable { cursor: pointer; transition: border-color 0.12s, box-shadow 0.12s; }
.ficha-hero-clickable:hover {
    border-color: var(--color-primary);
    box-shadow: 0 2px 10px rgba(29, 78, 216, 0.10);
}
.ficha-hero-hint {
    margin-top: 0.3rem;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--color-primary);
}
/* Encabezado de la ficha: "← Volver" (cuando aplica) + nombre + rótulo de vista. */
.ficha-header-left {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-width: 0;
    flex-wrap: wrap;
}
/* Listas de giros / direcciones de despacho en "Datos del cliente". */
.ficha-list-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.1rem;
    border-bottom: 1px solid var(--color-border);
    flex-wrap: wrap;
    font-size: 0.9rem;
}
.ficha-list-actions {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex-shrink: 0;
}
.ficha-link-btn {
    background: none;
    border: none;
    padding: 0;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--color-primary);
    cursor: pointer;
    white-space: nowrap;
}
.ficha-link-btn:hover { text-decoration: underline; }
.ficha-link-danger { color: var(--color-danger); }
.ficha-add-row {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.7rem;
    flex-wrap: wrap;
}
.ficha-add-row input {
    flex: 1;
    min-width: 200px;
    margin: 0;
}
/* Rótulo de la sub-pantalla de datos, junto al nombre en el encabezado. */
.ficha-title-tag {
    display: inline-block;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--color-primary);
    background: rgba(29, 78, 216, 0.12);
    border-radius: 20px;
    padding: 0.12rem 0.6rem;
    vertical-align: middle;
    margin-left: 0.5rem;
}
.ficha-hero-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.6rem;
    flex-wrap: wrap;
}
/* `.ficha-chip` / `.ficha-chip-manual` se eliminaron con el chip de origen
   (📍 Google Maps / ✍️ Subido por nosotros): de dónde salió la fila es metadato
   nuestro y no ayuda al vendedor a decidir. */
.ficha-tags {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex-wrap: wrap;
    margin-top: 0.6rem;
}
.ficha-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.75rem;
}
.ficha-wa {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: #25D366;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 0.35rem 0.7rem;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
}
.ficha-wa.is-off { opacity: 0.55; }
.ficha-section { margin-bottom: 1.4rem; }
.ficha-h3 { font-size: 0.98rem; margin: 0 0 0.6rem; }
.ficha-rel-card {
    margin-bottom: 0.6rem;
    cursor: pointer;
    padding: 0.8rem 0.9rem;
}
.ficha-rel-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.ficha-rel-badges {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.ficha-rel-foot { margin-top: 0.4rem; }
/* "Mis clientes": pie de tarjeta con recencia (izq.) + WhatsApp (der.). */
.mc-card-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.4rem;
    flex-wrap: wrap;
}
.mc-wa {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: #25D366;
    color: #fff;
    border: none;
    border-radius: var(--radius);
    padding: 0.28rem 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
}
.mc-wa.is-off { opacity: 0.5; }

/* ── Guardar un punto de venta (cartera SIN reservar) ─────────────────────
   Vive en tres superficies (Ficha, globo del mapa, tarjeta de resultado), así que
   el estilo tiene que sostenerse solo en cualquiera de las tres: sin depender del
   contenedor y sin heredar tamaño. A propósito NO se parece a la ★ de seguir —
   son cosas distintas y confundirlas es el error que esto viene a evitar.
   Padding explícito porque el reset propio (* { margin:0; padding:0 }) pisa todo. */
.save-pin {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: transparent;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.28rem 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    font-family: inherit;
    line-height: 1.2;
    cursor: pointer;
    flex-shrink: 0;
}
.save-pin .mp-icon { width: 0.95rem; height: 0.95rem; flex-shrink: 0; }
.save-pin:hover { border-color: var(--color-primary); color: var(--color-primary); }
/* Guardado: el marcador se rellena. El relleno del ícono es la señal de "ya está",
   sin necesidad de un segundo elemento (chevron, check, badge). */
.save-pin.is-on {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
    color: var(--color-primary);
}
.save-pin.is-on .mp-icon { fill: currentColor; }
.save-pin[disabled] { opacity: 0.55; cursor: default; }

/* Fila de acciones de una tarjeta de resultado en "Buscar". */
.search-result-actions { display: flex; justify-content: flex-end; margin-top: 0.5rem; }

/* Tarjeta de un punto guardado y NO reservado: acento neutro (no es cartera
   todavía) para que se distinga de un cliente de un vistazo. */
.mc-card--saved { border-left: 3px solid var(--color-border); }

/* ── INDEX: control de datos del pool ────────────────────────────────────
   Un caso muestra las DOS fichas lado a lado (no una sobre otra): la decisión es
   comparativa — cuál conservo y cuál doy de baja — y comparar exige verlas juntas.
   En móvil se apilan, que ahí no hay ancho para dos columnas. */
.index-case { margin-bottom: 0.75rem; }
.index-why-row { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem; }
.index-why-text { margin: 0.45rem 0 0; font-size: 0.85rem; color: var(--color-text-muted); line-height: 1.45; }
.index-why { margin: 0.5rem 0 0 1.1rem; font-size: 0.88rem; color: var(--color-text-muted); line-height: 1.5; }
.index-why li { margin-bottom: 0.2rem; }

.index-pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0.6rem;
    margin-top: 0.7rem;
}
.index-side {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.65rem 0.75rem;
}
.index-side .name { font-weight: 700; }
.index-side .sub { font-size: 0.83rem; color: var(--color-text-muted); margin-top: 0.1rem; }
.index-side-meta { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.45rem; }
/* Cuánto cuelga de esta fila: es lo que decide si el caso se puede cerrar dando de
   baja o si necesita una fusión. Va en negrita porque es EL dato de la pantalla. */
.index-side-att { margin-top: 0.5rem; font-size: 0.83rem; font-weight: 600; }
.index-side button { margin-top: 0.55rem; }
.index-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.7rem; }

/* ── FASE 1 — Tarjeta de "Mis clientes" por LOCAL ─────────────────────────
   Jerarquía: nombre+comuna · etapa/estrella · HÉROE del recontacto (coloreado
   por urgencia) · proveedor+motivo+actividad · plata discreta+acciones. Todo
   con flex-wrap y sin anchos fijos → no desborda en 360–375px (móvil primero). */
.mc-card .mc-foot-actions { display: inline-flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
/* Píldora HÉROE del recontacto: es lo primero que el vendedor busca ("¿a quién
   vuelvo hoy?"), por eso ocupa su propia línea y se colorea por urgencia. */
.mc-hero-recontact {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.55rem;
    padding: 0.3rem 0.6rem;
    border-radius: var(--radius);
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1.2;
}
.mc-hero-recontact .mp-icon { width: 1rem; height: 1rem; flex-shrink: 0; }
.mc-hero-recontact.is-overdue { background: var(--color-danger-bg); color: var(--color-danger); }
.mc-hero-recontact.is-soon    { background: var(--color-warning-bg); color: var(--color-warning); }
.mc-hero-recontact.is-later   { background: var(--color-primary-soft); color: var(--color-text-muted); }
.mc-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.55rem;
    margin-top: 0.5rem;
    font-size: 0.83rem;
    color: var(--color-text-muted);
}
.mc-prov-chip {
    display: inline-block;
    max-width: 100%;
    padding: 0.1rem 0.5rem;
    border-radius: 999px;
    background: var(--color-primary-soft);
    color: var(--color-text);
    font-weight: 600;
    font-size: 0.78rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.mc-prov-chip.mc-prov-none { background: transparent; color: var(--color-text-muted); font-weight: 500; font-style: italic; }
/* Punto liberado (búsqueda): acento verde + contexto comercial derivado. */
.search-result.is-released { border-left: 3px solid var(--color-success); }
.released-summary { margin-top: 0.45rem; font-size: 0.82rem; color: var(--color-success); line-height: 1.4; }
.mc-motivo::before { content: "· "; }
.mc-act::before { content: "· "; }
/* Etiqueta "Proveedor" junto al nombre de la empresa: deja claro que es el
   proveedor (vende), no el cliente. El cliente es el LOCAL (dueño de la ficha). */
.ficha-rel-role {
    display: inline-block;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #7c3aed;
    background: #f5f3ff;
    border: 1px solid #ddd6fe;
    border-radius: 20px;
    padding: 0.06rem 0.5rem;
    margin-left: 0.4rem;
    vertical-align: middle;
}
.ficha-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.6rem;
    margin: 0.5rem 0 1.2rem;
}
.ficha-stats .stat-card { padding: 0.7rem 0.8rem; }
.ficha-stats .stat-value { font-size: 1.2rem; }
@media (max-width: 520px) {
    .ficha-stats { grid-template-columns: 1fr; }
}

.danger-zone { border-color: var(--color-danger); }
.danger-zone h3 { color: var(--color-danger); }
.danger-note {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    line-height: 1.55;
    margin-bottom: 0.9rem;
}
.danger-note strong { color: var(--color-danger); }

/* ── "Tomar pedido": listas de cliente/empresa ─────────────── */
.take-list {
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    margin-top: 0.25rem;
}

.take-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.1rem;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-bottom: 1px solid var(--color-border);
    padding: 0.5rem 0.65rem;
    cursor: pointer;
}

.take-row:last-child { border-bottom: none; }
.take-row:hover { background: var(--color-neutral-bg); }

.take-selected {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.65rem;
    background: var(--color-neutral-bg);
    border-radius: var(--radius);
    margin-top: 0.25rem;
}

/* ── Notificaciones (campana + badge + bandeja) ───────────── */
.notif-wrap { position: relative; }

.notif-bell {
    position: relative;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 1.25rem;
    line-height: 1;
    padding: 0.25rem;
}

.notif-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--color-danger);
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

.notif-dropdown {
    position: absolute;
    right: 0;
    top: 2.25rem;
    width: 340px;
    max-width: 90vw;
    max-height: 420px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    z-index: 200;
}

.notif-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--color-border);
}

.notif-head a { color: var(--color-primary); cursor: pointer; font-size: 0.8rem; }

.notif-item {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
}

.notif-item:hover { background: var(--color-neutral-bg); }
.notif-unread { background: #eff5ff; }

/* ── Banner de impersonación ("Ingresar como…") ───────────── */
.impersonation-banner {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.5rem 1rem;
    background: var(--color-warning-bg);
    color: var(--color-warning);
    border-bottom: 1px solid var(--color-warning);
    font-size: 0.9rem;
    font-weight: 600;
}

.impersonation-banner .btn {
    background: var(--color-warning);
    color: #fff;
    border-color: var(--color-warning);
}

/* ── Footer ───────────────────────────────────────────────── */
.app-footer {
    text-align: center;
    padding: 1.25rem;
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 700px) {
    .app-header {
        flex-direction: column;
        align-items: flex-start;
    }

    .modal-overlay {
        padding: 0;
    }

    .modal-card {
        max-height: 100vh;
        border-radius: 0;
    }

    .overview-cols {
        grid-template-columns: 1fr;
    }
}

/* ── Medidor de completitud del perfil (anillo + chips) ──────
   Analizador compacto y guiado para los perfiles (vendedor y empresa):
   un anillo de progreso, chips por dimensión con ✓/~/○, y una tarjeta
   de análisis IA con preguntas guía. Portado del prototipo prueba-api-v2
   al sistema de diseño del marketplace. */
.perfil-meter {
    display: flex;
    gap: 0.9rem;
    align-items: flex-start;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-neutral-bg);
}
.pm-ring {
    flex: none;
    width: 56px;
    height: 56px;
    position: relative;
}
.pm-ring svg { transform: rotate(-90deg); }
.pm-ring .pm-fondo { stroke: var(--color-border); }
.pm-ring .pm-barra { transition: stroke-dashoffset 0.5s ease, stroke 0.3s; }
.pm-pct {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 0.8rem;
    font-weight: 800;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}
.pm-check { flex: 1; min-width: 0; }
.pm-check-title {
    font-size: 0.8rem;
    font-weight: 700;
    display: block;
    margin-bottom: 0.35rem;
}
.pm-check-title span {
    font-weight: 400;
    color: var(--color-text-muted);
    font-size: 0.72rem;
}
.pm-lista { display: flex; flex-wrap: wrap; gap: 0.3rem 0.5rem; }
.pm-tag {
    font-size: 0.72rem;
    padding: 0.14rem 0.55rem;
    border-radius: 11px;
    font-weight: 600;
    border: 1px solid transparent;
    white-space: nowrap;
}
.pm-tag.completo { background: var(--color-success-bg); color: var(--color-success); }
.pm-tag.parcial { background: var(--color-warning-bg); color: var(--color-warning); }
.pm-tag.falta {
    background: var(--color-surface);
    color: var(--color-text-muted);
    border-color: var(--color-border);
}
.pm-resumen {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    margin-top: 0.35rem;
}

/* Tarjeta de análisis IA con preguntas guía. */
.pm-ai-card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
    margin-top: 0.75rem;
}
.pm-ai-head {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    padding: 0.7rem 0.9rem;
    border-bottom: 1px solid var(--color-border);
}
.pm-ai-score {
    width: 46px;
    height: 46px;
    flex: none;
    border-radius: 50%;
    background: var(--color-surface);
    display: grid;
    place-items: center;
    font-size: 1.05rem;
    font-weight: 800;
    border: 3px solid currentColor;
    font-variant-numeric: tabular-nums;
}
.pm-ai-head-text b { font-size: 0.85rem; }
.pm-ai-head-text div {
    font-size: 0.78rem;
    color: var(--color-text-muted);
    margin-top: 0.1rem;
}
.pm-ai-chips {
    padding: 0.6rem 0.9rem 0.25rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 0.45rem;
}
.pm-questions { padding: 0.45rem 0.9rem 0.85rem; }
.pm-questions-title {
    font-size: 0.8rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
}
.pm-question { margin-bottom: 0.6rem; }
.pm-question label {
    display: block;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-primary);
    margin-bottom: 0.25rem;
}
.pm-question input { width: 100%; }
.pm-complete-note {
    padding: 0.75rem 0.9rem;
    text-align: center;
    font-size: 0.82rem;
    color: var(--color-success);
    font-weight: 600;
}

/* ── Cuenta y seguridad (perfil del vendedor) ────────────────
   Rejilla de estado (usuario, sesión, cifrado, último acceso) + nota. */
.sec-grid {
    background: rgba(29, 78, 216, 0.05);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.5rem 0.9rem;
    margin-bottom: 0.75rem;
}
.sec-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--color-border);
    font-size: 0.88rem;
}
.sec-row:last-child { border-bottom: none; }
.sec-row .k { color: var(--color-text-muted); }
.sec-row .v { font-weight: 700; text-align: right; word-break: break-word; }
.sec-row .v.ok { color: var(--color-success); }
.sec-note {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    line-height: 1.5;
    margin-bottom: 0.9rem;
}
.sec-note strong { color: var(--color-text); }

/* ── Placa de versión (solo superadmin, en el Panel general) ──
   Fondo oscuro con la versión en dorado — solo el superadmin ve qué versión
   corre de verdad en producción. */
.version-badge {
    background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
    border: 1px solid #334155;
    border-radius: var(--radius);
    padding: 0.9rem 1.2rem;
    margin-bottom: 1.25rem;
    text-align: right;
    box-shadow: var(--shadow-md);
}
.version-badge-num {
    font-size: 1.35rem;
    font-weight: 800;
    letter-spacing: 0.01em;
    color: #facc15;
    font-variant-numeric: tabular-nums;
}
.version-badge-credit {
    margin-top: 0.15rem;
    font-size: 0.9rem;
    color: #e2e8f0;
}
.version-badge-credit strong { color: #ffffff; font-weight: 700; }
.version-badge-email {
    margin-top: 0.1rem;
    font-size: 0.8rem;
    color: #94a3b8;
}
.version-badge-quote {
    margin-top: 0.7rem;
    padding-top: 0.6rem;
    border-top: 1px solid #334155;
    font-style: italic;
    font-size: 0.88rem;
    color: #facc15;
}

/* ── Acordeón de productos por categoría (catálogo) ──────────── */
.cat-accordion {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    margin-bottom: 0.5rem;
    overflow: hidden;
}
.cat-accordion > summary {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.9rem;
    cursor: pointer;
    font-weight: 600;
    background: var(--color-neutral-bg);
    list-style: none;
    user-select: none;
}
.cat-accordion > summary::-webkit-details-marker { display: none; }
.cat-accordion > summary::before {
    content: "▸";
    color: var(--color-text-muted);
    transition: transform 0.15s;
}
.cat-accordion[open] > summary::before { transform: rotate(90deg); }
.cat-accordion .cat-count {
    margin-left: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    padding: 0.05rem 0.55rem;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--color-text-muted);
}
.cat-accordion-body { overflow-x: auto; }
.cat-accordion > summary > span:first-child { font-weight: 600; }
/* Categoría hoja (sin subcategorías): fila simple, no colapsable. */
.cat-leaf {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.9rem;
    border-bottom: 1px solid var(--color-border);
}
.cat-leaf:last-child { border-bottom: none; }
.cat-leaf > span:first-child { flex: 1; }
/* Acciones (superadmin) dentro del summary/hoja, alineadas a la derecha. */
.cat-actions {
    display: flex;
    gap: 0.3rem;
    flex-wrap: wrap;
    margin-left: 0.5rem;
}

/* ═══════════════════════════════════════════════════════════════
   FASE 2 — Layout HORIZONTAL Tabler (menú ARRIBA, contenido fluido)
   Va SIN capa y al final: gana a @layer tabler donde haga falta. Solo
   estilos de shell; el contenido de los paneles no se toca. El menú reusa
   la clase .tab (switchTab no cambia): en horizontal quedan pestañas con
   subrayado activo (el look base de .tab, style.css:503-523). Se eligió el
   layout horizontal + fluido para darle TODO EL ANCHO al contenido (no hay
   sidebar que reste 15rem). Ver SESSION_LOG (Sesión 41).

   OJO (regla que se repite) — el reset propio `* { margin:0; padding:0 }`
   (sin capa, style.css:31-37) PISA todos los márgenes/paddings de Tabler
   (sin-capa gana a @layer tabler). Por eso acá se fija el padding de las
   barras y de los items de forma explícita, sin capa.
   ═══════════════════════════════════════════════════════════════ */

/* El contenedor raíz es el .page de Tabler, en columna y a todo el ancho.
   Neutralizamos el "boxed theme" de .page (max-width/borde/fondo). */
#app-wrap.page {
    flex: 1;
    max-width: none;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    display: flex;
    flex-direction: column;
}

/* ── Barra superior: marca + acciones ──────────────────────────── */
.app-topbar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    box-shadow: var(--shadow-sm);
    min-height: auto;
    padding: 0;
}
.app-topbar > .container-fluid {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.55rem 1.5rem;
}
.app-brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--color-text);
    white-space: nowrap;
}
.app-brand-mark { color: var(--color-primary); }
/* Empuja las acciones a la derecha (la marca y el subtítulo vacío quedan a la
   izquierda). */
.app-topbar .header-right { margin-left: auto; }

/* ── Barra del menú horizontal ─────────────────────────────────── */
.app-menubar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    box-shadow: var(--shadow-sm);
    min-height: auto;
    padding: 0;
}
.app-menubar > .container-fluid { padding: 0 1.5rem; }
.app-menubar .navbar-nav { gap: 0.15rem; }
.app-menubar .nav-item { display: flex; }
/* Los items reusan .tab (base: pestaña horizontal con subrayado activo). El
   -1px pega el subrayado activo al borde inferior de la barra. */
.app-menubar .tab {
    border-radius: 0;
    margin-bottom: -1px;
}

/* page-body sin el margen vertical propio de Tabler: el padding lo pone
   .app-main. */
.page-body { margin-top: 0; margin-bottom: 0; }

/* Contenido a todo el ancho (fluid): sin el cap de 1400px de .app-main. */
.app-main { max-width: none; }

/* ── Responsive ────────────────────────────────────────────────── */
@media (max-width: 767.98px) {
    /* La barra de menú colapsa (hamburguesa en la barra superior). Al expandir,
       los items se apilan a lo ancho; le damos aire y que ocupen la fila. */
    .app-menubar > .container-fluid { padding: 0 1rem; }
    .app-menubar .navbar-nav { gap: 0; padding: 0.25rem 0; }
    .app-menubar .nav-item { width: 100%; }
    .app-menubar .tab { width: 100%; margin-bottom: 0; }
}

/* ═══════════════════════════════════════════════════════════════
   FASE 3 — Contenido del VENDEDOR (lenguaje visual)
   Pulido de las pantallas del vendedor con estilo Tabler, reusando los
   tokens :root y las clases propias que ya existen (.stat-card, .card,
   .badge, .status-*). Clases NUEVAS y reutilizables (sin capa, sin chocar
   con Tabler ni con lo existente). Solo presentación: no toca datos/lógica.
   Ver SESSION_LOG (Sesión 42). Empezó por "Inicio" (piloto).
   ═══════════════════════════════════════════════════════════════ */

/* Grilla de métricas (mismas tarjetas .stat-card que el Panel general del
   superadmin → app cohesiva). El acento de color da lectura rápida al vendedor. */
.metric-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 1rem;
    margin-top: 1.25rem;
}
.stat-card { transition: box-shadow 0.12s, border-color 0.12s; }
/* El acento de color de la métrica del vendedor migró del borde-izq. grueso al
   avatar de ícono teñido (.stat-icon, sección FASE 3.5) — el patrón de Tabler. */
.stat-value.is-success { color: var(--color-success); }
.stat-value.is-warning { color: var(--color-warning); }

/* Encabezado de sección: título + acción a la derecha, espaciado consistente. */
.section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin: 2rem 0 0.85rem;
}
.section-head h3 { margin: 0; font-size: 1.05rem; }
.section-head .section-sub { margin: 0.15rem 0 0; width: 100%; }

/* Embudo del pipeline como chips (de un vistazo, no una línea de texto). */
.pipeline-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.9rem; }
.pipe-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35rem;
    padding: 0.3rem 0.75rem;
    background: var(--color-neutral-bg);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    font-size: 0.82rem;
    color: var(--color-text-muted);
    white-space: nowrap;
}
.pipe-chip-n { font-weight: 700; color: var(--color-text); font-size: 0.92rem; }
.pipe-chip.pipe-muted { opacity: 0.75; }

/* Estado vacío reutilizable (icono + mensaje, en vez de un texto suelto). */
.empty-state {
    text-align: center;
    padding: 1.75rem 1rem;
    color: var(--color-text-muted);
    background: var(--color-neutral-bg);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    font-size: 0.9rem;
}
.empty-state .empty-emoji { font-size: 1.6rem; display: block; margin-bottom: 0.4rem; }
.empty-state-action { margin-top: 0.75rem; }

/* Tarjeta clicable (abre modal/ficha): mismo hover que .order-card, genérico. */
.card--clickable { cursor: pointer; transition: box-shadow 0.12s, border-color 0.12s; }
.card--clickable:hover { border-color: var(--color-primary); box-shadow: var(--shadow-md); }
/* Separación entre tarjetas apiladas de una lista (antes iba en style inline). */
.order-card { margin-bottom: 0.6rem; }

/* Estructura de item de lista (orden, cliente, prospecto): 3 zonas, sin styles
   inline. Cabecera (identidad + badges) · meta (números clave) · pie (contexto +
   acción rápida). Mobile-first: todo con gap explícito (el reset mata los defaults). */
.list-card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 0.75rem; flex-wrap: wrap; }
.list-card-identity { min-width: 0; }
.list-card-identity .name { font-weight: 700; }
.list-card-identity .sub { color: var(--color-text-muted); font-size: 0.85rem; }
.list-card-badges { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.list-card-meta { margin-top: 0.5rem; color: var(--color-text-muted); font-size: 0.85rem; display: flex; gap: 0.35rem 0.75rem; flex-wrap: wrap; }
.list-card-foot { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; margin-top: 0.6rem; flex-wrap: wrap; }

/* Fila de KPIs compacta (Buscar prospectos): derivada de datos ya en el cliente. */
.kpi-row { display: flex; gap: 0.75rem; flex-wrap: wrap; margin: 0.85rem 0; }
.kpi { flex: 1 1 140px; }

/* Punto-semáforo de afinidad, alineado al color del marcador del mapa. */
.status-dot { display: inline-block; width: 0.6rem; height: 0.6rem; border-radius: 50%; flex: none; }
.dot-success { background: var(--color-success); }
.dot-muted { background: var(--color-text-muted); }
.dot-warning { background: var(--color-warning); }

/* Mini medidor horizontal (fit_score del prospecto). */
.mini-meter { height: 6px; border-radius: 999px; background: var(--color-neutral-bg); overflow: hidden; }
.mini-meter > span { display: block; height: 100%; border-radius: 999px; background: var(--color-primary); }

/* Toolbar de filtros/subtabs envuelta como card (agrupa el bloque de controles). */
.toolbar-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 0.75rem; display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1rem; }

/* Badge suave (segmento del prospecto, etiquetas): sin uppercase agresivo. */
.badge-soft { text-transform: none; letter-spacing: 0; font-weight: 600; background: var(--color-neutral-bg); color: var(--color-text-muted); }

/* Bloque de alerta (Zona peligrosa, avisos fuertes). */
.alert-danger { background: var(--color-danger-bg); border: 1px solid var(--color-danger); border-radius: var(--radius); padding: 0.8rem 1rem; color: var(--color-danger); }

/* Datagrid clave/valor reutilizable (lecturas rápidas: seguridad, datos). */
.data-grid { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 0.9rem; font-size: 0.88rem; }
.data-grid .k { color: var(--color-text-muted); }
.data-grid .v.ok { color: var(--color-success); }

/* Zona peligrosa (eliminar cuenta): acento rojo para separarla claramente. */
.danger-zone { border-color: var(--color-danger); border-left: 3px solid var(--color-danger); }

/* Hilo de notas de la orden (vendedor↔empresa) como burbujas de chat: las tuyas
   a la derecha (azul suave), las del otro lado a la izquierda. */
.note-thread { display: flex; flex-direction: column; gap: 0.1rem; }
.note-item { max-width: 85%; margin-bottom: 0.5rem; padding: 0.5rem 0.7rem; border-radius: 12px; background: var(--color-neutral-bg); }
.note-item.note-mine { margin-left: auto; background: var(--tint-info); }
.note-meta { font-size: 0.72rem; color: var(--color-text-muted); margin-bottom: 0.2rem; }
.note-body { white-space: pre-wrap; word-break: break-word; }

/* ═══════════════════════════════════════════════════════════════
   FASE 3.5 — Fidelidad Tabler (vendedor): íconos de línea, subheaders,
   avatares de métrica y micro-ajustes al detalle del tema. Solo
   presentación. Íconos: Tabler Icons (MIT), embebidos como SVG inline
   (sin CDN ni fuente, funcionan offline). Ver THIRD_PARTY_LICENSES.md.
   ═══════════════════════════════════════════════════════════════ */

/* Ícono de línea inline: hereda color (currentColor) y se dimensiona por
   font-size salvo que el contexto fije un tamaño. El reset propio no lo toca
   (no tiene margin/padding). */
.mp-icon {
    width: 1.15em;
    height: 1.15em;
    flex: none;
    stroke-width: 2;
    vertical-align: -0.2em;
}

/* Botón con ícono + texto: separa ambos (los botones de un solo hijo no cambian). */
.btn { gap: 0.4rem; }
.btn .mp-icon { width: 1.05em; height: 1.05em; }

/* Etiqueta "subheader" de Tabler: minúscula, versalita y con tracking. Es la
   firma visual de las tarjetas de métrica del tema. */
.subheader {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    line-height: 1.2;
}

/* Menú por rol: ícono de línea + etiqueta alineados. */
.app-menubar .tab { display: inline-flex; align-items: center; gap: 0.45rem; }
.app-menubar .tab .mp-icon { width: 18px; height: 18px; opacity: 0.9; }

/* Tarjeta de métrica estilo Tabler: fila [subheader | avatar de ícono], valor
   grande debajo. El avatar teñido es el semáforo de lectura rápida (reemplaza
   al borde-izquierdo grueso). */
.stat-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.5rem; }
.stat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius);
    flex: none;
}
.stat-icon .mp-icon { width: 1.2rem; height: 1.2rem; }
.stat-icon.accent-success { background: var(--color-success-bg); color: var(--color-success); }
.stat-icon.accent-warning { background: var(--color-warning-bg); color: var(--color-warning); }
.stat-icon.accent-primary { background: var(--color-primary-soft); color: var(--color-primary); }
.stat-icon.accent-muted { background: var(--color-neutral-bg); color: var(--color-text-muted); }

/* En la métrica del vendedor el valor va con aire arriba (tras la cabecera). */
.metric-grid .stat-card { box-shadow: var(--shadow-sm); }
.metric-grid .stat-value { margin-top: 0.55rem; font-size: 1.9rem; }

/* Encabezado de sección con ícono de línea (en vez del emoji). */
.section-head h3 { display: inline-flex; align-items: center; gap: 0.5rem; }
.section-head h3 .mp-icon { width: 1.15rem; height: 1.15rem; color: var(--color-text-muted); }

/* "Salir" dentro del menú: oculto en desktop, se muestra en móvil. La
   especificidad iguala a `.app-menubar .nav-item` (que lo pone en flex) y gana
   por ir después en el archivo. */
.app-menubar .nav-item-mobile-logout { display: none; }

/* En móvil el badge de usuario (correo · rol) es redundante — ese dato vive en
   "Mi cuenta" — y roba espacio. Y "Salir" pasa AL MENÚ (más alcanzable con el
   pulgar), así que se quita de la barra superior para no duplicarlo. */
@media (max-width: 767.98px) {
    .user-badge { display: none; }
    #logout-btn { display: none; }
    .app-menubar .nav-item-mobile-logout { display: flex; }

    /* En móvil se muestra el ISOTIPO de Triventa pegado a la izquierda, con la
       hamburguesa a su derecha. `order:-1` lo antepone al toggler sin tocar el
       HTML (en escritorio el toggler está oculto, así que la marca ya va primero
       igual). TODO tiene que caber en UNA sola línea → `nowrap`; por eso se
       aprietan padding/gap y se saca el subtítulo vacío. */
    .app-topbar > .container-fluid {
        flex-wrap: nowrap;
        padding: 0.5rem 0.6rem;
        gap: 0.4rem;
    }
    .app-brand { order: -1; flex: 0 0 auto; }
    .navbar-toggler { flex: 0 0 auto; padding: 0.25rem 0.4rem; }
    #app-subtitle { display: none; }                 /* subtítulo vacío: no roba ancho */
    .app-topbar .header-right { gap: 0.3rem; flex: 0 1 auto; min-width: 0; }
    /* Acciones más compactas en móvil: así "Tomar pedido" + "Nuevo" + campana +
       usuario caben junto al isotipo sin desbordar la línea en 360px. */
    .app-topbar .header-right .btn { padding-left: 0.5rem; padding-right: 0.5rem; }
}

/* ═══════════════════════════════════════════════════════════════
   FASE 3.5 — Móvil primero (el vendedor vive en terreno con el teléfono).
   En ≤640px: modales a PANTALLA COMPLETA (máximo espacio, sin franjas) y la
   tabla de productos del pedido se APILA (sin scroll horizontal, que escondía
   justo el total y la comisión). Solo presentación.
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
    .modal-overlay { padding: 0; align-items: stretch; }
    .modal-card {
        max-width: none;
        width: 100%;
        height: 100vh;
        height: 100dvh;   /* respeta la barra del navegador móvil */
        max-height: none;
        border-radius: 0;
    }
    .modal-header { padding: 0.85rem 1rem; }
    /* El cuerpo crece y hace scroll; encabezado y pie quedan fijos. */
    .modal-body { padding: 1rem; flex: 1 1 auto; min-height: 0; }
    .modal-footer { padding: 0.75rem 1rem; }
    /* Acciones grandes y fáciles de tocar en terreno (ocupan el ancho). */
    .modal-footer .btn { flex: 1 1 auto; }

    /* Tabla de productos del pedido → tarjetas apiladas. Cada producto es un
       bloque con su etiqueta a la izquierda. Solo la del detalle
       (.order-lines-detail), no el catálogo de "Tomar pedido". */
    .order-lines-detail thead { display: none; }
    .order-lines-detail,
    .order-lines-detail tbody,
    .order-lines-detail tr,
    .order-lines-detail td { display: block; width: 100%; }
    .order-lines-detail tr {
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        padding: 0.55rem 0.75rem;
        margin-bottom: 0.6rem;
    }
    .order-lines-detail td { border: none; padding: 0.12rem 0; }
    .order-lines-detail td.num {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        text-align: right;
    }
    .order-lines-detail td.num::before {
        content: attr(data-label);
        color: var(--color-text-muted);
        font-weight: 600;
        text-align: left;
        margin-right: 1rem;
    }
    /* La línea no entregada se atenúa como bloque (no celda a celda). */
    .order-lines-detail .line-lost { opacity: 0.6; }
    .order-lines-detail .line-lost td { opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════════
   FASE 3.5 — Móvil primero (2): objetivos táctiles, apilado y notch.
   Salió de una auditoría por pantalla (ver SESSION_LOG). Todo presentación.
   Los objetivos táctiles apuntan a ~40px sin agrandar el glifo. Selectores
   que no existan quedan inertes (no rompen nada).
   ═══════════════════════════════════════════════════════════════ */

/* Red de seguridad: un desborde puntual no arrastra el scroll de toda la página.
   Va en body (no en html/.page*): no toca el scroll vertical ni los position:fixed. */
body { overflow-x: hidden; }

/* Botón "quitar del carrito" (Tomar pedido): control real y accesible, área cómoda. */
.cart-remove {
    border: none;
    background: none;
    color: var(--color-danger);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    min-height: 40px;
    margin-left: 0.25rem;
}

/* "← Volver" del auth: área táctil sin separar de más los links inline. */
.auth-switch a { display: inline-block; padding: 0.35rem 0.5rem; margin: -0.2rem 0; }

/* iOS hace zoom al enfocar un input < 16px (la base es 0.9rem = 14.4px). Subirlo
   a 16px en móvil lo evita (y sube el alto del control de paso). */
@media (max-width: 767.98px) {
    input[type="text"], input[type="email"], input[type="password"],
    input[type="number"], input[type="search"], input[type="tel"],
    select, textarea { font-size: 16px; }
}

@media (max-width: 640px) {
    /* Objetivos táctiles: botones compactos y el ✕ de todos los modales. */
    .btn-sm, .btn-xs { min-height: 40px; padding-top: 0.5rem; padding-bottom: 0.5rem; }
    .modal-close { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }

    /* Sub-pestañas y controles de la tarjeta (estrella/etiquetas): blanco >= 40px
       sin agrandar el ícono. .subtab conserva su subrayado (margin-bottom:-1px). */
    .subtab { min-height: 40px; display: inline-flex; align-items: center; }
    .follow-star, .tag-add { min-width: 40px; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; padding: 0; }

    /* WhatsApp de la tarjeta de cliente (el gesto de calle con el pulgar). */
    .mc-wa { min-height: 40px; padding: 0.5rem 0.9rem; font-size: 0.82rem; }

    /* "Guardar": es EL gesto de terreno — se toca de pie, con una mano y el
       teléfono en la otra. Mismo blanco táctil que WhatsApp. */
    .save-pin { min-height: 40px; padding: 0.5rem 0.9rem; font-size: 0.82rem; }

    /* Ficha: acciones-enlace de las listas (giros/direcciones), con "Quitar"
       (destructiva) separada de "Marcar principal". */
    #ficha-body .ficha-link-btn { min-height: 40px; padding: 0.4rem 0.5rem; display: inline-flex; align-items: center; }
    #ficha-body .ficha-list-actions { gap: 1rem; }

    /* Empresas disponibles: el botón de afinidad IA a ancho completo (scopeado
       para no afectar las toolbars de Inicio/Mis órdenes). */
    .panel[data-panel="companies-feed"] .toolbar-card .btn { width: 100%; min-height: 44px; }

    /* Tomar pedido: si el nombre del cliente/empresa es largo, los botones bajan. */
    .take-selected { flex-wrap: wrap; row-gap: 0.4rem; }

    /* Auth: inputs y botón principal con alto táctil (no son .modal-* ni btn-sm). */
    .auth-card input[type="text"], .auth-card input[type="email"],
    .auth-card input[type="password"], .auth-card input[type="tel"],
    .auth-card #auth-btn { min-height: 44px; }

    /* Notch / home indicator (iPhone) en el modal a pantalla completa. env() vale
       0 sin viewport-fit=cover / en no-notch, así que max() no cambia nada ahí. */
    .modal-header { padding-top: max(0.85rem, env(safe-area-inset-top)); }
    .modal-footer { padding-bottom: max(0.75rem, env(safe-area-inset-bottom)); }

    /* Catálogo de "Tomar pedido" → tarjetas apiladas (igual que el detalle de la
       orden), AISLADO por la clase extra .order-lines-catalog: `.order-lines-catalog td`
       (0,0,1,1) gana a `.order-lines td` y NO toca la tabla del detalle. */
    .order-lines-catalog thead { display: none; }
    .order-lines-catalog,
    .order-lines-catalog tbody,
    .order-lines-catalog tr,
    .order-lines-catalog td { display: block; width: 100%; }
    .order-lines-catalog tr {
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        padding: 0.55rem 0.75rem;
        margin-bottom: 0.6rem;
    }
    .order-lines-catalog td { border: none; padding: 0.12rem 0; }
    .order-lines-catalog td.num { display: flex; justify-content: space-between; align-items: baseline; text-align: right; }
    .order-lines-catalog td.num::before {
        content: attr(data-label);
        color: var(--color-text-muted);
        font-weight: 600;
        text-align: left;
        margin-right: 1rem;
    }
}

@media (max-width: 480px) {
    /* Fila de filtros: alto táctil (hoy 2.4rem = 38.4px). */
    .filter-row .filter-select, .filter-row .btn { height: 2.6rem; }

    /* Buscar prospectos: apilar la fila de búsqueda y sus CTAs a ancho completo. */
    .search-hero .search-row { flex-direction: column; align-items: stretch; gap: 0.5rem; }
    .search-hero .search-row > .search-grow,
    .search-hero .search-row > .btn,
    .search-hero .search-row > div { width: 100%; min-width: 0; }
    .search-hero .search-row > .btn { min-height: 44px; }

    /* Barra del mapa: el CTA "Buscar en esta zona" a ancho completo. */
    .map-toolbar .map-toolbar-spacer { display: none; }
    #map-search-here { width: 100%; min-height: 44px; font-size: 0.85rem; }
    .map-toolbar .subtab { padding: 0.55rem 0.75rem; }
}

/* ═══════════════════════════════════════════════════════════════
   Confirmación flotante de "pedido registrado" (check verde + folio).
   Tarjeta COMPACTA centrada — NO usa .modal-card, así en móvil NO va a
   pantalla completa. Igual de bien en móvil y desktop. Solo presentación.
   ═══════════════════════════════════════════════════════════════ */
.confirm-overlay {
    position: fixed;
    inset: 0;
    background: rgba(24, 36, 51, 0.45);
    z-index: 1200;   /* sobre cualquier modal (1000–1100) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    padding-bottom: max(1rem, env(safe-area-inset-bottom));
    animation: confirm-fade 0.15s ease;
}
.confirm-pop {
    background: var(--color-surface);
    border-radius: 14px;
    box-shadow: var(--shadow-md);
    padding: 1.75rem 1.5rem 1.25rem;
    max-width: 360px;
    width: 100%;
    text-align: center;
    animation: confirm-pop-in 0.22s cubic-bezier(0.2, 0.8, 0.3, 1.2);
}
.confirm-check {
    width: 4rem;
    height: 4rem;
    margin: 0 auto 0.75rem;
    border-radius: 50%;
    background: var(--color-success-bg);
    color: var(--color-success);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.confirm-check .mp-icon { width: 2.4rem; height: 2.4rem; stroke-width: 2.2; }
/* Tonos del ícono según el resultado (verde éxito por defecto). */
.confirm-check.tone-danger { background: var(--color-danger-bg); color: var(--color-danger); }
.confirm-check.tone-primary { background: var(--color-primary-soft); color: var(--color-primary); }
/* Ámbar = "ojo con esto", ni error ni éxito. Lo usa el aviso de posible duplicado
   al dar de alta un punto: no se rechaza el alta, se advierte y decide la persona. */
.confirm-check.tone-warn { background: var(--color-warning-bg); color: var(--color-warning); }

/* ═══════════════════════════════════════════════════════════════
   Calendario propio con el estilo del tema (Tabler). El campo (.mp-datefield)
   es un botón que abre el calendario (.mp-datepicker), en vez del date picker
   nativo (que no se puede restilar por CSS). Solo presentación.
   ═══════════════════════════════════════════════════════════════ */
.mp-datefield-wrap { display: block; width: 100%; }
.mp-datefield {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font);
    font-size: 0.9rem;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.mp-datefield:hover { border-color: var(--color-primary); }
.mp-datefield:focus-visible { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-soft); }
.mp-datefield .mp-icon { color: var(--color-text-muted); flex: none; width: 1.05rem; height: 1.05rem; }
.mp-datefield-text.is-empty { color: var(--color-text-muted); }

.mp-datepicker {
    position: fixed;
    z-index: 1300;   /* sobre modales (1000-1100) y confirmaciones (1200) */
    width: 17rem;
    max-width: calc(100vw - 1rem);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    padding: 0.6rem;
    user-select: none;
}
.mp-dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.35rem; }
.mp-dp-title { font-weight: 700; font-size: 0.95rem; text-transform: capitalize; }
.mp-dp-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: none;
    background: none;
    border-radius: var(--radius);
    color: var(--color-text-muted);
    cursor: pointer;
}
.mp-dp-nav:hover { background: var(--color-neutral-bg); color: var(--color-text); }
.mp-dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.mp-dp-wd { text-align: center; font-size: 0.68rem; font-weight: 600; color: var(--color-text-muted); padding: 0.2rem 0; text-transform: uppercase; }
.mp-dp-day {
    aspect-ratio: 1 / 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: none;
    border-radius: var(--radius);
    font-family: var(--font);
    font-size: 0.85rem;
    color: var(--color-text);
    cursor: pointer;
}
.mp-dp-day:hover { background: var(--color-neutral-bg); }
.mp-dp-day.is-other { color: var(--color-text-muted); opacity: 0.55; }
.mp-dp-day.is-today { color: var(--color-primary); font-weight: 700; box-shadow: inset 0 0 0 1px var(--color-primary); }
.mp-dp-day.is-selected,
.mp-dp-day.is-selected.is-today { background: var(--color-primary); color: #fff; font-weight: 700; box-shadow: none; }
.mp-dp-day.is-selected:hover { background: var(--color-primary-dark); }
.mp-dp-foot { display: flex; justify-content: space-between; margin-top: 0.5rem; }
.mp-dp-foot button {
    background: none;
    border: none;
    color: var(--color-primary);
    font-family: var(--font);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.25rem 0.45rem;
    border-radius: var(--radius);
}
.mp-dp-foot button:hover { background: var(--color-neutral-bg); }

/* Móvil: calendario a lo ancho, días más grandes para el pulgar. */
@media (max-width: 480px) {
    .mp-datepicker { width: calc(100vw - 1rem); }
    .mp-dp-day { font-size: 0.95rem; }
}
.confirm-pop h3 { margin: 0 0 0.15rem; font-size: 1.15rem; }
.confirm-folio { font-size: 1.7rem; font-weight: 800; line-height: 1.1; margin: 0.1rem 0; }
.confirm-sub { color: var(--color-text-muted); font-size: 0.9rem; margin: 0.2rem 0 0.35rem; }
.confirm-total { font-size: 0.95rem; margin: 0 0 1.1rem; }
.confirm-actions { display: flex; gap: 0.5rem; }
.confirm-actions .btn { flex: 1; min-height: 44px; }

@keyframes confirm-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes confirm-pop-in {
    from { opacity: 0; transform: scale(0.92) translateY(10px); }
    to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .confirm-overlay, .confirm-pop { animation: none; }
}

/* Ventana "Productos con chance acá" (afinidad por producto de un punto). Reusa el
   overlay .confirm-overlay; la tarjeta va alineada a la izquierda porque es una
   lista (producto · empresa · % · razón), no un mensaje centrado. */
.affinity-pop {
    background: var(--color-surface);
    border-radius: 14px;
    box-shadow: var(--shadow-md);
    padding: 1.1rem 1.15rem 1rem;
    max-width: 420px; width: 100%;
    max-height: 80vh; overflow-y: auto;
    animation: confirm-pop-in 0.22s cubic-bezier(0.2, 0.8, 0.3, 1.2);
}
.affinity-pop-head { display: flex; align-items: flex-start; gap: 0.75rem; margin-bottom: 0.7rem; }
.affinity-pop-title { font-weight: 700; font-size: 1.05rem; line-height: 1.2; }
.affinity-pop-sub { color: var(--color-text-muted); font-size: 0.85rem; margin-top: 0.1rem; }
.affinity-pop-close {
    margin-left: auto; background: none; border: none; cursor: pointer;
    font-size: 1.05rem; line-height: 1; color: var(--color-text-muted); padding: 0.2rem 0.3rem;
}
.affinity-pop-body { display: flex; flex-direction: column; gap: 0.55rem; }
.affinity-prod { border: 1px solid var(--color-border); border-radius: 10px; padding: 0.55rem 0.7rem; }
.affinity-prod-top { display: flex; align-items: center; gap: 0.5rem; justify-content: space-between; }
.affinity-prod-name { font-weight: 600; }
.affinity-prod-meta { color: var(--color-text-muted); font-size: 0.8rem; margin-top: 0.15rem; }
.affinity-prod-reason { font-size: 0.85rem; margin-top: 0.25rem; line-height: 1.35; }
.affinity-pop-empty { color: var(--color-text-muted); }
.affinity-pop-foot { color: var(--color-text-muted); font-size: 0.78rem; margin-top: 0.7rem; line-height: 1.35; }
@media (prefers-reduced-motion: reduce) { .affinity-pop { animation: none; } }

/* ═══════════════════════════════════════════════════════════════
   MOTOR DE MISIONES — presentación (sin capa; padding/margin explícitos
   por el reset propio *{margin:0;padding:0}). Móvil primero: tarjetas
   claras, botones táctiles, sin scroll horizontal. Los modales heredan el
   fullscreen ≤640px de .modal-overlay/.modal-card (FASE 3.5).
   ═══════════════════════════════════════════════════════════════ */

/* Sub-pestañas del panel de misiones */
.subtab-row { display: flex; gap: 0.4rem; flex-wrap: wrap; margin-bottom: 0.6rem; }
.subtab {
    border: 1px solid var(--color-border); background: var(--color-surface);
    color: var(--color-text-muted); border-radius: var(--radius);
    padding: 0.45rem 0.85rem; font-size: 0.9rem; font-weight: 600;
    cursor: pointer; min-height: 40px;
}
.subtab-active { background: var(--color-primary-soft, #e8f2fd); color: var(--color-primary); border-color: var(--color-primary); }

/* Ledger de créditos */
.mission-ledger { display: flex; flex-direction: column; gap: 0.4rem; }
.ledger-row {
    display: flex; justify-content: space-between; align-items: center; gap: 0.6rem;
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 0.6rem 0.8rem;
}
.ledger-amt { font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Condiciones de una participación */
.mission-conditions { display: flex; flex-direction: column; gap: 0.3rem; margin: 0.5rem 0; }
.mission-cond { display: flex; align-items: center; gap: 0.45rem; font-size: 0.9rem; color: var(--color-text-muted); }
.mission-cond.is-met { color: var(--color-success, #10b981); }
.mission-cond .mp-icon { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }
.mission-cond span:nth-child(2) { color: var(--color-text); font-weight: 600; }
.mission-cond-list { margin: 0.3rem 0 0.6rem 1.1rem; }
.mission-cond-list li { margin: 0.15rem 0; }

/* Envíos + evidencia */
.mission-subs { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.6rem; }
.mission-sub { background: var(--color-bg, #f8fafc); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 0.6rem 0.75rem; }
.mission-sub-head { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.25rem; }
.mission-files { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.35rem; }
.mission-ai-flags { margin-top: 0.3rem; font-size: 0.85rem; color: var(--color-warning, #b45309); background: #fffbeb; border-radius: 6px; padding: 0.3rem 0.5rem; }

/* Participaciones (empresa) */
.mission-participation { margin-bottom: 0.75rem; }
.mission-part-actions, .mission-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.6rem; }
.mission-actions { margin-bottom: 1rem; }

/* Tira de créditos del vendedor */
.mission-credit-strip {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 0.5rem; margin: 0.6rem 0 1rem;
}
.mission-credit-strip > div {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 0.55rem 0.7rem; text-align: center;
}
.mission-credit-strip strong { display: block; font-size: 1.2rem; margin-top: 0.15rem; font-variant-numeric: tabular-nums; }
.mission-credit-strip .is-success { color: var(--color-success, #10b981); }
.mission-subhead { font-weight: 700; margin: 0.9rem 0 0.5rem; color: var(--color-text); }
.mission-vendor-card { margin-bottom: 0.7rem; }
.mission-corr { margin-top: 0.4rem; background: #fffbeb; border: 1px solid #fde68a; color: #92400e; border-radius: var(--radius); padding: 0.45rem 0.6rem; font-size: 0.88rem; }
/* Dónde queda el local. Sin flex a propósito: el ícono ya trae vertical-align y
   así el bloque sirve igual para una línea suelta (tarjeta) que para nombre +
   dirección apilados (modal). Margen explícito porque el reset propio lo pisa. */
.mission-where { margin-top: 0.4rem; font-size: 0.9rem; color: var(--color-text-muted); line-height: 1.35; }
.mission-where strong { color: var(--color-text); }

/* Creador de misiones */
.mission-ai-box { background: var(--color-primary-soft, #eef5ff); border: 1px solid var(--color-primary); border-radius: var(--radius); padding: 0.7rem 0.8rem; margin-bottom: 1rem; }
.mission-ai-box textarea { width: 100%; margin: 0.3rem 0; }
.mission-missing { margin-top: 0.3rem; color: var(--color-warning, #b45309); font-size: 0.85rem; }
.field-label { display: block; font-weight: 600; font-size: 0.88rem; margin: 0.7rem 0 0.25rem; }
.mc-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }
.mc-check { display: flex; align-items: center; gap: 0.5rem; margin: 0.5rem 0; font-size: 0.92rem; min-height: 40px; }
.mc-check input { width: auto; }
.mc-evidence-row, .mc-product-row { display: flex; gap: 0.4rem; align-items: center; margin: 0.3rem 0; flex-wrap: wrap; }
.mc-est-picker { background: var(--color-bg, #f8fafc); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 0.6rem; }
.mc-est-option { padding: 0.45rem 0.55rem; border-radius: 6px; cursor: pointer; min-height: 40px; }
.mc-est-option:hover { background: var(--color-primary-soft, #e8f2fd); }
#mission-creator-body input[type="text"], #mission-creator-body input[type="number"],
#mission-creator-body input[type="datetime-local"], #mission-creator-body select,
#mission-creator-body textarea { width: 100%; }

@media (max-width: 640px) {
    .mc-grid2 { grid-template-columns: 1fr; }
    .mission-part-actions .btn, .mission-actions .btn { flex: 1 1 auto; }
}

/* ══════════════════════════════════════════════════════════════
   LIQUIDACIÓN DE COMISIONES Y MISIONES (Boleta de Honorarios SII)
   ══════════════════════════════════════════════════════════════
   Va al FINAL del archivo a propósito: el orden ES la cascada (style.css va sin
   capa y dentro de él gana lo último). Todo declara su padding/margin explícito
   porque el reset propio `*{margin:0;padding:0}` pisa lo de Tabler.

   Los montos usan `tabular-nums` para que las columnas de plata alineen. El
   redondeo tiene un solo dueño en el servidor: acá solo se muestra. */

/* ── Card "Saldo disponible" (Inicio del vendedor) ───────────── */
.balance-card {
    border-left: 3px solid var(--color-success);
    margin-bottom: 1rem;
    padding: 1rem 1.1rem;
}
.balance-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.balance-value {
    font-size: 2rem; font-weight: 700; line-height: 1.15; margin-top: 0.15rem;
    color: var(--color-success); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.balance-unit { font-size: 0.85rem; font-weight: 600; color: var(--color-text-muted); margin-left: 0.4rem; }
.balance-split {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 0.6rem 1.2rem; margin-top: 0.8rem;
}
.balance-split strong { display: block; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.balance-split-muted { border-top: 1px solid var(--color-border); padding-top: 0.7rem; margin-top: 0.8rem; }
.balance-split-muted strong { font-size: 0.95rem; font-weight: 600; }
.balance-actions { margin-top: 0.9rem; }
.balance-blockers { margin-top: 0.8rem; }
.balance-blockers div { margin: 0.1rem 0; }

/* La plata en curso NO desaparece: se ve moviéndose entre estados. */
.bal-flow { margin-top: 0.8rem; border-top: 1px solid var(--color-border); padding-top: 0.7rem; }
.bal-flow-row {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
    padding: 0.35rem 0; font-size: 0.88rem;
}
.bal-flow-code { font-weight: 600; font-variant-numeric: tabular-nums; }
.bal-flow-amt, .bal-flow-net { font-variant-numeric: tabular-nums; }
.bal-flow-net { color: var(--color-success); font-weight: 600; }

/* ── Sección de "Mi cuenta" ──────────────────────────────────── */
.settle-card { margin-bottom: 1rem; padding: 1rem 1.1rem; }
.settle-card h3 { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 0.15rem; }
.settle-metrics { margin-top: 0.8rem; }
.settle-toolbar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.9rem;
    padding: 0.7rem 0.85rem; margin: 0.7rem 0;
}
.settle-all { display: flex; align-items: center; gap: 0.5rem; font-size: 0.9rem; min-height: 40px; }
.settle-all input { width: auto; }
.settle-total { margin-left: auto; text-align: right; }
.settle-total strong { display: block; font-size: 1.25rem; font-variant-numeric: tabular-nums; }

/* ── Tabla de ingresos / de líneas ───────────────────────────── */
.table-scroll { overflow-x: auto; }
.settle-lines { width: 100%; border-collapse: collapse; font-size: 0.88rem; margin-top: 0.3rem; }
.settle-lines th, .settle-lines td { padding: 0.45rem 0.5rem; text-align: left; border-bottom: 1px solid var(--color-border); }
.settle-lines th { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-muted); }
.settle-lines td.num, .settle-lines th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.settle-pick { width: 2.2rem; }
.settle-pick input { width: auto; }
.linklike {
    background: none; border: none; padding: 0; cursor: pointer;
    color: var(--color-primary); font: inherit; text-align: left; text-decoration: underline;
}
.linklike:hover { opacity: 0.8; }

/* ── Modal: la instrucción de emisión ────────────────────────── */
.settle-status-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-bottom: 0.8rem; }
.settle-step { font-size: 0.9rem; color: var(--color-text-muted); }
.settle-step.is-yours { color: var(--color-warning); font-weight: 600; }
.settle-emit {
    background: var(--color-primary-soft, #eef5ff);
    border: 1px solid var(--color-primary);
    border-radius: var(--radius);
    padding: 0.85rem 0.9rem; margin-bottom: 0.9rem;
}
.settle-emit-lead { font-size: 0.95rem; line-height: 1.5; margin-bottom: 0.7rem; }
.settle-emit-warn { color: var(--color-danger); font-weight: 600; }
.settle-amounts { margin-top: 0.2rem; }
.settle-amounts .stat-value { font-variant-numeric: tabular-nums; white-space: nowrap; }
.settle-receiver, .settle-doc, .settle-payment { margin: 0.9rem 0; }

/* El detalle que se pega en el SII: monoespaciado, seleccionable, con su botón
   de copiar (el texto va en data-* — nunca un literal JS dentro de un onclick). */
.settle-detail-box {
    border: 1px dashed var(--color-border); border-radius: var(--radius);
    padding: 0.8rem 0.85rem; margin: 0.9rem 0;
}
.settle-detail {
    background: var(--color-neutral-bg, #f8fafc); border-radius: 6px;
    padding: 0.6rem 0.7rem; margin: 0.5rem 0; font-size: 0.85rem;
    white-space: pre-wrap; word-break: break-word;
    font-family: ui-monospace, Menlo, Consolas, monospace;
}
.settle-detail-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.settle-issues { margin: 0.35rem 0 0 1.1rem; }
.settle-issues li { margin: 0.15rem 0; }
.settle-ok {
    background: color-mix(in srgb, var(--color-success) 10%, transparent);
    border: 1px solid var(--color-success); border-radius: var(--radius);
    padding: 0.55rem 0.7rem; margin: 0.8rem 0; font-size: 0.88rem; color: var(--color-success);
}

/* ── Formularios de subida / pago / checklist ────────────────── */
.settle-upload { border-top: 1px solid var(--color-border); margin-top: 1rem; padding-top: 0.9rem; }
.settle-upload h4 { margin-bottom: 0.2rem; }
.settle-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.6rem 0.9rem; margin: 0.6rem 0; }
.settle-fields label { display: block; font-weight: 600; font-size: 0.85rem; margin-bottom: 0.2rem; }
.settle-fields input, .settle-fields select { width: 100%; }
.settle-upload-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.6rem; }
.settle-checklist {
    background: var(--color-neutral-bg, #f8fafc); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 0.75rem 0.85rem; margin: 0.9rem 0;
}
.settle-checklist h4 { margin-bottom: 0.4rem; }
.settle-check { display: flex; align-items: flex-start; gap: 0.55rem; margin: 0.35rem 0; font-size: 0.9rem; min-height: 40px; }
.settle-check input { width: auto; margin-top: 0.15rem; }
.settle-timeline { margin-top: 0.4rem; }

/* ── Móvil primero: el vendedor vive en terreno con el teléfono ─ */
@media (max-width: 640px) {
    .balance-value { font-size: 1.7rem; }
    .balance-head { align-items: center; }
    .balance-split { grid-template-columns: 1fr 1fr; }
    .balance-actions .btn { width: 100%; min-height: 44px; }
    .settle-toolbar { flex-direction: column; align-items: stretch; }
    .settle-total { margin-left: 0; text-align: left; }
    .settle-toolbar .btn { width: 100%; min-height: 44px; }
    .settle-fields { grid-template-columns: 1fr; }
    .settle-detail-actions .btn { flex: 1 1 auto; min-height: 40px; }
    .bal-flow-row { flex-direction: column; align-items: flex-start; gap: 0.15rem; }

    /* La tabla se APILA en tarjetas: sin esto el scroll horizontal esconde justo
       la columna del monto, que es la que importa. Clase aislada (.settle-lines)
       para no contaminar las tablas del pedido. */
    .table-scroll { overflow-x: visible; }
    .settle-lines thead { display: none; }
    .settle-lines,
    .settle-lines tbody,
    .settle-lines tr,
    .settle-lines td { display: block; width: 100%; }
    .settle-lines tr {
        border: 1px solid var(--color-border); border-radius: var(--radius);
        padding: 0.55rem 0.75rem; margin-bottom: 0.6rem;
    }
    .settle-lines td { border: none; padding: 0.12rem 0; }
    .settle-lines td[data-label] {
        display: flex; justify-content: space-between; align-items: baseline; text-align: right;
    }
    .settle-lines td[data-label]::before {
        content: attr(data-label);
        color: var(--color-text-muted); font-weight: 600;
        text-align: left; margin-right: 1rem;
    }
    .settle-lines td.settle-pick { display: block; text-align: left; }
    .settle-lines td.settle-pick input { min-width: 22px; min-height: 22px; }
}

/* ══════════════════════════════════════════════════════════════
   PRUEBA DE CONEXIÓN (Configuración → API)
   ══════════════════════════════════════════════════════════════
   El semáforo por integración. Antes, configurar una key era a ciegas: se
   guardaba y no había forma de saber si servía hasta que la feature fallaba
   (o peor, hasta que NO fallaba de forma visible — el mapa se veía gris y
   nadie sabía por qué).

   El punto de color lleva SIEMPRE su palabra al lado ("PASSED"/"NO PASSED"):
   el color solo no le sirve a quien no distingue rojo de verde, y tampoco a
   un lector de pantalla. */

.conn-test {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin: 0.35rem 0 0.9rem;
}

.conn-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: 0 0 auto;
    margin-top: 0.55rem;
    background: var(--color-border, #e5e7eb);
}
.conn-dot[data-state="passed"]  { background: var(--color-success, #2fb344); }
.conn-dot[data-state="failed"]  { background: var(--color-danger,  #d63939); }
.conn-dot[data-state="testing"] {
    background: var(--color-primary, #1d4ed8);
    animation: conn-pulse 1s ease-in-out infinite;
}

@keyframes conn-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
    .conn-dot[data-state="testing"] { animation: none; }
}

.conn-msg {
    margin: 0.4rem 0 0;
    flex: 1 1 260px;
    min-width: 0;          /* deja que el texto largo corte en vez de desbordar */
    line-height: 1.45;
}

.conn-verdict { letter-spacing: 0.02em; }
.conn-passed  { color: var(--color-success, #2fb344); }
.conn-failed  { color: var(--color-danger,  #d63939); }

/* El detalle (la pista accionable) va debajo y más chico: el veredicto tiene
   que leerse de un vistazo, el porqué se lee después. */
.conn-detail {
    display: block;
    margin-top: 0.2rem;
    font-size: 0.85em;
    opacity: 0.85;
}

/* Móvil: el botón a todo el ancho y el resultado abajo — en 375px, botón y
   mensaje en la misma línea dejan el mensaje en una columna de 3 palabras. */
@media (max-width: 640px) {
    .conn-test > .btn { width: 100%; }
    .conn-dot { margin-top: 0.35rem; }
    .conn-msg { flex-basis: 100%; }
}

/* ══════════════════════════════════════════════════════════════
   TASA DE RETENCIÓN — lo que rige HOY (Configuración → Liquidación)
   ══════════════════════════════════════════════════════════════
   La pantalla tenía una lista de años y dos campos para teclear, pero no decía
   cuál se estaba aplicando. Esto responde esa pregunta de un vistazo, y avisa
   fuerte cuando la tasa del año en curso NO está cargada — porque en ese caso
   se está reteniendo con la de un año anterior, o sea de menos, en silencio y
   en todas las boletas. */

.rate-current {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    flex-wrap: wrap;
    border: 1px solid var(--color-border, #e5e7eb);
    border-left-width: 3px;
    border-radius: var(--radius, 6px);
    padding: 0.7rem 0.9rem;
    margin: 0.6rem 0 0.2rem;
}
.rate-current.is-ok   { border-left-color: var(--color-success, #2fb344); }
.rate-current.is-warn { border-left-color: var(--color-warning, #f76707); }

.rate-current .rate-year {
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted, #6c7a91);
    font-weight: 600;
}
.rate-current .rate-value {
    font-size: 1.35rem;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.rate-current > span:last-child {
    flex: 1 1 100%;
    font-size: 0.88rem;
    color: var(--color-text-muted, #6c7a91);
    line-height: 1.45;
}

/* El editor va PLEGADO: corregir una tasa es excepcional (solo si cambia la
   ley), así que no puede competir visualmente con el dato que sí se consulta. */
.rate-editor { margin-top: 0.9rem; }
.rate-editor > summary {
    cursor: pointer;
    font-weight: 600;
    padding: 0.35rem 0;
    min-height: 40px;              /* objetivo táctil en móvil */
    display: flex;
    align-items: center;
}
.rate-editor > summary:hover { color: var(--color-primary, #1d4ed8); }

/* ═══════════════════════════════════════════════════════════════
   FOTO DEL PRODUCTO — miniatura, campo del formulario y visor
   ═══════════════════════════════════════════════════════════════

   La foto la sube la empresa (fondo blanco) y el servidor genera la miniatura.
   La miniatura se dibuja en tres lugares —tabla del catálogo, catálogo del
   vendedor sobre el pedido, y ficha de empresa— así que la clase es UNA sola
   (`.prod-thumb`) y se ve igual en los tres. */

.prod-thumb {
    /* Fondo blanco propio: la foto viene sobre blanco, y si la tarjeta de atrás
       fuera gris (o el tema oscuro) se vería un recuadro flotando. */
    background: #fff;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    /* 9:16, el formato del catálogo: la proporción de la pantalla del teléfono.
       Se declara con `aspect-ratio` y no con un alto fijo para que cambiar el
       ancho en un contexto (la tabla de la empresa lo hace) no descuadre nada. */
    width: 48px;
    aspect-ratio: 9 / 16;
    padding: 2px;
    display: block;
    flex: 0 0 auto;
    overflow: hidden;
    cursor: pointer;
    line-height: 0;
}

/* En el escritorio de la empresa hay espacio de sobra en la columna «Foto». */
#catalog-products-list .prod-thumb { width: 58px; }

.prod-thumb img {
    width: 100%;
    height: 100%;
    /* `contain`, nunca `cover`: recortar le cortaría la cabeza a un producto
       vertical, que es justo lo que hay que reconocer de un vistazo. */
    object-fit: contain;
    display: block;
}

.prod-thumb:hover { border-color: var(--color-primary); }

/* Sin foto, en las pantallas del vendedor: un hueco sobrio y NO clicable — un
   recuadro que se puede tocar y no hace nada se lee como roto. */
.prod-thumb--empty {
    background: var(--color-neutral-bg);
    cursor: default;
}

/* El chip del fondo, bajo la miniatura en la tabla de la empresa. */
.prod-thumb-warn {
    margin-top: 0.25rem;
    display: inline-block;
    cursor: help;
}

/* Campo de foto en el modal de producto. */
.photo-field {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
    margin-bottom: 0.75rem;
}

.photo-field-preview {
    background: #fff;
    border: 1px dashed var(--color-border);
    border-radius: var(--radius);
    /* 9:16, igual que el catálogo: la previsualización tiene que mostrar el
       encuadre REAL con el que va a quedar, márgenes blancos incluidos. */
    width: 92px;
    aspect-ratio: 9 / 16;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    overflow: hidden;
}

.photo-field-preview img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.photo-field-empty {
    color: var(--color-text-muted);
    font-size: 0.75rem;
}

/* El aviso del fondo montado sobre la previsualización: pegado a la foto que
   describe, no perdido en otra parte del formulario. */
.photo-field-warn {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--color-warning-bg, #fff3cd);
    color: var(--color-warning-text, #7a5b00);
    font-size: 0.62rem;
    font-weight: 700;
    text-align: center;
    padding: 0.12rem 0.2rem;
    cursor: help;
}

.photo-field-actions { min-width: 0; }

/* Fila del catálogo en la ficha de empresa: la miniatura entra a la izquierda
   sin romper el nombre-a-la-izquierda / precio-a-la-derecha que ya tenía. */
.ficha-catalog-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    border-bottom: 1px solid var(--color-border);
    padding: 0.35rem 0;
}

/* ⚠️ El nombre lleva CLASE PROPIA, no `span:nth-of-type(1)`.
   Con el selector posicional, el placeholder de "sin foto" —que también es un
   <span> y va primero— se llevaba el `flex: 1 1 auto`: crecía a ~250 px de ancho
   y el `aspect-ratio: 9/16` le disparaba el alto a 443 px. En pantalla eran
   recuadros gigantes en cada producto sin foto. */
.ficha-catalog-row .ficha-catalog-name { flex: 1 1 auto; min-width: 0; }

/* Y la miniatura no crece ni se encoge pase lo que pase. */
.ficha-catalog-row .prod-thumb { flex: 0 0 auto; }

/* En ESCRITORIO la ficha de empresa se ensancha: hoy el catálogo entra en una
   columna angosta pensada para el teléfono, y ahí no cabe la información que
   viene después (stock, últimos precios, ficha del producto). En móvil se queda
   como está — el modal ya es de pantalla completa. */
@media (min-width: 900px) {
    #company-detail-modal .modal-card { max-width: 760px; width: 92%; }

    .ficha-catalog-row .prod-thumb { width: 64px; }
}

/* ── El visor a pantalla completa ──────────────────────────────
   Es el momento de MOSTRARLE el producto al cliente: la foto ocupa todo, sin
   barras ni botones, y un toque en cualquier parte cierra.

   z-index 1250: por encima del catálogo, que se dibuja en 1100 (igual que la
   Ficha) — ver el comentario de #ficha-overlay más arriba. Por debajo del
   datepicker (1300), que nunca convive con esto. */
.photo-viewer {
    position: fixed;
    inset: 0;
    z-index: 1250;
    background: rgba(12, 16, 22, 0.94);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    cursor: zoom-out;
    /* Notch y barra de gestos arriba y abajo; **a los lados no hay padding**: la
       foto es 9:16, la pantalla del teléfono también, y el punto de este formato es
       que la foto use TODO el ancho cuando el vendedor se la muestra al cliente.
       Un centímetro de negro a cada lado se lo comía sin proteger de nada (en
       vertical el notch está arriba, no al costado). */
    padding: max(0.75rem, env(safe-area-inset-top)) 0
             max(0.75rem, env(safe-area-inset-bottom));
}

.photo-viewer-img {
    max-width: 100%;
    /* 88vh y no 82: con 82 el alto ganaba por unos pocos píxeles y la foto volvía a
       quedar angosta. Deja espacio de sobra para el pie. */
    max-height: 88vh;
    object-fit: contain;
    background: #fff;
    border-radius: var(--radius);
    display: block;
}

/* Mientras llega la original se muestra la miniatura estirada: en la calle, con
   señal mala, la alternativa es un rectángulo negro por varios segundos. Se
   difumina apenas para que no se lea como una foto de mala calidad. */
.photo-viewer-img.is-loading { filter: blur(1.5px); }

.photo-viewer-caption {
    color: #fff;
    text-align: center;
    font-weight: 600;
    margin: 0;
    max-width: 90%;
}

.photo-viewer-caption span {
    display: block;
    font-weight: 400;
    font-size: 0.8rem;
    opacity: 0.7;
    margin-top: 0.2rem;
}

@media (prefers-reduced-motion: reduce) {
    .photo-viewer-img.is-loading { filter: none; }
}

/* ── Móvil: el catálogo del vendedor es una LISTA ──────────────
   El vendedor trabaja en un teléfono chico. Apilando como el resto de
   `.order-lines-catalog`, la foto quedaría ARRIBA del texto y cada producto se
   comería media pantalla. Acá la fila se dibuja como una grilla de dos
   columnas: la miniatura fija a la izquierda, ocupando el alto completo, y
   nombre y precios fluyendo a su derecha. Entran ~6 productos por pantalla. */
@media (max-width: 640px) {
    .order-lines-catalog tr {
        display: grid;
        grid-template-columns: 56px repeat(3, 1fr);
        column-gap: 0.5rem;
        align-items: start;
        padding: 0.5rem 0.6rem;
    }

    .order-lines-catalog td.cell-thumb {
        grid-column: 1;
        grid-row: 1 / 3;
        align-self: center;
    }

    /* Nombre + SKU: toda la fila de arriba, a la derecha de la foto. */
    .order-lines-catalog td:not(.cell-thumb):not(.num) {
        grid-column: 2 / -1;
        grid-row: 1;
    }

    /* Los tres precios comparten UNA fila, con el rótulo encima del número.
       Apilados uno bajo otro la tarjeta medía 160 px y entraban menos de 5
       productos por pantalla; así mide ~110 px y entran 7. El vendedor recorre
       el catálogo con el cliente al lado: cada scroll de más es tiempo suyo. */
    .order-lines-catalog td.num {
        grid-row: 2;
        display: block;
        text-align: left;
        padding-top: 0.2rem;
    }

    .order-lines-catalog td.num::before {
        display: block;
        margin: 0 0 0.05rem;
        font-size: 0.64rem;
        text-transform: uppercase;
        letter-spacing: 0.02em;
    }

    /* La miniatura acompaña al ancho de su columna. En 9:16, 46 px de ancho dan
       82 px de alto — justo lo que miden las dos filas de texto de al lado, así
       que la foto no estira la tarjeta. */
    .order-lines-catalog .prod-thumb { width: 46px; }
}

/* La línea que explica qué se hizo con el encuadre, bajo la previsualización del
   modal de producto. El texto lo compone la app a partir de un código cerrado —
   nunca es texto del modelo. */
.framing-line {
    margin-top: 0.4rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
   FASE 4 — SISTEMA DE DISEÑO TRIVENTA (aplicación a la app operativa)
   Solo presentación. Los colores/radios/sombras ya migraron vía los tokens
   :root (arriba); acá va lo que un swap de tokens no cubre: la tipografía de
   marca (Poppins/Inter) y micro-ajustes de componente contra
   REFERENCIA-COMPONENTES.md. Sin capa → gana por orden de fuente. No toca
   datos, rutas ni textos. Ver SESSION_LOG.
   ═══════════════════════════════════════════════════════════════════════════ */

/* — Tipografía ————————————————————————————————————————————————————————————
   Poppins = titulares, cifras y botones (display). Inter = cuerpo/UI (--font,
   ya heredado por <body>). Tracking negativo leve en los titulares. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    letter-spacing: -0.01em;
}
/* Titulares de marca sobre fondo claro → navy (no el azul interactivo). */
.app-header h1,
.app-brand,
.auth-card h2 {
    font-family: var(--font-display);
    color: var(--color-heading);
    letter-spacing: -0.01em;
}
/* Cifras (métricas, embudo del pipeline) = Poppins, tracking apretado. */
.stat-value,
.pipe-chip-n {
    font-family: var(--font-display);
    letter-spacing: -0.02em;
}

/* — Botones (REFERENCIA §Button) ——————————————————————————————————————————
   Poppins 600, tracking -0.5%, hundida de 1px al presionar. El primario lleva
   una sombra navy sutil. El verde/naranjo llevan texto navy (regla más arriba). */
.btn {
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.005em;
    transition: background .16s ease, transform .1s ease, border-color .16s ease, opacity .15s ease;
}
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn-primary { box-shadow: 0 1px 2px rgba(11, 29, 59, 0.18); }

/* — Tarjeta de métrica (REFERENCIA §StatCard): esquina 12px. El resto de la app
   queda en 8px (--radius base), fiel a "la app usa radios chicos, no marketing". */
.stat-card { border-radius: var(--radius-lg); }

/* — Tarjetas (REFERENCIA §Card) —————————————————————————————————————————————
   Superficie blanca con borde slate + sombra suave (el .card base ya la lleva).
   Las clicables se elevan 2px al pasar el mouse; conservan su propia sombra de
   hover (que ya migró a corp-blue), acá solo se suma el translate. */
.card--clickable,
.order-card,
.ficha-hero-clickable {
    transition: box-shadow .18s ease, border-color .18s ease, transform .18s ease;
}
.card--clickable:hover,
.order-card:hover,
.ficha-hero-clickable:hover { transform: translateY(-2px); }

/* — Mapa: el lienzo se lee como una tarjeta (sombra suave). Los marcadores (capas
   + semáforo de afinidad) ya se alinearon a la paleta Triventa en app.js:
   origen/radio corp-blue, potencial verde #10b981, poco afín slate, guardado
   violeta, cartera dorada. */
.map-canvas { box-shadow: var(--shadow-sm); }

/* ═══════════════════════════════════════════════════════════════════════════
   FASE 5 — TOPBAR TRIVENTA (logo + campana IconBtn + chip de usuario "Mi cuenta")
   Solo presentación. El texto "Portal…" salió del topbar (lo reemplaza el logo);
   "Mi cuenta" salió del menú y vive en el dropdown del chip (buildTabsForUser /
   MENU_HIDDEN + __mpSetUserChip en app.js). Sin capa → gana por orden de fuente.
   ═══════════════════════════════════════════════════════════════════════════ */

/* — Logo de marca (reemplaza al ◆ + "Portal…") ————————————————————————————— */
.app-brand { display: inline-flex; align-items: center; padding: 0; margin: 0; text-decoration: none; }
.app-logo { display: block; width: auto; }
.app-logo-full { height: 34px; }          /* logo completo (con descriptor), escritorio */
.app-logo-mark { display: none; height: 30px; } /* isotipo, móvil */

/* — Campana: botón de ícono (patrón IconBtn) con contador rojo (--color-danger) — */
.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; padding: 0; border-radius: var(--radius);
    background: none; border: none; cursor: pointer;
    color: var(--text-secondary); transition: background .12s ease, color .12s ease;
}
.icon-btn:hover { background: var(--slate-100); color: var(--text-primary); }
.notif-bell.icon-btn { font-size: inherit; }
.notif-bell .mp-icon { width: 21px; height: 21px; }

/* — Chip de usuario = "Mi cuenta" (avatar navy 34px + nombre + chevron) ————— */
.user-wrap { position: relative; }
.user-chip {
    display: inline-flex; align-items: center; gap: 0.5rem;
    background: none; border: none; cursor: pointer;
    padding: 0.2rem 0.4rem; border-radius: var(--radius-pill);
    font-family: var(--font-text); transition: background .15s ease;
}
.user-chip:hover { background: var(--slate-100); }
.user-avatar {
    width: 34px; height: 34px; border-radius: 50%; flex: none;
    background: var(--triventa-navy); color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    font-family: var(--font-display); font-weight: 600; font-size: 14px;
}
.user-name { font-size: 13.5px; font-weight: 600; color: var(--text-primary); white-space: nowrap; }
.user-chevron { display: inline-flex; color: var(--text-muted); }
.user-chevron .mp-icon { width: 15px; height: 15px; }

/* — Dropdown del chip: fondo blanco, borde subtle, radio 12px, sombra md ——— */
.user-menu {
    position: absolute; right: 0; top: calc(100% + 6px);
    min-width: 240px; padding: 6px; z-index: 250;
    background: #fff; border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
}
.user-menu-head {
    display: flex; flex-direction: column; gap: 2px;
    padding: 8px 10px 10px; margin-bottom: 6px;
    border-bottom: 1px solid var(--border-subtle);
    font-family: var(--font-display); font-weight: 600; font-size: 14px;
    color: var(--text-heading);
}
.user-menu-role { font-family: var(--font-text); font-weight: 500; font-size: 11.5px; color: var(--text-muted); }
.user-menu-item {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 9px 10px; border-radius: var(--radius);
    background: none; border: none; cursor: pointer; text-align: left;
    font-family: var(--font-text); font-size: 13.5px; font-weight: 500;
    color: var(--text-primary); transition: background .12s ease;
}
.user-menu-item:hover { background: var(--slate-100); }
.user-menu-item .mp-icon { width: 18px; height: 18px; color: var(--text-muted); flex: none; }
.user-menu-danger, .user-menu-danger .mp-icon { color: var(--color-danger); }
.user-menu-sep { height: 1px; background: var(--border-subtle); margin: 6px 4px; }

/* — Móvil: isotipo en vez del logo completo; el nombre del chip se oculta ——— */
@media (max-width: 767.98px) {
    .app-logo-full { display: none; }
    .app-logo-mark { display: block; height: 28px; }   /* isotipo compacto: cabe en la línea */
    .user-name { display: none; }
    .user-chip { padding: 0.15rem; }
}

/* — Inputs (REFERENCIA §Input): borde 1.5px, la firma del campo Triventa ———— */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"], input[type="tel"],
select, textarea { border-width: 1.5px; }

/* — Alerts (REFERENCIA §Alert): fondo tinte + borde 1px en el tono ————————— */
.status-info { border: 1px solid var(--border-subtle); }
.status-success, .status-ok { border: 1px solid rgba(16, 185, 129, 0.25); }
.status-warning { border: 1px solid rgba(250, 204, 21, 0.40); }
.status-error { border: 1px solid rgba(225, 29, 72, 0.25); }

/* — Pin "Agregar punto de venta" DENTRO del mapa (control TOP-LEFT de Google) ——
   Colapsado = solo el pin; 1er clic (is-armed) despliega la etiqueta de ayuda;
   2º clic arma el modo colocar (is-active). El margen evita pisar los controles
   de Google. Así un clic accidental ya no bloquea el mapa. */
.map-add-fab {
    display: inline-flex; align-items: center; margin: 10px;
    background: #fff; border-radius: var(--radius-pill);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); cursor: pointer;
    color: var(--color-primary); overflow: hidden; user-select: none;
    font-family: var(--font-display); font-weight: 600; font-size: 13.5px;
    transition: background .15s ease, color .15s ease;
}
.map-add-fab:hover { background: var(--slate-50); }
.map-add-fab-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: none;
    font-size: 19px; line-height: 1;
}
.map-add-fab-label {
    max-width: 0; opacity: 0; white-space: nowrap; overflow: hidden; padding: 0;
    transition: max-width .2s ease, opacity .2s ease, padding .2s ease;
}
.map-add-fab.is-armed .map-add-fab-label,
.map-add-fab.is-active .map-add-fab-label { max-width: 240px; opacity: 1; padding-right: 16px; }
.map-add-fab.is-active { background: var(--color-primary); color: #fff; }

/* — "Dónde estoy" DENTRO del mapa (control RIGHT_TOP de Google) — SOLO en móvil.
   En escritorio se oculta: manda el botón de la barra de arriba (que se queda donde
   está). Un clic = geolocaliza directo (__mpLocateMe). Botón redondo estilo control
   de Google. */
.map-locate-fab {
    display: none;   /* escritorio: el botón de la barra manda */
    align-items: center; justify-content: center;
    width: 40px; height: 40px; margin: 10px;
    background: #fff; border-radius: 50%;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); cursor: pointer;
    color: var(--color-primary); user-select: none;
}
.map-locate-fab:hover { background: var(--slate-50); }
.map-locate-fab .mp-icon { width: 22px; height: 22px; }
@media (max-width: 640px) {
    .map-locate-fab { display: inline-flex; }   /* móvil: aparece en el mapa */
    #map-locate { display: none; }              /* móvil: sale de la barra de arriba */
}

