/* ═══════════════════════════════════════
   ▓ COMPONENTE · Search — gemelo vanilla ▓
   v1.0 · 2026-08-23. Ficha: `design-system/COMPONENTE_SEARCH.md`
   Kit: `catalogo-cd/components/Search.jsx`

   El campo con el que se filtra o se encuentra EN VIVO. Rectángulo redondeado —nunca
   pastilla—, lupa a la izquierda, × de limpiar a la derecha que aparece con texto. Si abre
   resultados, se navegan con el teclado y el «sin resultados» **se ve**: un buscador que
   cierra su desplegable en silencio deja al usuario sin saber si buscó mal o si no hay nada.

   ⛔ UN BUSCADOR DECLARA SU TRABAJO — `data-busca` es OBLIGATORIO y no tiene valor por
   defecto. `lista` busca sólo en lo que la pantalla ya contiene y NUNCA abre desplegable;
   `sistema` busca cosas que no están en pantalla y sí lo abre. El test es de sí o no:
   *¿lo que busco puede estar fuera de la pantalla?* La conducta la impone `search.js`.

   REQUISITOS DEL ANFITRIÓN:
     1. Los tokens del canon (`colors_and_type.css`).
     2. `box-sizing: border-box`.
   ═══════════════════════════════════════ */

/* ── LA RAÍZ ─────────────────────────────────────────────────────────────────
   Ancla del desplegable, que se posiciona contra ella y no contra la caja del campo — así
   el popover cubre todo el ancho de la pieza. */
.exds-search {
  position: relative;
  max-width: 100%;
}

/* ── LA CAJA DEL CAMPO ───────────────────────────────────────────────────────
   Ancla la lupa y la ×. Las dos van ABSOLUTAS y no en un flex, para que el campo siga
   siendo un input normal de ancho 100 % y el texto tecleado no empuje nada. Los rellenos
   del input (36 a la izquierda, 34 a la derecha) son el hueco que se les reserva.

   ⚠ AQUÍ ESTÁ LA DIFERENCIA CON `.srch`, el buscador que vive dentro del patrón
   `patrones/pantalla-lista/`: aquél es un CONTENEDOR FLEX con el borde en la caja y los
   hijos en fila; éste lleva el borde en el propio `<input>` y coloca los adornos encima.
   **Los valores son los mismos** —alto 40, radio `--radius-md`, lupa a 12, × a 8 y de
   24×24, misma escalera de bordes—; lo que cambia es la técnica de montaje. No se
   contradicen porque no comparten una sola clase. Cuál de las dos se queda es una decisión
   que se toma midiendo, no aquí. */
.exds-search-caja { position: relative; }

.exds-search-ico {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--fg3, #5C6B7A);
  display: inline-flex;
  pointer-events: none;
}
/* El glifo de la lupa. En el kit React lo pone `<Icono>`, que ya trae estas dos propiedades
   en línea; aquí se declaran además en la hoja porque el gemelo escribe el `<svg>` a mano y
   sin ellas la línea base del ícono baila. Mismo valor en los dos sitios. */
.exds-search-ico svg { display: block; flex-shrink: 0; }

/* ── EL CAMPO ────────────────────────────────────────────────────────────────
   Rectángulo redondeado, NUNCA pastilla: la pill queda reservada al composer del chat.
   El texto va a 14px / `--fs-body`, homologado el 2026-08-16 — *un campo DONDE SE TECLEA
   no va por debajo del cuerpo de texto.* La ficha decía 13.5 y el kit React pintaba 13. */
.exds-search-input {
  width: 100%;
  height: 40px;
  padding: 0 34px 0 36px;
  border-radius: var(--radius-md, 10px);
  border: 1px solid var(--exds-search-borde, var(--color-border-default, #D1D5DB));
  background: var(--color-surface, #FFFFFF);
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-weight: 400;
  font-size: var(--fs-body, 14px);
  color: var(--fg1, #0F1419);
  transition: border-color var(--motion-fast, 120ms) var(--ease-out, cubic-bezier(0.32, 0.72, 0, 1));
}
.exds-search-input::placeholder { color: var(--fg3, #5C6B7A); opacity: 1; }

/* ── EL BORDE VIAJA EN UNA VARIABLE, Y NO ES UN CAPRICHO ─────────────────────
   Son CUATRO estados que tienen que ganarse unos a otros en un orden concreto
   —deshabilitado > foco > hover > variante > reposo— y la especificidad de CSS los
   ordenaría al revés: la variante vive en un atributo de la raíz, así que
   `.exds-search[data-variant="bar"] .exds-search-input` pesa MÁS que un `:hover` sobre el
   campo, y la barra se quedaría sin hover para siempre.

   Con una variable, los tres primeros escalones se declaran sobre el MISMO elemento y
   decide el orden de escritura, que es lo que se lee. El foco se declara sobre el propio
   campo: una declaración propia siempre gana a una heredada, sin contar especificidad.

   *Cuando hay que pelear con la especificidad para conservar un orden ya decidido, es que
   el valor no debería estar peleando: debería estar en una variable.*

   ⛔ LA ESCALERA ES DE TRES PELDAÑOS Y ESTÁ MEDIDA: 3.12 → 3.87 → 4.79 de contraste.
   Reposo `--color-border-default` (Ricardo, 2026-08-16: *en reposo un buscador es un
   contenedor; sólo al tocarlo pesa como control*) · hover `--color-border-control`, el
   peldaño intermedio que Ricardo aprobó ese mismo día · foco `--color-border-focus`.
   Antes hover y foco compartían valor y **quien enfocaba con el ratón no percibía el
   cambio**: el borde ya se había oscurecido al pasar por encima. */

/* variante `bar` — vive sobre una barra de fondo sutil: sin contorno propio. */
.exds-search[data-variant="bar"] { --exds-search-borde: transparent; }
.exds-search[data-variant="bar"] .exds-search-input { background: var(--color-bg-subtle, #F2F4F6); }

/* HOVER · un control responde al ratón ANTES de pulsarlo. Va sobre la raíz porque es toda
   la pieza la que reacciona, no sólo el rectángulo del campo. */
.exds-search:hover { --exds-search-borde: var(--color-border-control, #8B92A1); }

/* FOCO · borde discreto y SIN ANILLO: es un campo de texto (`COMPONENTE_FOCO.md`).
   Homologado el 2026-08-16: decía `--fg2`, que es un token de TEXTO haciendo de foco. */
.exds-search-input:focus {
  --exds-search-borde: var(--color-border-focus, #6E7378);
  outline: none;
}

/* DESHABILITADO · gana a todo lo anterior, incluido el hover: pasar el ratón por encima de
   un campo apagado no debe insinuar que responde. */
.exds-search-input:disabled {
  border-color: var(--color-border-default, #D1D5DB);
  background: var(--color-bg-subtle, #F2F4F6);
  color: var(--fg4, #B8BDC7);
  cursor: not-allowed;
}

/* ── CARGANDO · el spinner ocupa el lugar de la × ────────────────────────────
   Círculo de 15 con un cuarto en transparente. El `border-radius: 50%` aquí SÍ es correcto
   —ancho y alto son iguales, así que es un círculo y no una elipse—; la prohibición del
   50 % es del contador del Badge, que crece con los dígitos. */
.exds-search-spin {
  position: absolute;
  right: 12px;
  top: 50%;
  margin-top: -7.5px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid var(--fg3, #5C6B7A);
  border-top-color: transparent;
  display: inline-block;
  animation: exds-search-spin .7s linear infinite;
}
@keyframes exds-search-spin { to { transform: rotate(360deg); } }

/* ── LA × DE LIMPIAR · aparece CON TEXTO ─────────────────────────────────────
   24×24, radio `--radius-sm`, tinta `--fg3` y fondo sutil al pasar por encima. Su nombre
   accesible es «Limpiar búsqueda» EXACTO (sin el «la»): es el que ya usa la instancia viva
   del asistente, y dos nombres distintos para el mismo botón son dos botones para quien
   navega por voz. */
.exds-search-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm, 6px);
  border: 0;
  background: transparent;
  color: var(--fg3, #5C6B7A);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.exds-search-clear:hover { background: var(--color-bg-subtle, #F2F4F6); }
.exds-search-clear svg { display: block; flex-shrink: 0; }
/* ⛔ EL INTERRUPTOR DE LA × ES EL ATRIBUTO `hidden`, NO UNA CLASE — igual que en el `.srch`
   del backoffice. `hidden` ya significa «no está» para el lector de pantalla; una clase
   sólo lo esconde a la vista. Hace falta la regla porque `display: inline-flex` pisa al
   `display: none` que `hidden` trae de fábrica. */
.exds-search-clear[hidden] { display: none; }

/* ── EL DESPLEGABLE ──────────────────────────────────────────────────────────
   ⛔ Sólo lo abre el trabajo `sistema`. Radio `--radius-sm` (6px) por la escala del
   2026-07-21: el tamaño de la caja lo decide el relleno, y con relleno 6 el radio es 6.
   Sombra de nivel 2 (`--shadow-md`) y 360px de alto máximo, que es lo que cabe sin tapar
   la pantalla que hay debajo. */
.exds-search-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 40;
  background: var(--color-surface, #FFFFFF);
  border: 1px solid var(--color-border-subtle, #E5E7EB);
  border-radius: var(--radius-sm, 6px);
  box-shadow: var(--shadow-md, 0 4px 12px -2px rgba(15, 20, 25, 0.06));
  padding: var(--space-1-5, 6px);
  max-height: 360px;
  overflow-y: auto;
}
/* Misma razón que la ×: en React el desplegable no se monta, aquí se oculta con `hidden`. */
.exds-search-pop[hidden] { display: none; }

/* ── LOS DOS MENSAJES · «Buscando…» y «sin resultados» ───────────────────────
   ⛔ EL VACÍO ES VISIBLE Y NO SE NEGOCIA: cerrar el desplegable en silencio deja al usuario
   sin saber si buscó mal o si no hay nada. Es un estado, no la ausencia de uno.
   El vacío va un tono MÁS OSCURO que «Buscando…» (`--fg2` contra `--fg3`) porque el vacío
   es una respuesta que hay que leer, y «Buscando…» es sólo un compás de espera. */
.exds-search-msg {
  padding: 12px 10px;
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-size: var(--fs-body-sm, 13px);
  color: var(--fg3, #5C6B7A);
}
.exds-search-msg[data-estado="vacio"] { color: var(--fg2, #4B5563); }

/* ── LAS FILAS DE RESULTADO ──────────────────────────────────────────────────
   El resaltado por teclado y por ratón es EL MISMO: sólo relleno gris, sin anillo ni borde
   (Ricardo, 2026-07-27). Y cuelga de `aria-selected`, que es el atributo que el lector de
   pantalla ya lee — así no puede existir una fila que se vea elegida y no lo esté. */
.exds-search-opt {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  text-align: left;
  border: 0;
  padding: 9px 10px;
  border-radius: var(--radius-sm, 6px);
  cursor: pointer;
  background: transparent;
}
.exds-search-opt[aria-selected="true"] { background: var(--color-bg-subtle, #F2F4F6); }

.exds-search-opt-txt {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.exds-search-opt-title {
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-weight: 500;
  font-size: var(--fs-body, 14px);
  color: var(--fg1, #0F1419);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* El subtítulo suele llevar folio o teléfono: `tabular-nums` para que los dígitos alineen
   entre filas y la lista se pueda escanear en vertical. */
.exds-search-opt-sub {
  font-family: var(--font-sans, "Inter", -apple-system, system-ui, sans-serif);
  font-size: var(--fs-caption, 12px);
  color: var(--fg3, #5C6B7A);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── EL RESALTADO DE LA COINCIDENCIA · UN SOLO MECANISMO ─────────────────────
   `<mark>`, y nada más. Hoy conviven tres en las apps (`<mark>` / `.hl` /
   `.is-highlighted`) y ésa es la deuda que esta pieza cierra. El fondo sale de una variable
   porque hay un caso real que lo necesita: dentro de un panel cuyas filas YA se resaltan
   con `--color-bg-subtle`, un `<mark>` del mismo tono desaparece; ahí se pasa
   `--color-bg-sunken` con `style="--exds-search-mark-bg: var(--color-bg-sunken)"`. */
.exds-search-mark {
  background: var(--exds-search-mark-bg, var(--color-bg-subtle, #F2F4F6));
  color: var(--fg1, #0F1419);
  font-weight: 600;
  border-radius: 3px;
  padding: 0 1px;
}

/* ⛔ APAGAR EL MOVIMIENTO NO ES DEJAR SIN SEÑAL (INC-405), y aquí la señal sobrevive: el
   spinner se queda quieto pero sigue viéndose, y el desplegable dice «Buscando…» con
   palabras. La espera se comunica con texto, no sólo con un giro. */
@media (prefers-reduced-motion: reduce) {
  .exds-search-input, .exds-search-spin { transition: none !important; animation: none !important; }
}
