/* ============================================================
   BRANDTROPIC SYSTEM — controles

   Botones, campos, tablas, badges, avisos y tarjetas, en clave oscura.
   Las clases .crm-* y .bjs-* conviven mientras se migran las pantallas;
   se estilan juntas para que ninguna se quede atrás.

   Reglas de contraste que se respetan aquí:
   · botón de acción = degradado del logo + texto casi negro (≥ 8:1)
   · texto blanco sobre verde: prohibido
   · sobre oscuro, el acento de texto es --bt-accent (#bcd94b, ≥ 10:1)
   · el borde de un campo se distingue del fondo (--bt-line-field)
   ============================================================ */

/* ---------- Panel ---------- */
.bjs-panel {
  padding: clamp(1.125rem, 2.2vw, 1.5rem);
  border-radius: var(--r-lg);
  border: 1px solid var(--bt-line);
  background: var(--bt-s1);
  box-shadow: var(--sh-panel);
}

/* Título de panel. Es un encabezado de verdad (h2) aunque se vea pequeño:
   quien navega por encabezados necesita saltar de panel en panel. */
.bjs-panel-label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--bt-tx-3);
}

.bjs-panel-label .bjs-count {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--bt-tx-2);
}

/* Rejilla de paneles: se parten en dos cuando hay sitio, nunca antes. */
.bjs-grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
}

.bjs-stack { display: grid; gap: var(--sp-4); }

/* Un hijo de rejilla mide, por defecto, lo que mide su contenido: sin esto
   una tabla ancha estira el panel y saca la barra de scroll a la página
   entera en vez de quedarse dentro de .bjs-scroll-x. */
.bjs-stack > *, .bjs-grid > * { min-width: 0; }

/* Separación vertical entre bloques sueltos, en vez de style="margin-top". */
.bjs-mt-2 { margin-top: var(--sp-2); }
.bjs-mt-3 { margin-top: var(--sp-3); }
.bjs-mt-4 { margin-top: var(--sp-4); }
.bjs-mt-5 { margin-top: var(--sp-5); }

.crm-muted { color: var(--bt-tx-2); font-size: var(--fs-sm); }

/* Sólo para lectores de pantalla: encabezados de columna sin texto visible
   y etiquetas de <select> que la columna ya explica. */
.bjs-sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.bjs-lead { color: var(--bt-tx-2); max-width: 62ch; }

/* ---------- Avisos ---------- */
.crm-flash {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-5);
  border: 1px solid var(--bt-line);
  border-left-width: 3px;
  border-radius: var(--r-md);
  background: var(--bt-s2);
  font-size: var(--fs-sm);
  color: var(--bt-tx-1);
}

.crm-flash .bjs-icon { flex: none; margin-top: 2px; }

.crm-flash.success { border-left-color: var(--bt-ok); }
.crm-flash.success .bjs-icon { color: var(--bt-ok); }

.crm-flash.error { border-left-color: var(--bt-danger); background: var(--bt-danger-soft); }
.crm-flash.error .bjs-icon { color: var(--bt-danger); }

/* ---------- Campos ----------
   El markup es <label class="crm-field"><span>Texto</span><input></label>:
   la etiqueta es el primer <span>, no un <label> anidado. Antes la regla
   apuntaba a «.crm-field label» y ninguna etiqueta recibía su estilo. */
.crm-field { display: block; margin-bottom: var(--sp-4); }

.crm-field > span:first-child {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.3;
  color: var(--bt-tx-2);
}

.crm-field input,
.crm-field select,
.crm-field textarea,
.bjs-select {
  width: 100%;
  min-height: 42px;
  padding: 0.625rem 0.8rem;
  border-radius: var(--r-md);
  border: 1px solid var(--bt-line-field);
  background-color: var(--bt-bg);
  color: var(--bt-tx-1);
  font-family: inherit;
  font-size: var(--fs-md);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.crm-field textarea { min-height: 7rem; line-height: 1.5; resize: vertical; }

.crm-field input::placeholder,
.crm-field textarea::placeholder { color: var(--bt-tx-3); }

@media (hover: hover) and (pointer: fine) {
  .crm-field input:hover,
  .crm-field select:hover,
  .crm-field textarea:hover,
  .bjs-select:hover { border-color: rgba(232, 240, 220, 0.42); }
}

/* Foco visible y en marca: anillo suave además del contorno global. */
.crm-field input:focus-visible,
.crm-field select:focus-visible,
.crm-field textarea:focus-visible,
.bjs-select:focus-visible {
  outline: none;
  border-color: var(--bt-accent);
  box-shadow: 0 0 0 3px var(--bt-accent-soft);
}

/* Sólo los <select>: sin appearance:none el navegador dibuja su propio cromo
   claro y se come el fondo y el color. Al quitarlo hay que traer la flecha.
   OJO: esto NO puede ir en el bloque de arriba, que lo comparte con
   .crm-field input y textarea — les saldría una flecha a los campos de texto. */
.crm-field select,
.bjs-select {
  -webkit-appearance: none;
  appearance: none;
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='%23bcd94b'%3E%3Cpath d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 0.85rem;
}

/* El padding derecho deja sitio a la flecha; sin él el texto la pisa. */
.bjs-select { width: auto; min-height: 36px; padding: 0.4375rem 2rem 0.4375rem 0.75rem; font-size: var(--fs-sm); }
.crm-field select { padding-right: 2.25rem; }

/* El select nativo hereda el fondo del sistema en su lista desplegable;
   forzar el color en las opciones evita texto blanco sobre blanco. */
.crm-field select option,
.bjs-select option { background: var(--bt-s2); color: var(--bt-tx-1); }

.crm-checks { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-5); }

.crm-checks label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 32px;
  margin: 0;
  font-size: var(--fs-sm);
  text-transform: none;
  letter-spacing: normal;
  color: var(--bt-tx-1);
  cursor: pointer;
}

.crm-checks input[type="checkbox"],
input[type="checkbox"] { width: 1rem; height: 1rem; min-height: 0; accent-color: var(--bt-green); }

/* ---------- Botones ---------- */
.crm-btn,
.bjs-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 40px;
  padding: 0.5rem 1.125rem;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  background: var(--bt-grad);
  color: var(--bt-on-accent);
  box-shadow: var(--sh-accent);
  transition: transform 160ms var(--ease-out), background var(--dur-fast) ease,
              border-color var(--dur-fast) ease, color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .crm-btn:hover, .bjs-btn:hover { transform: translateY(-1px); background: var(--bt-grad-hover); }
}
.crm-btn:active, .bjs-btn:active { transform: scale(0.97); box-shadow: none; }
.crm-btn:disabled, .bjs-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Secundario: una placa, no un hueco. Se lee como botón sin competir. */
.crm-btn.secondary,
.bjs-btn.secondary {
  background: var(--bt-s3);
  border-color: var(--bt-line-2);
  color: var(--bt-tx-1);
  box-shadow: none;
}

@media (hover: hover) and (pointer: fine) {
  .crm-btn.secondary:hover,
  .bjs-btn.secondary:hover { background: var(--bt-s4); border-color: rgba(232, 240, 220, 0.26); }
}

/* Fantasma: acciones terciarias dentro de filas y paneles. */
.crm-btn.ghost,
.bjs-btn.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--bt-tx-2);
  box-shadow: none;
}

@media (hover: hover) and (pointer: fine) {
  .crm-btn.ghost:hover,
  .bjs-btn.ghost:hover { background: var(--nav-hover-bg); color: var(--bt-tx-1); }
}

/* Peligro: borrar, revocar, quitar acceso. Coral y sin relleno: se ve, pero
   no invita. Antes estas acciones usaban el botón verde principal. */
.crm-btn.danger,
.bjs-btn.danger {
  background: transparent;
  border-color: rgba(255, 122, 92, 0.5);
  color: var(--bt-danger);
  box-shadow: none;
}

@media (hover: hover) and (pointer: fine) {
  .crm-btn.danger:hover,
  .bjs-btn.danger:hover { background: var(--bt-danger-soft); border-color: var(--bt-danger); }
}

.crm-btn.small,
.bjs-btn.small { min-height: 32px; padding: 0.3125rem 0.8125rem; font-size: var(--fs-xs); }

/* Chips de filtro: es un filtro, no una fila de llamadas a la acción. */
.bjs-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.bjs-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 32px;
  padding: 0.3125rem 0.875rem;
  border: 1px solid var(--bt-line-2);
  border-radius: var(--radius-pill);
  background: transparent;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--bt-tx-2);
  text-decoration: none;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .bjs-chip:hover { background: var(--nav-hover-bg); color: var(--bt-tx-1); }
}

.bjs-chip.is-on {
  background: var(--bt-accent-soft);
  border-color: var(--bt-line-accent);
  color: var(--bt-tx-1);
  font-weight: 600;
}

/* ---------- Tablas ---------- */
.crm-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }

.crm-table th,
.crm-table td {
  padding: 0.75rem 0.875rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--bt-line);
}

.crm-table thead th {
  padding-block: 0.625rem;
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  font-weight: 400;
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--bt-tx-3);
  white-space: nowrap;
  border-bottom-color: var(--bt-line-2);
}

.crm-table tbody tr:last-child td { border-bottom: none; }
.crm-table tbody tr { transition: background-color var(--dur-fast) ease; }
@media (hover: hover) and (pointer: fine) {
  .crm-table tbody tr:hover td { background: rgba(232, 240, 220, 0.025); }
}

/* Dentro de una tabla o de una lista de filas casi todo es enlace. Pintarlos
   todos de verde convierte la pantalla en un campo de minas: el color se
   reserva para el que tienes debajo del cursor. */
.crm-table a, .bjs-rows a {
  color: inherit;
  text-decoration-color: rgba(232, 240, 220, 0.22);
  text-underline-offset: 3px;
}

/* En las listas de filas cada renglón ya es, por contexto, un enlace: el
   subrayado sólo aparece al pasar o enfocar, para no rayar el panel. */
.bjs-rows a { text-decoration-color: transparent; }
.bjs-rows a:focus-visible { text-decoration-color: currentColor; }

@media (hover: hover) and (pointer: fine) {
  .crm-table a:hover, .bjs-rows a:hover { color: var(--bt-accent); text-decoration-color: currentColor; }
}
.crm-table td { color: var(--bt-tx-2); }
.crm-table td:first-child { color: var(--bt-tx-1); font-weight: 600; }

/* Envoltura para tablas anchas: se desplaza la tabla, nunca la página. */
.bjs-scroll-x { overflow-x: auto; scrollbar-width: thin; scrollbar-color: var(--bt-s4) transparent; }
.bjs-scroll-x > .crm-table { min-width: 640px; }

/* Ficha clave/valor. */
.bjs-dl {
  display: grid;
  grid-template-columns: minmax(120px, 200px) 1fr;
  gap: 0 var(--sp-5);
  font-size: var(--fs-sm);
}

.bjs-dl dt {
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--bt-line);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--bt-tx-3);
}

.bjs-dl dd {
  margin: 0;
  padding: 0.625rem 0;
  border-bottom: 1px solid var(--bt-line);
  color: var(--bt-tx-1);
  overflow-wrap: anywhere;
}

.bjs-dl dt:last-of-type, .bjs-dl dd:last-of-type { border-bottom: none; }

/* ---------- Badges ----------
   Punto + texto sobre una placa tenue del mismo color. El color sale de
   --badge, así cada etapa o estado sólo declara su tono. Sin modificador
   el badge es neutro, pero sigue pareciendo un badge (antes se leía como
   texto suelto). */
.crm-badge,
.bjs-badge {
  --badge: var(--bt-tx-2);
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.625rem 0.1875rem 0.5rem;
  border: 1px solid color-mix(in srgb, var(--badge) 32%, transparent);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--badge) 12%, transparent);
  font-size: var(--fs-xs);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.01em;
  white-space: nowrap;
  color: color-mix(in srgb, var(--badge) 70%, var(--bt-tx-1));
}

.crm-badge::before,
.bjs-badge::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--badge);
}

.crm-badge.prospecto,  .bjs-badge.prospecto  { --badge: var(--stage-prospecto); }
.crm-badge.contactado, .bjs-badge.contactado { --badge: var(--stage-contactado); }
.crm-badge.propuesta,  .bjs-badge.propuesta  { --badge: var(--stage-propuesta); }
.crm-badge.contrato,   .bjs-badge.contrato   { --badge: var(--stage-contrato); }
.crm-badge.cliente,    .bjs-badge.cliente    { --badge: var(--stage-cliente); }
.crm-badge.perdido,    .bjs-badge.perdido    { --badge: var(--stage-perdido); }

.crm-badge.is-ok,     .bjs-badge.is-ok     { --badge: var(--bt-ok); }
.crm-badge.is-warn,   .bjs-badge.is-warn   { --badge: var(--bt-warn); }
.crm-badge.is-danger, .bjs-badge.is-danger { --badge: var(--bt-danger); }
.crm-badge.is-info,   .bjs-badge.is-info   { --badge: var(--bt-info); }

.crm-row-actions { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.crm-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;  /* si no, badge y select se estiran a todo el ancho de la celda */
  gap: var(--sp-2);
}

.crm-login { max-width: none; margin: 0; }
.crm-login .crm-btn { width: 100%; margin-top: var(--sp-2); }

/* ---------- Adaptación ---------- */
@media (max-width: 719px) {
  /* La tabla se apila como fichas. Cada celda lleva su etiqueta en
     data-label; sin eso los valores quedarían huérfanos. */
  .crm-table.is-stacked thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .crm-table.is-stacked, .bjs-scroll-x > .crm-table.is-stacked { display: block; min-width: 0; }
  .crm-table.is-stacked tbody, .crm-table.is-stacked tr, .crm-table.is-stacked td { display: block; }

  .crm-table.is-stacked tr {
    padding: var(--sp-2) 0;
    border-bottom: 1px solid var(--bt-line);
  }

  .crm-table.is-stacked td {
    display: grid;
    grid-template-columns: 7.5rem 1fr;
    gap: var(--sp-3);
    padding: 0.3125rem 0;
    border-bottom: none;
  }

  .crm-table.is-stacked td::before {
    content: attr(data-label);
    font-family: var(--f-mono);
    font-size: var(--fs-xs);
    letter-spacing: var(--track-mono);
    text-transform: uppercase;
    color: var(--bt-tx-3);
  }

  /* Badge y boton son elementos de rejilla: sin esto se estiran a lo
     ancho de la columna y un badge de 90px acaba midiendo 340. */
  .crm-table.is-stacked td > * { justify-self: start; }
  .crm-table.is-stacked td:empty { display: none; }
  .bjs-dl { grid-template-columns: 1fr; gap: 0; }
  .bjs-dl dt { border-bottom: none; padding-bottom: 0; }

  .crm-btn, .bjs-btn { min-height: 44px; }
}

/* Dentro de una tabla, el dato secundario va en su propia línea: pegado al
   principal se lee como si fuera parte del mismo valor. */
.crm-table td .crm-muted {
  display: block;
  margin-top: 0.125rem;
  font-size: var(--fs-xs);
}

@media (prefers-reduced-motion: reduce) {
  .crm-btn, .bjs-btn, .bjs-chip, .crm-table tbody tr { transition: none; }
  .crm-btn:hover, .bjs-btn:hover { transform: none; }
}

/* ---------- Leads y Marketing ---------- */

/* Barra de filtros: se reparte en columnas cuando hay sitio. */
.bjs-filters {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr));
  align-items: end;
  padding: var(--sp-4);
  border: 1px solid var(--bt-line);
  border-radius: var(--r-lg);
  background: var(--bt-s1);
}
.bjs-filters .crm-field { margin-bottom: 0; }
.bjs-filters-actions { display: flex; gap: var(--sp-2); align-items: center; }

/* El select de estado dentro de la tabla: compacto y con el color del estado. */
.bjs-select.is-compact { min-height: 32px; padding-block: 0.25rem; }
.bjs-select.is-nuevo { border-color: var(--bt-accent); }
.bjs-select.is-descartado { color: var(--bt-tx-3); }

/* De qué formulario vino, de un vistazo. */
.crm-badge.is-cotizador { --badge: var(--bt-accent); }
.crm-badge.is-discovery { --badge: var(--bt-info); }
.crm-badge.is-chat      { --badge: var(--bt-warn); }
.crm-badge.is-borrador  { --badge: var(--bt-tx-3); }
.crm-badge.is-programada, .crm-badge.is-enviando { --badge: var(--bt-info); }
.crm-badge.is-enviada   { --badge: var(--bt-ok); }
.crm-badge.is-cancelada { --badge: var(--bt-danger); }

.bjs-message { white-space: pre-wrap; line-height: 1.6; color: var(--bt-tx-1); }

.bjs-fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.bjs-fieldset:disabled { opacity: 0.75; }

.bjs-checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--bt-tx-2);
}
.bjs-checks > span:first-child { flex-basis: 100%; font-weight: 500; }
.bjs-checks label { display: inline-flex; gap: var(--sp-2); align-items: center; cursor: pointer; min-height: 32px; }
.bjs-checks input { accent-color: var(--bt-accent); width: 16px; height: 16px; }

/* En escritorio el editor se lleva más ancho que la columna de acciones. */
@media (min-width: 1100px) {
  .bjs-grid.bjs-grid-wide { grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr); }
}

/* «Qué va a ir aquí» en las pantallas que todavía no tienen datos. */
.bjs-plan {
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px dashed var(--bt-line-field);
  text-align: left;
}
.bjs-plan-label {
  margin-bottom: var(--sp-2);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--bt-accent);
}
.bjs-plan ul { margin: 0; padding-left: 1.1rem; display: grid; gap: var(--sp-2); }
.bjs-plan li { font-size: var(--fs-sm); line-height: 1.5; color: var(--bt-tx-2); }

/* Con la lista de «qué va a ir aquí» la tarjeta es alta: deja de flotar
   sobre el esqueleto y va encima de él, en el flujo. */
.bjs-skeleton-wrap.has-plan { display: flex; flex-direction: column-reverse; gap: var(--sp-4); }
.bjs-skeleton-wrap.has-plan .bjs-empty { position: static; transform: none; max-width: 44rem; margin-inline: auto; }

/* ---------- Avisos flotantes (toasts) ----------
   Abajo a la derecha, fuera del flujo: con la página bajada, un aviso
   arriba del contenido no se veía. Entran desde abajo, corto. */
.bjs-toasts {
  position: fixed;
  right: var(--sp-5);
  bottom: var(--sp-5);
  z-index: 80;
  display: grid;
  gap: var(--sp-2);
  justify-items: end;
  pointer-events: none;
}

.bjs-toast {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  max-width: min(92vw, 420px);
  padding: 0.625rem 0.625rem 0.625rem var(--sp-4);
  border: 1px solid var(--bt-line-2);
  border-left: 3px solid var(--bt-ok);
  border-radius: var(--r-md);
  background: var(--bt-s3);
  box-shadow: var(--sh-float);
  font-size: var(--fs-sm);
  color: var(--bt-tx-1);
  pointer-events: auto;
  /* Transición + @starting-style y no keyframes: si se crean varias tareas
     seguidas, los avisos se interrumpen y reacomodan en vez de reiniciar. */
  transition: opacity 200ms cubic-bezier(0.23, 1, 0.32, 1), transform 200ms cubic-bezier(0.23, 1, 0.32, 1);

  @starting-style {
    opacity: 0;
    transform: translateY(8px);
  }
}

.bjs-toast.is-error { border-left-color: var(--bt-danger); }

.bjs-toast-accion {
  min-height: 32px;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--bt-line-2);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--bt-accent);
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 700;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .bjs-toast-accion:hover { background: var(--bt-accent-soft); border-color: var(--bt-line-accent); }
}
.bjs-toast-accion,
.bjs-orto-opciones button,
.bjs-orto-todas { transition: transform 160ms var(--ease-out), background-color var(--dur-fast) ease; }

.bjs-toast-accion:active { transform: scale(0.97); }

@media (max-width: 719px) {
  .bjs-toasts {
    left: var(--sp-3);
    right: var(--sp-3);
    /* Por encima de la barra de inicio del iPhone cuando la hay. */
    bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
    justify-items: stretch;
  }
  .bjs-toast { max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Sin desplazamiento: sólo aparece. */
  .bjs-toast { transition: opacity 150ms ease; }
  @starting-style { .bjs-toast { transform: none; } }
}

/* ---------- Corrector: «Revisar ortografía» (public/js/ortografia.js) ----------
   Un enlace discreto bajo el campo; al pulsarlo, la lista de sugerencias con
   cada reemplazo a un clic. Sin movimiento: aparece y ya. */
.bjs-orto { display: grid; gap: var(--sp-2); margin: calc(var(--sp-2) * -1) 0 var(--sp-4); }

.bjs-orto-boton {
  justify-self: start;
  min-height: 28px;
  padding: 0.125rem 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--bt-accent);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .bjs-orto-boton:hover { text-decoration-color: currentColor; }
}
.bjs-orto-boton:disabled { color: var(--bt-tx-3); cursor: default; }

.bjs-orto-panel {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--bt-line-2);
  border-radius: var(--r-md);
  background: var(--bt-s2);
  font-size: var(--fs-sm);
}

.bjs-orto-cabeza {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-2);
  font-family: var(--f-mono);
  font-size: var(--fs-xs);
  color: var(--bt-tx-3);
}

.bjs-orto-lista { list-style: none; display: grid; }

.bjs-orto-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-1) var(--sp-3);
  align-items: baseline;
  padding: var(--sp-2) 0;
  border-top: 1px solid var(--bt-line);
}

.bjs-orto-item mark {
  padding: 0 0.25rem;
  border-radius: 3px;
  background: var(--bt-danger-soft);
  color: color-mix(in srgb, var(--bt-danger) 80%, var(--bt-tx-1));
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--bt-danger) 60%, transparent);
}

.bjs-orto-item.is-grammar mark,
.bjs-orto-item.is-typographical mark,
.bjs-orto-item.is-style mark { background: var(--bt-warn-soft); color: color-mix(in srgb, var(--bt-warn) 80%, var(--bt-tx-1)); }

.bjs-orto-msg { color: var(--bt-tx-2); font-size: var(--fs-xs); }
.bjs-orto-opciones { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 0.375rem; }

.bjs-orto-opciones button,
.bjs-orto-todas {
  min-height: 30px;
  padding: 0.1875rem 0.6875rem;
  border: 1px solid var(--bt-line-accent);
  border-radius: var(--radius-pill);
  background: var(--bt-accent-softer);
  color: var(--bt-tx-1);
  font: inherit;
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
}

.bjs-orto-todas { font-family: var(--f-ui); }

@media (hover: hover) and (pointer: fine) {
  .bjs-orto-opciones button:hover,
  .bjs-orto-todas:hover { background: var(--bt-accent-soft); }
}

.bjs-orto-opciones button:active,
.bjs-orto-todas:active { transform: scale(0.97); }

.bjs-orto-opciones .is-ignorar { border-color: var(--bt-line-2); background: transparent; color: var(--bt-tx-3); font-weight: 500; }
.bjs-orto-nota { margin: 0; color: var(--bt-tx-2); }
.bjs-orto-nota.is-error { color: var(--bt-warn); }
.bjs-orto-pie { margin: var(--sp-2) 0 0; font-size: var(--fs-xs); color: var(--bt-tx-3); }

/* ---------- Burbuja de correcciones al sombrear una palabra ----------
   Sale junto al puntero. Entra desde su esquina de arriba a la izquierda
   (de donde viene: el puntero), corto; se usa de vez en cuando, no a cada tecla. */
.bjs-burbuja {
  position: fixed;
  z-index: 90;
  display: grid;
  gap: var(--sp-2);
  max-width: min(92vw, 340px);
  padding: var(--sp-3);
  border: 1px solid var(--bt-line-2);
  border-radius: var(--r-md);
  background: var(--bt-s3);
  box-shadow: var(--sh-float);
  font-size: var(--fs-sm);
  color: var(--bt-tx-1);
  transform-origin: top left;
  transition: opacity 150ms cubic-bezier(0.23, 1, 0.32, 1), transform 150ms cubic-bezier(0.23, 1, 0.32, 1);

  @starting-style {
    opacity: 0;
    transform: scale(0.97);
  }
}

.bjs-burbuja[hidden] { display: none; }

.bjs-burbuja-msg { margin: 0; font-size: var(--fs-xs); color: var(--bt-tx-2); }
.bjs-burbuja-nota { margin: 0; font-size: var(--fs-xs); color: var(--bt-tx-2); }
.bjs-burbuja-nota.is-error { color: var(--bt-warn); }
.bjs-burbuja-opciones { display: flex; flex-wrap: wrap; gap: 0.375rem; }

.bjs-burbuja-opciones button {
  min-height: 32px;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--bt-line-accent);
  border-radius: var(--radius-pill);
  background: var(--bt-accent-softer);
  color: var(--bt-tx-1);
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: transform 160ms var(--ease-out), background-color var(--dur-fast) ease;
}

@media (hover: hover) and (pointer: fine) {
  .bjs-burbuja-opciones button:hover { background: var(--bt-accent-soft); }
}

.bjs-burbuja-opciones button:active { transform: scale(0.97); }

@media (prefers-reduced-motion: reduce) {
  .bjs-burbuja { transition: opacity 150ms ease; }
  @starting-style { .bjs-burbuja { transform: none; } }
}
