/* ============================================================================
   components.css — Primitivas de UI reutilizables del CRM Saphir Parfums
   ----------------------------------------------------------------------------
   Capa intermedia entre `app.css` (variables + base) y los `.razor.css` scoped
   por componente. Todo lo que viva aquí debe cumplir DOS condiciones:

   1. Ser un patrón compartido por 2+ componentes (modal, botón, campo de
      formulario, alert, spinner). Si solo lo usa un componente, vive en su
      `.razor.css`.

   2. No depender del scope de un componente concreto. Las reglas son globales
      a propósito — los `.razor.css` siguen pudiendo sobreescribir puntualmente
      gracias a la mayor especificidad que da el atributo `[b-xxxxxx]` que
      Blazor inyecta al compilar.

   Convenciones de naming
   ----------------------------------------------------------------------------
   Las clases conservan los nombres ya en uso por los componentes (`btn-primary`,
   `btn-secondary`, `btn-icon`, `field`, `form-alert`, `spin`) para que la
   migración sea sustracción, no renombrado masivo. Los prefijos `crm-modal-*`
   son nuevos y solo los usa `Shared/ModalShell.razor`.
   ========================================================================== */


/* ── Botones ──────────────────────────────────────────────────────────────── */
.btn-primary,
.btn-secondary {
    padding: 0.5rem 1rem;
    border-radius: 8px;
    font-size: 0.88rem;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: inherit;
}

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

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

.btn-primary:disabled,
.btn-secondary:disabled,
.btn-danger:disabled {
    opacity: 0.6;
    cursor: default;
}

/* Botón destructivo — confirmación de borrado y similares. Usa los mismos
   patrones de tamaño que .btn-primary/.btn-secondary para encajar en el
   footer del ModalShell sin estilos extra. */
.btn-danger {
    padding: 0.5rem 1rem;
    border-radius: 8px;
    font-size: 0.88rem;
    font-weight: 600;
    border: 1px solid var(--color-danger);
    background: var(--color-danger);
    color: #fff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: inherit;
}
.btn-danger:hover:not(:disabled) {
    background: #B62929;
    border-color: #B62929;
}

/* Botón icono — cierres de modal, acciones compactas en cabeceras */
.btn-icon {
    background: transparent;
    border: none;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    cursor: pointer;
    color: var(--color-text-secondary);
    transition: background 0.12s;
}
.btn-icon:hover {
    background: var(--color-bg);
}
.btn-icon .material-symbols-outlined {
    font-size: 22px;
}


/* ── Formularios ──────────────────────────────────────────────────────────── */
.field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    min-width: 0;
}
.field--wide {
    grid-column: 1 / -1;
}
.field label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-secondary);
    font-weight: 600;
}
.field input,
.field select,
.field textarea {
    border: 1px solid var(--color-border);
    border-radius: 6px;
    padding: 0.5rem 0.6rem;
    font-family: inherit;
    /* 16px mínimo: con valores menores Safari iOS dispara zoom forzado al focus
       en cada input. La regla aplica a TODOS los formularios que usan .field. */
    font-size: 1rem;
    color: var(--color-text);
    background: var(--color-surface);
    outline: none;
    transition: border-color 0.12s;
}
.field textarea {
    resize: vertical;
    min-height: 72px;
}
.field input:focus,
.field select:focus,
.field textarea:focus {
    border-color: var(--color-primary);
}

.input-error {
    border-color: var(--color-danger) !important;
}
.field-error {
    color: var(--color-danger);
    font-size: 0.78rem;
}
.field-help {
    color: var(--color-text-secondary);
    font-size: 0.78rem;
}
.req {
    color: var(--color-danger);
}


/* ── Alerts en formularios ───────────────────────────────────────────────── */
.form-alert {
    padding: 0.6rem 0.9rem;
    border-radius: 6px;
    font-size: 0.88rem;
}
.form-alert--error {
    background: rgba(204, 51, 51, 0.08);
    color: var(--color-danger);
    border: 1px solid rgba(204, 51, 51, 0.2);
}
.form-alert--success {
    background: rgba(46, 158, 90, 0.08);
    color: var(--color-success);
    border: 1px solid rgba(46, 158, 90, 0.2);
}


/* ── Spinner de carga inline (botones, indicadores) ──────────────────────── */
.spin {
    animation: spin 1s linear infinite;
    font-size: 18px;
}
@keyframes spin {
    100% { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .spin { animation-duration: 0.001ms; }
}


/* ── Banner de contexto en modales (cliente fijado, plantilla previa, etc.)  */
.customer-hint {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.7rem 0.85rem;
    background: rgba(45, 90, 142, 0.06);
    border: 1px solid rgba(45, 90, 142, 0.18);
    border-radius: 8px;
    color: var(--color-text);
}
.customer-hint .material-symbols-outlined {
    color: var(--color-primary);
    font-size: 22px;
}
.customer-hint__text {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    flex: 1;
}
.customer-hint__label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-secondary);
    font-weight: 600;
}
.customer-hint__value {
    font-size: 0.9rem;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}


/* ── Modal shell ──────────────────────────────────────────────────────────
   Las clases `.crm-modal-*` las consume `Shared/ModalShell.razor`. Son
   globales (no scoped) porque ModalShell expone su markup vía atributos
   estándar y los hijos render-fragment no pueden recibir scope ajeno.

   z-index strategy
   ----------------
   - Default (modal raíz, abierto desde una página):  backdrop 1050 / panel 1060
   - Stacked  (modal abierto sobre otro modal):       backdrop 1100 / panel 1110
   - Si en el futuro hay un tercer nivel (popover dentro de modal stacked),
     usar 1130/1140 — coherente con el rango de los pickers ya existentes.
   ───────────────────────────────────────────────────────────────────────── */

.crm-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 1050;
}
.crm-modal-backdrop--stacked {
    z-index: 1100;
}

.crm-modal-panel {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* Fallback `vh` para navegadores antiguos; el `dvh` se aplica si el browser
       lo soporta gracias al @supports de app.css que sobreescribe la variable. */
    max-height: 90vh;
    max-height: min(90dvh, calc(var(--app-100vh) - 24px));
    background: var(--color-surface);
    border-radius: 12px;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.22);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    z-index: 1060;
}
.crm-modal-panel--stacked {
    z-index: 1110;
}

/* Tamaños — alineados con los anchos previos para no romper layouts existentes.
   Anchos crecen ligeramente en pantallas grandes mediante clamp() para que
   pantallas 1440+ no malgasten espacio. */
.crm-modal-panel--compact { width: min(95vw, clamp(360px, 38vw, 480px)); }
.crm-modal-panel--small   { width: min(95vw, clamp(420px, 42vw, 520px)); }
.crm-modal-panel--medium  { width: min(95vw, clamp(460px, 48vw, 560px)); }
.crm-modal-panel--large   { width: min(95vw, clamp(520px, 60vw, 640px)); }

.crm-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
}
.crm-modal-header h3 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--color-text);
}

.crm-modal-body {
    padding: 1.25rem;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    /* Reserva espacio para el teclado virtual: cuando se enfoca un input al
       fondo del modal en móvil, el navegador puede hacer scroll y dejar el
       campo justo bajo el teclado. 56px aproxima la altura típica. */
    scroll-padding-bottom: 56px;
}

.crm-modal-footer {
    padding: 0.85rem 1.25rem;
    border-top: 1px solid var(--color-border);
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    background: #F9FAFD;
}

/* En móvil el modal pasa a full-screen — patrón ya consolidado en v0.18.1.
   En v0.46.0+ usamos `dvh` para que el panel se ajuste al alto REAL del
   viewport (sin barra URL), evitando el bug clásico iOS donde el footer
   queda oculto bajo la barra cuando ésta vuelve a aparecer. */
@media (max-width: 767.98px) {
    .crm-modal-panel {
        width: 100vw;
        height: 100vh;
        max-height: 100vh;
        height: var(--app-100vh);
        max-height: var(--app-100vh);
        top: 0;
        left: 0;
        transform: none;
        border-radius: 0;
    }
    .crm-modal-header { padding: 0.85rem 1rem; }
    .crm-modal-body { padding: 1rem; }
    .crm-modal-footer {
        padding: 0.75rem 1rem;
        flex-direction: column;
        align-items: stretch;
        /* Honor safe-area en iOS (notch / home indicator). */
        padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
    }
    .crm-modal-footer .btn-primary,
    .crm-modal-footer .btn-secondary,
    .crm-modal-footer .btn-danger {
        justify-content: center;
        /* En móvil, garantizar el touch-target Apple HIG (44 px) */
        min-height: 44px;
    }
}

/* En móviles muy estrechos los labels en uppercase de 0.75rem quedan al
   límite de legibilidad — los subimos un punto. */
@media (max-width: 479.98px) {
    .field label { font-size: 0.8rem; }
}

/* En tablet vertical / móvil grande (576-991 px) el header del modal en dos
   líneas (título largo + botón cierre) puede pisarse. Permite que el título
   wrappee si es necesario sin romper la cabecera. */
@media (min-width: 576px) and (max-width: 991.98px) {
    .crm-modal-header h3 {
        font-size: clamp(0.95rem, 1.4vw, 1.05rem);
        line-height: 1.3;
    }
}

/* Headers fluidos: el modal sigue legible en pantallas amplias y compacto en
   móvil. */
.crm-modal-header h3 {
    font-size: clamp(0.95rem, 1.1vw + 0.6rem, 1.1rem);
}

/* En pantallas táctiles (sin hover) los botones-icono ganan padding visual
   para mejorar la tasa de acierto del dedo. */
@media (hover: none) and (pointer: coarse) {
    .btn-icon {
        width: 40px;
        height: 40px;
    }
    .btn-icon .material-symbols-outlined {
        font-size: 24px;
    }
    .btn-primary,
    .btn-secondary,
    .btn-danger {
        min-height: 40px;
        padding: 0.55rem 1rem;
    }
}


/* ── Tablas con scroll horizontal ─────────────────────────────────────────
   Patrón "scroll shadow" (Roman Komarov): gradientes que aparecen en los
   bordes solo cuando hay contenido oculto a izquierda/derecha. Pista visual
   de que la tabla se puede deslizar — crítico en móvil donde no hay
   scrollbar nativa. Aplica globalmente a cualquier .table-scroll usado por
   las listas (Orders, DeliveryNotes, Invoices, ShoppingCarts, etc.). */
.table-scroll {
    background:
        linear-gradient(to right, var(--color-surface) 30%, rgba(255, 255, 255, 0)) left center,
        linear-gradient(to right, rgba(255, 255, 255, 0), var(--color-surface) 70%) right center,
        radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0)) left center,
        radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0)) right center;
    background-repeat: no-repeat;
    background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
}


/* ── Listados que ocupan el alto del viewport (v0.38.0+) ──────────────────
   Patrón opt-in: añade `table-card--fill` a un `.table-card` (o
   `catalog-card--fill` a un `.catalog-card`) para que ocupe todo el alto
   disponible del content area. La cabecera (caption + tabs + toolbar +
   chips) y la paginación quedan fijas, el `.table-scroll` (tbody) o el
   `.items-grid` (vista tarjetas del catálogo) es el único que scrollea
   internamente, y la cabecera de tabla queda sticky.

   Estructura esperada:
     .table-card / .catalog-card (display: flex column, height 100%)
       ├── .table-caption / .catalog-caption (flex-shrink: 0)
       ├── .tab-bar / .toolbar / .active-chips / .cart-lock-banner (flex-shrink: 0)
       ├── .table-scroll / .items-grid (flex: 1, overflow auto)
       └── .pagination-bar (flex-shrink: 0)

   Funciona porque `.layout__content` (MainLayout) tiene altura definida vía
   flex, así que el `height: 100%` del card propaga correctamente. La regla
   gana en especificidad (0,3,0) frente a las reglas scoped de cada página
   (0,2,0), por lo que anula los `max-height: 7Xvh` legacy sin necesidad de
   tocar cada `.razor.css` ni recurrir a `!important`. */
.table-card.table-card--fill,
.catalog-card.catalog-card--fill {
    display: flex;
    flex-direction: column;
    height: 100%;
    max-height: none;
    /* Permite que la card se contraiga si su contenido natural fuera mayor
       (no debería pasar gracias al scroll interno, pero es defensivo). */
    min-height: 0;
}

/* Hijos directos que NO deben crecer ni encogerse — caben con su tamaño
   natural y la zona scrollable se queda con el resto. Si una página añade
   un nuevo bloque "header-like" (banner, chips, breadcrumb), añadir su
   selector aquí. */
.table-card.table-card--fill > .table-caption,
.table-card.table-card--fill > .tab-bar,
.table-card.table-card--fill > .pagination-bar,
.table-card.table-card--fill > .table-toolbar,
.catalog-card.catalog-card--fill > .catalog-caption,
.catalog-card.catalog-card--fill > .toolbar,
.catalog-card.catalog-card--fill > .active-chips,
.catalog-card.catalog-card--fill > .cart-lock-banner,
.catalog-card.catalog-card--fill > .pagination-bar {
    flex-shrink: 0;
}

/* Zona scrollable: tabla (.table-scroll) o rejilla de tarjetas
   (.items-grid en catálogo). `min-height: 0` es la clave que permite que
   un hijo flex pueda contraerse por debajo de su tamaño de contenido y
   activar el overflow interno. */
.table-card.table-card--fill > .table-scroll,
.catalog-card.catalog-card--fill > .table-scroll,
.catalog-card.catalog-card--fill > .items-grid {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* La rejilla de tarjetas no necesita scroll horizontal y suele llevar
   padding interior; sólo activamos el scroll vertical. */
.catalog-card.catalog-card--fill > .items-grid {
    overflow-x: hidden;
}

/* Cabecera de tabla sticky para que las columnas se lean siempre durante el
   scroll interno. Z-index 2 para quedar por encima de `.bc-doc-tag` u otros
   pills de la primera fila. */
.table-card.table-card--fill .crm-table thead th,
.catalog-card.catalog-card--fill .crm-table thead th,
.admin-page--fill .users-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    /* El thead lleva fondo gris en todas las páginas; lo declaro aquí para
       garantizar que al hacer sticky no se vea contenido de fondo a través. */
    background: var(--color-bg);
}


/* ── Páginas admin que ocupan el alto del viewport ────────────────────────
   Pendant del patrón table-card--fill para Users.razor y Configuration.razor,
   que tienen una estructura distinta (header + tabs sueltos + wrapper) en
   lugar de una sola card. El wrapper marcado con .admin-page--fill se
   convierte en flex column de 100% de alto, deja la cabecera y las tabs
   con su tamaño natural y reserva el resto para el .users-table-wrapper
   marcado con .users-table-wrapper--fill, que scrollea internamente. */
.admin-page.admin-page--fill {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.admin-page--fill > .admin-header,
.admin-page--fill > .admin-tabs {
    flex-shrink: 0;
}

.users-table-wrapper.users-table-wrapper--fill {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}


/* ── Container queries — reactividad por contenedor (v0.46.0+) ──────────────
   El sidebar puede estar expandido (256 px) o colapsado (70 px), lo que cambia
   ~186 px del ancho útil del contenido a viewport idéntico. Las media queries
   sobre el viewport no lo distinguen. Marcamos el área de contenido como
   container y exponemos breakpoints de TABLA/CARD que reaccionan al ancho real
   del contenedor, no al viewport. Soporte: Safari ≥16, Chrome ≥105, Firefox
   ≥110 (≈97 % usuarios). Navegadores antiguos ignoran las @container y caen al
   tamaño base — sin regresiones. */
.layout__content {
    container-type: inline-size;
    container-name: content;
}

/* Cuando el contenedor de contenido es muy estrecho (≤720 px de ancho real,
   con sidebar colapsado o sin él), las cards laterales pasan a una sola columna
   automáticamente sin tocar cada `.razor.css`. */
@container content (max-width: 720px) {
    .responsive-grid--auto {
        grid-template-columns: 1fr !important;
    }
}

/* Layout con grid responsive automático para fichas y dashboards.
   Las cards adoptan tantas columnas como permita el contenedor. */
.responsive-grid {
    display: grid;
    gap: var(--space-content);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}
.responsive-grid--narrow {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
}
.responsive-grid--wide {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
}


/* ── Z-index de modales legacy (v0.46.0+) ──────────────────────────────────
   Patrón unificado para los modales que aún no han migrado a ModalShell
   (CustomerList, Users, OrderTemplateDetail, ApplyOrderTemplate,
   NewShoppingCart, ShoppingCartDetailModal, CatalogItemDetailModal,
   IncomingShareModal, OrderDetailModal, DeliveryNoteDetailModal,
   InvoiceDetailModal). Mantienen su CSS scoped propio pero heredan el
   comportamiento de panel responsive. La regla sólo aplica reset de
   max-height a dvh; cada componente sigue manejando width/posicionamiento. */
.modal-panel {
    max-height: 90vh;
    max-height: min(90dvh, calc(var(--app-100vh) - 24px));
}
@media (max-width: 767.98px) {
    .modal-panel {
        max-height: 100vh;
        max-height: var(--app-100vh);
    }
}
