/* ============================================================================
   Vitta Intranet — hoja de estilos propia (login, portada de clientes,
   esqueleto de staff, "próximamente")
   ----------------------------------------------------------------------------
   Los tokens (color, tipografía, radios, sombras) y los componentes que se
   comparten con WordPress (cabecera, pie, botones, tarjetas) YA NO se
   declaran aquí: vienen de /shared/tokens.css y /shared/base.css (carpeta
   shared/ de la raíz del repo, montada de solo lectura en este contenedor —
   ver docker-compose.yml). Aquí solo vive lo que es propio de estas páginas.
   ========================================================================== */

@import url('/shared/tokens.css');
@import url('/shared/base.css');

/* Satoshi ya no se redeclara aquí: shared/base.css la carga como fuente
   base de todo el proyecto (WordPress + intranet), decisión congelada en
   CLAUDE.md. Antes esta hoja tenía su propio @font-face y su propio
   --font-sans por encima del de tokens.css — con Satoshi ya como base
   compartida, era una duplicación de los mismos 4 archivos. */

/* El atributo [hidden] del navegador tiene la misma especificidad que
   cualquier selector de una clase (p.ej. .card-link { display:block } de
   shared/base.css) y pierde contra él por venir antes en la cascada — un
   elemento con hidden Y una clase que fija su display puede quedar
   VISIBLE pese a hidden=true. Encontrado de verdad probando la tarjeta de
   "Staff" del dashboard con Playwright: el DOM decía hidden=true pero
   seguía pintándose en pantalla. Esta regla, con !important, es la única
   forma fiable de que hidden gane siempre, sea la clase que sea.  */
[hidden] { display: none !important; }

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

/* Icono inline contra shared/icons.svg — ver docs/iconos.md para el
   inventario completo. Tamaño por defecto pensado para interfaz (16-24px);
   los sitios que necesiten los iconos de sección más grandes (64px) lo
   sobrescriben puntualmente. */
.ic { width: 20px; height: 20px; display: block; }

.app-main {
  flex: 1;
  max-width: 960px;
  width: 100%;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
}

/* ── Bienvenida ── */
.welcome { margin-bottom: 1.5rem; }
.welcome h1 {
  font-family: var(--font-sans);
  font-size: 32px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -.2px;
  margin-bottom: .4rem;
}
.welcome p { font-family: var(--font-sans); font-size: 13.5px; color: var(--text-muted); line-height: 1.6; }

/* ── Página "Próximamente" ── */
.placeholder {
  text-align: center;
  padding: 4rem 1rem;
  color: var(--text-muted);
}
.placeholder .icon { margin-bottom: 1rem; }
.placeholder .icon .ic { width: 48px; height: 48px; margin: 0 auto; color: var(--navy); }
.placeholder h1 { font-size: 16px; color: var(--navy); margin-bottom: .5rem; }
.placeholder p { font-size: 13px; margin-bottom: 1.5rem; }
/* Excepción a la regla general de a.back (de abajo): dentro del aviso
   "Próximamente" el botón ya es el último elemento de un único bloque de
   contenido centrado -- empujarlo a la derecha rompería esa composición
   sin ganar nada, así que aquí se queda centrado como el resto del aviso. */
.placeholder a.back {
  display: inline-flex;
  width: auto;
  margin: 0 auto;
}
/* a.back no depende de .placeholder — se usa también suelto (listado y
   formularios de staff). Al final del contenido de cada página (no
   flotante ni fijo -- pedido explícito), alineado a la derecha:
   width:fit-content + margin-left:auto en vez de un wrapper aparte, así
   solo hace falta mover el propio <a> al final del <main> en cada vista. */
a.back {
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  margin-left: auto;
  margin-top: var(--space-6);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--navy);
  text-decoration: none;
  border: 1.5px solid var(--navy);
  border-radius: var(--radius-sm);
  padding: 8px 16px;
}
a.back:hover { background: rgba(35, 35, 70, .05); }
a.back .ic { width: 16px; height: 16px; }

/* ── Interior de la intranet (clientes, staff, próximamente) ──
   Mismo lenguaje visual que el login: fondo a pantalla completa y cabecera
   / tarjetas en "cristal" (blur). Cabecera, botón outline y tarjetas vienen
   de shared/base.css (común con WordPress) — no se toca ese archivo, se
   sobrescriben aquí, en un archivo que WordPress no carga nunca. */
body.app-page {
  /* Fondo propio de la intranet (distinto del login, que se queda con
     fondo-web.svg) -- ver CLAUDE.md, punto 1 de la tanda de maquetación.
     El velo (gradiente blanco translúcido, primera capa) es necesario de
     verdad, medido con contraste real sobre capturas, no a ojo: sin él,
     el texto navy sobre las tarjetas/tablas "cristal" (que dejan ver el
     fondo casi entero, solo aclarado un 14%) bajaba de 4.5:1 en las
     zonas más oscuras de esta imagen en concreto (p.ej. las etiquetas de
     "Mis datos", ~2:1) -- fondo-web.svg (login) no tenía este problema
     porque su rango de luminosidad es más uniforme. */
  background-image:
    linear-gradient(rgba(255, 255, 255, .45), rgba(255, 255, 255, .45)),
    url('/marca/fondo_intranet2.svg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  /* 100vh en móvil no cubre del todo: varía con la barra de direcciones del
     navegador (se recalcula al aparecer/ocultarse) y background-size:cover
     se queda pintado para el 100vh inicial, dejando un hueco al cambiar. Con
     100dvh (viewport dinámico) se recalcula con el propio navegador. Se
     mantiene el min-height:100vh de shared/base.css como iba (no se toca ese
     archivo); esto solo añade el valor más nuevo, que gana por ir después. */
  min-height: 100dvh;
}

/* Sólida en azul marino de marca -- pedido explícito, en vez del cristal
   translúcido que llevaba antes (rgba navy + blur sobre el fondo). Solo
   la intranet: .app-header en sí (shared/base.css) no se toca, y
   WordPress no carga esta hoja. */
body.app-page .app-header {
  background: var(--navy);
  border-bottom: 1px solid rgba(255, 255, 255, .15);
}
/* Los dos SVG de marca (logotipo e isotipo) son de un solo color sólido
   — se fuerzan a blanco igual que en el login, en vez de duplicar archivos
   con otro color. */
body.app-page .app-header__logo { filter: brightness(0) invert(1); }

/* Cabecera de cliente algo más alta que la de siempre (.app-header, común
   con WordPress y con el resto de la intranet, en shared/base.css: no se
   toca ese archivo ni --header-h, que WordPress ya usa para calcular la
   home superpuesta) -- solo sube el padding vertical en las páginas de
   cliente (.client-page, añadida en su <body> junto a .app-page). */
body.client-page .app-header { padding-top: 1.15rem; padding-bottom: 1.15rem; }

body.app-page .app-header .btn-logout {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-color: rgba(255, 255, 255, .6);
  color: var(--white);
}
body.app-page .app-header .btn-logout:hover { background: rgba(255, 255, 255, .12); }

/* "who" ya no enseña el email/nombre de cuenta como texto (se consulta al
   pasar el ratón, en el title) — insignia con un icono de usuario. En las
   pantallas de staff es además un enlace a "Mi cuenta" (<a>, cursor de
   verdad); en el resto sigue siendo un <span> sin comportamiento — sin
   cursor forzado aquí, cada etiqueta trae el suyo por defecto. */
.app-header .who {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .16);
  color: var(--white);
  text-decoration: none;
}
.app-header .who .ic { width: 16px; height: 16px; }

body.app-page .welcome h1 { color: var(--navy); }
body.app-page .welcome p { color: var(--navy); }

body.app-page .placeholder h1 { color: var(--white); }
body.app-page .placeholder p { color: rgba(255, 255, 255, .8); }
body.app-page .placeholder .icon .ic { color: var(--white); }
body.app-page .placeholder a.back {
  color: var(--white);
  border-color: rgba(255, 255, 255, .6);
}
body.app-page .placeholder a.back:hover { background: rgba(255, 255, 255, .12); }

/* Más separación entre tarjetas — venían de var(--space-3)=12px y luego
   var(--space-5)=24px, seguían pegadas. */
body.app-page .cards-grid { gap: var(--space-6); }

/* Portada de cliente: 7 tarjetas (6 secciones + "Mis datos") en 4+3 en
   escritorio -- .cards-grid (shared/base.css, compartido con la
   calculadora pública de WordPress) se queda en 3 columnas como siempre;
   esta modificadora, solo intranet, sube a 4 a partir de --bp-md. En
   móvil no se toca: sigue en 1fr, apiladas. */
@media (min-width: 900px) {
  .cards-grid--client { grid-template-columns: repeat(4, 1fr); }
}

body.app-page .card-link {
  /* Mismo color que .login-card: fondo rgba(255,255,255,.14) y borde
     rgba(255,255,255,.35) — antes .4/blanco sólido. */
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  /* Sin border-radius propio: se queda el var(--radius-lg)=12px de
     shared/base.css, el mismo que usa .login-card — mismo redondeado que
     la ventana del login. */
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  text-align: center; /* icono, título y descripción, todo centrado */
}
body.app-page .card-link:hover { background: rgba(255, 255, 255, .22); }
/* Sin caja de fondo: el icono, a 64px (sin cambios de tamaño), en azul
   oscuro de marca (--navy) — antes --teal, pero con el cristal ya más
   opaco (arriba) hacía falta más contraste, no menos. */
body.app-page .card-link .card-icon {
  width: auto;
  height: auto;
  margin: 0 auto .8rem;
  background: none;
}
body.app-page .card-link .card-icon .ic { width: 64px; height: 64px; color: var(--navy); }
body.app-page .card-link .card-title { color: var(--navy); text-transform: uppercase; font-weight: 900; font-size: 19px; }
/* En ordenador, más pequeño que en móvil (antes 19px en todos los anchos). */
@media (min-width: 768px) {
  body.app-page .card-link .card-title { font-size: 15px; }
}
/* Navy, no blanco -- medido de verdad (ver el comentario del velo, más
   arriba): blanco sobre esta tarjeta "cristal" bajaba de 2.5:1 en las
   zonas claras de fondo_intranet2.svg (donde más se nota, porque
   además es la tarjeta con más tarjetas por fila). Semitransparente
   para distinguirse del título (negrita, navy sólido) sin perder
   contraste. */
body.app-page .card-link .card-desc { color: rgba(35, 35, 70, .72); }

/* ── Menú de secciones de cliente (/clientes/:seccion y /clientes/datos) ──
   Mismo cristal que las tarjetas de la portada, encima del listado (no al
   lado: ver CLAUDE.md, tanda de maquetación, punto 4) — fila siempre,
   envolviendo en varias líneas si no cabe (igual criterio que
   .table-actions/.filter-group, que ya envuelven así en pantallas
   estrechas). */
.side-menu {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
  /* Separación del siguiente bloque (p.ej. el buscador de la sección) --
     sin esto tocaban borde con borde, 0px de por medio: comprobado de
     verdad, no a ojo (getBoundingClientRect: gap real = 0). */
  margin-bottom: var(--space-5);
}
.side-menu--horizontal {
  flex-direction: row;
  flex-wrap: wrap;
}

.side-menu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: .7rem .9rem;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--navy);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  transition: background .15s;
}
.side-menu__item .ic { width: 20px; height: 20px; flex-shrink: 0; }
.side-menu__item:hover { background: rgba(255, 255, 255, .28); }
.side-menu__item.active {
  background: rgba(255, 255, 255, .42);
  border-color: var(--white);
}

/* Más ancho que el resto de .app-main (960px) -- listados/tablas y
   formularios anchos (clientes, staff, alta de cliente, subir
   documentos) lo necesitan; el resto de páginas (portadas, login) se
   queda en el .app-main normal. */
@media (min-width: 768px) {
  .app-main--wide { max-width: 1200px; }
}

/* ── Formularios de staff (alta/edición de cliente) ── */
.staff-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 1.5rem;
}
.form-card {
  max-width: 480px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: var(--radius-lg);
  padding: 1.5rem 1.5rem 1.75rem;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  margin-bottom: 1.5rem;
}
/* Alta de cliente y el paso a paso de "Subir documentos" (buscador +
   resultado): el ancho propio de 480px se quedaba corto -- usan el mismo
   ancho máximo que .app-main--wide (el del listado de clientes), en vez
   de uno propio. Solo estas dos pantallas; el resto de .form-card (alta
   de staff, mi cuenta, ficha de "Mis datos") se queda como está. */
.form-card--wide { max-width: 1200px; }

/* Dos .form-card en paralelo en ordenador ("Mis datos" del cliente, "Mi
   cuenta" del staff) -- apiladas en móvil, como ya venían, sin media
   query propia: flex-wrap ya se encarga solo por debajo de ~700px
   (2×320px no caben). */
.form-cards-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--space-5);
  margin-bottom: 1.5rem;
}
.form-cards-row .form-card {
  flex: 1 1 320px;
  margin-bottom: 0;
}
.form-card h2 {
  font-size: 14px;
  font-weight: 900;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: 1.1rem;
}
.form-field { margin-bottom: 1rem; }
.form-field label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--navy);
  margin-bottom: 6px;
}
.form-field input,
.form-field select {
  width: 100%;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--navy);
  background: rgba(255, 255, 255, .55);
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: var(--radius-md);
  padding: .65rem .8rem;
  outline: none;
}
.form-field select { min-height: 44px; } /* select nativo: dedo, no cursor, igual que el resto */
.form-field input:focus,
.form-field select:focus { border-color: var(--navy); }
.form-field input[readonly] { opacity: .7; cursor: default; }
.form-row { display: flex; gap: 10px; }
.form-row .form-field { flex: 1; }
.form-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.form-actions .btn-primary,
.form-actions .btn-outline { width: auto; }

.form-success {
  display: none;
  border: 1px solid #2e8b57;
  background: rgba(230, 250, 240, .92);
  color: #1e5c3a;
  border-radius: var(--radius-md);
  padding: .7rem .9rem;
  font-size: 12.5px;
  margin-bottom: 1rem;
}
.form-success.show { display: block; }

/* ============================================================================
   Buscador con sugerencias (autocompletar) -- selector de cliente de
   "Subir documentos" (views/staff-documentos.html): busca en el SERVIDOR
   mientras se escribe, nunca carga todos los clientes al navegador.
   ============================================================================ */
.autocomplete { position: relative; }
.autocomplete__list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 320px;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
  /* Sólida, no "cristal" como el resto de la intranet -- mismo criterio
     que .password-modal (ver más abajo): es un panel flotante encima de
     todo lo demás, necesita el máximo contraste, no mimetizarse con el
     fondo que tiene detrás. */
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}
.autocomplete__item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: .7rem .9rem;
  min-height: 44px; /* dedo, no cursor -- se usa desde el móvil en obra */
  justify-content: center;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.autocomplete__item:last-child { border-bottom: none; }
.autocomplete__item:hover,
.autocomplete__item:focus {
  background: var(--bg);
  outline: none;
}
.autocomplete__item[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: .55;
}
.autocomplete__item[aria-disabled="true"]:hover { background: none; }
.autocomplete__name { font-size: 13.5px; font-weight: 700; color: var(--navy); }
.autocomplete__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.autocomplete__empty {
  padding: .9rem;
  font-size: 12.5px;
  color: var(--text-muted);
  text-align: center;
}

/* ============================================================================
   Arrastrar y soltar un archivo -- paso "Archivo" de "Subir documentos"
   ============================================================================ */
.dropzone {
  position: relative;
  text-align: center;
  padding: 1.5rem 1rem;
  border: 2px dashed rgba(35, 35, 70, .35);
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, .35);
  transition: background .15s, border-color .15s;
}
.dropzone.is-dragover { background: rgba(35, 35, 70, .08); border-color: var(--navy); }
.dropzone .ic { width: 28px; height: 28px; margin: 0 auto .5rem; color: var(--navy); }
.dropzone p { font-size: 13px; color: var(--navy); word-break: break-word; }
.dropzone__link { font-weight: 700; text-decoration: underline; }
.dropzone input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

/* ── Login ──
   Diseño distinto del resto de la intranet (fondo a pantalla completa +
   tarjeta "cristal") a partir del mockup de la diseñadora — vive todo aquí,
   scoped a estas clases, sin tocar body ni el resto de componentes
   compartidos con WordPress en shared/base.css. */
body.login-page {
  background-image: url('/marca/fondo-web.svg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  min-height: 100dvh; /* mismo motivo que body.app-page, ver más arriba */
}

.login-wrap {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  padding: 1.5rem;
}

.login-brand img {
  height: 40px;
  width: auto;
  object-fit: contain;
  /* El SVG original es azul marino sólido (#242447) — se fuerza a blanco
     para que se vea sobre el fondo oscuro, en vez de duplicar el archivo
     con otro color. */
  filter: brightness(0) invert(1);
}

.login-card {
  width: 100%;
  max-width: 360px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: var(--radius-lg);
  padding: 1.75rem 1.5rem;
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}

.field { position: relative; margin-bottom: 1rem; }
.field-icon {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  color: var(--teal);
  pointer-events: none;
}
.field input {
  width: 100%;
  font-size: 14px;
  font-family: var(--font-sans);
  color: var(--white);
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(255, 255, 255, .4);
  border-radius: 0;
  padding: .5rem 0 .6rem 34px;
  outline: none;
}
.field input::placeholder { color: rgba(255, 255, 255, .65); }
.field input:focus { border-bottom-color: var(--white); }

.field-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  margin: 1.1rem 0 1.4rem;
  font-size: 12px;
}
.remember {
  display: flex;
  align-items: center;
  gap: 6px;
  color: rgba(255, 255, 255, .85);
  cursor: pointer;
}
.remember input { accent-color: var(--navy); width: 14px; height: 14px; }
#forgotLink {
  color: rgba(255, 255, 255, .85);
  text-decoration: none;
}
#forgotLink:hover { text-decoration: underline; }

.login-card .btn-primary {
  text-transform: uppercase;
  letter-spacing: .5px;
}

.login-confirm {
  text-align: center;
  padding: .5rem 0;
  color: var(--white);
}
.login-confirm__icon { font-size: 28px; margin-bottom: .75rem; }
.login-confirm p { font-size: 13.5px; line-height: 1.6; margin-bottom: 1.25rem; }
.login-confirm a {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--white);
  text-decoration: none;
}
.login-confirm a:hover { text-decoration: underline; }

.form-error {
  display: none;
  border: 1px solid var(--red);
  background: rgba(253, 240, 239, .92);
  color: #922b21;
  border-radius: var(--radius-md);
  padding: .7rem .9rem;
  font-size: 12.5px;
  margin-bottom: 1rem;
}
.form-error.show { display: block; }

/* ── Casilla dentro de un form-field (alta de staff: "dar permisos de
   administrador") — el resto de .form-field es para <input> de texto. ── */
.form-field .checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.form-field .checkbox-row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--navy);
  flex-shrink: 0;
}
.form-field .checkbox-row label {
  margin: 0;
  text-transform: none;
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0;
}

/* ============================================================================
   Tarjeta con contador (dashboard de staff: solicitudes pendientes)
   ========================================================================== */
.badge-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--red);
  color: var(--white);
  font-size: 11px;
  font-weight: 700;
  margin-left: 6px;
  vertical-align: middle;
}

/* ============================================================================
   Barra de herramientas (buscador + filtro + acciones) de los listados
   ========================================================================== */
.table-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: stretch;
  margin-bottom: var(--space-3);
}
.table-toolbar__search {
  position: relative;
  flex: 1 1 220px;
}
.table-toolbar__search .ic {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  color: var(--navy);
  pointer-events: none;
}
.table-toolbar__search input {
  width: 100%;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--navy);
  background: rgba(255, 255, 255, .55);
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: var(--radius-md);
  padding: .7rem .8rem .7rem 34px;
  outline: none;
  min-height: 44px; /* dedo, no cursor -- se usa mucho desde el móvil en obra */
}
.table-toolbar__search input:focus { border-color: var(--navy); }
.table-toolbar__search input::placeholder { color: var(--text-muted); }

.filter-group {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.filter-btn {
  font-family: var(--font-sans);
  font-size: 12.5px;
  font-weight: 600;
  padding: .6rem 1rem;
  min-height: 44px;
  border-radius: var(--radius-sm);
  border: 1.5px solid rgba(35, 35, 70, .4);
  background: rgba(255, 255, 255, .14);
  /* Navy, no blanco -- medido de verdad sobre el fondo real (el SVG con
     su velo, ver el comentario del velo en body.app-page): blanco sobre
     este cristal claro bajaba a ~1,5:1, ilegible. Navy sube a ~10:1. */
  color: var(--navy);
  cursor: pointer;
}
.filter-btn:hover { background: rgba(255, 255, 255, .35); }
.filter-btn.active { background: var(--white); color: var(--navy); border-color: var(--white); }

.table-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
}
.table-actions .btn-outline,
.action-bar .btn-outline {
  width: auto;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* Navy, no blanco -- mismo motivo que .filter-btn de aquí arriba: medido
     sobre el fondo real, blanco daba ~1,5:1 sobre este cristal claro. */
  color: var(--navy);
  border-color: rgba(35, 35, 70, .4);
}
.table-actions .btn-outline:hover,
.action-bar .btn-outline:hover { background: rgba(255, 255, 255, .3); }
.table-actions .btn-outline .ic,
.action-bar .btn-outline .ic { width: 16px; height: 16px; }

/* Botones deshabilitados (reglas del servidor reflejadas en la interfaz:
   autobaja, autodemoción, último admin) — sin scoping a un contenedor
   concreto, porque también aparecen sueltos dentro de una celda de tabla
   (.cell-actions en el listado de staff), no solo en .table-actions o
   .action-bar. */
.btn-outline:disabled {
  opacity: .4;
  cursor: not-allowed;
}
.btn-outline:disabled:hover { background: none; }

.action-bar {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 1.5rem;
}

/* ============================================================================
   Listados de datos (clientes, staff) — MÓVIL PRIMERO: por defecto cada
   fila es una tarjeta legible (nueve técnicos la usan desde el móvil, a
   menudo en obra); desde 700px se convierte en una tabla real dentro de
   una única tarjeta "cristal". El marcado sigue siendo un <table> de
   verdad en los dos casos (semántica y accesibilidad, y necesario para
   que "copiar como tabla" funcione) — solo cambia cómo se pinta.
   ========================================================================== */
.table-wrap { width: 100%; }
@media (min-width: 700px) {
  .table-wrap {
    background: rgba(255, 255, 255, .14);
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: var(--radius-lg);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    padding: .25rem .75rem;
    overflow-x: auto;
  }
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.data-table thead { display: none; }
.data-table tbody tr {
  display: block;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: var(--radius-md);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  margin-bottom: var(--space-3);
  padding: .8rem 1rem;
}
.data-table tbody tr[data-href] { cursor: pointer; }
.data-table td {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
  padding: .4rem 0;
  border-bottom: 1px solid rgba(35, 35, 70, .12);
  color: var(--navy);
  text-align: right;
}
.data-table td:last-child { border-bottom: none; }
.data-table td::before {
  content: attr(data-label);
  font-weight: 700;
  color: var(--navy);
  flex-shrink: 0;
  text-align: left;
}
.data-table td.no-label::before { content: none; }
.data-table td.cell-actions {
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
}
/* Botones sueltos dentro de una fila (conceder/retirar admin, dar de
   baja/reactivar, resolver/descartar solicitud) — dedo, no cursor, igual
   que el resto de botones de la interfaz. */
.data-table td.cell-actions .btn-outline {
  width: auto;
  min-height: 40px;
  /* inline-flex, no el inline-block de .btn-outline (shared/base.css): el
     icono (.ic, display:block) si no quedaba en su propia línea dentro
     del botón -- icono arriba, texto debajo -- doblando el alto de cada
     fila del listado (encontrado de verdad en "Descargar", pero el mismo
     botón se usa en todas las filas con icono+texto de cualquier
     listado). */
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--navy);
  border-color: rgba(35, 35, 70, .4);
}
.data-table td.cell-actions .btn-outline:hover { background: rgba(35, 35, 70, .06); }

@media (min-width: 700px) {
  .data-table thead { display: table-header-group; }
  .data-table th {
    text-align: left;
    padding: .6rem .6rem;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .4px;
    color: var(--navy);
    border-bottom: 1.5px solid rgba(35, 35, 70, .25);
  }
  .data-table tbody tr {
    display: table-row;
    background: none;
    border: none;
    border-radius: 0;
    backdrop-filter: none;
    margin-bottom: 0;
    padding: 0;
  }
  .data-table tbody tr:hover { background: rgba(35, 35, 70, .05); }
  .data-table td {
    display: table-cell;
    padding: .65rem .6rem;
    border-bottom: 1px solid rgba(35, 35, 70, .1);
    text-align: left;
  }
  .data-table td::before { content: none; }
  .data-table td.cell-actions { justify-content: flex-start; }
}

.empty-row { text-align: center; color: var(--white); padding: 2rem 0; }

/* ── Estado (activo/inactivo) ── */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  padding: .2rem .6rem;
  border-radius: 999px;
  white-space: nowrap;
}
.status-pill--activo { background: rgba(46, 139, 87, .16); color: #1e5c3a; }
.status-pill--inactivo { background: rgba(192, 57, 43, .14); color: var(--red); }

/* ============================================================================
   Ficha de solo lectura (datos del cliente, "lo que ve el cliente")
   ========================================================================== */
.ficha-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3) var(--space-4);
  margin-bottom: .5rem;
}
@media (min-width: 640px) {
  .ficha-grid { grid-template-columns: 1fr 1fr; }
}
.ficha-field .label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--navy);
  /* .65 medía 3.98:1 sobre el fondo nuevo de la intranet (contraste real,
     no a ojo -- ver el comentario del velo en body.app-page) -- por
     debajo del 4.5:1 mínimo para texto pequeño. .85 lo deja en ~5.5:1
     conservando el aspecto "atenuado" frente al valor de abajo. */
  opacity: .85;
  margin-bottom: 2px;
}
.ficha-field .value { font-size: 14px; color: var(--navy); font-weight: 600; }
.ficha-field .value--muted { font-weight: 400; opacity: .6; }

.trazabilidad p { font-size: 12.5px; color: var(--navy); margin-bottom: .4rem; line-height: 1.5; }
.trazabilidad p:last-child { margin-bottom: 0; }

/* ============================================================================
   Panel de contraseña de un solo uso (modal) — ver showOneTimePassword en
   public/staff-common.js. Deliberadamente sólido, no "cristal" como el
   resto de la intranet: es un aviso importante encima de todo, necesita
   el máximo contraste posible, no mimetizarse con el fondo.
   ========================================================================== */
.password-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  z-index: 100;
}
.password-modal {
  width: 100%;
  max-width: 380px;
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 1.5rem;
}
.password-modal h2 {
  font-size: 14px;
  font-weight: 900;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: .5rem;
}
.password-modal .warning {
  font-size: 12px;
  font-weight: 600;
  color: var(--red);
  margin-bottom: 1.1rem;
  line-height: 1.5;
}
.password-modal .password-value {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Courier New', monospace;
  font-size: 16px;
  font-weight: 700;
  color: var(--navy);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: .75rem .9rem;
  margin-bottom: .6rem;
  word-break: break-all;
}
.password-modal .password-value button {
  flex-shrink: 0;
  min-height: 40px;
}
.password-modal .copied-msg {
  font-size: 11.5px;
  font-weight: 600;
  color: #1e5c3a;
  visibility: hidden;
  margin-bottom: 1rem;
}
.password-modal .copied-msg.show { visibility: visible; }
.password-modal .btn-primary { min-height: 44px; }

/* ============================================================================
   Impresión de listados — solo la tabla, sin cabecera ni cromado. La regla
   de arriba pone cada fila como tarjeta en pantallas estrechas; aquí se
   fuerza de vuelta a tabla de verdad sin importar el ancho de la ventana
   en el momento de imprimir (por eso los !important: hay que ganarle a la
   regla de "tarjeta en móvil" aunque la ventana sea estrecha).
   ========================================================================== */
@media print {
  .app-header,
  .welcome,
  .table-toolbar,
  .table-actions,
  .action-bar,
  a.back,
  .side-menu { display: none !important; }

  body.app-page { background: none !important; }
  .app-main, .app-main--wide { max-width: none !important; padding: 0 !important; }

  .table-wrap {
    background: none !important;
    border: none !important;
    backdrop-filter: none !important;
    padding: 0 !important;
  }
  table.data-table { display: table !important; width: 100% !important; }
  table.data-table thead { display: table-header-group !important; }
  table.data-table tbody tr {
    display: table-row !important;
    background: none !important;
    border: none !important;
    backdrop-filter: none !important;
    margin: 0 !important;
    padding: 0 !important;
  }
  table.data-table th {
    display: table-cell !important;
    color: #000 !important;
    border-bottom: 1.5px solid #000 !important;
    padding: .4rem !important;
  }
  table.data-table td {
    display: table-cell !important;
    color: #000 !important;
    border-bottom: 1px solid #999 !important;
    padding: .4rem !important;
    text-align: left !important;
  }
  table.data-table td::before { content: none !important; }
}

/* ============================================================================
   Cliente por instalaciones (tanda 3, docs/intranet-instalaciones-analisis.md
   §7). Mismo aspecto que la demo de feria (demo-feria/estaticos/
   intranet-demo.css), que ya usaba este sistema: cristal, navy, radios.
   ========================================================================== */

/* «En construcción» (VITTA IA del cliente): en navy. El blanco de
   body.app-page .placeholder (arriba) estaba pensado para un fondo oscuro y
   sobre el fondo actual no se leía (medido en la demo: navy 8:1). Solo en las
   páginas de cliente: el «Próximamente» de staff se queda como está. */
body.client-page .placeholder h1,
body.client-page .placeholder p,
body.client-page .placeholder .icon .ic { color: var(--navy); }
body.client-page .placeholder a.back { color: var(--navy); border-color: var(--navy); }
body.client-page .placeholder a.back:hover { background: rgba(35, 35, 70, .05); }

.welcome p.welcome__sub { font-size: 14px; font-weight: 600; }
.aviso-vacio { font-size: 14px; color: var(--navy); line-height: 1.6; margin-bottom: 1.5rem; }

/* «Otros documentos» (lo del cliente sin instalación asignada). */
.otros-documentos { margin-top: var(--space-6); }
.otros-documentos h2 {
  font-size: 14px;
  font-weight: 900;
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: .35rem;
}
.otros-documentos > p { font-size: 13.5px; color: var(--navy); margin-bottom: var(--space-3); }

/* Página de la instalación: placa a la izquierda desde 900 px, apartados. */
.instalacion {
  display: grid;
  gap: var(--space-5);
  margin-bottom: 1.5rem;
}
@media (min-width: 900px) {
  .instalacion { grid-template-columns: 320px 1fr; align-items: start; }
}

.placa { margin: 0; }
.placa__foto {
  display: block;
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
  background: var(--white);
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: var(--radius-lg);
}
.placa__pie {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: .6rem;
  font-size: 13px;
  color: var(--navy);
}
.placa__pie a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 700;
  color: var(--navy);
  text-decoration: underline;
}
/* Sin placa: marco neutro con el icono y el aviso. */
.placa__marco {
  aspect-ratio: 4 / 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  padding: 1rem;
  text-align: center;
  background: rgba(255, 255, 255, .14);
  border: 1.5px dashed rgba(35, 35, 70, .55);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  color: var(--navy);
}
.placa__marco .ic { width: 64px; height: 64px; }
.placa__marco p { font-size: 13.5px; font-weight: 700; }

/* Acordeones nativos (<details>/<summary>): texto plano en el summary (sin
   encabezados dentro), marcador propio que gira, 48 px de alto y foco
   visible. */
.apartados { display: flex; flex-direction: column; gap: var(--space-3); }
.apartado {
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .35);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.apartado > summary,
.mant > summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  min-height: 48px;
  padding: .75rem 1rem;
  cursor: pointer;
  color: var(--navy);
  font-size: 14.5px;
  font-weight: 700;
  border-radius: var(--radius-lg);
}
.apartado > summary::-webkit-details-marker,
.mant > summary::-webkit-details-marker { display: none; }
.apartado > summary:hover,
.mant > summary:hover { background: rgba(255, 255, 255, .16); }
.apartado > summary:focus-visible,
.mant > summary:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
summary .ic-desplegar { width: 20px; height: 20px; flex-shrink: 0; transition: transform .15s; }
details[open] > summary .ic-desplegar { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  summary .ic-desplegar { transition: none; }
}

.apartado__cuerpo { padding: 0 1rem 1rem; }
/* La tabla ya va dentro de una caja de cristal: sin la segunda caja de
   .table-wrap desde 700 px. */
.apartado .table-wrap {
  background: none;
  border: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 0;
}
.apartado__vacio { font-size: 13px; color: var(--navy); padding: .25rem 0 .5rem; }
.data-table td.cell-fecha { white-space: nowrap; }

/* Un desplegable por mantenimiento, dentro de «Mantenimientos». */
.mant { border-top: 1px solid rgba(35, 35, 70, .15); }
.mant > summary { font-size: 13.5px; padding: .75rem .25rem; border-radius: 0; }
.mant__cuerpo { padding: 0 .25rem .75rem; }
.docs-grupo__rotulo {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .4px;
  color: var(--navy);
  margin: .75rem 0 .25rem;
}
