/* === base.css ========================================================== */
/* ============================================================================
   BASE — los tokens, el reset y las dos tipografías de servicio.
   Primero en el orden de la hoja: todo lo demás se apoya en estas variables.

   LA DIRECCIÓN: "mesa de cierre"

   El hecho que manda en este producto es que UN MAIL ENVIADO NO SE DESHACE.
   Todo panel de newsletter que existe se ve como un SaaS de marketing; este
   tiene que sentirse como el escritorio donde se decide qué sale: calmo,
   preciso, y con el envío como un acto deliberado.

   De ahí salen las tres reglas:

    1. EL COLOR ES CONSECUENCIA. Casi todo es tinta sobre papel. El verde
       aparece SOLO cuando el envío está listo; el óxido SOLO cuando algo lo
       bloquea o cuando se opera en nombre de otro. Si se ve color, algo pasa.
       Es lo contrario del panel típico, donde todo es azul de marca y por eso
       nada resalta.

    2. LA MONOESPACIADA ES PARA LOS HECHOS. Destinatarios, fechas, contadores,
       estados, identificadores. Son datos, no prosa, y se leen distinto.

    3. LA NUMERACIÓN SE GANA. Los módulos van numerados porque el orden ES
       información: es el orden en que se lee el mail. En otras pantallas no hay
       números, porque no habría nada que ordenar.
   ============================================================================ */

:root {
  --tinta:   #16233a;
  --tinta-2: #2b3a54;
  /* Un escalón más honda que `--tinta`, para cuando la tinta es el SUELO de una
     pantalla entera y no una pieza sobre papel. Es el fondo de la página pública
     de whatsnews: sobre esa superficie, `--tinta` pasa a ser el plano de arriba
     —una tarjeta, un panel— y las dos juntas dan profundidad donde antes había
     un solo azul plano. */
  --noche:   #101a2c;
  --papel:   #faf9f6;
  --fondo:   #efece5;
  --gris:    #59616e;
  --gris-2:  #8a919c;
  --linea:   #dedbd4;

  /* La altura de un control en una barra: campo, selector y botón miden lo
     mismo cuando comparten una línea. Es un token y no un número suelto porque
     el problema que resuelve es justamente que tres reglas distintas eligieran
     tres alturas distintas para lo que se lee como una sola fila. */
  --alto-control: 38px;

  /* A qué altura se pega lo que es `sticky`.
     Es un token porque NO es una constante: cuando un root está operando la
     cuenta de un cliente hay una barra fija de 43px arriba, y una columna
     pegada a 24px del viewport se mete debajo de ella. Con un número suelto en
     cada regla, arreglarlo era acordarse de todas. */
  --top-pegajoso: 24px;
  /* Cuanto mide la barra de cierre del constructor. Es un token y no un numero
     suelto porque hay algo mas que tiene que esquivarla, y dos numeros que
     tienen que coincidir escritos en dos lados se despegan el primer dia. */
  --alto-cierre: 63px;

  /* Los cuatro verdes de la marca (assets/marca/README.md). El logo los usa a
     la vez para dar profundidad a sus dos planos diagonales.
     El botón de enviar toma el MEDIO: es Amura y a la vez lee como "adelante".
     Que el único verde fuera del logo sea ese botón es lo que sostiene la regla
     de que el color es consecuencia. */
  --amura-claro: #0fcea9;
  --amura:       #00a78a;
  --listo:       #0c7762;
  --amura-hondo: #075b4b;

  --alerta:  #a3341f;
  --sombra:  0 1px 2px rgba(22,35,58,.06), 0 4px 16px rgba(22,35,58,.05);

  --serif: Georgia, 'Iowan Old Style', 'Times New Roman', serif;
  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', Menlo, Consolas, monospace;

  --lateral: 232px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

/* `hidden` TIENE QUE GANAR SIEMPRE.
   La regla que esconde un elemento con el atributo `hidden` la pone el
   navegador (`display: none` de origen UA), y CUALQUIER `display` escrito en
   esta hoja le gana — no por especificidad sino por origen. `.btn` declara
   `display: inline-flex`, asi que un boton marcado `hidden` desde el guion
   seguia a la vista con el atributo puesto: no habia error, no habia nada raro
   en el inspector salvo mirar el `display` calculado.
   Muerde una vez por componente y en silencio, por eso va una sola vez aca. */
[hidden] { display: none !important; }
body {
  background: var(--fondo);
  color: var(--tinta);
  font: 15px/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--tinta); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--tinta-2); }
:focus-visible { outline: 2px solid var(--tinta); outline-offset: 2px; border-radius: 2px; }

h1 { font: 400 30px/1.15 var(--serif); margin: 0 0 4px; letter-spacing: -.01em; }
h2 { font: 600 16px/1.3 var(--sans); margin: 0 0 10px; }
.sub { color: var(--gris); margin: 0 0 22px; }

/* ---------------------------------------------------------------------------
   EL ENCABEZADO DE PÁGINA.

   La pantalla de entrada fija el piso de calidad del producto, y lo que la hace
   funcionar no son los detalles: es que está compuesta A ESCALA DE PÁGINA. La
   serif entra en tamaño de portada, hay aire de sobra y el ojo sabe dónde
   empezar a leer.

   Adentro del panel eso se traduce acá. Un título de 30px pegado a una tarjeta
   es lo que hace que cualquier herramienta se vea como "un gestor más": todo el
   texto en el mismo cuerpo, sin un momento de respiro antes del trabajo. La
   diferencia entre las dos cosas son treinta píxeles de aire y ocho puntos de
   tipografía.
   --------------------------------------------------------------------------- */
.encabezado { margin-bottom: 30px; }
.encabezado h1 { font-size: 38px; line-height: 1.1; margin-bottom: 7px; }
.encabezado .sub {
  font-size: 16.5px; line-height: 1.55; color: var(--gris);
  /* En em y no en px: lo que importa es cuántos caracteres entran por línea. */
  max-width: 44em;
}
.encabezado .volver { display: inline-block; margin-bottom: 10px; }
@media (max-width: 700px) {
  .encabezado { margin-bottom: 22px; }
  .encabezado h1 { font-size: 29px; }
  .encabezado .sub { font-size: 15px; }
}

/* --- microetiquetas: el único uso de mayúsculas, para nombrar zonas --------- */
.eti {
  font: 600 11px/1 var(--sans);
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--gris-2);
}

.dato { font: 13px/1.4 var(--mono); font-variant-numeric: tabular-nums; }

/* --- lo poco que se repite en todas las pantallas ---------------------------
   Deliberadamente cortito. Una clase por espaciado es cómo se termina con un
   HTML que dice cuánto margen tiene cada cosa en vez de qué es cada cosa; estas
   existen sólo para que no vuelva el `style=` que la regla de la casa prohíbe. */
.conBajo { margin-bottom: 22px; }
.conBajoChico { margin-bottom: 8px; }
.sinBajo { margin-bottom: 0; }
.derecha { text-align: right; }
.apagado { color: var(--gris-2); }

/* El bloque de título de una pantalla: migas, h1 y bajada. */
.encabezado { margin-bottom: 20px; }
.volver { color: var(--gris); font-size: 13px; text-decoration: none; }
.volver:hover { color: var(--tinta); }

.fila { display: flex; gap: 14px; align-items: flex-start; }
.crece { flex: 1; min-width: 0; }
.entre { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.dosColumnas { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 700px) { .dosColumnas { grid-template-columns: 1fr; } }

@media (prefers-reduced-motion: no-preference) {
  .btn, .tarjeta { transition: background-color .12s ease, border-color .12s ease, box-shadow .12s ease; }
}

/* === componentes.css =================================================== */
/* ============================================================================
   COMPONENTES — las piezas que se repiten en todas las pantallas.
   Si una pantalla necesita algo que se parece a esto, usa ESTO. No se
   reinventa por pantalla: el sistema tiene una dirección declarada (base.css).
   ============================================================================ */

/* --- tarjetas -------------------------------------------------------------- */
.tarjeta {
  background: var(--papel); border: 1px solid var(--linea);
  border-radius: 6px; box-shadow: var(--sombra);
}
.tarjeta + .tarjeta { margin-top: 12px; }
.p { padding: 16px 18px; }
/* Lo que hay que leer sí o sí antes de irse de la pantalla. */
.tarjeta.destacado { border-color: var(--tinta); border-left-width: 3px; }

.vacio { padding: 46px 20px; text-align: center; color: var(--gris); }
.vacio p { margin: 0 0 14px; }

/* --- botones --------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  font: 500 14px/1 var(--sans); padding: 9px 14px;
  border: 1px solid var(--linea); border-radius: 5px;
  background: var(--papel); color: var(--tinta);
  cursor: pointer; text-decoration: none;
}
.btn:hover { border-color: var(--gris-2); }
.btn.fuerte { background: var(--tinta); border-color: var(--tinta); color: #fff; }
.btn.fuerte:hover { background: var(--tinta-2); }
/* El verde es EXCLUSIVO del envío: es la única acción que no se deshace. */
.btn.enviar { background: var(--listo); border-color: var(--listo); color: #fff; font-weight: 600; }
.btn.enviar:hover { filter: brightness(1.08); }
.btn[disabled], .btn.inerte {
  background: var(--fondo); color: var(--gris-2); border-color: var(--linea);
  cursor: not-allowed; box-shadow: none;
}
.btn.chico { font-size: 13px; padding: 6px 10px; }
/* Ocupa todo el ancho de su contenedor. Es lo que quiere un botón que cierra un
   formulario de una sola columna. */
.btn.bloque { width: 100%; justify-content: center; }
/* Sin marco ni fondo hasta que se lo señala. Para acciones secundarias que
   están al lado de su contenido: mover un bloque, quitar una nota, salir. */
.btn.plano { border-color: transparent; background: transparent; }
.btn.plano:hover { border-color: var(--linea); background: var(--papel); }

/* La fila de botones que cierra un formulario. El aire de arriba la separa del
   último campo: pegada, el botón se lee como parte de ese campo y no como el
   cierre de todo el bloque. */
.acciones { align-items: center; gap: 10px; margin-top: 18px; }

/* --- avisos ---------------------------------------------------------------- */
.aviso { border-left: 3px solid var(--gris-2); padding: 11px 14px; background: var(--papel); border-radius: 0 5px 5px 0; }
.aviso.mal { border-color: var(--alerta); color: var(--alerta); }
.aviso.bien { border-color: var(--listo); color: var(--listo); }
.aviso .lista { margin: 6px 0 0; padding-left: 18px; }
.aviso .lista li { margin-bottom: 2px; }

/* --- diagnóstico: qué pasa y qué hacer --------------------------------------
   Lo que se muestra cuando algo no está bien y hay alguien que lo puede
   arreglar. La forma es la misma que la del estado del sistema (`.senalSalud`):
   el porqué y el próximo paso pegados al dato, no escondidos en un tooltip.
   Nació con el error de una fuente —"HTTP 403 Forbidden" es cierto y no le sirve
   a nadie— y es genérico a propósito: la próxima pantalla que tenga que explicar
   una falla usa esta y no inventa la suya. */
.diagnostico { border-left: 3px solid var(--gris-2); padding: 8px 12px; background: var(--papel); border-radius: 0 5px 5px 0; max-width: 62ch; }
.diagnostico.mal { border-color: var(--alerta); }
.diagnostico p { margin: 0; font-size: 13px; line-height: 1.5; }
/* El próximo paso, separado del diagnóstico: lo que hay que hacer no se lee
   igual que lo que pasó. Monoespaciado como en salud, que es donde funcionó. */
.diagnostico .hacer { margin-top: 5px; font: 12.5px/1.5 var(--mono); color: var(--gris); }
/* El error crudo queda a un clic. Traducirlo y esconder el original deja sin
   nada a quien sabe leerlo — y la traducción se puede equivocar. */
.diagnostico .tecnico { margin-top: 6px; }
.diagnostico .tecnico summary { font-size: 12px; color: var(--gris-2); cursor: pointer; }
.diagnostico .tecnico code { display: block; margin-top: 4px; font-size: 12px; color: var(--gris); word-break: break-all; }

/* --- estado ---------------------------------------------------------------- */
.estado { display: inline-flex; align-items: center; gap: 6px; font: 12px/1 var(--mono); color: var(--gris); }
.punto { width: 7px; height: 7px; border-radius: 50%; background: var(--gris-2); flex: none; }
.punto.viva { background: var(--listo); }
.punto.rota { background: var(--alerta); }

/* Una etiqueta corta que nombra un valor cerrado: el plan, el driver. Es un
   dato, no una decoración, así que va en monoespaciada. */
.chip {
  display: inline-block; padding: 2px 8px; border-radius: 3px;
  background: var(--fondo); border: 1px solid var(--linea);
  font: 12px/1.5 var(--mono); color: var(--gris);
}

/* --- solapas: las secciones de un área --------------------------------------
   Nacieron para Suscriptores y Listas, que son pares en la cabeza de cualquiera
   que haya usado una herramienta de correo pero NO son dos ítems del menú: el
   menú se ordena por cada cuánto se toca cada cosa y crece una línea por cada
   cosa nueva. Ahora también son las tres secciones de Ajustes.

   Son ENLACES a URLs de verdad, no pestañas de JavaScript. Así guardar vuelve a
   su sección, se puede enlazar directo a una y andan sin guion — como el resto
   del panel. */
.solapas { display: flex; gap: 2px; margin-bottom: 18px; border-bottom: 1px solid var(--linea); }
.solapas a {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 14px; margin-bottom: -1px;
  border: 1px solid transparent; border-bottom-color: var(--linea);
  border-radius: 5px 5px 0 0;
  font: 500 14px/1 var(--sans); color: var(--gris); text-decoration: none;
}
.solapas a:hover { color: var(--tinta); }
.solapas a[aria-current="page"] {
  background: var(--papel); color: var(--tinta);
  border-color: var(--linea); border-bottom-color: var(--papel);
}
/* Lo que falta en una sección, contado en la solapa. Mismo trabajo que los
   números del menú: decir dónde hay algo que hacer sin obligar a entrar a las
   tres para averiguarlo.

   `.cuenta` ya existía, pero SOLO dentro de `.lateral nav`, así que acá no
   heredaba nada. Se estila aparte a propósito: la del menú va sobre fondo
   oscuro y esta sobre papel. */
.solapas .cuenta {
  font: 600 11px/1 var(--mono); padding: 3px 5px; border-radius: 3px;
  background: var(--fondo); color: var(--gris);
}
.solapas .cuenta.mal { background: var(--alerta); color: #fff; }

/* --- tabla ---------------------------------------------------------------- */
table { width: 100%; border-collapse: collapse; }
th { text-align: left; font: 600 11px/1 var(--sans); letter-spacing: .11em; text-transform: uppercase; color: var(--gris-2); padding: 0 0 9px; }
td { padding: 13px 0; border-top: 1px solid var(--linea); vertical-align: top; }

/* Dentro de una tabla el subrayado sobra: la columna ya dice que ahí está el
   nombre, y veinte subrayados seguidos convierten un listado en un directorio.
   La marca aparece al apuntar, que es cuando hace falta. */
td a { text-decoration: none; }
td a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* El nombre propio de una fila —un cliente, una cabecera— en la serif del
   título. Es lo que ata el listado con el encabezado de la página en lugar de
   dejarlo como una grilla de datos más. */
.nombrePropio { font: 400 18px/1.25 var(--serif); letter-spacing: -.005em; }

/* --- cifras: la tira de números que abre una pantalla de tablero -------------
   Es el equivalente interno del lema de la portada: lo primero que se lee y lo
   único que puede permitirse tamaño. Números grandes en monoespaciada —son
   hechos, no prosa— con aire suficiente para que respiren. Apretados en una
   caja chica se leen como un widget más y la pantalla vuelve a ser un gestor. */
.cifras { display: flex; gap: 12px; margin-bottom: 26px; flex-wrap: wrap; }
.cifras .cifra {
  flex: 1; min-width: 132px;
  background: var(--papel); border: 1px solid var(--linea);
  border-radius: 6px; box-shadow: var(--sombra); padding: 18px 20px 16px;
}
.cifras .cifra b {
  display: block; font: 400 34px/1 var(--mono);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.cifras .cifra .eti { margin-top: 9px; display: block; }
@media (max-width: 700px) {
  .cifras .cifra { padding: 14px 16px; }
  .cifras .cifra b { font-size: 27px; }
}

/* La versión de FILA de lo mismo, para una celda de tabla.
   No es `.cifra` con menos padding: `.cifra` es una tarjeta —fondo, borde,
   sombra— y cuatro tarjetas adentro de cada fila de una lista convierten la
   tabla en un tablero. Acá el número es un dato de la fila, no un titular, así
   que va sin caja y a tamaño de texto.
   Una raya en lugar de un número es "todavía no sabemos", y se apaga para que no
   compita con los que sí son un dato. */
.cifrasFila { display: flex; gap: 18px; }
.cifrasFila .cifraFila { min-width: 62px; }
.cifrasFila .cifraFila b {
  display: block; font: 400 16px/1 var(--mono);
  font-variant-numeric: tabular-nums;
}
.cifrasFila .cifraFila .eti { margin-top: 4px; display: block; }
.cifrasFila .cifraFila.sinDato b,
.cifrasFila .cifraFila.sinDato .eti { color: var(--gris-2); }

/* --- barras de ocupación ----------------------------------------------------
   Se llena en tinta y sólo se pone en óxido cuando ya no entra nada más: otra
   vez, el color es consecuencia.

   El ancho va en clases y no en un `style=` porque la regla de la casa no tiene
   excepciones. Veintiún pasos de 5% alcanzan de sobra para leer una proporción
   de un vistazo, que es todo lo que esta barra tiene que hacer. */
.barra { height: 4px; border-radius: 2px; background: var(--linea); margin-top: 7px; overflow: hidden; }
.barra i { display: block; height: 100%; background: var(--tinta); }
.barra i.p0   { width: 0; }
.barra i.p5   { width: 5%; }
.barra i.p10  { width: 10%; }
.barra i.p15  { width: 15%; }
.barra i.p20  { width: 20%; }
.barra i.p25  { width: 25%; }
.barra i.p30  { width: 30%; }
.barra i.p35  { width: 35%; }
.barra i.p40  { width: 40%; }
.barra i.p45  { width: 45%; }
.barra i.p50  { width: 50%; }
.barra i.p55  { width: 55%; }
.barra i.p60  { width: 60%; }
.barra i.p65  { width: 65%; }
.barra i.p70  { width: 70%; }
.barra i.p75  { width: 75%; }
.barra i.p80  { width: 80%; }
.barra i.p85  { width: 85%; }
.barra i.p90  { width: 90%; }
.barra i.p95  { width: 95%; }
.barra i.p100 { width: 100%; }

/* La misma barra, APILADA: varios tramos que suman el total.
   Es la forma de un envío en una línea —cuánto llegó, cuánto va en camino,
   cuánto rebotó— y por eso es lo único grande de esa pantalla. Reusa los anchos
   `pN` y los nombres de color de los puntos de estado: un solo vocabulario en
   toda la aplicación, así el verde de acá y el verde de la lista de abajo
   quieren decir lo mismo. */
.barra.apilada { display: flex; height: 10px; border-radius: 5px; margin-top: 0; }
.barra.apilada i { flex: none; }
.barra.apilada i.activo    { background: var(--listo); }
.barra.apilada i.pendiente { background: #c99a2e; }
.barra.apilada i.problema  { background: var(--alerta); }
.barra.apilada i.fuera     { background: var(--gris-2); }

/* --- el resumen de un envío -------------------------------------------------
   UNA cifra grande y no siete iguales. Siete tarjetas del mismo tamaño no
   ordenan nada: obligan a leerlas todas para descubrir cuál importaba. Acá la
   pregunta es una sola —¿llegó?— y el resto es contexto de esa pregunta. */
.resumenEnvio { padding: 24px 26px 22px; margin-bottom: 12px; }
.resumenEnvio .cabeza { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.resumenEnvio .grande {
  font: 400 52px/1 var(--mono); font-variant-numeric: tabular-nums;
  letter-spacing: -.03em; color: var(--tinta);
}
.resumenEnvio .de { font: 15px/1.4 var(--sans); color: var(--gris); }
.resumenEnvio .porcentaje { margin-left: auto; font: 400 20px/1 var(--mono); color: var(--gris); }
.resumenEnvio .barra { margin: 18px 0 14px; }
/* La leyenda ES el filtro de la tabla de abajo. Un color que se explica y además
   sirve para algo vale el doble que una referencia muda. */
.resumenEnvio .leyenda { display: flex; gap: 18px; flex-wrap: wrap; }
.resumenEnvio .leyenda a { text-decoration: none; color: inherit; }
.resumenEnvio .leyenda a:hover .eti { text-decoration: underline; }
.resumenEnvio .leyenda .punto { margin-right: 7px; }
/* Lo secundario, adentro de la misma tarjeta y detrás de una línea. La línea es
   la que dice cuáles son los principales: sueltos debajo de la tarjeta quedaban
   huérfanos entre el resumen y el texto de ayuda, y se leían como sobras. */
.resumenEnvio .pie {
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--linea);
}
.resumenEnvio .pie .cifrasFila { gap: 34px; }

/* --- qué nota se llevó los clics --------------------------------------------
   La barra de cada nota es la MISMA de los cupos, con sus anchos en clases: se
   compara contra la nota más clickeada, no contra el total, porque lo que se
   está mirando es el reparto entre notas y no la tasa de clics del envío.
   Una nota sin clics no se esconde —saber qué NO se leyó es la mitad del dato—
   pero se apaga, así el ojo cae en las que sí. */
.clicsNota td:last-child { width: 168px; vertical-align: middle; }
.clicsNota .barra { margin-top: 5px; }
.clicsNota tr.sinClics td,
.clicsNota tr.sinClics a { color: var(--gris-2); }
@media (max-width: 700px) {
  .resumenEnvio .grande { font-size: 40px; }
  .resumenEnvio .porcentaje { margin-left: 0; }
}

/* --- desplegable ------------------------------------------------------------
   Para lo que se toca poco y no tiene por qué ocupar la pantalla: cambiar un
   tope, mirar el detalle. Cerrado por defecto y sin sorpresas. */
details > summary {
  cursor: pointer; font: 600 14px/1.3 var(--sans);
  /* `inside` y no `outside`: afuera, el triángulo se sale de la caja de contenido
     y queda pegado al borde de la tarjeta que lo contiene. Adentro viaja con el
     texto, que es lo que se quiere de un marcador que forma parte del título. */
  list-style-position: inside;
}
details > summary::marker { color: var(--gris-2); }
/* El `::marker` no acepta margen, así que el aire entre el triángulo y la
   palabra sale de un espacio propio. */
details > summary::before { content: ''; display: inline-block; width: 3px; }
details[open] > summary { margin-bottom: 4px; }
/* Un estado adentro de un resumen necesita su aire: pegado al dato anterior, el
   punto de color se lee como parte de esa palabra. */
details > summary .estado { margin-left: 8px; }
.separado { margin-top: 16px; }

/* Una URL larga no puede estirar la tabla ni empujar las columnas de al lado. */
.cortable { word-break: break-all; }
.alerta { color: var(--alerta); }
.espacioArriba { margin-top: 3px; }

/* Una fila apagada sigue estando —con su historial— pero no compite con las
   activas por la atención. La tarjeta es el mismo caso en otra forma: quien está
   dado de baja sigue en la lista, porque reactivarlo es la acción de al lado. */
tr.enPausa td { opacity: .55; }
.tarjeta.enPausa { opacity: .6; }

/* La separación entre dos bloques de una misma pantalla. */
.seccion { margin: 34px 0 14px; }

/* --- la barra de filtro ------------------------------------------------------
   Una sola línea con todo lo que acota la lista, y a la derecha cuántas cosas
   quedaron. Sin el contador, filtrar es a ciegas: no se distingue "no hay nada"
   de "el filtro se comió todo".

   Cuando hay algún filtro puesto aparece "Quitar filtros". Un estado del que no
   se sabe salir es peor que no tener el estado. */
.barraFiltro {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 12px;
}
/* --- la barra de filtros -----------------------------------------------------
   UN componente para todas las barras de buscar y filtrar del panel: la de
   notas, la de suscriptores y la que venga.

   Antes eran dos. `.filtro` redeclaraba por su cuenta los estilos del campo de
   texto —los mismos de formularios.css, con otro padding— y `.buscador` usaba
   los de la hoja. El resultado era el que se ve en cuanto se mira: los campos de
   una barra medían distinto que los de la otra, y en las dos el botón era más
   bajo que los campos que tenía al lado.

   LA REGLA DE ESTE COMPONENTE: todo lo que va en la barra mide `--alto-control`.
   Un campo, un selector y un botón en la misma línea son tres cosas que se leen
   como una sola fila; que cada uno traiga su altura es lo que la rompe.
   ------------------------------------------------------------------------- */
.filtro {
  display: flex; gap: 8px; flex-wrap: wrap;
  /* `end` y no `center`: algunos controles llevan etiqueta arriba y otros no, y
     lo que tiene que quedar alineado es la línea de abajo de los controles. */
  align-items: flex-end;
  /* La barra de notas es un hijo flex de la fila que tiene el contador de
     resultados al costado, y ahí la encogía a su tamaño de contenido MENOS unos
     píxeles: alcanzaba para que el botón saltara solo a la línea de abajo con
     400px libres al lado. Pedir el espacio disponible lo resuelve, y donde la
     barra no es hijo de un flex esta línea no hace nada. */
  flex: 1 1 auto;
}
/* ADENTRO DE `.barraFiltro`, LA BARRA NO LLEVA MARGEN PROPIO.
   `audiencia.css` le da 14px abajo a todo `.filtro`, y ahí está bien: en
   Suscriptores la barra va suelta y necesita separarse de la tabla. Acá adentro
   ese margen no se ve como un margen — se ve como que la barra mide 52 y no 38,
   con una franja muerta abajo de los controles. Y lo que se alinee con la barra
   en vez de con los controles aparece 14px más abajo que ellos, que es lo que le
   pasó al «+» de al lado. El envoltorio ya trae su propio margen abajo.
   Va con el envoltorio en el selector y no en `audiencia.css` porque la regla es
   de este componente: quien tiene margen es la barra o su caja, nunca las dos. */
.barraFiltro > .filtro { margin-bottom: 0; }

/* Los controles sueltos y los que van dentro de un `.campo` con su etiqueta. */
.filtro > input, .filtro > select, .filtro > .btn,
.filtro .campo > input, .filtro .campo > select {
  height: var(--alto-control);
  padding-top: 0; padding-bottom: 0;
}
.filtro .campo { margin-bottom: 0; }
.filtro .campo > span { font-size: 11px; }
/* El ancho por defecto de un campo es 100%: en una barra eso lo hace ocupar todo
   y empujar al resto abajo. Acá cada uno pide lo suyo. */
.filtro input, .filtro select { width: auto; }
.filtro select { min-width: 168px; }
.filtro .texto, .filtro > input[type=search] { flex: 1 1 220px; min-width: 170px; max-width: 420px; }
.filtro .texto > input { width: 100%; }
/* La casilla no es un control de la fila: es una etiqueta con su casilla, y va
   centrada con los campos y no con la línea de abajo. */
.filtro > .opcion { align-self: center; height: var(--alto-control); align-items: center; }

.cuentaResultados { color: var(--gris-2); white-space: nowrap; }

/* --- listado de contenido -------------------------------------------------- */
/* LA FILA ENTERA es el botón que abre la previa de la nota, así que hay que
   apagarle todo el cromo de botón —fondo, marco, centrado, tipografía del
   sistema— y dejarla exactamente como se veía cuando era un `div`. Lo único que
   se gana es que responde al foco y al Enter, que es lo que se quiere de algo
   que se toca. */
.nota {
  display: flex; gap: 13px; width: 100%; padding: 15px 16px;
  border: 0; border-bottom: 1px solid var(--linea);
  background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.nota:last-child { border-bottom: 0; }
.nota:hover { background: rgba(255,255,255,.55); }
/* El anillo va por dentro: la fila ocupa todo el ancho de la tarjeta y un
   `outline` por fuera se corta contra el borde redondeado. */
.nota:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--tinta); }
/* La miniatura ES el botón que abre la previa de la nota: es lo que uno quiere
   tocar para ver la foto más grande, y el título ya lleva a la nota en el sitio
   del medio. Dos destinos distintos en dos lugares distintos, sin un tercer
   control al costado. */
.nota .miniatura {
  width: 76px; height: 52px; border-radius: 3px; background: var(--fondo); flex: none;
  padding: 0; border: 0; overflow: hidden; cursor: pointer; display: block;
}
.nota .miniatura img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* La cabecera de un modal: titulo a la izquierda, acciones a la derecha.
   Vivia en constructor.css y la usan DOS pantallas —la previa del correo y la
   de una nota—, asi que su lugar es aca: lo que usa mas de una pantalla no
   puede vivir en la hoja de una sola. */
.cabPrevia {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-bottom: 1px solid var(--linea); background: var(--papel);
}
/* Lo que empuja todo a la derecha es el TÍTULO, no la primera acción que haya.
   Antes el `margin-left:auto` estaba en los botones de ancho, así que en el
   modal del correo funcionaba y en el de la nota —que no los tiene— la ✕ quedaba
   pegada al título, a la izquierda. Puesto en el título vale para cualquier
   combinación de acciones, incluida ninguna. */
.cabPrevia .eti { margin-right: auto; }
.cabPrevia .anchos { display: flex; gap: 4px; }
/* El ancho elegido se marca con el botón lleno: es el mismo lenguaje que el
   resto de la hoja, y `aria-pressed` ya dice cuál está activo sin una clase. */
.cabPrevia .anchos .btn[aria-pressed="true"] {
  background: var(--tinta); border-color: var(--tinta); color: #fff;
}

/* --- la previa de una nota --------------------------------------------------
   Muestra la foto entera y sin recortar: es lo único que no se puede juzgar en
   76px, y es lo que decide si esa nota abre un correo. */
.notaModal {
  width: min(720px, 92vw); max-width: none; padding: 0;
  border: 1px solid var(--linea); border-radius: 8px;
  background: var(--papel); color: var(--tinta);
  box-shadow: 0 24px 70px rgba(22,35,58,.3);
}
.notaModal::backdrop { background: rgba(22,35,58,.45); }
.cuerpoNota { max-height: 76vh; overflow-y: auto; }
.cuerpoNota img { width: 100%; height: auto; display: block; background: var(--fondo); }
.cuerpoNota .textoModal { padding: 16px 20px 20px; }
.cuerpoNota h2 { margin: 0 0 8px; font: 400 26px/1.25 var(--serif); }
.cuerpoNota .bajada { margin: 0 0 10px; color: var(--gris); }
.cuerpoNota .meta { font: 12px/1.4 var(--mono); color: var(--gris-2); }

/* Cambiar la foto de la nota. Va al PIE del modal y separado por una línea: lo
   de arriba es la nota y esto es una acción sobre ella. Fuera de `.cuerpoNota`
   para que no se vaya con el scroll — es lo que se aprieta después de mirar. */
.fotoDeNota { padding: 14px 20px 16px; border-top: 1px solid var(--linea); background: var(--fondo); }
.fotoDeNota .ayuda { margin: 3px 0 10px; }
.fotoDeNota .fila { align-items: center; gap: 10px; }
.fotoDeNota input[type=file] { font-size: 13px; color: var(--gris); }
/* Sin foto, el hueco se marca con un trazo punteado en vez de un bloque gris:
   reserva el lugar —así los títulos siguen alineados— sin parecer una imagen
   que no cargó. */
/* Sin foto el hueco se marca con un trazo punteado: reserva el lugar —asi los
   titulos siguen alineados— sin parecer una imagen que no cargo. */
.nota .miniatura:empty { background: none; border: 1px dashed var(--linea); }
.nota .crece { display: block; min-width: 0; }
.nota .titulo { display: block; font: 600 15px/1.35 var(--sans); margin-bottom: 3px; }
.nota .meta { display: block; font: 12px/1.4 var(--mono); color: var(--gris-2); }

/* La volanta va arriba del título y en versalita, como en un diario: es una
   categoría, no una frase. */
.nota .volanta {
  display: block;
  font: 600 10.5px/1.3 var(--sans); letter-spacing: .09em; text-transform: uppercase;
  color: var(--gris-2); margin-bottom: 2px;
}
/* La bajada con ancho de lectura: en una fila de 900px una bajada a todo lo
   ancho se lee peor que en dos líneas. */
.nota .bajada {
  display: block; margin-bottom: 5px; font-size: 13.5px; line-height: 1.5;
  color: var(--gris); max-width: 62em;
}

/* --- elegir con qué arrancar -------------------------------------------------
   Las plantillas al crear una campaña. Son tarjetas y no un `<select>` porque la
   decisión se toma MIRANDO: cuántos bloques tiene cada una, cómo se llama la que
   se usa todos los días. Y porque "empezar en blanco" es una opción de primera
   clase, no la última fila de una lista de otra cosa.

   Cada tarjeta es un `<button>` de su propio formulario: un clic, un POST, sin
   una línea de JavaScript y sin un paso intermedio de confirmación. */
.arranques { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.arranques .arranque { margin: 0; }
.cajaArranque {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  width: 100%; text-align: left; cursor: pointer;
  padding: 18px 20px; font: inherit; color: var(--tinta);
  background: var(--papel); border: 1px solid var(--linea); border-radius: 6px;
  box-shadow: var(--sombra);
}
.cajaArranque:hover { border-color: var(--tinta); }
.cajaArranque b { font: 600 15px/1.3 var(--sans); }
/* La de en blanco se marca como lo que es: el camino sin estructura. El trazo
   punteado es el mismo que usa la nota sin foto — un lugar que todavía no tiene
   nada adentro. */
.cajaArranque.enBlanco { background: none; border-style: dashed; box-shadow: none; }

/* --- renombrar en la misma fila ---------------------------------------------
   El nombre de una plantilla es un campo de texto y no un enlace a otra
   pantalla: es el único dato que tiene, y abrir una pantalla para editar un
   campo es una pantalla de más. */
.renombrar { display: flex; gap: 6px; align-items: center; margin: 0; }
/* Se encoge con la columna en vez de desbordarla: un ancho fijo adentro de una
   celda de tabla se sale por la derecha y se monta sobre la celda de al lado. */
.renombrar input { flex: 1 1 200px; min-width: 0; max-width: 340px; height: 32px; padding-top: 0; padding-bottom: 0; }
/* Una tabla cuyas filas tienen controles: las celdas se alinean al medio, no
   arriba. Con un campo de 32px al lado de un texto, el texto queda flotando. */
.alineada td { vertical-align: middle; }
/* Dos formularios que van uno al lado del otro en la misma celda. */
.juntas { display: flex; gap: 6px; justify-content: flex-end; align-items: center; }
/* Un formulario que va al lado de otra cosa en la misma celda. */
.enLinea { display: inline-block; margin: 0; }
/* Una lista adentro de una tarjeta, con el mismo aire que la de un aviso. */
.lista { margin: 6px 0 0; padding-left: 18px; }
.lista li { margin-bottom: 2px; }

/* --- la marca ----------------------------------------------------------------
   El logotipo y la palabra son UNA marca, no dos cosas apiladas: el tracking de
   "newsletter" está calculado para que ocupe exactamente el ancho del logo y los
   dos bordes queden alineados.

   Vive acá y no en la pantalla de entrada porque el producto se llama Amura
   NEWSLETTER en todas partes. Estuvo sólo en el login, y el resultado era que ni
   el menú ni la pantalla de error decían de qué producto son. */
/* La marca suele ser un enlace a la portada del panel. Sin esto, la regla
   general de los enlaces le subraya la palabra "newsletter". */
.marca { text-decoration: none; }
.marca img { display: block; }

/* Acá vivía `.producto`: la palabra "newsletter" compuesta debajo del logotipo
   de Amura. Se fue con el cambio de nombre — el lockup de whatsnews ya trae la
   firma `by amura` adentro, así que la segunda pieza sobraba. */

/* --- pegar una nota de una dirección -----------------------------------------
   Un `details` que se abre hacia abajo, sobre el contenido. Es la misma forma
   que el flotante de la etapa de pruebas, y por el mismo motivo: abre, cierra y
   manda sin una línea de guion.

   El `summary` ES el botón. Hay que sacarle el marcador de despliegue —el
   triangulito— que en un botón se ve como un error, y darle el `inline-flex` que
   `.btn` da por sentado: un `summary` es `display: list-item`, así que sin esto
   el texto se parte en dos líneas y no se alinea con el botón de al lado. */
.pegarNota { position: relative; }
.pegarNota > summary { list-style: none; display: inline-flex; align-items: center; white-space: nowrap; }
.pegarNota > summary::-webkit-details-marker { display: none; }
.pegarNota > summary::marker { content: ''; }
/* En la barra de filtros va pegado al formulario y no repartido: quien empuja al
   contador contra la derecha es este margen, no `space-between`.

   Y OBEDECE LA REGLA DEL COMPONENTE, que está escrita arriba: todo lo que va en
   esta barra mide `--alto-control`. El «+» vive FUERA del `.filtro` —adentro
   sería un formulario dentro de otro— así que la altura de ahí no lo alcanza y
   se la damos acá. Sin `align-self`: lo alineado lo arregló sacarle al `<form>`
   el margen del navegador, y un `align-self: flex-end` puesto encima de ese
   margen lo empujaba 14px hacia abajo en vez de acomodarlo. */
.barraFiltro > .pegarNota { margin-right: auto; }
.barraFiltro > .pegarNota > summary.btn.chico.masPegar {
  width: var(--alto-control); height: var(--alto-control);
}
/* SE ABRE HACIA LA IZQUIERDA, o sea `right: 0`: lo que se ancla es el borde
   DERECHO del panel al borde derecho del botón, y los 420px crecen hacia adentro
   de la pantalla. El botón vive al final de la barra, contra el margen derecho,
   así que abrirlo hacia el otro lado —`left: 0`— manda el panel fuera de la
   pantalla. Es al revés de lo que dice la intuición: `right` no es "hacia la
   derecha", es "pegado a la derecha". */
.pegarNota > form {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 30;
  width: 420px; max-width: 80vw; text-align: left;
  box-shadow: 0 14px 40px rgb(0 0 0 / 18%);
}
.pegarNota textarea { width: 100%; font: 13px/1.5 var(--mono); resize: vertical; }

/* --- el botón de «traer una nota de una dirección» ---------------------------
   UN SOLO BOTÓN PARA LOS DOS LUGARES donde vive esa función: la barra de filtros
   de Notas y la barra del selector del constructor. Es la misma cosa y tiene que
   verse igual, o son dos funciones parecidas que hay que aprender por separado.

   Es un «+» y no su nombre entero porque el texto medía más que el buscador que
   tiene al lado, y es el control que menos se usa de la barra. Lo que lo salva
   de ser un botón mudo es el `title` y el `aria-label` en el markup — y, en el
   constructor, que el vacío de la lista lo ofrezca con todas las letras.

   Vive acá y no en `constructor.css` justamente porque lo comparten dos
   pantallas: una clase que usan dos lugares y vive en la hoja de uno de ellos es
   la que se borra el día que se rehace esa pantalla. */
/* `.btn.chico.masPegar` Y NO `.masPegar` A SECAS. El botón lleva las tres clases
   y `.btn.chico` pesa DOS: con una sola clase, el `padding: 0` y el tamaño del
   signo perdían en silencio y el «+» quedaba corrido 7px a la derecha, adentro
   de un botón que por lo demás medía bien. Se ve como "el ícono está descentrado"
   y se busca en el lugar equivocado — no hay nada mal en el centrado, lo que no
   llegó a aplicarse es que el botón no tuviera padding. */
/* EL ALTO ES EXPLÍCITO Y NO ES OPCIONAL. Con el signo sacado del flujo (abajo),
   adentro de este botón no queda NADA que lo estire: sin esta línea mide 2px, o
   sea los dos bordes, y el botón desaparece. Lo mismo vale para cualquier botón
   de sólo ícono que se centre por posición en vez de por contenido. */
.btn.chico.masPegar {
  position: relative;
  width: 30px; height: 30px; padding: 0; flex: none; font-size: 17px; line-height: 1;
}
/* EL SIGNO VA EN UN `span` FUERA DEL FLUJO, y no centrado con `justify-content`.
   La razón es que en `/notas` este botón es un `<summary>`, y Chrome le deja una
   caja de marcador de 3px adentro que NO se saca con `::marker` — probado con
   `list-style: none`, con `content: ''`, con `font-size: 0` y cambiando el
   `display` a flex, a inline-flex y a block: los 3px siguen ahí en los cinco
   casos. El signo terminaba 1,5px corrido a la derecha, que se ve.
   Medido: con el `span` absoluto quedan 13,1px de cada lado en una caja de 38.
   El mismo botón como `<button>` —el del constructor— ya estaba bien; esto lo
   deja igual y no le cambia nada. */
.btn.chico.masPegar > span {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
}
/* Abierto se ve apretado. Sin eso, el único rastro de que el panel salió de este
   botón es la memoria de quien lo apretó. Son dos selectores porque son dos
   mecanismos: en Notas es un `details` —que anda sin JavaScript— y en el
   constructor un botón con `aria-expanded`, donde igual no hay nada sin JS. */
.pegarNota[open] > summary.masPegar,
.masPegar[aria-expanded="true"] { background: var(--tinta); border-color: var(--tinta); color: var(--papel); }

/* === dialogo.css ======================================================= */
/* ============================================================================
   DIÁLOGO Y AVISOS FLOTANTES — el sistema de confirmación de toda la app.

   Las dos mitades de la misma conversación: el diálogo pregunta ANTES de una
   acción que no se deshace, el aviso flotante confirma DESPUÉS que se hizo.
   Van juntos porque se usan juntos y porque comparten la puesta en escena
   —flotan sobre la página— aunque el aviso sea el mismo componente `.aviso`
   de componentes.css con otra ubicación.

   Sigue la dirección de base.css: papel, línea fina, sombra larga y el color
   sólo cuando pasa algo. Un diálogo de confirmación no es un momento para
   inventar un lenguaje visual nuevo — es la misma mesa, más cerca.
   ============================================================================ */

/* --- el diálogo ------------------------------------------------------------- */
/* Angosto a propósito: adentro hay un título, una línea y dos botones. Si algo
   necesita más que eso, no es una confirmación, es una pantalla. */
.dialogo {
  width: min(430px, 92vw); padding: 0; color: var(--tinta);
  border: 1px solid var(--linea); border-radius: 8px; background: var(--papel);
  box-shadow: 0 24px 70px rgba(22,35,58,.3);
}
/* Más oscuro que el del selector de notas: el selector es un paso más del
   trabajo, esto es un alto. La página de atrás tiene que salir de foco. */
.dialogo::backdrop { background: rgba(22,35,58,.5); }
.dialogo form { margin: 0; padding: 22px 24px 18px; }
.dialogo h2 { font: 400 21px/1.25 var(--serif); margin: 0 0 8px; }
.dialogo p { margin: 0; color: var(--gris); font-size: 14.5px; }
.dialogo .acciones { display: flex; justify-content: flex-end; }

/* El único rojo del sistema, y acá se gana: es el botón que borra, corta o
   invalida. El verde no aparece acá: el botón que confirma un envío usa la
   clase `.enviar` de siempre, que ya ES el verde y nada más que el envío. */
.dialogo .btn.peligro { background: var(--alerta); border-color: var(--alerta); color: #fff; }
.dialogo .btn.peligro:hover { filter: brightness(1.08); }

/* EL FOCO SE MARCA POR DENTRO, CON UN BORDE.
   El foco arranca en Cancelar (dialogo.js dice por qué), así que la marca está
   puesta desde que el diálogo abre. Con el anillo de la hoja general —2px por
   fuera— ese botón ocupa ocho píxeles más que el de al lado y se lee más
   grande, aunque los dos midan exactamente lo mismo: dos botones de la misma
   fila con distinta caja se leen como dos jerarquías distintas, que es lo
   contrario de lo que pasa acá.

   Es `box-shadow` y no `outline: -2px`: un outline con offset negativo no se
   ve sobre un botón con fondo lleno, y la mitad de los botones de acá lo
   tienen. La sombra interior se dibuja siempre y no ocupa un solo píxel. */
.dialogo .btn:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--tinta); }
.dialogo .btn.fuerte:focus-visible,
.dialogo .btn.peligro:focus-visible,
.dialogo .btn.enviar:focus-visible { box-shadow: inset 0 0 0 2px #fff; }
/* En alto contraste el sistema no dibuja sombras: ahí vuelve el anillo, que es
   lo único que ese modo respeta. Sin esto el diálogo queda sin foco visible. */
@media (forced-colors: active) {
  .dialogo .btn:focus-visible { outline: 2px solid; outline-offset: 1px; }
}

/* La animación es corta y sólo de entrada: una confirmación que tarda en
   aparecer es una confirmación que alguien contesta sin haberla leído. */
@media (prefers-reduced-motion: no-preference) {
  .dialogo[open] { animation: dialogoEntra .14s ease-out; }
  .dialogo[open]::backdrop { animation: fondoEntra .14s ease-out; }
}
@keyframes dialogoEntra {
  from { opacity: 0; transform: translateY(-6px) scale(.98); }
}
@keyframes fondoEntra { from { opacity: 0; } }

/* --- los avisos flotantes --------------------------------------------------- */
/* Abajo a la derecha y no arriba: arriba está la barra de cuenta asumida, que es
   permanente y no se comparte lugar con algo que se va solo. */
.avisos {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: flex; flex-direction: column-reverse; gap: 8px;
  width: min(340px, calc(100vw - 36px));
}
.avisos .aviso.flota {
  background: var(--papel); border: 1px solid var(--linea);
  border-left-width: 3px; border-radius: 5px;
  box-shadow: var(--sombra); cursor: pointer;
  transition: opacity .18s ease, transform .18s ease;
}
.avisos .aviso.yendose { opacity: 0; transform: translateY(6px); }

/* La barra de envío es fija y vive abajo: sin esto el aviso le cae encima justo
   cuando más se lo mira, que es al terminar de mandar. */
body:has(.cierre) .avisos { bottom: 84px; }

@media (max-width: 700px) {
  .avisos { right: 12px; left: 12px; bottom: 12px; width: auto; }
}

/* === formularios.css =================================================== */
/* ============================================================================
   FORMULARIOS — campos, agrupaciones y rejillas.

   El panel es navegación y formularios (docs/17): no hay SPA ni estado de
   cliente salvo el constructor. Así que esto no es un rincón de la hoja, es la
   mitad del producto.
   ============================================================================ */

label.campo { display: block; margin-bottom: 14px; }
label.campo > span { display: block; margin-bottom: 5px; }

/* Un estado al lado de la etiqueta: «Cargada», «Sin cargar». Es para los campos
   cuyo VALOR no se puede mostrar —una clave de proveedor— y donde por lo tanto
   el campo vacío no distingue "no hay nada" de "hay algo que no te muestro".
   Va acá y no pegado a la izquierda porque la etiqueta es lo que se lee primero
   y el estado es su aclaración, no otro dato. */
label.campo > span > .estado { margin-left: 8px; }
label.campo:last-child { margin-bottom: 0; }

/* La lista de tipos se escribe por EXCLUSIÓN y no por enumeración.
   Enumerarlos fue un error real: la lista decía `text, email, password, number`
   y el día que apareció un `type=search` salió sin estilo, con el cromo del
   sistema operativo en medio del panel. Y no se ve hasta que alguien lo mira,
   porque nada falla — sólo queda feo.
   Lo que se excluye es lo que TIENE su propio diseño más abajo: las casillas,
   el selector de color y el de archivo. Cualquier tipo nuevo entra bien solo.

   EL `:where()` NO ES DECORATIVO. `:not()` suma la especificidad de lo que lleva
   adentro, así que la cadena de cinco `:not()` pesa (0,5,1) — más que cualquier
   clase— y se comía los estilos de los componentes: los campos en línea del
   constructor volvieron a salir con caja, y sólo los `input`, porque al
   `textarea` esta regla lo alcanza por su nombre y no por la cadena. `:where()`
   pesa CERO, así que esto queda en (0,0,1): estilo de base, fácil de pisar desde
   un componente, que es exactamente lo que tiene que ser. */
input:where(:not([type=checkbox], [type=radio], [type=color], [type=file], [type=hidden])),
textarea, select {
  width: 100%; font: 15px/1.4 var(--sans); color: var(--tinta);
  padding: 9px 11px; border: 1px solid var(--linea); border-radius: 5px;
  background: #fff;
}
input:focus, textarea:focus, select:focus { border-color: var(--tinta); }
input::placeholder { color: var(--gris-2); }
textarea { resize: vertical; min-height: 72px; }

/* Chrome le pone una X propia a los `type=search`, con su tipografía y su
   tamaño, que no se parece a nada del resto de la hoja. */
input[type=search]::-webkit-search-cancel-button { appearance: none; -webkit-appearance: none; }

/* --- las casillas -----------------------------------------------------------
   La casilla nativa la dibuja el SISTEMA OPERATIVO: es azul en Windows, gris en
   macOS, de otro tamaño en Linux, y no se parece a nada de esta hoja. Es el
   mismo argumento que ya se aplicó al caret del `select` y por el que las redes
   del pie van en SVG: si es parte del diseño, lo dibujamos nosotros.

   Se apaga la apariencia y se compone con la tinta de la marca. El tilde va como
   SVG embebido —no como un pseudo-elemento con un borde rotado— porque una
   marca de verificación de verdad se lee mejor y no se deforma al escalar. */
input[type=checkbox] {
  appearance: none; -webkit-appearance: none;
  flex: none; width: 17px; height: 17px; margin: 0; padding: 0;
  border: 1px solid var(--gris-2); border-radius: 4px; background: #fff;
  cursor: pointer; vertical-align: -3px;
  background-repeat: no-repeat; background-position: center;
}
input[type=checkbox]:hover { border-color: var(--tinta); }
input[type=checkbox]:checked {
  background-color: var(--tinta); border-color: var(--tinta);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='9'%3E%3Cpath d='M1 4.5l3 3 6-6' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* El anillo va por fuera y sin cambiar la caja: un `outline` con offset negativo
   no se ve sobre un fondo lleno, que es lo que ya pasó en el diálogo. */
input[type=checkbox]:focus-visible { outline: 2px solid var(--tinta); outline-offset: 2px; }
input[type=checkbox]:disabled { background-color: var(--fondo); border-color: var(--linea); cursor: not-allowed; }
input[type=checkbox]:disabled:checked { background-color: var(--gris-2); border-color: var(--gris-2); }

/* El botón de opción, por el mismo argumento que la casilla: el nativo lo dibuja
   el sistema operativo. Redondo y con el punto adentro, para que se lea de una
   que es "una de estas" y no "las que quieras". */
input[type=radio] {
  appearance: none; -webkit-appearance: none;
  flex: none; width: 17px; height: 17px; margin: 0; padding: 0;
  border: 1px solid var(--gris-2); border-radius: 50%; background: #fff;
  cursor: pointer; vertical-align: -3px;
  background-repeat: no-repeat; background-position: center;
}
input[type=radio]:hover { border-color: var(--tinta); }
input[type=radio]:checked {
  border-color: var(--tinta);
  background-image: radial-gradient(circle, var(--tinta) 0 4px, transparent 4px);
}
input[type=radio]:focus-visible { outline: 2px solid var(--tinta); outline-offset: 2px; }
input[type=radio]:disabled { background-color: var(--fondo); border-color: var(--linea); cursor: not-allowed; }

/* --- elegir entre dos formas de hacer lo mismo -------------------------------
   No es una lista de opciones sueltas: es UNA decisión con dos caminos, y uno
   de ellos trae sus propias casillas colgando. Con los botones de opción a
   secas, los cuatro renglones se leían al mismo nivel y no se veía dónde
   terminaba una opción y empezaba la otra.

   El elegido queda LLENO. Es la única pista de estado que no depende de ver el
   punto adentro de un círculo de 17px, y de paso hace de contenedor: las listas
   quedan visiblemente adentro de su modo y no debajo de la tarjeta.
   Fondo y no color: el color es consecuencia, y elegir a quién le llega no es
   un problema ni un envío listo. */
.modos { display: grid; gap: 3px; }
.modo { border-radius: 6px; }
.modo:has(input[name=modo]:checked) { background: var(--fondo); }

/* El renglón que se aprieta. Es el `label` entero y no sólo el texto: una fila
   de 14px de alto es un blanco difícil, y acá el error se paga caro. */
label.modo, .modo .titulo {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-radius: 6px;
  font-size: 14px; color: var(--gris); cursor: pointer;
}
label.modo:hover, .modo .titulo:hover { background: var(--fondo); }
.modo:has(input[name=modo]:checked) > .titulo,
label.modo:has(input:checked) { color: var(--tinta); font-weight: 500; }

/* Las listas del modo "sólo estas". Sangradas hasta la altura del TEXTO de su
   modo —no de su botón—, que es lo que dice a simple vista que cuelgan de él. */
.modo .listas { display: grid; gap: 10px; padding: 1px 11px 12px 37px; }
.modo .listas .casilla { gap: 9px; }

/* Apagadas cuando el modo elegido es el otro: no deciden nada, y decirlo es
   mejor que desactivarlas —marcar una es la forma natural de cambiar de modo—.
   `:where()` alrededor del `:has()` porque `:not()` SUMA la especificidad de lo
   que lleva adentro, y sin eso esta regla pesaría más que cualquier componente. */
.modo:not(:where(:has(input[name=modo]:checked))) .listas { opacity: .45; }

/* El número de cada opción, a la derecha y en monoespaciada: es un hecho, y los
   hechos se leen en fila cuando están alineados. */
.modo .cuanto { margin-left: auto; color: var(--gris-2); }

/* --- el campo de archivo ----------------------------------------------------
   Mismo problema que la casilla: el botón lo dibuja el sistema operativo y dice
   "Seleccionar archivo" con su propia tipografía, al lado de un "Sin archivos
   seleccionados" en gris del sistema. El texto no se puede cambiar —es del
   navegador— pero el botón sí, y es lo que se ve. */
input[type=file] {
  font: 14px/1 var(--sans); color: var(--gris);
  max-width: 100%;
}
input[type=file]::file-selector-button {
  font: 500 14px/1 var(--sans);
  margin-right: 10px; padding: 0 14px; height: var(--alto-control);
  border: 1px solid var(--linea); border-radius: 5px;
  background: var(--papel); color: var(--tinta); cursor: pointer;
}
input[type=file]::file-selector-button:hover { border-color: var(--gris-2); }

/* La etiqueta al lado de una casilla. Alineada por la PRIMERA línea del texto,
   no centrada: con dos renglones, centrar deja la casilla flotando al medio. */
.opcion, .casilla {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 14px; color: var(--gris); cursor: pointer;
}
.opcion input[type=checkbox], .casilla input[type=checkbox],
.opcion input[type=radio], .casilla input[type=radio] { margin-top: 1px; }
.opcion:has(input:disabled), .casilla:has(input:disabled) { cursor: not-allowed; }


/* --- el selector ------------------------------------------------------------
   El caret nativo queda PEGADO al borde y cada navegador dibuja el suyo: un
   triángulo del sistema, sin aire, contra la línea del campo. En una hoja donde
   todo lo demás respira, es lo primero que se ve fuera de lugar.

   Se apaga la apariencia nativa y se dibuja el nuestro, con la misma distancia
   al borde que tiene el texto del otro lado. Va como SVG embebido y no como una
   pieza de markup: un `select` no admite hijos que no sean `option`, así que
   componerlo con un ícono al lado obligaría a envolver cada uno en un `div` —
   veinte lugares del panel para un chevron.
   ------------------------------------------------------------------------- */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 34px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2359616e' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
select:hover { border-color: var(--gris-2); }
/* Sin esto, Edge en modo compatible dibuja SU flecha además de la nuestra. */
select::-ms-expand { display: none; }

.ayuda { color: var(--gris); font-size: 13px; margin-top: 4px; }

/* Un campo que no tiene por qué ocupar todo el ancho: un selector de cuatro
   valores en una línea de 900px se lee peor, no mejor. */
.campo.tercio { max-width: 260px; }

/* --- el trabajo a la izquierda, el contexto a la derecha ---------------------
   Para pantallas que son un formulario más lo que hay que saber alrededor.

   Existe porque la alternativa —apilar todo en una columna angosta— deja media
   página vacía, y una caja flotando en un hueco es exactamente lo que separa a
   este panel de la pantalla de entrada. Los campos conservan su ancho de lectura
   y el contexto ocupa el resto en lugar de empujarlo hacia abajo. */
.conContexto { display: grid; grid-template-columns: minmax(0, 1fr) 328px; gap: 20px; align-items: start; }
.conContexto > .contexto { position: sticky; top: var(--top-pegajoso); }
@media (max-width: 980px) {
  .conContexto { grid-template-columns: 1fr; }
  .conContexto > .contexto { position: static; }
}

/* --- agrupaciones -----------------------------------------------------------
   Un formulario largo son varias decisiones distintas —quién es el cliente, con
   qué cabecera arranca, quién lo administra, qué plan tiene— y se leen mejor
   como bloques con nombre que como veinte campos seguidos. */
fieldset { border: 0; padding: 0; margin: 0 0 26px; }
fieldset:last-of-type { margin-bottom: 0; }
legend { padding: 0; margin-bottom: 3px; font: 600 16px/1.3 var(--sans); }

.rejilla { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.rejilla .completo { grid-column: 1 / -1; }
@media (max-width: 640px) { .rejilla { grid-template-columns: 1fr; } }


/* --- el campo de color -------------------------------------------------------
   EL CÓDIGO ES EL CAMPO y la muestra abre NUESTRA paleta. Al revés no se puede:
   un selector de color siempre tiene un color, así que el campo nunca podría
   quedar vacío — y vacío es un estado que importa, porque significa "uso el de
   la plantilla".

   Y la paleta es nuestra porque la del sistema no sirve para esto: cada
   navegador abre la suya y la de Firefox pide rojo, verde y azul por separado
   sin aceptar un código pegado, que es justo el dato que tiene a mano quien
   conoce la marca del medio.

   La muestra sigue siendo un `input type=color` —es lo único que pinta un color
   arbitrario sin un `style=` en el HTML— con todo su cromo apagado: sin marco,
   sin relleno y con la esquina redondeada como el resto de la hoja. Queda un
   cuadrado de color y nada más. Su selector nativo lo frena el guion. */

/* La regla general de los campos pone en bloque a TODO span hijo de `.campo`, y
   gana por especificidad: por eso esta va con las dos clases. Sin eso el código
   cae debajo de la muestra en vez de quedar al lado. */
label.campo > .campoColor { position: relative; display: flex; gap: 8px; align-items: center; }
.campoColor .muestra {
  width: 34px; height: 34px; flex: none; padding: 0; cursor: pointer;
  border: 1px solid var(--linea); border-radius: 5px; background: none;
  appearance: none; -webkit-appearance: none;
}
.campoColor .muestra::-webkit-color-swatch-wrapper { padding: 0; }
.campoColor .muestra::-webkit-color-swatch { border: 0; border-radius: 4px; }
.campoColor .muestra::-moz-color-swatch { border: 0; border-radius: 4px; }
.campoColor .muestra:hover { border-color: var(--gris-2); }
.campoColor .hex {
  width: 120px; height: 34px; padding-top: 0; padding-bottom: 0;
  text-transform: lowercase;
}
/* El campo vacío muestra el código de la plantilla en gris: dice de dónde sale
   el color que se está viendo sin hacerlo pasar por una elección. */
.campoColor .hex::placeholder { color: var(--gris-2); }

/* La paleta de colores. Se llama `paletaColor` y NO `paleta` porque el
   constructor ya tiene una columna con esa clase —la suya es la lista de
   bloques— y esta le impuso una grilla de 22px: los bloques quedaron como
   cuadraditos altos. Una hoja es compartida: una clase con nombre común le pisa
   el diseño a cualquier pantalla que use la misma palabra.

   Cuelga del campo, así que se cierra sola al hacer clic afuera y no
   necesita tapar la pantalla: elegir un color no es un alto en el trabajo. */
.paletaColor {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 40;
  display: grid; grid-template-columns: repeat(10, 22px); gap: 4px;
  padding: 10px; background: var(--papel);
  border: 1px solid var(--linea); border-radius: 6px;
  box-shadow: 0 12px 34px rgba(22,35,58,.18);
}
.paletaColor .tono {
  width: 22px; height: 22px; padding: 0; cursor: pointer;
  border: 1px solid rgba(22,35,58,.12); border-radius: 4px;
}
.paletaColor .tono:hover { transform: scale(1.15); border-color: var(--tinta); }
.paletaColor .tono:focus-visible { outline: 2px solid var(--tinta); outline-offset: 1px; }

/* --- las redes del pie -------------------------------------------------------
   Una fila por red: QUÉ red —que es lo que define el ícono—, su dirección y el
   botón para sacarla. Se agregan con el botón de abajo; sin JavaScript vienen
   dos filas libres, así que la pantalla sirve igual. */
.redes { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.redes .red { display: flex; gap: 6px; align-items: center; }
.redes .red select { flex: 0 0 150px; height: 34px; padding-top: 0; padding-bottom: 0; }
.redes .red input { flex: 1 1 auto; min-width: 0; height: 34px; padding-top: 0; padding-bottom: 0; }
.redes .red .btn { flex: none; }
/* En el PANEL el ícono va en SVG. En el CORREO no: ahí un ícono es una imagen y
   la mitad de los clientes no las muestra, así que las redes van como texto. */
.iconoRed { width: 18px; height: 18px; flex: none; color: var(--gris-2); }
.redes .red:focus-within .iconoRed { color: var(--tinta); }

/* --- el campo de imagen: subir O pegar una dirección --------------------------
   Los dos controles apilados y no lado a lado: son dos caminos para lo mismo,
   no dos datos, y en una fila el de archivo —que en cada navegador mide
   distinto— empuja al otro a un ancho impredecible.

   La muestra va ARRIBA de todo y sólo cuando hay algo cargado. Es lo que
   convierte «logo_url tiene una dirección» en «el logotipo es este», que es lo
   único que alguien quiere confirmar en esta pantalla. */
label.campo > .campoImagen { display: grid; gap: 8px; }
.campoImagen .muestraImagen {
  max-width: 260px; max-height: 90px; justify-self: start;
  padding: 8px 10px; border: 1px solid var(--linea); border-radius: 5px;
  background: #fff;  /* Un logo en PNG transparente sobre el papel gris no se ve. */
}
.campoImagen input[type=file] { font-size: 13px; color: var(--gris); }

/* === estructura.css ==================================================== */
/* ============================================================================
   ESTRUCTURA — el armazón de toda página con sesión: el menú lateral, el
   envoltorio del contenido y las dos barras fijas.

   MENÚ A LA IZQUIERDA.
   Gana acá por una razón concreta, no por gusto: la cabecera en la que se está
   parado y la sección conviven en la misma columna y quedan a la vista todo el
   tiempo. Mandarle a la lista equivocada es el error más caro que se puede
   cometer en este panel, y no se arregla después.
   ============================================================================ */

.lateral {
  position: fixed; inset: 0 auto 0 0; width: var(--lateral); z-index: 25;
  background: var(--tinta); color: #fff;
  display: flex; flex-direction: column;
  padding: 22px 0 14px;
}
.lateral .logo { display: block; padding: 0 20px 22px; }
.lateral .logo img { width: 152px; height: auto; display: block; }

/* Crece hasta el pie: es lo que deja mandar el último plano al fondo. */
.lateral nav { display: flex; flex-direction: column; flex: 1; padding: 6px 12px; }
.lateral nav a {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 12px; border-radius: 5px;
  color: #b9c3d4; text-decoration: none; font-size: 14.5px;
  border-left: 2px solid transparent;
}
.lateral nav a:hover { color: #fff; background: rgba(255,255,255,.05); }
.lateral nav a[aria-current] {
  color: #fff; background: rgba(255,255,255,.08);
  /* La marca son dos planos diagonales; el indicador de sección es un trazo del
     verde de la marca. Es lo único de la paleta que aparece en el menú. */
  border-left-color: var(--amura);
}

/* --- los tres planos del menú -----------------------------------------------
   El menú se ordena por CADA CUÁNTO SE TOCA CADA COSA, no por temas: el trabajo
   de todos los días, lo que se toca a veces, y lo de una sola vez. La línea
   entre planos hace el trabajo que hacía una microetiqueta ("Contenido"), pero
   sin nombrar la agrupación — porque no es un tema, es una frecuencia, y ponerle
   nombre a eso obliga a inventar palabras que nadie usa.

   Sin desplegar ni plegar: un acordeón acá sólo serviría para esconder algo que
   entra igual. */
.lateral nav .plano { display: flex; flex-direction: column; gap: 1px; padding: 7px 0; }
.lateral nav .plano + .plano { border-top: 1px solid rgba(255,255,255,.07); }
/* El último plano se va al fondo: entre lo que se usa y lo que se configura hay
   una pantalla de por medio, y el aire lo dice mejor que otra línea. */
.lateral nav .plano.final { margin-top: auto; }

/* --- el contador de una sección ---------------------------------------------
   Un panel de operación se abre para saber qué hay que hacer hoy. Que esa
   respuesta esté en el menú —doce notas sin usar, una fuente rota— es lo que lo
   diferencia de una lista de enlaces.

   Monoespaciada porque es un dato (base.css, regla 2), y sin fondo ni globo: no
   es una notificación que hay que despachar, es cuánto hay. */
.lateral nav .cuenta {
  font: 12.5px/1 var(--mono); font-style: normal;
  font-variant-numeric: tabular-nums; color: #7f8ca6;
}
.lateral nav a:hover .cuenta, .lateral nav a[aria-current] .cuenta { color: #c9d3e3; }
/* Lo único que se rompe solo en todo el menú. Es el mismo óxido de las alertas,
   levantado para que se lea sobre el lateral oscuro. */
.lateral nav .cuenta.mal { color: #e08d76; }

/* EL CONTEXTO, arriba de todo y separado del menú por una línea. No es una
   sección más: es dónde estás parado, y de eso depende a qué lista le va a
   llegar lo que se mande. */
.lateral .cabecera { padding: 2px 20px 14px; border-bottom: 1px solid rgba(255,255,255,.07); }
.lateral .cabecera .eti { display: block; margin-bottom: 5px; color: #6f7f9b; }
.lateral .cabecera form { margin: 0; }
/* Con una sola cabecera no hay nada que elegir, pero sí que saber. Va como
   texto, con el peso de un título: es el nombre del medio al que se le escribe. */
.lateral .cabecera .unica { font: 600 15px/1.25 var(--sans); color: #fff; }
/* El mismo selector que el resto del panel, pero sobre el lateral oscuro: el
   caret va claro. Se declara `background-color` y no el atajo `background`,
   que borraría el chevron que puso formularios.css. */
.lateral .cabecera select {
  width: 100%; padding: 7px 30px 7px 9px; font-size: 13.5px;
  background-color: #22314c; color: #fff; border: 1px solid #35486a; border-radius: 5px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%238ea0bd' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-position: right 10px center;
}
.lateral .cabecera select:hover { border-color: #4a608a; }
.lateral .pie { margin-top: auto; padding: 14px 20px 0; border-top: 1px solid rgba(255,255,255,.09); }
/* El nombre propio es el enlace al perfil: sin subrayado hasta que se lo apunta,
   para que no compita con el menú de arriba. */
.lateral .pie .quien {
  display: block; color: #8ea0bd; margin-bottom: 6px; text-decoration: none;
}
.lateral .pie .quien:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.lateral .pieForm { margin: 0; }

/* "Salir" NO se ve como botón, aunque tenga que serlo.
   Cerrar sesión es un POST —un GET no puede tener efecto—, así que el elemento
   es un `<button>` a la fuerza. Pero está en una columna de enlaces, y un botón
   con marco ahí adentro se lee como una pieza de otra pantalla. Se le da la
   forma que le corresponde a lo que hace: un enlace. */
.lateral .salir {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: 13.5px/1.4 var(--sans); color: #8ea0bd;
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: rgba(255,255,255,.28);
}
.lateral .salir:hover { color: #fff; text-decoration-color: currentColor; }

.envoltorio { max-width: 1080px; margin: 0 auto; padding: 30px 30px 120px; }

/* Angosto es el CONTENIDO, no la página.
   Estrechar el envoltorio lo recentra, y entonces el bloque arranca en otra
   coordenada que en el resto del panel: navegando entre pantallas el contenido
   salta de costado y queda flotando en un hueco. La columna de la página es
   siempre la misma; lo que se limita es el ancho de línea de lo que va adentro. */
.envoltorio.angosto > * { max-width: 720px; }
body.conLateral { padding-left: var(--lateral); }

@media (max-width: 860px) {
  :root { --lateral: 0px; }
  body.conLateral { padding-left: 0; }
  .lateral { position: static; width: auto; flex-direction: row; align-items: center;
    flex-wrap: wrap; gap: 10px; padding: 12px 16px; }
  .lateral .logo { padding: 0; }
  .lateral .logo img { width: 118px; }
  .lateral nav { flex-direction: row; padding: 0; margin-left: auto; }
  .lateral .cabecera { padding: 0; width: 100%; }
  .lateral .pie { margin: 0; padding: 0; border: 0; display: flex; align-items: center; gap: 12px; }
  .lateral .pie .quien { margin: 0; }
  .envoltorio { padding: 20px 16px 130px; }
}

/* ============================================================================
   LA BARRA DE CUENTA ASUMIDA.
   Un root operando en nombre de un cliente. Fija arriba, del mismo modo que la
   barra de cierre está fija abajo: las dos existen porque el error que evitan no
   se deshace. Ésta contesta "en nombre de quién estoy trabajando" sin que haya
   que ir a buscarlo.

   Va en óxido y no en tinta a propósito. La regla de la casa es que el color es
   consecuencia, y esto ES una consecuencia: no es el estado normal del panel.
   ============================================================================ */
/* Va SOBRE EL CONTENIDO, a la derecha del menú, y no de borde a borde.
   El menú lateral es lo que no se mueve nunca: es la referencia de dónde estás
   parado, y una franja que lo empuja hacia abajo hace que la aplicación entera
   parezca haberse corrido. Así que la barra ocupa la columna de trabajo —que es
   justamente de lo que habla— y el lateral sigue anclado arriba, entero.

   Tampoco se encajona en los 1080px del contenido, como sí hace la barra de
   cierre: esa habla de LA CAMPAÑA que se está mirando y se alinea con ella; ésta
   habla de la sesión. */
.asumida {
  position: fixed; top: 0; left: var(--lateral); right: 0; z-index: 40;
  background: var(--alerta); color: #fff;
  border-bottom: 1px solid rgba(0,0,0,.16);
}
/* Alto fijo y no padding: `body` y `.lateral` tienen que correrse exactamente lo
   que mide, y un alto que dependa del botón de adentro deja un hueco o tapa una
   franja. */
.asumida .dentro {
  height: 42px; padding: 0 30px;
  display: flex; align-items: center; gap: 16px;
}
.asumida .quien { flex: 1; min-width: 0; font-size: 13.5px; }
.asumida .quien b { font-weight: 600; }
.asumida .eti { color: rgba(255,255,255,.72); }
/* La cabecera, separada del cliente por una línea: son dos cosas de distinto
   nivel —el cliente y una de sus cabeceras— y en una sola fila corrida se leen
   como si fueran la misma. Se esconde antes que el resto en pantalla angosta:
   el selector del menú la sigue diciendo. */
.asumida .asumidaCabecera {
  margin-left: 14px; padding-left: 14px; border-left: 1px solid rgba(255,255,255,.3);
}
@media (max-width: 720px) { .asumida .asumidaCabecera { display: none; } }
.asumida .btn {
  background: transparent; color: #fff; border-color: rgba(255,255,255,.45);
  white-space: nowrap;
}
.asumida .btn:hover { background: rgba(0,0,0,.14); border-color: #fff; }

/* El hueco lo hace el CONTENIDO, no el `body`: correr el body bajaría también el
   lateral, que es exactamente lo que no tiene que pasar. 43 = los 42 de la barra
   más su borde inferior.

   Va en `margin-top` y no en `padding-top` para no pisar el padding que ya trae
   el envoltorio. */
body.asumiendo main { margin-top: 43px; }
/* Y lo que sea pegajoso tiene que quedar DEBAJO de la barra, no atrás: 43 de la
   barra más el aire de siempre. Es UNA línea porque el alto vive en un token
   (base.css); con el número suelto en cada regla, arreglarlo era acordarse de
   todas las columnas pegajosas del panel. */
body.asumiendo { --top-pegajoso: 67px; }

/* Mientras se opera en nombre de otro, el botón de enviar deja de ser verde.
   El verde significa "adelante" y esto no es un envío como los otros: sale de la
   lista de un cliente, firmado con su remitente, decidido por nosotros. */
body.asumiendo .btn.enviar { background: var(--alerta); border-color: var(--alerta); }

@media (max-width: 860px) {
  /* Acá el lateral deja de ser fijo y pasa a ser una tira horizontal arriba de
     todo, así que la barra vuelve a ocupar el ancho entero y lo que se corre es
     el documento: el menú se acomoda solo, abajo de la franja. */
  body.asumiendo { padding-top: 43px; }
  body.asumiendo main { margin-top: 0; }
  .asumida .dentro { padding: 0 16px; gap: 10px; }
}

/* ============================================================================
   LA BARRA DE CIERRE — el elemento que hace memorable a este panel.
   Fija abajo, siempre visible: a cuántos les llega, qué falta, y un botón que
   permanece deshabilitado DICIENDO POR QUÉ. Hace visible la irreversibilidad en
   vez de esconderla detrás de un modal de confirmación que nadie lee.
   ============================================================================ */
.cierre {
  position: fixed; left: var(--lateral); right: 0; bottom: 0; z-index: 30;
  background: var(--papel); border-top: 1px solid var(--linea);
  box-shadow: 0 -2px 20px rgba(22,35,58,.07);
}
.cierre .dentro {
  max-width: 1080px; margin: 0 auto; padding: 12px 30px;
  min-height: var(--alto-cierre); box-sizing: border-box;
  display: flex; align-items: center; gap: 26px;
}
.cierre .cuenta { display: flex; align-items: baseline; gap: 8px; }
.cierre .cuenta b { font: 600 22px/1 var(--mono); font-variant-numeric: tabular-nums; }
.cierre .trabas { flex: 1; min-width: 0; color: var(--alerta); font-size: 13px; }
.cierre .trabas ul { margin: 0; padding-left: 17px; }
.cierre .listo { flex: 1; color: var(--listo); font-size: 13px; }
.cierre .der { display: flex; gap: 8px; align-items: center; }
/* La prueba es un formulario adentro de la barra, así que trae su propia caja.
   Sin esto hereda el `align-items: flex-start` de `.fila` y su botón queda
   pegado ARRIBA de los 41px del campo, tres píxeles más alto que el de enviar
   —dos botones de la misma barra a distinta altura, que es lo primero que se
   nota cuando se los mira juntos. */
.cierre .der form { margin: 0; align-items: center; gap: 6px; }
/* El campo del correo de prueba: al lado de su botón, no a todo el ancho, y de
   la misma altura. Un campo y un botón lado a lado son una sola fila de
   controles: que midan distinto los separa en dos cosas que no lo son. */
.cierre .angostoCampo {
  width: 190px;
  /* La altura exacta del botón de al lado. Con padding no da: el campo mide
     15px de texto por 1.4 de interlínea y termina un píxel más alto, que
     alcanza para que la fila se vea desprolija. Un input centra su texto solo
     cuando tiene altura. */
  height: 34px; padding-top: 0; padding-bottom: 0;
}
@media (max-width: 720px) {
  .cierre .dentro { flex-wrap: wrap; gap: 12px; }
  .cierre .der { width: 100%; }
  .cierre .der .btn { flex: 1; justify-content: center; }
}

/* === entrada.css ======================================================= */
/* ============================================================================
   ENTRADA — la única pantalla que ve alguien sin sesión.

   Es la primera impresión del producto y la única que se mira sin estar
   trabajando, así que se la trata como una portada: a escala de página, con
   aire, y con el logotipo haciendo de título. Nada de color — el verde sigue
   siendo exclusivo del envío.

   ESTA PANTALLA ES EL PISO DE CALIDAD VISUAL DEL PRODUCTO, no la excepción.
   Al tocar cualquier otra, la pregunta es si la composición ocupa la página o si
   es un bloque centrado en un hueco.
   ============================================================================ */

main.desnudo { max-width: none; margin: 0; padding: 0; }

/* Dos mitades: a la izquierda la marca sobre tinta, a la derecha el trabajo
   sobre papel. Es la misma división que gobierna todo el panel —tinta y papel—
   pero acá puesta a escala de portada. */
.entrada { min-height: 100vh; display: grid; grid-template-columns: 1fr .88fr; }

/* El suelo es `--noche`, el mismo de la página pública: quien llega acá viene de
   ahí, y que la mitad oscura sea del mismo azul es lo que hace que se lea como
   el mismo producto y no como otro sitio. */
.entrada .lado {
  background: var(--noche); color: #fff;
  padding: 46px 52px; display: flex; flex-direction: column;
  position: relative; overflow: hidden;
}
/* Eco de los dos planos diagonales del logotipo. Va al 4%: la primera versión
   estaba al 13% y se leía como una figura atravesando la pantalla, que es
   exactamente lo que no tiene que pasar. Esto es textura — se nota si falta,
   no si está. */
.entrada .lado::after {
  content: ''; position: absolute; inset: -20%;
  background:
    linear-gradient(116deg, transparent 40%, rgba(15,206,169,.045) 40%, rgba(15,206,169,.045) 62%, transparent 62%),
    linear-gradient(116deg, transparent 62%, rgba(0,167,138,.03) 62%, rgba(0,167,138,.03) 84%, transparent 84%);
  pointer-events: none;
}
.entrada .lado > * { position: relative; z-index: 1; }

/* La frase va en el medio, no pegada abajo: con el logo arriba y el texto al
   pie quedaba un hueco enorme en el centro que no decía nada. */
.entrada .lado .centro { margin: auto 0; }
.entrada .lado .pieLado { font: 12px/1 var(--mono); color: rgba(255,255,255,.34); }

/* La marca —el logotipo y la palabra— vive en componentes.css: la usan también
   el menú lateral y la pantalla de error. Acá no hay nada que agregarle. */

/* El ancho máximo va en em y no en px: la medida que importa es cuántos
   caracteres entran por línea, no cuántos píxeles. */
.entrada .lema { font: 400 38px/1.18 var(--serif); margin: 0 0 14px; max-width: 12em; letter-spacing: -.01em; }
/* El mismo gris de apoyo que usa la página pública sobre este fondo. Antes era
   un `#9daaba` suelto que no salía de ningún lado. */
.entrada .apoyo { margin: 0; max-width: 24em; font-size: 14px; line-height: 1.65; color: #a9b1bf; }

/* --- la mitad de papel --- */
.entrada .panel { background: var(--papel); display: grid; place-items: center; padding: 44px 30px; }
.entrada .caja { width: 100%; max-width: 328px; }
.entrada h1 { font-size: 27px; margin-bottom: 4px; }
.entrada .sub { font-size: 14px; margin-bottom: 24px; }
.entrada .campo > span { font-size: 13px; color: var(--gris); }
.entrada input { padding: 11px 12px; }
.entrada .campo:last-of-type { margin-bottom: 22px; }
.entrada .aviso { margin-bottom: 18px; }

/* ============================================================================
   CUANDO ALGO SALE MAL.

   Vive en el mismo archivo que la entrada porque es el mismo problema: una
   pantalla que alguien ve fuera del flujo de trabajo, a veces sin sesión. La
   marca sobre el fondo, la caja de papel, y una salida. Nada de blanco pelado.
   ============================================================================ */
.pantallaProblema { min-height: 100vh; display: grid; place-items: center; padding: 40px 24px; }
.pantallaProblema .caja {
  width: 100%; max-width: 460px; text-align: center;
  background: var(--papel); border: 1px solid var(--linea);
  border-radius: 8px; box-shadow: var(--sombra); padding: 40px 34px 34px;
}
.pantallaProblema .marca { display: inline-block; margin-bottom: 26px; }
.pantallaProblema .marca img { display: block; }
.pantallaProblema h1 { font-size: 27px; margin-bottom: 8px; }
.pantallaProblema .sub { font-size: 15px; margin-bottom: 24px; }

@media (max-width: 840px) {
  .entrada { grid-template-columns: 1fr; min-height: 0; }
  .entrada .lado { padding: 28px 26px 32px; gap: 22px; }
  .entrada .lado .centro { margin: 0; }
  .entrada .lado .pieLado { display: none; }
  .entrada .lema { font-size: 25px; max-width: none; margin-bottom: 8px; }
  .entrada .apoyo { font-size: 13px; max-width: none; }
  .entrada .panel { padding: 34px 26px 64px; place-items: start center; }
}

/* === constructor.css =================================================== */
/* ============================================================================
   EL CONSTRUCTOR — tres columnas: paleta / lienzo / previa.

   El modelo es ESQUELETO PRIMERO: se agrega el bloque y aparece con sus ranuras
   vacías. Por eso una ranura vacía tiene que verse como un lugar que espera
   algo —borde punteado, invitación— y no como un error.
   ============================================================================ */

.envoltorio.ancho { max-width: 1560px; }

.cabeceraArmado { display: flex; align-items: flex-end; gap: 16px; margin-bottom: 16px; }
.cabeceraArmado h1 { margin: 0; }

.guardado { color: var(--gris-2); white-space: nowrap; }
.guardado.error { color: var(--alerta); }

/* La columna del medio es la que más aire tiene que tener: es donde se trabaja.
   Antes se la comía una previa de 440px que no servía para juzgar un correo de
   600px — entraba apretada y con scroll—, así que el ancho se lo lleva ahora el
   lienzo y lo de al lado sólo necesita entrar un formulario. */
.constructor {
  display: grid; grid-template-columns: 208px minmax(0, 1fr) minmax(0, 330px);
  gap: 18px; align-items: start;
}
.constructor .columna.lados { position: sticky; top: var(--top-pegajoso); }
.constructor .paleta { position: sticky; top: var(--top-pegajoso); }
@media (max-width: 1180px) {
  .constructor { grid-template-columns: 190px minmax(0, 1fr); }
  .constructor .columna.lados { grid-column: 1 / -1; position: static; }
}
@media (max-width: 860px) {
  .constructor { grid-template-columns: 1fr; }
  .constructor .paleta { position: static; }
}
.tituloColumna { padding: 0 4px 10px; }
.asuntoLeido { font: 400 18px/1.3 var(--serif); }
.ayuda.centrado { text-align: center; margin-bottom: 0; }

/* --- la previa a tamaño real -------------------------------------------------
   Va en un diálogo y no incrustada al costado por una razón de medidas, no de
   gusto: un correo se diseña a 600px y la columna daba 440. Lo que se veía ahí
   no era el correo, era el correo apretado — y para juzgar un diseño eso es
   peor que no verlo, porque lleva a corregir cosas que no están mal.

   Los dos anchos son los que importan de verdad: 600px es el estándar del
   correo, y 390px es un teléfono actual, que es donde lo va a leer la mayoría.
   ------------------------------------------------------------------------- */
.previaModal {
  width: min(1100px, 94vw); height: min(88vh, 900px); max-width: none; max-height: none;
  padding: 0; border: 1px solid var(--linea); border-radius: 8px;
  background: var(--fondo); color: var(--tinta);
  box-shadow: 0 24px 70px rgba(22,35,58,.3);
}
.previaModal::backdrop { background: rgba(22,35,58,.45); }

.cuerpoPrevia {
  height: calc(100% - 55px); overflow-y: auto; padding: 18px 0;
  display: flex; justify-content: center;
}
.cuerpoPrevia iframe {
  width: 100%; height: 100%; min-height: 100%; border: 0; display: block;
  background: #fff; box-shadow: 0 2px 18px rgba(22,35,58,.12);
}
/* 640 y no 600: los 40 de sobra son el margen que el propio correo se pone a los
   costados, así que a 600 clavados el contenido queda pegado al borde. */
.cuerpoPrevia.escritorio iframe { max-width: 640px; }
/* El teléfono se dibuja con su marco: sin él, un iframe angosto en el medio de
   una pantalla grande no se lee como un teléfono, se lee como algo cortado. */
.cuerpoPrevia.telefono iframe {
  max-width: 390px; border-radius: 14px; border: 8px solid var(--tinta);
  box-shadow: 0 8px 30px rgba(22,35,58,.28);
}

/* --- la paleta -------------------------------------------------------------- */
#paleta .grupo { margin-bottom: 16px; }
#paleta .eti { padding: 0 4px 6px; }
.pieza {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 10px; margin-bottom: 3px;
  background: var(--papel); border: 1px solid var(--linea); border-radius: 5px;
  font: 500 13.5px/1.2 var(--sans); color: var(--tinta); text-align: left; cursor: pointer;
}
.pieza:hover { border-color: var(--gris-2); box-shadow: var(--sombra); }
.pieza .icono { color: var(--gris-2); width: 15px; text-align: center; flex: none; }

/* --- el lienzo -------------------------------------------------------------- */
.lienzo { display: flex; flex-direction: column; gap: 10px; }
.lienzoVacio {
  padding: 60px 24px; text-align: center; color: var(--gris);
  border: 2px dashed var(--linea); border-radius: 8px; background: rgba(255,255,255,.4);
}
.lienzoVacio p { margin: 0 0 6px; }
.lienzoVacio .dato { color: var(--gris-2); }

.tarjetaModulo { background: var(--papel); border: 1px solid var(--linea); border-radius: 6px; box-shadow: var(--sombra); }
.tarjetaModulo.llevando { opacity: .4; }
.tarjetaModulo.encima { border-color: var(--listo); box-shadow: 0 0 0 2px rgba(12,119,98,.18); }
.tarjetaModulo > header {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px; border-bottom: 1px solid var(--linea);
}
.tarjetaModulo .agarre { cursor: grab; color: var(--gris-2); font-size: 15px; line-height: 1; }
.tarjetaModulo .agarre:active { cursor: grabbing; }
.tarjetaModulo header .icono { color: var(--gris-2); }
.tarjetaModulo .nombre { font: 600 13px/1 var(--sans); letter-spacing: .01em; }
.tarjetaModulo header .n {
  color: var(--gris-2); background: var(--fondo); border-radius: 3px;
  min-width: 20px; text-align: center; padding: 3px 0; font-size: 11px;
}
.tarjetaModulo header .acciones { margin-left: auto; }
.tarjetaModulo .cuerpo { padding: 12px; }
.tarjetaModulo .campo:last-child { margin-bottom: 0; }

/* --- las ranuras ------------------------------------------------------------ */
.ranuras { display: grid; gap: 8px; margin-bottom: 10px; }
.ranuras:last-child { margin-bottom: 0; }
.ranuras.grid-2 { grid-template-columns: 1fr 1fr; }
.ranuras.grid-3 { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 700px) { .ranuras.grid-2, .ranuras.grid-3 { grid-template-columns: 1fr; } }

.ranura.vacia, .ranura.sumar {
  display: block; width: 100%; padding: 14px 12px;
  border: 1px dashed var(--gris-2); border-radius: 5px; background: transparent;
  color: var(--gris); font: 13.5px/1 var(--sans); cursor: pointer;
}
.ranura.vacia:hover, .ranura.sumar:hover { border-color: var(--tinta); color: var(--tinta); background: rgba(255,255,255,.6); }
.ranura.sumar { padding: 10px; font-size: 16px; }

.ranura.llena {
  display: flex; align-items: flex-start; gap: 9px; padding: 7px 8px;
  border: 1px solid var(--linea); border-radius: 5px; background: #fff; min-width: 0;
}
.ranura.llena img { width: 52px; height: 36px; object-fit: cover; border-radius: 3px; flex: none; }
.textoNota { display: grid; gap: 1px; min-width: 0; flex: 1; }

/* LA FOTO ES EL BOTÓN DE CAMBIAR LA FOTO.
   En la ranura ya hay cuatro cosas apretadas y no entra un botón más; y el lugar
   donde cualquiera va a apretar para cambiar una foto es la foto. El `label`
   dispara el `input type=file` que tiene adentro sin una línea de guion.
   La tapa se ve al pasar por encima o al llegar con el teclado — y SIEMPRE
   cuando no hay foto, que es cuando hay que contar que se puede poner una. */
.fotoNota {
  position: relative; display: block; width: 52px; height: 36px; flex: none;
  border-radius: 3px; overflow: hidden; cursor: pointer;
}
.fotoNota.sinFoto { border: 1px dashed var(--gris-2); }
.fotoNota .tapa {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: 0 3px; text-align: center;
  font: 600 9.5px/1.15 var(--sans); text-transform: uppercase; letter-spacing: .03em;
  color: #fff; background: rgb(22 35 58 / 62%); opacity: 0; transition: opacity .12s;
}
.fotoNota:hover .tapa,
.fotoNota:focus-within .tapa { opacity: 1; }
/* Sin foto no hay nada abajo que tapar, así que el rótulo es el contenido y va
   en tinta sobre el papel: blanco sobre blanco no se lee. */
.fotoNota.sinFoto .tapa { opacity: 1; color: var(--gris); background: none; }
.fotoNota.sinFoto:hover .tapa { color: var(--tinta); }

/* Mientras la imagen viaja. Sin esto, en una conexión lenta no pasa nada
   visible y se elige otro archivo encima del que está subiendo. */
.ranura.subiendo { opacity: .55; pointer-events: none; }

/* ============================================================================
   EDICIÓN EN LÍNEA
   La ranura ES la nota en miniatura: cada campo está tipografiado como el papel
   que cumple —volanta en versales, título en negrita, bajada en gris— y no como
   un control. Sin etiquetas, sin cajas y sin fondo hasta que se lo toca; lo que
   dice qué es cada cosa cuando está vacía es el placeholder.
   El borde aparece al pasar por encima: es lo único que avisa que eso se puede
   escribir, y aparece recién cuando hace falta saberlo.
   ============================================================================ */
/* ============================================================================
   NO ES UN TEXTAREA, ES UN ELEMENTO EDITABLE.

   Fue un textarea dos veces y las dos dieron el mismo problema: un textarea
   tiene alto propio y hay que calcularlo. Primero con `field-sizing: content`
   —que Firefox no implementa— y despues midiendo con JavaScript. En las dos, el
   campo quedaba con un alto que no era el de su texto, y sobre un textarea con
   el alto equivocado y `overflow:hidden` el cursor no cae donde se hizo clic:
   se iba al principio.

   Un elemento editable CRECE SOLO, en todos los navegadores, porque es un
   bloque de texto normal. No hay alto que calcular, no hay `overflow` que
   esconda nada, y el cursor lo pone el navegador donde uno tocó. Se elimina el
   problema en vez de compensarlo por tercera vez.

   Lo que se paga: hay que aplastar el pegado y atajar el Enter, que es lo que
   hace el guion. Barato al lado de medir alturas.
   ============================================================================ */
.textoNota .campoNota {
  padding: 1px 4px; margin: 0; min-width: 0;
  border: 1px solid transparent; border-radius: 3px;
  font: 13.5px/1.35 var(--sans); color: var(--tinta);
  /* Las palabras largas —una URL en una bajada— no pueden ensanchar la ranura. */
  overflow-wrap: anywhere;
}
/* El texto de ayuda cuando está vacío. Un elemento editable no tiene
   `placeholder`, así que se dibuja con el atributo que ya lleva. */
.textoNota .campoNota:empty::before {
  content: attr(data-placeholder);
  color: var(--gris-2); font-weight: 400; text-transform: none; letter-spacing: 0;
}

/* La señal de "esto se puede escribir" es un SUBRAYADO, no una caja.
   Una caja completa alrededor del texto lo convierte en un control de
   formulario a la vista, y entonces enfocar se siente "se transformó en un
   input" en vez de "estoy editando este texto". El subrayado es la convención
   de la edición en el lugar: marca la línea de escritura y deja el texto
   siendo texto. El borde de arriba y los costados quedan transparentes SIEMPRE
   —nunca cambian— así que nada se mueve ni un pixel al pasar el mouse ni al
   enfocar, que es la otra mitad de que se sienta natural. */
.textoNota .campoNota:hover { border-bottom-color: var(--linea); }
.textoNota .campoNota:focus { border-bottom-color: var(--tinta); outline: none; }

.textoNota .volantaNota { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--gris-2); }
.textoNota .tituloNota  { font-weight: 600; }
.textoNota .bajadaNota  { font-size: 12.5px; color: var(--gris); }
.textoNota .autorNota   { font-size: 11.5px; color: var(--gris-2); }

/* --- opciones por módulo ---------------------------------------------------- */
.opciones { display: flex; flex-wrap: wrap; gap: 6px 16px; padding-top: 10px; border-top: 1px solid var(--linea); }

/* --- selector de nota ------------------------------------------------------- */
/* MÁS ANCHO Y MÁS ALTO QUE EL RESTO DE LOS DIÁLOGOS, y no por gusto: acá no se
   confirma nada, se ELIGE mirando. Lo que se decide en esta pantalla es si el
   titular entra de un vistazo y si esa foto sirve para abrir un correo, y eso
   pide fila alta y miniatura grande. Con 560px de ancho y una foto de 66px la
   lista se leía como un menú desplegable, que es la forma de "elegí una opción"
   y no la de "mirá cuál va". */
.selector {
  width: min(720px, 94vw); max-height: min(760px, 84vh); padding: 0;
  border: 1px solid var(--linea); border-radius: 8px; background: var(--papel);
  box-shadow: 0 20px 60px rgba(22,35,58,.25);
}
/* EL `[open]` NO ES DECORACIÓN, es lo único que deja el diálogo cerrado.
   Lo que esconde un `dialog` sin abrir es un `display: none` del navegador, y
   cualquier `display` de autor le gana por ORIGEN y no por especificidad — un
   `.selector { display: flex }` pelado deja el selector a la vista en toda la
   pantalla, sin error y sin nada raro en el inspector. Es la misma trampa del
   atributo `hidden` contra `.btn { display: inline-flex }`.
   Y es columna porque arriba hay dos franjas de alto variable (el buscador y el
   bloque de pegar): con `max-height` fija en la lista, abrir el formulario
   empujaba el final fuera de la caja del diálogo, que recorta. */
.selector[open] { display: flex; flex-direction: column; }
.selector::backdrop { background: rgba(22,35,58,.35); }
/* UNA SOLA BARRA CON TODO LO DE "de dónde saco una nota": buscar, recortar por
   fuente y traer una de una dirección. `flex: none` porque lo que se achica
   cuando no entra todo es la lista, que scrollea, y nunca los controles. */
.cabSelector {
  display: flex; flex: none; align-items: center; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--linea);
}
/* El buscador se lleva el ancho sobrante (`.crece` en el markup); los demás
   ocupan lo suyo y no se dejan aplastar — un `<select>` flex se encoge hasta
   quedar ilegible. */
.cabSelector select { flex: none; max-width: 190px; }
.cabSelector .btn { flex: none; }
/* La ✕ es el botón de envío del form con method=dialog, así que cierra el
   diálogo sin una línea de guion. Se dibuja como ícono y no como "Cerrar": la
   palabra pesaba igual que el botón de agregar, y de las dos la que importa es
   la otra.
   El «+» de al lado NO se define acá: lo comparte con la barra de filtros de
   Notas, así que vive en `componentes.css` (`.masPegar`). */
/* `.btn.chico.cerrarX` y no `.cerrarX`: `.btn.chico` pesa DOS clases, así que
   con una sola el `padding: 0` no se aplicaba nunca. Cuadrado de 30 para que
   mida lo mismo que el «+» que tiene al lado — son los dos botones de ícono de
   esta barra y verlos de distinto alto es lo primero que se nota. */
.btn.chico.cerrarX {
  width: 30px; height: 30px; padding: 0; justify-content: center; flex: none;
}

/* El panel de pegar. Plegado no ocupa NADA —lo esconde `hidden`— y abierto es
   una franja más entre la barra y la lista, que scrollea abajo. Es franja y no
   capa flotante como la de Notas: adentro de un `dialog`, lo que se sale de la
   caja queda recortado. */
.pegarSelector { flex: none; padding: 12px 14px; border-bottom: 1px solid var(--linea); background: var(--fondo); }
.pegarSelector textarea { width: 100%; font: 13px/1.5 var(--mono); resize: vertical; }
.pegarSelector .fila { align-items: center; gap: 10px; margin-top: 8px; }
.pegarSelector .ayuda { margin: 0; }
#pegadoSelector { margin-top: 10px; }
#pegadoSelector p { font: 12.5px/1.45 var(--sans); margin: 0 0 5px; }
#pegadoSelector p:last-child { margin-bottom: 0; }
#pegadoSelector p.bien { color: var(--listo); }
#pegadoSelector p.mal { color: var(--alerta); }

/* La que scrollea es la lista, y se lleva el alto que sobre. `min-height: 0` es
   obligatorio: un hijo flex no baja de su contenido sin eso, y la lista de 60
   notas empujaría el diálogo a crecer en vez de scrollear. El `min-height` en
   píxeles es lo otro: sin él, filtrar hasta dejar dos notas encoge el diálogo y
   el buscador se le mueve a alguien que está escribiendo en él. */
.listaSelector { flex: 1 1 auto; min-height: min(240px, 34vh); overflow-y: auto; }
/* Un botón que se ve como un enlace: lo que hace es abrir un panel de esta misma
   pantalla, así que no puede ser un `<a>` —un enlace promete llevar a otro
   lado—, y al lado de uno de verdad tiene que leerse igual. */
.listaSelector .comoEnlace {
  font: inherit; color: inherit; background: none; border: 0; padding: 0;
  text-decoration: underline; cursor: pointer;
}
.listaSelector .nota {
  display: flex; gap: 13px; width: 100%; padding: 12px 14px; text-align: left;
  background: none; border: 0; border-bottom: 1px solid var(--linea); cursor: pointer;
}
.listaSelector .nota:hover { background: #fff; }
.listaSelector .nota h3 { font: 600 15px/1.35 var(--sans); margin: 0 0 3px; }
.listaSelector .nota .meta { font: 12px/1.4 var(--mono); color: var(--gris-2); }
/* La foto, del tamaño en que se puede juzgar. Es la mitad de la decisión que se
   toma acá y a 66px sólo servía para reconocer una nota ya leída. */
.listaSelector .miniatura { width: 96px; height: 64px; object-fit: cover; border-radius: 3px; background: var(--fondo); flex: none; }


/* --- el diálogo de programar ---------------------------------------------- */
/* Hereda todo de `.dialogo`; acá va sólo lo suyo. Antes esto era un campo de
   fecha metido en la barra de cierre y quedaba apretado: la barra ya tiene el
   correo de prueba y dos botones. */
.dlgProgramar { max-width: 420px; }
.dlgProgramar .ayuda { margin: 0 0 14px; }
.dlgProgramar .atajos { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.dlgProgramar .cuando { display: grid; grid-template-columns: 1fr auto; gap: 10px; margin-bottom: 14px; }
.dlgProgramar .cuando label { display: block; font: 600 12.5px/1.3 var(--sans); margin-bottom: 4px; }
.dlgProgramar .cuando input { width: 100%; }
.dlgProgramar .acciones { gap: 8px; margin-top: 4px; }

/* === audiencia.css ===================================================== */
/* ============================================================================
   AUDIENCIA — suscriptores, sus listas y la ficha de una persona.

   Esta pantalla venía escrita con `style=` inline, que la regla del proyecto
   prohíbe y que CLAUDE.md ya tenía anotado como deuda ("suscriptores todavía
   está por debajo de esa vara"). Todo lo visual de acá vive en clases con
   nombre, que es lo que permite que la próxima pantalla las reuse en vez de
   volver a inventar los mismos 8px.
   ============================================================================ */

/* Las solapas de esta pantalla NO se estilan acá: `.solapas` vive en
   componentes.css desde que Ajustes también las usa. Nacieron en esta hoja, y
   dejarlas acá habría sido pedirle a otra pantalla que dependiera del archivo de
   audiencia — que es cómo empiezan las hojas donde nadie sabe qué puede tocar.

   Las cuatro cifras de arriba NO se estilan acá: `.cifras` y `.cifra` ya existen
   en componentes.css y hacen exactamente esto. Redefinirlas sería el error que
   ya nos mordió dos veces —una clase con nombre común pisando el diseño de otra
   pantalla— y encima al revés: pisándolo yo. Se usa el marcado que ya espera esa
   hoja: .cifras > .cifra > b + .eti

   La barra de buscar y filtrar tampoco: es .filtro de componentes.css, un
   solo componente para todas las del panel. Acá había una copia con otro alto,
   que era justamente el bug — dos barras midiendo distinto para hacer lo mismo. */
.filtro { margin-bottom: 14px; }

/* ============================================================================
   EL BUSCADOR

   Creció por acumulación —texto, estado, lista, condiciones, ayuda, botones,
   guardar, guardados— y quedó todo al mismo nivel visual, sin nada que dijera
   que es UNA cosa: «quedan todo como colgado».

   Ahora es una tarjeta con partes separadas por una línea, en el orden en que se
   piensa: a quién se busca, qué datos tiene que cumplir, y qué se hace con eso.
   ============================================================================ */
.buscador { margin-bottom: 14px; }

/* Las guardadas van ARRIBA de todo: recuperar una búsqueda es la alternativa a
   armarla, no algo que se hace después. */
.buscadorGuardados {
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--linea);
}
.buscadorGuardados .eti { font-size: 11px; margin-right: 2px; }

.buscadorFila { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.buscadorFila .campo { margin-bottom: 0; }
.buscadorFila .texto { flex: 1 1 220px; min-width: 170px; max-width: 420px; }
.buscadorFila .texto > input { width: 100%; }

/* Cada parte, con su línea y su título. El título es una etiqueta y no un h3:
   nombra una zona de un formulario, no una sección de la página. */
.buscadorParte {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--linea);
}
.buscadorTitulo {
  display: block; margin-bottom: 8px;
  font: 600 12px/1.4 var(--sans); color: var(--gris);
}

/* Las condiciones: cada una en su renglón, y los dos desplegables de una
   condición pegados entre sí. Van en un envoltorio propio porque son PARES —el
   dato y su valor se leen juntos—, y sueltas en un flex que envuelve el valor de
   una termina al lado del dato de la siguiente. */
.condiciones { display: flex; flex-direction: column; gap: 8px; }
.condicion { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; }
.condicion .campo { margin-bottom: 0; }
/* El conector va alineado con los desplegables y NO con sus etiquetas: es una
   palabra que une dos controles, no el nombre de uno. Puesto arriba se leía como
   la etiqueta de un campo y la primera pregunta era cómo se elegía. */
.condicion .conector {
  font: 13px/1 var(--sans); color: var(--gris-2); padding-bottom: 9px;
  min-width: 60px; text-align: right;
}

.buscadorAcciones {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--linea);
}
/* La cuenta al otro extremo: es el resultado de lo que se acaba de armar, y
   mirarla es cómo se comprueba un segmento antes de guardarlo. */
.buscadorAcciones .buscadorCuenta { margin-left: auto; }

/* Guardar va al final de la tarjeta, después de la línea de acciones: es lo que
   se hace con la búsqueda que se acaba de comprobar. */
.buscadorGuardar {
  display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--linea);
}
.buscadorGuardar .campo { margin-bottom: 0; }
.buscadorGuardar .texto { flex: 1 1 240px; max-width: 380px; }
.buscadorGuardar .texto > input { width: 100%; }
/* La ayuda ocupa el renglón entero: al costado del botón lo empujaba y se leía
   como parte del control. */
.buscadorGuardar .anchoTotal { flex: 1 0 100%; margin: 6px 0 0; }

/* --- la tabla de suscriptores ----------------------------------------------- */
.tablaAudiencia td { vertical-align: top; }
.tablaAudiencia .quien { min-width: 0; }
.tablaAudiencia .listasDe { color: var(--gris-2); font-size: 12px; }
/* Los atributos, en mono y más apagados que las listas: son datos crudos que
   llegaron de un CSV o de un conector, no algo que alguien eligió. La jerarquía
   dice eso — la lista es a qué se suscribió, el atributo es lo que sabemos. */
.tablaAudiencia .atributosDe {
  color: var(--gris-2); font: 11.5px/1.5 var(--mono); margin-top: 2px;
}

/* El punto de color del estado. Reusa `.punto` de componentes y sólo agrega los
   colores que esta pantalla necesita nombrar. */
.punto.activo { background: var(--listo); }
.punto.pendiente { background: #c99a2e; }
.punto.fuera { background: var(--gris-2); }
.punto.problema { background: var(--alerta); }

/* --- paginado --------------------------------------------------------------- */
.paginado { display: flex; align-items: center; gap: 10px; justify-content: flex-end; margin-top: 14px; }
.paginado .dato { color: var(--gris-2); }

/* --- la ficha de una persona ------------------------------------------------
   Dos columnas: a la izquierda lo que se edita, a la derecha lo que se lee. Se
   apila en una sola columna cuando no entra. */
.ficha { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 340px); gap: 18px; align-items: start; }
@media (max-width: 900px) { .ficha { grid-template-columns: 1fr; } }

.fichaCabecera { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.fichaCabecera h1 { margin: 0; }

/* Los datos que sólo se leen: consentimiento, origen, fechas. Dos columnas de
   etiqueta y valor, que es más compacto y más legible que una tabla. */
.datos { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 14px; }
.datos dt { color: var(--gris-2); font-size: 12px; text-transform: uppercase; letter-spacing: .05em; }
.datos dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

/* Las listas como casillas, no como un multi-select: un `<select multiple>` es
   el control que nadie sabe usar sin instrucciones. */
.casillas { display: grid; gap: 8px; }
/* `.aclaracion` y no `.nota`: esa clase ya es la tarjeta de una nota de prensa
   en componentes.css, con su display:flex y su padding, y le rompería la caja
   a esto. Antes de nombrar una clase, grep en assets/css/. */
.casilla .aclaracion { color: var(--gris-2); font-size: 12px; }

/* El historial de eventos de una persona vive en su propia solapa y a todo el
   ancho: era una lista en la columna de 340px, y alcanzaba mientras un evento
   fuera "entregado · Diaria". Con los clics pasó a llevar la URL de destino
   adentro —que es EL dato, porque sin ella "hizo clic" no dice en qué— y ahí ya
   no entraba nada.

   Una URL no tiene espacios, así que sin esto estira la columna y desarma la
   tabla entera. `anywhere` y no `break-word`: parte también donde no hay ningún
   punto de corte natural, que es justo el caso de una URL larga. */
.quiebraUrl { overflow-wrap: anywhere; }

/* La zona de acciones que no se deshacen, al final y separada del resto para
   que nadie la toque de paso. */
.zonaCuidado { border-top: 1px solid var(--linea); margin-top: 16px; padding-top: 14px; }
.zonaCuidado h3 { margin: 0 0 4px; font-size: 14px; }
.zonaCuidado p { margin: 0 0 10px; color: var(--gris); font-size: 13px; }
.zonaCuidado form { margin-bottom: 10px; }
.zonaCuidado form:last-child { margin-bottom: 0; }

/* --- listas ----------------------------------------------------------------- */
.tablaListas .porDefecto {
  display: inline-block; margin-left: 8px; padding: 1px 7px;
  border: 1px solid var(--linea); border-radius: 10px;
  font: 11px/1.6 var(--sans); color: var(--gris);
}
.tablaListas tr.archivada .nombrePropio { color: var(--gris-2); }

/* El detalle de lo que no entró en un import.
   Va plegado: el número es lo que hay que leer siempre y las 300 líneas sólo
   cuando alguien las va a corregir. Y con alto máximo, porque un archivo malo
   puede traer miles y empujar el listado fuera de la pantalla. */
.importDetalle summary { font-size: 13px; color: var(--gris); cursor: pointer; margin-top: 4px; }
/* El scroll va en el ENVOLTORIO. Puesto sobre la tabla, el `display:block` que
   hace falta para que el `max-height` funcione desarma el modelo de tabla y las
   columnas colapsan contra su contenido — «LÍNEADECÍAPOR QUÉ» todo pegado. Sólo
   se ve mirándolo. */
.importFilas { margin-top: 10px; max-height: 340px; overflow-y: auto; }
.importFilas .tabla { width: 100%; margin: 0; }
.importDetalle .ayuda { margin-top: 8px; }

/* --- segmentos --------------------------------------------------------------- */
/* El nombre de un segmento ES su campo de renombrar: mostrarlo además como
   texto ponía el mismo nombre dos veces en la misma fila.
   El botón se mantiene apagado hasta que la fila tiene el foco — está para
   cuando hace falta y no compite con el nombre, que es lo que se viene a leer.
   Es `visibility` y no `display`: reservando el lugar, la columna no cambia de
   ancho al entrar al campo. */
.renombrar { display: flex; gap: 6px; align-items: center; margin: 0; }
.renombrar input { width: 220px; }
.renombrar .btn { visibility: hidden; }
.renombrar:hover .btn, .renombrar:focus-within .btn { visibility: visible; }

/* La llave del boton que prende y apaga un formulario. Va en el BOTON y no en
   la columna de estado: ahi el punto ya dice como esta, y lo que faltaba era ver
   que va a pasar si lo tocas. Hereda el color del boton por currentColor, asi
   que no abre ninguna paleta nueva. */
.btn.conLlave { display: inline-flex; align-items: center; gap: 7px; }
.llave { flex: none; display: block; }

/* === equipo.css ======================================================== */
/* QUIÉNES ENTRAN — la cuarta solapa de Ajustes.
   ==========================================================================
   Una tarjeta por persona y, adentro, una columna por cabecera. La forma es el
   argumento: el acceso es POR CABECERA y no por cliente (docs/08), y una lista
   de personas con un rol al lado diría lo contrario sin decirlo.

   Las clases van con prefijo `equipo`. Es la cuarta vez que una clase de nombre
   común le pisa el diseño a otra pantalla (`.opciones`, `.paleta`,
   `.barraFiltro`, `.problema`), y el prefijo es lo único que lo cierra. */

.equipoQuien { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; }
.equipoQuien b { font-size: 15px; }
.equipoQuien .dato { margin-top: 2px; }
.equipoQuien form { flex: none; }

/* `auto-fit` y no un número de columnas: un cliente puede tener una cabecera o
   diez, y con `minmax` las de una sola no quedan estiradas de punta a punta. */
.equipoAccesos {
  display: grid; gap: 10px 14px; margin-top: 12px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  align-items: end;
}
.equipoAccesos .campo { margin: 0; }
.equipoAccesos button { grid-column: 1 / -1; justify-self: start; }

/* Un select en gris pálido se lee como "roto". Apagado es apagado, y al lado va
   escrito por qué (nadie se edita a sí mismo). */
.equipoAccesos select:disabled { opacity: .6; cursor: not-allowed; }

/* === administracion.css ================================================ */
/* ============================================================================
   ADMINISTRACIÓN — lo que ve un root (docs/19).

   Es otro trabajo que operar un envío: acá se mira una cartera de clientes, no
   una campaña. La composición lo acompaña —cifras arriba, la cartera abajo—
   pero la paleta y las piezas son las mismas: es el mismo producto.
   ============================================================================ */

/* --- cupos: el tope contra lo usado ----------------------------------------- */
.cupos { display: grid; grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); gap: 16px 24px; }
.cupo .cab { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.cupo .cab .n { font: 13px/1.4 var(--mono); font-variant-numeric: tabular-nums; color: var(--gris); }
.cupo .ayuda { margin-top: 5px; }
.cupo.lleno .cab .n { color: var(--alerta); }
.cupo.lleno .barra i { background: var(--alerta); }
/* Un tope que hoy no lo frena ninguna pantalla se dice, no se disimula. */
.cupo.flojo .barra i { background: var(--gris-2); }

/* --- la tabla de planes del alta --------------------------------------------
   Un plan por FILA, un tope por columna: cada fila es una de las opciones del
   selector, y elegir es leer una línea de punta a punta. Estuvo traspuesta
   mientras vivía en una columna de apoyo de 322px —donde no entraban seis
   números por línea— y quedaba apretadísima; a ancho completo la orientación
   natural es ésta.

   Va con scroll horizontal propio por si la ventana es angosta: siete columnas
   no entran en un teléfono, y lo que no puede pasar es que la página entera se
   desplace de costado. */
.tablaPlanes { margin: 4px 0 10px; overflow-x: auto; }
.tablaPlanes table { min-width: 620px; }
.tablaPlanes th.n, .tablaPlanes td.n { text-align: right; padding-left: 14px; }
.tablaPlanes td { padding: 9px 0; }
.tablaPlanes td.n { font: 13px/1.4 var(--mono); font-variant-numeric: tabular-nums; color: var(--gris); }
.tablaPlanes td.plan { font-weight: 600; }

/* La fila del plan elegido AHORA, sin una línea de JavaScript. `:has()` lee la
   opción seleccionada del `select` de arriba y sigue el cambio en vivo; hacerlo
   desde el servidor dejaría marcada la fila del plan anterior hasta la próxima
   recarga, que es peor que no marcar nada.

   Una regla por plan: agregar un plan a `PLANES` sin agregar su regla acá no
   rompe nada — la fila simplemente no se resalta. */
.elPlan:has(select[name=plan] option[value=piloto]:checked) .tablaPlanes tr.fila-piloto td,
.elPlan:has(select[name=plan] option[value=base]:checked)   .tablaPlanes tr.fila-base td,
.elPlan:has(select[name=plan] option[value=medio]:checked)  .tablaPlanes tr.fila-medio td,
.elPlan:has(select[name=plan] option[value=amplio]:checked) .tablaPlanes tr.fila-amplio td {
  background: var(--fondo); color: var(--tinta);
}
/* Un trazo al principio de la fila elegida. Es el mismo recurso que marca la
   sección activa en el menú lateral: un borde, no un color de fondo distinto. */
.elPlan:has(select[name=plan] option[value=piloto]:checked) .tablaPlanes tr.fila-piloto td.plan,
.elPlan:has(select[name=plan] option[value=base]:checked)   .tablaPlanes tr.fila-base td.plan,
.elPlan:has(select[name=plan] option[value=medio]:checked)  .tablaPlanes tr.fila-medio td.plan,
.elPlan:has(select[name=plan] option[value=amplio]:checked) .tablaPlanes tr.fila-amplio td.plan {
  box-shadow: inset 2px 0 0 var(--tinta);
  padding-left: 9px;
}

/* --- los seis números, sólo cuando se piden ---------------------------------
   Elegir un plan es una decisión de una línea; los topes uno por uno son la
   excepción. Mostrarlos siempre convierte esa línea en un formulario de siete
   campos que casi nadie toca.

   Aparecen con `personalizado` y sin una línea de JavaScript: `:has()` lee la
   opción seleccionada del `select` y responde al cambio en vivo. Los campos
   siguen en el DOM mientras están ocultos —el navegador los manda igual— y por
   eso `leerFormularioPlan()` los IGNORA salvo con `personalizado`. */
.elPlan .topesAMedida { display: none; }
.elPlan:has(select[name=plan] option[value=personalizado]:checked) .topesAMedida {
  display: block;
  margin-top: 6px;
}

/* --- la clave inicial -------------------------------------------------------
   Se muestra una sola vez y hay que poder copiarla sin equivocarse: grande, en
   monoespaciada y seleccionable de un doble clic. */
.clave {
  font: 400 22px/1.3 var(--mono); letter-spacing: .04em;
  margin: 6px 0 10px; user-select: all;
}

/* === salud.css ========================================================= */
/* La pantalla de estado del sistema (docs/26). Es del root. */

/* El resumen de arriba: lo primero que se ve es la respuesta. El color del
   borde izquierdo es lo único que hace falta leer desde lejos. */
.resumenSalud { border-left: 4px solid var(--linea); margin-bottom: 18px; }
.resumenSalud.bien { border-left-color: var(--listo); }
.resumenSalud.atencion { border-left-color: #c08a12; }
.resumenSalud.mal { border-left-color: var(--alerta); }
.resumenSalud b { font-size: 16px; }
.resumenSalud p { margin: 6px 0 0; color: var(--gris); }
.resumenSalud ul { margin: 10px 0 0; padding-left: 0; list-style: none; display: grid; gap: 7px; }
.resumenSalud li { display: flex; align-items: baseline; gap: 8px; }
.resumenSalud i { color: var(--gris); font-style: normal; }

/* El punto de color. Va con `flex: none` para que no lo aplaste el texto de al
   lado: es un punto de 8px y una vez ya nos pasó que otra regla lo estirara. */
.puntoSalud {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  flex: none; background: var(--gris-2);
}
.puntoSalud.bien { background: var(--listo); }
.puntoSalud.atencion { background: #c08a12; }
.puntoSalud.mal { background: var(--alerta); }

.grupoSalud { margin-bottom: 16px; }
.grupoSalud h2 {
  font: 600 12.5px/1.3 var(--sans); text-transform: uppercase; letter-spacing: .05em;
  color: var(--gris-2); margin: 0 0 12px;
}

.senalSalud { padding: 11px 0; border-top: 1px solid var(--linea); }
.senalSalud:first-of-type { border-top: 0; padding-top: 0; }
.senalSalud .cab { display: flex; align-items: baseline; gap: 9px; }
.senalSalud .cab b { font-weight: 600; }
/* El dato a la derecha y en monoespaciada: es un valor, no prosa. */
.senalSalud .valor { margin-left: auto; font: 13px/1.4 var(--mono); color: var(--tinta); }
.senalSalud.mal .valor { color: var(--alerta); font-weight: 600; }
.senalSalud.atencion .valor { color: #8a6209; }

/* EL PORQUÉ ES PARTE DEL DATO, no una ayuda escondida en un tooltip. Un número
   sin consecuencia se mira dos veces y después nunca más. */
.senalSalud .porque { margin: 4px 0 0 17px; font-size: 13px; color: var(--gris); max-width: 78ch; }
.senalSalud .hacer {
  margin: 6px 0 0 17px; font: 12.5px/1.5 var(--mono);
  background: var(--fondo); border-radius: 4px; padding: 6px 9px; max-width: 78ch;
}

/* === campo.css ========================================================= */
/* ===========================================================================
   LA ETAPA DE PRUEBAS. ESTE ARCHIVO ES TEMPORAL Y SE BORRA ENTERO.
   Ver `esquema/16-etapa-de-pruebas.sql` para el resto de la limpieza: hay que
   sacar 'campo.css' de ORDEN en `estilos.ts`.
   =========================================================================== */

.pruebasCaja {
  /* El ámbar es LOCAL de esta etapa y por eso vive acá y no en los tokens: un
     color en `base.css` es parte del diseño del producto, y esto se borra. */
  --pruebas-fondo: #fdf3d8;
  --pruebas-tinta: #6b4d09;
  --pruebas-linea: #e6cf95;

  position: fixed; right: 18px; bottom: 18px;
  font: 14px/1.45 var(--sans);

  /* POR DEBAJO DEL AVISO FLOTANTE, que vive en este mismo rincón con z-index 60.
     Los dos no pueden estar al mismo nivel: el aviso dura seis segundos y el
     botón está siempre, así que el que se va tapa al que se queda y no al revés.
     Un botón escondido detrás de un cartel que ya no está es un botón roto.
     Y por encima de la barra de cierre (30), para que ella no lo tape a él. */
  z-index: 55;
}

/* Y CUANDO HAY BARRA DE CIERRE, ARRIBA DE ELLA. El constructor tiene una barra
   fija abajo con el botón de enviar: dejar el flotante en el rincón lo ponía
   justo encima. Se descubrió mirándolo, que es lo único que lo encuentra. */
body:has(.cierre) .pruebasCaja { bottom: calc(var(--alto-cierre) + 16px); }

/* El botón. Se ve que es de una etapa y no una sección del producto: por eso el
   tono ámbar y no el de la marca. Alguien tiene que poder mirar una captura de
   pantalla dentro de seis meses y saber que eso no iba. */
.pruebasCaja > summary {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 13px; border-radius: 999px; cursor: pointer;
  background: var(--pruebas-fondo); color: var(--pruebas-tinta);
  border: 1px solid var(--pruebas-linea);
  box-shadow: 0 6px 18px rgb(0 0 0 / 14%);
  font-weight: 600; list-style: none; user-select: none;
}
.pruebasCaja > summary::-webkit-details-marker { display: none; }
.pruebasCaja > summary:hover { filter: brightness(0.97); }
/* El anillo va por dentro: con `outline` y offset negativo no se ve sobre un
   fondo lleno, que ya mordió en el diálogo. */
.pruebasCaja > summary:focus-visible { outline: 0; box-shadow: inset 0 0 0 2px var(--tinta); }

.pruebasPunto {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 999px; font: 600 11px/1 var(--mono);
  background: var(--alerta); color: #fff; font-style: normal;
}

/* CERRADO ES CERRADO, Y ESTO NO SOBRA.
   Un <details> cerrado esconde a sus hijos con una regla del NAVEGADOR, y una
   regla de autor le gana por origen: `.pruebasForm { display: grid }` alcanza para
   que el formulario quede a la vista con el panel cerrado, según el navegador.
   Es la misma trampa que ya mordió con `[hidden]` y un `display` de la hoja
   —anotada en CLAUDE.md—, un nivel más abajo. Se cierra de una vez acá. */
.pruebasCaja:not([open]) .pruebasPanel { display: none !important; }

.pruebasPanel {
  position: absolute; right: 0; bottom: calc(100% + 10px); width: 340px;
  max-height: 70vh; overflow-y: auto;
  background: #fff; border: 1px solid var(--linea); border-radius: 8px;
  box-shadow: 0 14px 40px rgb(0 0 0 / 18%);
}
/* Las dos solapas. Los radios no se ven: lo que se ve son sus etiquetas. */
.pruebasSolapas { display: flex; border-bottom: 1px solid var(--linea); }
.pruebasSolapas input { position: absolute; opacity: 0; pointer-events: none; }
.pruebasSolapas label {
  flex: 1; text-align: center; padding: 11px 8px; cursor: pointer;
  font: 600 13px/1.3 var(--sans); color: var(--gris-2);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.pruebasSolapas label:hover { color: var(--tinta); }
.pruebasSolapas input:checked + label { color: var(--tinta); border-bottom-color: var(--tinta); }
/* El anillo de foco va en la etiqueta, porque el radio es invisible: sin esto la
   solapa no se puede recorrer con el teclado a la vista. */
.pruebasSolapas input:focus-visible + label { box-shadow: inset 0 0 0 2px var(--tinta); border-radius: 4px; }
.pruebasSolapas i { font-style: normal; font-family: var(--mono); font-size: 11.5px; margin-left: 5px; position: relative; }
/* El punto de "hay algo sin leer", al lado del numero. */
.pruebasSinVer {
  position: absolute; top: -2px; right: -7px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--alerta);
}

/* QUE SOLAPA SE VE. Con :has(), sin una linea de guion.
   Escrito como "todo escondido y se muestra la elegida", y no como una lista de
   "escondé esto cuando esta otra este marcada": con dos solapas las dos formas
   se ven iguales, con tres la segunda son seis reglas y la que falte deja dos
   paneles a la vez. */
.pruebasCab, .pruebasHecho, .pruebasForm, .pruebasNov, .pruebasMios { display: none; }
.pruebasPanel:has(#pvReportar:checked) .pruebasCab,
.pruebasPanel:has(#pvReportar:checked) .pruebasHecho { display: block; }
.pruebasPanel:has(#pvReportar:checked) .pruebasForm { display: grid; }
.pruebasPanel:has(#pvNovedades:checked) .pruebasNov { display: block; }
.pruebasPanel:has(#pvMios:checked) .pruebasMios { display: block; }

.pruebasCab { padding: 14px 15px 0; }
.pruebasCab p { margin: 4px 0 0; font-size: 13px; color: var(--gris-2); }

/* "Listo, lo anotamos". Ocupa el lugar de la cabecera del flotante, que en ese
   momento no tiene nada nuevo que decir. Va con el borde de `--listo` y no en
   verde de fondo: el verde de la marca es exclusivo del envío (base.css). */
.pruebasHecho { margin: 14px 15px 0; padding: 10px 13px; border-left: 3px solid var(--listo); background: var(--papel); border-radius: 0 5px 5px 0; }
.pruebasHecho b { color: var(--listo); }
.pruebasHecho p { margin: 3px 0 0; font-size: 13px; color: var(--gris-2); }

/* SIN `display` ACÁ. La solapa que se ve la deciden las reglas de arriba, y el
   `display: grid` que estaba en esta línea las pisaba: pesa lo mismo (una clase)
   y está más abajo, así que ganaba por ORDEN. El efecto era que el formulario de
   reportar se quedaba a la vista debajo de «Lo tuyo», los dos paneles juntos. Se
   vio mirándolo; ninguna regla estaba mal escrita por separado. */
.pruebasForm { gap: 4px; padding: 12px 15px 14px; }
.pruebasForm label { font: 600 12.5px/1.3 var(--sans); margin-top: 6px; }
.pruebasForm textarea { width: 100%; font: 14px/1.45 var(--sans); resize: vertical; }
.pruebasForm button { margin-top: 9px; justify-self: start; }
.pruebasOpc { font-weight: 400; color: var(--gris-2); }

/* Las tres puertas. Cada una con su explicación al lado: sin eso, "Duda" y
   "Problema" se parecen lo suficiente como para que la gente elija cualquiera. */
.pruebasTipos { border: 0; margin: 4px 0 2px; padding: 0; display: grid; gap: 2px; }
.pruebasTipos legend { font: 600 12.5px/1.3 var(--sans); padding: 0; margin-bottom: 5px; }
.pruebasTipos label {
  display: flex; gap: 8px; align-items: baseline;
  padding: 6px 8px; border-radius: 5px; cursor: pointer; font-weight: 400;
}
.pruebasTipos label:hover { background: var(--fondo); }
/* La elegida se marca con el fondo de la etapa: se ve cuál es sin leer. */
.pruebasTipos label:has(input:checked) { background: var(--pruebas-fondo); }
.pruebasTipos input { margin: 0; flex: none; }
.pruebasTipos span { font-size: 13px; color: var(--gris); }
.pruebasTipos b { color: var(--tinta); font-weight: 600; }

.pruebasNov { padding: 8px 15px 12px; }
.pruebasNov article { padding: 8px 0; border-bottom: 1px solid var(--linea); }
.pruebasNov article:last-child { border-bottom: 0; }
.pruebasNov h4 { font: 600 14px/1.35 var(--sans); margin: 0; }
.pruebasNov time { font: 11.5px/1.4 var(--mono); color: var(--gris-2); }
/* Los saltos de línea de una novedad se ven, igual que los de la respuesta y los
   del reporte. Faltaba justo acá: se arregló en la respuesta y esta quedó, y se
   notó la primera vez que una novedad trajo un ejemplo en varias líneas — quedó
   un párrafo corrido donde había una lista, que es peor que no poner el ejemplo.
   Quien la escribe la redacta en un textarea, donde SÍ los ve. */
.pruebasNov p { margin: 3px 0 0; font-size: 13.5px; white-space: pre-wrap; }
.pruebasVacio { color: var(--gris-2); font-size: 13px; }

/* LO TUYO: lo que reportó esta persona y qué le contestamos.
   El reporte propio va en gris y la respuesta destacada, al revés de lo que
   pediría la cronología: lo que se viene a leer acá es la respuesta — el reporte
   ya lo escribió quien está mirando. */
.pruebasMios { padding: 8px 15px 12px; max-height: 340px; overflow-y: auto; }
.pruebasMios article { padding: 9px 0; border-bottom: 1px solid var(--linea); }
.pruebasMios article:last-child { border-bottom: 0; }
.pruebasMioCab { display: flex; align-items: center; gap: 6px; }
.pruebasMioCab time { font: 11.5px/1.4 var(--mono); color: var(--gris-2); margin-left: auto; }
/* TODO LO QUE SE ESCRIBE EN UN TEXTAREA SE MUESTRA CON `pre-wrap`, y ésta es la
   tercera del mismo grupo: el reporte de la pantalla del root ya lo tenía, la
   respuesta se arregló al ir a contestar algo con pasos, la novedad al publicar
   un ejemplo en varias líneas, y ésta —el reporte propio en «Lo tuyo»— estaba
   por caer igual. La regla es del grupo entero y no de cada caso: si el que
   escribe ve los saltos y el que lee no, alguna vez va a mandar una lista y va
   a llegar un párrafo. */
.pruebasMioTexto { margin: 5px 0 0; font-size: 13px; color: var(--gris); white-space: pre-wrap; }
.pruebasRespuesta {
  margin-top: 7px; padding: 8px 11px; border-left: 3px solid var(--listo);
  background: var(--papel); border-radius: 0 5px 5px 0;
}
.pruebasRespuesta b { font: 600 12px/1.3 var(--sans); color: var(--listo); }
/* Los saltos de línea de la respuesta se ven, igual que los del reporte.
   Sin esto, quien escribe la contesta en un textarea —donde SÍ los ve— y a
   quien preguntó le llega un párrafo corrido: una respuesta con pasos se
   convierte en una masa de texto justo cuando lo que hacía falta era la lista.
   La asimetría es lo que la hacía invisible desde el lado del root. */
.pruebasRespuesta p { margin: 3px 0 0; font-size: 13.5px; white-space: pre-wrap; }
.pruebasSinRespuesta { margin: 6px 0 0; font: 12px/1.4 var(--mono); color: var(--gris-2); }

.pruebasPie {
  margin: 0; padding: 9px 15px; border-top: 1px solid var(--linea);
  font: 11.5px/1.4 var(--mono); color: var(--gris-2); background: var(--fondo);
  border-radius: 0 0 8px 8px;
}

/* En un teléfono el panel toma el ancho: 340px fijos se salen de la pantalla. */
@media (max-width: 480px) {
  .pruebasCaja { right: 10px; bottom: 10px; left: 10px; }
  .pruebasPanel { width: auto; left: 0; right: 0; }
}
/* Angosto, la barra de cierre se parte en varias filas y crece bastante. El
   número es generoso a propósito: de más sobra aire, de menos tapa el botón de
   enviar, que es el que no se puede tapar. */
@media (max-width: 720px) {
  body:has(.cierre) .pruebasCaja { bottom: 180px; }
}

/* --- la pantalla del root ------------------------------------------------- */
.pruebasReporte { margin-bottom: 12px; }
.pruebasReporteTexto { margin: 10px 0 0; white-space: pre-wrap; }
.pruebasReporteEsperaba { margin: 6px 0 0; color: var(--gris); white-space: pre-wrap; }
.pruebasReporteUrl, .pruebasReporteAgente { margin: 8px 0 0; word-break: break-all; }
.pruebasReporte .fila { margin-top: 10px; gap: 6px; }
.pruebasPastilla {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font: 600 11.5px/1.6 var(--mono); background: var(--fondo); border: 1px solid var(--linea);
}
.pruebasPastilla.e1 { background: #fdf3d8; border-color: #e6cf95; color: #6b4d09; }
.pruebasPastilla.e3 { background: #e8f3ea; border-color: #bcdcc3; color: #2c6135; }
/* «Para después» tiene su color y no el verde de resuelto: gris y no verde
   porque no se hizo nada todavía, y con nombre propio porque tampoco está
   pendiente. Confundirlo con resuelto es exactamente lo que este estado vino a
   evitar. */
.pruebasPastilla.e4 { background: #eef0f3; border-color: #ccd2da; color: #46505e; }
/* Los tres tipos, cada uno con su color: en una lista larga, la clase de cosa
   se ve antes de leer. Un problema pesa y se ve que pesa. */
.pruebasPastilla.t1 { background: #fbe9e5; border-color: #eec4b9; color: #8c2c17; }
.pruebasPastilla.t2 { background: #e9eefb; border-color: #c2cef0; color: #23407f; }
.pruebasPastilla.t3 { background: #f1ecf9; border-color: #d3c7ea; color: #4a3277; }
a.pruebasPastilla { text-decoration: none; }
a.pruebasPastilla:hover { filter: brightness(0.97); }
.pruebasPastilla.elegida { box-shadow: inset 0 0 0 1.5px currentColor; }
.pruebasPastilla.contestado { background: #e8f3ea; border-color: #bcdcc3; color: #2c6135; }
.pruebasPorTipo { gap: 6px; margin: 0 0 16px; align-items: center; }

/* La barra de la tanda. Pegada arriba de la lista y no flotando: lo que decide
   qué se va a cambiar son las casillas de abajo, y una barra que viaja mientras
   se scrollea invita a apretarla sin ver cuáles quedaron marcadas. */
.pruebasTanda { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.pruebasTanda .dato { margin-right: 2px; }
/* Cuántos hay elegidos, al lado del botón que los va a cambiar. Lo escribe el
   guion en un `data-`; sin JavaScript no aparece y no falta nada. */
.pruebasTandaTodos { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.pruebasTandaTodos::before {
  content: attr(data-cuantos);
  font: 12px/1.4 var(--mono); color: var(--gris-2);
}

/* Responder. Plegado por defecto: con veintidós reportes en pantalla, veintidós
   cajas de texto abiertas no dejan leer ninguno. */
.pruebasResponder { margin-top: 12px; border-top: 1px solid var(--linea); padding-top: 10px; }
.pruebasResponder > summary {
  font: 600 12.5px/1.3 var(--sans); cursor: pointer; color: var(--gris);
  list-style: none; display: inline-flex; align-items: center; gap: 5px;
}
.pruebasResponder > summary::-webkit-details-marker { display: none; }
.pruebasResponder > summary::marker { content: ''; }
/* El triangulito lo dibujamos nosotros: el del navegador no se puede alinear y
   se ve distinto en cada uno. */
.pruebasResponder > summary::before { content: '▸'; font-size: 13px; line-height: 1; color: var(--gris-2); }
.pruebasResponder[open] > summary::before { content: '▾'; }
.pruebasResponder > summary:hover { color: var(--tinta); }
.pruebasRespondio { margin: 8px 0 0; }
.pruebasResponder textarea { width: 100%; margin-top: 8px; font: 14px/1.45 var(--sans); resize: vertical; }
.pruebasNovedades { margin-top: 16px; border-top: 1px solid var(--linea); padding-top: 12px; display: grid; gap: 8px; }
