/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   BASE VISUAL — primera capa reutilizable de diseño de FlyClean.  ENCENDIDA POR DEFECTO (04/09/2026).

   CÓMO SE APAGA:    abriendo la app con ?base-visual=0 (queda recordado como 'off' en ese navegador,
                     o localStorage fc_base_visual = 'off'). Vuelve la interfaz anterior en el acto.
   CÓMO SE VUELVE:   ?base-visual=1 borra esa marca y devuelve el valor por defecto (encendida).
   index.html trae `data-base-visual="on"` en <html> y src/base-visual.js lo saca si hay opt-out.
   TODAS las reglas de este archivo cuelgan de ese atributo: sin él, NO pinta un solo píxel.

   TEMA: CLARO. Se midió public/styles.css antes de escribir un color (--bg: #ffffff). Dos prototipos
   anteriores se rehicieron por asumir tema oscuro; los tokens de acá se derivan del verde de marca
   que ya existe (#00c98d), no de una paleta nueva.

   DÓNDE APLICA (superficies de bajo riesgo, aprobadas el 04/09):
     #screen-country · #screen-login · #screen-pin   → entrar a la cuenta
     #screen-coordinator .coord-tab-bar              → navegación principal
     #coord-content (vocabulario CRM/prospección)    → inicio del CRM, lista de prospectos
     #coord-content .coord-service-card              → la tarjeta de «Mis trabajos» (bloque 5bis)
     #prospecto-overlay · #contact-overlay           → ficha de prospecto / de cliente
     #prop-overlay                                   → embudo comercial
     #soporte-overlay                                → soporte
   DÓNDE NO APLICA, A PROPÓSITO: todo el circuito del operario (iniciar jornada, checklist, sectores,
   cámara, fotos antes/después, cierre, cola sin conexión, rescate). Esas pantallas se migran de a una
   y se validan en el campo. tests/base-visual-alcance.test.mjs lo hace cumplir midiendo los selectores.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── 1 · TOKENS ────────────────────────────────────────────────────────────────────────────────
   Esta es la ÚNICA regla del archivo sin raíz de superficie, y solo declara variables --bv-*:
   no puede pintar nada por sí sola. El contrato lo verifica. */
html[data-base-visual='on'] {
  /* color — contraste medido contra el fondo real sobre el que se usa (ver el contrato) */
  --bv-marca: #00c98d; /* verde de marca. RELLENO/DECORACIÓN: 1.8:1 sobre blanco, nunca para texto */
  --bv-marca-fuerte: #00694a; /* la marca en versión legible: 6.7:1 sobre blanco → texto y enlaces */
  --bv-marca-suave: #e6f9f2; /* fondo teñido de marca */
  --bv-superficie: #ffffff;
  --bv-superficie-2: #f4f8f6;
  --bv-texto: #0d1f19; /* 17:1 sobre blanco */
  --bv-texto-2: #3d5c52; /* 7.3:1 */
  --bv-texto-3: #55786c; /* 4.9:1 — el más claro que sigue cumpliendo AA para texto normal */
  --bv-borde: #d5e5df;
  --bv-borde-fuerte: #a9c8bd;
  --bv-exito: #0f7a55; /* 5.3:1 */
  --bv-aviso: #8a5200; /* 6.4:1 */
  --bv-error: #b3261e; /* 6.6:1 */
  --bv-info: #0b5fa5; /* 6.6:1 */
  --bv-exito-fondo: #e6f7ef;
  --bv-aviso-fondo: #fdf3e2;
  --bv-error-fondo: #fdeceb;
  --bv-info-fondo: #e8f2fb;
  --bv-foco: #0b5fa5; /* anillo de foco: 6.6:1 sobre blanco y 6.2:1 sobre la superficie 2 */

  /* tipografía — TODO en rem para que el texto ampliado del sistema escale de verdad */
  --bv-fuente: 'Exo 2', system-ui, sans-serif;
  --bv-txt-xs: 0.75rem;
  --bv-txt-sm: 0.875rem;
  --bv-txt-md: 1rem;
  --bv-txt-lg: 1.125rem;
  --bv-txt-xl: 1.375rem;
  --bv-txt-2xl: 1.75rem;
  --bv-peso-normal: 500;
  --bv-peso-medio: 600;
  --bv-peso-fuerte: 700;
  --bv-interlinea: 1.45;

  /* espacio y forma */
  --bv-esp-1: 4px;
  --bv-esp-2: 8px;
  --bv-esp-3: 12px;
  --bv-esp-4: 16px;
  --bv-esp-5: 24px;
  --bv-esp-6: 32px;
  --bv-radio-sm: 8px;
  --bv-radio: 12px;
  --bv-radio-lg: 16px;
  --bv-radio-pildora: 999px;
  --bv-sombra-1: 0 1px 2px rgba(13, 31, 25, 0.06);
  --bv-sombra-2: 0 4px 12px rgba(13, 31, 25, 0.09);
  --bv-sombra-3: 0 12px 32px rgba(13, 31, 25, 0.16);

  /* táctil — el piso de 44px de las guías de accesibilidad, en un solo lugar */
  --bv-tap: 44px;
  --bv-foco-ancho: 3px;
  --bv-foco-sep: 2px;

  /* movimiento (se anula entero más abajo si el sistema pide movimiento reducido) */
  --bv-transicion: 140ms ease;

  /* puntos de quiebre — declarados como tokens para que estén escritos en un solo lugar;
     las @media de abajo usan estos mismos números: 360 / 430 / 768 / 1024 */
  --bv-quiebre-movil-chico: 360px;
  --bv-quiebre-movil: 430px;
  --bv-quiebre-tablet: 768px;
  --bv-quiebre-escritorio: 1024px;

  /* densidad de la TARJETA DE TRABAJO (#coord-content .coord-service-card, "Mis trabajos").
     Compactos A PROPÓSITO — es la pieza que devuelve la 4ª tarjeta a la pantalla sin bajar
     tipografía ni área táctil. Medido con Playwright sobre scripts/preview-visual/marco.html
     (sección «Mis trabajos»); la tabla por viewport vive en el PR de la rama de densidad. */
  --bv-svc-pad-y: 8px;
  --bv-svc-pad-x: 12px;
  --bv-svc-gap: 6px; /* separación entre tarjetas */
  --bv-svc-row-gap: 3px; /* separación entre líneas dentro de una tarjeta */
  --bv-svc-thumb: 44px; /* miniatura: exactamente el piso táctil (--bv-tap), no menos */

  /* ANCHO EN TABLET Y ESCRITORIO (bloque 10). Los cuatro números del rediseño aprobado el 05/09,
     escritos en un solo lugar. --bv-lienzo repite a propósito el tope que public/styles.css ya le
     pone al <body> desde 900px: la capa lo BAJA a 768 para el panel del coordinador, no lo inventa. */
  --bv-lienzo: 1400px; /* tope del lienzo (el mismo de styles.css ≥900) */
  --bv-medida: 900px; /* medida cómoda de la columna de lista: el texto no se estira a 1400 */
  --bv-riel: 236px; /* ancho de la navegación vertical del escritorio */
  --bv-detalle: min(46vw, 520px); /* el panel de detalle acoplado a la derecha */

  /* BLOQUE 01 · ENTRAR (login partido, diseño aprobado el 05/09). Los números del pliego, en un
     solo lugar. Contraste medido con la fórmula de luminancia relativa (tests/login-visual.test.mjs
     lo recalcula, no lo lee). */
  --bv-login-titulo: #00785a; /* «FlyClean» del teléfono: 5,48:1 sobre blanco (antes --bv-texto, 17:1 pero sin marca) */
  --bv-login-boton-tinta: #04241c; /* tinta del botón sobre el verde de marca: 7,64:1 */
  --bv-login-columna: 400px; /* la columna blanca del formulario en tablet (≥768) */
  --bv-login-columna-escritorio: 480px; /* y en escritorio (≥1024) */
  --bv-login-marca-fondo: #0b3d2e; /* panel de marca: verde oscuro, SÓLIDO (el degradado va encima) */
  --bv-login-marca-texto: #ffffff; /* 12,2:1 sobre el panel */
  --bv-login-marca-texto-2: #cfe8dd; /* tagline y subtítulo: 9,4:1 sobre el panel */
  --bv-login-chip-fondo: rgba(
    255,
    255,
    255,
    0.12
  ); /* mezclado con el panel da #285447: 8,6:1 con texto blanco */
}

/* ── 2 · CANVAS ADAPTABLE (solo las pantallas de cuenta) ───────────────────────────────────────
   `max-width` es un TOPE, no un ensanche. Partiendo de los 430px que public/styles.css le pone al
   <body>, subirlo a 560/720 ENSANCHA; pero si otra hoja dejara el cuerpo más ancho que eso, esta
   regla lo ANGOSTA. La revisión del 04/09 midió exactamente eso a 1200px —de 1400 a 720— sobre un
   árbol donde styles.css no acotaba el cuerpo, y el comentario anterior («se ensancha») describía
   solo una de las dos direcciones. Se aplica SOLO mientras la pantalla activa es una de las tres de
   cuenta, con :has(); si el navegador no soporta :has(), la regla se ignora y queda el ancho de hoy. */
@media (min-width: 768px) {
  html[data-base-visual='on'] body:has(#screen-pin.active) {
    max-width: 560px;
  }
  /* Las dos pantallas PARTIDAS son la excepción: desde 768 se dividen en panel de marca + columna,
     y para eso necesitan el ancho entero de la ventana.
     · El login (bloque 01, 05/09) fue la primera. Hasta el 05/09 compartía los 560 de arriba.
     · El selector de región (bloque 01bis, 06/09) es la segunda, por decisión del dueño: reusa el
       MISMO panel verde para que elegir región → entrar → volver sea UNA composición. Hasta el
       06/09 tenía 560 acá y 720 a 1024; con esos topes el panel de marca habría medido 160 px en
       una tablet y la partición no habría tenido dónde pasar.
     El lienzo del PIN NO cambia: no está en la composición que el dueño pidió. */
  html[data-base-visual='on'] body:has(#screen-login.active) {
    max-width: none;
  }
  html[data-base-visual='on'] body:has(#screen-country.active) {
    max-width: none;
  }
}

/* ── 3 · NAVEGACIÓN — la barra de pestañas del coordinador ─────────────────────────────────────
   Estado activo con TRES señales, no solo color: peso de la letra, subrayado grueso y fondo. */
html[data-base-visual='on'] #screen-coordinator .coord-tab-bar {
  gap: var(--bv-esp-1);
  /* sin relleno vertical: cada pestaña ya mide 44 px (piso táctil); el relleno sumaba 8 px de cromo
     en todos los tamaños y a 1280×900 esos 8 px son parte de la 5ª tarjeta (medido el 05/09) */
  padding: 0 var(--bv-esp-2);
  background: var(--bv-superficie);
  border-bottom: 1px solid var(--bv-borde);
  /* NUNCA desborda el documento (05/09). styles.css pone la barra en `overflow-x: visible` desde
     900 px porque supone que a ese ancho todas las pestañas entran; con las pestañas de esta capa
     (más relleno y separación) a 1024 px —un iPad apaisado— ya no entran: la última quedaba 81 px
     afuera y la página scrolleaba de costado. El `flex-wrap` que esta capa tenía a ≥768 lo tapaba
     envolviendo la barra en dos filas, y esa fila era la 5ª tarjeta. Scroll interno a cualquier
     ancho: donde todo entra no se nota, y donde no entra se llega deslizando, como en el teléfono. */
  overflow-x: auto;
  scrollbar-width: none; /* Firefox; el ::-webkit-scrollbar oculto ya lo pone styles.css y la capa no lo repite:
                            el candado de paridad lee «display:none» como esconder un control */
  /* La pista de que hay más a la derecha: el mismo degradado que styles.css usa en el teléfono y
     quita desde 900 px (donde suponía que no hacía falta). Acá sí hace falta a 1024. Cuando todo
     entra, el degradado cae sobre el relleno final de la barra y no se nota. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent);
}
html[data-base-visual='on'] #screen-coordinator .coord-tab {
  min-height: var(--bv-tap);
  display: inline-flex;
  align-items: center;
  padding: 0 var(--bv-esp-3);
  border-radius: var(--bv-radio-sm);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto-2);
  background: transparent;
  border-bottom: 3px solid transparent;
  transition:
    background var(--bv-transicion),
    color var(--bv-transicion);
}
html[data-base-visual='on'] #screen-coordinator .coord-tab:hover {
  background: var(--bv-superficie-2);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #screen-coordinator .coord-tab:active {
  background: var(--bv-marca-suave);
}
html[data-base-visual='on'] #screen-coordinator .coord-tab.active {
  color: var(--bv-marca-fuerte);
  background: var(--bv-marca-suave);
  font-weight: var(--bv-peso-fuerte);
  border-bottom-color: var(--bv-marca-fuerte);
}

/* ── 4 · ENTRAR A LA CUENTA ────────────────────────────────────────────────────────────────────
   Tarjetas de región, formulario de ingreso, teclado de PIN. */
html[data-base-visual='on'] #screen-country .country-brand {
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-2xl);
  font-weight: var(--bv-peso-fuerte);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #screen-country .country-tagline {
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
  line-height: var(--bv-interlinea);
}
html[data-base-visual='on'] #screen-country .country-cards {
  display: grid;
  gap: var(--bv-esp-3);
  width: 100%;
}
html[data-base-visual='on'] #screen-country .country-card {
  min-height: var(--bv-tap);
  gap: var(--bv-esp-3);
  padding: var(--bv-esp-3) var(--bv-esp-4);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio-lg);
  background: var(--bv-superficie);
  box-shadow: var(--bv-sombra-1);
  transition:
    box-shadow var(--bv-transicion),
    border-color var(--bv-transicion);
}
html[data-base-visual='on'] #screen-country .country-card:hover {
  border-color: var(--bv-borde-fuerte);
  box-shadow: var(--bv-sombra-2);
}
html[data-base-visual='on'] #screen-country .country-card:active {
  box-shadow: none;
  border-color: var(--bv-marca-fuerte);
}
html[data-base-visual='on'] #screen-country .country-card-name {
  font-size: var(--bv-txt-md);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #screen-country .country-card-sub {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-3);
}
@media (min-width: 768px) {
  html[data-base-visual='on'] #screen-country .country-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

html[data-base-visual='on'] #screen-login .login-title {
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-2xl);
  font-weight: var(--bv-peso-fuerte);
  /* Bloque 01: el título vuelve a ser VERDE, pero legible — #00785a da 5,48:1 sobre blanco. Hasta el
     05/09 la capa lo pintaba con --bv-texto (casi negro): cumplía de sobra y perdía la marca. */
  color: var(--bv-login-titulo);
}
html[data-base-visual='on'] #screen-login .login-sub,
html[data-base-visual='on'] #screen-login .login-label {
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #screen-login .login-form {
  display: grid;
  gap: var(--bv-esp-2);
  width: 100%;
}
html[data-base-visual='on'] #screen-login .login-field-label {
  font-size: var(--bv-txt-xs);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto-2);
  letter-spacing: 0.02em;
  text-transform: uppercase; /* bloque 01: rótulos en mayúsculas (styles.css ya lo hacía; acá queda garantizado) */
}
/* CAMPO — normal / encima / foco / deshabilitado */
html[data-base-visual='on'] #screen-login .login-input {
  min-height: var(--bv-tap);
  width: 100%;
  padding: 0 var(--bv-esp-3);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-md);
  color: var(--bv-texto);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio);
  transition:
    border-color var(--bv-transicion),
    box-shadow var(--bv-transicion);
}
html[data-base-visual='on'] #screen-login .login-input::placeholder {
  color: var(--bv-texto-3);
}
html[data-base-visual='on'] #screen-login .login-input:hover {
  border-color: var(--bv-texto-3);
}
html[data-base-visual='on'] #screen-login .login-input:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
  border-color: var(--bv-foco);
}
html[data-base-visual='on'] #screen-login .login-input:disabled {
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  border-style: dashed;
  cursor: not-allowed;
}
/* BOTÓN primario */
html[data-base-visual='on'] #screen-login .login-btn {
  min-height: var(--bv-tap);
  width: 100%;
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-md);
  font-weight: var(--bv-peso-fuerte);
  color: var(--bv-login-boton-tinta); /* bloque 01: #04241c, 7,64:1 sobre el verde (antes #05231a, 7,72:1) */
  background: var(--bv-marca);
  border: 1px solid var(--bv-marca);
  border-radius: var(--bv-radio);
  box-shadow: var(--bv-sombra-1);
  transition:
    filter var(--bv-transicion),
    box-shadow var(--bv-transicion);
}
html[data-base-visual='on'] #screen-login .login-btn:hover {
  filter: brightness(0.94);
  box-shadow: var(--bv-sombra-2);
}
html[data-base-visual='on'] #screen-login .login-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
html[data-base-visual='on'] #screen-login .login-btn:active {
  filter: brightness(0.88);
  box-shadow: none;
}
html[data-base-visual='on'] #screen-login .login-btn:disabled {
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  border-style: dashed;
  border-color: var(--bv-borde-fuerte);
  box-shadow: none;
  cursor: not-allowed;
}
/* CARGANDO — el estado se dice con el atributo, no con un color: el cursor y el rótulo cambian */
html[data-base-visual='on'] #screen-login .login-btn[aria-busy='true'] {
  cursor: progress;
  filter: saturate(0.5);
  border-style: dotted;
}
/* MENSAJE DE ERROR — color + un símbolo, para que no dependa solo del color */
html[data-base-visual='on'] #screen-login .pin-error:not(:empty),
html[data-base-visual='on'] #screen-pin .pin-error:not(:empty) {
  display: block;
  padding: var(--bv-esp-2) var(--bv-esp-3);
  border-left: 3px solid var(--bv-error);
  border-radius: var(--bv-radio-sm);
  background: var(--bv-error-fondo);
  color: var(--bv-error);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
  line-height: var(--bv-interlinea);
}
html[data-base-visual='on'] #screen-login .login-legal a {
  color: var(--bv-marca-fuerte);
  font-size: var(--bv-txt-xs);
  text-decoration: underline;
}
html[data-base-visual='on'] #screen-login .login-version {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-3);
}

html[data-base-visual='on'] #screen-pin .pin-user-name {
  font-size: var(--bv-txt-xl);
  font-weight: var(--bv-peso-fuerte);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #screen-pin .pin-sub {
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #screen-pin .pin-dot {
  border: 2px solid var(--bv-borde-fuerte);
  background: var(--bv-superficie);
}
html[data-base-visual='on'] #screen-pin .pin-dot.filled {
  background: var(--bv-marca-fuerte);
  border-color: var(--bv-marca-fuerte);
  transform: scale(1.15); /* segunda señal además del color: el punto lleno CRECE */
}
html[data-base-visual='on'] #screen-pin .pin-key {
  min-height: var(--bv-tap);
  min-width: var(--bv-tap);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-xl);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto);
  background: var(--bv-superficie-2);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio);
  transition: background var(--bv-transicion);
}
html[data-base-visual='on'] #screen-pin .pin-key:hover {
  background: var(--bv-marca-suave);
}
html[data-base-visual='on'] #screen-pin .pin-key:active {
  background: var(--bv-marca);
  transform: scale(0.96);
}
html[data-base-visual='on'] #screen-pin .pin-back-btn {
  min-height: var(--bv-tap);
  padding: 0 var(--bv-esp-3);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--bv-radio-sm);
}
html[data-base-visual='on'] #screen-pin .pin-back-btn:hover {
  border-color: var(--bv-borde-fuerte);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #screen-pin .pin-back-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}

/* ── 4bis · BLOQUE 01 · ENTRAR, PARTIDO DESDE 768 (diseño aprobado el 05/09) ────────────────────
   Teléfono (< 768): columna única, como hoy, más la línea «¿Olvidaste el PIN?» debajo del botón.
   Tablet (≥ 768):   panel de marca a la izquierda (verde oscuro, sparkle, «FlyClean», tagline y
                     cinco chips decorativos) + columna blanca de formulario de 400 px con el
                     encabezado «Entrar». Escritorio (≥ 1024): la columna pasa a 480 px.

   CÓMO SE PARTE SIN TOCAR renderLogin() NI UN SOLO NODO DEL FORMULARIO: el marcado del panel es
   estático en index.html (.login-marca envuelve la marca que ya existía). Desde 768 el panel se
   coloca ABSOLUTO ocupando todo el alto del lado izquierdo, y a #screen-login se le da un relleno
   izquierdo igual al ancho del panel: la columna de formulario es lo que queda a la derecha, y el
   flex-column centrado de styles.css sigue intacto para todos sus hijos. Nada cambia de orden en
   el DOM, así que el orden del foco es el de siempre.

   LO QUE ESTA SECCIÓN NO HACE: ningún display:none, visibility:hidden ni opacity:0 (la paridad lo
   prohíbe). Las piezas nuevas se ESCONDEN con el atributo `hidden` del marcado —es el navegador el
   que no las pinta— y acá solo se MUESTRAN donde el pliego las pide. Sin la hoja, no se ven. */
html[data-base-visual='on'] #screen-login .login-olvido {
  display: block;
  width: 100%;
  margin: var(--bv-esp-3) 0 0;
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-sm);
  line-height: var(--bv-interlinea);
  color: var(--bv-texto-2);
  text-align: left;
}
/* El subtítulo del teléfono: mismo gris legible que hoy, un poco más separado del título. */
html[data-base-visual='on'] #screen-login .login-marca .login-sub {
  margin-top: var(--bv-esp-1);
}

@media (min-width: 768px) {
  html[data-base-visual='on'] #screen-login.active {
    /* la columna del formulario: lo que queda a la derecha del panel, con 32px de aire a cada lado */
    padding: 48px 32px 48px calc(100% - var(--bv-login-columna) + 32px);
  }
  /* EL PANEL DE MARCA. Fondo SÓLIDO declarado aparte del degradado: el contraste del texto se mide
     contra background-color, y un degradado solo no es un fondo medible. */
  html[data-base-visual='on'] #screen-login .login-marca,
  html[data-base-visual='on'] #screen-country .login-marca {
    position: absolute;
    inset: 0 var(--bv-login-columna) 0 0;
    justify-content: center;
    padding: 48px 40px;
    background-color: var(--bv-login-marca-fondo);
    background-image:
      radial-gradient(ellipse at 85% 100%, rgba(0, 201, 141, 0.28), transparent 58%),
      linear-gradient(165deg, rgba(255, 255, 255, 0.04), transparent 45%);
    color: var(--bv-login-marca-texto);
    text-align: left;
  }
  html[data-base-visual='on'] #screen-login .login-marca > *,
  html[data-base-visual='on'] #screen-country .login-marca > * {
    align-self: flex-start; /* el style en línea centra (para el teléfono); en el panel todo va a la izquierda */
  }
  html[data-base-visual='on'] #screen-login .login-marca .fly-mark-lg,
  html[data-base-visual='on'] #screen-country .login-marca .fly-mark-lg {
    margin: 0 0 var(--bv-esp-4); /* el tamaño (64px) es el de styles.css: la capa no fija alturas */
  }
  html[data-base-visual='on'] #screen-login .login-marca .login-title {
    font-size: 2.25rem;
    line-height: 1.1;
    color: var(--bv-login-marca-texto);
    margin-bottom: var(--bv-esp-1);
  }
  html[data-base-visual='on'] #screen-login .login-marca .login-sub {
    font-size: var(--bv-txt-xs);
    font-weight: var(--bv-peso-medio);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--bv-login-marca-texto-2);
    margin: 0 0 var(--bv-esp-3);
  }
  html[data-base-visual='on'] #screen-login .login-marca-tagline,
  html[data-base-visual='on'] #screen-country .login-marca-tagline {
    display: block;
    max-width: 30ch;
    margin: 0 0 var(--bv-esp-4);
    font-family: var(--bv-fuente);
    font-size: var(--bv-txt-sm);
    line-height: var(--bv-interlinea);
    color: var(--bv-login-marca-texto-2);
  }
  html[data-base-visual='on'] #screen-login .login-marca-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--bv-esp-2);
    max-width: 30ch;
  }
  html[data-base-visual='on'] #screen-login .login-marca-chip {
    display: inline-block;
    padding: 5px 10px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: var(--bv-radio-pildora);
    background: var(--bv-login-chip-fondo);
    color: var(--bv-login-marca-texto);
    font-family: var(--bv-fuente);
    font-size: 0.6875rem; /* 11px: es decoración (aria-hidden), no texto que haya que leer */
    font-weight: var(--bv-peso-medio);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
  }
  /* EL ENCABEZADO de la columna: «Entrar» (misma clave i18n que el botón: dice lo que hace la columna). */
  html[data-base-visual='on'] #screen-login .login-encabezado {
    display: block;
    width: 100%;
    margin: 0 0 var(--bv-esp-2);
    font-family: var(--bv-fuente);
    font-size: var(--bv-txt-xl);
    font-weight: var(--bv-peso-fuerte);
    line-height: 1.2;
    color: var(--bv-texto);
    text-align: left;
  }
  html[data-base-visual='on'] #screen-login .login-label {
    margin-bottom: var(--bv-esp-4);
  }
}
@media (min-width: 1024px) {
  html[data-base-visual='on'] #screen-login.active {
    padding-left: calc(100% - var(--bv-login-columna-escritorio) + 40px);
    padding-right: 40px;
  }
  html[data-base-visual='on'] #screen-login .login-marca,
  html[data-base-visual='on'] #screen-country .login-marca {
    inset: 0 var(--bv-login-columna-escritorio) 0 0;
    padding: 64px 72px;
  }
  html[data-base-visual='on'] #screen-login .login-marca .login-title {
    font-size: 3rem;
  }
  html[data-base-visual='on'] #screen-login .login-marca-tagline,
  html[data-base-visual='on'] #screen-country .login-marca-tagline {
    font-size: var(--bv-txt-md);
    max-width: 34ch;
  }
}

/* ── 4ter · BLOQUE 01bis · ELEGIR REGIÓN, CON EL MISMO PANEL DE MARCA (06/09/2026) ──────────────
   Decisión del dueño: la pantalla donde se elige el país REUSA el panel verde que el bloque 01 ya
   puso en el login, para que las tres pantallas del ingreso —elegir región → entrar con la cuenta →
   volver al selector— sean UNA composición y no tres pantallas sueltas.

   ═══ QUÉ SE REUSA, LITERALMENTE ═══
   · El COMPONENTE: la clase `.login-marca` es la misma. No hay una clase nueva, ni un token nuevo,
     ni un color nuevo: el fondo, el degradado, las dos tintas y los dos anchos de columna salen de
     los mismos `--bv-login-*` que declara el bloque 01. Si alguien cambia el verde del panel, cambia
     en las dos pantallas — que es exactamente lo que se quiere de una composición coherente.
   · Los TEXTOS: los que esta pantalla ya tenía. «FlyClean» y «Seleccioná tu región para continuar»
     (`country.tagline`, el mismo `data-i18n` de siempre, traducido a pt-BR como siempre). No se
     escribió ni una palabra nueva.
   · El MARCADO: `index.html` ENVUELVE los tres nodos de marca que ya estaban y agrega UNO solo, que
     va `hidden`: la frase prestada de abajo. Ningún control. La selección de país y «‹ Cambiar
     región» no se tocan: siguen siendo los mismos `data-click`, en el mismo orden del DOM.
   · LO ÚNICO PRESTADO DEL LOGIN es esa frase —la que dice qué hace la empresa—, y se toma prestada
     de verdad: la MISMA clave i18n (`login.marca.tagline`), no una copia del texto. Va `hidden` en
     el marcado: sin la hoja no existe.
     ⚠️ NO es «para que Brasil la vea traducida»: eso lo afirmé y era FALSO. Esta pantalla se ve
     SIEMPRE en español porque los dos caminos que la abren fijan el idioma en `es` antes
     (`backToCountry()` lo llama; `init()` solo la muestra cuando no hay país guardado). La razón
     verdadera es la que este proyecto ya pagó: copiada a mano, la frase queda ESCRITA DOS VECES y
     las dos pantallas pueden divergir. El hecho está pineado en tests/login-visual.test.mjs.

   ═══ QUÉ NO SE COPIÓ DEL LOGIN, Y POR QUÉ ═══
   · El EYEBROW («PANEL OPERARIO»): acá no existe. Su lugar lo ocupa el tagline propio de la
     pantalla, que dice lo que hay que hacer en ella.
   · Los CINCO CHIPS decorativos («Uruguay · Brasil · Panamá · Guatemala · México»): en el login son
     decoración; acá esos cinco nombres SON las cinco tarjetas que hay que elegir dos centímetros
     más a la derecha. Repetirlos como adorno al lado de la decisión real sería ruido, no
     composición. Se dejaron afuera a propósito, y por eso el panel de esta pantalla tiene CUATRO
     piezas donde el del login tiene cinco.

   ═══ CÓMO SE PARTE ═══
   Igual que el login: desde 768 el panel se vuelve ABSOLUTO ocupando el alto entero del lado
   izquierdo y a `#screen-country` se le da un relleno izquierdo del mismo ancho. La columna es lo
   que queda a la derecha, y `.country-screen` —que ya era un flex-column centrado de alto completo—
   sigue intacta ahí adentro con sus tarjetas. Por debajo de 768 y con la capa apagada no hay una
   sola regla de este bloque: la pantalla es la de siempre.
   ⚠️ El panel se posiciona contra `#screen-country` (que es `position: relative` cuando está
   activa, por `styles.css`) y NO contra `.country-screen`, que es estática. Vive dentro de ella
   para que el teléfono no cambie, y se pinta por encima de su fondo blanco porque un descendiente
   posicionado pinta después que el fondo de un hermano en flujo. */
@media (min-width: 768px) {
  html[data-base-visual='on'] #screen-country.active {
    padding-left: calc(100% - var(--bv-login-columna));
  }
  /* ⚠️ EL PANEL EN SÍ NO SE DECLARA ACÁ: `#screen-country .login-marca` está en la MISMA REGLA que
     `#screen-login .login-marca`, arriba, en el bloque 4bis. Es a propósito y es la diferencia
     entre reusar un componente y copiarlo: el fondo, el degradado, la tinta, el `inset` y el
     relleno tienen UNA sola definición para las dos pantallas, así que no existe el día en que una
     se cambie y la otra no. Acá abajo va solo lo que de verdad difiere: los nodos de marca de esta
     pantalla se llaman distinto (`.country-brand`/`.country-tagline` en vez de
     `.login-title`/`.login-sub`) y la columna de la derecha lleva tarjetas en vez de formulario. */
  html[data-base-visual='on'] #screen-country .login-marca .country-brand {
    font-size: 2.25rem;
    line-height: 1.1;
    color: var(--bv-login-marca-texto); /* 12,2:1 sobre el panel */
    margin-bottom: var(--bv-esp-3);
  }
  html[data-base-visual='on'] #screen-country .login-marca .country-tagline {
    max-width: 30ch;
    margin: 0 0 var(--bv-esp-4);
    font-family: var(--bv-fuente);
    font-size: var(--bv-txt-sm);
    line-height: var(--bv-interlinea);
    color: var(--bv-login-marca-texto-2); /* 9,4:1 sobre el panel */
  }
  /* La ÚNICA pieza que se toma prestada del login: la frase que dice qué hace la empresa. Es la
     misma clave (`login.marca.tagline`), el mismo texto, la misma traducción a pt-BR y —arriba— la
     misma regla. Acá solo se le saca el margen de abajo: en el login separa la frase de los cinco
     chips, y en esta pantalla no hay chips debajo. */
  html[data-base-visual='on'] #screen-country .login-marca-tagline {
    margin-bottom: 0;
  }
  /* ── LA COLUMNA DE LA DERECHA, con la misma medida que la del login ─────────────────────────
     `styles.css` reparte las tarjetas de región en el ancho que haya y la capa las pone en DOS
     columnas desde 768 — que era lo correcto en un lienzo de 560/720 px. Dentro de una columna de
     400 px eso da tarjetas de 164 px donde «Punta del Este · Montevideo» cae en TRES renglones:
     medido a 1440, y es peor que el teléfono. En la partición la columna vuelve a UNA, que es lo
     que hace el formulario del login al lado.
     El relleno se iguala al de #screen-login (32 px en tablet, 40 en escritorio) para que la
     columna útil mida lo mismo en las dos pantallas: 336 y 400 px. */
  html[data-base-visual='on'] #screen-country .country-screen {
    padding-inline: 32px;
  }
  html[data-base-visual='on'] #screen-country .country-cards {
    grid-template-columns: minmax(0, 1fr);
    max-width: none;
  }
}
@media (min-width: 1024px) {
  html[data-base-visual='on'] #screen-country.active {
    padding-left: calc(100% - var(--bv-login-columna-escritorio));
  }
  html[data-base-visual='on'] #screen-country .login-marca .country-brand {
    font-size: 3rem;
  }
  html[data-base-visual='on'] #screen-country .login-marca .country-tagline,
  html[data-base-visual='on'] #screen-country .login-marca-tagline {
    font-size: var(--bv-txt-md);
    max-width: 34ch;
  }
  html[data-base-visual='on'] #screen-country .country-screen {
    padding-inline: 40px;
  }
}

/* ── 5 · INICIO DEL CRM Y LISTA DE PROSPECTOS ──────────────────────────────────────────────────
   Se tocan SOLO las clases del vocabulario CRM/prospección/embudo dentro de #coord-content. Las
   clases compartidas con el circuito del operario (.estado-btn, .spinner, …) NO se tocan acá: se
   tocan dentro de las fichas, que son contenedores propios de esta superficie. */
html[data-base-visual='on'] #coord-content .contact-card {
  gap: var(--bv-esp-3);
  padding: var(--bv-esp-3) var(--bv-esp-4);
  margin-bottom: var(--bv-esp-2);
  min-height: var(--bv-tap);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio-lg);
  box-shadow: var(--bv-sombra-1);
  transition:
    box-shadow var(--bv-transicion),
    border-color var(--bv-transicion);
}
html[data-base-visual='on'] #coord-content .contact-card:hover {
  border-color: var(--bv-borde-fuerte);
  box-shadow: var(--bv-sombra-2);
}
html[data-base-visual='on'] #coord-content .contact-card:active {
  box-shadow: none;
  border-color: var(--bv-marca-fuerte);
}
html[data-base-visual='on'] #coord-content .contact-name {
  font-size: var(--bv-txt-md);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto);
  line-height: var(--bv-interlinea);
}
html[data-base-visual='on'] #coord-content .contact-detail {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #coord-content .contact-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bv-esp-1);
  margin-top: var(--bv-esp-1);
}
/* CHIP */
html[data-base-visual='on'] #coord-content .coord-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--bv-esp-2);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-pildora);
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-xs);
  font-weight: var(--bv-peso-normal);
}
/* BARRA DE ESTADO — el estado se lee por color Y por grosor de borde Y por peso de letra */
html[data-base-visual='on'] #coord-content .contact-estado,
html[data-base-visual='on'] #coord-content .prop-estado {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--bv-esp-2);
  /* A PROPÓSITO no se declara `color` ni `background`: cada estado del embudo trae el suyo desde
     public/styles.css y ESE color es información. Pisarlo con un verde único haría que todos los
     estados se vieran iguales — sería perder un dato, no rediseñarlo. Acá se agrega la señal que
     NO depende del color: borde grueso del mismo tono del texto y negrita. */
  border: 2px solid currentColor;
  border-radius: var(--bv-radio-pildora);
  font-size: var(--bv-txt-xs);
  font-weight: var(--bv-peso-fuerte);
}
/* EMBUDO — tarjeta de propuesta */
html[data-base-visual='on'] #coord-content .prop-card {
  padding: var(--bv-esp-3) var(--bv-esp-4);
  margin-bottom: var(--bv-esp-2);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde);
  border-left: 4px solid var(--bv-marca-fuerte);
  border-radius: var(--bv-radio-lg);
  box-shadow: var(--bv-sombra-1);
}
html[data-base-visual='on'] #coord-content .prop-card.vencer {
  border-left-color: var(--bv-aviso);
  border-left-width: 8px; /* el ámbar solo no alcanza: la barra de la izquierda se ENGROSA */
  background: var(--bv-aviso-fondo);
}
html[data-base-visual='on'] #coord-content .prop-nombre {
  font-size: var(--bv-txt-md);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #coord-content .prop-dias {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #coord-content .prop-dias.vencer {
  color: var(--bv-aviso);
  font-weight: var(--bv-peso-fuerte);
  text-decoration: underline; /* segunda señal: no depende del color */
}
/* BOTÓN secundario de la lista */
html[data-base-visual='on'] #coord-content .nueva-prop-btn,
html[data-base-visual='on'] #coord-content .cargar-mas-btn {
  min-height: var(--bv-tap);
  width: 100%;
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-marca-fuerte);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-marca-fuerte);
  border-radius: var(--bv-radio);
  transition: background var(--bv-transicion);
}
html[data-base-visual='on'] #coord-content .nueva-prop-btn:hover,
html[data-base-visual='on'] #coord-content .cargar-mas-btn:hover {
  background: var(--bv-marca-suave);
}
html[data-base-visual='on'] #coord-content .nueva-prop-btn:focus-visible,
html[data-base-visual='on'] #coord-content .cargar-mas-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
html[data-base-visual='on'] #coord-content .nueva-prop-btn:active,
html[data-base-visual='on'] #coord-content .cargar-mas-btn:active {
  background: var(--bv-marca);
  color: #05231a;
}
html[data-base-visual='on'] #coord-content .nueva-prop-btn:disabled,
html[data-base-visual='on'] #coord-content .cargar-mas-btn:disabled {
  color: var(--bv-texto-2);
  border-style: dashed;
  border-color: var(--bv-borde-fuerte);
  cursor: not-allowed;
}
/* CAMPO de búsqueda */
html[data-base-visual='on'] #coord-content .contact-search {
  min-height: var(--bv-tap);
  width: 100%;
  padding: 0 var(--bv-esp-3);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-md);
  color: var(--bv-texto);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio);
}
html[data-base-visual='on'] #coord-content .contact-search:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
/* ESTADO VACÍO */
html[data-base-visual='on'] #coord-content .coord-empty {
  padding: var(--bv-esp-6) var(--bv-esp-4);
  text-align: center;
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-sm);
  line-height: var(--bv-interlinea);
  background: var(--bv-superficie-2);
  border: 1px dashed var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-lg);
}
/* ALERTA (el banner de avisos por rol que vive en el inicio del CRM) */
html[data-base-visual='on'] #coord-content .alerts-banner {
  border-radius: var(--bv-radio-lg);
  overflow: hidden;
  box-shadow: var(--bv-sombra-1);
}
html[data-base-visual='on'] #coord-content .alerts-header {
  min-height: var(--bv-tap);
  padding: var(--bv-esp-2) var(--bv-esp-4);
  background: var(--bv-info-fondo);
  color: var(--bv-info);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
  border-left: 4px solid var(--bv-info);
}
html[data-base-visual='on'] #coord-content .alerts-header.critical {
  background: var(--bv-error-fondo);
  color: var(--bv-error);
  border-left-color: var(--bv-error);
  border-left-width: 6px; /* la criticidad también se ve en el grosor, no solo en el rojo */
  font-weight: var(--bv-peso-fuerte);
}
html[data-base-visual='on'] #coord-content .alert-item {
  padding: var(--bv-esp-2) var(--bv-esp-4);
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
  line-height: var(--bv-interlinea);
  border-top: 1px solid var(--bv-borde);
}
html[data-base-visual='on'] #coord-content .alert-dismiss {
  min-height: var(--bv-tap);
  min-width: var(--bv-tap);
  color: var(--bv-texto-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--bv-radio-sm);
}
html[data-base-visual='on'] #coord-content .alert-dismiss:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
/* LISTA ADAPTABLE — en móvil una tarjeta por fila; desde tablet, dos columnas */
@media (min-width: 768px) {
  html[data-base-visual='on'] #coord-content .contact-card,
  html[data-base-visual='on'] #coord-content .prop-card {
    margin-bottom: var(--bv-esp-3);
  }
}

/* ── 5bis · «MIS TRABAJOS» — tarjeta de servicio/jornada (coordServiceCard) ────────────────────
   Pedido de Diego (04/09): la dirección visual (colores/contraste/jerarquía) ya está aprobada;
   el único ajuste es DENSIDAD en móvil — que una pantalla comparable vuelva a mostrar ~4 tarjetas
   en vez de 3, sin bajar tipografía (piso 12px en metadatos, 14px en el nombre) ni el piso táctil
   de 44px. La ganancia sale de --bv-svc-* (arriba): menos padding y menos espacio ENTRE líneas,
   nunca del tamaño de lo que se lee ni de lo que se toca. Medido en navegador real (Playwright,
   360/390/428/768/1280) sobre scripts/preview-visual/marco.html; la tabla vive en el PR. */
html[data-base-visual='on'] #coord-content .coord-service-card {
  padding: var(--bv-svc-pad-y) var(--bv-svc-pad-x);
  margin-bottom: var(--bv-svc-gap);
  min-height: var(--bv-tap); /* piso táctil: la tarjeta entera es el control (data-click) */
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio);
  box-shadow: var(--bv-sombra-1);
  transition:
    box-shadow var(--bv-transicion),
    border-color var(--bv-transicion);
}
html[data-base-visual='on'] #coord-content .coord-service-card:hover {
  border-color: var(--bv-borde-fuerte);
  box-shadow: var(--bv-sombra-2);
}
html[data-base-visual='on'] #coord-content .coord-service-card:active {
  box-shadow: none;
  border-color: var(--bv-marca-fuerte);
}
/* con miniatura: fila horizontal [cuerpo | foto], igual dirección que ya usaba public/styles.css */
html[data-base-visual='on'] #coord-content .coord-service-card.has-thumb {
  display: flex;
  gap: var(--bv-esp-2);
  /* stretch (no flex-start): así el flex item de la miniatura tiene una altura DEFINIDA (la del
     cuerpo, más alto), que es lo que deja que el <img> de abajo use `min-height: 100%` en vez de
     `height: 100%` — la capa no fija `height` en ningún selector (contrato de accesibilidad). */
  align-items: stretch;
}
/* El wrapper de contenido es `.coord-card-body`, pero acá se lo selecciona por estructura
   (`> div`, el único <div> hijo directo — la miniatura es un <a>) y NO por esa clase: su nombre
   contiene el texto «body» y el contrato de esta hoja escanea los selectores buscando reglas que
   ensanchen el elemento <body> real (§2). Es la misma tarjeta, es el mismo elemento; solo se lo
   nombra distinto para no disparar un falso positivo en ESE contrato. */
html[data-base-visual='on'] #coord-content .coord-service-card > div {
  display: flex;
  flex-direction: column;
  gap: var(--bv-svc-row-gap);
  min-width: 0; /* sin esto el ellipsis/line-clamp de abajo no corta: el flex item no se achica */
  flex: 1 1 auto;
}
html[data-base-visual='on'] #coord-content .coord-card-thumb {
  flex: 0 0 auto;
  width: var(--bv-svc-thumb);
  min-height: var(--bv-svc-thumb);
  border-radius: var(--bv-radio-sm);
  border: 1px solid var(--bv-borde);
  background: var(--bv-superficie-2);
  overflow: hidden;
}
html[data-base-visual='on'] #coord-content .coord-card-thumb img {
  width: 100%;
  min-height: 100%;
  object-fit: cover;
  display: block;
}
/* NOMBRE — hasta 2 líneas con «…»: un nombre de cliente/obra largo no puede empujar la tarjeta
   a un alto impredecible (roto medido con 80 caracteres en la revisión adversarial). El tamaño
   NO baja de --bv-txt-sm (14px): la densidad se gana en el interlineado, no en la letra. */
html[data-base-visual='on'] #coord-content .coord-service-name {
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto);
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* METADATOS — badges y línea de lugar/operario: 12px es el piso de esta capa para texto SECUNDARIO
   (el nombre, que es el texto principal, se queda en 14px arriba). */
html[data-base-visual='on'] #coord-content .coord-service-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bv-esp-1);
  align-items: center;
}
html[data-base-visual='on'] #coord-content .coord-service-card .service-estado {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--bv-esp-2);
  border: 2px solid currentColor; /* misma segunda señal que .contact-estado: no solo color */
  border-radius: var(--bv-radio-pildora);
  font-size: var(--bv-txt-xs);
  font-weight: var(--bv-peso-fuerte);
  color: var(--bv-texto-2);
  /* styles.css le deja `margin-bottom: 5px` (era para su fila vieja, sin gap). Bajo la capa la fila
     ya separa con su propio gap, así que eran 5 px muertos por tarjeta: los que a 360/390 px
     costaban la 4ª tarjeta cuando la línea lugar/operario pasó a 2 líneas (05/09, medido). */
  margin-bottom: 0;
}
html[data-base-visual='on'] #coord-content .coord-service-card .service-estado.estado-completado {
  color: var(--bv-exito);
}
html[data-base-visual='on'] #coord-content .coord-service-card .service-estado.estado-asignado {
  color: var(--bv-info);
}
html[data-base-visual='on'] #coord-content .coord-service-card .service-estado.estado-en-curso {
  color: var(--purple, #6d28d9); /* la capa no trae morado propio: reusa el token global existente */
}
html[data-base-visual='on'] #coord-content .coord-service-card .coord-tag,
html[data-base-visual='on'] #coord-content .coord-service-card .coord-tipo-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--bv-esp-2);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-pildora);
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-xs);
}
/* LUGAR + OPERARIO — HASTA 2 LÍNEAS con «…» (line-clamp), no una sola. Esta línea dice QUIÉN está
   asignado («👤 piloto +N ayudantes»), y eso es exactamente lo que el coordinador busca al escanear
   «Mis trabajos»: la versión anterior la recortaba a UNA línea con la premisa de que «no es
   información crítica», y con una dirección de largo normal el «+N ayudantes» quedaba fuera del
   recorte, invisible (medido el 05/09 sobre la tarjeta #6 de scripts/preview-visual/marco.html).
   Con 2 líneas ese caso cabe entero a 360 y a 390 px, con y sin miniatura (tarjeta #7), y el alto
   sigue acotado: como máximo un renglón más (15,6 px) y solo en las tarjetas que envuelven. Límite
   conocido, declarado en el contrato: la dirección adversarial de 95 caracteres (tarjeta #3)
   necesita 3 líneas y ahí el «+N» sigue tapado; con miniatura la línea es 52 px más angosta y el
   límite baja (medido por la revisión: ~64 caracteres a 360 px, ~72 a 390) — el arreglo de fondo
   es de markup (operario antes que lugar), no de esta hoja.
   Candados: tests/base-visual-densidad.test.mjs (modelo hermético, corre en CI) y
   tests/base-visual-densidad-navegador.mjs (Chromium real, `npm run test:full`). */
html[data-base-visual='on'] #coord-content .coord-ops {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-2);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* «+N ayudante(s)» — el único <span> que coordServiceCard mete dentro de .coord-ops, con un
   `style=` en línea (`color:var(--text3)`, 2.45:1 — el mismo problema que ya tapó el bloque 9 para
   el botón «‹ Cambiar región»). Gana lo en línea salvo `!important`; medido por la fixture de
   scripts/preview-visual/marco.html, no supuesto. */
html[data-base-visual='on'] #coord-content .coord-ops span {
  color: var(--bv-texto-2) !important;
}
/* Fecha de hoy en el encabezado del día — `.day-label.today` (styles.css) pinta con el verde de
   marca puro (2.16:1). Es una regla existente que hasta ahora nunca se medía: no había ninguna
   tarjeta de trabajo en la fixture de accesibilidad hasta este PR. */
html[data-base-visual='on'] #coord-content .day-label.today {
  color: var(--bv-exito);
}
/* Los DOS `coord-tag` con color en línea que trae coordServiceCard («fuera de fecha» ámbar y
   «servicio completo» verde): sus fallbacks (`var(--green-dark, #14532d)`) nunca se usan porque
   `--green-dark`/`--green` YA existen en :root con otros valores (tema claro) — el resultado medido
   da 1.92:1, no lo que el fallback sugiere. Mismo caso que arriba: gana lo en línea, hace falta
   `!important` para corregirlo sin tocar el JS que lo escribe. */
html[data-base-visual='on'] #coord-content .coord-tag[style*='green'] {
  background: var(--bv-exito-fondo) !important;
  color: var(--bv-exito) !important;
}
html[data-base-visual='on'] #coord-content .coord-tag[style*='amber'] {
  background: var(--bv-aviso-fondo) !important;
  color: var(--bv-aviso) !important;
}
/* Badge rosa de Prueba (`.service-prueba-badge`, styles.css): #ff69b4 sobre su propio tinte da
   2.30:1. Se sube a un rosa más oscuro que sigue leyéndose como «distinto», no como error (no
   reusa --bv-error): 7.88:1 en blanco, 6.70:1 sobre el tinte — medido con tests/_lib-contraste.mjs. */
html[data-base-visual='on'] #coord-content .service-prueba-badge {
  background: #fce7f3;
  color: #9d174d;
}
/* Desde tablet la tarjeta NO se afloja. Hasta el 05/09 había acá un bloque ≥768 px que le devolvía
   relleno y separación «porque hay alto de sobra»: medida la composición completa del viewport, era
   justamente lo que dejaba 4 tarjetas en vez de 5 a 768×1024 y a 1280×900. La misma tarjeta en los
   tres tamaños; lo que cambia con el ancho es cuánto texto entra por línea, no el cromo. */

/* ── 6 · FICHAS (prospecto · cliente · propuesta) Y SOPORTE ────────────────────────────────────
   Estos overlays son contenedores propios de la superficie: acá sí se puede usar el vocabulario
   compartido (.edit-sheet, .estado-btn, .spinner) sin alcanzar al circuito del operario. */
html[data-base-visual='on'] #prospecto-overlay,
html[data-base-visual='on'] #contact-overlay,
html[data-base-visual='on'] #prop-overlay,
html[data-base-visual='on'] #soporte-overlay {
  background: rgba(13, 31, 25, 0.45);
}
/* PANEL INFERIOR */
html[data-base-visual='on'] #prospecto-overlay .edit-sheet,
html[data-base-visual='on'] #contact-overlay .edit-sheet,
html[data-base-visual='on'] #prop-overlay .edit-sheet,
html[data-base-visual='on'] #soporte-overlay .edit-sheet {
  background: var(--bv-superficie);
  border-radius: var(--bv-radio-lg) var(--bv-radio-lg) 0 0;
  box-shadow: var(--bv-sombra-3);
}
html[data-base-visual='on'] #prospecto-overlay .edit-sheet-title,
html[data-base-visual='on'] #contact-overlay .edit-sheet-title,
html[data-base-visual='on'] #prop-overlay .edit-sheet-title,
html[data-base-visual='on'] #soporte-overlay .edit-sheet-title {
  font-size: var(--bv-txt-lg);
  font-weight: var(--bv-peso-fuerte);
  color: var(--bv-texto);
}
html[data-base-visual='on'] #prospecto-overlay .edit-sheet-sub,
html[data-base-visual='on'] #contact-overlay .edit-sheet-sub,
html[data-base-visual='on'] #prop-overlay .edit-sheet-sub,
html[data-base-visual='on'] #soporte-overlay .edit-sheet-sub {
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #prospecto-overlay .edit-section-label,
html[data-base-visual='on'] #contact-overlay .edit-section-label,
html[data-base-visual='on'] #prop-overlay .edit-section-label {
  font-size: var(--bv-txt-xs);
  font-weight: var(--bv-peso-medio);
  color: var(--bv-texto-2);
  letter-spacing: 0.02em;
}
html[data-base-visual='on'] #prospecto-overlay .edit-section-hint,
html[data-base-visual='on'] #contact-overlay .edit-section-hint,
html[data-base-visual='on'] #prop-overlay .edit-section-hint {
  font-size: var(--bv-txt-xs);
  color: var(--bv-texto-3);
  line-height: var(--bv-interlinea);
}
/* CAMPO dentro de la ficha */
html[data-base-visual='on'] #prospecto-overlay .edit-date-input,
html[data-base-visual='on'] #contact-overlay .edit-date-input,
html[data-base-visual='on'] #soporte-overlay .edit-date-input,
html[data-base-visual='on'] #prop-overlay .edit-date-input {
  min-height: var(--bv-tap);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-md);
  color: var(--bv-texto);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio);
  padding: var(--bv-esp-2) var(--bv-esp-3);
}
html[data-base-visual='on'] #prospecto-overlay .edit-date-input:hover,
html[data-base-visual='on'] #contact-overlay .edit-date-input:hover,
html[data-base-visual='on'] #soporte-overlay .edit-date-input:hover,
html[data-base-visual='on'] #prop-overlay .edit-date-input:hover {
  border-color: var(--bv-texto-3);
}
html[data-base-visual='on'] #prospecto-overlay .edit-date-input:focus-visible,
html[data-base-visual='on'] #contact-overlay .edit-date-input:focus-visible,
html[data-base-visual='on'] #soporte-overlay .edit-date-input:focus-visible,
html[data-base-visual='on'] #prop-overlay .edit-date-input:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
  border-color: var(--bv-foco);
}
html[data-base-visual='on'] #prospecto-overlay .edit-date-input:disabled,
html[data-base-visual='on'] #contact-overlay .edit-date-input:disabled,
html[data-base-visual='on'] #soporte-overlay .edit-date-input:disabled,
html[data-base-visual='on'] #prop-overlay .edit-date-input:disabled {
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  border-style: dashed;
  cursor: not-allowed;
}
/* BOTÓN de opción / chip conmutable — activo con borde grueso Y negrita, no solo color */
html[data-base-visual='on'] #prospecto-overlay .estado-btn,
html[data-base-visual='on'] #contact-overlay .estado-btn,
html[data-base-visual='on'] #prop-overlay .estado-btn,
html[data-base-visual='on'] #soporte-overlay .estado-btn,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn {
  min-height: var(--bv-tap);
  padding: 0 var(--bv-esp-3);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-normal);
  color: var(--bv-texto-2);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-pildora);
  transition:
    background var(--bv-transicion),
    border-color var(--bv-transicion);
}
html[data-base-visual='on'] #prospecto-overlay .estado-btn:hover,
html[data-base-visual='on'] #contact-overlay .estado-btn:hover,
html[data-base-visual='on'] #prop-overlay .estado-btn:hover,
html[data-base-visual='on'] #soporte-overlay .estado-btn:hover,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn:hover,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn:hover,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn:hover {
  background: var(--bv-marca-suave);
  border-color: var(--bv-marca-fuerte);
}
html[data-base-visual='on'] #prospecto-overlay .estado-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .estado-btn:focus-visible,
html[data-base-visual='on'] #prop-overlay .estado-btn:focus-visible,
html[data-base-visual='on'] #soporte-overlay .estado-btn:focus-visible,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn:focus-visible,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
html[data-base-visual='on'] #prospecto-overlay .estado-btn:active,
html[data-base-visual='on'] #contact-overlay .estado-btn:active,
html[data-base-visual='on'] #prop-overlay .estado-btn:active,
html[data-base-visual='on'] #soporte-overlay .estado-btn:active,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn:active,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn:active,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn:active {
  background: var(--bv-marca);
  color: #05231a;
}
html[data-base-visual='on'] #prospecto-overlay .estado-btn.active,
html[data-base-visual='on'] #contact-overlay .estado-btn.active,
html[data-base-visual='on'] #prop-overlay .estado-btn.active,
html[data-base-visual='on'] #soporte-overlay .estado-btn.active,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn.active,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn.active,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn.active {
  color: var(--bv-marca-fuerte);
  background: var(--bv-marca-suave);
  border: 2px solid var(--bv-marca-fuerte);
  font-weight: var(--bv-peso-fuerte);
}
html[data-base-visual='on'] #prospecto-overlay .estado-btn:disabled,
html[data-base-visual='on'] #contact-overlay .estado-btn:disabled,
html[data-base-visual='on'] #prop-overlay .estado-btn:disabled,
html[data-base-visual='on'] #soporte-overlay .estado-btn:disabled,
html[data-base-visual='on'] #prospecto-overlay .multi-toggle-btn:disabled,
html[data-base-visual='on'] #contact-overlay .multi-toggle-btn:disabled,
html[data-base-visual='on'] #prop-overlay .multi-toggle-btn:disabled {
  color: var(--bv-texto-2);
  background: var(--bv-superficie-2);
  border-style: dashed;
  cursor: not-allowed;
}
/* BOTÓN de guardar (primario dentro de la ficha) */
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn,
html[data-base-visual='on'] #contact-overlay .edit-save-btn,
html[data-base-visual='on'] #prop-overlay .edit-save-btn,
html[data-base-visual='on'] #soporte-overlay .edit-save-btn {
  min-height: var(--bv-tap);
  font-family: var(--bv-fuente);
  font-size: var(--bv-txt-md);
  font-weight: var(--bv-peso-fuerte);
  color: #05231a;
  background: var(--bv-marca);
  border: 1px solid var(--bv-marca);
  border-radius: var(--bv-radio);
}
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn:hover,
html[data-base-visual='on'] #contact-overlay .edit-save-btn:hover,
html[data-base-visual='on'] #prop-overlay .edit-save-btn:hover,
html[data-base-visual='on'] #soporte-overlay .edit-save-btn:hover {
  filter: brightness(0.94);
}
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .edit-save-btn:focus-visible,
html[data-base-visual='on'] #prop-overlay .edit-save-btn:focus-visible,
html[data-base-visual='on'] #soporte-overlay .edit-save-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn:active,
html[data-base-visual='on'] #contact-overlay .edit-save-btn:active,
html[data-base-visual='on'] #prop-overlay .edit-save-btn:active,
html[data-base-visual='on'] #soporte-overlay .edit-save-btn:active {
  filter: brightness(0.88);
}
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn:disabled,
html[data-base-visual='on'] #contact-overlay .edit-save-btn:disabled,
html[data-base-visual='on'] #prop-overlay .edit-save-btn:disabled,
html[data-base-visual='on'] #soporte-overlay .edit-save-btn:disabled {
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  border: 1px dashed var(--bv-borde-fuerte);
  cursor: not-allowed;
}
html[data-base-visual='on'] #prospecto-overlay .edit-save-btn[aria-busy='true'],
html[data-base-visual='on'] #contact-overlay .edit-save-btn[aria-busy='true'],
html[data-base-visual='on'] #prop-overlay .edit-save-btn[aria-busy='true'],
html[data-base-visual='on'] #soporte-overlay .edit-save-btn[aria-busy='true'] {
  cursor: progress;
  filter: saturate(0.5);
  border-style: dotted;
}
/* CERRAR la ficha */
html[data-base-visual='on'] #prospecto-overlay .sheet-close-btn,
html[data-base-visual='on'] #contact-overlay .sheet-close-btn,
html[data-base-visual='on'] #prop-overlay .sheet-close-btn,
html[data-base-visual='on'] #soporte-overlay .sheet-close-btn {
  min-height: var(--bv-tap);
  min-width: var(--bv-tap);
  color: var(--bv-texto-2);
  background: var(--bv-superficie-2);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio-pildora);
}
html[data-base-visual='on'] #prospecto-overlay .sheet-close-btn:hover,
html[data-base-visual='on'] #contact-overlay .sheet-close-btn:hover,
html[data-base-visual='on'] #prop-overlay .sheet-close-btn:hover,
html[data-base-visual='on'] #soporte-overlay .sheet-close-btn:hover {
  color: var(--bv-texto);
  border-color: var(--bv-borde-fuerte);
}
html[data-base-visual='on'] #prospecto-overlay .sheet-close-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .sheet-close-btn:focus-visible,
html[data-base-visual='on'] #prop-overlay .sheet-close-btn:focus-visible,
html[data-base-visual='on'] #soporte-overlay .sheet-close-btn:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
/* INDICADOR DE CARGA */
html[data-base-visual='on'] #prospecto-overlay .spinner,
html[data-base-visual='on'] #contact-overlay .spinner,
html[data-base-visual='on'] #prop-overlay .spinner,
html[data-base-visual='on'] #soporte-overlay .spinner {
  border-color: var(--bv-borde);
  border-top-color: var(--bv-marca-fuerte);
}
/* LISTA/TABLA ADAPTABLE — las filas del estado de cuenta del cliente: apiladas en móvil,
   en columnas desde 480px. Sin scroll horizontal en ningún ancho. */
html[data-base-visual='on'] #contact-overlay .ec-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--bv-esp-1);
  padding: var(--bv-esp-2) 0;
  border-bottom: 1px solid var(--bv-borde);
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
}
@media (min-width: 480px) {
  html[data-base-visual='on'] #contact-overlay .ec-row {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    align-items: baseline;
  }
}
/* SOPORTE — tarjeta del reporte y sus etiquetas */
html[data-base-visual='on'] #soporte-overlay .pedido-card {
  padding: var(--bv-esp-3);
  background: var(--bv-superficie);
  border: 1px solid var(--bv-borde);
  border-radius: var(--bv-radio);
  box-shadow: var(--bv-sombra-1);
}
html[data-base-visual='on'] #soporte-overlay .pedido-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--bv-esp-2);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-pildora);
  background: var(--bv-superficie-2);
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-xs);
}
html[data-base-visual='on'] #soporte-overlay .pedido-card-detail {
  font-size: var(--bv-txt-sm);
  color: var(--bv-texto-2);
  line-height: var(--bv-interlinea);
}
html[data-base-visual='on'] #soporte-overlay .coord-empty {
  padding: var(--bv-esp-5) var(--bv-esp-4);
  text-align: center;
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-sm);
  background: var(--bv-superficie-2);
  border: 1px dashed var(--bv-borde-fuerte);
  border-radius: var(--bv-radio);
}

/* ── 6bis · LOS CUATRO CONTROLES QUE NO SE ALCANZAN POR TECLADO ────────────────────────────────
   `.country-card`, `.pin-key`, `.coord-tab` y `.contact-card` son <div> con `data-click`: sin
   `tabindex` ni `role`, NINGUNO recibe el foco (medido con seis tabulaciones seguidas en la revisión
   del 04/09, y ahora por contrato). La primera versión de esta capa les daba un `:focus-visible`
   precioso sobre un camino que no existe — una promesa sin el hecho. Las reglas se RETIRARON.
   Hacerlos alcanzables es un cambio de markup (tabindex + role + activación por Enter) en cuatro
   familias distintas, dos de ellas dibujadas desde JS: va en su propio PR, y hasta entonces está
   declarado como pendiente en docs/BASE-VISUAL.md y verificado por
   tests/base-visual-accesible.test.mjs, que exige que ese conjunto sea EXACTAMENTE ese y no crezca. */

/* ── 6ter · LA FICHA DEL SERVICIO: PISO TÁCTIL (27/09/2026, G0 del inventario de fichas) ──────────
   Medido con el banco: 31 de 41 controles de la ficha del servicio debajo de 44 px (la × en 32×32, los
   chips de estado y de tipo en 38, los enlaces «Cambiar cliente» en 28 y «usar otra ubicación» en 24).
   #edit-overlay es un contenedor COMPARTIDO (tests/_lib-hojas-capa.mjs): estas reglas van atadas al
   coordinador activo, igual que las de colocación de §10.3bis, y sólo pueden AGRANDAR la zona táctil —
   la lista blanca `compartidasTactiles` del registro ata CADA objetivo a sus declaraciones exactas
   (min-height, min-width; y display:inline-flex + align-items:center sólo para el <span> del cliente).
   Objetivos por clase o por acción, uno por uno: ni las filas de la cadena (J1/J2) ni las cabeceras de
   los desplegables entran. Nada se esconde, se achica ni se reubica; con cualquier otra pantalla
   activa la ficha es la de antes. */
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .sheet-close-btn {
  min-width: var(--bv-tap);
  min-height: var(--bv-tap);
}
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .estado-btn,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .operario-btns button,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .report-pdf-btn,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .add-equipo-btn,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .jornada-cta-btn,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .edit-date-input,
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open button[data-click='toggleEditClienteSelector'],
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open button[data-click='verPropuestaDesdeServicio'],
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open button[data-click='toggleSvcUbicacionOverride'] {
  min-height: var(--bv-tap);
}
html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open span[data-click='verClienteDesdeServicio'] {
  min-height: var(--bv-tap);
  display: inline-flex;
  align-items: center;
}

/* ── 7 · MOVIMIENTO REDUCIDO ───────────────────────────────────────────────────────────────────
   Si el sistema pide menos movimiento, se apagan TODAS las transiciones y animaciones de la capa
   y también los cambios de escala (el punto del PIN y la tecla que se hunde). El estado se sigue
   viendo: cada uno tiene además una señal que no es movimiento. */
@media (prefers-reduced-motion: reduce) {
  html[data-base-visual='on'] #screen-country *,
  html[data-base-visual='on'] #screen-login *,
  html[data-base-visual='on'] #screen-pin *,
  html[data-base-visual='on'] #screen-coordinator .coord-tab-bar *,
  html[data-base-visual='on'] #coord-content *,
  html[data-base-visual='on'] #prospecto-overlay *,
  html[data-base-visual='on'] #contact-overlay *,
  html[data-base-visual='on'] #prop-overlay *,
  html[data-base-visual='on'] #soporte-overlay * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  html[data-base-visual='on'] #screen-pin .pin-dot.filled,
  html[data-base-visual='on'] #screen-pin .pin-key:active {
    transform: none;
  }
}

/* ── 8 · MÓVIL CHICO (≤360px) ──────────────────────────────────────────────────────────────────
   El piso táctil de 44px NO se baja: lo que se aprieta es el espacio, no el control. */
@media (max-width: 360px) {
  html[data-base-visual='on'] #screen-country .country-card,
  html[data-base-visual='on'] #coord-content .contact-card,
  html[data-base-visual='on'] #coord-content .prop-card {
    padding: var(--bv-esp-2) var(--bv-esp-3);
  }
  html[data-base-visual='on'] #screen-coordinator .coord-tab {
    padding: 0 var(--bv-esp-2);
    font-size: var(--bv-txt-xs);
  }
}

/* ── 9 · LO QUE ENCONTRÓ MEDIR LA PANTALLA (revisión adversarial del 04/09/2026) ────────────────
   Todo este bloque existe porque el contrato dejó de recorrer un catálogo escrito a mano y pasó a
   medir el markup real. Cada regla de acá tapa un agujero MEDIDO, no supuesto. */

/* La flecha «›» de las tarjetas de región daba 2,45:1. Es decorativa, pero está dentro de una
   superficie migrada y contradecía la afirmación de que todo el texto de la capa cumple. Se sube al
   gris más claro que SÍ cumple (4,9:1) en vez de declararla decorativa y mirar para otro lado. */
html[data-base-visual='on'] #screen-country .country-card-arrow {
  color: var(--bv-texto-3);
}

/* El botón «‹ Cambiar región» medía 104×30 y su gris daba 2,45:1. Lleva su estilo en un `style=` EN
   LÍNEA dentro de index.html, que gana sobre cualquier hoja: por eso —y solo por eso— acá hay dos
   `!important`. La alternativa era editar el markup, y eso cambiaría cómo se ve la app con el
   interruptor APAGADO, que es justo lo que esta capa promete no hacer. Sacar esos `style=` en línea
   queda como trabajo aparte. */
html[data-base-visual='on'] #screen-login > button {
  min-height: var(--bv-tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--bv-esp-3);
  border-radius: var(--bv-radio-sm);
  color: var(--bv-texto-2) !important;
  font-size: var(--bv-txt-sm) !important;
}
html[data-base-visual='on'] #screen-login > button:hover {
  background: var(--bv-superficie-2);
}
html[data-base-visual='on'] #screen-login > button:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}

/* Los dos enlaces legales medían 57×14 y 50×14: imposibles de acertar con un dedo. Y el contenedor
   lleva `opacity: .7`, que licuaba el color del enlace a 3,51:1 por más que la capa le diera uno
   perfecto — la opacidad del padre se lleva puesto el contraste del hijo. */
html[data-base-visual='on'] #screen-login .login-legal {
  opacity: 1;
  color: var(--bv-texto-2);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--bv-esp-1);
}
html[data-base-visual='on'] #screen-login .login-legal a {
  display: inline-flex;
  align-items: center;
  min-height: var(--bv-tap);
  padding: 0 var(--bv-esp-2);
  border-radius: var(--bv-radio-sm);
}
html[data-base-visual='on'] #screen-login .login-legal a:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
/* Mismo caso: `opacity: .5` dejaba el rótulo de versión en 1,99:1. */
html[data-base-visual='on'] #screen-login .login-version {
  opacity: 1;
}
html[data-base-visual='on'] #screen-pin .pin-back-sep {
  color: var(--bv-texto-2);
}

/* El aviso: la capa le cambió el fondo a uno más claro y los hijos se quedaron con el rojo y el gris
   de la app — 4,23:1 y 2,14:1. Heredar el color del encabezado los arregla a los dos de una vez y
   mantiene la distinción crítico/normal, que la da el encabezado. */
html[data-base-visual='on'] #coord-content .alerts-header .alerts-header-left,
html[data-base-visual='on'] #coord-content .alerts-header .alerts-toggle {
  color: inherit;
}

/* Las píldoras de estado daban 4,06:1 y 3,92:1 sobre su propio tinte. La capa NO les tocaba el color
   a propósito (cada estado trae el suyo y ESE color es información); la salida no es aplanarlos a un
   verde único —eso borraría el dato— sino subir cada uno a su versión legible, estado por estado. */
html[data-base-visual='on'] #coord-content .contact-estado,
html[data-base-visual='on'] #coord-content .prop-estado {
  color: var(--bv-info);
}
html[data-base-visual='on'] #coord-content .contact-estado.activo,
html[data-base-visual='on'] #coord-content .prop-estado.aceptada {
  color: var(--bv-exito);
}
html[data-base-visual='on'] #coord-content .contact-estado.inactivo {
  color: var(--bv-texto-2);
}
html[data-base-visual='on'] #coord-content .prop-estado.negociando {
  color: var(--bv-aviso);
}
html[data-base-visual='on'] #coord-content .prop-estado.enviada {
  color: #5b21b6;
}

/* El conmutador Míos/Bandeja de soporte: 34px de alto y 1,92:1 en la opción elegida. */
html[data-base-visual='on'] #soporte-overlay .pedido-tab-toggle button {
  min-height: var(--bv-tap);
  border: 1px solid var(--bv-borde-fuerte);
  border-radius: var(--bv-radio-sm);
  background: var(--bv-superficie);
  color: var(--bv-texto-2);
  font-size: var(--bv-txt-sm);
}
html[data-base-visual='on'] #soporte-overlay .pedido-tab-toggle button:hover {
  background: var(--bv-marca-suave);
}
html[data-base-visual='on'] #soporte-overlay .pedido-tab-toggle button:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}
html[data-base-visual='on'] #soporte-overlay .pedido-tab-toggle button.active {
  color: var(--bv-marca-fuerte);
  background: var(--bv-marca-suave);
  border: 2px solid var(--bv-marca-fuerte);
  font-weight: var(--bv-peso-fuerte);
}

/* Los otros dos botones de la ficha de propuesta (generar PDF y eliminar) son controles reales de
   una superficie migrada y quedaban sin piso táctil ni anillo de foco: los vio la medición de
   pantalla, no el catálogo. */
html[data-base-visual='on'] #prop-overlay .report-pdf-btn,
html[data-base-visual='on'] #prop-overlay .delete-svc-btn,
html[data-base-visual='on'] #contact-overlay .report-pdf-btn,
html[data-base-visual='on'] #contact-overlay .delete-svc-btn,
html[data-base-visual='on'] #prospecto-overlay .report-pdf-btn {
  min-height: var(--bv-tap);
  border-radius: var(--bv-radio);
  font-size: var(--bv-txt-sm);
  font-weight: var(--bv-peso-medio);
}
html[data-base-visual='on'] #prop-overlay .report-pdf-btn:focus-visible,
html[data-base-visual='on'] #prop-overlay .delete-svc-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .report-pdf-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .delete-svc-btn:focus-visible,
html[data-base-visual='on'] #prospecto-overlay .report-pdf-btn:focus-visible,
html[data-base-visual='on'] #contact-overlay .ceo-acc-head:focus-visible {
  outline: var(--bv-foco-ancho) solid var(--bv-foco);
  outline-offset: var(--bv-foco-sep);
}

/* ── 10 · ANCHO: TABLET Y ESCRITORIO (solo el panel del coordinador) ───────────────────────────
   El pendiente 4 de docs/BASE-VISUAL.md, resuelto. Antes de este bloque el <body> estaba clavado a
   430px hasta los 900 —el único punto de quiebre de public/styles.css— así que una tablet en
   vertical (834px, un iPad) recibía el layout del teléfono con ~200px de blanco muerto de cada lado.

   TRES DECISIONES, Y POR QUÉ:

   1. EL QUIEBRE BAJA A 768 Y EL ENSANCHE VA ATADO A `:has(#screen-coordinator.active)`.
      El propio repo declaraba el riesgo: ensanchar el <body> alcanza también a las pestañas del
      coordinador que NO están migradas —y, peor, al circuito del operario, que está fuera del
      alcance de esta capa por contrato—. Por eso el ensanche NO es global: solo pinta mientras la
      pantalla activa es #screen-coordinator. Con el operario en pantalla, el lienzo es exactamente
      el de hoy (430 abajo de 900; 1400 arriba, que se lo pone styles.css y esta capa no toca).
      Si el navegador no soporta `:has()`, la regla se ignora entera y queda el ancho de hoy.

   2. EL ESCRITORIO DE styles.css SE ABSORBE, NO SE REEMPLAZA. El bloque `@media (min-width: 900px)`
      de public/styles.css (shell 1400, kanban de 5 columnas, calendario ancho, sheet como diálogo
      de 560, lista del operario a 760, :hover en tarjetas) está bien hecho y sigue mandando. Este
      bloque le suma lo que no tenía: el tramo 768–899, la columna de lista con medida, el detalle
      acoplado y la navegación vertical.

   3. EL TELÉFONO NO CAMBIA NI UN PÍXEL. Todo lo de acá vive dentro de `@media (min-width: 768px)` o
      `(min-width: 1024px)`. La densidad 4/5/5 de «Mis trabajos» se mide igual, en el mismo contrato
      de navegador; este bloque no toca ni el relleno, ni la separación, ni el tope de líneas de la
      tarjeta —que es exactamente lo que S44/S45 castigan—. */

@media (min-width: 768px) {
  /* 10.1 · EL LIENZO — el ancho real de la tablet, y solo para el coordinador. */
  html[data-base-visual='on'] body:has(#screen-coordinator.active) {
    max-width: var(--bv-lienzo);
  }

  /* 10.2 · LA COLUMNA DE CONTENIDO NO SE ESTIRA.
     Ensanchar el lienzo sin esto cambia 200px de blanco muerto por tarjetas de 1300px de ancho con
     tres palabras adentro. El relleno lateral centra el contenido en una medida cómoda y deja que
     cada tarjeta conserve sus propios márgenes.

     LA MEDIDA ES EL DEFECTO, Y SE SALEN DOS VISTAS. La primera versión iba al revés —la medida solo
     pintaba si el contenido traía `.day-group`, `.contact-card` o `.prop-card`— y la revisión del
     05/09 midió lo que eso dejaba afuera: Resumen, Pedidos, Equipos, Documentos y Mensajes no emiten
     ninguna de esas tres clases, así que a 1440 quedaban con líneas de texto de 1.100px (~150
     caracteres por renglón). Para esas cinco pestañas el ensanche era una REGRESIÓN: antes eran una
     columna de 430px. Ahora la medida aplica a todo #coord-content y las dos vistas que sí quieren
     el ancho entero —el tablero y el calendario— son las que se salen, nombradas una por una. */
  html[data-base-visual='on'] #coord-content {
    padding-inline: max(0px, calc((100% - var(--bv-medida)) / 2));
  }
  html[data-base-visual='on'] #coord-content:has(.kb-board),
  html[data-base-visual='on'] #coord-content:has(.cal-grid) {
    padding-inline: 0;
  }

  /* 10.3 · MAESTRO-DETALLE: la ficha deja de tapar la lista.
     Hoy la lista y el detalle son DOS MOMENTOS: la ficha se abre como un panel que ocupa el ancho
     entero y oscurece todo lo de atrás. En tablet y escritorio hay lugar para las dos cosas, así que
     la ficha se acopla a la derecha y la lista sigue visible Y USABLE (tocar otra tarjeta cambia el
     detalle, como en cualquier bandeja de correo). El fondo oscuro se retira: si la lista se ve pero
     no se puede tocar, es peor que taparla. Se acopla con `position: absolute` —no `fixed`— para
     anclar al lienzo centrado del <body> (styles.css le da `position: relative`) y no al viewport:
     con `fixed` el panel se despegaba del shell en pantallas más anchas que 1400.
     SOLO las cuatro superficies migradas. #edit-overlay (la ficha de servicio) NO entra: ese overlay
     lo comparte el circuito del operario y está fuera del alcance de la capa por contrato. */
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #prospecto-overlay.open,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #contact-overlay.open,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #prop-overlay.open,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #soporte-overlay.open {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: auto;
    width: var(--bv-detalle);
    align-items: stretch;
    justify-content: flex-start;
    background: transparent;
    border-left: 1px solid var(--bv-borde);
    box-shadow: var(--bv-sombra-3);
  }
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #prospecto-overlay.open .edit-sheet,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #contact-overlay.open .edit-sheet,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #prop-overlay.open .edit-sheet,
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #soporte-overlay.open .edit-sheet {
    max-width: none;
    max-height: none;
    border-radius: 0;
    box-shadow: none;
  }
  /* …y la lista deja el lugar, en vez de quedar debajo del panel. */
  html[data-base-visual='on']
    body:has(#screen-coordinator.active):has(#prospecto-overlay.open)
    #screen-coordinator,
  html[data-base-visual='on']
    body:has(#screen-coordinator.active):has(#contact-overlay.open)
    #screen-coordinator,
  html[data-base-visual='on']
    body:has(#screen-coordinator.active):has(#prop-overlay.open)
    #screen-coordinator,
  html[data-base-visual='on']
    body:has(#screen-coordinator.active):has(#soporte-overlay.open)
    #screen-coordinator {
    padding-right: var(--bv-detalle);
  }

  /* 10.3bis · LA FICHA DE SERVICIO TAMBIÉN SE ACOPLA — pero solo con el coordinador en pantalla.
     #edit-overlay es UN contenedor compartido: la abre el coordinador desde sus tarjetas,
     Finanzas/CEO desde «Por cobrar», y vive en la lista de overlays del operario. Hasta el 05/09
     quedaba afuera del maestro-detalle por eso (decisión 3 del bloque). Se resuelve SIN cambiar el
     contenedor: las reglas van atadas a `body:has(#screen-coordinator.active)`, así que con
     cualquier otra pantalla activa —las del operario, Finanzas, el CEO— la ficha es EXACTAMENTE la
     de antes (medido en píxeles, capa prendida y apagada, en tests/base-visual-ancho-navegador.mjs).
     Es CSS de colocación: ni un control se esconde ni se deshabilita (contrato de alcance); el
     formulario, sus validaciones, el guardado, el cierre y el teclado son los mismos de siempre. */
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: auto;
    width: var(--bv-detalle);
    align-items: stretch;
    justify-content: flex-start;
    background: transparent;
    border-left: 1px solid var(--bv-borde);
    box-shadow: var(--bv-sombra-3);
  }
  html[data-base-visual='on'] body:has(#screen-coordinator.active) #edit-overlay.open .edit-sheet {
    max-width: none;
    max-height: none;
    border-radius: 0;
    box-shadow: none;
  }
  html[data-base-visual='on'] body:has(#screen-coordinator.active):has(#edit-overlay.open) #screen-coordinator {
    padding-right: var(--bv-detalle);
  }

  /* 10.4 · PUNTERO. styles.css da `cursor` y `:hover` a las tarjetas desde 900; en tablet con mouse
     o trackpad (y en el tramo 768–899) también hay puntero. Nada de esto cambia el alto. */
  html[data-base-visual='on'] #coord-content .contact-card,
  html[data-base-visual='on'] #coord-content .prop-card {
    cursor: pointer;
  }
  html[data-base-visual='on'] #coord-content .contact-card:hover,
  html[data-base-visual='on'] #coord-content .prop-card:hover {
    border-color: var(--bv-borde-fuerte);
  }
}

@media (min-width: 1024px) {
  /* 10.4bis · EL DETALLE NO SE COME LA LISTA CUANDO TAMBIÉN ESTÁ EL RIEL.
     Desde 1024 se suman DOS aperturas: el riel se lleva 236px fijos y el detalle un 46% — y ese 46%
     se calculaba sobre el viewport ENTERO, sin descontar el riel. Medido en la revisión del 05/09
     justo en el punto donde arranca el riel, con la ficha abierta: a 1024×768 (un iPad apaisado, no
     un caso de laboratorio) el detalle se llevaba 471px y la lista quedaba en 317 — el detalle más
     grande que el maestro, y la tarjeta de cliente en 285px, más angosta que en un teléfono.
     Acá el porcentaje se toma de lo que queda DESPUÉS del riel. A 1024: panel 362, lista 426. A
     1440 el tope de 520px sigue mandando, así que el escritorio no cambia. Va sobre el lienzo
     —ancestro común del panel y de la pantalla— y no en el bloque de tokens, que tiene que seguir
     siendo una sola regla sin raíz de superficie. */
  html[data-base-visual='on'] body:has(#screen-coordinator.active) {
    --bv-detalle: min(calc((100% - var(--bv-riel)) * 0.46), 520px);
  }

  /* 10.5 · NAVEGACIÓN VERTICAL AGRUPADA — devuelve alto, que es lo escaso a 900px de alto.
     La tira horizontal de 12 pestañas se come ~46px de los 900 y obliga a deslizar de costado para
     llegar a «Mensajes» (medido: a 1024 la barra desbordaba 81px). De pie, en un riel de 236px,
     no cuesta alto, se ve entera y se puede agrupar por tema. Va `position: absolute` dentro de
     #screen-coordinator (que es `position: relative` cuando está activa) y la pantalla le abre el
     lugar con `padding-left`: así el resto de la columna —encabezado, buscador, mes, lista— se
     acomoda solo, sin reescribir el layout de nueve hijos que aparecen y desaparecen según la
     pestaña y el rol. */
  html[data-base-visual='on'] #screen-coordinator.active {
    padding-left: var(--bv-riel);
  }
  html[data-base-visual='on'] #screen-coordinator .coord-tab-bar {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--bv-riel);
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: var(--bv-esp-3) var(--bv-esp-2) var(--bv-esp-5);
    overflow-x: hidden;
    overflow-y: auto;
    background: var(--bv-superficie-2);
    border-bottom: none;
    border-right: 1px solid var(--bv-borde);
    /* LA PISTA, GIRADA. La primera versión apagaba la máscara con el comentario «el degradado de
       "hay más a la derecha" no aplica de pie» — y no ponía la vertical: el riel quedaba
       deslizándose EN SILENCIO (hereda `scrollbar-width: none` del bloque 3). Medido en la revisión
       del 05/09: el contenido del riel mide ~638px, así que en un portátil de 1366×768 con la barra
       del navegador —~620px de alto útil— «💬 Mensajes» desaparecía sin ninguna señal. Ahora el
       degradado va de arriba abajo; cuando todo entra cae sobre el relleno inferior y no se nota. */
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent);
  }
  html[data-base-visual='on'] #screen-coordinator .coord-tab-group {
    display: block;
    padding: var(--bv-esp-4) var(--bv-esp-3) var(--bv-esp-1);
    font-family: var(--bv-fuente);
    font-size: var(--bv-txt-xs);
    font-weight: var(--bv-peso-fuerte);
    letter-spacing: 0.08em;
    /* CONTRASTE MEDIDO ACÁ, no heredado del comentario del token: --bv-texto-3 da 4,9:1 sobre BLANCO
       y el riel no es blanco (--bv-superficie-2). Sobre ese fondo da 4,57:1 — cumple AA por 0,07, y
       por eso el número lo vigila un contrato (tests/base-visual-ancho.test.mjs) en vez de un
       comentario: si alguien aclara cualquiera de los dos tokens, se pone rojo. */
    color: var(--bv-texto-3);
  }
  html[data-base-visual='on'] #screen-coordinator .coord-tab {
    flex: 0 0 auto;
    justify-content: flex-start;
    text-align: left;
    border-bottom: 3px solid transparent;
    /* styles.css le pone `white-space: nowrap` y la barra es `overflow-x: hidden`: sin esto un
       rótulo más largo que ~195px se cortaba a la mitad de una palabra y no había forma de leerlo.
       Hoy no pasa en español ni en portugués; es el próximo rótulo o el próximo idioma. */
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* El estado activo no depende del color: barra de 3px al costado y letra más pesada. La barra pasa
     de abajo (tira horizontal) al costado (riel), que es donde se lee de pie. */
  html[data-base-visual='on'] #screen-coordinator .coord-tab.active {
    border-bottom-color: transparent;
    border-left: 3px solid var(--bv-marca-fuerte);
    padding-left: var(--bv-esp-2);
  }
}
