/*
 * Formularios, filtros y listas de contacto de los maestros.
 *
 * Toda pastilla y todo control usa las alturas de --control-*, y todo contenedor flex de
 * controles lleva align-items: center. Es la regla que evita el desalineado de chips.
 */

/* ---- Tarjeta de formulario de página completa ---------------------------------------- */

/* Ancho máximo cómodo para un formulario de página completa (RiskForm, PartnershipForm...),
   sin recurrir a un style="" en la vista -- ver la regla de front-end sobre CSS en ficheros
   aparte. */
.card--narrow {
    max-width: 720px;
}

/* Hermana de .card--narrow para los formularios largos de página completa: alta y cierre de
   visita (cinco cuadros de texto libre con dictado, RF-48) y edición de proyecto y de
   oportunidad (multi-select de servicios, y de etiquetas en proyecto). Con 720px esos
   campos anchos se apretaban y el texto libre saltaba de línea demasiado pronto; 820px es
   el ancho que ya usaban por style="" antes de esta regla, así que el aspecto no cambia. */
.card--medium {
    max-width: 820px;
}

/* ---- Cabecera con acción a la derecha ----------------------------------------------- */

.page-head--row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-6);
    flex-wrap: wrap;
}

/* Dos o más acciones junto a un título (p. ej. "Edit" + "Archive" en la ficha de empresa):
   align-items: center para que el botón y el formulario que envuelve al otro botón midan lo
   mismo, misma regla de siempre para contenedores flex de controles. */
.page-head__actions {
    display: flex;
    align-items: center;
    /* Envuelve: con tres o cuatro acciones (p. ej. las tres exportaciones agrupadas más el
       primario de /Reports/Design) la fila no cabe en un móvil y sacaba la página del viewport.
       En escritorio no cambia nada -- solo actúa cuando de verdad no cabe. */
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* ---- Barra de filtros --------------------------------------------------------------- */

/*
 * align-items: center es la regla de siempre para todo contenedor flex de controles: sin ella
 * un chip estrecho se estira a la altura de la fila y aparece cuadrado entre píldoras.
 */
.filters {
    /*
     * Altura declarada de la barra, no derivada del contenido: la cabecera pegajosa de
     * `.table--data` (components.css) se pega justo debajo con
     * calc(--topbar-height + --filters-height), y esa aritmética necesita un número, no una
     * medida que cambie según qué controles lleve cada pantalla. 56px = --control-md (32) +
     * --space-3 (12) arriba y abajo. Por eso también los controles de filtro van todos en una
     * sola fila, con la etiqueta al lado y no encima.
     */
    --filters-height: 56px;

    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-6);
}

/*
 * Barra de filtros pegajosa (§3.2, plantilla A).
 *
 * Se pega justo bajo la barra superior. --z-sticky, el mismo escalón que `.topbar`: no compiten
 * porque no llegan a solaparse (una empieza donde acaba la otra), y así la cabecera de la tabla
 * (--z-raised, más bajo) pasa por debajo de las dos al desplazar.
 *
 * El fondo es opaco a propósito: sin él, las filas de la tabla se leerían a través de la barra.
 */
.filters--sticky {
    position: sticky;
    top: var(--topbar-height);
    z-index: var(--z-sticky);
    box-sizing: border-box;
    min-height: var(--filters-height);
    margin-bottom: var(--space-6);
    padding: var(--space-3) 0;
    background: var(--surface);
    border-bottom: 1px solid var(--outline-subtle);
}

/*
 * Filtro con etiqueta: la etiqueta va A LA IZQUIERDA del control, no encima. Es lo que mantiene
 * la barra en una sola fila de 56px — que es de lo que depende el `top` de la cabecera pegajosa
 * de la tabla. `.filters .field` (forms.css) apila etiqueta y control y la haría crecer.
 */
.filters__field {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.filters__field > .field__label {
    margin: 0;
    white-space: nowrap;
}

.filters__field input[type="date"] {
    height: var(--control-sm);
    box-sizing: border-box;
}

.search--inline .icon { color: var(--on-surface-variant); }

.search--inline input {
    /* Base = movil (§4.1): a lo ancho de su contenedor. Vuelve a 260px a partir de `md`. */
    width: 100%;
    height: var(--control-sm);
    box-sizing: border-box;
}

.select {
    height: var(--control-sm);
    box-sizing: border-box;
    padding: 0 var(--space-2);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface-container-lowest);
    font-family: var(--font-label);
    font-size: var(--text-body-md-size);
    color: var(--on-surface);
}

.filters .button {
    height: var(--control-sm);
    box-sizing: border-box;
}

/* ---- Filtros en hoja bajo `md` (§4.3, tanda 82) -------------------------------------- */

/*
 * El disparador "Filtros (2)" lo fabrica filters-sheet.js, nunca el marcado: sin JavaScript no
 * debe existir un botón que no abre nada, y la barra de filtros se queda en su sitio de siempre
 * funcionando como el formulario normal que es.
 *
 * MOBILE-FIRST: el botón es el estado base y se APAGA a partir de `md`, donde la barra vuelve a
 * su hueco y hay ancho de sobra para enseñarla entera.
 */
.filters-trigger {
    display: flex;
    align-items: center;
    margin-bottom: var(--space-6);
}

.filters-trigger__button {
    min-height: var(--control-touch);
}

/* Con filtros aplicados el botón deja de ser neutro: el recuento no basta si no se ve de un
   vistazo que la lista de abajo está recortada. */
.filters-trigger--active .filters-trigger__button {
    border-color: var(--primary);
    color: var(--primary);
}

@media (min-width: 768px) {
    .filters-trigger { display: none; }
}

/*
 * La hoja. Lleva la clase `.dialog`, así que hereda de dialog.css el patrón de hoja inferior de
 * la tanda 81 (anclada abajo, 90dvh, esquinas superiores, asa) sin una regla de posición nueva.
 * Aquí solo va lo de dentro.
 */
.filters-sheet__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
}

.filters-sheet__title {
    margin: 0;
    font: var(--text-title-lg);
    letter-spacing: var(--tracking-title-lg);
}

/*
 * La barra de filtros, dentro de la hoja, deja de ser una barra: los controles se apilan a lo
 * ancho, que es la única forma de que un <select> o un campo de fecha sean pulsables con el
 * dedo. Se anulan además las tres propiedades que solo tienen sentido en su sitio original
 * (pegajosa, fondo opaco y regla inferior): dentro de un modal no se pega a nada.
 */
.filters-sheet .filters {
    position: static;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-4);
    margin-bottom: 0;
    padding: 0;
    background: none;
    border-bottom: 0;
}

.filters-sheet .filters__field {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
}

.filters-sheet .filters .button,
.filters-sheet .filters__field input,
.filters-sheet .filters__field select,
.filters-sheet .filters .select {
    width: 100%;
    height: var(--field-touch);
}

/* El filtro de etiquetas de /Projects sí es una nube de píldoras: dentro de la hoja se queda
   en fila envolviendo, no apilado uno por línea. */
.filters-sheet .tag-filter {
    position: static;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    background: none;
    border-bottom: 0;
}

.check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-label);
    font-size: var(--text-body-md-size);
    color: var(--on-surface-variant);
    cursor: pointer;
}

.check input { margin: 0; }

.check-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-top: var(--space-1);
}

/* ---- Formulario --------------------------------------------------------------------- */

.form-block h3 { margin-bottom: var(--space-4); }

/* Base = movil (§4.1): columna unica. Dos columnas a partir de `md`, mas abajo. */
.form-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    border: 0;
    padding: 0;
    margin: 0;
}

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

/* Campo condicional (p. ej. WorkItems.Unblock*, RF-17): oculto por clase y no por el atributo
   `hidden`, porque `.field { display: flex }` es una regla de autor y gana siempre sobre la
   hoja de estilos del user-agent que pone `[hidden] { display: none }`, con independencia de
   la especificidad — el campo se quedaría visible pese al atributo. */
.field--collapsed { display: none; }

/* .field__label también etiqueta un <legend> (p. ej. Customers/Edit, _ScheduleVisitForm,
   _OpportunityForm, Projects/Edit) -- con Bootstrap cargado (1.54) el reboot de Bootstrap fija
   `float: left; width: 100%; margin-bottom: .5rem;` en cualquier <legend>, que sin este bloque
   se sumaría al gap de 4px que ya pone `.field { gap: var(--space-1) }`. float/margin-bottom
   a cero anulan esa regla para que un <legend> se comporte como cualquier otro <label> del
   mismo formulario, sin mover ni un píxel el resto del layout. */
.field__label {
    /* Rótulo en mayúsculas: --text-overline, el único escalón que conserva los 11px (§2.2). */
    font: var(--text-overline);
    letter-spacing: var(--tracking-overline);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    padding: 0;
    margin: 0;
    float: none;
    width: auto;
}

/* Pista corta bajo un campo opcional (p. ej. Table.EstimatedHoursHint, 2.7/RF-23): mismo tono
   apagado que .muted, sin el ancho acotado de .help-text porque aquí vive dentro de un único
   campo del grid, no debajo de un título de bloque. */
.field__hint {
    /* Texto de ayuda bajo un campo: body-sm, tal como fija §5.2. */
    font: var(--text-body-sm);
    color: var(--on-surface-variant);
    margin: 0;
}

/* Mismo tamaño que .field__hint, pero en el tono de --error: para un aviso en línea que sí exige
   atención (p. ej. "elige al menos un campo" en el constructor de informes), no una pista neutra. */
.field__hint--error {
    color: var(--error);
}

.field input,
.field select {
    height: var(--control-sm);
    box-sizing: border-box;
    padding: 0 var(--space-2);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface-container-lowest);
    font-family: var(--font-sans);
    font-size: var(--text-body-md-size);
    color: var(--on-surface);
    outline: none;
    transition: border-color var(--duration-fast) var(--ease-standard),
                box-shadow var(--duration-fast) var(--ease-standard);
}

.field input:focus,
.field select:focus {
    border-color: var(--secondary);
    box-shadow: 0 0 0 1px var(--secondary);
}

/* No es una pastilla, así que no lleva --control-*: la altura de un textarea es de contenido,
   no de control, y forzarla partiría el resumen ejecutivo de una visita en una sola línea. */
.field textarea {
    min-height: 72px;
    box-sizing: border-box;
    padding: var(--space-2);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface-container-lowest);
    font: var(--text-body-md);
    color: var(--on-surface);
    outline: none;
    resize: vertical;
    transition: border-color var(--duration-fast) var(--ease-standard),
                box-shadow var(--duration-fast) var(--ease-standard);
}

.field textarea:focus {
    border-color: var(--secondary);
    box-shadow: 0 0 0 1px var(--secondary);
}

.field textarea:user-invalid { border-color: var(--error); }

/*
 * :user-invalid y no :invalid. La diferencia importa: :invalid marca en rojo un campo
 * obligatorio vacío desde el instante en que se pinta la página, así que un formulario nuevo
 * recibe al usuario con un error que él no ha cometido todavía. :user-invalid solo se activa
 * después de que la persona haya escrito algo o intentado enviar.
 *
 * Tampoco vale el truco de :not(:placeholder-shown): si el campo no tiene atributo placeholder
 * —y estos no lo tienen— esa condición es siempre cierta y volvemos al mismo problema.
 */
.field input:user-invalid,
.field select:user-invalid { border-color: var(--error); }

.form-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

/*
 * Encabezado de grupo dentro de un form-grid largo (p. ej. _WorkItemForm.cshtml: identidad,
 * estado, seguimiento, bloqueo). Mismo tipo que .field__label —misma mayúscula, mismo peso—
 * pero a ancho completo y con un separador fino arriba, para que un formulario de una docena
 * de campos se lea en bloques con sentido en vez de como una lista plana. :first-of-type y no
 * :first-child: el formulario suele empezar con <input type="hidden">/el token antifalsificación
 * antes del primer grupo, así que comparar contra el primer <div> del mismo tipo es lo único que
 * no depende de cuántos campos ocultos haya delante.
 */
.form-section-title {
    grid-column: 1 / -1;
    padding-top: var(--space-2);
    border-top: 1px solid var(--surface-container);
    font: var(--text-overline);
    letter-spacing: var(--tracking-overline);
    text-transform: uppercase;
    color: var(--on-surface-variant);
}

.form-section-title:first-of-type {
    padding-top: 0;
    border-top: 0;
}

/*
 * Escritorio (§4.1). Sustituye a la @media (max-width: 720px) que hacia esto mismo al reves:
 * 720 no era ninguno de los seis breakpoints con nombre, era uno de los siete ad-hoc que la
 * fase 4 viene a retirar. La frontera correcta es `md`, la del dedo y el puntero.
 */
@media (min-width: 768px) {
    .form-grid { grid-template-columns: 1fr 1fr; }
    .search--inline input { width: 260px; }
}

/* ---- Plantilla F: columna de formulario (§3.2) --------------------------------------- */

/*
 * Techo de 720px aplicado POR REGION y no por pagina, para las pantallas donde la columna de
 * formulario convive con una region ancha que no cabe en 720px (el panel de resultado de
 * /Reports/Design, la tabla de revision del importador). Cuando la pagina entera es el
 * formulario se usa data-template="form" en .content__inner (layout.css), que hace lo mismo
 * incluyendo la cabecera.
 *
 * Alineada a la izquierda y no centrada: la cabecera de pagina arranca en la vertical
 * izquierda del contenido, y una columna centrada dejaria el titulo desalineado con sus
 * propios campos.
 */
.form-column {
    max-width: min(720px, 100%);
}

/*
 * Acciones ancladas (§4.3): en un formulario largo el boton de guardar no puede vivir solo al
 * final del scroll. Se pega abajo con position: sticky y respeta env(safe-area-inset-bottom),
 * que en un movil es lo que se lleva el indicador de inicio.
 *
 * sticky y no fixed a proposito: una barra fija se saldria del ancho de la columna y taparia
 * contenido de otras regiones de la misma pagina; sticky se queda dentro del flujo y del
 * ancho de su formulario, y deja de pegarse en cuanto el formulario acaba.
 *
 * Fondo opaco obligatorio: sin el, los campos se leerian a traves de la barra al desplazar.
 * --z-raised (no --z-sticky) para pasar por DEBAJO de la barra de filtros y de la cabecera de
 * tabla pegajosas de la plantilla A, que ya ocupan ese escalon.
 */
.form-actions--anchored {
    position: sticky;
    bottom: 0;
    z-index: var(--z-raised);
    margin-top: var(--space-4);
    padding: var(--space-3) 0 calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    background: var(--surface-container-lowest);
    border-top: 1px solid var(--outline-subtle);
}

/*
 * Agrupacion en bloques de la plantilla F: overline + regla.
 *
 * NO se inventa un componente nuevo. Dentro de un .form-grid ya existia .form-section-title
 * (aqui arriba), y para una <section> suelta ya existe .detail-section de components.css, que
 * es exactamente el mismo contrato visual que pide §3.2 para F: sin marco, regla superior,
 * overline y titulo. Reutilizarla es lo que evita que /Opportunities/Convert y /Reports/Design
 * acaben con un tercer patron de agrupacion propio.
 */

/* ---- Lista de contactos de una empresa ---------------------------------------------- */

.contact-list {
    display: flex;
    flex-direction: column;
}

.contact {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-6);
    border-bottom: 1px solid var(--surface-container);
}

.contact:last-child { border-bottom: 0; }

.contact__name {
    font: var(--text-body-md);
    font-weight: 500;
}

.contact__line {
    display: block;
    font: var(--text-body-sm);
}

/* "Editar" + "Quitar" por fila (hallazgo real del usuario: antes solo había "Quitar", ninguna
   forma de corregir un contacto ya dado de alta). Mismo tratamiento que .collab-comment__actions
   /.visit__actions: dos acciones secundarias en fila, sin competir con el nombre del contacto. */
.contact__actions {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex: 0 0 auto;
}

/* Botón que parece enlace: una acción secundaria dentro de una fila no debe competir
   visualmente con la acción principal de la pantalla. */
.link-button {
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
    font-family: var(--font-label);
    font-size: var(--text-body-sm-size);
    color: var(--on-surface-variant);
    white-space: nowrap;
}

.link-button:hover { color: var(--error); }

/* ---- Fila archivada ----------------------------------------------------------------- */

.is-archived .project-name { color: var(--on-surface-variant); }
.is-archived { opacity: .7; }

/* ---- Aviso de éxito ----------------------------------------------------------------- */

.notice--ok {
    border-left-color: var(--status-done);
    background: var(--surface-container-low);
    color: var(--on-surface);
}

/* ---- Campo de color ----------------------------------------------------------------- */

.color-field {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.color-field input[type="color"] {
    width: var(--control-sm);
    height: var(--control-sm);
    padding: 2px;
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius);
    background: var(--surface-container-lowest);
    cursor: pointer;
    flex: 0 0 auto;
}

.color-field input[type="text"],
.color-field input:not([type]) {
    flex: 1;
    min-width: 0;
    font-family: var(--font-mono);
}

/* ---- Vista previa de marca ---------------------------------------------------------- */

.brand-preview {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-6);
    padding: var(--space-4);
    border: 1px solid var(--outline-variant);
    border-radius: var(--radius-lg);
    background: var(--surface-container-lowest);
}

.brand-preview img {
    max-width: 100%;
    max-height: 56px;
    object-fit: contain;
}


/* ---- Objetivo táctil de los campos (§4.4) -------------------------------------------- */

/*
 * Base = móvil (§4.1). La tabla de §4.4 pide 48px para un campo de formulario bajo `md`; hoy
 * todos usan `--control-md` (32px), que es la mitad justa del mínimo de 44 y se falla con el
 * pulgar de forma sistemática. Aquí crecen de verdad: un campo de texto no puede resolverse con
 * un área de pulsación invisible, porque hay que ver dónde se escribe.
 *
 * El bloque va al final del fichero, después de todas las reglas que fijan `--control-md`, para
 * que la cascada se lea de arriba abajo sin buscar especificidades: primero la pastilla de
 * siempre, después el suelo táctil que la pisa, y por último `md` devolviéndola.
 *
 * El `<textarea>` no entra: su altura es de contenido, no de control, y ya arranca en 72px.
 */
.field input,
.field select,
.select,
.filters__field input[type="date"],
.search--inline input,
.filters .button {
    height: var(--field-touch);
}

/* Una casilla con su rótulo es una sola diana: se le da el mínimo de 44 al conjunto, no al
   cuadrado de 16px del <input>, que es lo que la persona intenta acertar de verdad. */
.check { min-height: var(--control-touch); }

@media (min-width: 768px) {
    .field input,
    .field select,
    .select,
    .filters__field input[type="date"],
    .search--inline input,
    .filters .button {
        height: var(--control-sm);
    }

    .check { min-height: 0; }
}

/*
 * Resumen de filtros activos con salida explícita (maqueta v3, listado de cartera). Se pinta
 * SOLO cuando hay filtro real: la vista no emite la fila cuando no hay ninguno, así que aquí no
 * hace falta ningún estado "vacío".
 *
 * align-items: center, la regla de siempre para todo contenedor flex de controles.
 */
.filter-summary {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
}

.filter-summary__label {
    font-family: var(--font-label);
    font-size: var(--text-label-size);
    font-weight: 600;
    color: var(--on-surface-variant);
}

.filter-summary__clear {
    font-family: var(--font-label);
    font-size: var(--text-body-sm-size);
    font-weight: 600;
}

/*
 * Chip de filtro activo que se quita solo (maqueta 02-proyectos-lista). Es un <a> real: su
 * destino es la misma lista sin ESE filtro, con los demás intactos, así que funciona sin una
 * línea de JavaScript y se puede abrir en otra pestaña.
 *
 * Hereda de .tag su altura fija de píldora; aquí solo se le añade el borde, la mano y la aspa.
 */
.filter-summary__chip {
    box-sizing: border-box;
    border: 1px solid var(--outline-variant);
    background: var(--surface-container-lowest);
    cursor: pointer;

    /*
     * Mínimo táctil bajo `md` (§4.4). A diferencia de los chips de `.tag-filter`, que se van
     * dentro de la hoja de filtros, éste se queda en la página y se pulsa con el pulgar: 24px
     * de alto no es un objetivo aceptable. Mismo mecanismo que `.button` -- `min-height` y no
     * `height`, para que el mínimo gane sobre la altura de píldora sin perseguirla.
     */
    min-height: var(--control-touch);
}

@media (min-width: 768px) {
    .filter-summary__chip { min-height: 0; }
}

.filter-summary__chip:hover {
    background: var(--surface-container);
    text-decoration: none;
}

/* Decorativa (aria-hidden en el marcado): lo que anuncia el lector es el texto oculto de al
 * lado, "Quitar este filtro". */
.filter-summary__x {
    margin-left: var(--space-1);
    font-weight: 700;
    color: var(--on-surface-variant);
    line-height: 1;
}

/*
 * Un nombre de portfolio o de persona largo no puede ensanchar su <select> más allá de la barra.
 * `flex-wrap` ya reparte los controles en varias filas, pero eso no salva de un ÚNICO control
 * más ancho que su contenedor: ahí sí habría desbordamiento horizontal de la página. Con
 * `min-width: 0` el elemento flexible puede encoger por debajo de su contenido, que es
 * justamente lo que el valor `auto` por defecto impide.
 */
.filters__field {
    min-width: 0;
    max-width: 100%;
}

.filters__field > .select {
    min-width: 0;
    max-width: 100%;
    text-overflow: ellipsis;
}
